/*========================== begin_copyright_notice ============================
Copyright (C) 2021-2024 Intel Corporation

SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/

/*!
 * @file Interface of the decoder of SEND messages
 */

#ifndef GEN_SEND_DECODER_H_
#define GEN_SEND_DECODER_H_

#include <string>

#include "ged.h"

/*!
 * Class that decodes SEND message instructions and provides accessors to the message attributes
 */
class DcSendMsg
{
public:
    /// Construct an object that represents result of decoding of an invalid/unsupported SEND instruction
    DcSendMsg();

    /*!
     * Construct an object that represents result of decoding of the specified SEND instruction.
     * DcSendMsg::IsValid() indicates success/failure of the decoding
     */
    explicit DcSendMsg(const ged_ins_t& gedIns);

     /*!
      * Construct an object that represents result of decoding of the specified SEND instruction.
      * DcSendMsg::IsValid() indicates success/failure of the decoding
      */
    static DcSendMsg Decode(const ged_ins_t& gedIns, bool isVerbose = false);

    /// Accessors
    bool                IsValid()           const;
    GED_SFID            Sfid()              const   { return _sfid; }
    GED_MESSAGE_TYPE    Type()              const   { return _type; };
    GED_DP_OPCODE       Opcode()            const   { return _opcode; };
    bool                IsDp0()             const   { return (_sfid == GED_SFID_DP_DC0); }
    bool                IsDp1()             const   { return (_sfid == GED_SFID_DP_DC1); }
    bool                IsUgm()             const   { return (_sfid == GED_SFID_UGM);    }
    bool                IsUgml()            const   { return (_sfid == GED_SFID_UGML); }
    bool                IsUrb()             const   { return (_sfid == GED_SFID_URB); }
    bool                IsTgm()             const   { return (_sfid == GED_SFID_TGM); }
    bool                IsLsc()             const   { return (_sfid == GED_SFID_UGM || _sfid == GED_SFID_SLM || _sfid == GED_SFID_UGML || _sfid == GED_SFID_TGM); }
    bool                IsWrite()           const   { return _isWrite; }
    bool                IsScatter()         const   { return _isScatter; }
    bool                IsScratch()         const   { return _isScratch; }
    bool                IsAtomic()          const   { return _isAtomic; }
    bool                IsMemFence()        const   { return _isMemFence; }
    bool                IsMedia()           const   { return _isMedia; }
    bool                IsEot()             const   { return _isEOT; }

    bool                IsBts()             const   { return (_bti < 0xf0); }
    bool                IsSlm()             const   { return ((_sfid == GED_SFID_SLM) || (_bti == 0xfe)); }
    bool                IsStateless()       const   { return ((_bti == 0xff) || (_bti == 0xfd)); }
    bool                IsA64()             const   { return (_isA64 && IsStateless()); }
    bool                IsTranspose()       const   { return (IsLsc() && (_transpose == GED_DP_TRANSPOSE_SIMT)); }
    uint32_t            AddrSize()          const   { return IsA64() ? sizeof(uint64_t) : sizeof(uint32_t); }
    uint32_t            Bti()               const   { return _bti; }

    uint32_t            Src0()              const   { return _src0; }
    uint32_t            Src1()              const   { return _src1; }
    uint32_t            Src0Length()        const   { return _src0Length; }
    uint32_t            Src1Length()        const   { return _src1Length; }
    uint32_t            MsgLength()         const   { return _src0Length + _src1Length; }
    uint32_t            AddrPayloadLength() const   { return _addrPayloadLength; }
    uint32_t            DataPayloadLength() const   { return _dataPayloadLength; }

    uint32_t            SimdWidth()         const   { return _simdWidth; }
    uint32_t            ElementSize()       const   { return _elementSize; }
    uint32_t            NumElements()       const   { return _numElements; }
    uint32_t            ExecSize()          const   { return _execSize; }
    uint32_t            ChannelOffset()     const   { return _channelOffset; }
    uint32_t            GlobalOffset()      const { return _globalOffset; }
    uint32_t            RGBAMask()          const   { return _cmask; }

    std::string         ToString()          const;

private:
    /*!
     * Decode instruction that SENDs message to DP0 port.
     * DcSendMsg::IsValid() indicates success/failure of the decoding.
     * @note This function provides default values for message attributes that are present in
     *       the specified message descriptors. General attributes are set by DecodeSendAttr
     */
    static DcSendMsg DecodeDp0Descriptors(ged_ins_t& gedIns, bool isVerbose = false);

    /*!
     * Decode instruction that SENDs message to DP1 port.
     * DcSendMsg::IsValid() indicates success/failure of the decoding.
     * @note This function provides default values for message attributes that are present in
     *       the specified message descriptors. General attributes are set by DecodeSendAttr
     */
    static DcSendMsg DecodeDp1Descriptors(ged_ins_t& gedIns, bool isVerbose = false);

    /*!
     * Decode instruction that SENDs message in LSC format.
     * DcSendMsg::IsValid() indicates success/failure of the decoding.
     * @note This function provides default values for message attributes that are present in
     *       the specified message descriptors. General attributes are set by DecodeSendAttr
     */
    static DcSendMsg DecodeLscDescriptors(ged_ins_t& gedIns, bool isVerbose = false);

    /*!
     * Decode SEND instruction that accesses URB device
     * DcSendMsg::IsValid() indicates success/failure of the decoding.
     * @note This function provides default values for message attributes that are present in
     *       the specified message descriptors. General attributes are set by DecodeSendAttr
     */
    static DcSendMsg DecodeUrbDescriptors(ged_ins_t& gedIns, bool isVerbose = false);

    /*!
     * Decode general attributes of SEND instruction: Src0, Src1, ExecSize, ChannelOffset, IsEot
     */
    void DecodeSendGeneralAttr(ged_ins_t& gedIns);

private:
    bool                _isWrite;               ///< Write (true) or read (false) operation
    bool                _isScatter;             ///< Scatter (true) operation
    bool                _isScratch;             ///< Is access to scratch block (true)
    bool                _isAtomic;              ///< Is atomic operation (true)
    bool                _isMemFence;            ///< Is memory synchronization fence (true)
    bool                _isMedia;               ///< Media Block access
    bool                _isEOT;                 ///< End Of Thread (EOT) SEND instruction
    uint32_t            _elementSize;           ///< Data element size in bytes
    uint32_t            _numElements;           ///< Number of elements to be read or written
    uint32_t            _addrPayloadLength;     ///< Address payload length in GRF registers
    uint32_t            _dataPayloadLength;     ///< Data payload length in GRF registers
    uint32_t            _src0Length;            ///< Message length starting from Src0 operand, in GRF registers
    uint32_t            _src1Length;            ///< Message length starting from Src1 operand, in GRF registers
    uint32_t            _src0;                  ///< Register number of the Src0 operand
    uint32_t            _src1;                  ///< Register number of the Src1 operand
    uint32_t            _execSize;              ///< The number of SIMD elements the instruction is configured to execute
    uint32_t            _channelOffset;         ///< The starting bit number within the channel mask
    uint32_t            _globalOffset;          ///< Specifes the offset, in units of Oword elements, from the start of the URB handle for the access.
    uint32_t            _cmask;                 ///< RGBA channels mask
    bool                _isA64;                 ///< true for 64-bit address model, false otherwise
    uint32_t            _bti;                   ///< Binding table index
    uint32_t            _simdWidth;             ///< SIMD width
    GED_SFID            _sfid;                  ///< Shared function ID (data port, etc.)
    GED_MESSAGE_TYPE    _type;                  ///< Message type
    GED_DP_OPCODE       _opcode;                ///< Message opcode
    GED_DP_TRANSPOSE    _transpose;             ///< Transpose (LSC)
};

#endif
