/*! \file Instruction.h \brief Decode instructions part of the RISC-V \author Màrius Montón \date August 2018 */ #ifndef INSTRUCTION__H #define INSTRUCTION__H #include "systemc" using namespace sc_core; using namespace sc_dt; using namespace std; typedef enum { BASE_EXTENSION, M_EXTENSION, A_EXTENSION, F_EXTENSION, D_EXTENSION, Q_EXTENSION, L_EXTENSION, C_EXTENSION, R_EXTENSION, J_EXTENSION, P_EXTENSION, V_EXTENSION, N_EXTENSION, UNKNOWN_EXTENSION } extension_t; typedef enum { OP_LUI, OP_AUIPC, OP_JAL, OP_JALR, OP_BEQ, OP_BNE, OP_BLT, OP_BGE, OP_BLTU, OP_BGEU, OP_LB, OP_LH, OP_LW, OP_LBU, OP_LHU, OP_SB, OP_SH, OP_SW, OP_ADDI, OP_SLTI, OP_SLTIU, OP_XORI, OP_ORI, OP_ANDI, OP_SLLI, OP_SRLI, OP_SRAI, OP_ADD, OP_SUB, OP_SLL, OP_SLT, OP_SLTU, OP_XOR, OP_SRL, OP_SRA, OP_OR, OP_AND, OP_FENCE, OP_ECALL, OP_EBREAK, OP_CSRRW, OP_CSRRS, OP_CSRRC, OP_CSRRWI, OP_CSRRSI, OP_CSRRCI, OP_URET, OP_SRET, OP_MRET, OP_WFI, OP_SFENCE, OP_ERROR } opCodes; typedef enum { LUI = 0b0110111, AUIPC = 0b0010111, JAL = 0b1101111, JALR = 0b1100111, BEQ = 0b1100011, BEQ_F = 0b000, BNE_F = 0b001, BLT_F = 0b100, BGE_F = 0b101, BLTU_F = 0b110, BGEU_F = 0b111, LB = 0b0000011, LB_F = 0b000, LH_F = 0b001, LW_F = 0b010, LBU_F = 0b100, LHU_F = 0b101, SB = 0b0100011, SB_F = 0b000, SH_F = 0b001, SW_F = 0b010, ADDI = 0b0010011, ADDI_F = 0b000, SLTI_F = 0b010, SLTIU_F = 0b011, XORI_F = 0b100, ORI_F = 0b110, ANDI_F = 0b111, SLLI_F = 0b001, SRLI_F = 0b101, SRLI_F7 = 0b0000000, SRAI_F7 = 0b0100000, ADD = 0b0110011, ADD_F = 0b000, SUB_F = 0b000, ADD_F7 = 0b0000000, SUB_F7 = 0b0100000, SLL_F = 0b001, SLT_F = 0b010, SLTU_F = 0b011, XOR_F = 0b100, SRL_F = 0b101, SRA_F = 0b101, SRL_F7 = 0b0000000, SRA_F7 = 0b0100000, OR_F = 0b110, AND_F = 0b111, FENCE = 0b0001111, ECALL = 0b1110011, ECALL_F = 0b000000000000, EBREAK_F= 0b000000000001, URET_F = 0b000000000010, SRET_F = 0b000100000010, MRET_F = 0b001100000010, WFI_F = 0b000100000101, SFENCE_F = 0b0001001, ECALL_F3= 0b000, CSRRW = 0b001, CSRRS = 0b010, CSRRC = 0b011, CSRRWI = 0b101, CSRRSI = 0b110, CSRRCI = 0b111, } Codes; #define EXCEPTION_CAUSE_INSTRUCTION_MISALIGN 0 #define EXCEPTION_CAUSE_INSTRUCTION_ACCESS 1 #define EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION 2 #define EXCEPTION_CAUSE_BREAKPOINT 3 #define EXCEPTION_CAUSE_LOAD_ADDR_MISALIGN 4 #define EXCEPTION_CAUSE_LOAD_ACCESS_FAULT 5 /** * @brief Instruction decoding and fields access */ class Instruction { public: /** * @brief Constructor * @param instr Instruction to decode */ Instruction(sc_uint<32> instr); /** * @brief Access to opcode field * @return return opcode field */ inline int32_t opcode() { return m_instr.range(6,0); } /** * @brief Access to rd field * @return rd field */ inline int32_t get_rd() { return m_instr.range(11, 7); } /** * @brief Sets rd field * @param value desired rd value */ inline void set_rd(int32_t value) { m_instr.range(11,7) = value; } /** * @brief Access to funct3 field * @return funct3 field */ inline int32_t get_funct3() { return m_instr.range(14, 12); } /** * @brief Sets func3 field * @param value desired func3 value */ inline void set_funct3(int32_t value) { m_instr.range(14,12) = value; } /** * @brief Access to rs1 field * @return rs1 field */ inline int32_t get_rs1() { return m_instr.range(19, 15); } /** * @brief Sets rs1 field * @param value desired rs1 value */ inline void set_rs1(int32_t value) { m_instr.range(19,15) = value; } /** * @brief Access to rs2 field * @return rs2 field */ inline int32_t get_rs2() { return m_instr.range(24, 20); } /** * @brief Sets rs2 field * @param value desired rs2 value */ inline void set_rs2(int32_t value) { m_instr.range(24,10) = value; } /** * @brief Access to funct7 field * @return funct7 field */ inline int32_t get_funct7() { return m_instr.range(31, 25); } /** * @brief Sets func7 field * @param value desired func7 value */ inline void set_func7(int32_t value) { m_instr.range(31,25) = value; } /** * @brief Gets immediate field value for I-type * @return immediate_I field */ inline int32_t get_imm_I() { int32_t aux = 0; aux = m_instr.range(31, 20); /* sign extension (optimize) */ if (m_instr[31] == 1) { aux |= (0b11111111111111111111) << 12; } return aux; } /** * @brief Sets immediate field for I-type * @param value desired I value */ inline void set_imm_I(int32_t value) { m_instr.range(31,20) = value; } /** * @brief Gets immediate field value for S-type * @return immediate_S field */ inline int32_t get_imm_S() { int32_t aux = 0; aux = m_instr.range(31, 25) << 5; aux |= m_instr.range(11,7); if (m_instr[31] == 1) { aux |= (0b11111111111111111111) << 12; } return aux; } /** * @brief Sets immediate field for S-type * @param value desired S value */ inline void set_imm_S(int32_t value) { sc_uint<32> aux = value; m_instr.range(31,25) = aux.range(11,5); m_instr.range(11,7) = aux.range(4,0); } /** * @brief Gets immediate field value for U-type * @return immediate_U field */ inline int32_t get_imm_U() { return m_instr.range(31, 12); } /** * @brief Sets immediate field for U-type * @param value desired U value */ inline void set_imm_U(int32_t value) { m_instr.range(31,12) = (value << 12); } /** * @brief Gets immediate field value for B-type * @return immediate_B field */ inline int32_t get_imm_B() { int32_t aux = 0; aux |= m_instr[7] << 11; aux |= m_instr.range(30, 25) << 5; aux |= m_instr[31] << 12; aux |= m_instr.range(11, 8) << 1; if (m_instr[31] == 1) { aux |= (0b11111111111111111111) << 12; } return aux; } /** * @brief Sets immediate field for B-type * @param value desired B value */ inline void set_imm_B(int32_t value) { sc_uint<32> aux = value; m_instr[31] = aux[12]; m_instr.range(30,25) = aux.range(10,5); m_instr.range(11,7) = aux.range(4,1); m_instr[6] = aux[11]; } /** * @brief Gets immediate field value for J-type * @return immediate_J field */ inline int32_t get_imm_J() { int32_t aux = 0; aux = m_instr[31] << 20; aux |= m_instr.range(19,12) << 12; aux |= m_instr[20] << 11; aux |= m_instr.range(30,21) << 1; /* bit extension (better way to do that?) */ if (m_instr[31] == 1) { aux |= (0b111111111111) << 20; } return aux; } /** * @brief Sets immediate field for J-type * @param value desired J value */ inline void set_imm_J(int32_t value) { sc_uint<32> aux = (value << 20); m_instr[31] = aux[20]; m_instr.range(30,21) = aux.range(10,1); m_instr[20] = aux[11]; m_instr.range(19,12) = aux.range(19,12); } /** * @brief Returns shamt field for Shifts instructions * @return value corresponding to inst(25:20) */ inline int32_t get_shamt() { return m_instr.range(25, 20); } /** * @brief Returns CSR field for CSR instructions * @return value corresponding to instr(31:20) */ inline int32_t get_csr() { int32_t aux = 0; aux = m_instr.range(31, 20); return aux; } /** * @brief Decodes opcode of instruction * @return opcode of instruction */ opCodes decode(); /** * @brief returns what instruction extension * @return extension */ extension_t check_extension(); void setInstr(uint32_t p_instr) { m_instr = p_instr; } /** * @brief return instruction * @return all instruction bits (31:0) */ uint32_t getInstr() { return m_instr; } inline void dump() { cout << hex << "0x" << m_instr << dec << endl; } private: sc_uint<32> m_instr; }; #endif