diff --git a/inc/A_extension.h b/inc/A_extension.h index 3b86391..019c243 100644 --- a/inc/A_extension.h +++ b/inc/A_extension.h @@ -17,84 +17,98 @@ #include "MemoryInterface.h" #include "extension_base.h" -typedef enum { - OP_A_LR, - OP_A_SC, - OP_A_AMOSWAP, - OP_A_AMOADD, - OP_A_AMOXOR, - OP_A_AMOAND, - OP_A_AMOOR, - OP_A_AMOMIN, - OP_A_AMOMAX, - OP_A_AMOMINU, - OP_A_AMOMAXU, +namespace riscv_tlm { - OP_A_ERROR -} op_A_Codes; + typedef enum { + OP_A_LR, + OP_A_SC, + OP_A_AMOSWAP, + OP_A_AMOADD, + OP_A_AMOXOR, + OP_A_AMOAND, + OP_A_AMOOR, + OP_A_AMOMIN, + OP_A_AMOMAX, + OP_A_AMOMINU, + OP_A_AMOMAXU, -typedef enum { - A_LR = 0b00010, - A_SC = 0b00011, - A_AMOSWAP = 0b00001, - A_AMOADD = 0b00000, - A_AMOXOR = 0b00100, - A_AMOAND = 0b01100, - A_AMOOR = 0b01000, - A_AMOMIN = 0b10000, - A_AMOMAX = 0b10100, - A_AMOMINU = 0b11000, - A_AMOMAXU = 0b11100, -} A_Codes; + OP_A_ERROR + } op_A_Codes; + + typedef enum { + A_LR = 0b00010, + A_SC = 0b00011, + A_AMOSWAP = 0b00001, + A_AMOADD = 0b00000, + A_AMOXOR = 0b00100, + A_AMOAND = 0b01100, + A_AMOOR = 0b01000, + A_AMOMIN = 0b10000, + A_AMOMAX = 0b10100, + A_AMOMINU = 0b11000, + A_AMOMAXU = 0b11100, + } A_Codes; /** * @brief Instruction decoding and fields access */ -class A_extension: public extension_base { -public: + class A_extension : public extension_base { + public: - /** - * @brief Constructor, same as base class - */ - using extension_base::extension_base; + /** + * @brief Constructor, same as base class + */ + using extension_base::extension_base; - /** - * @brief Access to opcode field - * @return return opcode field - */ - inline int32_t opcode() const override { - return static_cast(m_instr.range(31, 27)); - } + /** + * @brief Access to opcode field + * @return return opcode field + */ + inline int32_t opcode() const override { + return static_cast(m_instr.range(31, 27)); + } - /** - * @brief Decodes opcode of instruction - * @return opcode of instruction - */ - op_A_Codes decode() const; + /** + * @brief Decodes opcode of instruction + * @return opcode of instruction + */ + op_A_Codes decode() const; - inline void dump() const override { - std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; - } + inline void dump() const override { + std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; + } - bool Exec_A_LR(); - bool Exec_A_SC(); - bool Exec_A_AMOSWAP() const; - bool Exec_A_AMOADD() const; - bool Exec_A_AMOXOR() const; - bool Exec_A_AMOAND() const; - bool Exec_A_AMOOR() const; - bool Exec_A_AMOMIN() const; - bool Exec_A_AMOMAX() const; - bool Exec_A_AMOMINU() const; - bool Exec_A_AMOMAXU() const; + bool Exec_A_LR(); - bool process_instruction(Instruction &inst); + bool Exec_A_SC(); - void TLB_reserve(std::uint32_t address); - bool TLB_reserved(std::uint32_t address); + bool Exec_A_AMOSWAP() const; -private: - std::unordered_set TLB_A_Entries; -}; + bool Exec_A_AMOADD() const; + + bool Exec_A_AMOXOR() const; + + bool Exec_A_AMOAND() const; + + bool Exec_A_AMOOR() const; + + bool Exec_A_AMOMIN() const; + + bool Exec_A_AMOMAX() const; + + bool Exec_A_AMOMINU() const; + + bool Exec_A_AMOMAXU() const; + + bool process_instruction(Instruction &inst); + + void TLB_reserve(std::uint32_t address); + + bool TLB_reserved(std::uint32_t address); + + private: + std::unordered_set TLB_A_Entries; + }; +} #endif diff --git a/inc/BASE_ISA.h b/inc/BASE_ISA.h index 9ed0a29..6822149 100644 --- a/inc/BASE_ISA.h +++ b/inc/BASE_ISA.h @@ -23,324 +23,367 @@ #include "A_extension.h" #include "Registers.h" -typedef enum { - OP_LUI, - OP_AUIPC, - OP_JAL, - OP_JALR, +namespace riscv_tlm { - OP_BEQ, - OP_BNE, - OP_BLT, - OP_BGE, - OP_BLTU, - OP_BGEU, + typedef enum { + OP_LUI, + OP_AUIPC, + OP_JAL, + OP_JALR, - OP_LB, - OP_LH, - OP_LW, - OP_LBU, - OP_LHU, + OP_BEQ, + OP_BNE, + OP_BLT, + OP_BGE, + OP_BLTU, + OP_BGEU, - OP_SB, - OP_SH, - OP_SW, + OP_LB, + OP_LH, + OP_LW, + OP_LBU, + OP_LHU, - OP_ADDI, - OP_SLTI, - OP_SLTIU, - OP_XORI, - OP_ORI, - OP_ANDI, - OP_SLLI, - OP_SRLI, - OP_SRAI, + OP_SB, + OP_SH, + OP_SW, - OP_ADD, - OP_SUB, - OP_SLL, - OP_SLT, - OP_SLTU, - OP_XOR, - OP_SRL, - OP_SRA, - OP_OR, - OP_AND, + OP_ADDI, + OP_SLTI, + OP_SLTIU, + OP_XORI, + OP_ORI, + OP_ANDI, + OP_SLLI, + OP_SRLI, + OP_SRAI, - OP_FENCE, - OP_ECALL, - OP_EBREAK, + OP_ADD, + OP_SUB, + OP_SLL, + OP_SLT, + OP_SLTU, + OP_XOR, + OP_SRL, + OP_SRA, + OP_OR, + OP_AND, - OP_CSRRW, - OP_CSRRS, - OP_CSRRC, - OP_CSRRWI, - OP_CSRRSI, - OP_CSRRCI, + OP_FENCE, + OP_ECALL, + OP_EBREAK, - OP_URET, - OP_SRET, - OP_MRET, - OP_WFI, - OP_SFENCE, + OP_CSRRW, + OP_CSRRS, + OP_CSRRC, + OP_CSRRWI, + OP_CSRRSI, + OP_CSRRCI, - OP_ERROR -} opCodes; + OP_URET, + OP_SRET, + OP_MRET, + OP_WFI, + OP_SFENCE, + + OP_ERROR + } opCodes; /** * @brief Risc_V execute module */ -class BASE_ISA: public extension_base { -public: + class BASE_ISA : public extension_base { + public: - /** - * @brief Constructor, same as base class - */ - using extension_base::extension_base; + /** + * @brief Constructor, same as base class + */ + using extension_base::extension_base; - /** - * @brief Access to funct7 field - * @return funct7 field - */ - inline std::int32_t get_funct7() const { - return m_instr.range(31, 25); - } + /** + * @brief Access to funct7 field + * @return funct7 field + */ + inline std::int32_t get_funct7() const { + return m_instr.range(31, 25); + } - /** - * @brief Sets func7 field - * @param value desired func7 value - */ - inline void set_func7(std::int32_t value) { - m_instr.range(31, 25) = value; - } + /** + * @brief Sets func7 field + * @param value desired func7 value + */ + inline void set_func7(std::int32_t value) { + m_instr.range(31, 25) = value; + } - /** - * @brief Gets immediate field value for I-type - * @return immediate_I field - */ - inline std::int32_t get_imm_I() const { - std::int32_t aux = 0; + /** + * @brief Gets immediate field value for I-type + * @return immediate_I field + */ + inline std::int32_t get_imm_I() const { + std::uint32_t aux = 0; - aux = m_instr.range(31, 20); + aux = m_instr.range(31, 20); - /* sign extension (optimize) */ - if (m_instr[31] == 1) { - aux |= (0b11111111111111111111) << 12; - } + /* sign extension (optimize) */ + if (m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + } - return aux; - } + return static_cast(aux); + } - /** - * @brief Sets immediate field for I-type - * @param value desired I value - */ - inline void set_imm_I(std::int32_t value) { - m_instr.range(31, 20) = value; - } + /** + * @brief Sets immediate field for I-type + * @param value desired I value + */ + inline void set_imm_I(std::int32_t value) { + m_instr.range(31, 20) = value; + } - /** - * @brief Gets immediate field value for S-type - * @return immediate_S field - */ - inline std::int32_t get_imm_S() const { - std::int32_t aux = 0; + /** + * @brief Gets immediate field value for S-type + * @return immediate_S field + */ + inline std::int32_t get_imm_S() const { + std::uint32_t aux = 0; - aux = m_instr.range(31, 25) << 5; - aux |= m_instr.range(11, 7); + aux = m_instr.range(31, 25) << 5; + aux |= m_instr.range(11, 7); - if (m_instr[31] == 1) { - aux |= (0b11111111111111111111) << 12; - } + if (m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + } - return aux; - } + return static_cast(aux); + } - /** - * @brief Gets immediate field value for U-type - * @return immediate_U field - */ - inline std::int32_t get_imm_U() const { - return m_instr.range(31, 12); - } + /** + * @brief Gets immediate field value for U-type + * @return immediate_U field + */ + inline std::int32_t get_imm_U() const { + return static_cast(m_instr.range(31, 12)); + } - /** - * @brief Sets immediate field for U-type - * @param value desired U value - */ - inline void set_imm_U(std::int32_t value) { - m_instr.range(31, 12) = (value << 12); - } + /** + * @brief Sets immediate field for U-type + * @param value desired U value + */ + inline void set_imm_U(std::int32_t value) { + m_instr.range(31, 12) = (value << 12); + } - /** - * @brief Gets immediate field value for B-type - * @return immediate_B field - */ - inline std::int32_t get_imm_B() const { - std::int32_t aux = 0; + /** + * @brief Gets immediate field value for B-type + * @return immediate_B field + */ + inline std::int32_t get_imm_B() const { + std::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; + 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; - } + if (m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + } - return aux; - } + return aux; + } - /** - * @brief Sets immediate field for B-type - * @param value desired B value - */ - inline void set_imm_B(std::int32_t value) { - sc_dt::sc_uint<32> aux = value; + /** + * @brief Sets immediate field for B-type + * @param value desired B value + */ + inline void set_imm_B(std::int32_t value) { + sc_dt::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]; - } + 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 std::int32_t get_imm_J() const { - std::int32_t aux = 0; + /** + * @brief Gets immediate field value for J-type + * @return immediate_J field + */ + inline std::int32_t get_imm_J() const { + std::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; + 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; - } + /* bit extension (better way to do that?) */ + if (m_instr[31] == 1) { + aux |= (0b111111111111) << 20; + } - return aux; - } + return aux; + } - /** - * @brief Sets immediate field for J-type - * @param value desired J value - */ - inline void set_imm_J(std::int32_t value) { - sc_dt::sc_uint<32> aux = (value << 20); + /** + * @brief Sets immediate field for J-type + * @param value desired J value + */ + inline void set_imm_J(std::int32_t value) { + sc_dt::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); - } + 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 std::int32_t get_shamt() const { - return static_cast(m_instr.range(25, 20)); - } + /** + * @brief Returns shamt field for Shifts instructions + * @return value corresponding to inst(25:20) + */ + inline std::int32_t get_shamt() const { + return static_cast(m_instr.range(25, 20)); + } - /** - * @brief Returns CSR field for CSR instructions - * @return value corresponding to instr(31:20) - */ - inline std::int32_t get_csr() const { - std::int32_t aux = 0; + /** + * @brief Returns CSR field for CSR instructions + * @return value corresponding to instr(31:20) + */ + inline std::int32_t get_csr() const { + std::int32_t aux = 0; - aux = static_cast(m_instr.range(31, 20)); + aux = static_cast(m_instr.range(31, 20)); - return aux; - } + return aux; + } - /** - * @brief Access to opcode field - * @return return opcode field - */ - inline std::int32_t opcode() const override { - return static_cast(m_instr.range(6, 0)); - } + /** + * @brief Access to opcode field + * @return return opcode field + */ + inline std::int32_t opcode() const override { + return static_cast(m_instr.range(6, 0)); + } - bool Exec_LUI() const; - bool Exec_AUIPC() const; + bool Exec_LUI() const; - bool Exec_JAL() const; - bool Exec_JALR(); + bool Exec_AUIPC() const; - bool Exec_BEQ() const; - bool Exec_BNE() const; - bool Exec_BLT() const; - bool Exec_BGE() const; - bool Exec_BLTU() const; - bool Exec_BGEU() const; + bool Exec_JAL() const; - bool Exec_LB() const; - bool Exec_LH() const; - bool Exec_LW() const; - bool Exec_LBU() const; - bool Exec_LHU() const; + bool Exec_JALR(); - bool Exec_SB() const; - bool Exec_SH() const; - bool Exec_SW() const; - bool Exec_SBU() const; - bool Exec_SHU() const; + bool Exec_BEQ() const; - bool Exec_ADDI() const; - bool Exec_SLTI() const; - bool Exec_SLTIU() const; - bool Exec_XORI() const; - bool Exec_ORI() const; - bool Exec_ANDI() const; - bool Exec_SLLI(); - bool Exec_SRLI() const; - bool Exec_SRAI() const; + bool Exec_BNE() const; - bool Exec_ADD() const; - bool Exec_SUB() const; - bool Exec_SLL() const; - bool Exec_SLT() const; - bool Exec_SLTU() const; + bool Exec_BLT() const; - bool Exec_XOR() const; - bool Exec_SRL() const; - bool Exec_SRA() const; - bool Exec_OR() const; - bool Exec_AND() const; + bool Exec_BGE() const; - bool Exec_FENCE() const; - bool Exec_ECALL(); - bool Exec_EBREAK(); + bool Exec_BLTU() const; - bool Exec_CSRRW() const; - bool Exec_CSRRS() const; - bool Exec_CSRRC() const; - bool Exec_CSRRWI() const; - bool Exec_CSRRSI() const; - bool Exec_CSRRCI() const; + bool Exec_BGEU() const; - /*********************** Privileged Instructions ******************************/ - bool Exec_MRET() const; - bool Exec_SRET() const; - bool Exec_WFI() const; - bool Exec_SFENCE() const; + bool Exec_LB() const; - /** - * @brief Executes default ISA instruction - * @param inst instruction to execute - * @return true if PC is affected by instruction - */ - bool process_instruction(Instruction &inst, bool *breakpoint = nullptr); + bool Exec_LH() const; - /** - * @brief Decodes opcode of instruction - * @return opcode of instruction - */ - opCodes decode(); -}; + bool Exec_LW() const; + bool Exec_LBU() const; + + bool Exec_LHU() const; + + bool Exec_SB() const; + + bool Exec_SH() const; + + bool Exec_SW() const; + + bool Exec_SBU() const; + + bool Exec_SHU() const; + + bool Exec_ADDI() const; + + bool Exec_SLTI() const; + + bool Exec_SLTIU() const; + + bool Exec_XORI() const; + + bool Exec_ORI() const; + + bool Exec_ANDI() const; + + bool Exec_SLLI(); + + bool Exec_SRLI() const; + + bool Exec_SRAI() const; + + bool Exec_ADD() const; + + bool Exec_SUB() const; + + bool Exec_SLL() const; + + bool Exec_SLT() const; + + bool Exec_SLTU() const; + + bool Exec_XOR() const; + + bool Exec_SRL() const; + + bool Exec_SRA() const; + + bool Exec_OR() const; + + bool Exec_AND() const; + + bool Exec_FENCE() const; + + bool Exec_ECALL(); + + bool Exec_EBREAK(); + + bool Exec_CSRRW() const; + + bool Exec_CSRRS() const; + + bool Exec_CSRRC() const; + + bool Exec_CSRRWI() const; + + bool Exec_CSRRSI() const; + + bool Exec_CSRRCI() const; + + /*********************** Privileged Instructions ******************************/ + bool Exec_MRET() const; + + bool Exec_SRET() const; + + bool Exec_WFI() const; + + bool Exec_SFENCE() const; + + /** + * @brief Executes default ISA instruction + * @param inst instruction to execute + * @return true if PC is affected by instruction + */ + bool process_instruction(Instruction &inst, bool *breakpoint = nullptr); + + /** + * @brief Decodes opcode of instruction + * @return opcode of instruction + */ + opCodes decode(); + }; +} #endif diff --git a/inc/BusCtrl.h b/inc/BusCtrl.h index 9046f2d..e5c9307 100644 --- a/inc/BusCtrl.h +++ b/inc/BusCtrl.h @@ -20,6 +20,8 @@ #include "tlm_utils/simple_initiator_socket.h" #include "tlm_utils/simple_target_socket.h" +namespace riscv_tlm { + /** * Memory mapped Trace peripheral address */ @@ -41,51 +43,52 @@ * It will be expanded with more ports when required (for DMA, * other peripherals, etc.) */ -class BusCtrl: sc_core::sc_module { -public: - /** - * @brief TLM target socket CPU instruction memory bus - */ - tlm_utils::simple_target_socket cpu_instr_socket; + class BusCtrl : sc_core::sc_module { + public: + /** + * @brief TLM target socket CPU instruction memory bus + */ + tlm_utils::simple_target_socket cpu_instr_socket; - /** - * @brief TLM target socket CPU data memory bus - */ - tlm_utils::simple_target_socket cpu_data_socket; + /** + * @brief TLM target socket CPU data memory bus + */ + tlm_utils::simple_target_socket cpu_data_socket; - /** - * @brief TLM initiator socket Main memory bus - */ - tlm_utils::simple_initiator_socket memory_socket; + /** + * @brief TLM initiator socket Main memory bus + */ + tlm_utils::simple_initiator_socket memory_socket; - /** - * @brief TLM initiator socket Trace module - */ - tlm_utils::simple_initiator_socket trace_socket; + /** + * @brief TLM initiator socket Trace module + */ + tlm_utils::simple_initiator_socket trace_socket; - /** - * @brief TLM initiator socket Trace module - */ - tlm_utils::simple_initiator_socket timer_socket; + /** + * @brief TLM initiator socket Trace module + */ + tlm_utils::simple_initiator_socket timer_socket; - /** - * @brief constructor - * @param name module's name - */ - explicit BusCtrl(sc_core::sc_module_name const &name); + /** + * @brief constructor + * @param name module's name + */ + explicit BusCtrl(sc_core::sc_module_name const &name); - /** - * @brief TLM-2 blocking mechanism - * @param trans transtractino to perform - * @param delay delay associated to this transaction - */ - virtual void b_transport(tlm::tlm_generic_payload &trans, - sc_core::sc_time &delay); + /** + * @brief TLM-2 blocking mechanism + * @param trans transtractino to perform + * @param delay delay associated to this transaction + */ + virtual void b_transport(tlm::tlm_generic_payload &trans, + sc_core::sc_time &delay); -private: - bool instr_direct_mem_ptr(tlm::tlm_generic_payload&, - tlm::tlm_dmi &dmi_data); - void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end); -}; + private: + bool instr_direct_mem_ptr(tlm::tlm_generic_payload &, + tlm::tlm_dmi &dmi_data); + void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end); + }; +} #endif diff --git a/inc/CPU.h b/inc/CPU.h index 1701909..2781383 100644 --- a/inc/CPU.h +++ b/inc/CPU.h @@ -26,99 +26,101 @@ #include "M_extension.h" #include "A_extension.h" + +namespace riscv_tlm { /** * @brief ISC_V CPU model * @param name name of the module */ -class CPU: sc_core::sc_module { -public: + class CPU : sc_core::sc_module { + public: - /** - * @brief Instruction Memory bus socket - * @param trans transction to perfoem - * @param delay time to annotate - */ - tlm_utils::simple_initiator_socket instr_bus; + /** + * @brief Instruction Memory bus socket + * @param trans transction to perfoem + * @param delay time to annotate + */ + tlm_utils::simple_initiator_socket instr_bus; - /** - * @brief IRQ line socket - * @param trans transction to perform (empty) - * @param delay time to annotate - */ - tlm_utils::simple_target_socket irq_line_socket; + /** + * @brief IRQ line socket + * @param trans transction to perform (empty) + * @param delay time to annotate + */ + tlm_utils::simple_target_socket irq_line_socket; - /** - * @brief Constructor - * @param name Module name - * @param PC Program Counter initialize value - * @param debug To start debugging - */ - CPU(sc_core::sc_module_name const &name, std::uint32_t PC, bool debug); + /** + * @brief Constructor + * @param name Module name + * @param PC Program Counter initialize value + * @param debug To start debugging + */ + CPU(sc_core::sc_module_name const &name, std::uint32_t PC, bool debug); - /** - * @brief Destructor - */ - ~CPU() override; + /** + * @brief Destructor + */ + ~CPU() override; - MemoryInterface *mem_intf; + MemoryInterface *mem_intf; - bool CPU_step(); + bool CPU_step(); - Registers *getRegisterBank() {return register_bank;} + Registers *getRegisterBank() { return register_bank; } -private: - Registers *register_bank; - Performance *perf; - std::shared_ptr logger; - C_extension *c_inst; - M_extension *m_inst; - A_extension *a_inst; - BASE_ISA *exec; - tlm_utils::tlm_quantumkeeper *m_qk; + private: + Registers *register_bank; + Performance *perf; + std::shared_ptr logger; + C_extension *c_inst; + M_extension *m_inst; + A_extension *a_inst; + BASE_ISA *exec; + tlm_utils::tlm_quantumkeeper *m_qk; - Instruction inst; - bool interrupt; - std::uint32_t int_cause; - bool irq_already_down; - sc_core::sc_time default_time; - bool dmi_ptr_valid; + Instruction inst; + bool interrupt; + std::uint32_t int_cause; + bool irq_already_down; + sc_core::sc_time default_time; + bool dmi_ptr_valid; - tlm::tlm_generic_payload trans; - std::uint32_t INSTR; - unsigned char *dmi_ptr = nullptr; + tlm::tlm_generic_payload trans; + std::uint32_t INSTR; + unsigned char *dmi_ptr = nullptr; + /** + * + * @brief Process and triggers IRQ if all conditions met + * @return true if IRQ is triggered, false otherwise + */ + bool cpu_process_IRQ(); - /** - * - * @brief Process and triggers IRQ if all conditions met - * @return true if IRQ is triggered, false otherwise - */ - bool cpu_process_IRQ(); + /** + * main thread for CPU simulation + * @brief CPU mai thread + */ + [[noreturn]] void CPU_thread(); - /** - * main thread for CPU simulation - * @brief CPU mai thread - */ - [[noreturn]] void CPU_thread(); + /** + * @brief callback for IRQ simple socket + * @param trans transaction to perform (empty) + * @param delay time to annotate + * + * it triggers an IRQ when called + */ + void call_interrupt(tlm::tlm_generic_payload &trans, + sc_core::sc_time &delay); - /** - * @brief callback for IRQ simple socket - * @param trans transaction to perform (empty) - * @param delay time to annotate - * - * it triggers an IRQ when called - */ - void call_interrupt(tlm::tlm_generic_payload &trans, - sc_core::sc_time &delay); - - /** - * DMI pointer is not longer valid - * @param start memory address region start - * @param end memory address region end - */ - void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end); -}; + /** + * DMI pointer is not longer valid + * @param start memory address region start + * @param end memory address region end + */ + void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end); + }; +} #endif diff --git a/inc/C_extension.h b/inc/C_extension.h index 6db5429..3501bd6 100644 --- a/inc/C_extension.h +++ b/inc/C_extension.h @@ -12,400 +12,426 @@ #include "systemc" #include "extension_base.h" -typedef enum { - OP_C_ADDI4SPN, - OP_C_FLD, - OP_C_LW, - OP_C_FLW, - OP_C_FSD, - OP_C_SW, - OP_C_FSW, +namespace riscv_tlm { - OP_C_NOP, - OP_C_ADDI, - OP_C_JAL, - OP_C_LI, - OP_C_ADDI16SP, - OP_C_LUI, - OP_C_SRLI, - OP_C_SRAI, - OP_C_ANDI, - OP_C_SUB, - OP_C_XOR, - OP_C_OR, - OP_C_AND, - OP_C_J, - OP_C_BEQZ, - OP_C_BNEZ, + typedef enum { + OP_C_ADDI4SPN, + OP_C_FLD, + OP_C_LW, + OP_C_FLW, + OP_C_FSD, + OP_C_SW, + OP_C_FSW, - OP_C_SLLI, - OP_C_FLDSP, - OP_C_LWSP, - OP_C_FLWSP, - OP_C_JR, - OP_C_MV, - OP_C_EBREAK, - OP_C_JALR, - OP_C_ADD, - OP_C_FSDSP, - OP_C_SWSP, - OP_C_FSWSP, + OP_C_NOP, + OP_C_ADDI, + OP_C_JAL, + OP_C_LI, + OP_C_ADDI16SP, + OP_C_LUI, + OP_C_SRLI, + OP_C_SRAI, + OP_C_ANDI, + OP_C_SUB, + OP_C_XOR, + OP_C_OR, + OP_C_AND, + OP_C_J, + OP_C_BEQZ, + OP_C_BNEZ, - OP_C_ERROR -} op_C_Codes; + OP_C_SLLI, + OP_C_FLDSP, + OP_C_LWSP, + OP_C_FLWSP, + OP_C_JR, + OP_C_MV, + OP_C_EBREAK, + OP_C_JALR, + OP_C_ADD, + OP_C_FSDSP, + OP_C_SWSP, + OP_C_FSWSP, -typedef enum { - C_ADDI4SPN = 0b000, - C_FLD = 0b001, - C_LW = 0b010, - C_FLW = 0b011, - C_FSD = 0b101, - C_SW = 0b110, - C_FSW = 0b111, + OP_C_ERROR + } op_C_Codes; - C_ADDI = 0b000, - C_JAL = 0b001, - C_LI = 0b010, - C_ADDI16SP = 0b011, - C_SRLI = 0b100, - C_2_SRLI = 0b00, - C_2_SRAI = 0b01, - C_2_ANDI = 0b10, - C_2_SUB = 0b11, - C_3_SUB = 0b00, - C_3_XOR = 0b01, - C_3_OR = 0b10, - C_3_AND = 0b11, - C_J = 0b101, - C_BEQZ = 0b110, - C_BNEZ = 0b111, + typedef enum { + C_ADDI4SPN = 0b000, + C_FLD = 0b001, + C_LW = 0b010, + C_FLW = 0b011, + C_FSD = 0b101, + C_SW = 0b110, + C_FSW = 0b111, - C_SLLI = 0b000, - C_FLDSP = 0b001, - C_LWSP = 0b010, - C_FLWSP = 0b011, - C_JR = 0b100, - C_FDSP = 0b101, - C_SWSP = 0b110, - C_FWWSP = 0b111, -} C_Codes; + C_ADDI = 0b000, + C_JAL = 0b001, + C_LI = 0b010, + C_ADDI16SP = 0b011, + C_SRLI = 0b100, + C_2_SRLI = 0b00, + C_2_SRAI = 0b01, + C_2_ANDI = 0b10, + C_2_SUB = 0b11, + C_3_SUB = 0b00, + C_3_XOR = 0b01, + C_3_OR = 0b10, + C_3_AND = 0b11, + C_J = 0b101, + C_BEQZ = 0b110, + C_BNEZ = 0b111, + + C_SLLI = 0b000, + C_FLDSP = 0b001, + C_LWSP = 0b010, + C_FLWSP = 0b011, + C_JR = 0b100, + C_FDSP = 0b101, + C_SWSP = 0b110, + C_FWWSP = 0b111, + } C_Codes; /** * @brief Instruction decoding and fields access */ -class C_extension: public extension_base { -public: - - /** - * @brief Constructor, same as base clase - */ - using extension_base::extension_base; - - /** - * @brief Access to opcode field - * @return return opcode field - */ - inline std::int32_t opcode() const override { - return static_cast(m_instr.range(1, 0)); - } - - inline std::int32_t get_rdp() const { - return static_cast(m_instr.range(4, 2) + 8); - } - - /** - * @brief Access to rs1 field - * @return rs1 field - */ - inline std::int32_t get_rs1() const override { - return static_cast(m_instr.range(11, 7)); - } - - inline void set_rs1(std::int32_t value) override { - m_instr.range(11, 7) = value; - } - - inline std::int32_t get_rs1p() const { - return static_cast(m_instr.range(9, 7) + 8); - } - - /** - * @brief Access to rs2 field - * @return rs2 field - */ - inline std::int32_t get_rs2() const override { - return static_cast(m_instr.range(6, 2)); - } - - inline void set_rs2(std::int32_t value) override { - m_instr.range(6, 2) = value; - } - - inline std::int32_t get_rs2p() const { - return static_cast(m_instr.range(4, 2) + 8); - } - - inline std::int32_t get_funct3() const override { - return static_cast(m_instr.range(15, 13)); - } - - inline void set_funct3(std::int32_t value) override { - m_instr.range(15, 13) = value; - } - - /** - * @brief Access to immediate field for I-type - * @return immediate_I field - */ - inline std::int32_t get_imm_I() const { - std::int32_t aux = 0; - - aux = static_cast(m_instr.range(31, 20)); - - /* sign extension (optimize) */ - if (m_instr[31] == 1) { - aux |= (0b11111111111111111111) << 12; - } - - return aux; - } - - inline void set_imm_I(std::int32_t value) { - m_instr.range(31, 20) = value; - } - - /** - * @brief Access to immediate field for S-type - * @return immediate_S field - */ - inline std::int32_t get_imm_S() const { - std::int32_t aux = 0; - - aux = static_cast(m_instr.range(31, 25) << 5); - aux |= static_cast(m_instr.range(11, 7)); - - if (m_instr[31] == 1) { - aux |= (0b11111111111111111111) << 12; - } - - return aux; - } - - inline void set_imm_S(std::int32_t value) { - sc_dt::sc_uint<32> aux = value; - - m_instr.range(31, 25) = aux.range(11, 5); - m_instr.range(11, 7) = aux.range(4, 0); - } - - /** - * @brief Access to immediate field for U-type - * @return immediate_U field - */ - inline std::int32_t get_imm_U() const { - return static_cast(m_instr.range(31, 12)); - } - - inline void set_imm_U(std::int32_t value) { - m_instr.range(31, 12) = (value << 12); - } - - /** - * @brief Access to immediate field for B-type - * @return immediate_B field - */ - inline std::int32_t get_imm_B() const { - std::int32_t aux = 0; - - aux |= static_cast(m_instr[7] << 11); - aux |= static_cast(m_instr.range(30, 25) << 5); - aux |= static_cast(m_instr[31] << 12); - aux |= static_cast(m_instr.range(11, 8) << 1); - - if (m_instr[31] == 1) { - aux |= (0b11111111111111111111) << 12; - } - - return aux; - } - - inline void set_imm_B(std::int32_t value) { - sc_dt::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 Access to immediate field for J-type - * @return immediate_J field - */ - inline std::int32_t get_imm_J() const { - std::int32_t aux = 0; - - aux = static_cast(m_instr[12] << 11); - aux |= static_cast(m_instr[11] << 4); - aux |= static_cast(m_instr[10] << 9); - aux |= static_cast(m_instr[9] << 8); - aux |= static_cast(m_instr[8] << 10); - aux |= static_cast(m_instr[7] << 6); - aux |= static_cast(m_instr[6] << 7); - aux |= static_cast(m_instr.range(5, 3) << 1); - aux |= static_cast(m_instr[2] << 5); - - if (m_instr[12] == 1) { - aux |= 0b11111111111111111111 << 12; - } - - return aux; - } - - inline void set_imm_J(std::int32_t value) { - sc_dt::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); - } - - inline std::int32_t get_imm_L() const { - std::int32_t aux = 0; - - aux = static_cast(m_instr.range(12, 10) << 3); - aux |= static_cast(m_instr[6] << 2); - aux |= static_cast(m_instr[5] << 6); - - return aux; - } - - inline std::int32_t get_imm_LWSP() const { - std::int32_t aux = 0; - - aux = static_cast(m_instr[12] << 5); - aux |= static_cast(m_instr.range(6, 4) << 2); - aux |= static_cast(m_instr.range(3, 2) << 6); - - return aux; - } - - inline std::int32_t get_imm_ADDI () const { - std::int32_t aux = 0; - - aux = static_cast(m_instr[12] << 5); - aux |= static_cast(m_instr.range(6, 2)); - - if (m_instr[12] == 1) { - aux |= 0b11111111111111111111111111 << 6; - } - return aux; - } - - inline std::int32_t get_imm_ADDI4SPN() const { - std::int32_t aux = 0; - - aux = static_cast(m_instr.range(12, 11) << 4); - aux |= static_cast(m_instr.range(10, 7) << 6); - aux |= static_cast(m_instr[6] << 2); - aux |= static_cast(m_instr[5] << 3); - - return aux; - } - - inline std::int32_t get_imm_ADDI16SP() const { - std::int32_t aux = 0; - - aux = static_cast(m_instr[12] << 9); - aux |= static_cast(m_instr[6] << 4); - aux |= static_cast(m_instr[5] << 6); - aux |= static_cast(m_instr[4] << 8); - aux |= static_cast(m_instr[3] << 7); - aux |= static_cast(m_instr[2] << 5); - - if (m_instr[12] == 1) { - aux |= 0b1111111111111111111111 << 10; - } - return aux; - } - - inline std::int32_t get_imm_CSS() const { - std::int32_t aux = 0; - aux = static_cast(m_instr.range(12, 9) << 2); - aux |= static_cast(m_instr.range(8, 7) << 6); - - return aux; - } - - inline std::int32_t get_imm_CB() const { - std::int32_t aux = 0; - - aux = static_cast(m_instr[12] << 8); - aux |= static_cast(m_instr[11] << 4); - aux |= static_cast(m_instr[10] << 3); - aux |= static_cast(m_instr[6] << 7); - aux |= static_cast(m_instr[5] << 6); - aux |= static_cast(m_instr[4] << 2); - aux |= static_cast(m_instr[3] << 1); - aux |= static_cast(m_instr[2] << 5); - - if (m_instr[12] == 1) { - aux |= 0b11111111111111111111111 << 9; - } - - return aux; - } - - inline std::int32_t get_imm_LUI() const { - std::int32_t aux = 0; - - aux = static_cast(m_instr[12] << 17); - aux |= static_cast(m_instr.range(6, 2) << 12); - - if (m_instr[12] == 1) { - aux |= 0b111111111111111 << 17; - } - - return aux; - } - - inline std::int32_t get_csr() const { - return get_imm_I(); - } - - /** - * @brief Decodes opcode of instruction - * @return opcode of instruction - */ - op_C_Codes decode() const; - - bool Exec_C_JR(); - bool Exec_C_MV(); - bool Exec_C_LWSP(); - bool Exec_C_ADDI4SPN(); - bool Exec_C_SLLI(); - bool Exec_C_ADDI16SP(); - bool Exec_C_SWSP(); - bool Exec_C_BEQZ(); - bool Exec_C_BNEZ(); - bool Exec_C_LI(); - bool Exec_C_SRLI(); - bool Exec_C_SRAI(); - bool Exec_C_ANDI(); - bool Exec_C_ADD(); - bool Exec_C_SUB(); - bool Exec_C_XOR(); - bool Exec_C_OR(); - bool Exec_C_AND(); - - bool Exec_C_ADDI() const; - bool Exec_C_JALR(); - bool Exec_C_LW(); - bool Exec_C_SW(); - bool Exec_C_JAL(int m_rd); - bool Exec_C_EBREAK(); - - bool process_instruction(Instruction &inst, bool *breakpoint = nullptr); -}; + class C_extension : public extension_base { + public: + + /** + * @brief Constructor, same as base clase + */ + using extension_base::extension_base; + + /** + * @brief Access to opcode field + * @return return opcode field + */ + inline std::int32_t opcode() const override { + return static_cast(m_instr.range(1, 0)); + } + + inline std::int32_t get_rdp() const { + return static_cast(m_instr.range(4, 2) + 8); + } + + /** + * @brief Access to rs1 field + * @return rs1 field + */ + inline std::int32_t get_rs1() const override { + return static_cast(m_instr.range(11, 7)); + } + + inline void set_rs1(std::int32_t value) override { + m_instr.range(11, 7) = value; + } + + inline std::int32_t get_rs1p() const { + return static_cast(m_instr.range(9, 7) + 8); + } + + /** + * @brief Access to rs2 field + * @return rs2 field + */ + inline std::int32_t get_rs2() const override { + return static_cast(m_instr.range(6, 2)); + } + + inline void set_rs2(std::int32_t value) override { + m_instr.range(6, 2) = value; + } + + inline std::int32_t get_rs2p() const { + return static_cast(m_instr.range(4, 2) + 8); + } + + inline std::int32_t get_funct3() const override { + return static_cast(m_instr.range(15, 13)); + } + + inline void set_funct3(std::int32_t value) override { + m_instr.range(15, 13) = value; + } + + /** + * @brief Access to immediate field for I-type + * @return immediate_I field + */ + inline std::int32_t get_imm_I() const { + std::int32_t aux = 0; + + aux = static_cast(m_instr.range(31, 20)); + + /* sign extension (optimize) */ + if (m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + } + + return aux; + } + + inline void set_imm_I(std::int32_t value) { + m_instr.range(31, 20) = value; + } + + /** + * @brief Access to immediate field for S-type + * @return immediate_S field + */ + inline std::int32_t get_imm_S() const { + std::int32_t aux = 0; + + aux = static_cast(m_instr.range(31, 25) << 5); + aux |= static_cast(m_instr.range(11, 7)); + + if (m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + } + + return aux; + } + + inline void set_imm_S(std::int32_t value) { + sc_dt::sc_uint<32> aux = value; + + m_instr.range(31, 25) = aux.range(11, 5); + m_instr.range(11, 7) = aux.range(4, 0); + } + + /** + * @brief Access to immediate field for U-type + * @return immediate_U field + */ + inline std::int32_t get_imm_U() const { + return static_cast(m_instr.range(31, 12)); + } + + inline void set_imm_U(std::int32_t value) { + m_instr.range(31, 12) = (value << 12); + } + + /** + * @brief Access to immediate field for B-type + * @return immediate_B field + */ + inline std::int32_t get_imm_B() const { + std::int32_t aux = 0; + + aux |= static_cast(m_instr[7] << 11); + aux |= static_cast(m_instr.range(30, 25) << 5); + aux |= static_cast(m_instr[31] << 12); + aux |= static_cast(m_instr.range(11, 8) << 1); + + if (m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + } + + return aux; + } + + inline void set_imm_B(std::int32_t value) { + sc_dt::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 Access to immediate field for J-type + * @return immediate_J field + */ + inline std::int32_t get_imm_J() const { + std::int32_t aux = 0; + + aux = static_cast(m_instr[12] << 11); + aux |= static_cast(m_instr[11] << 4); + aux |= static_cast(m_instr[10] << 9); + aux |= static_cast(m_instr[9] << 8); + aux |= static_cast(m_instr[8] << 10); + aux |= static_cast(m_instr[7] << 6); + aux |= static_cast(m_instr[6] << 7); + aux |= static_cast(m_instr.range(5, 3) << 1); + aux |= static_cast(m_instr[2] << 5); + + if (m_instr[12] == 1) { + aux |= 0b11111111111111111111 << 12; + } + + return aux; + } + + inline void set_imm_J(std::int32_t value) { + sc_dt::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); + } + + inline std::int32_t get_imm_L() const { + std::int32_t aux = 0; + + aux = static_cast(m_instr.range(12, 10) << 3); + aux |= static_cast(m_instr[6] << 2); + aux |= static_cast(m_instr[5] << 6); + + return aux; + } + + inline std::int32_t get_imm_LWSP() const { + std::int32_t aux = 0; + + aux = static_cast(m_instr[12] << 5); + aux |= static_cast(m_instr.range(6, 4) << 2); + aux |= static_cast(m_instr.range(3, 2) << 6); + + return aux; + } + + inline std::int32_t get_imm_ADDI() const { + std::int32_t aux = 0; + + aux = static_cast(m_instr[12] << 5); + aux |= static_cast(m_instr.range(6, 2)); + + if (m_instr[12] == 1) { + aux |= 0b11111111111111111111111111 << 6; + } + return aux; + } + + inline std::int32_t get_imm_ADDI4SPN() const { + std::int32_t aux = 0; + + aux = static_cast(m_instr.range(12, 11) << 4); + aux |= static_cast(m_instr.range(10, 7) << 6); + aux |= static_cast(m_instr[6] << 2); + aux |= static_cast(m_instr[5] << 3); + + return aux; + } + + inline std::int32_t get_imm_ADDI16SP() const { + std::int32_t aux = 0; + + aux = static_cast(m_instr[12] << 9); + aux |= static_cast(m_instr[6] << 4); + aux |= static_cast(m_instr[5] << 6); + aux |= static_cast(m_instr[4] << 8); + aux |= static_cast(m_instr[3] << 7); + aux |= static_cast(m_instr[2] << 5); + + if (m_instr[12] == 1) { + aux |= 0b1111111111111111111111 << 10; + } + return aux; + } + + inline std::int32_t get_imm_CSS() const { + std::int32_t aux = 0; + aux = static_cast(m_instr.range(12, 9) << 2); + aux |= static_cast(m_instr.range(8, 7) << 6); + + return aux; + } + + inline std::int32_t get_imm_CB() const { + std::int32_t aux = 0; + + aux = static_cast(m_instr[12] << 8); + aux |= static_cast(m_instr[11] << 4); + aux |= static_cast(m_instr[10] << 3); + aux |= static_cast(m_instr[6] << 7); + aux |= static_cast(m_instr[5] << 6); + aux |= static_cast(m_instr[4] << 2); + aux |= static_cast(m_instr[3] << 1); + aux |= static_cast(m_instr[2] << 5); + + if (m_instr[12] == 1) { + aux |= 0b11111111111111111111111 << 9; + } + + return aux; + } + + inline std::int32_t get_imm_LUI() const { + std::int32_t aux = 0; + + aux = static_cast(m_instr[12] << 17); + aux |= static_cast(m_instr.range(6, 2) << 12); + + if (m_instr[12] == 1) { + aux |= 0b111111111111111 << 17; + } + + return aux; + } + + inline std::int32_t get_csr() const { + return get_imm_I(); + } + + /** + * @brief Decodes opcode of instruction + * @return opcode of instruction + */ + op_C_Codes decode() const; + + bool Exec_C_JR(); + + bool Exec_C_MV(); + + bool Exec_C_LWSP(); + + bool Exec_C_ADDI4SPN(); + + bool Exec_C_SLLI(); + + bool Exec_C_ADDI16SP(); + + bool Exec_C_SWSP(); + + bool Exec_C_BEQZ(); + + bool Exec_C_BNEZ(); + + bool Exec_C_LI(); + + bool Exec_C_SRLI(); + + bool Exec_C_SRAI(); + + bool Exec_C_ANDI(); + + bool Exec_C_ADD(); + + bool Exec_C_SUB(); + + bool Exec_C_XOR(); + + bool Exec_C_OR(); + + bool Exec_C_AND(); + + bool Exec_C_ADDI() const; + + bool Exec_C_JALR(); + + bool Exec_C_LW(); + + bool Exec_C_SW(); + + bool Exec_C_JAL(int m_rd); + + bool Exec_C_EBREAK(); + + bool process_instruction(Instruction &inst, bool *breakpoint = nullptr); + }; +} #endif diff --git a/inc/Instruction.h b/inc/Instruction.h index da29a19..fefb306 100644 --- a/inc/Instruction.h +++ b/inc/Instruction.h @@ -12,54 +12,58 @@ #include "systemc" #include "extension_base.h" -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; +namespace riscv_tlm { + + 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; /** * @brief Instruction decoding and fields access */ -class Instruction { -public: + class Instruction { + public: - Instruction(std::uint32_t instr); + Instruction(std::uint32_t instr); - /** - * @brief returns what instruction extension - * @return extension - */ - extension_t check_extension() const; + /** + * @brief returns what instruction extension + * @return extension + */ + extension_t check_extension() const; - void setInstr(std::uint32_t p_instr) { - m_instr = p_instr; - } - /** - * @brief return instruction - * @return all instruction bits (31:0) - */ - std::uint32_t getInstr() { - return m_instr; - } + void setInstr(std::uint32_t p_instr) { + m_instr = p_instr; + } - inline void dump() { - std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; - } + /** + * @brief return instruction + * @return all instruction bits (31:0) + */ + std::uint32_t getInstr() { + return m_instr; + } -private: - std::uint32_t m_instr; -}; + inline void dump() { + std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; + } + + private: + std::uint32_t m_instr; + }; +} #endif diff --git a/inc/M_extension.h b/inc/M_extension.h index 3751f5b..f1db0d4 100644 --- a/inc/M_extension.h +++ b/inc/M_extension.h @@ -14,72 +14,82 @@ #include "extension_base.h" #include "Registers.h" -typedef enum { - OP_M_MUL, - OP_M_MULH, - OP_M_MULHSU, - OP_M_MULHU, - OP_M_DIV, - OP_M_DIVU, - OP_M_REM, - OP_M_REMU, +namespace riscv_tlm { - OP_M_ERROR -} op_M_Codes; + typedef enum { + OP_M_MUL, + OP_M_MULH, + OP_M_MULHSU, + OP_M_MULHU, + OP_M_DIV, + OP_M_DIVU, + OP_M_REM, + OP_M_REMU, -typedef enum { - M_MUL = 0b000, - M_MULH = 0b001, - M_MULHSU = 0b010, - M_MULHU = 0b011, - M_DIV = 0b100, - M_DIVU = 0b101, - M_REM = 0b110, - M_REMU = 0b111, -} M_Codes; + OP_M_ERROR + } op_M_Codes; + + typedef enum { + M_MUL = 0b000, + M_MULH = 0b001, + M_MULHSU = 0b010, + M_MULHU = 0b011, + M_DIV = 0b100, + M_DIVU = 0b101, + M_REM = 0b110, + M_REMU = 0b111, + } M_Codes; /** * @brief Instruction decoding and fields access */ -class M_extension: public extension_base { -public: + class M_extension : public extension_base { + public: - /** - * @brief Constructor, same as base clase - */ - using extension_base::extension_base; + /** + * @brief Constructor, same as base clase + */ + using extension_base::extension_base; - /** - * @brief Decodes opcode of instruction - * @return opcode of instruction - */ - op_M_Codes decode() const; + /** + * @brief Decodes opcode of instruction + * @return opcode of instruction + */ + op_M_Codes decode() const; - inline void dump() const override { - std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; - } + inline void dump() const override { + std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; + } - bool Exec_M_MUL() const; - bool Exec_M_MULH() const; - bool Exec_M_MULHSU() const; - bool Exec_M_MULHU() const; - bool Exec_M_DIV() const; - bool Exec_M_DIVU() const; - bool Exec_M_REM() const; - bool Exec_M_REMU() const; + bool Exec_M_MUL() const; - bool process_instruction(Instruction &inst); + bool Exec_M_MULH() const; -private: + bool Exec_M_MULHSU() const; - /** - * @brief Access to opcode field - * @return return opcode field - */ - inline std::int32_t opcode() const override { - return static_cast(m_instr.range(14, 12)); - } + bool Exec_M_MULHU() const; -}; + bool Exec_M_DIV() const; + + bool Exec_M_DIVU() const; + + bool Exec_M_REM() const; + + bool Exec_M_REMU() const; + + bool process_instruction(Instruction &inst); + + private: + + /** + * @brief Access to opcode field + * @return return opcode field + */ + inline std::int32_t opcode() const override { + return static_cast(m_instr.range(14, 12)); + } + + }; +} #endif diff --git a/inc/Memory.h b/inc/Memory.h index 23b3d61..95b154c 100644 --- a/inc/Memory.h +++ b/inc/Memory.h @@ -21,72 +21,76 @@ #include "spdlog/spdlog.h" #include "spdlog/sinks/basic_file_sink.h" + +namespace riscv_tlm { /** * @brief Basic TLM-2 memory */ -class Memory: sc_core::sc_module { -public: - // TLM-2 socket, defaults to 32-bits wide, base protocol - tlm_utils::simple_target_socket socket; + class Memory : sc_core::sc_module { + public: + // TLM-2 socket, defaults to 32-bits wide, base protocol + tlm_utils::simple_target_socket socket; - /* 16 MBytes */ - enum { - SIZE = 0x1000000 - }; - const sc_core::sc_time LATENCY; + /* 16 MBytes */ + enum { + SIZE = 0x1000000 + }; + const sc_core::sc_time LATENCY; - Memory(sc_core::sc_module_name const &name, std::string const &filename); - explicit Memory(const sc_core::sc_module_name& name); + Memory(sc_core::sc_module_name const &name, std::string const &filename); - ~Memory() override; + explicit Memory(const sc_core::sc_module_name &name); - /** - * @brief Returns Program Counter read from hexfile - * @return Initial PC - */ - virtual std::uint32_t getPCfromHEX(); + ~Memory() override; - // TLM-2 blocking transport method - virtual void b_transport(tlm::tlm_generic_payload &trans, - sc_core::sc_time &delay); + /** + * @brief Returns Program Counter read from hexfile + * @return Initial PC + */ + virtual std::uint32_t getPCfromHEX(); - // ********************************************* - // TLM-2 forward DMI method - // ********************************************* - virtual bool get_direct_mem_ptr(tlm::tlm_generic_payload &trans, - tlm::tlm_dmi &dmi_data); + // TLM-2 blocking transport method + virtual void b_transport(tlm::tlm_generic_payload &trans, + sc_core::sc_time &delay); - // ********************************************* - // TLM-2 debug transport method - // ********************************************* - virtual unsigned int transport_dbg(tlm::tlm_generic_payload &trans); + // ********************************************* + // TLM-2 forward DMI method + // ********************************************* + virtual bool get_direct_mem_ptr(tlm::tlm_generic_payload &trans, + tlm::tlm_dmi &dmi_data); -private: + // ********************************************* + // TLM-2 debug transport method + // ********************************************* + virtual unsigned int transport_dbg(tlm::tlm_generic_payload &trans); - /** - * @brief Memory array in bytes - */ - std::array mem{}; + private: - /** - * @brief Log class - */ - std::shared_ptr logger; + /** + * @brief Memory array in bytes + */ + std::array mem{}; - /** - * @brief Program counter (PC) read from hex file - */ - std::uint32_t program_counter; + /** + * @brief Log class + */ + std::shared_ptr logger; - /** - * @brief DMI can be used? - */ - bool dmi_allowed; + /** + * @brief Program counter (PC) read from hex file + */ + std::uint32_t program_counter; - /** - * @brief Read Intel hex file - * @param filename file name to read - */ - void readHexFile(const std::string& filename); -}; + /** + * @brief DMI can be used? + */ + bool dmi_allowed; + + /** + * @brief Read Intel hex file + * @param filename file name to read + */ + void readHexFile(const std::string &filename); + }; +} #endif /* __MEMORY_H__ */ diff --git a/inc/MemoryInterface.h b/inc/MemoryInterface.h index 5ab8afa..c9f22a2 100644 --- a/inc/MemoryInterface.h +++ b/inc/MemoryInterface.h @@ -17,17 +17,21 @@ #include "memory.h" +namespace riscv_tlm { + /** * @brief Memory Interface */ -class MemoryInterface { -public: + class MemoryInterface { + public: - tlm_utils::simple_initiator_socket data_bus; + tlm_utils::simple_initiator_socket data_bus; - MemoryInterface(); - std::uint32_t readDataMem(std::uint32_t addr, int size); - void writeDataMem(std::uint32_t addr, std::uint32_t data, int size); -}; + MemoryInterface(); + std::uint32_t readDataMem(std::uint32_t addr, int size); + + void writeDataMem(std::uint32_t addr, std::uint32_t data, int size); + }; +} #endif /* INC_MEMORYINTERFACE_H_ */ diff --git a/inc/Registers.h b/inc/Registers.h index c0bf58f..d9e4a38 100644 --- a/inc/Registers.h +++ b/inc/Registers.h @@ -19,6 +19,8 @@ #include "Performance.h" #include "Memory.h" +namespace riscv_tlm { + #define MISA_A_EXTENSION (1 << 0) #define MISA_B_EXTENSION (1 << 1) #define MISA_C_EXTENSION (1 << 2) @@ -76,7 +78,7 @@ #define MSTATUS_SPP (1 << 8) #define MSTATUS_MPP (1 << 11) #define MSTATUS_FS (1 << 13) -#define MSTATUS_XS (1 << 15) +#define MSTATUS_XS (1 << 15) #define MSTATUS_MPRV (1 << 17) #define MSTATUS_SUM (1 << 18) #define MSTATUS_MXR (1 << 19) @@ -110,156 +112,158 @@ /** * @brief Register file implementation */ -class Registers { -public: + class Registers { + public: - enum { - x0 = 0, - x1 = 1, - x2, - x3, - x4, - x5, - x6, - x7, - x8, - x9, - x10, - x11, - x12, - x13, - x14, - x15, - x16, - x17, - x18, - x19, - x20, - x21, - x22, - x23, - x24, - x25, - x26, - x27, - x28, - x29, - x30, - x31, - zero = x0, - ra = x1, - sp = x2, - gp = x3, - tp = x4, - t0 = x5, - t1 = x6, - t2 = x7, - s0 = x8, - fp = x8, - s1 = x9, - a0 = x10, - a1 = x11, - a2 = x12, - a3 = x13, - a4 = x14, - a5 = x15, - a6 = x16, - a7 = x17, - s2 = x18, - s3 = x19, - s4 = x20, - s5 = x21, - s6 = x22, - s7 = x23, - s8 = x24, - s9 = x25, - s10 = x26, - s11 = x27, - t3 = x28, - t4 = x29, - t5 = x30, - t6 = x31 - }; - /** - * Default constructor - */ - Registers(); + enum { + x0 = 0, + x1 = 1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15, + x16, + x17, + x18, + x19, + x20, + x21, + x22, + x23, + x24, + x25, + x26, + x27, + x28, + x29, + x30, + x31, + zero = x0, + ra = x1, + sp = x2, + gp = x3, + tp = x4, + t0 = x5, + t1 = x6, + t2 = x7, + s0 = x8, + fp = x8, + s1 = x9, + a0 = x10, + a1 = x11, + a2 = x12, + a3 = x13, + a4 = x14, + a5 = x15, + a6 = x16, + a7 = x17, + s2 = x18, + s3 = x19, + s4 = x20, + s5 = x21, + s6 = x22, + s7 = x23, + s8 = x24, + s9 = x25, + s10 = x26, + s11 = x27, + t3 = x28, + t4 = x29, + t5 = x30, + t6 = x31 + }; - /** - * Set value for a register - * @param reg_num register number - * @param value register value - */ - void setValue(int reg_num, std::int32_t value); + /** + * Default constructor + */ + Registers(); - /** - * Returns register value - * @param reg_num register number - * @return register value - */ - std::uint32_t getValue(int reg_num) const; + /** + * Set value for a register + * @param reg_num register number + * @param value register value + */ + void setValue(int reg_num, std::int32_t value); - /** - * Returns PC value - * @return PC value - */ - std::uint32_t getPC() const; + /** + * Returns register value + * @param reg_num register number + * @return register value + */ + std::uint32_t getValue(int reg_num) const; - /** - * Sets arbitraty value to PC - * @param new_pc new address to PC - */ - void setPC(std::uint32_t new_pc); + /** + * Returns PC value + * @return PC value + */ + std::uint32_t getPC() const; - /** - * Increments PC couunter to next address - */ - inline void incPC() { - register_PC += 4; - } + /** + * Sets arbitraty value to PC + * @param new_pc new address to PC + */ + void setPC(std::uint32_t new_pc); - inline void incPCby2() { - register_PC += 2; - } + /** + * Increments PC couunter to next address + */ + inline void incPC() { + register_PC += 4; + } - /** - * @brief Get CSR value - * @param csr CSR number to access - * @return CSR value - */ - std::uint32_t getCSR(int csr); + inline void incPCby2() { + register_PC += 2; + } - /** - * @brief Set CSR value - * @param csr CSR number to access - * @param value new value to register - */ - void setCSR(int csr, std::uint32_t value); + /** + * @brief Get CSR value + * @param csr CSR number to access + * @return CSR value + */ + std::uint32_t getCSR(int csr); - /** - * Dump register data to console - */ - void dump(); -private: - /** - * bank of registers (32 regs of 32bits each) - */ - std::array register_bank = { {0} }; + /** + * @brief Set CSR value + * @param csr CSR number to access + * @param value new value to register + */ + void setCSR(int csr, std::uint32_t value); - /** - * Program counter (32 bits width) - */ - std::uint32_t register_PC; + /** + * Dump register data to console + */ + void dump(); - /** - * CSR registers (4096 maximum) - */ - std::unordered_map CSR; + private: + /** + * bank of registers (32 regs of 32bits each) + */ + std::array register_bank = {{0}}; + + /** + * Program counter (32 bits width) + */ + std::uint32_t register_PC; + + /** + * CSR registers (4096 maximum) + */ + std::unordered_map CSR; - Performance *perf; - - void initCSR(); -}; + Performance *perf; + void initCSR(); + }; +} #endif diff --git a/inc/Timer.h b/inc/Timer.h index 6068941..331af38 100644 --- a/inc/Timer.h +++ b/inc/Timer.h @@ -21,50 +21,51 @@ #include "BusCtrl.h" +namespace riscv_tlm::peripherals { /** * @brief Simple timer peripheral * * It runs a 1 ns (nanoseconds) pace * */ -class Timer: sc_core::sc_module { -public: - // TLM-2 socket, defaults to 32-bits wide, base protocol - tlm_utils::simple_target_socket socket; + class Timer : sc_core::sc_module { + public: + // TLM-2 socket, defaults to 32-bits wide, base protocol + tlm_utils::simple_target_socket socket; - tlm_utils::simple_initiator_socket irq_line; + tlm_utils::simple_initiator_socket irq_line; - /** - * - * @brief Constructor - * @param name module name - */ - explicit Timer(sc_core::sc_module_name const &name); + /** + * + * @brief Constructor + * @param name module name + */ + explicit Timer(sc_core::sc_module_name const &name); - /** - * @brief Waits for event timer_event and triggers an IRQ - * - * Waits for event timer_event and triggers an IRQ (if it is not already - * triggered). - * After that, it posts the timer_event to 20 ns in the future to clear the IRQ - * line. - * - */ - [[noreturn]] void run(); + /** + * @brief Waits for event timer_event and triggers an IRQ + * + * Waits for event timer_event and triggers an IRQ (if it is not already + * triggered). + * After that, it posts the timer_event to 20 ns in the future to clear the IRQ + * line. + * + */ + [[noreturn]] void run(); - /** - * - * @brief TLM-2.0 socket implementation - * @param trans TLM-2.0 transaction - * @param delay transaction delay time - */ - virtual void b_transport(tlm::tlm_generic_payload &trans, - sc_core::sc_time &delay); - -private: - sc_dt::sc_uint<64> m_mtime; /**< mtime register */ - sc_dt::sc_uint<64> m_mtimecmp; /**< mtimecmp register */ - sc_core::sc_event timer_event; /**< event */ -}; + /** + * + * @brief TLM-2.0 socket implementation + * @param trans TLM-2.0 transaction + * @param delay transaction delay time + */ + virtual void b_transport(tlm::tlm_generic_payload &trans, + sc_core::sc_time &delay); + private: + sc_dt::sc_uint<64> m_mtime; /**< mtime register */ + sc_dt::sc_uint<64> m_mtimecmp; /**< mtimecmp register */ + sc_core::sc_event timer_event; /**< event */ + }; +} #endif diff --git a/inc/Trace.h b/inc/Trace.h index 0c32c87..1ef2fcb 100644 --- a/inc/Trace.h +++ b/inc/Trace.h @@ -19,43 +19,46 @@ #include "tlm.h" #include "tlm_utils/simple_target_socket.h" +namespace riscv_tlm::peripherals { /** * @brief Simple trace peripheral * * This peripheral outputs to cout any character written to its unique register */ -class Trace: sc_core::sc_module { -public: + class Trace : sc_core::sc_module { + public: - /** - * @brief Bus socket - */ - tlm_utils::simple_target_socket socket; + /** + * @brief Bus socket + */ + tlm_utils::simple_target_socket socket; - /** - * @brief Constructor - * @param name Module name - */ - explicit Trace(sc_core::sc_module_name const &name); + /** + * @brief Constructor + * @param name Module name + */ + explicit Trace(sc_core::sc_module_name const &name); - /** - * @brief Destructor - */ - ~Trace() override; + /** + * @brief Destructor + */ + ~Trace() override; -private: + private: - // TLM-2 blocking transport method - virtual void b_transport(tlm::tlm_generic_payload &trans, - sc_core::sc_time &delay); + // TLM-2 blocking transport method + virtual void b_transport(tlm::tlm_generic_payload &trans, + sc_core::sc_time &delay); - void xtermLaunch(char *slaveName) const; - void xtermKill(); - void xtermSetup(); + void xtermLaunch(char *slaveName) const; - int ptSlave{}; - int ptMaster{}; - int xtermPid{}; -}; + void xtermKill(); + void xtermSetup(); + + int ptSlave{}; + int ptMaster{}; + int xtermPid{}; + }; +} #endif diff --git a/inc/extension_base.h b/inc/extension_base.h index c994b5e..2b2ffe9 100644 --- a/inc/extension_base.h +++ b/inc/extension_base.h @@ -26,60 +26,66 @@ #define EXCEPTION_CAUSE_LOAD_ADDR_MISALIGN 4 #define EXCEPTION_CAUSE_LOAD_ACCESS_FAULT 5 -class extension_base { +namespace riscv_tlm { -public: - extension_base(const sc_dt::sc_uint<32> & instr, Registers *register_bank, - MemoryInterface *mem_interface); - virtual ~extension_base() = 0; + class extension_base { - void setInstr(std::uint32_t p_instr); - void RaiseException(std::uint32_t cause, std::uint32_t inst); - bool NOP(); + public: + extension_base(const sc_dt::sc_uint<32> &instr, Registers *register_bank, + MemoryInterface *mem_interface); - /* pure virtual functions */ - virtual std::int32_t opcode() const = 0; + virtual ~extension_base() = 0; - virtual std::int32_t get_rd() const { - return m_instr.range(11, 7); - } + void setInstr(std::uint32_t p_instr); - virtual void set_rd(std::int32_t value) { - m_instr.range(11, 7) = value; - } + void RaiseException(std::uint32_t cause, std::uint32_t inst); - virtual std::int32_t get_rs1() const { - return m_instr.range(19, 15); - } + bool NOP(); - virtual void set_rs1(std::int32_t value) { - m_instr.range(19, 15) = value; - } + /* pure virtual functions */ + virtual std::int32_t opcode() const = 0; - virtual std::int32_t get_rs2() const { - return m_instr.range(24, 20); - } + virtual std::int32_t get_rd() const { + return m_instr.range(11, 7); + } - virtual void set_rs2(std::int32_t value) { - m_instr.range(24, 20) = value; - } + virtual void set_rd(std::int32_t value) { + m_instr.range(11, 7) = value; + } - virtual std::int32_t get_funct3() const { - return m_instr.range(14, 12); - } + virtual std::int32_t get_rs1() const { + return m_instr.range(19, 15); + } - virtual void set_funct3(std::int32_t value) { - m_instr.range(14, 12) = value; - } + virtual void set_rs1(std::int32_t value) { + m_instr.range(19, 15) = value; + } - virtual void dump() const; + virtual std::int32_t get_rs2() const { + return m_instr.range(24, 20); + } -protected: - sc_dt::sc_uint<32> m_instr; - Registers *regs; - Performance *perf; - MemoryInterface *mem_intf; - std::shared_ptr logger; -}; + virtual void set_rs2(std::int32_t value) { + m_instr.range(24, 20) = value; + } + + virtual std::int32_t get_funct3() const { + return m_instr.range(14, 12); + } + + virtual void set_funct3(std::int32_t value) { + m_instr.range(14, 12) = value; + } + + virtual void dump() const; + + protected: + sc_dt::sc_uint<32> m_instr; + Registers *regs; + Performance *perf; + MemoryInterface *mem_intf; + std::shared_ptr logger; + }; +} #endif /* INC_EXTENSION_BASE_H_ */ diff --git a/src/A_extension.cpp b/src/A_extension.cpp index 8d8d455..b603772 100644 --- a/src/A_extension.cpp +++ b/src/A_extension.cpp @@ -8,429 +8,438 @@ #include "A_extension.h" -op_A_Codes A_extension::decode() const { - - switch (opcode()) { - case A_LR: - return OP_A_LR; - break; - case A_SC: - return OP_A_SC; - break; - case A_AMOSWAP: - return OP_A_AMOSWAP; - break; - case A_AMOADD: - return OP_A_AMOADD; - break; - case A_AMOXOR: - return OP_A_AMOXOR; - break; - case A_AMOAND: - return OP_A_AMOAND; - break; - case A_AMOOR: - return OP_A_AMOOR; - break; - case A_AMOMIN: - return OP_A_AMOMIN; - break; - case A_AMOMAX: - return OP_A_AMOMAX; - break; - case A_AMOMINU: - return OP_A_AMOMINU; - break; - case A_AMOMAXU: - return OP_A_AMOMAXU; - break; - [[unlikely]] default: - return OP_A_ERROR; - break; - - } - - return OP_A_ERROR; -} - -bool A_extension::Exec_A_LR() { - std::uint32_t mem_addr = 0; - int rd, rs1, rs2; - std::uint32_t data; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (rs2 != 0) { - std::cout << "ILEGAL INSTRUCTION, LR.W: rs2 != 0" << std::endl; - RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr); - - return false; - } - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); - - TLB_reserve(mem_addr); - - logger->debug("{} ns. PC: 0x{:x}. A.LR.W: x{:d}(0x{:x}) -> x{:d}(0x{:x}) ", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, mem_addr, rd, data); - - return true; -} - -bool A_extension::Exec_A_SC() { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = regs->getValue(rs2); - - if (TLB_reserved(mem_addr)) { - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); - regs->setValue(rd, 0); // SC writes 0 to rd on success - } else { - regs->setValue(rd, 1); // SC writes nonzero on failure - } - - logger->debug("{} ns. PC: 0x{:x}. A.SC.W: (0x{:x}) <- x{:d}(0x{:x}) ", sc_core::sc_time_stamp().value(), regs->getPC(), - mem_addr, rs2, data); - - return true; -} - -bool A_extension::Exec_A_AMOSWAP() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - std::uint32_t aux; - - /* These instructions must be atomic */ - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); +namespace riscv_tlm { + + op_A_Codes A_extension::decode() const { + + switch (opcode()) { + case A_LR: + return OP_A_LR; + break; + case A_SC: + return OP_A_SC; + break; + case A_AMOSWAP: + return OP_A_AMOSWAP; + break; + case A_AMOADD: + return OP_A_AMOADD; + break; + case A_AMOXOR: + return OP_A_AMOXOR; + break; + case A_AMOAND: + return OP_A_AMOAND; + break; + case A_AMOOR: + return OP_A_AMOOR; + break; + case A_AMOMIN: + return OP_A_AMOMIN; + break; + case A_AMOMAX: + return OP_A_AMOMAX; + break; + case A_AMOMINU: + return OP_A_AMOMINU; + break; + case A_AMOMAXU: + return OP_A_AMOMAXU; + break; + [[unlikely]] default: + return OP_A_ERROR; + break; + + } + + return OP_A_ERROR; + } + + bool A_extension::Exec_A_LR() { + std::uint32_t mem_addr = 0; + int rd, rs1, rs2; + std::uint32_t data; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + if (rs2 != 0) { + std::cout << "ILEGAL INSTRUCTION, LR.W: rs2 != 0" << std::endl; + RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr); + + return false; + } + + mem_addr = regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 4); + perf->dataMemoryRead(); + regs->setValue(rd, static_cast(data)); + + TLB_reserve(mem_addr); + + logger->debug("{} ns. PC: 0x{:x}. A.LR.W: x{:d}(0x{:x}) -> x{:d}(0x{:x}) ", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, mem_addr, rd, data); + + return true; + } + + bool A_extension::Exec_A_SC() { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + mem_addr = regs->getValue(rs1); + data = regs->getValue(rs2); + + if (TLB_reserved(mem_addr)) { + mem_intf->writeDataMem(mem_addr, data, 4); + perf->dataMemoryWrite(); + regs->setValue(rd, 0); // SC writes 0 to rd on success + } else { + regs->setValue(rd, 1); // SC writes nonzero on failure + } + + logger->debug("{} ns. PC: 0x{:x}. A.SC.W: (0x{:x}) <- x{:d}(0x{:x}) ", sc_core::sc_time_stamp().value(), + regs->getPC(), + mem_addr, rs2, data); + + return true; + } + + bool A_extension::Exec_A_AMOSWAP() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + std::uint32_t aux; + + /* These instructions must be atomic */ - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - // swap - aux = regs->getValue(rs2); - regs->setValue(rs2, static_cast(data)); + mem_addr = regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 4); + perf->dataMemoryRead(); + regs->setValue(rd, static_cast(data)); - mem_intf->writeDataMem(mem_addr, aux, 4); - perf->dataMemoryWrite(); + // swap + aux = regs->getValue(rs2); + regs->setValue(rs2, static_cast(data)); - logger->debug("{} ns. PC: 0x{:x}. A.AMOSWAP"); + mem_intf->writeDataMem(mem_addr, aux, 4); + perf->dataMemoryWrite(); - return true; -} + logger->debug("{} ns. PC: 0x{:x}. A.AMOSWAP"); -bool A_extension::Exec_A_AMOADD() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; + return true; + } - /* These instructions must be atomic */ + bool A_extension::Exec_A_AMOADD() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + /* These instructions must be atomic */ - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - regs->setValue(rd, static_cast(data)); + mem_addr = regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 4); + perf->dataMemoryRead(); - // add - data = data + regs->getValue(rs2); + regs->setValue(rd, static_cast(data)); - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); + // add + data = data + regs->getValue(rs2); - logger->debug("{} ns. PC: 0x{:x}. A.AMOADD"); + mem_intf->writeDataMem(mem_addr, data, 4); + perf->dataMemoryWrite(); - return true; -} + logger->debug("{} ns. PC: 0x{:x}. A.AMOADD"); -bool A_extension::Exec_A_AMOXOR() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; + return true; + } - /* These instructions must be atomic */ + bool A_extension::Exec_A_AMOXOR() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + /* These instructions must be atomic */ - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - regs->setValue(rd, static_cast(data)); + mem_addr = regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 4); + perf->dataMemoryRead(); - // add - data = data ^ regs->getValue(rs2); + regs->setValue(rd, static_cast(data)); - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); + // add + data = data ^ regs->getValue(rs2); - logger->debug("{} ns. PC: 0x{:x}. A.AMOXOR"); + mem_intf->writeDataMem(mem_addr, data, 4); + perf->dataMemoryWrite(); - return true; -} -bool A_extension::Exec_A_AMOAND() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; + logger->debug("{} ns. PC: 0x{:x}. A.AMOXOR"); - /* These instructions must be atomic */ + return true; + } - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + bool A_extension::Exec_A_AMOAND() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); + /* These instructions must be atomic */ - regs->setValue(rd, static_cast(data)); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - // add - data = data & regs->getValue(rs2); + mem_addr = regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 4); + perf->dataMemoryRead(); - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); + regs->setValue(rd, static_cast(data)); - logger->debug("{} ns. PC: 0x{:x}. A.AMOAND"); + // add + data = data & regs->getValue(rs2); - return true; -} + mem_intf->writeDataMem(mem_addr, data, 4); + perf->dataMemoryWrite(); -bool A_extension::Exec_A_AMOOR() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; + logger->debug("{} ns. PC: 0x{:x}. A.AMOAND"); - /* These instructions must be atomic */ + return true; + } - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + bool A_extension::Exec_A_AMOOR() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); + /* These instructions must be atomic */ - regs->setValue(rd, static_cast(data)); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - // add - data = data | regs->getValue(rs2); + mem_addr = regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 4); + perf->dataMemoryRead(); - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); + regs->setValue(rd, static_cast(data)); - logger->debug("{} ns. PC: 0x{:x}. A.AMOOR"); + // add + data = data | regs->getValue(rs2); - return true; -} + mem_intf->writeDataMem(mem_addr, data, 4); + perf->dataMemoryWrite(); -bool A_extension::Exec_A_AMOMIN() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - std::uint32_t aux; + logger->debug("{} ns. PC: 0x{:x}. A.AMOOR"); - /* These instructions must be atomic */ + return true; + } - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + bool A_extension::Exec_A_AMOMIN() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + std::uint32_t aux; - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); + /* These instructions must be atomic */ - regs->setValue(rd, static_cast(data)); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - // min - aux = regs->getValue(rs2); - if ((int32_t) data < (int32_t) aux) { - aux = data; - } + mem_addr = regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 4); + perf->dataMemoryRead(); - mem_intf->writeDataMem(mem_addr, aux, 4); - perf->dataMemoryWrite(); + regs->setValue(rd, static_cast(data)); - logger->debug("{} ns. PC: 0x{:x}. A.AMOMIN"); + // min + aux = regs->getValue(rs2); + if ((int32_t) data < (int32_t) aux) { + aux = data; + } - return true; -} -bool A_extension::Exec_A_AMOMAX() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - std::uint32_t aux; + mem_intf->writeDataMem(mem_addr, aux, 4); + perf->dataMemoryWrite(); - /* These instructions must be atomic */ + logger->debug("{} ns. PC: 0x{:x}. A.AMOMIN"); - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + return true; + } - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); + bool A_extension::Exec_A_AMOMAX() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + std::uint32_t aux; - regs->setValue(rd, static_cast(data)); + /* These instructions must be atomic */ - // > - aux = regs->getValue(rs2); - if ((int32_t) data > (int32_t) aux) { - aux = data; - } + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - mem_intf->writeDataMem(mem_addr, aux, 4); - perf->dataMemoryWrite(); + mem_addr = regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 4); + perf->dataMemoryRead(); - logger->debug("{} ns. PC: 0x{:x}. A.AMOMAX"); + regs->setValue(rd, static_cast(data)); - return true; -} -bool A_extension::Exec_A_AMOMINU() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - std::uint32_t aux; - - /* These instructions must be atomic */ - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // min - aux = regs->getValue(rs2); - if (data < aux) { - aux = data; - } - - mem_intf->writeDataMem(mem_addr, aux, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOMINU"); - - return true; -} -bool A_extension::Exec_A_AMOMAXU() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - std::uint32_t aux; - - /* These instructions must be atomic */ - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // max - aux = regs->getValue(rs2); - if (data > aux) { - aux = data; - } - - mem_intf->writeDataMem(mem_addr, aux, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOMAXU"); - - return true; -} - -void A_extension::TLB_reserve(std::uint32_t address) { - TLB_A_Entries.insert(address); -} - -bool A_extension::TLB_reserved(std::uint32_t address) { - if (TLB_A_Entries.count(address) == 1) { - TLB_A_Entries.erase(address); - return true; - } else { - return false; - } -} - -bool A_extension::process_instruction(Instruction &inst) { - bool PC_not_affected = true; - - setInstr(inst.getInstr()); - - switch (decode()) { - case OP_A_LR: - Exec_A_LR(); - break; - case OP_A_SC: - Exec_A_SC(); - break; - case OP_A_AMOSWAP: - Exec_A_AMOSWAP(); - break; - case OP_A_AMOADD: - Exec_A_AMOADD(); - break; - case OP_A_AMOXOR: - Exec_A_AMOXOR(); - break; - case OP_A_AMOAND: - Exec_A_AMOAND(); - break; - case OP_A_AMOOR: - Exec_A_AMOOR(); - break; - case OP_A_AMOMIN: - Exec_A_AMOMIN(); - break; - case OP_A_AMOMAX: - Exec_A_AMOMAX(); - break; - case OP_A_AMOMINU: - Exec_A_AMOMINU(); - break; - case OP_A_AMOMAXU: - Exec_A_AMOMAXU(); - break; - [[unlikely]] default: - std::cout << "A instruction not implemented yet" << std::endl; - inst.dump(); - NOP(); - break; - } - - return PC_not_affected; -} + // > + aux = regs->getValue(rs2); + if ((int32_t) data > (int32_t) aux) { + aux = data; + } + + mem_intf->writeDataMem(mem_addr, aux, 4); + perf->dataMemoryWrite(); + + logger->debug("{} ns. PC: 0x{:x}. A.AMOMAX"); + + return true; + } + + bool A_extension::Exec_A_AMOMINU() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + std::uint32_t aux; + + /* These instructions must be atomic */ + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + mem_addr = regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 4); + perf->dataMemoryRead(); + + regs->setValue(rd, static_cast(data)); + + // min + aux = regs->getValue(rs2); + if (data < aux) { + aux = data; + } + + mem_intf->writeDataMem(mem_addr, aux, 4); + perf->dataMemoryWrite(); + + logger->debug("{} ns. PC: 0x{:x}. A.AMOMINU"); + + return true; + } + + bool A_extension::Exec_A_AMOMAXU() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + std::uint32_t aux; + + /* These instructions must be atomic */ + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + mem_addr = regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 4); + perf->dataMemoryRead(); + + regs->setValue(rd, static_cast(data)); + + // max + aux = regs->getValue(rs2); + if (data > aux) { + aux = data; + } + + mem_intf->writeDataMem(mem_addr, aux, 4); + perf->dataMemoryWrite(); + + logger->debug("{} ns. PC: 0x{:x}. A.AMOMAXU"); + + return true; + } + + void A_extension::TLB_reserve(std::uint32_t address) { + TLB_A_Entries.insert(address); + } + + bool A_extension::TLB_reserved(std::uint32_t address) { + if (TLB_A_Entries.count(address) == 1) { + TLB_A_Entries.erase(address); + return true; + } else { + return false; + } + } + + bool A_extension::process_instruction(Instruction &inst) { + bool PC_not_affected = true; + + setInstr(inst.getInstr()); + + switch (decode()) { + case OP_A_LR: + Exec_A_LR(); + break; + case OP_A_SC: + Exec_A_SC(); + break; + case OP_A_AMOSWAP: + Exec_A_AMOSWAP(); + break; + case OP_A_AMOADD: + Exec_A_AMOADD(); + break; + case OP_A_AMOXOR: + Exec_A_AMOXOR(); + break; + case OP_A_AMOAND: + Exec_A_AMOAND(); + break; + case OP_A_AMOOR: + Exec_A_AMOOR(); + break; + case OP_A_AMOMIN: + Exec_A_AMOMIN(); + break; + case OP_A_AMOMAX: + Exec_A_AMOMAX(); + break; + case OP_A_AMOMINU: + Exec_A_AMOMINU(); + break; + case OP_A_AMOMAXU: + Exec_A_AMOMAXU(); + break; + [[unlikely]] default: + std::cout << "A instruction not implemented yet" << std::endl; + inst.dump(); + NOP(); + break; + } + + return PC_not_affected; + } +} \ No newline at end of file diff --git a/src/BASE_ISA.cpp b/src/BASE_ISA.cpp index 89ea383..8ca35bb 100644 --- a/src/BASE_ISA.cpp +++ b/src/BASE_ISA.cpp @@ -11,1422 +11,1473 @@ #include "BASE_ISA.h" -enum Codes { - LUI = 0b0110111, - AUIPC = 0b0010111, - JAL = 0b1101111, - JALR = 0b1100111, +namespace riscv_tlm { - BEQ = 0b1100011, - BEQ_F = 0b000, - BNE_F = 0b001, - BLT_F = 0b100, - BGE_F = 0b101, - BLTU_F = 0b110, - BGEU_F = 0b111, + enum Codes { + LUI = 0b0110111, + AUIPC = 0b0010111, + JAL = 0b1101111, + JALR = 0b1100111, - LB = 0b0000011, - LB_F = 0b000, - LH_F = 0b001, - LW_F = 0b010, - LBU_F = 0b100, - LHU_F = 0b101, + BEQ = 0b1100011, + BEQ_F = 0b000, + BNE_F = 0b001, + BLT_F = 0b100, + BGE_F = 0b101, + BLTU_F = 0b110, + BGEU_F = 0b111, - SB = 0b0100011, - SB_F = 0b000, - SH_F = 0b001, - SW_F = 0b010, + LB = 0b0000011, + LB_F = 0b000, + LH_F = 0b001, + LW_F = 0b010, + LBU_F = 0b100, + LHU_F = 0b101, - 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, + SB = 0b0100011, + SB_F = 0b000, + SH_F = 0b001, + SW_F = 0b010, - ADD = 0b0110011, - ADD_F = 0b000, - SUB_F = 0b000, - ADD_F7 = 0b0000000, - SUB_F7 = 0b0100000, + 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, - 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, + ADD = 0b0110011, + ADD_F = 0b000, + SUB_F = 0b000, + ADD_F7 = 0b0000000, + SUB_F7 = 0b0100000, - 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, + 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, - ECALL_F3 = 0b000, - CSRRW = 0b001, - CSRRS = 0b010, - CSRRC = 0b011, - CSRRWI = 0b101, - CSRRSI = 0b110, - CSRRCI = 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, -bool BASE_ISA::Exec_LUI() const { - int rd; - std::uint32_t imm; + ECALL_F3 = 0b000, + CSRRW = 0b001, + CSRRS = 0b010, + CSRRC = 0b011, + CSRRWI = 0b101, + CSRRSI = 0b110, + CSRRCI = 0b111, + }; - rd = get_rd(); - imm = get_imm_U() << 12; - regs->setValue(rd, static_cast(imm)); + bool BASE_ISA::Exec_LUI() const { + int rd; + std::uint32_t imm; - logger->debug("{} ns. PC: 0x{:x}. LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), - rd, imm); + rd = get_rd(); + imm = get_imm_U() << 12; + regs->setValue(rd, static_cast(imm)); - return true; -} + logger->debug("{} ns. PC: 0x{:x}. LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), + rd, imm); -bool BASE_ISA::Exec_AUIPC() const { - int rd; - std::uint32_t imm; - std::uint32_t new_pc; - - rd = get_rd(); - imm = get_imm_U() << 12; - new_pc = static_cast(regs->getPC() + imm); - - regs->setValue(rd, new_pc); - - logger->debug("{} ns. PC: 0x{:x}. AUIPC: x{:d} <- 0x{:x} + PC (0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rd, imm, new_pc); - - return true; -} - -bool BASE_ISA::Exec_JAL() const { - int32_t mem_addr; - int rd; - std::uint32_t new_pc, old_pc; - - rd = get_rd(); - mem_addr = get_imm_J(); - old_pc = static_cast(regs->getPC()); - new_pc = old_pc + mem_addr; - - regs->setPC(new_pc); - - old_pc = old_pc + 4; - regs->setValue(rd, old_pc); - - logger->debug("{} ns. PC: 0x{:x}. JAL: x{:d} <- 0x{:x}. PC + 0x{:x} -> PC (0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rd, old_pc, mem_addr, new_pc); - - return true; -} - -bool BASE_ISA::Exec_JALR() { - std::uint32_t mem_addr; - int rd, rs1; - std::uint32_t new_pc, old_pc; - - rd = get_rd(); - rs1 = get_rs1(); - mem_addr = get_imm_I(); - - old_pc = static_cast(regs->getPC()); - regs->setValue(rd, old_pc + 4); - - new_pc = static_cast((regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); - - if( (new_pc & 0x00000003) != 0) { - // not aligned - logger->debug("{} ns. PC: 0x{:x}. JALR: x{:d} <- 0x{:x} PC <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), - rd, old_pc + 4, new_pc); - - logger->debug("{} ns. PC: 0x{:x}. JALR : Exception"); - RaiseException(EXCEPTION_CAUSE_LOAD_ADDR_MISALIGN, m_instr); - } else { - regs->setPC(new_pc); + return true; } - logger->debug("{} ns. PC: 0x{:x}. JALR: x{:d} <- 0x{:x}. PC <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), - rd, old_pc + 4, new_pc); - - return true; -} - -bool BASE_ISA::Exec_BEQ() const { - int rs1, rs2; - std::uint32_t new_pc; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (regs->getValue(rs1) == regs->getValue(rs2)) { - new_pc = static_cast(regs->getPC() + get_imm_B()); - regs->setPC(new_pc); - } else { - regs->incPC(); - new_pc = static_cast(regs->getPC()); - } - - logger->debug("{} ns. PC: 0x{:x}. BEQ: x{:d}(0x{:x}) == x{:d}(0x{:x})? -> PC (0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - - return true; -} - -bool BASE_ISA::Exec_BNE() const { - int rs1, rs2; - std::uint32_t new_pc; - std::uint32_t val1, val2; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - val1 = regs->getValue(rs1); - val2 = regs->getValue(rs2); - - if (val1 != val2) { - new_pc = static_cast(regs->getPC() + get_imm_B()); - regs->setPC(new_pc); - } else { - regs->incPC(); - new_pc = static_cast(regs->getPC()); - } - - logger->debug("{} ns. PC: 0x{:x}. BNE: x{:d}(0x{:x}) != x{:d}(0x{:x})? -> PC (0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, val1, rs2, val2, new_pc); - - return true; -} - -bool BASE_ISA::Exec_BLT() const { - int rs1, rs2; - std::uint32_t new_pc = 0; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - if ( static_cast(regs->getValue(rs1)) < static_cast(regs->getValue(rs2)) ) { - new_pc = static_cast(regs->getPC() + get_imm_B()); - regs->setPC(new_pc); - } else { - regs->incPC(); - } - - logger->debug("{} ns. PC: 0x{:x}. BLT: x{:d}(0x{:x}) < x{:d}(0x{:x})? -> PC (0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - - return true; -} - -bool BASE_ISA::Exec_BGE() const { - int rs1, rs2; - std::uint32_t new_pc = 0; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - if ( static_cast(regs->getValue(rs1)) >= static_cast( regs->getValue(rs2)) ) { - new_pc = static_cast(regs->getPC() + get_imm_B()); - regs->setPC(new_pc); - } else { - regs->incPC(); - } - - logger->debug("{} ns. PC: 0x{:x}. BGE: x{:d}(0x{:x}) > x{:d}(0x{:x})? -> PC (0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - - return true; -} - -bool BASE_ISA::Exec_BLTU() const { - int rs1, rs2; - std::uint32_t new_pc; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - if ( static_cast(regs->getValue(rs1)) < static_cast(regs->getValue(rs2)) ) { - new_pc = static_cast(regs->getPC() + get_imm_B()); - regs->setPC(new_pc); - } else { - regs->incPC(); - new_pc = static_cast(regs->getPC()); - } - - logger->debug("{} ns. PC: 0x{:x}. BLTU: x{:d}(0x{:x}) < x{:d}(0x{:x})? -> PC (0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - - return true; -} - -bool BASE_ISA::Exec_BGEU() const { - int rs1, rs2; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - if ( static_cast(regs->getValue(rs1)) >= static_cast(regs->getValue(rs2)) ) { + bool BASE_ISA::Exec_AUIPC() const { + int rd; + std::uint32_t imm; std::uint32_t new_pc; - new_pc = static_cast(regs->getPC() + get_imm_B()); - logger->debug("{} ns. PC: 0x{:x}. BGEU: x{:d}(0x{:x}) > x{:d}(0x{:x}) -> PC (0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), + rd = get_rd(); + imm = get_imm_U() << 12; + new_pc = static_cast(regs->getPC() + imm); + + regs->setValue(rd, new_pc); + + logger->debug("{} ns. PC: 0x{:x}. AUIPC: x{:d} <- 0x{:x} + PC (0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rd, imm, new_pc); + + return true; + } + + bool BASE_ISA::Exec_JAL() const { + std::int32_t mem_addr; + int rd; + std::uint32_t new_pc, old_pc; + + rd = get_rd(); + mem_addr = get_imm_J(); + old_pc = static_cast(regs->getPC()); + new_pc = old_pc + mem_addr; + + regs->setPC(new_pc); + + old_pc = old_pc + 4; + regs->setValue(rd, old_pc); + + logger->debug("{} ns. PC: 0x{:x}. JAL: x{:d} <- 0x{:x}. PC + 0x{:x} -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), + rd, old_pc, mem_addr, new_pc); + + return true; + } + + bool BASE_ISA::Exec_JALR() { + std::uint32_t mem_addr; + int rd, rs1; + std::uint32_t new_pc, old_pc; + + rd = get_rd(); + rs1 = get_rs1(); + mem_addr = get_imm_I(); + + old_pc = static_cast(regs->getPC()); + regs->setValue(rd, old_pc + 4); + + new_pc = static_cast((regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); + + if ((new_pc & 0x00000003) != 0) { + // not aligned + logger->debug("{} ns. PC: 0x{:x}. JALR: x{:d} <- 0x{:x} PC <- 0x{:x}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rd, old_pc + 4, new_pc); + + logger->debug("{} ns. PC: 0x{:x}. JALR : Exception"); + RaiseException(EXCEPTION_CAUSE_LOAD_ADDR_MISALIGN, m_instr); + } else { + regs->setPC(new_pc); + } + + logger->debug("{} ns. PC: 0x{:x}. JALR: x{:d} <- 0x{:x}. PC <- 0x{:x}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rd, old_pc + 4, new_pc); + + return true; + } + + bool BASE_ISA::Exec_BEQ() const { + int rs1, rs2; + std::uint32_t new_pc; + + rs1 = get_rs1(); + rs2 = get_rs2(); + + if (regs->getValue(rs1) == regs->getValue(rs2)) { + new_pc = static_cast(regs->getPC() + get_imm_B()); + regs->setPC(new_pc); + } else { + regs->incPC(); + new_pc = static_cast(regs->getPC()); + } + + logger->debug("{} ns. PC: 0x{:x}. BEQ: x{:d}(0x{:x}) == x{:d}(0x{:x})? -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - regs->setPC(new_pc); - } else { - logger->debug("{} ns. PC: 0x{:x}. BGEU: x{:d}(0x{:x}) > x{:d}(0x{:x}) -> PC (0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), regs->getPC() + 4); - regs->incPC(); - } + return true; + } - return true; -} + bool BASE_ISA::Exec_BNE() const { + int rs1, rs2; + std::uint32_t new_pc; + std::uint32_t val1, val2; -bool BASE_ISA::Exec_LB() const { - std::uint32_t mem_addr ; - int rd, rs1; - std::int32_t imm; - std::int8_t data; + rs1 = get_rs1(); + rs2 = get_rs2(); - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); + val1 = regs->getValue(rs1); + val2 = regs->getValue(rs2); - mem_addr = imm + regs->getValue(rs1); - data = static_cast(mem_intf->readDataMem(mem_addr, 1)); - perf->dataMemoryRead(); - regs->setValue(rd, data); + if (val1 != val2) { + new_pc = static_cast(regs->getPC() + get_imm_B()); + regs->setPC(new_pc); + } else { + regs->incPC(); + new_pc = static_cast(regs->getPC()); + } - logger->debug("{} ns. PC: 0x{:x}. LB: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, imm, mem_addr, rd); + logger->debug("{} ns. PC: 0x{:x}. BNE: x{:d}(0x{:x}) != x{:d}(0x{:x})? -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), + rs1, val1, rs2, val2, new_pc); - return true; -} + return true; + } -bool BASE_ISA::Exec_LH() const { - std::uint32_t mem_addr ; - int rd, rs1; - std::int32_t imm; - int16_t data; + bool BASE_ISA::Exec_BLT() const { + int rs1, rs2; + std::uint32_t new_pc = 0; - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); + rs1 = get_rs1(); + rs2 = get_rs2(); - mem_addr = imm + regs->getValue(rs1); - data = static_cast(mem_intf->readDataMem(mem_addr, 2)); - perf->dataMemoryRead(); - regs->setValue(rd, data); + if (static_cast(regs->getValue(rs1)) < static_cast(regs->getValue(rs2))) { + new_pc = static_cast(regs->getPC() + get_imm_B()); + regs->setPC(new_pc); + } else { + regs->incPC(); + } - logger->debug("{} ns. PC: 0x{:x}. LH: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, imm, mem_addr, rd); + logger->debug("{} ns. PC: 0x{:x}. BLT: x{:d}(0x{:x}) < x{:d}(0x{:x})? -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), + rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - return true; -} + return true; + } -bool BASE_ISA::Exec_LW() const { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - std::uint32_t data; + bool BASE_ISA::Exec_BGE() const { + int rs1, rs2; + std::uint32_t new_pc = 0; - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); + rs1 = get_rs1(); + rs2 = get_rs2(); - mem_addr = imm + regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); + if (static_cast(regs->getValue(rs1)) >= static_cast( regs->getValue(rs2))) { + new_pc = static_cast(regs->getPC() + get_imm_B()); + regs->setPC(new_pc); + } else { + regs->incPC(); + } - logger->debug("{} ns. PC: 0x{:x}. LW: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, imm, mem_addr, rd); + logger->debug("{} ns. PC: 0x{:x}. BGE: x{:d}(0x{:x}) > x{:d}(0x{:x})? -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), + rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - return true; -} + return true; + } -bool BASE_ISA::Exec_LBU() const { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - std::uint8_t data; + bool BASE_ISA::Exec_BLTU() const { + int rs1, rs2; + std::uint32_t new_pc; - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); + rs1 = get_rs1(); + rs2 = get_rs2(); - mem_addr = imm + regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 1); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); + if (static_cast(regs->getValue(rs1)) < static_cast(regs->getValue(rs2))) { + new_pc = static_cast(regs->getPC() + get_imm_B()); + regs->setPC(new_pc); + } else { + regs->incPC(); + new_pc = static_cast(regs->getPC()); + } - logger->debug("{} ns. PC: 0x{:x}. LBU: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, imm, mem_addr, rd); + logger->debug("{} ns. PC: 0x{:x}. BLTU: x{:d}(0x{:x}) < x{:d}(0x{:x})? -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), + rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - return true; -} + return true; + } -bool BASE_ISA::Exec_LHU() const { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - uint16_t data; + bool BASE_ISA::Exec_BGEU() const { + int rs1, rs2; - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); + rs1 = get_rs1(); + rs2 = get_rs2(); - mem_addr = imm + regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 2); - perf->dataMemoryRead(); + if (static_cast(regs->getValue(rs1)) >= static_cast(regs->getValue(rs2))) { + std::uint32_t new_pc; + new_pc = static_cast(regs->getPC() + get_imm_B()); - regs->setValue(rd, data); + logger->debug("{} ns. PC: 0x{:x}. BGEU: x{:d}(0x{:x}) > x{:d}(0x{:x}) -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), + rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - logger->debug("{} ns. PC: 0x{:x}. LHU: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, imm, mem_addr, rd); + regs->setPC(new_pc); + } else { + logger->debug("{} ns. PC: 0x{:x}. BGEU: x{:d}(0x{:x}) > x{:d}(0x{:x}) -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), + rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), regs->getPC() + 4); + regs->incPC(); + } - return true; -} + return true; + } -bool BASE_ISA::Exec_SB() const { - std::uint32_t mem_addr; - int rs1, rs2; - std::int32_t imm; - std::uint32_t data; + bool BASE_ISA::Exec_LB() const { + std::uint32_t mem_addr; + int rd, rs1; + std::int32_t imm; + std::int8_t data; - rs1 = get_rs1(); - rs2 = get_rs2(); - imm = get_imm_S(); + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); + mem_addr = imm + regs->getValue(rs1); + data = static_cast(mem_intf->readDataMem(mem_addr, 1)); + perf->dataMemoryRead(); + regs->setValue(rd, data); - mem_intf->writeDataMem(mem_addr, data, 1); - perf->dataMemoryWrite(); + logger->debug("{} ns. PC: 0x{:x}. LB: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, imm, mem_addr, rd); - logger->debug("{} ns. PC: 0x{:x}. SB: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs2, rs1, imm, mem_addr); + return true; + } - return true; -} + bool BASE_ISA::Exec_LH() const { + std::uint32_t mem_addr; + int rd, rs1; + std::int32_t imm; + int16_t data; -bool BASE_ISA::Exec_SH() const { - std::uint32_t mem_addr; - int rs1, rs2; - std::int32_t imm; - std::uint32_t data; + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); - rs1 = get_rs1(); - rs2 = get_rs2(); - imm = get_imm_S(); + mem_addr = imm + regs->getValue(rs1); + data = static_cast(mem_intf->readDataMem(mem_addr, 2)); + perf->dataMemoryRead(); + regs->setValue(rd, data); - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); + logger->debug("{} ns. PC: 0x{:x}. LH: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, imm, mem_addr, rd); - mem_intf->writeDataMem(mem_addr, data, 2); - perf->dataMemoryWrite(); + return true; + } - logger->debug("{} ns. PC: 0x{:x}. SH: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs2, rs1, imm, mem_addr); + bool BASE_ISA::Exec_LW() const { + std::uint32_t mem_addr; + int rd, rs1; + std::int32_t imm; + std::uint32_t data; - return true; -} + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); -bool BASE_ISA::Exec_SW() const { - std::uint32_t mem_addr; - int rs1, rs2; - std::int32_t imm; - std::uint32_t data; + mem_addr = imm + regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 4); + perf->dataMemoryRead(); + regs->setValue(rd, static_cast(data)); - rs1 = get_rs1(); - rs2 = get_rs2(); - imm = get_imm_S(); + logger->debug("{} ns. PC: 0x{:x}. LW: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, imm, mem_addr, rd); - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); + return true; + } - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); + bool BASE_ISA::Exec_LBU() const { + std::uint32_t mem_addr; + int rd, rs1; + std::int32_t imm; + std::uint8_t data; - logger->debug("{} ns. PC: 0x{:x}. SW: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs2, rs1, imm, mem_addr); + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); - return true; -} + mem_addr = imm + regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 1); + perf->dataMemoryRead(); + regs->setValue(rd, static_cast(data)); -bool BASE_ISA::Exec_ADDI() const { - int rd, rs1; - std::int32_t imm; - std::int32_t calc; + logger->debug("{} ns. PC: 0x{:x}. LBU: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, imm, mem_addr, rd); - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); + return true; + } - calc = static_cast(regs->getValue(rs1)) + imm; - regs->setValue(rd, calc); + bool BASE_ISA::Exec_LHU() const { + std::uint32_t mem_addr; + int rd, rs1; + std::int32_t imm; + uint16_t data; - logger->debug("{} ns. PC: 0x{:x}. ADDI: x{:d} + x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, imm, rd, calc); + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); - return true; -} + mem_addr = imm + regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 2); + perf->dataMemoryRead(); -bool BASE_ISA::Exec_SLTI() const { - int rd, rs1; - std::int32_t imm; + regs->setValue(rd, data); - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); + logger->debug("{} ns. PC: 0x{:x}. LHU: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, imm, mem_addr, rd); - if (static_cast(regs->getValue(rs1)) < imm) { - regs->setValue(rd, 1); + return true; + } - logger->debug("{} ns. PC: 0x{:x}. SLTI: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), + bool BASE_ISA::Exec_SB() const { + std::uint32_t mem_addr; + int rs1, rs2; + std::int32_t imm; + std::uint32_t data; + + rs1 = get_rs1(); + rs2 = get_rs2(); + imm = get_imm_S(); + + mem_addr = imm + regs->getValue(rs1); + data = regs->getValue(rs2); + + mem_intf->writeDataMem(mem_addr, data, 1); + perf->dataMemoryWrite(); + + logger->debug("{} ns. PC: 0x{:x}. SB: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs2, rs1, imm, mem_addr); + + return true; + } + + bool BASE_ISA::Exec_SH() const { + std::uint32_t mem_addr; + int rs1, rs2; + std::int32_t imm; + std::uint32_t data; + + rs1 = get_rs1(); + rs2 = get_rs2(); + imm = get_imm_S(); + + mem_addr = imm + regs->getValue(rs1); + data = regs->getValue(rs2); + + mem_intf->writeDataMem(mem_addr, data, 2); + perf->dataMemoryWrite(); + + logger->debug("{} ns. PC: 0x{:x}. SH: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs2, rs1, imm, mem_addr); + + return true; + } + + bool BASE_ISA::Exec_SW() const { + std::uint32_t mem_addr; + int rs1, rs2; + std::int32_t imm; + std::uint32_t data; + + rs1 = get_rs1(); + rs2 = get_rs2(); + imm = get_imm_S(); + + mem_addr = imm + regs->getValue(rs1); + data = regs->getValue(rs2); + + mem_intf->writeDataMem(mem_addr, data, 4); + perf->dataMemoryWrite(); + + logger->debug("{} ns. PC: 0x{:x}. SW: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs2, rs1, imm, mem_addr); + + return true; + } + + bool BASE_ISA::Exec_ADDI() const { + int rd, rs1; + std::int32_t imm; + std::int32_t calc; + + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); + + calc = static_cast(regs->getValue(rs1)) + imm; + regs->setValue(rd, calc); + + logger->debug("{} ns. PC: 0x{:x}. ADDI: x{:d} + x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, imm, rd, calc); + + return true; + } + + bool BASE_ISA::Exec_SLTI() const { + int rd, rs1; + std::int32_t imm; + + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); + + if (static_cast(regs->getValue(rs1)) < imm) { + regs->setValue(rd, 1); + + logger->debug("{} ns. PC: 0x{:x}. SLTI: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, imm, rd); + } else { + regs->setValue(rd, 0); + logger->debug("{} ns. PC: 0x{:x}. SLTI: x{:d} < x{:d} => 0 -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, imm, rd); + } + + return true; + } + + bool BASE_ISA::Exec_SLTIU() const { + int rd, rs1; + std::int32_t imm; + + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); + + if (static_cast(regs->getValue(rs1)) < static_cast(imm)) { + regs->setValue(rd, 1); + logger->debug("{} ns. PC: 0x{:x}. SLTIU: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, imm, rd); + } else { + regs->setValue(rd, 0); + logger->debug("{} ns. PC: 0x{:x}. SLTIU: x{:d} < x{:d} => 0 -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, imm, rd); + } + + return true; + } + + bool BASE_ISA::Exec_XORI() const { + int rd, rs1; + std::int32_t imm; + std::uint32_t calc; + + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); + + calc = regs->getValue(rs1) ^ imm; + regs->setValue(rd, static_cast(calc)); + + logger->debug("{} ns. PC: 0x{:x}. XORI: x{:d} XOR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), rs1, imm, rd); - } else { - regs->setValue(rd, 0); - logger->debug("{} ns. PC: 0x{:x}. SLTI: x{:d} < x{:d} => 0 -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), + + return true; + } + + bool BASE_ISA::Exec_ORI() const { + int rd, rs1; + std::int32_t imm; + std::uint32_t calc; + + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); + + calc = regs->getValue(rs1) | imm; + regs->setValue(rd, static_cast(calc)); + + logger->debug("{} ns. PC: 0x{:x}. ORI: x{:d} OR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), rs1, imm, rd); - } - return true; -} + return true; + } -bool BASE_ISA::Exec_SLTIU() const { - int rd, rs1; - std::int32_t imm; + bool BASE_ISA::Exec_ANDI() const { + int rd, rs1; + std::uint32_t imm; + std::uint32_t calc; + std::uint32_t aux; - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); - if (static_cast(regs->getValue(rs1)) < static_cast(imm)) { - regs->setValue(rd, 1); - logger->debug("{} ns. PC: 0x{:x}. SLTIU: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, imm, rd); - } else { - regs->setValue(rd, 0); - logger->debug("{} ns. PC: 0x{:x}. SLTIU: x{:d} < x{:d} => 0 -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, imm, rd); - } + aux = regs->getValue(rs1); + calc = aux & imm; + regs->setValue(rd, static_cast(calc)); - return true; -} + logger->debug("{} ns. PC: 0x{:x}. ANDI: x{:d}(0x{:x}) AND 0x{:x} -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, aux, imm, rd); -bool BASE_ISA::Exec_XORI() const { - int rd, rs1; - std::int32_t imm; - std::uint32_t calc; + return true; + } - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); + bool BASE_ISA::Exec_SLLI() { + int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; - calc = regs->getValue(rs1) ^ imm; - regs->setValue(rd, static_cast(calc)); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_shamt(); - logger->debug("{} ns. PC: 0x{:x}. XORI: x{:d} XOR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, imm, rd); + if (rs2 >= 0x20) { + std::cout << "ILEGAL INSTRUCTION, shamt[5] != 0" << "\n"; + RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr); - return true; -} + return false; + } -bool BASE_ISA::Exec_ORI() const { - int rd, rs1; - std::int32_t imm; - std::uint32_t calc; + shift = rs2 & 0x1F; - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); + calc = static_cast(regs->getValue(rs1)) << shift; + regs->setValue(rd, static_cast(calc)); - calc = regs->getValue(rs1) | imm; - regs->setValue(rd, static_cast(calc)); + logger->debug("{} ns. PC: 0x{:x}. SLLI: x{:d} << {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, shift, rd, calc); - logger->debug("{} ns. PC: 0x{:x}. ORI: x{:d} OR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, imm, rd); + return true; + } - return true; -} + bool BASE_ISA::Exec_SRLI() const { + int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; -bool BASE_ISA::Exec_ANDI() const { - int rd, rs1; - std::uint32_t imm; - std::uint32_t calc; - std::uint32_t aux; + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); + shift = rs2 & 0x1F; - aux = regs->getValue(rs1); - calc = aux & imm; - regs->setValue(rd, static_cast(calc)); + calc = static_cast(regs->getValue(rs1)) >> shift; + regs->setValue(rd, static_cast(calc)); - logger->debug("{} ns. PC: 0x{:x}. ANDI: x{:d}(0x{:x}) AND 0x{:x} -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, aux, imm, rd); + logger->debug("{} ns. PC: 0x{:x}. SRLI: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, shift, rd, calc); - return true; -} + return true; + } -bool BASE_ISA::Exec_SLLI() { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; + bool BASE_ISA::Exec_SRAI() const { + int rd, rs1, rs2; + std::uint32_t shift; + std::int32_t calc; - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_shamt(); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - if (rs2 >= 0x20) { - std::cout << "ILEGAL INSTRUCTION, shamt[5] != 0" << "\n"; - RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr); + shift = rs2 & 0x1F; - return false; - } + calc = static_cast(regs->getValue(rs1)) >> shift; + regs->setValue(rd, calc); - shift = rs2 & 0x1F; + logger->debug("{} ns. PC: 0x{:x}. SRAI: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, shift, rd, calc); - calc = static_cast(regs->getValue(rs1)) << shift; - regs->setValue(rd, static_cast(calc)); + return true; + } - logger->debug("{} ns. PC: 0x{:x}. SLLI: x{:d} << {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, shift, rd, calc); + bool BASE_ISA::Exec_ADD() const { + int rd, rs1, rs2; + std::uint32_t calc; + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - return true; -} + calc = regs->getValue(rs1) + regs->getValue(rs2); -bool BASE_ISA::Exec_SRLI() const { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; + regs->setValue(rd, static_cast(calc)); - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + logger->debug("{} ns. PC: 0x{:x}. ADD: x{:d} + x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd, calc); - shift = rs2 & 0x1F; + return true; + } - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, static_cast(calc)); + bool BASE_ISA::Exec_SUB() const { + int rd, rs1, rs2; + std::uint32_t calc; + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - logger->debug("{} ns. PC: 0x{:x}. SRLI: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, shift, rd, calc); + calc = regs->getValue(rs1) - regs->getValue(rs2); + regs->setValue(rd, static_cast(calc)); - return true; -} + logger->debug("{} ns. PC: 0x{:x}. SUB: x{:d} - x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd, calc); -bool BASE_ISA::Exec_SRAI() const { - int rd, rs1, rs2; - std::uint32_t shift; - std::int32_t calc; + return true; + } - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + bool BASE_ISA::Exec_SLL() const { + int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; - shift = rs2 & 0x1F; + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, calc); + shift = regs->getValue(rs2) & 0x1F; - logger->debug("{} ns. PC: 0x{:x}. SRAI: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, shift, rd, calc); + calc = static_cast(regs->getValue(rs1)) << shift; + regs->setValue(rd, static_cast(calc)); - return true; -} + logger->debug("{} ns. PC: 0x{:x}. SLL: x{:d} << x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, shift, rd, calc); -bool BASE_ISA::Exec_ADD() const { - int rd, rs1, rs2; - std::uint32_t calc; - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + return true; + } - calc = regs->getValue(rs1) + regs->getValue(rs2); + bool BASE_ISA::Exec_SLT() const { + int rd, rs1, rs2; - regs->setValue(rd, static_cast(calc)); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - logger->debug("{} ns. PC: 0x{:x}. ADD: x{:d} + x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd, calc); + if (regs->getValue(rs1) < regs->getValue(rs2)) { + regs->setValue(rd, 1); + logger->debug("{} ns. PC: 0x{:x}. SLT: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd); + } else { + regs->setValue(rd, 0); + logger->debug("{} ns. PC: 0x{:x}. SLT: x{:d} < x{:d} => 0 -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd); + } - return true; -} + return true; + } -bool BASE_ISA::Exec_SUB() const { - int rd, rs1, rs2; - std::uint32_t calc; - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + bool BASE_ISA::Exec_SLTU() const { + int rd, rs1, rs2; - calc = regs->getValue(rs1) - regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - logger->debug("{} ns. PC: 0x{:x}. SUB: x{:d} - x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd, calc); + if (static_cast(regs->getValue(rs1)) < static_cast(regs->getValue(rs2))) { + regs->setValue(rd, 1); + logger->debug("{} ns. PC: 0x{:x}. SLTU: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd); + } else { + regs->setValue(rd, 0); + logger->debug("{} ns. PC: 0x{:x}. SLTU: x{:d} < x{:d} => 0 -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd); + } - return true; -} + return true; + } -bool BASE_ISA::Exec_SLL() const { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; + bool BASE_ISA::Exec_XOR() const { + int rd, rs1, rs2; + std::uint32_t calc; - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - shift = regs->getValue(rs2) & 0x1F; + calc = regs->getValue(rs1) ^ regs->getValue(rs2); + regs->setValue(rd, static_cast(calc)); - calc = static_cast(regs->getValue(rs1)) << shift; - regs->setValue(rd, static_cast(calc)); + logger->debug("{} ns. PC: 0x{:x}. XOR: x{:d} XOR x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd, calc); - logger->debug("{} ns. PC: 0x{:x}. SLL: x{:d} << x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, shift, rd, calc); + return true; + } - return true; -} + bool BASE_ISA::Exec_SRL() const { + int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; -bool BASE_ISA::Exec_SLT() const { - int rd, rs1, rs2; + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + shift = regs->getValue(rs2) & 0x1F; - if (regs->getValue(rs1) < regs->getValue(rs2)) { - regs->setValue(rd, 1); - logger->debug("{} ns. PC: 0x{:x}. SLT: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd); - } else { - regs->setValue(rd, 0); - logger->debug("{} ns. PC: 0x{:x}. SLT: x{:d} < x{:d} => 0 -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd); - } + calc = static_cast(regs->getValue(rs1)) >> shift; + regs->setValue(rd, static_cast(calc)); - return true; -} + logger->debug("{} ns. PC: 0x{:x}. SRL: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, shift, rd, calc); -bool BASE_ISA::Exec_SLTU() const { - int rd, rs1, rs2; + return true; + } - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + bool BASE_ISA::Exec_SRA() const { + int rd, rs1, rs2; + std::uint32_t shift; + std::int32_t calc; - if ( static_cast(regs->getValue(rs1)) < static_cast(regs->getValue(rs2)) ) { - regs->setValue(rd, 1); - logger->debug("{} ns. PC: 0x{:x}. SLTU: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd); - } else { - regs->setValue(rd, 0); - logger->debug("{} ns. PC: 0x{:x}. SLTU: x{:d} < x{:d} => 0 -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd); - } + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - return true; -} + shift = regs->getValue(rs2) & 0x1F; -bool BASE_ISA::Exec_XOR() const { - int rd, rs1, rs2; - std::uint32_t calc; + calc = static_cast(regs->getValue(rs1)) >> shift; + regs->setValue(rd, calc); - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + logger->debug("{} ns. PC: 0x{:x}. SRA: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, shift, rd, calc); - calc = regs->getValue(rs1) ^ regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); + return true; + } - logger->debug("{} ns. PC: 0x{:x}. XOR: x{:d} XOR x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd, calc); + bool BASE_ISA::Exec_OR() const { + int rd, rs1, rs2; + std::uint32_t calc; - return true; -} + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); -bool BASE_ISA::Exec_SRL() const { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; + calc = regs->getValue(rs1) | regs->getValue(rs2); + regs->setValue(rd, static_cast(calc)); - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + logger->debug("{} ns. PC: 0x{:x}. OR: x{:d} OR x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd, calc); - shift = regs->getValue(rs2) & 0x1F; + return true; + } - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, static_cast(calc)); + bool BASE_ISA::Exec_AND() const { + int rd, rs1, rs2; + std::uint32_t calc; - logger->debug("{} ns. PC: 0x{:x}. SRL: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, shift, rd, calc); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - return true; -} + calc = regs->getValue(rs1) & regs->getValue(rs2); + regs->setValue(rd, static_cast(calc)); -bool BASE_ISA::Exec_SRA() const { - int rd, rs1, rs2; - std::uint32_t shift; - std::int32_t calc; + logger->debug("{} ns. PC: 0x{:x}. AND: x{:d} AND x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd, calc); - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + return true; + } - shift = regs->getValue(rs2) & 0x1F; + bool BASE_ISA::Exec_FENCE() const { + logger->debug("{} ns. PC: 0x{:x}. FENCE"); - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, calc); + return true; + } - logger->debug("{} ns. PC: 0x{:x}. SRA: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, shift, rd, calc); + bool BASE_ISA::Exec_ECALL() { - return true; -} + logger->debug("{} ns. PC: 0x{:x}. ECALL"); -bool BASE_ISA::Exec_OR() const { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - calc = regs->getValue(rs1) | regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. OR: x{:d} OR x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd, calc); - - return true; -} - -bool BASE_ISA::Exec_AND() const { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - calc = regs->getValue(rs1) & regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. AND: x{:d} AND x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd, calc); - - return true; -} - -bool BASE_ISA::Exec_FENCE() const { - logger->debug("{} ns. PC: 0x{:x}. FENCE"); - - return true; -} - -bool BASE_ISA::Exec_ECALL() { - - logger->debug("{} ns. PC: 0x{:x}. ECALL"); - - std::cout << std::endl << "ECALL Instruction called, stopping simulation" - << std::endl; - regs->dump(); - std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; - perf->dump(); + std::cout << std::endl << "ECALL Instruction called, stopping simulation" + << std::endl; + regs->dump(); + std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; + perf->dump(); #if 0 - std::uint32_t gp_value = regs->getValue(Registers::gp); - if (gp_value == 1) { - std::cout << "GP value is 1, test result is OK" << "\n"; - } else { - std::cout << "GP value is " << gp_value << "\n"; - } + std::uint32_t gp_value = regs->getValue(Registers::gp); + if (gp_value == 1) { + std::cout << "GP value is 1, test result is OK" << "\n"; + } else { + std::cout << "GP value is " << gp_value << "\n"; + } - sc_core::sc_stop(); + sc_core::sc_stop(); #else - RaiseException(11, m_instr); + RaiseException(11, m_instr); #endif - return true; -} + return true; + } -bool BASE_ISA::Exec_EBREAK() { + bool BASE_ISA::Exec_EBREAK() { - logger->debug("{} ns. PC: 0x{:x}. EBREAK"); - std::cout << std::endl << "EBRAK Instruction called, dumping information" - << std::endl; - regs->dump(); - std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; - perf->dump(); + logger->debug("{} ns. PC: 0x{:x}. EBREAK"); + std::cout << std::endl << "EBRAK Instruction called, dumping information" + << std::endl; + regs->dump(); + std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; + perf->dump(); - RaiseException(11, m_instr); + RaiseException(11, m_instr); - return false; -} + return false; + } -bool BASE_ISA::Exec_CSRRW() const { - int rd, rs1; - int csr; - std::uint32_t aux; + bool BASE_ISA::Exec_CSRRW() const { + int rd, rs1; + int csr; + std::uint32_t aux; - rd = get_rd(); - rs1 = get_rs1(); - csr = get_csr(); + rd = get_rd(); + rs1 = get_rs1(); + csr = get_csr(); - /* These operations must be atomical */ - if (rd != 0) { - aux = regs->getCSR(csr); - regs->setValue(rd, static_cast(aux)); - } + /* These operations must be atomical */ + if (rd != 0) { + aux = regs->getCSR(csr); + regs->setValue(rd, static_cast(aux)); + } - aux = regs->getValue(rs1); - regs->setCSR(csr, aux); + aux = regs->getValue(rs1); + regs->setCSR(csr, aux); - logger->debug("{} ns. PC: 0x{:x}. CSRRW: CSR #{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - csr, rd, aux); + logger->debug("{} ns. PC: 0x{:x}. CSRRW: CSR #{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + csr, rd, aux); - return true; -} + return true; + } -bool BASE_ISA::Exec_CSRRS() const { - int rd, rs1; - int csr; - std::uint32_t bitmask, aux, aux2; + bool BASE_ISA::Exec_CSRRS() const { + int rd, rs1; + int csr; + std::uint32_t bitmask, aux, aux2; - rd = get_rd(); - rs1 = get_rs1(); - csr = get_csr(); + rd = get_rd(); + rs1 = get_rs1(); + csr = get_csr(); - if (rd == 0) { - logger->debug("{} ns. PC: 0x{:x}. CSRRS with rd1 == 0, doing nothing."); - return false; - } + if (rd == 0) { + logger->debug("{} ns. PC: 0x{:x}. CSRRS with rd1 == 0, doing nothing."); + return false; + } - /* These operations must be atomical */ - aux = regs->getCSR(csr); - bitmask = regs->getValue(rs1); + /* These operations must be atomical */ + aux = regs->getCSR(csr); + bitmask = regs->getValue(rs1); - regs->setValue(rd, static_cast(aux)); + regs->setValue(rd, static_cast(aux)); - aux2 = aux | bitmask; - regs->setCSR(csr, aux2); + aux2 = aux | bitmask; + regs->setCSR(csr, aux2); - logger->debug("{} ns. PC: 0x{:x}. CSRRS: CSR #{:d}(0x{:x}) -> x{:d}(0x{:x}) & CSR #{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), - csr, aux, rd, rs1, csr, aux2); + logger->debug("{} ns. PC: 0x{:x}. CSRRS: CSR #{:d}(0x{:x}) -> x{:d}(0x{:x}) & CSR #{:d} <- 0x{:x}", + sc_core::sc_time_stamp().value(), regs->getPC(), + csr, aux, rd, rs1, csr, aux2); - return true; -} + return true; + } -bool BASE_ISA::Exec_CSRRC() const { - int rd, rs1; - int csr; - std::uint32_t bitmask, aux, aux2; + bool BASE_ISA::Exec_CSRRC() const { + int rd, rs1; + int csr; + std::uint32_t bitmask, aux, aux2; - rd = get_rd(); - rs1 = get_rs1(); - csr = get_csr(); + rd = get_rd(); + rs1 = get_rs1(); + csr = get_csr(); - if (rd == 0) { - logger->debug("{} ns. PC: 0x{:x}. CSRRC with rd1 == 0, doing nothing."); - return true; - } + if (rd == 0) { + logger->debug("{} ns. PC: 0x{:x}. CSRRC with rd1 == 0, doing nothing."); + return true; + } - /* These operations must be atomical */ - aux = regs->getCSR(csr); - bitmask = regs->getValue(rs1); + /* These operations must be atomical */ + aux = regs->getCSR(csr); + bitmask = regs->getValue(rs1); - regs->setValue(rd, static_cast(aux)); + regs->setValue(rd, static_cast(aux)); - aux2 = aux & ~bitmask; - regs->setCSR(csr, aux2); + aux2 = aux & ~bitmask; + regs->setCSR(csr, aux2); - logger->debug("{} ns. PC: 0x{:x}. CSRRC: CSR #{:d}(0x{:x}) -> x{:d}(0x{:x}) & CSR #{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), - csr, aux, rd, rs1, csr, aux2); + logger->debug("{} ns. PC: 0x{:x}. CSRRC: CSR #{:d}(0x{:x}) -> x{:d}(0x{:x}) & CSR #{:d} <- 0x{:x}", + sc_core::sc_time_stamp().value(), regs->getPC(), + csr, aux, rd, rs1, csr, aux2); - return true; -} + return true; + } -bool BASE_ISA::Exec_CSRRWI() const { - int rd, rs1; - int csr; - std::uint32_t aux; + bool BASE_ISA::Exec_CSRRWI() const { + int rd, rs1; + int csr; + std::uint32_t aux; - rd = get_rd(); - rs1 = get_rs1(); - csr = get_csr(); + rd = get_rd(); + rs1 = get_rs1(); + csr = get_csr(); - /* These operations must be atomical */ - if (rd != 0) { - aux = regs->getCSR(csr); - regs->setValue(rd, static_cast(aux)); - } - aux = rs1; - regs->setCSR(csr, aux); + /* These operations must be atomical */ + if (rd != 0) { + aux = regs->getCSR(csr); + regs->setValue(rd, static_cast(aux)); + } + aux = rs1; + regs->setCSR(csr, aux); - logger->debug("{} ns. PC: 0x{:x}. CSRRWI: CSR #{:d} -> x{:d}. x{:d} -> CSR #{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - csr, rd, rs1, csr); + logger->debug("{} ns. PC: 0x{:x}. CSRRWI: CSR #{:d} -> x{:d}. x{:d} -> CSR #{:d}", + sc_core::sc_time_stamp().value(), regs->getPC(), + csr, rd, rs1, csr); - return true; -} + return true; + } -bool BASE_ISA::Exec_CSRRSI() const { - int rd, rs1; - int csr; - std::uint32_t bitmask, aux; + bool BASE_ISA::Exec_CSRRSI() const { + int rd, rs1; + int csr; + std::uint32_t bitmask, aux; - rd = get_rd(); - rs1 = get_rs1(); - csr = get_csr(); + rd = get_rd(); + rs1 = get_rs1(); + csr = get_csr(); - if (rs1 == 0) { - return true; - } + if (rs1 == 0) { + return true; + } - /* These operations must be atomical */ - aux = regs->getCSR(csr); - regs->setValue(rd, static_cast(aux)); + /* These operations must be atomical */ + aux = regs->getCSR(csr); + regs->setValue(rd, static_cast(aux)); - bitmask = rs1; - aux = aux | bitmask; - regs->setCSR(csr, aux); + bitmask = rs1; + aux = aux | bitmask; + regs->setCSR(csr, aux); - logger->debug("{} ns. PC: 0x{:x}. CSRRSI: CSR #{:d} -> x{:d}. x{:d} & CSR #{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - csr, rd, rs1, csr, aux); + logger->debug("{} ns. PC: 0x{:x}. CSRRSI: CSR #{:d} -> x{:d}. x{:d} & CSR #{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), + csr, rd, rs1, csr, aux); - return true; -} + return true; + } -bool BASE_ISA::Exec_CSRRCI() const { - int rd, rs1; - int csr; - std::uint32_t bitmask, aux; + bool BASE_ISA::Exec_CSRRCI() const { + int rd, rs1; + int csr; + std::uint32_t bitmask, aux; - rd = get_rd(); - rs1 = get_rs1(); - csr = get_csr(); + rd = get_rd(); + rs1 = get_rs1(); + csr = get_csr(); - if (rs1 == 0) { - return true; - } + if (rs1 == 0) { + return true; + } - /* These operations must be atomical */ - aux = regs->getCSR(csr); - regs->setValue(rd, static_cast(aux)); + /* These operations must be atomical */ + aux = regs->getCSR(csr); + regs->setValue(rd, static_cast(aux)); - bitmask = rs1; - aux = aux & ~bitmask; - regs->setCSR(csr, aux); + bitmask = rs1; + aux = aux & ~bitmask; + regs->setCSR(csr, aux); - logger->debug("{} ns. PC: 0x{:x}. CSRRCI: CSR #{:d} -> x{:d}. x{:d} & CSR #{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - csr, rd, rs1, csr, aux); + logger->debug("{} ns. PC: 0x{:x}. CSRRCI: CSR #{:d} -> x{:d}. x{:d} & CSR #{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), + csr, rd, rs1, csr, aux); - return true; -} + return true; + } /*********************** Privileged Instructions ******************************/ -bool BASE_ISA::Exec_MRET() const { - std::uint32_t new_pc = 0; + bool BASE_ISA::Exec_MRET() const { + std::uint32_t new_pc = 0; - new_pc = regs->getCSR(CSR_MEPC); - regs->setPC(new_pc); + new_pc = regs->getCSR(CSR_MEPC); + regs->setPC(new_pc); - logger->debug("{} ns. PC: 0x{:x}. MRET: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), new_pc); + logger->debug("{} ns. PC: 0x{:x}. MRET: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), new_pc); - // update mstatus - std::uint32_t csr_temp; - csr_temp = regs->getCSR(CSR_MSTATUS); - if (csr_temp & MSTATUS_MPIE) { - csr_temp |= MSTATUS_MIE; - } - csr_temp |= MSTATUS_MPIE; - regs->setCSR(CSR_MSTATUS, csr_temp); + // update mstatus + std::uint32_t csr_temp; + csr_temp = regs->getCSR(CSR_MSTATUS); + if (csr_temp & MSTATUS_MPIE) { + csr_temp |= MSTATUS_MIE; + } + csr_temp |= MSTATUS_MPIE; + regs->setCSR(CSR_MSTATUS, csr_temp); - return true; -} + return true; + } -bool BASE_ISA::Exec_SRET() const { - std::uint32_t new_pc = 0; + bool BASE_ISA::Exec_SRET() const { + std::uint32_t new_pc = 0; - new_pc = regs->getCSR(CSR_SEPC); - regs->setPC(new_pc); + new_pc = regs->getCSR(CSR_SEPC); + regs->setPC(new_pc); - logger->debug("{} ns. PC: 0x{:x}. SRET: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC()); - return true; -} + logger->debug("{} ns. PC: 0x{:x}. SRET: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC()); + return true; + } -bool BASE_ISA::Exec_WFI() const { - logger->debug("{} ns. PC: 0x{:x}. WFI"); - return true; -} + bool BASE_ISA::Exec_WFI() const { + logger->debug("{} ns. PC: 0x{:x}. WFI"); + return true; + } -bool BASE_ISA::Exec_SFENCE() const { - logger->debug("{} ns. PC: 0x{:x}. SFENCE"); - return true; -} + bool BASE_ISA::Exec_SFENCE() const { + logger->debug("{} ns. PC: 0x{:x}. SFENCE"); + return true; + } -bool BASE_ISA::process_instruction(Instruction &inst, bool *breakpoint) { - bool PC_not_affected = true; + bool BASE_ISA::process_instruction(Instruction &inst, bool *breakpoint) { + bool PC_not_affected = true; - *breakpoint = false; - setInstr(inst.getInstr()); + *breakpoint = false; + setInstr(inst.getInstr()); - switch (decode()) { - case OP_LUI: - Exec_LUI(); - break; - case OP_AUIPC: - Exec_AUIPC(); - break; - case OP_JAL: - Exec_JAL(); - PC_not_affected = false; - break; - case OP_JALR: - Exec_JALR(); - PC_not_affected = false; - break; - case OP_BEQ: - Exec_BEQ(); - PC_not_affected = false; - break; - case OP_BNE: - Exec_BNE(); - PC_not_affected = false; - break; - case OP_BLT: - Exec_BLT(); - PC_not_affected = false; - break; - case OP_BGE: - Exec_BGE(); - PC_not_affected = false; - break; - case OP_BLTU: - Exec_BLTU(); - PC_not_affected = false; - break; - case OP_BGEU: - Exec_BGEU(); - PC_not_affected = false; - break; - case OP_LB: - Exec_LB(); - break; - case OP_LH: - Exec_LH(); - break; - case OP_LW: - Exec_LW(); - break; - case OP_LBU: - Exec_LBU(); - break; - case OP_LHU: - Exec_LHU(); - break; - case OP_SB: - Exec_SB(); - break; - case OP_SH: - Exec_SH(); - break; - case OP_SW: - Exec_SW(); - break; - case OP_ADDI: - Exec_ADDI(); - break; - case OP_SLTI: - Exec_SLTI(); - break; - case OP_SLTIU: - Exec_SLTIU(); - break; - case OP_XORI: - Exec_XORI(); - break; - case OP_ORI: - Exec_ORI(); - break; - case OP_ANDI: - Exec_ANDI(); - break; - case OP_SLLI: - PC_not_affected = Exec_SLLI(); - break; - case OP_SRLI: - Exec_SRLI(); - break; - case OP_SRAI: - Exec_SRAI(); - break; - case OP_ADD: - Exec_ADD(); - break; - case OP_SUB: - Exec_SUB(); - break; - case OP_SLL: - Exec_SLL(); - break; - case OP_SLT: - Exec_SLT(); - break; - case OP_SLTU: - Exec_SLTU(); - break; - case OP_XOR: - Exec_XOR(); - break; - case OP_SRL: - Exec_SRL(); - break; - case OP_SRA: - Exec_SRA(); - break; - case OP_OR: - Exec_OR(); - break; - case OP_AND: - Exec_AND(); - break; - case OP_FENCE: - Exec_FENCE(); - break; - case OP_ECALL: - Exec_ECALL(); - *breakpoint = true; - std::cout << "ECALL" << std::endl; - break; - case OP_EBREAK: - PC_not_affected = Exec_EBREAK(); + switch (decode()) { + case OP_LUI: + Exec_LUI(); + break; + case OP_AUIPC: + Exec_AUIPC(); + break; + case OP_JAL: + Exec_JAL(); + PC_not_affected = false; + break; + case OP_JALR: + Exec_JALR(); + PC_not_affected = false; + break; + case OP_BEQ: + Exec_BEQ(); + PC_not_affected = false; + break; + case OP_BNE: + Exec_BNE(); + PC_not_affected = false; + break; + case OP_BLT: + Exec_BLT(); + PC_not_affected = false; + break; + case OP_BGE: + Exec_BGE(); + PC_not_affected = false; + break; + case OP_BLTU: + Exec_BLTU(); + PC_not_affected = false; + break; + case OP_BGEU: + Exec_BGEU(); + PC_not_affected = false; + break; + case OP_LB: + Exec_LB(); + break; + case OP_LH: + Exec_LH(); + break; + case OP_LW: + Exec_LW(); + break; + case OP_LBU: + Exec_LBU(); + break; + case OP_LHU: + Exec_LHU(); + break; + case OP_SB: + Exec_SB(); + break; + case OP_SH: + Exec_SH(); + break; + case OP_SW: + Exec_SW(); + break; + case OP_ADDI: + Exec_ADDI(); + break; + case OP_SLTI: + Exec_SLTI(); + break; + case OP_SLTIU: + Exec_SLTIU(); + break; + case OP_XORI: + Exec_XORI(); + break; + case OP_ORI: + Exec_ORI(); + break; + case OP_ANDI: + Exec_ANDI(); + break; + case OP_SLLI: + PC_not_affected = Exec_SLLI(); + break; + case OP_SRLI: + Exec_SRLI(); + break; + case OP_SRAI: + Exec_SRAI(); + break; + case OP_ADD: + Exec_ADD(); + break; + case OP_SUB: + Exec_SUB(); + break; + case OP_SLL: + Exec_SLL(); + break; + case OP_SLT: + Exec_SLT(); + break; + case OP_SLTU: + Exec_SLTU(); + break; + case OP_XOR: + Exec_XOR(); + break; + case OP_SRL: + Exec_SRL(); + break; + case OP_SRA: + Exec_SRA(); + break; + case OP_OR: + Exec_OR(); + break; + case OP_AND: + Exec_AND(); + break; + case OP_FENCE: + Exec_FENCE(); + break; + case OP_ECALL: + Exec_ECALL(); + *breakpoint = true; + std::cout << "ECALL" << std::endl; + break; + case OP_EBREAK: + PC_not_affected = Exec_EBREAK(); // *breakpoint = true; - break; - case OP_CSRRW: - Exec_CSRRW(); - break; - case OP_CSRRS: - Exec_CSRRS(); - break; - case OP_CSRRC: - Exec_CSRRC(); - break; - case OP_CSRRWI: - Exec_CSRRWI(); - break; - case OP_CSRRSI: - Exec_CSRRSI(); - break; - case OP_CSRRCI: - Exec_CSRRCI(); - break; - case OP_MRET: - Exec_MRET(); - PC_not_affected = false; - break; - case OP_SRET: - Exec_SRET(); - PC_not_affected = false; - break; - case OP_WFI: - Exec_WFI(); - break; - case OP_SFENCE: - Exec_SFENCE(); - break; - [[unlikely]] default: - std::cout << "Wrong instruction" << "\n"; - inst.dump(); - NOP(); - //sc_stop(); - break; - } + break; + case OP_CSRRW: + Exec_CSRRW(); + break; + case OP_CSRRS: + Exec_CSRRS(); + break; + case OP_CSRRC: + Exec_CSRRC(); + break; + case OP_CSRRWI: + Exec_CSRRWI(); + break; + case OP_CSRRSI: + Exec_CSRRSI(); + break; + case OP_CSRRCI: + Exec_CSRRCI(); + break; + case OP_MRET: + Exec_MRET(); + PC_not_affected = false; + break; + case OP_SRET: + Exec_SRET(); + PC_not_affected = false; + break; + case OP_WFI: + Exec_WFI(); + break; + case OP_SFENCE: + Exec_SFENCE(); + break; + [[unlikely]] default: + std::cout << "Wrong instruction" << "\n"; + inst.dump(); + NOP(); + //sc_stop(); + break; + } - return PC_not_affected; -} + return PC_not_affected; + } -opCodes BASE_ISA::decode() { - switch (opcode()) { - case LUI: - return OP_LUI; - case AUIPC: - return OP_AUIPC; - case JAL: - return OP_JAL; - case JALR: - return OP_JALR; - case BEQ: - switch (get_funct3()) { - case BEQ_F: - return OP_BEQ; - case BNE_F: - return OP_BNE; - case BLT_F: - return OP_BLT; - case BGE_F: - return OP_BGE; - case BLTU_F: - return OP_BLTU; - case BGEU_F: - return OP_BGEU; - } - return OP_ERROR; - case LB: - switch (get_funct3()) { - case LB_F: - return OP_LB; - case LH_F: - return OP_LH; - case LW_F: - return OP_LW; - case LBU_F: - return OP_LBU; - case LHU_F: - return OP_LHU; - } - return OP_ERROR; - case SB: - switch (get_funct3()) { - case SB_F: - return OP_SB; - case SH_F: - return OP_SH; - case SW_F: - return OP_SW; - } - return OP_ERROR; - case ADDI: - switch (get_funct3()) { - case ADDI_F: - return OP_ADDI; - case SLTI_F: - return OP_SLTI; - case SLTIU_F: - return OP_SLTIU; - case XORI_F: - return OP_XORI; - case ORI_F: - return OP_ORI; - case ANDI_F: - return OP_ANDI; - case SLLI_F: - return OP_SLLI; - case SRLI_F: - switch (get_funct7()) { - case SRLI_F7: - return OP_SRLI; - case SRAI_F7: - return OP_SRAI; - } - return OP_ERROR; - } - return OP_ERROR; - case ADD: { - switch (get_funct3()) { - case ADD_F: - switch (get_funct7()) { - case ADD_F7: - return OP_ADD; - case SUB_F7: - return OP_SUB; - default: - return OP_ADD; - } - break; - case SLL_F: - return OP_SLL; - case SLT_F: - return OP_SLT; - case SLTU_F: - return OP_SLTU; - case XOR_F: - return OP_XOR; - case SRL_F: - switch (get_funct7()) { - case SRL_F7: - return OP_SRL; - case SRA_F7: - return OP_SRA; - default: - return OP_ERROR; - } - case OR_F: - return OP_OR; - case AND_F: - return OP_AND; - default: - return OP_ERROR; - } - } /* ADD */ - case FENCE: - return OP_FENCE; - case ECALL: { - switch (get_funct3()) { - case ECALL_F3: - switch (get_csr()) { - case ECALL_F: - return OP_ECALL; - case EBREAK_F: - return OP_EBREAK; - case URET_F: - return OP_URET; - case SRET_F: - return OP_SRET; - case MRET_F: - return OP_MRET; - case WFI_F: - return OP_WFI; - case SFENCE_F: - return OP_SFENCE; - } - if (m_instr.range(31, 25) == 0b0001001) { - return OP_SFENCE; - } - break; - case CSRRW: - return OP_CSRRW; - break; - case CSRRS: - return OP_CSRRS; - break; - case CSRRC: - return OP_CSRRC; - break; - case CSRRWI: - return OP_CSRRWI; - break; - case CSRRSI: - return OP_CSRRSI; - break; - case CSRRCI: - return OP_CSRRCI; - break; - } - } - break; - default: - return OP_ERROR; - } + opCodes BASE_ISA::decode() { + switch (opcode()) { + case LUI: + return OP_LUI; + case AUIPC: + return OP_AUIPC; + case JAL: + return OP_JAL; + case JALR: + return OP_JALR; + case BEQ: + switch (get_funct3()) { + case BEQ_F: + return OP_BEQ; + case BNE_F: + return OP_BNE; + case BLT_F: + return OP_BLT; + case BGE_F: + return OP_BGE; + case BLTU_F: + return OP_BLTU; + case BGEU_F: + return OP_BGEU; + } + return OP_ERROR; + case LB: + switch (get_funct3()) { + case LB_F: + return OP_LB; + case LH_F: + return OP_LH; + case LW_F: + return OP_LW; + case LBU_F: + return OP_LBU; + case LHU_F: + return OP_LHU; + } + return OP_ERROR; + case SB: + switch (get_funct3()) { + case SB_F: + return OP_SB; + case SH_F: + return OP_SH; + case SW_F: + return OP_SW; + } + return OP_ERROR; + case ADDI: + switch (get_funct3()) { + case ADDI_F: + return OP_ADDI; + case SLTI_F: + return OP_SLTI; + case SLTIU_F: + return OP_SLTIU; + case XORI_F: + return OP_XORI; + case ORI_F: + return OP_ORI; + case ANDI_F: + return OP_ANDI; + case SLLI_F: + return OP_SLLI; + case SRLI_F: + switch (get_funct7()) { + case SRLI_F7: + return OP_SRLI; + case SRAI_F7: + return OP_SRAI; + } + return OP_ERROR; + } + return OP_ERROR; + case ADD: { + switch (get_funct3()) { + case ADD_F: + switch (get_funct7()) { + case ADD_F7: + return OP_ADD; + case SUB_F7: + return OP_SUB; + default: + return OP_ADD; + } + break; + case SLL_F: + return OP_SLL; + case SLT_F: + return OP_SLT; + case SLTU_F: + return OP_SLTU; + case XOR_F: + return OP_XOR; + case SRL_F: + switch (get_funct7()) { + case SRL_F7: + return OP_SRL; + case SRA_F7: + return OP_SRA; + default: + return OP_ERROR; + } + case OR_F: + return OP_OR; + case AND_F: + return OP_AND; + default: + return OP_ERROR; + } + } /* ADD */ + case FENCE: + return OP_FENCE; + case ECALL: { + switch (get_funct3()) { + case ECALL_F3: + switch (get_csr()) { + case ECALL_F: + return OP_ECALL; + case EBREAK_F: + return OP_EBREAK; + case URET_F: + return OP_URET; + case SRET_F: + return OP_SRET; + case MRET_F: + return OP_MRET; + case WFI_F: + return OP_WFI; + case SFENCE_F: + return OP_SFENCE; + } + if (m_instr.range(31, 25) == 0b0001001) { + return OP_SFENCE; + } + break; + case CSRRW: + return OP_CSRRW; + break; + case CSRRS: + return OP_CSRRS; + break; + case CSRRC: + return OP_CSRRC; + break; + case CSRRWI: + return OP_CSRRWI; + break; + case CSRRSI: + return OP_CSRRSI; + break; + case CSRRCI: + return OP_CSRRCI; + break; + } + } + break; + default: + return OP_ERROR; + } - return OP_ERROR; -} + return OP_ERROR; + } +} \ No newline at end of file diff --git a/src/BusCtrl.cpp b/src/BusCtrl.cpp index 8f9d9c8..f6c2cc4 100644 --- a/src/BusCtrl.cpp +++ b/src/BusCtrl.cpp @@ -8,64 +8,67 @@ #include "BusCtrl.h" -SC_HAS_PROCESS(BusCtrl); -BusCtrl::BusCtrl(sc_core::sc_module_name const &name) : - sc_module(name), cpu_instr_socket("cpu_instr_socket"), cpu_data_socket( - "cpu_data_socket"), memory_socket("memory_socket"), trace_socket( - "trace_socket") { - cpu_instr_socket.register_b_transport(this, &BusCtrl::b_transport); - cpu_data_socket.register_b_transport(this, &BusCtrl::b_transport); +namespace riscv_tlm { - cpu_instr_socket.register_get_direct_mem_ptr(this, - &BusCtrl::instr_direct_mem_ptr); - memory_socket.register_invalidate_direct_mem_ptr(this, - &BusCtrl::invalidate_direct_mem_ptr); -} + SC_HAS_PROCESS(BusCtrl); -void BusCtrl::b_transport(tlm::tlm_generic_payload &trans, - sc_core::sc_time &delay) { + BusCtrl::BusCtrl(sc_core::sc_module_name const &name) : + sc_module(name), cpu_instr_socket("cpu_instr_socket"), cpu_data_socket( + "cpu_data_socket"), memory_socket("memory_socket"), trace_socket( + "trace_socket") { + cpu_instr_socket.register_b_transport(this, &BusCtrl::b_transport); + cpu_data_socket.register_b_transport(this, &BusCtrl::b_transport); - sc_dt::uint64 adr = trans.get_address() / 4; + cpu_instr_socket.register_get_direct_mem_ptr(this, + &BusCtrl::instr_direct_mem_ptr); + memory_socket.register_invalidate_direct_mem_ptr(this, + &BusCtrl::invalidate_direct_mem_ptr); + } - if (adr >= TO_HOST_ADDRESS / 4) { - std::cout << "To host\n" << std::flush; - sc_core::sc_stop(); - return; - } + void BusCtrl::b_transport(tlm::tlm_generic_payload &trans, + sc_core::sc_time &delay) { - switch (adr) { - case TIMER_MEMORY_ADDRESS_HI / 4: - case TIMER_MEMORY_ADDRESS_LO / 4: - case TIMERCMP_MEMORY_ADDRESS_HI / 4: - case TIMERCMP_MEMORY_ADDRESS_LO / 4: - timer_socket->b_transport(trans, delay); - break; - case TRACE_MEMORY_ADDRESS / 4: - trace_socket->b_transport(trans, delay); - break; - [[likely]] default: - memory_socket->b_transport(trans, delay); - break; - } + sc_dt::uint64 adr = trans.get_address() / 4; + + if (adr >= TO_HOST_ADDRESS / 4) { + std::cout << "To host\n" << std::flush; + sc_core::sc_stop(); + return; + } + + switch (adr) { + case TIMER_MEMORY_ADDRESS_HI / 4: + case TIMER_MEMORY_ADDRESS_LO / 4: + case TIMERCMP_MEMORY_ADDRESS_HI / 4: + case TIMERCMP_MEMORY_ADDRESS_LO / 4: + timer_socket->b_transport(trans, delay); + break; + case TRACE_MEMORY_ADDRESS / 4: + trace_socket->b_transport(trans, delay); + break; + [[likely]] default: + memory_socket->b_transport(trans, delay); + break; + } #if 0 - if (cmd == tlm::TLM_READ_COMMAND) { - log->SC_log(Log::DEBUG) << "RD Address: @0x" << hex << adr << dec << endl; - } else { - log->SC_log(Log::DEBUG) << "WR Address: @0x" << hex << adr << dec << endl; - } + if (cmd == tlm::TLM_READ_COMMAND) { + log->SC_log(Log::DEBUG) << "RD Address: @0x" << hex << adr << dec << endl; + } else { + log->SC_log(Log::DEBUG) << "WR Address: @0x" << hex << adr << dec << endl; + } #endif - trans.set_response_status(tlm::TLM_OK_RESPONSE); -} + trans.set_response_status(tlm::TLM_OK_RESPONSE); + } -bool BusCtrl::instr_direct_mem_ptr(tlm::tlm_generic_payload &gp, - tlm::tlm_dmi &dmi_data) { - return memory_socket->get_direct_mem_ptr(gp, dmi_data); -} - -void BusCtrl::invalidate_direct_mem_ptr(sc_dt::uint64 start, - sc_dt::uint64 end) { - cpu_instr_socket->invalidate_direct_mem_ptr(start, end); -} + bool BusCtrl::instr_direct_mem_ptr(tlm::tlm_generic_payload &gp, + tlm::tlm_dmi &dmi_data) { + return memory_socket->get_direct_mem_ptr(gp, dmi_data); + } + void BusCtrl::invalidate_direct_mem_ptr(sc_dt::uint64 start, + sc_dt::uint64 end) { + cpu_instr_socket->invalidate_direct_mem_ptr(start, end); + } +} \ No newline at end of file diff --git a/src/CPU.cpp b/src/CPU.cpp index 218e439..02b0d50 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -7,222 +7,230 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CPU.h" -SC_HAS_PROCESS(CPU); -CPU::CPU(sc_core::sc_module_name const &name, std::uint32_t PC, bool debug) : - sc_module(name), instr_bus("instr_bus"), inst(0), default_time(10, - sc_core::SC_NS), INSTR(0) { - register_bank = new Registers(); - mem_intf = new MemoryInterface(); +namespace riscv_tlm { - perf = Performance::getInstance(); + SC_HAS_PROCESS(CPU); - register_bank->setPC(PC); - register_bank->setValue(Registers::sp, (Memory::SIZE / 4) - 1); + CPU::CPU(sc_core::sc_module_name const &name, std::uint32_t PC, bool debug) : + sc_module(name), instr_bus("instr_bus"), inst(0), default_time(10, + sc_core::SC_NS), INSTR(0) { + register_bank = new Registers(); + mem_intf = new MemoryInterface(); - irq_line_socket.register_b_transport(this, &CPU::call_interrupt); - interrupt = false; + perf = Performance::getInstance(); - int_cause = 0; - irq_already_down = false; + register_bank->setPC(PC); + register_bank->setValue(Registers::sp, (Memory::SIZE / 4) - 1); - dmi_ptr_valid = false; - instr_bus.register_invalidate_direct_mem_ptr(this, - &CPU::invalidate_direct_mem_ptr); + irq_line_socket.register_b_transport(this, &CPU::call_interrupt); + interrupt = false; - exec = new BASE_ISA(0, register_bank, mem_intf); - c_inst = new C_extension(0, register_bank, mem_intf); - m_inst = new M_extension(0, register_bank, mem_intf); - a_inst = new A_extension(0, register_bank, mem_intf); + int_cause = 0; + irq_already_down = false; - m_qk = new tlm_utils::tlm_quantumkeeper(); - m_qk->reset(); + dmi_ptr_valid = false; + instr_bus.register_invalidate_direct_mem_ptr(this, + &CPU::invalidate_direct_mem_ptr); - trans.set_command(tlm::TLM_READ_COMMAND); - trans.set_data_ptr(reinterpret_cast(&INSTR)); - trans.set_data_length(4); - trans.set_streaming_width(4); // = data_length to indicate no streaming - trans.set_byte_enable_ptr(nullptr); // 0 indicates unused - trans.set_dmi_allowed(false); // Mandatory initial value - trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); + exec = new BASE_ISA(0, register_bank, mem_intf); + c_inst = new C_extension(0, register_bank, mem_intf); + m_inst = new M_extension(0, register_bank, mem_intf); + a_inst = new A_extension(0, register_bank, mem_intf); - if (!debug) { - SC_THREAD(CPU_thread); - } + m_qk = new tlm_utils::tlm_quantumkeeper(); + m_qk->reset(); - logger = spdlog::get("my_logger"); -} + trans.set_command(tlm::TLM_READ_COMMAND); + trans.set_data_ptr(reinterpret_cast(&INSTR)); + trans.set_data_length(4); + trans.set_streaming_width(4); // = data_length to indicate no streaming + trans.set_byte_enable_ptr(nullptr); // 0 indicates unused + trans.set_dmi_allowed(false); // Mandatory initial value + trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); -CPU::~CPU() { - delete register_bank; - delete mem_intf; - delete exec; - delete c_inst; - delete m_inst; - delete a_inst; - delete m_qk; -} - -bool CPU::cpu_process_IRQ() { - std::uint32_t csr_temp; - bool ret_value = false; - - if (interrupt) { - csr_temp = register_bank->getCSR(CSR_MSTATUS); - if ((csr_temp & MSTATUS_MIE) == 0) { - logger->debug("{} ns. PC: 0x{:x}. Interrupt delayed", sc_core::sc_time_stamp().value(), register_bank->getPC()); - - return ret_value; - } - - csr_temp = register_bank->getCSR(CSR_MIP); - - if ((csr_temp & MIP_MEIP) == 0) { - csr_temp |= MIP_MEIP; // MEIP bit in MIP register (11th bit) - register_bank->setCSR(CSR_MIP, csr_temp); - - logger->debug("{} ns. PC: 0x{:x}. Interrupt!", sc_core::sc_time_stamp().value(), register_bank->getPC()); - - - /* updated MEPC register */ - std::uint32_t old_pc = register_bank->getPC(); - register_bank->setCSR(CSR_MEPC, old_pc); - - logger->debug("{} ns. PC: 0x{:x}. Old PC Value 0x{:x}", sc_core::sc_time_stamp().value(), register_bank->getPC(), - old_pc); - - /* update MCAUSE register */ - register_bank->setCSR(CSR_MCAUSE, 0x80000000); - - /* set new PC address */ - std::uint32_t new_pc = register_bank->getCSR(CSR_MTVEC); - //new_pc = new_pc & 0xFFFFFFFC; // last two bits always to 0 - logger->debug("{} ns. PC: 0x{:x}. NEW PC Value 0x{:x}", sc_core::sc_time_stamp().value(), register_bank->getPC(), - new_pc); - register_bank->setPC(new_pc); - - ret_value = true; - interrupt = false; - irq_already_down = false; - } - } else { - if (!irq_already_down) { - csr_temp = register_bank->getCSR(CSR_MIP); - csr_temp &= ~MIP_MEIP; - register_bank->setCSR(CSR_MIP, csr_temp); - irq_already_down = true; - } - } - - return ret_value; -} - -bool CPU::CPU_step() { - bool PC_not_affected = false; - - /* Get new PC value */ - if (dmi_ptr_valid) { - /* if memory_offset at Memory module is set, this won't work */ - std::memcpy(&INSTR, dmi_ptr + register_bank->getPC(), 4); - } else { - sc_core::sc_time delay = sc_core::SC_ZERO_TIME; - tlm::tlm_dmi dmi_data; - trans.set_address(register_bank->getPC()); - instr_bus->b_transport(trans, delay); - - if (trans.is_response_error()) { - SC_REPORT_ERROR("CPU base", "Read memory"); - } - - if (trans.is_dmi_allowed()) { - dmi_ptr_valid = instr_bus->get_direct_mem_ptr(trans, dmi_data); - if (dmi_ptr_valid) { - std::cout << "Get DMI_PTR " << std::endl; - dmi_ptr = dmi_data.get_dmi_ptr(); - } - } - } - - perf->codeMemoryRead(); - inst.setInstr(INSTR); - bool breakpoint = false; - - /* check what type of instruction is and execute it */ - switch (inst.check_extension()) { - [[likely]] case BASE_EXTENSION: - PC_not_affected = exec->process_instruction(inst, &breakpoint); - if (PC_not_affected) { - register_bank->incPC(); + if (!debug) { + SC_THREAD(CPU_thread); } - break; - case C_EXTENSION: - PC_not_affected = c_inst->process_instruction(inst, &breakpoint); - if (PC_not_affected) { - register_bank->incPCby2(); + + logger = spdlog::get("my_logger"); + } + + CPU::~CPU() { + delete register_bank; + delete mem_intf; + delete exec; + delete c_inst; + delete m_inst; + delete a_inst; + delete m_qk; + } + + bool CPU::cpu_process_IRQ() { + std::uint32_t csr_temp; + bool ret_value = false; + + if (interrupt) { + csr_temp = register_bank->getCSR(CSR_MSTATUS); + if ((csr_temp & MSTATUS_MIE) == 0) { + logger->debug("{} ns. PC: 0x{:x}. Interrupt delayed", sc_core::sc_time_stamp().value(), + register_bank->getPC()); + + return ret_value; + } + + csr_temp = register_bank->getCSR(CSR_MIP); + + if ((csr_temp & MIP_MEIP) == 0) { + csr_temp |= MIP_MEIP; // MEIP bit in MIP register (11th bit) + register_bank->setCSR(CSR_MIP, csr_temp); + + logger->debug("{} ns. PC: 0x{:x}. Interrupt!", sc_core::sc_time_stamp().value(), + register_bank->getPC()); + + + /* updated MEPC register */ + std::uint32_t old_pc = register_bank->getPC(); + register_bank->setCSR(CSR_MEPC, old_pc); + + logger->debug("{} ns. PC: 0x{:x}. Old PC Value 0x{:x}", sc_core::sc_time_stamp().value(), + register_bank->getPC(), + old_pc); + + /* update MCAUSE register */ + register_bank->setCSR(CSR_MCAUSE, 0x80000000); + + /* set new PC address */ + std::uint32_t new_pc = register_bank->getCSR(CSR_MTVEC); + //new_pc = new_pc & 0xFFFFFFFC; // last two bits always to 0 + logger->debug("{} ns. PC: 0x{:x}. NEW PC Value 0x{:x}", sc_core::sc_time_stamp().value(), + register_bank->getPC(), + new_pc); + register_bank->setPC(new_pc); + + ret_value = true; + interrupt = false; + irq_already_down = false; + } + } else { + if (!irq_already_down) { + csr_temp = register_bank->getCSR(CSR_MIP); + csr_temp &= ~MIP_MEIP; + register_bank->setCSR(CSR_MIP, csr_temp); + irq_already_down = true; + } } - break; - case M_EXTENSION: - PC_not_affected = m_inst->process_instruction(inst); - if (PC_not_affected) { - register_bank->incPC(); + + return ret_value; + } + + bool CPU::CPU_step() { + bool PC_not_affected = false; + + /* Get new PC value */ + if (dmi_ptr_valid) { + /* if memory_offset at Memory module is set, this won't work */ + std::memcpy(&INSTR, dmi_ptr + register_bank->getPC(), 4); + } else { + sc_core::sc_time delay = sc_core::SC_ZERO_TIME; + tlm::tlm_dmi dmi_data; + trans.set_address(register_bank->getPC()); + instr_bus->b_transport(trans, delay); + + if (trans.is_response_error()) { + SC_REPORT_ERROR("CPU base", "Read memory"); + } + + if (trans.is_dmi_allowed()) { + dmi_ptr_valid = instr_bus->get_direct_mem_ptr(trans, dmi_data); + if (dmi_ptr_valid) { + std::cout << "Get DMI_PTR " << std::endl; + dmi_ptr = dmi_data.get_dmi_ptr(); + } + } } - break; - case A_EXTENSION: - PC_not_affected = a_inst->process_instruction(inst); - if (PC_not_affected) { - register_bank->incPC(); + + perf->codeMemoryRead(); + inst.setInstr(INSTR); + bool breakpoint = false; + + /* check what type of instruction is and execute it */ + switch (inst.check_extension()) { + [[likely]] case BASE_EXTENSION: + PC_not_affected = exec->process_instruction(inst, &breakpoint); + if (PC_not_affected) { + register_bank->incPC(); + } + break; + case C_EXTENSION: + PC_not_affected = c_inst->process_instruction(inst, &breakpoint); + if (PC_not_affected) { + register_bank->incPCby2(); + } + break; + case M_EXTENSION: + PC_not_affected = m_inst->process_instruction(inst); + if (PC_not_affected) { + register_bank->incPC(); + } + break; + case A_EXTENSION: + PC_not_affected = a_inst->process_instruction(inst); + if (PC_not_affected) { + register_bank->incPC(); + } + break; + [[unlikely]] default: + std::cout << "Extension not implemented yet" << std::endl; + inst.dump(); + exec->NOP(); } - break; - [[unlikely]] default: - std::cout << "Extension not implemented yet" << std::endl; - inst.dump(); - exec->NOP(); - } - if (breakpoint) { - std::cout << "Breakpoint set to true\n"; - } + if (breakpoint) { + std::cout << "Breakpoint set to true\n"; + } - perf->instructionsInc(); + perf->instructionsInc(); - return breakpoint; -} + return breakpoint; + } -[[noreturn]] void CPU::CPU_thread() { + [[noreturn]] void CPU::CPU_thread() { - sc_core::sc_time instr_time = default_time; + sc_core::sc_time instr_time = default_time; - while (true) { + while (true) { - /* Process one instruction */ - CPU_step(); + /* Process one instruction */ + CPU_step(); - /* Process IRQ (if any) */ - cpu_process_IRQ(); + /* Process IRQ (if any) */ + cpu_process_IRQ(); - /* Fixed instruction time to 10 ns (i.e. 100 MHz) */ + /* Fixed instruction time to 10 ns (i.e. 100 MHz) */ //#define USE_QK #ifdef USE_QK - // Model time used for additional processing - m_qk->inc(default_time); - if (m_qk->need_sync()) { - m_qk->sync(); - } + // Model time used for additional processing + m_qk->inc(default_time); + if (m_qk->need_sync()) { + m_qk->sync(); + } #else - sc_core::wait(instr_time); + sc_core::wait(instr_time); #endif - } // while(1) -} // CPU_thread + } // while(1) + } // CPU_thread -void CPU::call_interrupt(tlm::tlm_generic_payload &m_trans, - sc_core::sc_time &delay) { - interrupt = true; - /* Socket caller send a cause (its id) */ - memcpy(&int_cause, m_trans.get_data_ptr(), sizeof(std::uint32_t)); - delay = sc_core::SC_ZERO_TIME; -} + void CPU::call_interrupt(tlm::tlm_generic_payload &m_trans, + sc_core::sc_time &delay) { + interrupt = true; + /* Socket caller send a cause (its id) */ + memcpy(&int_cause, m_trans.get_data_ptr(), sizeof(std::uint32_t)); + delay = sc_core::SC_ZERO_TIME; + } -void CPU::invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end) { - (void) start; - (void) end; - dmi_ptr_valid = false; -} + void CPU::invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end) { + (void) start; + (void) end; + dmi_ptr_valid = false; + } +} \ No newline at end of file diff --git a/src/C_extension.cpp b/src/C_extension.cpp index 1db40d8..e70f446 100644 --- a/src/C_extension.cpp +++ b/src/C_extension.cpp @@ -6,720 +6,748 @@ */ #include "C_extension.h" -op_C_Codes C_extension::decode() const { - - switch (opcode()) { - - case 0b00: - switch (get_funct3()) { - case C_ADDI4SPN: - return OP_C_ADDI4SPN; - break; - case C_FLD: - return OP_C_FLD; - break; - case C_LW: - return OP_C_LW; - break; - case C_FLW: - return OP_C_FLW; - break; - case C_FSD: - return OP_C_FSD; - break; - case C_SW: - return OP_C_SW; - break; - case C_FSW: - return OP_C_FSW; - break; - [[unlikely]] default: - return OP_C_ERROR; - break; - } - break; - - case 0b01: - switch (get_funct3()) { - case C_ADDI: - return OP_C_ADDI; - break; - case C_JAL: - return OP_C_JAL; - break; - case C_LI: - return OP_C_LI; - break; - case C_ADDI16SP: - return OP_C_ADDI16SP; - break; - case C_SRLI: - switch (m_instr.range(11, 10)) { - case C_2_SRLI: - return OP_C_SRLI; - break; - case C_2_SRAI: - return OP_C_SRAI; - break; - case C_2_ANDI: - return OP_C_ANDI; - break; - case C_2_SUB: - switch (m_instr.range(6, 5)) { - case C_3_SUB: - return OP_C_SUB; - break; - case C_3_XOR: - return OP_C_XOR; - break; - case C_3_OR: - return OP_C_OR; - break; - case C_3_AND: - return OP_C_AND; - break; - } - } - break; - case C_J: - return OP_C_J; - break; - case C_BEQZ: - return OP_C_BEQZ; - break; - case C_BNEZ: - return OP_C_BNEZ; - break; - [[unlikely]] default: - return OP_C_ERROR; - break; - } - break; - - case 0b10: - switch (get_funct3()) { - case C_SLLI: - return OP_C_SLLI; - break; - case C_FLDSP: - case C_LWSP: - return OP_C_LWSP; - break; - case C_FLWSP: - return OP_C_FLWSP; - break; - case C_JR: - if (m_instr[12] == 0) { - if (m_instr.range(6, 2) == 0) { - return OP_C_JR; - } else { - return OP_C_MV; - } - } else { - if (m_instr.range(11, 2) == 0) { - return OP_C_EBREAK; - } else if (m_instr.range(6, 2) == 0) { - return OP_C_JALR; - } else { - return OP_C_ADD; - } - } - break; - case C_FDSP: - break; - case C_SWSP: - return OP_C_SWSP; - break; - case C_FWWSP: - [[unlikely]] default: - return OP_C_ERROR; - break; - } - break; - - [[unlikely]] default: - - return OP_C_ERROR; - break; - } - return OP_C_ERROR; -} - -bool C_extension::Exec_C_JR() { - std::uint32_t mem_addr; - int rs1; - int new_pc; - - rs1 = get_rs1(); - mem_addr = 0; - - new_pc = static_cast(static_cast((regs->getValue(rs1)) + static_cast(mem_addr)) & 0xFFFFFFFE); - - logger->debug("{} ns. PC: 0x{:x}. C.JR: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), new_pc); - - regs->setPC(new_pc); - - return true; -} - -bool C_extension::Exec_C_MV() { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rd(); - rs1 = 0; - rs2 = get_rs2(); - - calc = regs->getValue(rs1) + regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.MV: x{:d}(0x{:x}) + x{:d}(0x{:x}) -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), rd, calc); - - return true; -} - -bool C_extension::Exec_C_ADD() { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rs1(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - calc = regs->getValue(rs1) + regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.ADD: x{:d} + x{} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd, calc); - - return true; -} - -bool C_extension::Exec_C_LWSP() { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - std::uint32_t data; - - // lw rd, offset[7:2](x2) - - rd = get_rd(); - rs1 = 2; - imm = get_imm_LWSP(); - - mem_addr = imm + regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); - - regs->setValue(rd, data); - - logger->debug("{} ns. PC: 0x{:x}. C.LWSP: x{:d} + {:d}(@0x{:x}) -> x{:d}({:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, imm, mem_addr, rd, data); - - return true; -} +namespace riscv_tlm { + + op_C_Codes C_extension::decode() const { + + switch (opcode()) { + + case 0b00: + switch (get_funct3()) { + case C_ADDI4SPN: + return OP_C_ADDI4SPN; + break; + case C_FLD: + return OP_C_FLD; + break; + case C_LW: + return OP_C_LW; + break; + case C_FLW: + return OP_C_FLW; + break; + case C_FSD: + return OP_C_FSD; + break; + case C_SW: + return OP_C_SW; + break; + case C_FSW: + return OP_C_FSW; + break; + [[unlikely]] default: + return OP_C_ERROR; + break; + } + break; + + case 0b01: + switch (get_funct3()) { + case C_ADDI: + return OP_C_ADDI; + break; + case C_JAL: + return OP_C_JAL; + break; + case C_LI: + return OP_C_LI; + break; + case C_ADDI16SP: + return OP_C_ADDI16SP; + break; + case C_SRLI: + switch (m_instr.range(11, 10)) { + case C_2_SRLI: + return OP_C_SRLI; + break; + case C_2_SRAI: + return OP_C_SRAI; + break; + case C_2_ANDI: + return OP_C_ANDI; + break; + case C_2_SUB: + switch (m_instr.range(6, 5)) { + case C_3_SUB: + return OP_C_SUB; + break; + case C_3_XOR: + return OP_C_XOR; + break; + case C_3_OR: + return OP_C_OR; + break; + case C_3_AND: + return OP_C_AND; + break; + } + } + break; + case C_J: + return OP_C_J; + break; + case C_BEQZ: + return OP_C_BEQZ; + break; + case C_BNEZ: + return OP_C_BNEZ; + break; + [[unlikely]] default: + return OP_C_ERROR; + break; + } + break; + + case 0b10: + switch (get_funct3()) { + case C_SLLI: + return OP_C_SLLI; + break; + case C_FLDSP: + case C_LWSP: + return OP_C_LWSP; + break; + case C_FLWSP: + return OP_C_FLWSP; + break; + case C_JR: + if (m_instr[12] == 0) { + if (m_instr.range(6, 2) == 0) { + return OP_C_JR; + } else { + return OP_C_MV; + } + } else { + if (m_instr.range(11, 2) == 0) { + return OP_C_EBREAK; + } else if (m_instr.range(6, 2) == 0) { + return OP_C_JALR; + } else { + return OP_C_ADD; + } + } + break; + case C_FDSP: + break; + case C_SWSP: + return OP_C_SWSP; + break; + case C_FWWSP: + [[unlikely]] + default: + return OP_C_ERROR; + break; + } + break; + + [[unlikely]] default: + + return OP_C_ERROR; + break; + } + return OP_C_ERROR; + } + + bool C_extension::Exec_C_JR() { + std::uint32_t mem_addr; + int rs1; + int new_pc; + + rs1 = get_rs1(); + mem_addr = 0; + + new_pc = static_cast( + static_cast((regs->getValue(rs1)) + static_cast(mem_addr)) & 0xFFFFFFFE); + + logger->debug("{} ns. PC: 0x{:x}. C.JR: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), new_pc); + + regs->setPC(new_pc); + + return true; + } + + bool C_extension::Exec_C_MV() { + int rd, rs1, rs2; + std::uint32_t calc; + + rd = get_rd(); + rs1 = 0; + rs2 = get_rs2(); + + calc = regs->getValue(rs1) + regs->getValue(rs2); + regs->setValue(rd, static_cast(calc)); + + logger->debug("{} ns. PC: 0x{:x}. C.MV: x{:d}(0x{:x}) + x{:d}(0x{:x}) -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), + rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), rd, calc); + + return true; + } + + bool C_extension::Exec_C_ADD() { + int rd, rs1, rs2; + std::uint32_t calc; + + rd = get_rs1(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + calc = regs->getValue(rs1) + regs->getValue(rs2); + regs->setValue(rd, static_cast(calc)); + + logger->debug("{} ns. PC: 0x{:x}. C.ADD: x{:d} + x{} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd, calc); + + return true; + } + + bool C_extension::Exec_C_LWSP() { + std::uint32_t mem_addr; + int rd, rs1; + std::int32_t imm; + std::uint32_t data; + + // lw rd, offset[7:2](x2) + + rd = get_rd(); + rs1 = 2; + imm = get_imm_LWSP(); + + mem_addr = imm + regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 4); + perf->dataMemoryRead(); + regs->setValue(rd, static_cast(data)); + + regs->setValue(rd, data); + + logger->debug("{} ns. PC: 0x{:x}. C.LWSP: x{:d} + {:d}(@0x{:x}) -> x{:d}({:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), + rs1, imm, mem_addr, rd, data); + + return true; + } + + bool C_extension::Exec_C_ADDI4SPN() { + int rd, rs1; + std::int32_t imm; + std::int32_t calc; -bool C_extension::Exec_C_ADDI4SPN() { - int rd, rs1; - std::int32_t imm; - std::int32_t calc; + rd = get_rdp(); + rs1 = 2; + imm = get_imm_ADDI4SPN(); - rd = get_rdp(); - rs1 = 2; - imm = get_imm_ADDI4SPN(); + if (imm == 0) { + RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr); + return false; + } - if (imm == 0) { - RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr); - return false; - } + calc = static_cast(regs->getValue(rs1)) + imm; + regs->setValue(rd, calc); - calc = static_cast(regs->getValue(rs1)) + imm; - regs->setValue(rd, calc); + logger->debug("{} ns. PC: 0x{:x}. C.ADDI4SN: x{:d} + (0x{:x}) + {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), + rs1, regs->getValue(rs1), imm, rd, calc); - logger->debug("{} ns. PC: 0x{:x}. C.ADDI4SN: x{:d} + (0x{:x}) + {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), imm, rd, calc); + return true; + } - return true; -} + bool C_extension::Exec_C_ADDI16SP() { + // addi x2, x2, nzimm[9:4] + int rd; + std::int32_t imm; -bool C_extension::Exec_C_ADDI16SP() { - // addi x2, x2, nzimm[9:4] - int rd; - std::int32_t imm; + if (get_rd() == 2) { + int rs1; + std::int32_t calc; - if (get_rd() == 2) { - int rs1; - std::int32_t calc; + rd = 2; + rs1 = 2; + imm = get_imm_ADDI16SP(); + + calc = static_cast(regs->getValue(rs1)) + imm; + regs->setValue(rd, calc); + + logger->debug("{} ns. PC: 0x{:x}. C.ADDI16SP: x{:d} + {:d} -> x{:d} (0x{:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), + rs1, imm, rd, calc); + } else { + /* C.LUI OPCODE */ + rd = get_rd(); + imm = get_imm_LUI(); + regs->setValue(rd, imm); + + logger->debug("{} ns. PC: 0x{:x}. C.LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), + rd, imm); + } + + return true; + } - rd = 2; - rs1 = 2; - imm = get_imm_ADDI16SP(); + bool C_extension::Exec_C_SWSP() { + // sw rs2, offset(x2) + std::uint32_t mem_addr; + int rs1, rs2; + std::int32_t imm; + std::uint32_t data; - calc = static_cast(regs->getValue(rs1)) + imm; - regs->setValue(rd, calc); + rs1 = 2; + rs2 = get_rs2(); + imm = get_imm_CSS(); - logger->debug("{} ns. PC: 0x{:x}. C.ADDI16SP: x{:d} + {:d} -> x{:d} (0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, imm, rd, calc); - } else { - /* C.LUI OPCODE */ - rd = get_rd(); - imm = get_imm_LUI(); - regs->setValue(rd, imm); + mem_addr = imm + regs->getValue(rs1); + data = regs->getValue(rs2); + + mem_intf->writeDataMem(mem_addr, data, 4); + perf->dataMemoryWrite(); + + logger->debug("{} ns. PC: 0x{:x}. C.SWSP: x{:d}(0x{:x}) -> x{:d} + {} (@0x{:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), + rs2, data, rs1, imm, mem_addr); - logger->debug("{} ns. PC: 0x{:x}. C.LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), - rd, imm); - } + return true; + } - return true; -} + bool C_extension::Exec_C_BEQZ() { + int rs1; + int new_pc; + std::uint32_t val1; -bool C_extension::Exec_C_SWSP() { - // sw rs2, offset(x2) - std::uint32_t mem_addr; - int rs1, rs2; - std::int32_t imm; - std::uint32_t data; + rs1 = get_rs1p(); + val1 = regs->getValue(rs1); - rs1 = 2; - rs2 = get_rs2(); - imm = get_imm_CSS(); + if (val1 == 0) { + new_pc = static_cast(regs->getPC()) + get_imm_CB(); + regs->setPC(new_pc); + } else { + regs->incPCby2(); + new_pc = static_cast(regs->getPC()); + } - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); + logger->debug("{} ns. PC: 0x{:x}. C.BEQZ: x{:d}(0x{:x}) == 0? -> PC (0xx{:d})", + sc_core::sc_time_stamp().value(), regs->getPC(), + rs1, val1, new_pc); - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); + return true; + } - logger->debug("{} ns. PC: 0x{:x}. C.SWSP: x{:d}(0x{:x}) -> x{:d} + {} (@0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs2, data, rs1, imm, mem_addr); + bool C_extension::Exec_C_BNEZ() { + int rs1; + int new_pc; + std::uint32_t val1; - return true; -} + rs1 = get_rs1p(); + val1 = regs->getValue(rs1); -bool C_extension::Exec_C_BEQZ() { - int rs1; - int new_pc; - std::uint32_t val1; + if (val1 != 0) { + new_pc = static_cast(regs->getPC()) + get_imm_CB(); + regs->setPC(new_pc); + } else { + regs->incPCby2(); //PC <- PC +2 + new_pc = static_cast(regs->getPC()); + } - rs1 = get_rs1p(); - val1 = regs->getValue(rs1); + logger->debug("{} ns. PC: 0x{:x}. C.BNEZ: x{:d}(0x{:x}) != 0? -> PC (0xx{:d})", + sc_core::sc_time_stamp().value(), regs->getPC(), + rs1, val1, new_pc); - if (val1 == 0) { - new_pc = static_cast(regs->getPC()) + get_imm_CB(); - regs->setPC(new_pc); - } else { - regs->incPCby2(); - new_pc = static_cast(regs->getPC()); - } + return true; + } - logger->debug("{} ns. PC: 0x{:x}. C.BEQZ: x{:d}(0x{:x}) == 0? -> PC (0xx{:d})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, val1, new_pc); + bool C_extension::Exec_C_LI() { + int rd, rs1; + std::int32_t imm; + std::int32_t calc; - return true; -} + rd = get_rd(); + rs1 = 0; + imm = get_imm_ADDI(); -bool C_extension::Exec_C_BNEZ() { - int rs1; - int new_pc; - std::uint32_t val1; + calc = static_cast(regs->getValue(rs1)) + imm; + regs->setValue(rd, calc); - rs1 = get_rs1p(); - val1 = regs->getValue(rs1); + logger->debug("{} ns. PC: 0x{:x}. C.LI: x{:d} ({:d}) + {:d} -> x{:d}(0x{:x}) ", + sc_core::sc_time_stamp().value(), regs->getPC(), + rs1, regs->getValue(rs1), imm, rd, calc); - if (val1 != 0) { - new_pc = static_cast(regs->getPC()) + get_imm_CB(); - regs->setPC(new_pc); - } else { - regs->incPCby2(); //PC <- PC +2 - new_pc = static_cast(regs->getPC()); - } + return true; + } - logger->debug("{} ns. PC: 0x{:x}. C.BNEZ: x{:d}(0x{:x}) != 0? -> PC (0xx{:d})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, val1, new_pc); + bool C_extension::Exec_C_SRLI() { + int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; - return true; -} + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2(); -bool C_extension::Exec_C_LI() { - int rd, rs1; - std::int32_t imm; - std::int32_t calc; + shift = rs2 & 0x1F; - rd = get_rd(); - rs1 = 0; - imm = get_imm_ADDI(); + calc = static_cast(regs->getValue(rs1)) >> shift; + regs->setValue(rd, static_cast(calc)); - calc = static_cast(regs->getValue(rs1)) + imm; - regs->setValue(rd, calc); + logger->debug("{} ns. PC: 0x{:x}. C.SRLI: x{:d} >> {} -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, shift, rd); - logger->debug("{} ns. PC: 0x{:x}. C.LI: x{:d} ({:d}) + {:d} -> x{:d}(0x{:x}) ", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), imm, rd, calc); + return true; + } - return true; -} + bool C_extension::Exec_C_SRAI() { + int rd, rs1, rs2; + std::uint32_t shift; + std::int32_t calc; -bool C_extension::Exec_C_SRLI() { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2(); - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2(); + shift = rs2 & 0x1F; - shift = rs2 & 0x1F; + calc = static_cast(regs->getValue(rs1)) >> shift; + regs->setValue(rd, calc); - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, static_cast(calc)); + logger->debug("{} ns. PC: 0x{:x}. C.SRAI: x{:d} >> {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, shift, rd, calc); - logger->debug("{} ns. PC: 0x{:x}. C.SRLI: x{:d} >> {} -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, shift, rd); + return true; + } - return true; -} + bool C_extension::Exec_C_SLLI() { + int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; -bool C_extension::Exec_C_SRAI() { - int rd, rs1, rs2; - std::uint32_t shift; - std::int32_t calc; + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_imm_ADDI(); - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2(); + shift = rs2 & 0x1F; - shift = rs2 & 0x1F; + calc = static_cast(regs->getValue(rs1)) << shift; + regs->setValue(rd, static_cast(calc)); - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, calc); + logger->debug("{} ns. PC: 0x{:x}. C.SLLI: x{:d} << {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, shift, rd, calc); - logger->debug("{} ns. PC: 0x{:x}. C.SRAI: x{:d} >> {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, shift, rd, calc); + return true; + } - return true; -} + bool C_extension::Exec_C_ANDI() { + int rd, rs1; + std::uint32_t imm; + std::uint32_t aux; + std::uint32_t calc; -bool C_extension::Exec_C_SLLI() { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; + rd = get_rs1p(); + rs1 = get_rs1p(); + imm = get_imm_ADDI(); - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_imm_ADDI(); + aux = regs->getValue(rs1); + calc = aux & imm; + regs->setValue(rd, static_cast(calc)); - shift = rs2 & 0x1F; + logger->debug("{} ns. PC: 0x{:x}. C.ANDI: x{:d}(0x{:x}) AND 0x{:x} -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, aux, imm, rd); - calc = static_cast(regs->getValue(rs1)) << shift; - regs->setValue(rd, static_cast(calc)); + return true; + } - logger->debug("{} ns. PC: 0x{:x}. C.SLLI: x{:d} << {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, shift, rd, calc); + bool C_extension::Exec_C_SUB() { + int rd, rs1, rs2; + std::uint32_t calc; - return true; -} + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); -bool C_extension::Exec_C_ANDI() { - int rd, rs1; - std::uint32_t imm; - std::uint32_t aux; - std::uint32_t calc; + calc = regs->getValue(rs1) - regs->getValue(rs2); + regs->setValue(rd, static_cast(calc)); - rd = get_rs1p(); - rs1 = get_rs1p(); - imm = get_imm_ADDI(); + logger->debug("{} ns. PC: 0x{:x}. C.SUB: x{:d} - x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd, calc); - aux = regs->getValue(rs1); - calc = aux & imm; - regs->setValue(rd, static_cast(calc)); + return true; + } - logger->debug("{} ns. PC: 0x{:x}. C.ANDI: x{:d}(0x{:x}) AND 0x{:x} -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, aux, imm, rd); + bool C_extension::Exec_C_XOR() { + int rd, rs1, rs2; + std::uint32_t calc; - return true; -} + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); -bool C_extension::Exec_C_SUB() { - int rd, rs1, rs2; - std::uint32_t calc; + calc = regs->getValue(rs1) ^ regs->getValue(rs2); + regs->setValue(rd, static_cast(calc)); - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2p(); + logger->debug("{} ns. PC: 0x{:x}. C.XOR: x{:d} XOR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd); - calc = regs->getValue(rs1) - regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); + return true; + } - logger->debug("{} ns. PC: 0x{:x}. C.SUB: x{:d} - x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd, calc); + bool C_extension::Exec_C_OR() { + int rd, rs1, rs2; + std::uint32_t calc; - return true; -} + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); -bool C_extension::Exec_C_XOR() { - int rd, rs1, rs2; - std::uint32_t calc; + calc = regs->getValue(rs1) | regs->getValue(rs2); + regs->setValue(rd, static_cast(calc)); - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2p(); + logger->debug("{} ns. PC: 0x{:x}. C.OR: x{:d} OR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd); - calc = regs->getValue(rs1) ^ regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); + return true; + } - logger->debug("{} ns. PC: 0x{:x}. C.XOR: x{:d} XOR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd); + bool C_extension::Exec_C_AND() { + int rd, rs1, rs2; + std::uint32_t calc; - return true; -} + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); -bool C_extension::Exec_C_OR() { - int rd, rs1, rs2; - std::uint32_t calc; + calc = regs->getValue(rs1) & regs->getValue(rs2); + regs->setValue(rd, static_cast(calc)); - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2p(); + logger->debug("{} ns. PC: 0x{:x}. C.AND: x{:d} AND x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd); - calc = regs->getValue(rs1) | regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); + return true; + } - logger->debug("{} ns. PC: 0x{:x}. C.OR: x{:d} OR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd); + bool C_extension::Exec_C_ADDI() const { + int rd, rs1; + std::int32_t imm; + std::int32_t calc; - return true; -} + rd = get_rd(); + rs1 = rd; + imm = get_imm_ADDI(); -bool C_extension::Exec_C_AND() { - int rd, rs1, rs2; - std::uint32_t calc; + calc = static_cast(regs->getValue(rs1)) + imm; + regs->setValue(rd, calc); - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2p(); + logger->debug("{} ns. PC: 0x{:x}. C.ADDI: x{:d} + {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + regs->getPC(), rs1, imm, rd, calc); - calc = regs->getValue(rs1) & regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); + return true; + } - logger->debug("{} ns. PC: 0x{:x}. C.AND: x{:d} AND x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd); + bool C_extension::Exec_C_JALR() { + std::uint32_t mem_addr = 0; + int rd, rs1; + int new_pc, old_pc; - return true; -} + rd = 1; + rs1 = get_rs1(); -bool C_extension::Exec_C_ADDI() const { - int rd, rs1; - std::int32_t imm; - std::int32_t calc; + old_pc = static_cast(regs->getPC()); + regs->setValue(rd, old_pc + 2); - rd = get_rd(); - rs1 = rd; - imm = get_imm_ADDI(); + new_pc = static_cast((regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); + regs->setPC(new_pc); - calc = static_cast(regs->getValue(rs1)) + imm; - regs->setValue(rd, calc); + logger->debug("{} ns. PC: 0x{:x}. C.JALR: x{:d} <- 0x{:x} PC <- 0xx{:x}", sc_core::sc_time_stamp().value(), + regs->getPC(), + rd, old_pc + 4, new_pc); - logger->debug("{} ns. PC: 0x{:x}. C.ADDI: x{:d} + {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), rs1, imm, rd, calc); + return true; + } - return true; -} + bool C_extension::Exec_C_LW() { + std::uint32_t mem_addr; + int rd, rs1; + std::int32_t imm; + std::uint32_t data; -bool C_extension::Exec_C_JALR() { - std::uint32_t mem_addr = 0; - int rd, rs1; - int new_pc, old_pc; + rd = get_rdp(); + rs1 = get_rs1p(); + imm = get_imm_L(); - rd = 1; - rs1 = get_rs1(); - - old_pc = static_cast(regs->getPC()); - regs->setValue(rd, old_pc + 2); - - new_pc = static_cast((regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); - regs->setPC(new_pc); - - logger->debug("{} ns. PC: 0x{:x}. C.JALR: x{:d} <- 0x{:x} PC <- 0xx{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), - rd, old_pc + 4, new_pc); - - return true; -} - -bool C_extension::Exec_C_LW() { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - std::uint32_t data; - - rd = get_rdp(); - rs1 = get_rs1p(); - imm = get_imm_L(); - - mem_addr = imm + regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); - - logger->debug("{} ns. PC: 0x{:x}. C.LW: x{:d}(0x{:x}) + {:d} (@0x{:x}) -> {:d} (0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), imm, mem_addr, rd, data); - - return true; -} - -bool C_extension::Exec_C_SW() { - std::uint32_t mem_addr; - int rs1, rs2; - std::int32_t imm; - std::uint32_t data; - - rs1 = get_rs1p(); - rs2 = get_rs2p(); - imm = get_imm_L(); - - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. C.SW: x{:d}(0x{:x}) -> x{:d} + 0x{:x}(@0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs2, data, rs1, imm, mem_addr); - - return true; -} - -bool C_extension::Exec_C_JAL(int m_rd) { - std::int32_t mem_addr; - int rd; - int new_pc, old_pc; - - rd = m_rd; - mem_addr = get_imm_J(); - old_pc = static_cast(regs->getPC()); - - new_pc = old_pc + mem_addr; - regs->setPC(new_pc); - - old_pc = old_pc + 2; - regs->setValue(rd, old_pc); - - logger->debug("{} ns. PC: 0x{:x}. C.JAL: x{:d} <- 0x{:x}. PC + 0x{:x} -> PC (0x{:x})", sc_core::sc_time_stamp().value(), regs->getPC(), - rd, old_pc, mem_addr, new_pc); - - return true; -} - -bool C_extension::Exec_C_EBREAK() { - - logger->debug("C.EBREAK"); - std::cout << "\n" << "C.EBRAK Instruction called, dumping information" - << "\n"; - regs->dump(); - std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; - perf->dump(); - - sc_core::sc_stop(); - - return true; -} - -bool C_extension::process_instruction(Instruction &inst, bool *breakpoint) { - bool PC_not_affected = true; - - *breakpoint = false; - - setInstr(inst.getInstr()); - - switch (decode()) { - case OP_C_ADDI4SPN: - PC_not_affected = Exec_C_ADDI4SPN(); - break; - case OP_C_LW: - Exec_C_LW(); - break; - case OP_C_SW: - Exec_C_SW(); - break; - case OP_C_ADDI: - Exec_C_ADDI(); - break; - case OP_C_JAL: - Exec_C_JAL(1); - PC_not_affected = false; - break; - case OP_C_J: - Exec_C_JAL(0); - PC_not_affected = false; - break; - case OP_C_LI: - Exec_C_LI(); - break; - case OP_C_SLLI: - Exec_C_SLLI(); - break; - case OP_C_LWSP: - Exec_C_LWSP(); - break; - case OP_C_JR: - Exec_C_JR(); - PC_not_affected = false; - break; - case OP_C_MV: - Exec_C_MV(); - break; - case OP_C_JALR: - Exec_C_JALR(); - PC_not_affected = false; - break; - case OP_C_ADD: - Exec_C_ADD(); - break; - case OP_C_SWSP: - Exec_C_SWSP(); - break; - case OP_C_ADDI16SP: - Exec_C_ADDI16SP(); - break; - case OP_C_BEQZ: - Exec_C_BEQZ(); - PC_not_affected = false; - break; - case OP_C_BNEZ: - Exec_C_BNEZ(); - PC_not_affected = false; - break; - case OP_C_SRLI: - Exec_C_SRLI(); - break; - case OP_C_SRAI: - Exec_C_SRAI(); - break; - case OP_C_ANDI: - Exec_C_ANDI(); - break; - case OP_C_SUB: - Exec_C_SUB(); - break; - case OP_C_XOR: - Exec_C_XOR(); - break; - case OP_C_OR: - Exec_C_OR(); - break; - case OP_C_AND: - Exec_C_AND(); - break; - case OP_C_EBREAK: - Exec_C_EBREAK(); - std::cout << "C_EBREAK" << std::endl; - *breakpoint = true; - break; - [[unlikely]] default: - std::cout << "C instruction not implemented yet" << "\n"; - inst.dump(); - NOP(); - break; - } - - return PC_not_affected; -} + mem_addr = imm + regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 4); + perf->dataMemoryRead(); + regs->setValue(rd, static_cast(data)); + + logger->debug("{} ns. PC: 0x{:x}. C.LW: x{:d}(0x{:x}) + {:d} (@0x{:x}) -> {:d} (0x{:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), + rs1, regs->getValue(rs1), imm, mem_addr, rd, data); + + return true; + } + + bool C_extension::Exec_C_SW() { + std::uint32_t mem_addr; + int rs1, rs2; + std::int32_t imm; + std::uint32_t data; + + rs1 = get_rs1p(); + rs2 = get_rs2p(); + imm = get_imm_L(); + + mem_addr = imm + regs->getValue(rs1); + data = regs->getValue(rs2); + + mem_intf->writeDataMem(mem_addr, data, 4); + perf->dataMemoryWrite(); + + logger->debug("{} ns. PC: 0x{:x}. C.SW: x{:d}(0x{:x}) -> x{:d} + 0x{:x}(@0x{:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), + rs2, data, rs1, imm, mem_addr); + + return true; + } + + bool C_extension::Exec_C_JAL(int m_rd) { + std::int32_t mem_addr; + int rd; + int new_pc, old_pc; + + rd = m_rd; + mem_addr = get_imm_J(); + old_pc = static_cast(regs->getPC()); + + new_pc = old_pc + mem_addr; + regs->setPC(new_pc); + + old_pc = old_pc + 2; + regs->setValue(rd, old_pc); + + logger->debug("{} ns. PC: 0x{:x}. C.JAL: x{:d} <- 0x{:x}. PC + 0x{:x} -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), regs->getPC(), + rd, old_pc, mem_addr, new_pc); + + return true; + } + + bool C_extension::Exec_C_EBREAK() { + + logger->debug("C.EBREAK"); + std::cout << "\n" << "C.EBRAK Instruction called, dumping information" + << "\n"; + regs->dump(); + std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; + perf->dump(); + + sc_core::sc_stop(); + + return true; + } + + bool C_extension::process_instruction(Instruction &inst, bool *breakpoint) { + bool PC_not_affected = true; + + *breakpoint = false; + + setInstr(inst.getInstr()); + + switch (decode()) { + case OP_C_ADDI4SPN: + PC_not_affected = Exec_C_ADDI4SPN(); + break; + case OP_C_LW: + Exec_C_LW(); + break; + case OP_C_SW: + Exec_C_SW(); + break; + case OP_C_ADDI: + Exec_C_ADDI(); + break; + case OP_C_JAL: + Exec_C_JAL(1); + PC_not_affected = false; + break; + case OP_C_J: + Exec_C_JAL(0); + PC_not_affected = false; + break; + case OP_C_LI: + Exec_C_LI(); + break; + case OP_C_SLLI: + Exec_C_SLLI(); + break; + case OP_C_LWSP: + Exec_C_LWSP(); + break; + case OP_C_JR: + Exec_C_JR(); + PC_not_affected = false; + break; + case OP_C_MV: + Exec_C_MV(); + break; + case OP_C_JALR: + Exec_C_JALR(); + PC_not_affected = false; + break; + case OP_C_ADD: + Exec_C_ADD(); + break; + case OP_C_SWSP: + Exec_C_SWSP(); + break; + case OP_C_ADDI16SP: + Exec_C_ADDI16SP(); + break; + case OP_C_BEQZ: + Exec_C_BEQZ(); + PC_not_affected = false; + break; + case OP_C_BNEZ: + Exec_C_BNEZ(); + PC_not_affected = false; + break; + case OP_C_SRLI: + Exec_C_SRLI(); + break; + case OP_C_SRAI: + Exec_C_SRAI(); + break; + case OP_C_ANDI: + Exec_C_ANDI(); + break; + case OP_C_SUB: + Exec_C_SUB(); + break; + case OP_C_XOR: + Exec_C_XOR(); + break; + case OP_C_OR: + Exec_C_OR(); + break; + case OP_C_AND: + Exec_C_AND(); + break; + case OP_C_EBREAK: + Exec_C_EBREAK(); + std::cout << "C_EBREAK" << std::endl; + *breakpoint = true; + break; + [[unlikely]] default: + std::cout << "C instruction not implemented yet" << "\n"; + inst.dump(); + NOP(); + break; + } + + return PC_not_affected; + } + +} \ No newline at end of file diff --git a/src/Debug.cpp b/src/Debug.cpp index 5f874eb..9331355 100644 --- a/src/Debug.cpp +++ b/src/Debug.cpp @@ -18,234 +18,238 @@ #include "Debug.h" -constexpr char nibble_to_hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; +namespace riscv_tlm { -Debug::Debug(CPU *cpu, Memory* mem): sc_module(sc_core::sc_module_name("Debug")) { - dbg_cpu = cpu; - dbg_mem = mem; + constexpr char nibble_to_hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - int sock = socket(AF_INET, SOCK_STREAM, 0); + Debug::Debug(riscv_tlm::CPU *cpu, Memory *mem) : sc_module(sc_core::sc_module_name("Debug")) { + dbg_cpu = cpu; + dbg_mem = mem; - int optval = 1; - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, - sizeof(optval)); + int sock = socket(AF_INET, SOCK_STREAM, 0); - sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = htons(1234); + int optval = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, + sizeof(optval)); - bind(sock, (struct sockaddr *) &addr, sizeof(addr)); - listen(sock, 1); + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(1234); - socklen_t len = sizeof(addr); - conn = accept(sock, (struct sockaddr *) &addr, &len); + bind(sock, (struct sockaddr *) &addr, sizeof(addr)); + listen(sock, 1); - handle_gdb_loop(); -} + socklen_t len = sizeof(addr); + conn = accept(sock, (struct sockaddr *) &addr, &len); -Debug::~Debug() { + handle_gdb_loop(); + } -} + Debug::~Debug() { -void Debug::send_packet(int conn, const std::string &msg) { - std::string frame = "+$" + msg + "#" + compute_checksum_string(msg); + } - memcpy(iobuf, frame.c_str(), frame.size()); + void Debug::send_packet(int conn, const std::string &msg) { + std::string frame = "+$" + msg + "#" + compute_checksum_string(msg); - ::send(conn, iobuf, frame.size(), 0); -} + memcpy(iobuf, frame.c_str(), frame.size()); -std::string Debug::receive_packet() { - int nbytes = ::recv(conn, iobuf, bufsize, 0); + ::send(conn, iobuf, frame.size(), 0); + } - if (nbytes == 0) { - return ""; - } else if (nbytes == 1) { - return std::string("+"); - } else { - char *start = strchr(iobuf, '$'); - char *end = strchr(iobuf, '#'); + std::string Debug::receive_packet() { + int nbytes = ::recv(conn, iobuf, bufsize, 0); - std::string message(start + 1, end - (start + 1)); + if (nbytes == 0) { + return ""; + } else if (nbytes == 1) { + return std::string("+"); + } else { + char *start = strchr(iobuf, '$'); + char *end = strchr(iobuf, '#'); - return message; - } -} + std::string message(start + 1, end - (start + 1)); -void Debug::handle_gdb_loop() { - std::cout << "Handle_GDB_Loop\n"; + return message; + } + } - Registers *register_bank = dbg_cpu->getRegisterBank(); + void Debug::handle_gdb_loop() { + std::cout << "Handle_GDB_Loop\n"; - while (true) { - std::string msg = receive_packet(); + Registers *register_bank = dbg_cpu->getRegisterBank(); - if (msg.size() == 0) { - std::cout << "remote connection seems to be closed, terminating ..." - << std::endl; - break; - } else if (msg == "+") { - // NOTE: just ignore this message, nothing to do in this case - } else if (boost::starts_with(msg, "qSupported")) { - send_packet(conn, "PacketSize=256;swbreak+;hwbreak+;vContSupported+;multiprocess-"); - } else if (msg == "vMustReplyEmpty") { - send_packet(conn, ""); - } else if (msg == "Hg0") { - send_packet(conn, "OK"); - } else if (msg == "Hc0") { - send_packet(conn, ""); - } else if (msg == "qTStatus") { - send_packet(conn, ""); - } else if (msg == "?") { - send_packet(conn, "S05"); - } else if (msg == "qfThreadInfo") { - send_packet(conn, ""); - } else if (boost::starts_with(msg, "qL")) { - send_packet(conn, ""); - } else if (msg == "Hc-1") { - send_packet(conn, "OK"); - } else if (msg == "qC") { - send_packet(conn, "-1"); - } else if (msg == "qAttached") { - send_packet(conn, "0"); // 0 process started, 1 attached to process - } else if (msg == "g") { + while (true) { + std::string msg = receive_packet(); - std::stringstream stream; - stream << std::setfill('0') << std::hex; - for (int i = 1; i < 32; i++) { - stream << std::setw(8) << register_bank->getValue(i); - } - send_packet(conn, stream.str()); - } else if (boost::starts_with(msg, "p")) { - long n = strtol(msg.c_str() + 1, 0, 16); - int reg_value; - if (n < 32) { - reg_value = register_bank->getValue(n); - } else if (n == 32) { - reg_value = register_bank->getPC(); - } else { - // see: https://github.com/riscv/riscv-gnu-toolchain/issues/217 - // risc-v register 834 - reg_value = register_bank->getCSR(n - 65); - } - std::stringstream stream; - stream << std::setfill('0') << std::hex; - stream << std::setw(8) << htonl(reg_value); - send_packet(conn, stream.str()); - } else if (boost::starts_with(msg, "P")) { - char * pEnd; - long reg = strtol(msg.c_str() + 1, &pEnd, 16); - int val = strtol(pEnd + 1, 0, 16); - register_bank->setValue(reg + 1, val); - send_packet(conn, "OK"); - } else if (boost::starts_with(msg, "m")) { - char * pEnd; - long addr = strtol(msg.c_str() + 1, &pEnd, 16);; - int len = strtol(pEnd + 1, &pEnd, 16); + if (msg.size() == 0) { + std::cout << "remote connection seems to be closed, terminating ..." + << std::endl; + break; + } else if (msg == "+") { + // NOTE: just ignore this message, nothing to do in this case + } else if (boost::starts_with(msg, "qSupported")) { + send_packet(conn, "PacketSize=256;swbreak+;hwbreak+;vContSupported+;multiprocess-"); + } else if (msg == "vMustReplyEmpty") { + send_packet(conn, ""); + } else if (msg == "Hg0") { + send_packet(conn, "OK"); + } else if (msg == "Hc0") { + send_packet(conn, ""); + } else if (msg == "qTStatus") { + send_packet(conn, ""); + } else if (msg == "?") { + send_packet(conn, "S05"); + } else if (msg == "qfThreadInfo") { + send_packet(conn, ""); + } else if (boost::starts_with(msg, "qL")) { + send_packet(conn, ""); + } else if (msg == "Hc-1") { + send_packet(conn, "OK"); + } else if (msg == "qC") { + send_packet(conn, "-1"); + } else if (msg == "qAttached") { + send_packet(conn, "0"); // 0 process started, 1 attached to process + } else if (msg == "g") { - dbg_trans.set_data_ptr(pyld_array); - dbg_trans.set_command(tlm::TLM_READ_COMMAND); - dbg_trans.set_address(addr); - dbg_trans.set_data_length(len); - dbg_mem->transport_dbg(dbg_trans); + std::stringstream stream; + stream << std::setfill('0') << std::hex; + for (int i = 1; i < 32; i++) { + stream << std::setw(8) << register_bank->getValue(i); + } + send_packet(conn, stream.str()); + } else if (boost::starts_with(msg, "p")) { + long n = strtol(msg.c_str() + 1, 0, 16); + int reg_value; + if (n < 32) { + reg_value = register_bank->getValue(n); + } else if (n == 32) { + reg_value = register_bank->getPC(); + } else { + // see: https://github.com/riscv/riscv-gnu-toolchain/issues/217 + // risc-v register 834 + reg_value = register_bank->getCSR(n - 65); + } + std::stringstream stream; + stream << std::setfill('0') << std::hex; + stream << std::setw(8) << htonl(reg_value); + send_packet(conn, stream.str()); + } else if (boost::starts_with(msg, "P")) { + char *pEnd; + long reg = strtol(msg.c_str() + 1, &pEnd, 16); + int val = strtol(pEnd + 1, 0, 16); + register_bank->setValue(reg + 1, val); + send_packet(conn, "OK"); + } else if (boost::starts_with(msg, "m")) { + char *pEnd; + long addr = strtol(msg.c_str() + 1, &pEnd, 16);; + int len = strtol(pEnd + 1, &pEnd, 16); - std::stringstream stream; - stream << std::setfill('0') << std::hex; - for (auto &c : pyld_array) { - stream << std::setw(2) << (0xFF & c); - } + dbg_trans.set_data_ptr(pyld_array); + dbg_trans.set_command(tlm::TLM_READ_COMMAND); + dbg_trans.set_address(addr); + dbg_trans.set_data_length(len); + dbg_mem->transport_dbg(dbg_trans); - send_packet(conn, stream.str()); + std::stringstream stream; + stream << std::setfill('0') << std::hex; + for (auto &c: pyld_array) { + stream << std::setw(2) << (0xFF & c); + } - } else if (boost::starts_with(msg, "M")) { - printf("M TBD\n"); - send_packet(conn, "OK"); - } else if (boost::starts_with(msg, "X")) { - send_packet(conn, ""); // binary data unsupported - } else if (msg == "qOffsets") { - send_packet(conn, "Text=0;Data=0;Bss=0"); - } else if (msg == "qSymbol::") { - send_packet(conn, "OK"); - } else if (msg == "vCont?") { - send_packet(conn, "vCont;cs"); - } else if (msg == "c") { - bool breakpoint_hit = false; - bool bkpt = false; - do { - bkpt = dbg_cpu->CPU_step(); - uint32_t currentPC = register_bank->getPC(); + send_packet(conn, stream.str()); - auto search = breakpoints.find(currentPC); - if (search != breakpoints.end()) { - breakpoint_hit = true; - } - } while ((breakpoint_hit == false) && (bkpt == false)); + } else if (boost::starts_with(msg, "M")) { + printf("M TBD\n"); + send_packet(conn, "OK"); + } else if (boost::starts_with(msg, "X")) { + send_packet(conn, ""); // binary data unsupported + } else if (msg == "qOffsets") { + send_packet(conn, "Text=0;Data=0;Bss=0"); + } else if (msg == "qSymbol::") { + send_packet(conn, "OK"); + } else if (msg == "vCont?") { + send_packet(conn, "vCont;cs"); + } else if (msg == "c") { + bool breakpoint_hit = false; + bool bkpt = false; + do { + bkpt = dbg_cpu->CPU_step(); + uint32_t currentPC = register_bank->getPC(); - std::cout << "Breakpoint hit at 0x" << std::hex << register_bank->getPC() << std::endl; - send_packet(conn, "S05"); - } else if (msg == "s") { + auto search = breakpoints.find(currentPC); + if (search != breakpoints.end()) { + breakpoint_hit = true; + } + } while ((breakpoint_hit == false) && (bkpt == false)); - bool breakpoint; - dbg_cpu->CPU_step(); + std::cout << "Breakpoint hit at 0x" << std::hex << register_bank->getPC() << std::endl; + send_packet(conn, "S05"); + } else if (msg == "s") { - uint32_t currentPC = register_bank->getPC(); - auto search = breakpoints.find(currentPC); - if (search != breakpoints.end()) { - breakpoint = true; - } else { - breakpoint = false; - } + bool breakpoint; + dbg_cpu->CPU_step(); - if (breakpoint) { - send_packet(conn, "S03"); - } else { - send_packet(conn, "S05"); - } + uint32_t currentPC = register_bank->getPC(); + auto search = breakpoints.find(currentPC); + if (search != breakpoints.end()) { + breakpoint = true; + } else { + breakpoint = false; + } - } else if (boost::starts_with(msg, "vKill")) { - send_packet(conn, "OK"); - break; - } else if (boost::starts_with(msg, "Z1")) { - char * pEnd; - long addr = strtol(msg.c_str() + 3, &pEnd, 16);; - breakpoints.insert(addr); - std::cout << "Breakpoint set to address 0x"<< std::hex << addr << std::endl; - send_packet(conn, "OK"); - } else if (boost::starts_with(msg, "z1")) { - char * pEnd; - long addr = strtol(msg.c_str() + 3, &pEnd, 16);; - breakpoints.erase(addr); - send_packet(conn, "OK"); - } else if (boost::starts_with(msg, "z0")) { - char * pEnd; - long addr = strtol(msg.c_str() + 3, &pEnd, 16);; - breakpoints.erase(addr); - send_packet(conn, ""); - } else if (boost::starts_with(msg, "Z0")) { - char * pEnd; - long addr = strtol(msg.c_str() + 3, &pEnd, 16);; - breakpoints.insert(addr); - std::cout << "Breakpoint set to address 0x"<< std::hex << addr << std::endl; - send_packet(conn, "OK"); - } else { - std::cout << "unsupported message '" << msg - << "' detected, terminating ..." << std::endl; - break; - } - } -} + if (breakpoint) { + send_packet(conn, "S03"); + } else { + send_packet(conn, "S05"); + } -std::string Debug::compute_checksum_string(const std::string &msg) { - unsigned sum = 0; - for (auto c : msg) { - sum += unsigned(c); - } - sum = sum % 256; + } else if (boost::starts_with(msg, "vKill")) { + send_packet(conn, "OK"); + break; + } else if (boost::starts_with(msg, "Z1")) { + char *pEnd; + long addr = strtol(msg.c_str() + 3, &pEnd, 16);; + breakpoints.insert(addr); + std::cout << "Breakpoint set to address 0x" << std::hex << addr << std::endl; + send_packet(conn, "OK"); + } else if (boost::starts_with(msg, "z1")) { + char *pEnd; + long addr = strtol(msg.c_str() + 3, &pEnd, 16);; + breakpoints.erase(addr); + send_packet(conn, "OK"); + } else if (boost::starts_with(msg, "z0")) { + char *pEnd; + long addr = strtol(msg.c_str() + 3, &pEnd, 16);; + breakpoints.erase(addr); + send_packet(conn, ""); + } else if (boost::starts_with(msg, "Z0")) { + char *pEnd; + long addr = strtol(msg.c_str() + 3, &pEnd, 16);; + breakpoints.insert(addr); + std::cout << "Breakpoint set to address 0x" << std::hex << addr << std::endl; + send_packet(conn, "OK"); + } else { + std::cout << "unsupported message '" << msg + << "' detected, terminating ..." << std::endl; + break; + } + } + } - char low = nibble_to_hex[sum & 0xf]; - char high = nibble_to_hex[(sum & (0xf << 4)) >> 4]; + std::string Debug::compute_checksum_string(const std::string &msg) { + unsigned sum = 0; + for (auto c: msg) { + sum += unsigned(c); + } + sum = sum % 256; - return {high, low}; -} + char low = nibble_to_hex[sum & 0xf]; + char high = nibble_to_hex[(sum & (0xf << 4)) >> 4]; + + return {high, low}; + } + +} \ No newline at end of file diff --git a/src/Instruction.cpp b/src/Instruction.cpp index b442137..3886289 100644 --- a/src/Instruction.cpp +++ b/src/Instruction.cpp @@ -8,26 +8,28 @@ #include "Instruction.h" -Instruction::Instruction(std::uint32_t instr) { - m_instr = instr; +namespace riscv_tlm { + + Instruction::Instruction(std::uint32_t instr) { + m_instr = instr; + } + + extension_t Instruction::check_extension() const { + if (((m_instr & 0x0000007F) == 0b0110011) + && (((m_instr & 0x7F000000) >> 25) == 0b0000001)) { + return M_EXTENSION; + } else if ((m_instr & 0x0000007F) == 0b0101111) { + return A_EXTENSION; + } else if ((m_instr & 0x00000003) == 0b00) { + return C_EXTENSION; + } else if ((m_instr & 0x00000003) == 0b01) { + return C_EXTENSION; + } else if ((m_instr & 0x00000003) == 0b10) { + return C_EXTENSION; + } else { + return BASE_EXTENSION; + } + } + } -extension_t Instruction::check_extension() const { - if (((m_instr & 0x0000007F) == 0b0110011) - && ( ((m_instr & 0x7F000000) >> 25) == 0b0000001)) { - return M_EXTENSION; - } else if ((m_instr & 0x0000007F) == 0b0101111) { - return A_EXTENSION; - } else if ((m_instr & 0x00000003) == 0b00) { - return C_EXTENSION; - } else if ((m_instr & 0x00000003) == 0b01) { - return C_EXTENSION; - } else if ((m_instr & 0x00000003) == 0b10) { - return C_EXTENSION; - } else { - return BASE_EXTENSION; - } -} - - - diff --git a/src/M_extension.cpp b/src/M_extension.cpp index 647ba80..a29d544 100644 --- a/src/M_extension.cpp +++ b/src/M_extension.cpp @@ -8,280 +8,292 @@ #include "M_extension.h" -op_M_Codes M_extension::decode() const { +namespace riscv_tlm { - switch (opcode()) { - case M_MUL: - return OP_M_MUL; - break; - case M_MULH: - return OP_M_MULH; - break; - case M_MULHSU: - return OP_M_MULHSU; - break; - case M_MULHU: - return OP_M_MULHU; - break; - case M_DIV: - return OP_M_DIV; - break; - case M_DIVU: - return OP_M_DIVU; - break; - case M_REM: - return OP_M_REM; - break; - case M_REMU: - return OP_M_REMU; - break; - [[unlikely]] default: - return OP_M_ERROR; - break; - } + op_M_Codes M_extension::decode() const { - return OP_M_ERROR; -} + switch (opcode()) { + case M_MUL: + return OP_M_MUL; + break; + case M_MULH: + return OP_M_MULH; + break; + case M_MULHSU: + return OP_M_MULHSU; + break; + case M_MULHU: + return OP_M_MULHU; + break; + case M_DIV: + return OP_M_DIV; + break; + case M_DIVU: + return OP_M_DIVU; + break; + case M_REM: + return OP_M_REM; + break; + case M_REMU: + return OP_M_REMU; + break; + [[unlikely]] default: + return OP_M_ERROR; + break; + } -bool M_extension::Exec_M_MUL() const { - int rd, rs1, rs2; - std::int32_t multiplier, multiplicand; - std::int64_t result; + return OP_M_ERROR; + } - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + bool M_extension::Exec_M_MUL() const { + int rd, rs1, rs2; + std::int32_t multiplier, multiplicand; + std::int64_t result; - multiplier = static_cast(regs->getValue(rs1)); - multiplicand = static_cast(regs->getValue(rs2)); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - result = static_cast(multiplier * multiplicand); - result = result & 0x00000000FFFFFFFF; - regs->setValue(rd, static_cast(result)); + multiplier = static_cast(regs->getValue(rs1)); + multiplicand = static_cast(regs->getValue(rs2)); - logger->debug("{} ns. PC: 0x{:x}. M.MUL: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd, result); + result = static_cast(multiplier * multiplicand); + result = result & 0x00000000FFFFFFFF; + regs->setValue(rd, static_cast(result)); - return true; -} + logger->debug("{} ns. PC: 0x{:x}. M.MUL: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd, result); -bool M_extension::Exec_M_MULH() const { - int rd, rs1, rs2; - std::int32_t multiplier, multiplicand; - std::int64_t result; - std::int32_t ret_value; + return true; + } - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + bool M_extension::Exec_M_MULH() const { + int rd, rs1, rs2; + std::int32_t multiplier, multiplicand; + std::int64_t result; + std::int32_t ret_value; - multiplier = static_cast(regs->getValue(rs1)); - multiplicand = static_cast(regs->getValue(rs2)); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - result = static_cast(multiplier) * static_cast(multiplicand); + multiplier = static_cast(regs->getValue(rs1)); + multiplicand = static_cast(regs->getValue(rs2)); - ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); - regs->setValue(rd, ret_value); + result = static_cast(multiplier) * static_cast(multiplicand); - logger->debug("{} ns. PC: 0x{:x}. M.MULH: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd, result); + ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); + regs->setValue(rd, ret_value); - return true; -} + logger->debug("{} ns. PC: 0x{:x}. M.MULH: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd, result); -bool M_extension::Exec_M_MULHSU() const { - int rd, rs1, rs2; - std::int32_t multiplier; - std::uint32_t multiplicand; - std::int64_t result; + return true; + } - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + bool M_extension::Exec_M_MULHSU() const { + int rd, rs1, rs2; + std::int32_t multiplier; + std::uint32_t multiplicand; + std::int64_t result; - multiplier = static_cast(regs->getValue(rs1)); - multiplicand = regs->getValue(rs2); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - result = static_cast(multiplier * static_cast(multiplicand)); - result = (result >> 32) & 0x00000000FFFFFFFF; - regs->setValue(rd, static_cast(result)); + multiplier = static_cast(regs->getValue(rs1)); + multiplicand = regs->getValue(rs2); - logger->debug("{} ns. PC: 0x{:x}. M.MULHSU: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd, result); + result = static_cast(multiplier * static_cast(multiplicand)); + result = (result >> 32) & 0x00000000FFFFFFFF; + regs->setValue(rd, static_cast(result)); - return true; -} + logger->debug("{} ns. PC: 0x{:x}. M.MULHSU: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd, result); -bool M_extension::Exec_M_MULHU() const { - int rd, rs1, rs2; - std::uint32_t multiplier, multiplicand; - std::uint64_t result; - std::int32_t ret_value; + return true; + } - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + bool M_extension::Exec_M_MULHU() const { + int rd, rs1, rs2; + std::uint32_t multiplier, multiplicand; + std::uint64_t result; + std::int32_t ret_value; - multiplier = static_cast(regs->getValue(rs1)); - multiplicand = static_cast(regs->getValue(rs2)); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - result = static_cast(multiplier) * static_cast(multiplicand); - ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); - regs->setValue(rd, ret_value); + multiplier = static_cast(regs->getValue(rs1)); + multiplicand = static_cast(regs->getValue(rs2)); - logger->debug("{} ns. PC: 0x{:x}. M.MULHU: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd, result); + result = static_cast(multiplier) * static_cast(multiplicand); + ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); + regs->setValue(rd, ret_value); - return true; -} + logger->debug("{} ns. PC: 0x{:x}. M.MULHU: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd, result); -bool M_extension::Exec_M_DIV() const { - int rd, rs1, rs2; - std::int32_t divisor, dividend; - std::int64_t result; + return true; + } - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + bool M_extension::Exec_M_DIV() const { + int rd, rs1, rs2; + std::int32_t divisor, dividend; + std::int64_t result; - dividend = static_cast(regs->getValue(rs1)); - divisor = static_cast(regs->getValue(rs2)); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - if (divisor == 0) { - result = -1; - } else if ((divisor == -1) && (dividend == static_cast(0x80000000)) ) { - result = 0x0000000080000000; - } else { - result = dividend / divisor; - result = result & 0x00000000FFFFFFFF; - } + dividend = static_cast(regs->getValue(rs1)); + divisor = static_cast(regs->getValue(rs2)); - regs->setValue(rd, static_cast(result)); + if (divisor == 0) { + result = -1; + } else if ((divisor == -1) && (dividend == static_cast(0x80000000))) { + result = 0x0000000080000000; + } else { + result = dividend / divisor; + result = result & 0x00000000FFFFFFFF; + } - logger->debug("{} ns. PC: 0x{:x}. M.DIV: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd, result); + regs->setValue(rd, static_cast(result)); - return true; -} + logger->debug("{} ns. PC: 0x{:x}. M.DIV: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd, result); -bool M_extension::Exec_M_DIVU() const { - int rd, rs1, rs2; - std::uint32_t divisor, dividend; - std::uint64_t result; + return true; + } - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + bool M_extension::Exec_M_DIVU() const { + int rd, rs1, rs2; + std::uint32_t divisor, dividend; + std::uint64_t result; - dividend = regs->getValue(rs1); - divisor = regs->getValue(rs2); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - if (divisor == 0) { - result = -1; - } else { - result = dividend / divisor; - result = result & 0x00000000FFFFFFFF; - } + dividend = regs->getValue(rs1); + divisor = regs->getValue(rs2); - regs->setValue(rd, static_cast(result)); + if (divisor == 0) { + result = -1; + } else { + result = dividend / divisor; + result = result & 0x00000000FFFFFFFF; + } - logger->debug("{} ns. PC: 0x{:x}. M.DIVU: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd, result); + regs->setValue(rd, static_cast(result)); - return true; -} + logger->debug("{} ns. PC: 0x{:x}. M.DIVU: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd, result); -bool M_extension::Exec_M_REM() const { - int rd, rs1, rs2; - std::int32_t divisor, dividend; - std::int32_t result; + return true; + } - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + bool M_extension::Exec_M_REM() const { + int rd, rs1, rs2; + std::int32_t divisor, dividend; + std::int32_t result; - dividend = static_cast(regs->getValue(rs1)); - divisor = static_cast(regs->getValue(rs2)); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - if (divisor == 0) { - result = dividend; - } else if ((divisor == -1) && (dividend == static_cast(0x80000000)) ) { - result = 0; - } else { - result = dividend % divisor; - } + dividend = static_cast(regs->getValue(rs1)); + divisor = static_cast(regs->getValue(rs2)); - regs->setValue(rd, result); + if (divisor == 0) { + result = dividend; + } else if ((divisor == -1) && (dividend == static_cast(0x80000000))) { + result = 0; + } else { + result = dividend % divisor; + } - logger->debug("{} ns. PC: 0x{:x}. M.REM: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd, result); + regs->setValue(rd, result); - return true; -} + logger->debug("{} ns. PC: 0x{:x}. M.REM: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd, result); -bool M_extension::Exec_M_REMU() const { - int rd, rs1, rs2; - std::uint32_t divisor, dividend; - std::uint32_t result; + return true; + } - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); + bool M_extension::Exec_M_REMU() const { + int rd, rs1, rs2; + std::uint32_t divisor, dividend; + std::uint32_t result; - dividend = static_cast(regs->getValue(rs1)); - divisor = static_cast(regs->getValue(rs2)); + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); - if (divisor == 0) { - result = dividend; - } else { - result = dividend % divisor; - } + dividend = static_cast(regs->getValue(rs1)); + divisor = static_cast(regs->getValue(rs2)); - regs->setValue(rd, static_cast(result)); + if (divisor == 0) { + result = dividend; + } else { + result = dividend % divisor; + } - logger->debug("{} ns. PC: 0x{:x}. M.REMU: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, rs2, rd, result); + regs->setValue(rd, static_cast(result)); - return true; -} + logger->debug("{} ns. PC: 0x{:x}. M.REMU: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), + regs->getPC(), + rs1, rs2, rd, result); -bool M_extension::process_instruction(Instruction &inst) { - bool PC_not_affected = true; + return true; + } - setInstr(inst.getInstr()); + bool M_extension::process_instruction(Instruction &inst) { + bool PC_not_affected = true; - switch (decode()) { - case OP_M_MUL: - Exec_M_MUL(); - break; - case OP_M_MULH: - Exec_M_MULH(); - break; - case OP_M_MULHSU: - Exec_M_MULHSU(); - break; - case OP_M_MULHU: - Exec_M_MULHU(); - break; - case OP_M_DIV: - Exec_M_DIV(); - break; - case OP_M_DIVU: - Exec_M_DIVU(); - break; - case OP_M_REM: - Exec_M_REM(); - break; - case OP_M_REMU: - Exec_M_REMU(); - break; - [[unlikely]] default: - std::cout << "M instruction not implemented yet" << "\n"; - inst.dump(); - //NOP(inst); - sc_core::sc_stop(); - break; - } + setInstr(inst.getInstr()); - return PC_not_affected; -} + switch (decode()) { + case OP_M_MUL: + Exec_M_MUL(); + break; + case OP_M_MULH: + Exec_M_MULH(); + break; + case OP_M_MULHSU: + Exec_M_MULHSU(); + break; + case OP_M_MULHU: + Exec_M_MULHU(); + break; + case OP_M_DIV: + Exec_M_DIV(); + break; + case OP_M_DIVU: + Exec_M_DIVU(); + break; + case OP_M_REM: + Exec_M_REM(); + break; + case OP_M_REMU: + Exec_M_REMU(); + break; + [[unlikely]] default: + std::cout << "M instruction not implemented yet" << "\n"; + inst.dump(); + //NOP(inst); + sc_core::sc_stop(); + break; + } + + return PC_not_affected; + } + +} \ No newline at end of file diff --git a/src/Memory.cpp b/src/Memory.cpp index fc88474..394e80a 100644 --- a/src/Memory.cpp +++ b/src/Memory.cpp @@ -8,194 +8,199 @@ #include "Memory.h" -SC_HAS_PROCESS(Memory); -Memory::Memory(sc_core::sc_module_name const &name, std::string const &filename) : - sc_module(name), socket("socket"), LATENCY(sc_core::SC_ZERO_TIME) { - // Register callbacks for incoming interface method calls - socket.register_b_transport(this, &Memory::b_transport); - socket.register_get_direct_mem_ptr(this, &Memory::get_direct_mem_ptr); - socket.register_transport_dbg(this, &Memory::transport_dbg); +namespace riscv_tlm { - dmi_allowed = false; - program_counter = 0; - readHexFile(filename); + SC_HAS_PROCESS(Memory); - logger = spdlog::get("my_logger"); - logger->debug("Using file {}", filename); -} + Memory::Memory(sc_core::sc_module_name const &name, std::string const &filename) : + sc_module(name), socket("socket"), LATENCY(sc_core::SC_ZERO_TIME) { + // Register callbacks for incoming interface method calls + socket.register_b_transport(this, &Memory::b_transport); + socket.register_get_direct_mem_ptr(this, &Memory::get_direct_mem_ptr); + socket.register_transport_dbg(this, &Memory::transport_dbg); -Memory::Memory(sc_core::sc_module_name const& name) : - sc_module(name), socket("socket"), LATENCY(sc_core::SC_ZERO_TIME) { - socket.register_b_transport(this, &Memory::b_transport); - socket.register_get_direct_mem_ptr(this, &Memory::get_direct_mem_ptr); - socket.register_transport_dbg(this, &Memory::transport_dbg); + dmi_allowed = false; + program_counter = 0; + readHexFile(filename); - program_counter = 0; - - logger = spdlog::get("my_logger"); - logger->debug("Memory instantiated wihtout file"); -} - -Memory::~Memory() = default; - -std::uint32_t Memory::getPCfromHEX() { - return program_counter; - -} -void Memory::b_transport(tlm::tlm_generic_payload &trans, - sc_core::sc_time &delay) { - tlm::tlm_command cmd = trans.get_command(); - sc_dt::uint64 adr = trans.get_address(); - unsigned char *ptr = trans.get_data_ptr(); - unsigned int len = trans.get_data_length(); - unsigned char *byt = trans.get_byte_enable_ptr(); - unsigned int wid = trans.get_streaming_width(); - - // ********************************************* - // Generate the appropriate error response - // ********************************************* - if (adr >= sc_dt::uint64(Memory::SIZE)) { - trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE); - return; - } - if (byt != nullptr) { - trans.set_response_status(tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE); - return; - } - if (len > 4 || wid < len) { - trans.set_response_status(tlm::TLM_BURST_ERROR_RESPONSE); - return; - } - - // Obliged to implement read and write commands - if (cmd == tlm::TLM_READ_COMMAND) { - std::copy_n(mem.cbegin() + adr, len, ptr); - } else if (cmd == tlm::TLM_WRITE_COMMAND) { - std::copy_n(ptr, len, mem.begin() + adr); + logger = spdlog::get("my_logger"); + logger->debug("Using file {}", filename); } - // Illustrates that b_transport may block - //sc_core::wait(delay); + Memory::Memory(sc_core::sc_module_name const &name) : + sc_module(name), socket("socket"), LATENCY(sc_core::SC_ZERO_TIME) { + socket.register_b_transport(this, &Memory::b_transport); + socket.register_get_direct_mem_ptr(this, &Memory::get_direct_mem_ptr); + socket.register_transport_dbg(this, &Memory::transport_dbg); - // Reset timing annotation after waiting - delay = sc_core::SC_ZERO_TIME; + program_counter = 0; - // ********************************************* - // Set DMI hint to indicated that DMI is supported - // ********************************************* - trans.set_dmi_allowed(dmi_allowed); - - // Obliged to set response status to indicate successful completion - trans.set_response_status(tlm::TLM_OK_RESPONSE); -} - -bool Memory::get_direct_mem_ptr(tlm::tlm_generic_payload &trans, - tlm::tlm_dmi &dmi_data) { - - (void) trans; - - if (!dmi_allowed) { - return false; - } - - // Permit read and write access - dmi_data.allow_read_write(); - - // Set other details of DMI region - dmi_data.set_dmi_ptr(reinterpret_cast(&mem[0])); - dmi_data.set_start_address(0); - dmi_data.set_end_address(Memory::SIZE * 4 - 1); - dmi_data.set_read_latency(LATENCY); - dmi_data.set_write_latency(LATENCY); - - return true; -} - -unsigned int Memory::transport_dbg(tlm::tlm_generic_payload &trans) { - tlm::tlm_command cmd = trans.get_command(); - sc_dt::uint64 adr = trans.get_address(); - unsigned char *ptr = trans.get_data_ptr(); - unsigned int len = trans.get_data_length(); - - if (adr >= sc_dt::uint64(Memory::SIZE)) { - trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE); - return 0; - } - - // Calculate the number of bytes to be actually copied - unsigned int num_bytes = (len < (Memory::SIZE - adr) * 4) ? len : (Memory::SIZE - adr) * 4; - - if (cmd == tlm::TLM_READ_COMMAND) { - std::copy_n(mem.cbegin() + adr, len, ptr); - } else if (cmd == tlm::TLM_WRITE_COMMAND) { - std::copy_n(ptr, len, mem.begin() + adr); + logger = spdlog::get("my_logger"); + logger->debug("Memory instantiated wihtout file"); } - return num_bytes; -} + Memory::~Memory() = default; -void Memory::readHexFile(std::string const& filename) { - std::ifstream hexfile; - std::string line; - std::uint32_t memory_offset = 0; + std::uint32_t Memory::getPCfromHEX() { + return program_counter; - hexfile.open(filename); + } - if (hexfile.is_open()) { - std::uint32_t extended_address = 0; + void Memory::b_transport(tlm::tlm_generic_payload &trans, + sc_core::sc_time &delay) { + tlm::tlm_command cmd = trans.get_command(); + sc_dt::uint64 adr = trans.get_address(); + unsigned char *ptr = trans.get_data_ptr(); + unsigned int len = trans.get_data_length(); + unsigned char *byt = trans.get_byte_enable_ptr(); + unsigned int wid = trans.get_streaming_width(); - while (getline(hexfile, line)) { - if (line[0] == ':') { - if (line.substr(7, 2) == "00") { - /* Data */ - int byte_count; - std::uint32_t address; - byte_count = std::stoi(line.substr(1, 2), nullptr, 16); - address = std::stoi(line.substr(3, 4), nullptr, 16); - address = address + extended_address + memory_offset; - - for (int i = 0; i < byte_count; i++) { - mem[address + i] = stol(line.substr(9 + (i * 2), 2), - nullptr, 16); - } - } else if (line.substr(7, 2) == "02") { - /* Extended segment address */ - extended_address = stol(line.substr(9, 4), nullptr, 16) - * 16; - std::cout << "02 extended address 0x" << std::hex - << extended_address << std::dec << std::endl; - } else if (line.substr(7, 2) == "03") { - /* Start segment address */ - std::uint32_t code_segment; - code_segment = stol(line.substr(9, 4), nullptr, 16) * 16; /* ? */ - program_counter = stol(line.substr(13, 4), nullptr, 16); - program_counter = program_counter + code_segment; - std::cout << "03 PC set to 0x" << std::hex - << program_counter << std::dec << std::endl; - } else if (line.substr(7, 2) == "04") { - /* Start segment address */ - memory_offset = stol(line.substr(9, 4), nullptr, 16) << 16; - extended_address = 0; - std::cout << "04 address set to 0x" << std::hex - << extended_address << std::dec << std::endl; - std::cout << "04 offset set to 0x" << std::hex - << memory_offset << std::dec << std::endl; - } else if (line.substr(7, 2) == "05") { - program_counter = stol(line.substr(9, 8), nullptr, 16); - std::cout << "05 PC set to 0x" << std::hex - << program_counter << std::dec << std::endl; - } - } - } - hexfile.close(); - - if (memory_offset != 0) { - dmi_allowed = false; - } else { - dmi_allowed = true; + // ********************************************* + // Generate the appropriate error response + // ********************************************* + if (adr >= sc_dt::uint64(Memory::SIZE)) { + trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE); + return; + } + if (byt != nullptr) { + trans.set_response_status(tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE); + return; + } + if (len > 4 || wid < len) { + trans.set_response_status(tlm::TLM_BURST_ERROR_RESPONSE); + return; } - } else { - SC_REPORT_ERROR("Memory", "Open file error"); - } -} + // Obliged to implement read and write commands + if (cmd == tlm::TLM_READ_COMMAND) { + std::copy_n(mem.cbegin() + adr, len, ptr); + } else if (cmd == tlm::TLM_WRITE_COMMAND) { + std::copy_n(ptr, len, mem.begin() + adr); + } + + // Illustrates that b_transport may block + //sc_core::wait(delay); + + // Reset timing annotation after waiting + delay = sc_core::SC_ZERO_TIME; + + // ********************************************* + // Set DMI hint to indicated that DMI is supported + // ********************************************* + trans.set_dmi_allowed(dmi_allowed); + + // Obliged to set response status to indicate successful completion + trans.set_response_status(tlm::TLM_OK_RESPONSE); + } + + bool Memory::get_direct_mem_ptr(tlm::tlm_generic_payload &trans, + tlm::tlm_dmi &dmi_data) { + + (void) trans; + + if (!dmi_allowed) { + return false; + } + + // Permit read and write access + dmi_data.allow_read_write(); + + // Set other details of DMI region + dmi_data.set_dmi_ptr(reinterpret_cast(&mem[0])); + dmi_data.set_start_address(0); + dmi_data.set_end_address(Memory::SIZE * 4 - 1); + dmi_data.set_read_latency(LATENCY); + dmi_data.set_write_latency(LATENCY); + + return true; + } + + unsigned int Memory::transport_dbg(tlm::tlm_generic_payload &trans) { + tlm::tlm_command cmd = trans.get_command(); + sc_dt::uint64 adr = trans.get_address(); + unsigned char *ptr = trans.get_data_ptr(); + unsigned int len = trans.get_data_length(); + + if (adr >= sc_dt::uint64(Memory::SIZE)) { + trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE); + return 0; + } + + // Calculate the number of bytes to be actually copied + unsigned int num_bytes = (len < (Memory::SIZE - adr) * 4) ? len : (Memory::SIZE - adr) * 4; + + if (cmd == tlm::TLM_READ_COMMAND) { + std::copy_n(mem.cbegin() + adr, len, ptr); + } else if (cmd == tlm::TLM_WRITE_COMMAND) { + std::copy_n(ptr, len, mem.begin() + adr); + } + + return num_bytes; + } + + void Memory::readHexFile(std::string const &filename) { + std::ifstream hexfile; + std::string line; + std::uint32_t memory_offset = 0; + + hexfile.open(filename); + + if (hexfile.is_open()) { + std::uint32_t extended_address = 0; + + while (getline(hexfile, line)) { + if (line[0] == ':') { + if (line.substr(7, 2) == "00") { + /* Data */ + int byte_count; + std::uint32_t address; + byte_count = std::stoi(line.substr(1, 2), nullptr, 16); + address = std::stoi(line.substr(3, 4), nullptr, 16); + address = address + extended_address + memory_offset; + + for (int i = 0; i < byte_count; i++) { + mem[address + i] = stol(line.substr(9 + (i * 2), 2), + nullptr, 16); + } + } else if (line.substr(7, 2) == "02") { + /* Extended segment address */ + extended_address = stol(line.substr(9, 4), nullptr, 16) + * 16; + std::cout << "02 extended address 0x" << std::hex + << extended_address << std::dec << std::endl; + } else if (line.substr(7, 2) == "03") { + /* Start segment address */ + std::uint32_t code_segment; + code_segment = stol(line.substr(9, 4), nullptr, 16) * 16; /* ? */ + program_counter = stol(line.substr(13, 4), nullptr, 16); + program_counter = program_counter + code_segment; + std::cout << "03 PC set to 0x" << std::hex + << program_counter << std::dec << std::endl; + } else if (line.substr(7, 2) == "04") { + /* Start segment address */ + memory_offset = stol(line.substr(9, 4), nullptr, 16) << 16; + extended_address = 0; + std::cout << "04 address set to 0x" << std::hex + << extended_address << std::dec << std::endl; + std::cout << "04 offset set to 0x" << std::hex + << memory_offset << std::dec << std::endl; + } else if (line.substr(7, 2) == "05") { + program_counter = stol(line.substr(9, 8), nullptr, 16); + std::cout << "05 PC set to 0x" << std::hex + << program_counter << std::dec << std::endl; + } + } + } + hexfile.close(); + + if (memory_offset != 0) { + dmi_allowed = false; + } else { + dmi_allowed = true; + } + + } else { + SC_REPORT_ERROR("Memory", "Open file error"); + } + } +} \ No newline at end of file diff --git a/src/MemoryInterface.cpp b/src/MemoryInterface.cpp index 2dd3e2c..46a6c29 100644 --- a/src/MemoryInterface.cpp +++ b/src/MemoryInterface.cpp @@ -8,9 +8,10 @@ #include "MemoryInterface.h" +namespace riscv_tlm { -MemoryInterface::MemoryInterface() : - data_bus("data_bus") {} + MemoryInterface::MemoryInterface() : + data_bus("data_bus") {} /** * Access data memory to get data @@ -18,27 +19,27 @@ MemoryInterface::MemoryInterface() : * @param size size of the data to read in bytes * @return data value read */ -std::uint32_t MemoryInterface::readDataMem(std::uint32_t addr, int size) { - std::uint32_t data; - tlm::tlm_generic_payload trans; - sc_core::sc_time delay = sc_core::SC_ZERO_TIME; + std::uint32_t MemoryInterface::readDataMem(std::uint32_t addr, int size) { + std::uint32_t data; + tlm::tlm_generic_payload trans; + sc_core::sc_time delay = sc_core::SC_ZERO_TIME; - trans.set_command(tlm::TLM_READ_COMMAND); - trans.set_data_ptr(reinterpret_cast(&data)); - trans.set_data_length(size); - trans.set_streaming_width(4); // = data_length to indicate no streaming - trans.set_byte_enable_ptr(nullptr); // 0 indicates unused - trans.set_dmi_allowed(false); // Mandatory initial value - trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); - trans.set_address(addr); + trans.set_command(tlm::TLM_READ_COMMAND); + trans.set_data_ptr(reinterpret_cast(&data)); + trans.set_data_length(size); + trans.set_streaming_width(4); // = data_length to indicate no streaming + trans.set_byte_enable_ptr(nullptr); // 0 indicates unused + trans.set_dmi_allowed(false); // Mandatory initial value + trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); + trans.set_address(addr); - data_bus->b_transport(trans, delay); + data_bus->b_transport(trans, delay); - if (trans.is_response_error()) { - SC_REPORT_ERROR("Memory", "Read memory"); - } - return data; -} + if (trans.is_response_error()) { + SC_REPORT_ERROR("Memory", "Read memory"); + } + return data; + } /** * Acces data memory to write data @@ -47,18 +48,19 @@ std::uint32_t MemoryInterface::readDataMem(std::uint32_t addr, int size) { * @param data data to write * @param size size of the data to write in bytes */ -void MemoryInterface::writeDataMem(std::uint32_t addr, std::uint32_t data, int size) { - tlm::tlm_generic_payload trans; - sc_core::sc_time delay = sc_core::SC_ZERO_TIME; + void MemoryInterface::writeDataMem(std::uint32_t addr, std::uint32_t data, int size) { + tlm::tlm_generic_payload trans; + sc_core::sc_time delay = sc_core::SC_ZERO_TIME; - trans.set_command(tlm::TLM_WRITE_COMMAND); - trans.set_data_ptr(reinterpret_cast(&data)); - trans.set_data_length(size); - trans.set_streaming_width(4); // = data_length to indicate no streaming - trans.set_byte_enable_ptr(nullptr); // 0 indicates unused - trans.set_dmi_allowed(false); // Mandatory initial value - trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); - trans.set_address(addr); + trans.set_command(tlm::TLM_WRITE_COMMAND); + trans.set_data_ptr(reinterpret_cast(&data)); + trans.set_data_length(size); + trans.set_streaming_width(4); // = data_length to indicate no streaming + trans.set_byte_enable_ptr(nullptr); // 0 indicates unused + trans.set_dmi_allowed(false); // Mandatory initial value + trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); + trans.set_address(addr); - data_bus->b_transport(trans, delay); -} + data_bus->b_transport(trans, delay); + } +} \ No newline at end of file diff --git a/src/Registers.cpp b/src/Registers.cpp index 7589f4e..c1d168e 100644 --- a/src/Registers.cpp +++ b/src/Registers.cpp @@ -8,166 +8,169 @@ #include "Registers.h" -Registers::Registers() { - perf = Performance::getInstance(); +namespace riscv_tlm { - initCSR(); - register_bank[sp] = Memory::SIZE - 4; // default stack at the end of the memory - register_PC = 0x80000000; // default _start address -} + Registers::Registers() { + perf = Performance::getInstance(); -void Registers::dump() { - std::cout << "************************************" << std::endl; - std::cout << "Registers dump" << std::dec << std::endl; - std::cout << std::setfill('0') << std::uppercase; - std::cout << "x0 (zero): 0x" << std::right << std::setw(8) - << std::hex << register_bank[0]; - std::cout << " x1 (ra): 0x" << std::right << std::setw(8) - << std::hex << register_bank[1]; - std::cout << " x2 (sp): 0x" << std::right << std::setw(8) - << std::hex << register_bank[2]; - std::cout << " x3 (gp): 0x" << std::right << std::setw(8) - << std::hex << register_bank[3] << std::endl; + initCSR(); + register_bank[sp] = Memory::SIZE - 4; // default stack at the end of the memory + register_PC = 0x80000000; // default _start address + } - std::cout << "x4 (tp): 0x" << std::right << std::setw(8) - << std::hex << register_bank[4]; - std::cout << " x5 (t0): 0x" << std::right << std::setw(8) - << std::hex << register_bank[5]; - std::cout << " x6 (t1): 0x" << std::right << std::setw(8) - << std::hex << register_bank[6]; - std::cout << " x7 (t2): 0x" << std::right << std::setw(8) - << std::hex << register_bank[7] << std::endl; + void Registers::dump() { + std::cout << "************************************" << std::endl; + std::cout << "Registers dump" << std::dec << std::endl; + std::cout << std::setfill('0') << std::uppercase; + std::cout << "x0 (zero): 0x" << std::right << std::setw(8) + << std::hex << register_bank[0]; + std::cout << " x1 (ra): 0x" << std::right << std::setw(8) + << std::hex << register_bank[1]; + std::cout << " x2 (sp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[2]; + std::cout << " x3 (gp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[3] << std::endl; - std::cout << "x8 (s0/fp): 0x" << std::right << std::setw(8) - << std::hex << register_bank[8]; - std::cout << " x9 (s1): 0x" << std::right << std::setw(8) - << std::hex << register_bank[9]; - std::cout << " x10 (a0): 0x" << std::right << std::setw(8) - << std::hex << register_bank[10]; - std::cout << " x11 (a1): 0x" << std::right << std::setw(8) - << std::hex << register_bank[11] << std::endl; + std::cout << "x4 (tp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[4]; + std::cout << " x5 (t0): 0x" << std::right << std::setw(8) + << std::hex << register_bank[5]; + std::cout << " x6 (t1): 0x" << std::right << std::setw(8) + << std::hex << register_bank[6]; + std::cout << " x7 (t2): 0x" << std::right << std::setw(8) + << std::hex << register_bank[7] << std::endl; - std::cout << "x12 (a2): 0x" << std::right << std::setw(8) - << std::hex << register_bank[12]; - std::cout << " x13 (a3): 0x" << std::right << std::setw(8) - << std::hex << register_bank[13]; - std::cout << " x14 (a4): 0x" << std::right << std::setw(8) - << std::hex << register_bank[14]; - std::cout << " x15 (a5): 0x" << std::right << std::setw(8) - << std::hex << register_bank[15] << std::endl; + std::cout << "x8 (s0/fp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[8]; + std::cout << " x9 (s1): 0x" << std::right << std::setw(8) + << std::hex << register_bank[9]; + std::cout << " x10 (a0): 0x" << std::right << std::setw(8) + << std::hex << register_bank[10]; + std::cout << " x11 (a1): 0x" << std::right << std::setw(8) + << std::hex << register_bank[11] << std::endl; - std::cout << "x16 (a6): 0x" << std::right << std::setw(8) - << std::hex << register_bank[16]; - std::cout << " x17 (a7): 0x" << std::right << std::setw(8) - << std::hex << register_bank[17]; - std::cout << " x18 (s2): 0x" << std::right << std::setw(8) - << std::hex << register_bank[18]; - std::cout << " x19 (s3): 0x" << std::right << std::setw(8) - << std::hex << register_bank[19] << std::endl; + std::cout << "x12 (a2): 0x" << std::right << std::setw(8) + << std::hex << register_bank[12]; + std::cout << " x13 (a3): 0x" << std::right << std::setw(8) + << std::hex << register_bank[13]; + std::cout << " x14 (a4): 0x" << std::right << std::setw(8) + << std::hex << register_bank[14]; + std::cout << " x15 (a5): 0x" << std::right << std::setw(8) + << std::hex << register_bank[15] << std::endl; - std::cout << "x20 (s4): 0x" << std::right << std::setw(8) - << std::hex << register_bank[20]; - std::cout << " x21 (s5): 0x" << std::right << std::setw(8) - << std::hex << register_bank[21]; - std::cout << " x22 (s6): 0x" << std::right << std::setw(8) - << std::hex << register_bank[22]; - std::cout << " x23 (s7): 0x" << std::right << std::setw(8) - << std::hex << register_bank[23] << std::endl; + std::cout << "x16 (a6): 0x" << std::right << std::setw(8) + << std::hex << register_bank[16]; + std::cout << " x17 (a7): 0x" << std::right << std::setw(8) + << std::hex << register_bank[17]; + std::cout << " x18 (s2): 0x" << std::right << std::setw(8) + << std::hex << register_bank[18]; + std::cout << " x19 (s3): 0x" << std::right << std::setw(8) + << std::hex << register_bank[19] << std::endl; - std::cout << "x24 (s8): 0x" << std::right << std::setw(8) - << std::hex << register_bank[24]; - std::cout << " x25 (s9): 0x" << std::right << std::setw(8) - << std::hex << register_bank[25]; - std::cout << " x26 (s10): 0x" << std::right << std::setw(8) - << std::hex << register_bank[26]; - std::cout << " x27 (s11): 0x" << std::right << std::setw(8) - << std::hex << register_bank[27] << std::endl; + std::cout << "x20 (s4): 0x" << std::right << std::setw(8) + << std::hex << register_bank[20]; + std::cout << " x21 (s5): 0x" << std::right << std::setw(8) + << std::hex << register_bank[21]; + std::cout << " x22 (s6): 0x" << std::right << std::setw(8) + << std::hex << register_bank[22]; + std::cout << " x23 (s7): 0x" << std::right << std::setw(8) + << std::hex << register_bank[23] << std::endl; - std::cout << "x28 (t3): 0x" << std::right << std::setw(8) - << std::hex << register_bank[28]; - std::cout << " x29 (t4): 0x" << std::right << std::setw(8) - << std::hex << register_bank[29]; - std::cout << " x30 (t5): 0x" << std::right << std::setw(8) - << std::hex << register_bank[30]; - std::cout << " x31 (t6): 0x" << std::right << std::setw(8) - << std::hex << register_bank[31] << std::endl; + std::cout << "x24 (s8): 0x" << std::right << std::setw(8) + << std::hex << register_bank[24]; + std::cout << " x25 (s9): 0x" << std::right << std::setw(8) + << std::hex << register_bank[25]; + std::cout << " x26 (s10): 0x" << std::right << std::setw(8) + << std::hex << register_bank[26]; + std::cout << " x27 (s11): 0x" << std::right << std::setw(8) + << std::hex << register_bank[27] << std::endl; - std::cout << "PC: 0x" << std::setw(8) << std::hex << register_PC << std::dec << std::endl; - std::cout << "************************************" << std::endl; -} + std::cout << "x28 (t3): 0x" << std::right << std::setw(8) + << std::hex << register_bank[28]; + std::cout << " x29 (t4): 0x" << std::right << std::setw(8) + << std::hex << register_bank[29]; + std::cout << " x30 (t5): 0x" << std::right << std::setw(8) + << std::hex << register_bank[30]; + std::cout << " x31 (t6): 0x" << std::right << std::setw(8) + << std::hex << register_bank[31] << std::endl; -void Registers::setValue(int reg_num, std::int32_t value) { - if ((reg_num != 0) && (reg_num < 32)) { - register_bank[reg_num] = value; - perf->registerWrite(); - } -} + std::cout << "PC: 0x" << std::setw(8) << std::hex << register_PC << std::dec << std::endl; + std::cout << "************************************" << std::endl; + } -std::uint32_t Registers::getValue(int reg_num) const { - if ((reg_num >= 0) && (reg_num < 32)) { - perf->registerRead(); - return register_bank[reg_num]; - } else { - return static_cast(0xFFFFFFFF); - } -} + void Registers::setValue(int reg_num, std::int32_t value) { + if ((reg_num != 0) && (reg_num < 32)) { + register_bank[reg_num] = value; + perf->registerWrite(); + } + } -std::uint32_t Registers::getPC() const { - return register_PC; -} + std::uint32_t Registers::getValue(int reg_num) const { + if ((reg_num >= 0) && (reg_num < 32)) { + perf->registerRead(); + return register_bank[reg_num]; + } else { + return static_cast(0xFFFFFFFF); + } + } -void Registers::setPC(std::uint32_t new_pc) { - register_PC = new_pc; -} + std::uint32_t Registers::getPC() const { + return register_PC; + } -std::uint32_t Registers::getCSR(const int csr) { - std::uint32_t ret_value; + void Registers::setPC(std::uint32_t new_pc) { + register_PC = new_pc; + } - switch (csr) { - case CSR_CYCLE: - case CSR_MCYCLE: - ret_value = static_cast(sc_core::sc_time( - sc_core::sc_time_stamp() - - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) - & 0x00000000FFFFFFFF; - break; - case CSR_CYCLEH: - case CSR_MCYCLEH: - ret_value = static_cast((std::uint64_t) (sc_core::sc_time( - sc_core::sc_time_stamp() - - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) - >> 32 & 0x00000000FFFFFFFF); - break; - case CSR_TIME: - ret_value = static_cast(sc_core::sc_time( - sc_core::sc_time_stamp() - - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) - & 0x00000000FFFFFFFF; - break; - case CSR_TIMEH: - ret_value = static_cast((std::uint64_t) (sc_core::sc_time( - sc_core::sc_time_stamp() - - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) - >> 32 & 0x00000000FFFFFFFF); - break; - [[likely]] default: - ret_value = CSR[csr]; - break; - } - return ret_value; -} + std::uint32_t Registers::getCSR(const int csr) { + std::uint32_t ret_value; -void Registers::setCSR(int csr, std::uint32_t value) { - /* @FIXME: rv32mi-p-ma_fetch tests doesn't allow MISA to be writable, - * but Volume II: Privileged Architecture v1.10 says MISA is writable (?) - */ - if (csr != CSR_MISA) { - CSR[csr] = value; - } -} + switch (csr) { + case CSR_CYCLE: + case CSR_MCYCLE: + ret_value = static_cast(sc_core::sc_time( + sc_core::sc_time_stamp() + - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) + & 0x00000000FFFFFFFF; + break; + case CSR_CYCLEH: + case CSR_MCYCLEH: + ret_value = static_cast((std::uint64_t) (sc_core::sc_time( + sc_core::sc_time_stamp() + - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) + >> 32 & 0x00000000FFFFFFFF); + break; + case CSR_TIME: + ret_value = static_cast(sc_core::sc_time( + sc_core::sc_time_stamp() + - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) + & 0x00000000FFFFFFFF; + break; + case CSR_TIMEH: + ret_value = static_cast((std::uint64_t) (sc_core::sc_time( + sc_core::sc_time_stamp() + - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) + >> 32 & 0x00000000FFFFFFFF); + break; + [[likely]] default: + ret_value = CSR[csr]; + break; + } + return ret_value; + } -void Registers::initCSR() { - CSR[CSR_MISA] = MISA_MXL | MISA_M_EXTENSION | MISA_C_EXTENSION - | MISA_A_EXTENSION | MISA_I_BASE; - CSR[CSR_MSTATUS] = MISA_MXL; -} + void Registers::setCSR(int csr, std::uint32_t value) { + /* @FIXME: rv32mi-p-ma_fetch tests doesn't allow MISA to be writable, + * but Volume II: Privileged Architecture v1.10 says MISA is writable (?) + */ + if (csr != CSR_MISA) { + CSR[csr] = value; + } + } + + void Registers::initCSR() { + CSR[CSR_MISA] = MISA_MXL | MISA_M_EXTENSION | MISA_C_EXTENSION + | MISA_A_EXTENSION | MISA_I_BASE; + CSR[CSR_MSTATUS] = MISA_MXL; + } +} \ No newline at end of file diff --git a/src/Simulator.cpp b/src/Simulator.cpp index dbbde9f..50d81a6 100644 --- a/src/Simulator.cpp +++ b/src/Simulator.cpp @@ -39,23 +39,23 @@ uint32_t dump_addr_end = 0; */ class Simulator : sc_core::sc_module { public: - CPU *cpu; - Memory *MainMemory; - BusCtrl *Bus; - Trace *trace; - Timer *timer; + riscv_tlm::CPU *cpu; + riscv_tlm::Memory *MainMemory; + riscv_tlm::BusCtrl *Bus; + riscv_tlm::peripherals::Trace *trace; + riscv_tlm::peripherals::Timer *timer; explicit Simulator(sc_core::sc_module_name const &name): sc_module(name) { std::uint32_t start_PC; - MainMemory = new Memory("Main_Memory", filename); + MainMemory = new riscv_tlm::Memory("Main_Memory", filename); start_PC = MainMemory->getPCfromHEX(); - cpu = new CPU("cpu", start_PC, debug_session); + cpu = new riscv_tlm::CPU("cpu", start_PC, debug_session); - Bus = new BusCtrl("BusCtrl"); - trace = new Trace("Trace"); - timer = new Timer("Timer"); + Bus = new riscv_tlm::BusCtrl("BusCtrl"); + trace = new riscv_tlm::peripherals::Trace("Trace"); + timer = new riscv_tlm::peripherals::Timer("Timer"); cpu->instr_bus.bind(Bus->cpu_instr_socket); cpu->mem_intf->data_bus.bind(Bus->cpu_data_socket); @@ -67,7 +67,7 @@ public: timer->irq_line.bind(cpu->irq_line_socket); if (debug_session) { - Debug debug(cpu, MainMemory); + riscv_tlm::Debug debug(cpu, MainMemory); } } diff --git a/src/Timer.cpp b/src/Timer.cpp index b0c93b1..f82e5a2 100644 --- a/src/Timer.cpp +++ b/src/Timer.cpp @@ -9,93 +9,97 @@ #include #include "Timer.h" -SC_HAS_PROCESS(Timer); -Timer::Timer(sc_core::sc_module_name const &name) : - sc_module(name), socket("timer_socket"), m_mtime(0), m_mtimecmp(0) { +namespace riscv_tlm::peripherals { + SC_HAS_PROCESS(Timer); - socket.register_b_transport(this, &Timer::b_transport); + Timer::Timer(sc_core::sc_module_name const &name) : + sc_module(name), socket("timer_socket"), m_mtime(0), m_mtimecmp(0) { - SC_THREAD(run); -} + socket.register_b_transport(this, &Timer::b_transport); -[[noreturn]] void Timer::run() { + SC_THREAD(run); + } - auto *irq_trans = new tlm::tlm_generic_payload; - sc_core::sc_time delay = sc_core::SC_ZERO_TIME; - std::uint32_t cause = 1 << 31 | 0x07; // Machine timer interrupt - irq_trans->set_command(tlm::TLM_WRITE_COMMAND); - irq_trans->set_data_ptr(reinterpret_cast(&cause)); - irq_trans->set_data_length(4); - irq_trans->set_streaming_width(4); - irq_trans->set_byte_enable_ptr(nullptr); - irq_trans->set_dmi_allowed(false); - irq_trans->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); - irq_trans->set_address(0); + [[noreturn]] void Timer::run() { - while (true) { - wait(timer_event); - irq_line->b_transport(*irq_trans, delay); - } -} + auto *irq_trans = new tlm::tlm_generic_payload; + sc_core::sc_time delay = sc_core::SC_ZERO_TIME; + std::uint32_t cause = 1 << 31 | 0x07; // Machine timer interrupt + irq_trans->set_command(tlm::TLM_WRITE_COMMAND); + irq_trans->set_data_ptr(reinterpret_cast(&cause)); + irq_trans->set_data_length(4); + irq_trans->set_streaming_width(4); + irq_trans->set_byte_enable_ptr(nullptr); + irq_trans->set_dmi_allowed(false); + irq_trans->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); + irq_trans->set_address(0); -void Timer::b_transport(tlm::tlm_generic_payload &trans, - sc_core::sc_time &delay) { + while (true) { + wait(timer_event); + irq_line->b_transport(*irq_trans, delay); + } + } - tlm::tlm_command cmd = trans.get_command(); - sc_dt::uint64 addr = trans.get_address(); - unsigned char *ptr = trans.get_data_ptr(); - unsigned int len = trans.get_data_length(); - delay = sc_core::SC_ZERO_TIME; + void Timer::b_transport(tlm::tlm_generic_payload &trans, + sc_core::sc_time &delay) { - std::uint32_t aux_value = 0; + tlm::tlm_command cmd = trans.get_command(); + sc_dt::uint64 addr = trans.get_address(); + unsigned char *ptr = trans.get_data_ptr(); + unsigned int len = trans.get_data_length(); + delay = sc_core::SC_ZERO_TIME; + + std::uint32_t aux_value = 0; - if (cmd == tlm::TLM_WRITE_COMMAND) { - memcpy(&aux_value, ptr, len); - switch (addr) { - case TIMER_MEMORY_ADDRESS_LO: - m_mtime.range(31, 0) = aux_value; - break; - case TIMER_MEMORY_ADDRESS_HI: - m_mtime.range(63, 32) = aux_value; - break; - case TIMERCMP_MEMORY_ADDRESS_LO: - m_mtimecmp.range(31, 0) = aux_value; - break; - case TIMERCMP_MEMORY_ADDRESS_HI: - m_mtimecmp.range(63, 32) = aux_value; + if (cmd == tlm::TLM_WRITE_COMMAND) { + memcpy(&aux_value, ptr, len); + switch (addr) { + case TIMER_MEMORY_ADDRESS_LO: + m_mtime.range(31, 0) = aux_value; + break; + case TIMER_MEMORY_ADDRESS_HI: + m_mtime.range(63, 32) = aux_value; + break; + case TIMERCMP_MEMORY_ADDRESS_LO: + m_mtimecmp.range(31, 0) = aux_value; + break; + case TIMERCMP_MEMORY_ADDRESS_HI: + m_mtimecmp.range(63, 32) = aux_value; - std::uint64_t notify_time; - // notify needs relative time, mtimecmp works in absolute time - notify_time = m_mtimecmp - m_mtime; + std::uint64_t notify_time; + // notify needs relative time, mtimecmp works in absolute time + notify_time = m_mtimecmp - m_mtime; - timer_event.notify(sc_core::sc_time(notify_time, sc_core::SC_NS)); - break; - default: - trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE); - return; - } - } else { // TLM_READ_COMMAND - switch (addr) { - case TIMER_MEMORY_ADDRESS_LO: - m_mtime = sc_core::sc_time_stamp().value(); - aux_value = m_mtime.range(31, 0); - break; - case TIMER_MEMORY_ADDRESS_HI: - aux_value = m_mtime.range(63, 32); - break; - case TIMERCMP_MEMORY_ADDRESS_LO: - aux_value = m_mtimecmp.range(31, 0); - break; - case TIMERCMP_MEMORY_ADDRESS_HI: - aux_value = m_mtimecmp.range(63, 32); - break; - default: - trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE); - return; - } - memcpy(ptr, &aux_value, len); - } + timer_event.notify(sc_core::sc_time(notify_time, sc_core::SC_NS)); + break; + default: + trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE); + return; + } + } else { // TLM_READ_COMMAND + switch (addr) { + case TIMER_MEMORY_ADDRESS_LO: + m_mtime = sc_core::sc_time_stamp().value(); + aux_value = m_mtime.range(31, 0); + break; + case TIMER_MEMORY_ADDRESS_HI: + aux_value = m_mtime.range(63, 32); + break; + case TIMERCMP_MEMORY_ADDRESS_LO: + aux_value = m_mtimecmp.range(31, 0); + break; + case TIMERCMP_MEMORY_ADDRESS_HI: + aux_value = m_mtimecmp.range(63, 32); + break; + default: + trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE); + return; + } + memcpy(ptr, &aux_value, len); + } - trans.set_response_status(tlm::TLM_OK_RESPONSE); -} + trans.set_response_status(tlm::TLM_OK_RESPONSE); + } + +} \ No newline at end of file diff --git a/src/Trace.cpp b/src/Trace.cpp index 1140ed5..55440bd 100644 --- a/src/Trace.cpp +++ b/src/Trace.cpp @@ -20,92 +20,97 @@ #include "Trace.h" -void Trace::xtermLaunch(char *slaveName) const { - char *arg; - char *fin = &(slaveName[strlen(slaveName) - 2]); +namespace riscv_tlm::peripherals { - if ( nullptr == strchr(fin, '/')) { - arg = new char[2 + 1 + 1 + 20 + 1]; - sprintf(arg, "-S%c%c%d", fin[0], fin[1], ptMaster); - } else { - char *slaveBase = ::basename(slaveName); - arg = new char[2 + strlen(slaveBase) + 1 + 20 + 1]; - sprintf(arg, "-S%s/%d", slaveBase, ptMaster); - } + void Trace::xtermLaunch(char *slaveName) const { + char *arg; + char *fin = &(slaveName[strlen(slaveName) - 2]); - char *argv[3]; - argv[0] = (char*) ("xterm"); - argv[1] = arg; - argv[2] = nullptr; + if (nullptr == strchr(fin, '/')) { + arg = new char[2 + 1 + 1 + 20 + 1]; + sprintf(arg, "-S%c%c%d", fin[0], fin[1], ptMaster); + } else { + char *slaveBase = ::basename(slaveName); + arg = new char[2 + strlen(slaveBase) + 1 + 20 + 1]; + sprintf(arg, "-S%s/%d", slaveBase, ptMaster); + } - execvp("xterm", argv); -} + char *argv[3]; + argv[0] = (char *) ("xterm"); + argv[1] = arg; + argv[2] = nullptr; -void Trace::xtermKill() { + execvp("xterm", argv); + } - if (-1 != ptSlave) { // Close down the slave - close(ptSlave); // Close the FD - ptSlave = -1; - } + void Trace::xtermKill() { - if (-1 != ptMaster) { // Close down the master - close(ptMaster); - ptMaster = -1; - } + if (-1 != ptSlave) { // Close down the slave + close(ptSlave); // Close the FD + ptSlave = -1; + } - if (xtermPid > 0) { // Kill the terminal - kill(xtermPid, SIGKILL); - waitpid(xtermPid, nullptr, 0); - } -} + if (-1 != ptMaster) { // Close down the master + close(ptMaster); + ptMaster = -1; + } -void Trace::xtermSetup() { - ptMaster = open("/dev/ptmx", O_RDWR); + if (xtermPid > 0) { // Kill the terminal + kill(xtermPid, SIGKILL); + waitpid(xtermPid, nullptr, 0); + } + } - if (ptMaster != -1) { - grantpt(ptMaster); + void Trace::xtermSetup() { + ptMaster = open("/dev/ptmx", O_RDWR); - unlockpt(ptMaster); + if (ptMaster != -1) { + grantpt(ptMaster); - char *ptSlaveName = ptsname(ptMaster); - ptSlave = open(ptSlaveName, O_RDWR); // In and out are the same + unlockpt(ptMaster); - struct termios termInfo{}; - tcgetattr(ptSlave, &termInfo); + char *ptSlaveName = ptsname(ptMaster); + ptSlave = open(ptSlaveName, O_RDWR); // In and out are the same - termInfo.c_lflag &= ~ECHO; - termInfo.c_lflag &= ~ICANON; - tcsetattr(ptSlave, TCSADRAIN, &termInfo); + struct termios termInfo{}; + tcgetattr(ptSlave, &termInfo); - xtermPid = fork(); + termInfo.c_lflag &= ~ECHO; + termInfo.c_lflag &= ~ICANON; + tcsetattr(ptSlave, TCSADRAIN, &termInfo); - if (xtermPid == 0) { - xtermLaunch(ptSlaveName); - } - } -} + xtermPid = fork(); -SC_HAS_PROCESS(Trace); -Trace::Trace(sc_core::sc_module_name const &name) : - sc_module(name), socket("socket") { + if (xtermPid == 0) { + xtermLaunch(ptSlaveName); + } + } + } - socket.register_b_transport(this, &Trace::b_transport); + SC_HAS_PROCESS(Trace); - xtermSetup(); -} + Trace::Trace(sc_core::sc_module_name const &name) : + sc_module(name), socket("socket") { -Trace::~Trace() { - xtermKill(); -} + socket.register_b_transport(this, &Trace::b_transport); -void Trace::b_transport(tlm::tlm_generic_payload &trans, - sc_core::sc_time &delay) { + xtermSetup(); + } - unsigned char *ptr = trans.get_data_ptr(); - delay = sc_core::SC_ZERO_TIME; + Trace::~Trace() { + xtermKill(); + } - ssize_t a = write(ptSlave, ptr, 1); - (void) a; + void Trace::b_transport(tlm::tlm_generic_payload &trans, + sc_core::sc_time &delay) { - trans.set_response_status(tlm::TLM_OK_RESPONSE); -} + unsigned char *ptr = trans.get_data_ptr(); + delay = sc_core::SC_ZERO_TIME; + + ssize_t a = write(ptSlave, ptr, 1); + (void) a; + + trans.set_response_status(tlm::TLM_OK_RESPONSE); + } + +} \ No newline at end of file diff --git a/src/extension_base.cpp b/src/extension_base.cpp index 21b1db4..2905ddb 100644 --- a/src/extension_base.cpp +++ b/src/extension_base.cpp @@ -8,53 +8,56 @@ #include "extension_base.h" -extension_base::extension_base(const sc_dt::sc_uint<32> & instr, - Registers *register_bank, MemoryInterface *mem_interface) : - m_instr(instr), regs(register_bank), mem_intf(mem_interface) { +namespace riscv_tlm { - perf = Performance::getInstance(); - logger = spdlog::get("my_logger"); -} + extension_base::extension_base(const sc_dt::sc_uint<32> &instr, + Registers *register_bank, MemoryInterface *mem_interface) : + m_instr(instr), regs(register_bank), mem_intf(mem_interface) { -extension_base::~extension_base() =default; + perf = Performance::getInstance(); + logger = spdlog::get("my_logger"); + } -void extension_base::setInstr(std::uint32_t p_instr) { - m_instr = sc_dt::sc_uint<32>(p_instr); -} + extension_base::~extension_base() = default; -void extension_base::dump() const { - std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; -} + void extension_base::setInstr(std::uint32_t p_instr) { + m_instr = sc_dt::sc_uint<32>(p_instr); + } -void extension_base::RaiseException(std::uint32_t cause, std::uint32_t inst) { - std::uint32_t new_pc, current_pc, m_cause; + void extension_base::dump() const { + std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; + } - current_pc = regs->getPC(); - m_cause = regs->getCSR(CSR_MSTATUS); - m_cause |= cause; + void extension_base::RaiseException(std::uint32_t cause, std::uint32_t inst) { + std::uint32_t new_pc, current_pc, m_cause; - new_pc = regs->getCSR(CSR_MTVEC); + current_pc = regs->getPC(); + m_cause = regs->getCSR(CSR_MSTATUS); + m_cause |= cause; - regs->setCSR(CSR_MEPC, current_pc); + new_pc = regs->getCSR(CSR_MTVEC); - if (cause == EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION) { - regs->setCSR(CSR_MTVAL, inst); - } else { - regs->setCSR(CSR_MTVAL, current_pc); - } + regs->setCSR(CSR_MEPC, current_pc); - regs->setCSR(CSR_MCAUSE, cause); - regs->setCSR(CSR_MSTATUS, m_cause); + if (cause == EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION) { + regs->setCSR(CSR_MTVAL, inst); + } else { + regs->setCSR(CSR_MTVAL, current_pc); + } - regs->setPC(new_pc); + regs->setCSR(CSR_MCAUSE, cause); + regs->setCSR(CSR_MSTATUS, m_cause); - logger->debug("{} ns. PC: 0x{:x}. Exception! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC(), - new_pc); -} + regs->setPC(new_pc); -bool extension_base::NOP() { + logger->debug("{} ns. PC: 0x{:x}. Exception! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC(), + new_pc); + } - logger->debug("{} ns. PC: 0x{:x}. NOP! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC()); - sc_core::sc_stop(); - return true; -} + bool extension_base::NOP() { + + logger->debug("{} ns. PC: 0x{:x}. NOP! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC()); + sc_core::sc_stop(); + return true; + } +} \ No newline at end of file