From 5ee634e4b4116cdbabb999228ffac7fe0a6e904c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Tue, 2 Jun 2020 13:08:38 +0200 Subject: [PATCH] Major refactoring! * A_Instruction, C_Instruction and M_Instruction renamed to *_extension * These files decode and executes extensions * These classes use a new base clase extension_base * Execute & Instruction classes heavyly modified: * Execute now is BASE_ISA and decodes and executes base ISA, Zicsr & Zifencei * Instruction keeps the instruction being executed, nothing else * Add memory interface to ISS to clear the code and the structure * Removed "using namespace " directives, all classes are called using their namespace * Added proper header to each file * Added license to all files --- README.md | 19 +- inc/A_Instruction.h | 136 --- inc/A_extension.h | 145 +++ inc/BASE_ISA.h | 423 ++++++++ inc/BusCtrl.h | 87 +- inc/CPU.h | 157 ++- inc/C_Instruction.h | 413 -------- inc/C_extension.h | 422 ++++++++ inc/Execute.h | 172 --- inc/Instruction.h | 483 +-------- inc/Log.h | 87 +- inc/M_Instruction.h | 130 --- inc/M_extension.h | 129 +++ inc/Memory.h | 110 +- inc/MemoryInterface.h | 34 + inc/Performance.h | 137 ++- inc/Registers.h | 285 +++-- inc/Timer.h | 77 +- inc/Trace.h | 70 +- inc/extension_base.h | 58 ++ src/A_Instruction.cpp | 51 - src/A_extension.cpp | 416 ++++++++ src/BASE_ISA.cpp | 1489 ++++++++++++++++++++++++++ src/BusCtrl.cpp | 76 +- src/CPU.cpp | 438 +------- src/C_Instruction.cpp | 146 --- src/C_extension.cpp | 756 ++++++++++++++ src/Execute.cpp | 2193 --------------------------------------- src/Instruction.cpp | 207 +--- src/Log.cpp | 55 +- src/M_Instruction.cpp | 42 - src/M_extension.cpp | 287 +++++ src/Memory.cpp | 315 +++--- src/MemoryInterface.cpp | 66 ++ src/Performance.cpp | 55 +- src/Registers.cpp | 233 +++-- src/Simulator.cpp | 170 ++- src/Timer.cpp | 143 +-- src/Trace.cpp | 171 +-- src/extension_base.cpp | 70 ++ 40 files changed, 5560 insertions(+), 5393 deletions(-) delete mode 100644 inc/A_Instruction.h create mode 100644 inc/A_extension.h create mode 100644 inc/BASE_ISA.h delete mode 100644 inc/C_Instruction.h create mode 100644 inc/C_extension.h delete mode 100644 inc/Execute.h delete mode 100644 inc/M_Instruction.h create mode 100644 inc/M_extension.h create mode 100644 inc/MemoryInterface.h create mode 100644 inc/extension_base.h delete mode 100644 src/A_Instruction.cpp create mode 100644 src/A_extension.cpp create mode 100644 src/BASE_ISA.cpp delete mode 100644 src/C_Instruction.cpp create mode 100644 src/C_extension.cpp delete mode 100644 src/Execute.cpp delete mode 100644 src/M_Instruction.cpp create mode 100644 src/M_extension.cpp create mode 100644 src/MemoryInterface.cpp create mode 100644 src/extension_base.cpp diff --git a/README.md b/README.md index 5961724..38b041c 100644 --- a/README.md +++ b/README.md @@ -45,14 +45,11 @@ Brief description of the modules: * CPU: Top entity that includes all other modules. * Memory: Memory highly based on TLM-2 example with read file capability * Registers: Implements the register file, PC register & CSR registers -* Execute: Executes ISA instructions - * Executes C instruction extensions - * Executes M instruction extensions - * Executes A instruction extensions -* Instruction: Decodes instruction and acces to any instruction field - * C_Instruction: Decodes Compressed instructions (C extension) - * M_Instruction: Decodes Multiplication and Division instructions (M extension) - * A_Instruction: Decodes Atomic instructions (A extension) +* Instruction: Decodes instruction type and keeps instruction field +* BASE_ISA: Executes Base ISA, Zifencei and Zicsr. + * C_extension: Decodes & Executes Compressed instructions (C extension) + * M_extension: Decodes & Executes Multiplication and Division instructions (M extension) + * A_extension: Decodes & Executes Atomic instructions (A extension) * Simulator: Top-level entity that builds & starts the simulation * BusCtrl: Simple bus manager * Trace: Simple trace peripheral @@ -100,7 +97,7 @@ Task to do: - [ ] generic IRQ comtroller - [x] Test, test, test & test. I'm sure there are a ~~lot of~~ some bugs in the code - [x] riscv-test almost complete (see [Test](https://github.com/mariusmm/RISC-V-TLM/wiki/Tests)) - - [ ] riscv-compliance WiP + - [x] riscv-compliance * Improve structure and modules hierarchy * Add 64 & 128 bits architecture (RV64I, RV128I) @@ -129,7 +126,7 @@ $ ./RISCV_TLM asm/BasicLoop.hex -f filename .hex filename to use ## Cross-compiler -It is possible to use gcc for risc-v compiler. Follow the instructions (from https://github.com/riscv/riscv-gnu-toolchain): +It is possible to use gcc as risc-v compiler. Follow the instructions (from https://github.com/riscv/riscv-gnu-toolchain): ~~~ $ git clone --recursive https://github.com/riscv/riscv-gnu-toolchain $ cd riscv-gnu-toolchain @@ -240,7 +237,7 @@ If you find this code useful, please consider citing: ``` @inproceedings{montonriscvtlm2020, title = {A {RISC}-{V} {SystemC}-{TLM} simulator}, - booktitle = {Workshop on {Computer} {Architecture} {Research} with {RISC}-{V}}, + booktitle = {Workshop on {Computer} {Architecture} {Research} with {RISC}-{V} ({CARRV 2020}), author = {Montón, Màrius}, year = {2020} } diff --git a/inc/A_Instruction.h b/inc/A_Instruction.h deleted file mode 100644 index f9e41fc..0000000 --- a/inc/A_Instruction.h +++ /dev/null @@ -1,136 +0,0 @@ -/*! - \file A_Instruction.h - \brief Decode A extensions part of the RISC-V - \author Màrius Montón - \date December 2018 -*/ - -#ifndef A_INSTRUCTION__H -#define A_INSTRUCTION__H - -#include "systemc" - -using namespace sc_core; -using namespace sc_dt; -using namespace std; - -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, - - 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_Instruction{ -public: - - /** - * @brief Constructor - * @param instr Instruction to decode - */ - A_Instruction(sc_uint<32> instr); - - /** - * @brief Sets instruction - * @param p_instr instruction to decode - */ - void setInstr(uint32_t p_instr) { - a_instr = sc_uint<32> (p_instr); - } - - /** - * @brief Access to opcode field - * @return return opcode field - */ - inline int32_t opcode() { - return a_instr.range(31,27); - } - - /** - * @brief Access to rd field - * @return rd field - */ - inline int32_t get_rd() { - return a_instr.range(11, 7); - } - - inline void set_rd(int32_t value) { - a_instr.range(11,7) = value; - } - - - /** - * @brief Access to rs1 field - * @return rs1 field - */ - inline int32_t get_rs1() { - return a_instr.range(19, 15); - } - - inline void set_rs1(int32_t value) { - a_instr.range(19,15) = value; - } - - - /** - * @brief Access to rs2 field - * @return rs2 field - */ - inline int32_t get_rs2() { - return a_instr.range(24, 20); - } - - inline void set_rs2(int32_t value) { - a_instr.range(24,20) = value; - } - - - inline int32_t get_funct3() { - return a_instr.range(14, 12); - } - - inline void set_funct3(int32_t value) { - a_instr.range(14,12) = value; - } - - /** - * @brief Decodes opcode of instruction - * @return opcode of instruction - */ - op_A_Codes decode(); - - inline void dump() { - cout << hex << "0x" << a_instr << dec << endl; - } -private: - sc_uint<32> a_instr; -}; - -#endif diff --git a/inc/A_extension.h b/inc/A_extension.h new file mode 100644 index 0000000..397c18c --- /dev/null +++ b/inc/A_extension.h @@ -0,0 +1,145 @@ +/*! + \file A_extension.h + \brief Implement A extensions part of the RISC-V + \author Màrius Montón + \date December 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef A_EXTENSION__H +#define A_EXTENSION__H + +#include "systemc" + +#include + +#include "Log.h" +#include "Registers.h" +#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, + + 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: + + /** + * @brief Constructor, same as base class + */ + using extension_base::extension_base; + + /** + * @brief Access to opcode field + * @return return opcode field + */ + inline int32_t opcode() { + return m_instr.range(31, 27); + } + + /** + * @brief Access to rd field + * @return rd field + */ + inline int32_t get_rd() { + return m_instr.range(11, 7); + } + + inline void set_rd(int32_t value) { + m_instr.range(11, 7) = value; + } + + /** + * @brief Access to rs1 field + * @return rs1 field + */ + inline int32_t get_rs1() { + return m_instr.range(19, 15); + } + + inline void set_rs1(int32_t value) { + m_instr.range(19, 15) = value; + } + + /** + * @brief Access to rs2 field + * @return rs2 field + */ + inline int32_t get_rs2() { + return m_instr.range(24, 20); + } + + inline void set_rs2(int32_t value) { + m_instr.range(24, 20) = value; + } + + inline int32_t get_funct3() { + return m_instr.range(14, 12); + } + + inline void set_funct3(int32_t value) { + m_instr.range(14, 12) = value; + } + + /** + * @brief Decodes opcode of instruction + * @return opcode of instruction + */ + op_A_Codes decode(); + + inline void dump() { + std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; + } + + bool Exec_A_LR(); + bool Exec_A_SC(); + bool Exec_A_AMOSWAP(); + bool Exec_A_AMOADD(); + bool Exec_A_AMOXOR(); + bool Exec_A_AMOAND(); + bool Exec_A_AMOOR(); + bool Exec_A_AMOMIN(); + bool Exec_A_AMOMAX(); + bool Exec_A_AMOMINU(); + bool Exec_A_AMOMAXU(); + + bool process_instruction(Instruction &inst); + + void TLB_reserve(uint32_t address); + bool TLB_reserved(uint32_t address); + +private: + std::set TLB_A_Entries; +}; + +#endif diff --git a/inc/BASE_ISA.h b/inc/BASE_ISA.h new file mode 100644 index 0000000..4546cf5 --- /dev/null +++ b/inc/BASE_ISA.h @@ -0,0 +1,423 @@ +/*! + \file BASE_ISA.h + \brief RISC-V ISA implementation + \author Màrius Montón + \date August 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef Execute_H +#define Execute_H + +#define SC_INCLUDE_DYNAMIC_PROCESSES + +#include "systemc" +#include "tlm.h" +#include "tlm_utils/simple_initiator_socket.h" + +#include "memory.h" +#include "MemoryInterface.h" +#include "Instruction.h" +#include "C_extension.h" +#include "M_extension.h" +#include "A_extension.h" +#include "Registers.h" +#include "Log.h" + + +typedef enum { + OP_LUI, + OP_AUIPC, + OP_JAL, + OP_JALR, + + OP_BEQ, + OP_BNE, + OP_BLT, + OP_BGE, + OP_BLTU, + OP_BGEU, + + OP_LB, + OP_LH, + OP_LW, + OP_LBU, + OP_LHU, + + OP_SB, + OP_SH, + OP_SW, + + OP_ADDI, + OP_SLTI, + OP_SLTIU, + OP_XORI, + OP_ORI, + OP_ANDI, + OP_SLLI, + OP_SRLI, + OP_SRAI, + + OP_ADD, + OP_SUB, + OP_SLL, + OP_SLT, + OP_SLTU, + OP_XOR, + OP_SRL, + OP_SRA, + OP_OR, + OP_AND, + + OP_FENCE, + OP_ECALL, + OP_EBREAK, + + OP_CSRRW, + OP_CSRRS, + OP_CSRRC, + OP_CSRRWI, + OP_CSRRSI, + OP_CSRRCI, + + OP_URET, + OP_SRET, + OP_MRET, + OP_WFI, + OP_SFENCE, + + OP_ERROR +} opCodes; + +/** + * @brief Risc_V execute module + */ +class BASE_ISA: public extension_base { +public: + + /** + * @brief Constructor, same as base class + */ + using extension_base::extension_base; + + /** + * @brief Access to rd field + * @return rd field + */ + inline int32_t get_rd() { + return m_instr.range(11, 7); + } + + /** + * @brief Sets rd field + * @param value desired rd value + */ + inline void set_rd(int32_t value) { + m_instr.range(11, 7) = value; + } + + /** + * @brief Access to rs1 field + * @return rs1 field + */ + inline int32_t get_rs1() { + return m_instr.range(19, 15); + } + + /** + * @brief Sets rs1 field + * @param value desired rs1 value + */ + inline void set_rs1(int32_t value) { + m_instr.range(19, 15) = value; + } + + /** + * @brief Access to rs2 field + * @return rs2 field + */ + inline int32_t get_rs2() { + return m_instr.range(24, 20); + } + + /** + * @brief Sets rs2 field + * @param value desired rs2 value + */ + inline void set_rs2(int32_t value) { + m_instr.range(24, 10) = value; + } + + /** + * @brief Access to funct3 field + * @return funct3 field + */ + inline int32_t get_funct3() { + return m_instr.range(14, 12); + } + + /** + * @brief Sets func3 field + * @param value desired func3 value + */ + inline void set_funct3(int32_t value) { + m_instr.range(14, 12) = value; + } + + /** + * @brief Access to funct7 field + * @return funct7 field + */ + inline int32_t get_funct7() { + return m_instr.range(31, 25); + } + + /** + * @brief Sets func7 field + * @param value desired func7 value + */ + inline void set_func7(int32_t value) { + m_instr.range(31, 25) = value; + } + + /** + * @brief Gets immediate field value for I-type + * @return immediate_I field + */ + inline int32_t get_imm_I() { + int32_t aux = 0; + + aux = m_instr.range(31, 20); + + /* sign extension (optimize) */ + if (m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + } + + return aux; + } + + /** + * @brief Sets immediate field for I-type + * @param value desired I value + */ + inline void set_imm_I(int32_t value) { + m_instr.range(31, 20) = value; + } + + /** + * @brief Gets immediate field value for S-type + * @return immediate_S field + */ + inline int32_t get_imm_S() { + int32_t aux = 0; + + aux = m_instr.range(31, 25) << 5; + aux |= m_instr.range(11, 7); + + if (m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + } + + return aux; + } + + /** + * @brief Sets immediate field for S-type + * @param value desired S value + */ + inline void set_imm_S(int32_t value) { + sc_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 Gets immediate field value for U-type + * @return immediate_U field + */ + inline int32_t get_imm_U() { + return m_instr.range(31, 12); + } + + /** + * @brief Sets immediate field for U-type + * @param value desired U value + */ + inline void set_imm_U(int32_t value) { + m_instr.range(31, 12) = (value << 12); + } + + /** + * @brief Gets immediate field value for B-type + * @return immediate_B field + */ + inline int32_t get_imm_B() { + int32_t aux = 0; + + aux |= m_instr[7] << 11; + aux |= m_instr.range(30, 25) << 5; + aux |= m_instr[31] << 12; + aux |= m_instr.range(11, 8) << 1; + + if (m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + } + + return aux; + } + + /** + * @brief Sets immediate field for B-type + * @param value desired B value + */ + inline void set_imm_B(int32_t value) { + sc_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 Gets immediate field value for J-type + * @return immediate_J field + */ + inline int32_t get_imm_J() { + int32_t aux = 0; + + aux = m_instr[31] << 20; + aux |= m_instr.range(19, 12) << 12; + aux |= m_instr[20] << 11; + aux |= m_instr.range(30, 21) << 1; + + /* bit extension (better way to do that?) */ + if (m_instr[31] == 1) { + aux |= (0b111111111111) << 20; + } + + return aux; + } + + /** + * @brief Sets immediate field for J-type + * @param value desired J value + */ + inline void set_imm_J(int32_t value) { + sc_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); + } + + /** + * @brief Returns shamt field for Shifts instructions + * @return value corresponding to inst(25:20) + */ + inline int32_t get_shamt() { + return m_instr.range(25, 20); + } + + /** + * @brief Returns CSR field for CSR instructions + * @return value corresponding to instr(31:20) + */ + inline int32_t get_csr() { + int32_t aux = 0; + + aux = m_instr.range(31, 20); + + return aux; + } + + /** + * @brief Access to opcode field + * @return return opcode field + */ + inline int32_t opcode() { + return m_instr.range(6, 0); + } + + bool Exec_LUI(); + bool Exec_AUIPC(); + + bool Exec_JAL(); + bool Exec_JALR(); + + bool Exec_BEQ(); + bool Exec_BNE(); + bool Exec_BLT(); + bool Exec_BGE(); + bool Exec_BLTU(); + bool Exec_BGEU(); + + bool Exec_LB(); + bool Exec_LH(); + bool Exec_LW(); + bool Exec_LBU(); + bool Exec_LHU(); + + bool Exec_SB(); + bool Exec_SH(); + bool Exec_SW(); + bool Exec_SBU(); + bool Exec_SHU(); + + bool Exec_ADDI(); + bool Exec_SLTI(); + bool Exec_SLTIU(); + bool Exec_XORI(); + bool Exec_ORI(); + bool Exec_ANDI(); + bool Exec_SLLI(); + bool Exec_SRLI(); + bool Exec_SRAI(); + + bool Exec_ADD(); + bool Exec_SUB(); + bool Exec_SLL(); + bool Exec_SLT(); + bool Exec_SLTU(); + + bool Exec_XOR(); + bool Exec_SRL(); + bool Exec_SRA(); + bool Exec_OR(); + bool Exec_AND(); + + bool Exec_FENCE(); + bool Exec_ECALL(); + bool Exec_EBREAK(); + + bool Exec_CSRRW(); + bool Exec_CSRRS(); + bool Exec_CSRRC(); + bool Exec_CSRRWI(); + bool Exec_CSRRSI(); + bool Exec_CSRRCI(); + + /*********************** Privileged Instructions ******************************/ + bool Exec_MRET(); + bool Exec_SRET(); + bool Exec_WFI(); + bool Exec_SFENCE(); + + /** + * @brief Executes default ISA instruction + * @param inst instruction to execute + * @return true if PC is affected by instruction + */ + bool process_instruction(Instruction &inst); + + /** + * @brief Decodes opcode of instruction + * @return opcode of instruction + */ + opCodes decode(); +}; + +#endif diff --git a/inc/BusCtrl.h b/inc/BusCtrl.h index 2634bf4..e6eabad 100644 --- a/inc/BusCtrl.h +++ b/inc/BusCtrl.h @@ -1,9 +1,10 @@ /** - @file BusCtrl.h - @brief Basic TLM-2 Bus controller - @author Màrius Montón - @date September 2018 -*/ + @file BusCtrl.h + @brief Basic TLM-2 Bus controller + @author Màrius Montón + @date September 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later #ifndef __BUSCTRL_H__ #define __BUSCTRL_H__ @@ -21,10 +22,6 @@ #include "Log.h" -using namespace sc_core; -using namespace sc_dt; -using namespace std; - /** * Memory mapped Trace peripheral address */ @@ -44,51 +41,53 @@ using namespace std; * It will be expanded with more ports when required (for DMA, * other peripherals, etc.) */ -class BusCtrl: sc_module { +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 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 - */ - BusCtrl(sc_module_name name); + /** + * @brief constructor + * @param name module's name + */ + BusCtrl(sc_core::sc_module_name 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_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: - Log *log; + Log *log; - 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); + 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 2191b77..6735d4e 100644 --- a/inc/CPU.h +++ b/inc/CPU.h @@ -1,9 +1,11 @@ /*! - \file CPU.h - \brief Main CPU class - \author Màrius Montón - \date August 2018 -*/ + \file CPU.h + \brief Main CPU class + \author Màrius Montón + \date August 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef CPU_BASE_H #define CPU_BASE_H @@ -16,104 +18,97 @@ #include "tlm_utils/tlm_quantumkeeper.h" #include "memory.h" -#include "Execute.h" +#include "MemoryInterface.h" +#include "BASE_ISA.h" #include "Registers.h" #include "Log.h" #include "Instruction.h" -#include "C_Instruction.h" -#include "M_Instruction.h" -#include "A_Instruction.h" - -using namespace sc_core; -using namespace sc_dt; -using namespace std; +#include "C_extension.h" +#include "M_extension.h" +#include "A_extension.h" /** * @brief ISC_V CPU model * @param name name of the module */ -class CPU: sc_module { +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 - */ - CPU(sc_module_name name, uint32_t PC); + /** + * @brief Constructor + * @param name Module name + * @param PC Program Counter initialize value + */ + CPU(sc_core::sc_module_name name, uint32_t PC); - /** - * @brief Destructor - */ - ~CPU(); + /** + * @brief Destructor + */ + ~CPU(); - Execute *exec; + MemoryInterface *mem_intf; private: - Registers *register_bank; - Performance *perf; - Log *log; - Instruction * inst; - C_Instruction *c_inst; - M_Instruction *m_inst; - A_Instruction *a_inst; + Registers *register_bank; + Performance *perf; + Log *log; + Instruction *inst; + C_extension *c_inst; + M_extension *m_inst; + A_extension *a_inst; + BASE_ISA *exec; - tlm_utils::tlm_quantumkeeper *m_qk; + tlm_utils::tlm_quantumkeeper *m_qk; - bool interrupt; - uint32_t int_cause; - bool irq_already_down; + bool interrupt; + uint32_t int_cause; + bool irq_already_down; + sc_core::sc_time default_time; + bool dmi_ptr_valid; - sc_time default_time; + /** + * + * @brief Process and triggers IRQ if all conditions met + * @return true if IRQ is triggered, false otherwise + */ + bool cpu_process_IRQ(); - bool dmi_ptr_valid; + /** + * main thread for CPU simulation + * @brief CPU mai thread + */ + void CPU_thread(void); - /** - * - * @brief Process and triggers IRQ if all conditions met - * @return true if IRQ is triggered, false otherwise - */ - bool cpu_process_IRQ(); + /** + * @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 Executes default ISA instruction - * @param inst instruction to execute - * @return true if PC is affected by instruction - */ - bool process_base_instruction(Instruction &inst); - - bool process_c_instruction(Instruction &inst); - - bool process_m_instruction(Instruction &inst); - - bool process_a_instruction(Instruction inst); - - void CPU_thread(void); - - /** - * @brief callback for IRQ simple socket - * @param trans transaction to perform (empty) - * @param delay time to annotate - * - * When called it triggers an IRQ - */ - void call_interrupt(tlm::tlm_generic_payload &trans, sc_time &delay); - - 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_Instruction.h b/inc/C_Instruction.h deleted file mode 100644 index 16ed93a..0000000 --- a/inc/C_Instruction.h +++ /dev/null @@ -1,413 +0,0 @@ -/*! - \file C_Instruction.h - \brief Decode C extensions part of the RISC-V - \author Màrius Montón - \date August 2018 -*/ - -#ifndef C_INSTRUCTION__H -#define C_INSTRUCTION__H - -#include "systemc" - -using namespace sc_core; -using namespace sc_dt; -using namespace std; - -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_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_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_ERROR -} op_C_Codes; - - -typedef enum { - C_ADDI4SPN = 0b000, - C_FLD = 0b001, - C_LW = 0b010, - C_FLW = 0b011, - C_FSD = 0b101, - C_SW = 0b110, - C_FSW = 0b111, - - 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_Instruction{ -public: - - /** - * @brief Constructor - * @param instr Instruction to decode - */ - C_Instruction(sc_uint<32> instr); - - /** - * @brief Sets instruction - * @param p_instr instruction to decode - */ - void setInstr(uint32_t p_instr) { - m_instr = sc_uint<32> (p_instr); - } - /** - * @brief Access to opcode field - * @return return opcode field - */ - inline int32_t opcode() { - return m_instr.range(1,0); - } - - /** - * @brief Access to rd field - * @return rd field - */ - inline int32_t get_rd() { - return m_instr.range(11, 7); - } - - inline void set_rd(int32_t value) { - m_instr.range(11,7) = value; - } - - inline int32_t get_rdp() { - return m_instr.range(4, 2) + 8; - } - - /** - * @brief Access to rs1 field - * @return rs1 field - */ - inline int32_t get_rs1() { - return m_instr.range(11, 7); - } - - inline void set_rs1(int32_t value) { - m_instr.range(11,7) = value; - } - - - inline int32_t get_rs1p() { - return m_instr.range(9, 7) + 8; - } - - /** - * @brief Access to rs2 field - * @return rs2 field - */ - inline int32_t get_rs2() { - return m_instr.range(6, 2); - } - - inline void set_rs2(int32_t value) { - m_instr.range(6,2) = value; - } - - inline int32_t get_rs2p() { - return m_instr.range(4, 2) + 8; - } - - inline int32_t get_funct3() { - return m_instr.range(15, 13); - } - - inline void set_funct3(int32_t value) { - m_instr.range(15,13) = value; - } - - /** - * @brief Access to immediate field for I-type - * @return immediate_I field - */ - inline int32_t get_imm_I() { - int32_t aux = 0; - - aux = m_instr.range(31, 20); - - /* sign extension (optimize) */ - if (m_instr[31] == 1) { - aux |= (0b11111111111111111111) << 12; - } - - return aux; - } - - inline void set_imm_I(int32_t value) { - m_instr.range(31,20) = value; - } - - /** - * @brief Access to immediate field for S-type - * @return immediate_S field - */ - inline int32_t get_imm_S() { - int32_t aux = 0; - - aux = m_instr.range(31, 25) << 5; - aux |= m_instr.range(11,7); - - if (m_instr[31] == 1) { - aux |= (0b11111111111111111111) << 12; - } - - return aux; - } - - inline void set_imm_S(int32_t value) { - sc_uint<32> aux = value; - - m_instr.range(31,25) = aux.range(11,5); - m_instr.range(11,7) = aux.range(4,0); - } - - /** - * @brief Access to immediate field for U-type - * @return immediate_U field - */ - inline int32_t get_imm_U() { - return m_instr.range(31, 12); - } - - inline void set_imm_U(int32_t value) { - m_instr.range(31,12) = (value << 12); - } - - /** - * @brief Access to immediate field for B-type - * @return immediate_B field - */ - inline int32_t get_imm_B() { - int32_t aux = 0; - - aux |= m_instr[7] << 11; - aux |= m_instr.range(30, 25) << 5; - aux |= m_instr[31] << 12; - aux |= m_instr.range(11, 8) << 1; - - if (m_instr[31] == 1) { - aux |= (0b11111111111111111111) << 12; - } - - return aux; - } - - inline void set_imm_B(int32_t value) { - sc_uint<32> aux = value; - - m_instr[31] = aux[12]; - m_instr.range(30,25) = aux.range(10,5); - m_instr.range(11,7) = aux.range(4,1); - m_instr[6] = aux[11]; - } - /** - * @brief Access to immediate field for J-type - * @return immediate_J field - */ - inline int32_t get_imm_J() { - int32_t aux = 0; - - aux = m_instr[12] << 11; - aux |= m_instr[11] << 4; - aux |= m_instr[10] << 9; - aux |= m_instr[9] << 8; - aux |= m_instr[8] << 10; - aux |= m_instr[7] << 6; - aux |= m_instr[6] << 7; - aux |= m_instr.range(5,3) << 1; - aux |= m_instr[2] << 5; - - if (m_instr[12] == 1) { - aux |= 0b11111111111111111111 << 12; - } - - return aux; - } - - inline void set_imm_J(int32_t value) { - sc_uint<32> aux = (value << 20); - - m_instr[31] = aux[20]; - m_instr.range(30,21) = aux.range(10,1); - m_instr[20] = aux[11]; - m_instr.range(19,12) = aux.range(19,12); - } - - inline int32_t get_imm_L() { - int32_t aux = 0; - - aux = m_instr.range(12,10) << 3; - aux |= m_instr[6] << 2; - aux |= m_instr[5] << 6; - - return aux; - } - - inline int32_t get_imm_LWSP() { - int32_t aux = 0; - - aux = m_instr[12] << 5; - aux |= m_instr.range(6,4) << 2; - aux |= m_instr.range(3,2) << 6; - - return aux; - } - - inline int32_t get_imm_ADDI() { - int32_t aux = 0; - - aux = m_instr[12] << 5; - aux |= m_instr.range(6,2); - - if (m_instr[12] == 1) { - aux |= 0b11111111111111111111111111 << 6; - } - return aux; - } - - inline int32_t get_imm_ADDI4SPN() { - int32_t aux = 0; - - aux = m_instr.range(12,11) << 4; - aux |= m_instr.range(10,7) << 6; - aux |= m_instr[6] << 2; - aux |= m_instr[5] << 3; - - return aux; - } - - inline int32_t get_imm_ADDI16SP() { - int32_t aux = 0; - - aux = m_instr[12] << 9; - aux |= m_instr[6] << 4; - aux |= m_instr[5] << 6; - aux |= m_instr[4] << 8; - aux |= m_instr[3] << 7; - aux |= m_instr[2] << 5; - - if (m_instr[12] == 1) { - aux |= 0b1111111111111111111111 << 10; - } - return aux; - } - - inline int32_t get_imm_CSS() { - int32_t aux = 0; - aux = m_instr.range(12,9) << 2; - aux |= m_instr.range(8,7) << 6; - - return aux; - } - - inline int32_t get_imm_CB() { - int32_t aux = 0; - - aux = m_instr[12] << 8; - aux |= m_instr[11] << 4; - aux |= m_instr[10] << 3; - aux |= m_instr[6] << 7; - aux |= m_instr[5] << 6; - aux |= m_instr[4] << 2; - aux |= m_instr[3] << 1; - aux |= m_instr[2] << 5; - - if (m_instr[12] == 1) { - aux |= 0b11111111111111111111111 << 9; - } - - return aux; - } - - inline int32_t get_imm_LUI() { - int32_t aux = 0; - - aux = m_instr[12] << 17; - aux |= m_instr.range(6,2) << 12; - - if (m_instr[12] == 1) { - aux |= 0b111111111111111 << 17; - } - - return aux; - } - - inline int32_t get_csr() { - return get_imm_I(); - } - - /** - * @brief Decodes opcode of instruction - * @return opcode of instruction - */ - op_C_Codes decode(); - - inline void dump() { - cout << hex << "0x" << m_instr << dec << endl; - } -private: - sc_uint<32> m_instr; -}; - -#endif diff --git a/inc/C_extension.h b/inc/C_extension.h new file mode 100644 index 0000000..54fd6d4 --- /dev/null +++ b/inc/C_extension.h @@ -0,0 +1,422 @@ +/*! + \file C_extension.h + \brief Implement C extensions part of the RISC-V + \author Màrius Montón + \date August 2018 +*/ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef C_EXTENSION__H +#define C_EXTENSION__H + +#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, + + 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_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_ERROR +} op_C_Codes; + +typedef enum { + C_ADDI4SPN = 0b000, + C_FLD = 0b001, + C_LW = 0b010, + C_FLW = 0b011, + C_FSD = 0b101, + C_SW = 0b110, + C_FSW = 0b111, + + 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 int32_t opcode() { + return m_instr.range(1, 0); + } + + /** + * @brief Access to rd field + * @return rd field + */ + inline int32_t get_rd() { + return m_instr.range(11, 7); + } + + inline void set_rd(int32_t value) { + m_instr.range(11, 7) = value; + } + + inline int32_t get_rdp() { + return m_instr.range(4, 2) + 8; + } + + /** + * @brief Access to rs1 field + * @return rs1 field + */ + inline int32_t get_rs1() { + return m_instr.range(11, 7); + } + + inline void set_rs1(int32_t value) { + m_instr.range(11, 7) = value; + } + + inline int32_t get_rs1p() { + return m_instr.range(9, 7) + 8; + } + + /** + * @brief Access to rs2 field + * @return rs2 field + */ + inline int32_t get_rs2() { + return m_instr.range(6, 2); + } + + inline void set_rs2(int32_t value) { + m_instr.range(6, 2) = value; + } + + inline int32_t get_rs2p() { + return m_instr.range(4, 2) + 8; + } + + inline int32_t get_funct3() { + return m_instr.range(15, 13); + } + + inline void set_funct3(int32_t value) { + m_instr.range(15, 13) = value; + } + + /** + * @brief Access to immediate field for I-type + * @return immediate_I field + */ + inline int32_t get_imm_I() { + int32_t aux = 0; + + aux = m_instr.range(31, 20); + + /* sign extension (optimize) */ + if (m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + } + + return aux; + } + + inline void set_imm_I(int32_t value) { + m_instr.range(31, 20) = value; + } + + /** + * @brief Access to immediate field for S-type + * @return immediate_S field + */ + inline int32_t get_imm_S() { + int32_t aux = 0; + + aux = m_instr.range(31, 25) << 5; + aux |= m_instr.range(11, 7); + + if (m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + } + + return aux; + } + + inline void set_imm_S(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 int32_t get_imm_U() { + return m_instr.range(31, 12); + } + + inline void set_imm_U(int32_t value) { + m_instr.range(31, 12) = (value << 12); + } + + /** + * @brief Access to immediate field for B-type + * @return immediate_B field + */ + inline int32_t get_imm_B() { + int32_t aux = 0; + + aux |= m_instr[7] << 11; + aux |= m_instr.range(30, 25) << 5; + aux |= m_instr[31] << 12; + aux |= m_instr.range(11, 8) << 1; + + if (m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + } + + return aux; + } + + inline void set_imm_B(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 int32_t get_imm_J() { + int32_t aux = 0; + + aux = m_instr[12] << 11; + aux |= m_instr[11] << 4; + aux |= m_instr[10] << 9; + aux |= m_instr[9] << 8; + aux |= m_instr[8] << 10; + aux |= m_instr[7] << 6; + aux |= m_instr[6] << 7; + aux |= m_instr.range(5, 3) << 1; + aux |= m_instr[2] << 5; + + if (m_instr[12] == 1) { + aux |= 0b11111111111111111111 << 12; + } + + return aux; + } + + inline void set_imm_J(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 int32_t get_imm_L() { + int32_t aux = 0; + + aux = m_instr.range(12, 10) << 3; + aux |= m_instr[6] << 2; + aux |= m_instr[5] << 6; + + return aux; + } + + inline int32_t get_imm_LWSP() { + int32_t aux = 0; + + aux = m_instr[12] << 5; + aux |= m_instr.range(6, 4) << 2; + aux |= m_instr.range(3, 2) << 6; + + return aux; + } + + inline int32_t get_imm_ADDI() { + int32_t aux = 0; + + aux = m_instr[12] << 5; + aux |= m_instr.range(6, 2); + + if (m_instr[12] == 1) { + aux |= 0b11111111111111111111111111 << 6; + } + return aux; + } + + inline int32_t get_imm_ADDI4SPN() { + int32_t aux = 0; + + aux = m_instr.range(12, 11) << 4; + aux |= m_instr.range(10, 7) << 6; + aux |= m_instr[6] << 2; + aux |= m_instr[5] << 3; + + return aux; + } + + inline int32_t get_imm_ADDI16SP() { + int32_t aux = 0; + + aux = m_instr[12] << 9; + aux |= m_instr[6] << 4; + aux |= m_instr[5] << 6; + aux |= m_instr[4] << 8; + aux |= m_instr[3] << 7; + aux |= m_instr[2] << 5; + + if (m_instr[12] == 1) { + aux |= 0b1111111111111111111111 << 10; + } + return aux; + } + + inline int32_t get_imm_CSS() { + int32_t aux = 0; + aux = m_instr.range(12, 9) << 2; + aux |= m_instr.range(8, 7) << 6; + + return aux; + } + + inline int32_t get_imm_CB() { + int32_t aux = 0; + + aux = m_instr[12] << 8; + aux |= m_instr[11] << 4; + aux |= m_instr[10] << 3; + aux |= m_instr[6] << 7; + aux |= m_instr[5] << 6; + aux |= m_instr[4] << 2; + aux |= m_instr[3] << 1; + aux |= m_instr[2] << 5; + + if (m_instr[12] == 1) { + aux |= 0b11111111111111111111111 << 9; + } + + return aux; + } + + inline int32_t get_imm_LUI() { + int32_t aux = 0; + + aux = m_instr[12] << 17; + aux |= m_instr.range(6, 2) << 12; + + if (m_instr[12] == 1) { + aux |= 0b111111111111111 << 17; + } + + return aux; + } + + inline int32_t get_csr() { + return get_imm_I(); + } + + /** + * @brief Decodes opcode of instruction + * @return opcode of instruction + */ + op_C_Codes decode(); + + 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(); + bool Exec_C_JALR(); + bool Exec_C_LW(); + bool Exec_C_SW(); + bool Exec_C_JAL(int m_rd); + + bool process_instruction(Instruction &inst); +}; + +#endif diff --git a/inc/Execute.h b/inc/Execute.h deleted file mode 100644 index 5ac5334..0000000 --- a/inc/Execute.h +++ /dev/null @@ -1,172 +0,0 @@ -/*! - \file Execute.h - \brief RISC-V ISA implementation - \author Màrius Montón - \date August 2018 -*/ -#ifndef Execute_H -#define Execute_H - -#define SC_INCLUDE_DYNAMIC_PROCESSES - -#include "systemc" -#include -#include "tlm.h" -#include "tlm_utils/simple_initiator_socket.h" - -#include "memory.h" -#include "Instruction.h" -#include "C_Instruction.h" -#include "M_Instruction.h" -#include "A_Instruction.h" -#include "Registers.h" -#include "Log.h" - -using namespace sc_core; -using namespace sc_dt; -using namespace std; - -/** - * @brief Risc_V execute module - */ -class Execute : sc_module { -public: - - /** - * @brief Constructor - * @param name module name - * @param register_bank pointer to register bank to use - */ - Execute(sc_module_name name, - Registers *register_bank); - - /* Quick & dirty way to publish a socket though modules */ - tlm_utils::simple_initiator_socket data_bus; - - bool LUI(Instruction &inst); - bool AUIPC(Instruction &inst); - - bool JAL(Instruction &inst, bool c_extension = false, int m_rd = 1); - bool JALR(Instruction &inst, bool c_extension = false); - - bool BEQ(Instruction &inst); - bool BNE(Instruction &inst); - bool BLT(Instruction &inst); - bool BGE(Instruction &inst); - bool BLTU(Instruction &inst); - bool BGEU(Instruction &inst); - - bool LB(Instruction &inst); - bool LH(Instruction &inst); - bool LW(Instruction &inst, bool c_extension = false); - bool LBU(Instruction &inst); - bool LHU(Instruction &inst); - - bool SB(Instruction &inst); - bool SH(Instruction &inst); - bool SW(Instruction &inst, bool c_extension = false); - bool SBU(Instruction &inst); - bool SHU(Instruction &inst); - - bool ADDI(Instruction &inst, bool c_extension = false); - bool SLTI(Instruction &inst); - bool SLTIU(Instruction &inst); - bool XORI(Instruction &inst); - bool ORI(Instruction &inst); - bool ANDI(Instruction &inst); - bool SLLI(Instruction &inst); - bool SRLI(Instruction &inst); - bool SRAI(Instruction &inst); - - bool ADD(Instruction &inst); - bool SUB(Instruction &inst); - bool SLL(Instruction &inst); - bool SLT(Instruction &inst); - bool SLTU(Instruction &inst); - - bool XOR(Instruction &inst); - bool SRL(Instruction &inst); - bool SRA(Instruction &inst); - bool OR(Instruction &inst); - bool AND(Instruction &inst); - - bool FENCE(Instruction &inst); - bool ECALL(Instruction &inst); - bool EBREAK(Instruction &inst); - - bool CSRRW(Instruction &inst); - bool CSRRS(Instruction &inst); - bool CSRRC(Instruction &inst); - bool CSRRWI(Instruction &inst); - bool CSRRSI(Instruction &inst); - bool CSRRCI(Instruction &inst); - -/*********************** Privileged Instructions ******************************/ - bool MRET(Instruction &inst); - bool SRET(Instruction &inst); - bool WFI(Instruction &inst); - bool SFENCE(Instruction &inst); - - /* C Extensions */ - bool C_JR(Instruction &inst); - bool C_MV(Instruction &inst); - bool C_LWSP(Instruction &inst); - bool C_ADDI4SPN(Instruction &inst); - bool C_SLLI(Instruction &inst); - bool C_ADDI16SP(Instruction &inst); - bool C_SWSP(Instruction &inst); - bool C_BEQZ(Instruction &inst); - bool C_BNEZ(Instruction &inst); - bool C_LI(Instruction &inst); - bool C_SRLI(Instruction &inst); - bool C_SRAI(Instruction &inst); - bool C_ANDI(Instruction &inst); - bool C_ADD(Instruction &inst); - bool C_SUB(Instruction &inst); - bool C_XOR(Instruction &inst); - bool C_OR(Instruction &inst); - bool C_AND(Instruction &inst); - - /* M Extensinos */ - bool M_MUL(Instruction &inst); - bool M_MULH(Instruction &inst); - bool M_MULHSU(Instruction &inst); - bool M_MULHU(Instruction &inst); - bool M_DIV(Instruction &inst); - bool M_DIVU(Instruction &inst); - bool M_REM(Instruction &inst); - bool M_REMU(Instruction &inst); - - /* A Extensinos */ - bool A_LR(Instruction &inst); - bool A_SC(Instruction &inst); - bool A_AMOSWAP(Instruction &inst); - bool A_AMOADD(Instruction &inst); - bool A_AMOXOR(Instruction &inst); - bool A_AMOAND(Instruction &inst); - bool A_AMOOR(Instruction &inst); - bool A_AMOMIN(Instruction &inst); - bool A_AMOMAX(Instruction &inst); - bool A_AMOMINU(Instruction &inst); - bool A_AMOMAXU(Instruction &inst); - - bool NOP(Instruction &inst); - -private: - uint32_t readDataMem(uint32_t addr, int size); - void writeDataMem(uint32_t addr, uint32_t data, int size); - - void RaiseException(uint32_t cause, uint32_t inst = 0); - - std::set TLB_A_Entries; - - void TLB_reserve(uint32_t address); - bool TLB_reserved(uint32_t address); - - Registers *regs; - Performance *perf; - Log *log; -}; - - -#endif diff --git a/inc/Instruction.h b/inc/Instruction.h index 5624e0e..e88f1b0 100644 --- a/inc/Instruction.h +++ b/inc/Instruction.h @@ -1,466 +1,65 @@ /*! - \file Instruction.h - \brief Decode instructions part of the RISC-V - \author Màrius Montón - \date August 2018 -*/ + \file Instruction.h + \brief Decode instructions part of the RISC-V + \author Màrius Montón + \date August 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later #ifndef INSTRUCTION__H #define INSTRUCTION__H #include "systemc" - -using namespace sc_core; -using namespace sc_dt; -using namespace std; +#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 + BASE_EXTENSION, + M_EXTENSION, + A_EXTENSION, + F_EXTENSION, + D_EXTENSION, + Q_EXTENSION, + L_EXTENSION, + C_EXTENSION, + R_EXTENSION, + J_EXTENSION, + P_EXTENSION, + V_EXTENSION, + N_EXTENSION, + UNKNOWN_EXTENSION } extension_t; -typedef enum { -OP_LUI, -OP_AUIPC, -OP_JAL, -OP_JALR, - -OP_BEQ, -OP_BNE, -OP_BLT, -OP_BGE, -OP_BLTU, -OP_BGEU, - -OP_LB, -OP_LH, -OP_LW, -OP_LBU, -OP_LHU, - -OP_SB, -OP_SH, -OP_SW, - -OP_ADDI, -OP_SLTI, -OP_SLTIU, -OP_XORI, -OP_ORI, -OP_ANDI, -OP_SLLI, -OP_SRLI, -OP_SRAI, - -OP_ADD, -OP_SUB, -OP_SLL, -OP_SLT, -OP_SLTU, -OP_XOR, -OP_SRL, -OP_SRA, -OP_OR, -OP_AND, - -OP_FENCE, -OP_ECALL, -OP_EBREAK, - -OP_CSRRW, -OP_CSRRS, -OP_CSRRC, -OP_CSRRWI, -OP_CSRRSI, -OP_CSRRCI, - -OP_URET, -OP_SRET, -OP_MRET, -OP_WFI, -OP_SFENCE, - -OP_ERROR -} opCodes; - - -typedef enum { - LUI = 0b0110111, - AUIPC = 0b0010111, - JAL = 0b1101111, - JALR = 0b1100111, - - BEQ = 0b1100011, - BEQ_F = 0b000, - BNE_F = 0b001, - BLT_F = 0b100, - BGE_F = 0b101, - BLTU_F = 0b110, - BGEU_F = 0b111, - - LB = 0b0000011, - LB_F = 0b000, - LH_F = 0b001, - LW_F = 0b010, - LBU_F = 0b100, - LHU_F = 0b101, - - SB = 0b0100011, - SB_F = 0b000, - SH_F = 0b001, - SW_F = 0b010, - - ADDI = 0b0010011, - ADDI_F = 0b000, - SLTI_F = 0b010, - SLTIU_F = 0b011, - XORI_F = 0b100, - ORI_F = 0b110, - ANDI_F = 0b111, - SLLI_F = 0b001, - SRLI_F = 0b101, - SRLI_F7 = 0b0000000, - SRAI_F7 = 0b0100000, - - ADD = 0b0110011, - ADD_F = 0b000, - SUB_F = 0b000, - ADD_F7 = 0b0000000, - SUB_F7 = 0b0100000, - - SLL_F = 0b001, - SLT_F = 0b010, - SLTU_F = 0b011, - XOR_F = 0b100, - SRL_F = 0b101, - SRA_F = 0b101, - SRL_F7 = 0b0000000, - SRA_F7 = 0b0100000, - OR_F = 0b110, - AND_F = 0b111, - - FENCE = 0b0001111, - ECALL = 0b1110011, - ECALL_F = 0b000000000000, - EBREAK_F= 0b000000000001, - URET_F = 0b000000000010, - SRET_F = 0b000100000010, - MRET_F = 0b001100000010, - WFI_F = 0b000100000101, - SFENCE_F = 0b0001001, - - ECALL_F3= 0b000, - CSRRW = 0b001, - CSRRS = 0b010, - CSRRC = 0b011, - CSRRWI = 0b101, - CSRRSI = 0b110, - CSRRCI = 0b111, -} Codes; - -#define EXCEPTION_CAUSE_INSTRUCTION_MISALIGN 0 -#define EXCEPTION_CAUSE_INSTRUCTION_ACCESS 1 -#define EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION 2 -#define EXCEPTION_CAUSE_BREAKPOINT 3 -#define EXCEPTION_CAUSE_LOAD_ADDR_MISALIGN 4 -#define EXCEPTION_CAUSE_LOAD_ACCESS_FAULT 5 - /** * @brief Instruction decoding and fields access */ class Instruction { public: - /** - * @brief Constructor - * @param instr Instruction to decode - */ - Instruction(sc_uint<32> instr); + Instruction(sc_dt::sc_uint<32> instr); - /** - * @brief Access to opcode field - * @return return opcode field - */ - inline int32_t opcode() { - return m_instr.range(6,0); - } + /** + * @brief returns what instruction extension + * @return extension + */ + extension_t check_extension(); - /** - * @brief Access to rd field - * @return rd field - */ - inline int32_t get_rd() { - return m_instr.range(11, 7); - } + void setInstr(uint32_t p_instr) { + m_instr = p_instr; + } + /** + * @brief return instruction + * @return all instruction bits (31:0) + */ + uint32_t getInstr() { + return m_instr; + } - /** - * @brief Sets rd field - * @param value desired rd value - */ - inline void set_rd(int32_t value) { - m_instr.range(11,7) = value; - } + inline void dump() { + std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; + } - /** - * @brief Access to funct3 field - * @return funct3 field - */ - inline int32_t get_funct3() { - return m_instr.range(14, 12); - } - - /** - * @brief Sets func3 field - * @param value desired func3 value - */ - inline void set_funct3(int32_t value) { - m_instr.range(14,12) = value; - } - - /** - * @brief Access to rs1 field - * @return rs1 field - */ - inline int32_t get_rs1() { - return m_instr.range(19, 15); - } - - /** - * @brief Sets rs1 field - * @param value desired rs1 value - */ - inline void set_rs1(int32_t value) { - m_instr.range(19,15) = value; - } - - /** - * @brief Access to rs2 field - * @return rs2 field - */ - inline int32_t get_rs2() { - return m_instr.range(24, 20); - } - - /** - * @brief Sets rs2 field - * @param value desired rs2 value - */ - inline void set_rs2(int32_t value) { - m_instr.range(24,10) = value; - } - - /** - * @brief Access to funct7 field - * @return funct7 field - */ - inline int32_t get_funct7() { - return m_instr.range(31, 25); - } - - /** - * @brief Sets func7 field - * @param value desired func7 value - */ - inline void set_func7(int32_t value) { - m_instr.range(31,25) = value; - } - - /** - * @brief Gets immediate field value for I-type - * @return immediate_I field - */ - inline int32_t get_imm_I() { - int32_t aux = 0; - - aux = m_instr.range(31, 20); - - /* sign extension (optimize) */ - if (m_instr[31] == 1) { - aux |= (0b11111111111111111111) << 12; - } - - return aux; - } - - /** - * @brief Sets immediate field for I-type - * @param value desired I value - */ - inline void set_imm_I(int32_t value) { - m_instr.range(31,20) = value; - } - - /** - * @brief Gets immediate field value for S-type - * @return immediate_S field - */ - inline int32_t get_imm_S() { - int32_t aux = 0; - - aux = m_instr.range(31, 25) << 5; - aux |= m_instr.range(11,7); - - if (m_instr[31] == 1) { - aux |= (0b11111111111111111111) << 12; - } - - return aux; - } - - /** - * @brief Sets immediate field for S-type - * @param value desired S value - */ - inline void set_imm_S(int32_t value) { - sc_uint<32> aux = value; - - m_instr.range(31,25) = aux.range(11,5); - m_instr.range(11,7) = aux.range(4,0); - } - - /** - * @brief Gets immediate field value for U-type - * @return immediate_U field - */ - inline int32_t get_imm_U() { - return m_instr.range(31, 12); - } - - /** - * @brief Sets immediate field for U-type - * @param value desired U value - */ - inline void set_imm_U(int32_t value) { - m_instr.range(31,12) = (value << 12); - } - - /** - * @brief Gets immediate field value for B-type - * @return immediate_B field - */ - inline int32_t get_imm_B() { - int32_t aux = 0; - - aux |= m_instr[7] << 11; - aux |= m_instr.range(30, 25) << 5; - aux |= m_instr[31] << 12; - aux |= m_instr.range(11, 8) << 1; - - if (m_instr[31] == 1) { - aux |= (0b11111111111111111111) << 12; - } - - return aux; - } - - /** - * @brief Sets immediate field for B-type - * @param value desired B value - */ - inline void set_imm_B(int32_t value) { - sc_uint<32> aux = value; - - m_instr[31] = aux[12]; - m_instr.range(30,25) = aux.range(10,5); - m_instr.range(11,7) = aux.range(4,1); - m_instr[6] = aux[11]; - } - - /** - * @brief Gets immediate field value for J-type - * @return immediate_J field - */ - inline int32_t get_imm_J() { - int32_t aux = 0; - - aux = m_instr[31] << 20; - aux |= m_instr.range(19,12) << 12; - aux |= m_instr[20] << 11; - aux |= m_instr.range(30,21) << 1; - - /* bit extension (better way to do that?) */ - if (m_instr[31] == 1) { - aux |= (0b111111111111) << 20; - } - - return aux; - } - - /** - * @brief Sets immediate field for J-type - * @param value desired J value - */ - inline void set_imm_J(int32_t value) { - sc_uint<32> aux = (value << 20); - - m_instr[31] = aux[20]; - m_instr.range(30,21) = aux.range(10,1); - m_instr[20] = aux[11]; - m_instr.range(19,12) = aux.range(19,12); - } - - /** - * @brief Returns shamt field for Shifts instructions - * @return value corresponding to inst(25:20) - */ - inline int32_t get_shamt() { - return m_instr.range(25, 20); - } - - /** - * @brief Returns CSR field for CSR instructions - * @return value corresponding to instr(31:20) - */ - inline int32_t get_csr() { - int32_t aux = 0; - - aux = m_instr.range(31, 20); - - return aux; - } - - /** - * @brief Decodes opcode of instruction - * @return opcode of instruction - */ - opCodes decode(); - - /** - * @brief returns what instruction extension - * @return extension - */ - extension_t check_extension(); - - - void setInstr(uint32_t p_instr) { - m_instr = p_instr; - } - /** - * @brief return instruction - * @return all instruction bits (31:0) - */ - uint32_t getInstr() { - return m_instr; - } - - - inline void dump() { - cout << hex << "0x" << m_instr << dec << endl; - } private: - sc_uint<32> m_instr; + sc_dt::sc_uint<32> m_instr; }; #endif diff --git a/inc/Log.h b/inc/Log.h index 6808646..020a815 100644 --- a/inc/Log.h +++ b/inc/Log.h @@ -1,9 +1,10 @@ /*! - \file Log.h - \brief Class to manage Log - \author Màrius Montón - \date Aug 2018 -*/ + \file Log.h + \brief Class to manage Log + \author Màrius Montón + \date Aug 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later #ifndef LOG_H #define LOG_H @@ -16,10 +17,6 @@ #include "systemc" #include "tlm.h" -using namespace sc_core; -using namespace sc_dt; -using namespace std; - /** * @brief Log management class * @@ -28,50 +25,48 @@ using namespace std; class Log { public: - enum LogLevel{ - ERROR = 0, - DEBUG, - WARNING, - INFO - } currentLogLevel; + enum LogLevel { + ERROR = 0, DEBUG, WARNING, INFO + } currentLogLevel; + /** + * @brief Constructor + * @return pointer to Log class + */ + static Log* getInstance(); - /** - * @brief Constructor - * @return pointer to Log class - */ - static Log* getInstance(); + /** + * @brief method to log some string + * @param msg mesasge string + * @param level level of the log (LogLevel) + */ + void SC_log(std::string msg, enum LogLevel level); - /** - * @brief method to log some string - * @param msg mesasge string - * @param level level of the log (LogLevel) - */ - void SC_log(std::string msg, enum LogLevel level); + /** + * @brief method to log some string + * @param level level of the log (LogLevel) + * @return streaming + * + * This function can be used in the following way: + * \code + * my_log->SC_log(Log::WARNING) << "some warning text" + * \endcode + */ + std::ofstream& SC_log(enum LogLevel level); - /** - * @brief method to log some string - * @param level level of the log (LogLevel) - * @return streaming - * - * This function can be used in the following way: - * \code - * my_log->SC_log(Log::WARNING) << "some warning text" - * \endcode - */ - std::ofstream& SC_log(enum LogLevel level); + /** + * @brief Sets log level + * @param newLevel Level of the log + */ + void setLogLevel(enum LogLevel newLevel); - /** - * @brief Sets log level - * @param newLevel Level of the log - */ - void setLogLevel(enum LogLevel newLevel); + enum LogLevel getLogLevel(); private: - static Log* instance; - Log(const char* filename); - std::ofstream m_stream; - std::ofstream m_sink; + static Log *instance; + Log(const char *filename); + std::ofstream m_stream; + std::ofstream m_sink; }; #endif diff --git a/inc/M_Instruction.h b/inc/M_Instruction.h deleted file mode 100644 index b7f6ee2..0000000 --- a/inc/M_Instruction.h +++ /dev/null @@ -1,130 +0,0 @@ -/*! - \file M_Instruction.h - \brief Decode M extensions part of the RISC-V - \author Màrius Montón - \date November 2018 -*/ - -#ifndef M_INSTRUCTION__H -#define M_INSTRUCTION__H - -#include "systemc" - -using namespace sc_core; -using namespace sc_dt; -using namespace std; - -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, - -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_Instruction{ -public: - - /** - * @brief Constructor - * @param instr Instruction to decode - */ - M_Instruction(sc_uint<32> instr); - - /** - * @brief Sets instruction - * @param p_instr instruction to decode - */ - void setInstr(uint32_t p_instr) { - m_instr = sc_uint<32> (p_instr); - } - - /** - * @brief Access to opcode field - * @return return opcode field - */ - inline int32_t opcode() { - return m_instr.range(14,12); - } - - /** - * @brief Access to rd field - * @return rd field - */ - inline int32_t get_rd() { - return m_instr.range(11, 7); - } - - inline void set_rd(int32_t value) { - m_instr.range(11,7) = value; - } - - - /** - * @brief Access to rs1 field - * @return rs1 field - */ - inline int32_t get_rs1() { - return m_instr.range(19, 15); - } - - inline void set_rs1(int32_t value) { - m_instr.range(19,15) = value; - } - - - /** - * @brief Access to rs2 field - * @return rs2 field - */ - inline int32_t get_rs2() { - return m_instr.range(24, 20); - } - - inline void set_rs2(int32_t value) { - m_instr.range(24,20) = value; - } - - - inline int32_t get_funct3() { - return m_instr.range(14, 12); - } - - inline void set_funct3(int32_t value) { - m_instr.range(14,12) = value; - } - - /** - * @brief Decodes opcode of instruction - * @return opcode of instruction - */ - op_M_Codes decode(); - - inline void dump() { - cout << hex << "0x" << m_instr << dec << endl; - } -private: - sc_uint<32> m_instr; -}; - -#endif diff --git a/inc/M_extension.h b/inc/M_extension.h new file mode 100644 index 0000000..14dcc4b --- /dev/null +++ b/inc/M_extension.h @@ -0,0 +1,129 @@ +/*! + \file M_extension.h + \brief Implement M extensions part of the RISC-V + \author Màrius Montón + \date November 2018 +*/ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef M_EXTENSION__H +#define M_EXTENSION__H + +#include "systemc" + +#include "extension_base.h" +#include "Log.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, + + 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: + + /** + * @brief Constructor, same as base clase + */ + using extension_base::extension_base; + + /** + * @brief Decodes opcode of instruction + * @return opcode of instruction + */ + op_M_Codes decode(); + + inline void dump() { + std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; + } + + bool Exec_M_MUL(); + bool Exec_M_MULH(); + bool Exec_M_MULHSU(); + bool Exec_M_MULHU(); + bool Exec_M_DIV(); + bool Exec_M_DIVU(); + bool Exec_M_REM(); + bool Exec_M_REMU(); + + bool process_instruction(Instruction &inst); + +private: + + /** + * @brief Access to opcode field + * @return return opcode field + */ + inline int32_t opcode() { + return m_instr.range(14, 12); + } + + /** + * @brief Access to rd field + * @return rd field + */ + inline int32_t get_rd() { + return m_instr.range(11, 7); + } + + inline void set_rd(int32_t value) { + m_instr.range(11, 7) = value; + } + + /** + * @brief Access to rs1 field + * @return rs1 field + */ + inline int32_t get_rs1() { + return m_instr.range(19, 15); + } + + inline void set_rs1(int32_t value) { + m_instr.range(19, 15) = value; + } + + /** + * @brief Access to rs2 field + * @return rs2 field + */ + inline int32_t get_rs2() { + return m_instr.range(24, 20); + } + + inline void set_rs2(int32_t value) { + m_instr.range(24, 20) = value; + } + + inline int32_t get_funct3() { + return m_instr.range(14, 12); + } + + inline void set_funct3(int32_t value) { + m_instr.range(14, 12) = value; + } +}; + +#endif diff --git a/inc/Memory.h b/inc/Memory.h index 71d1064..894b237 100644 --- a/inc/Memory.h +++ b/inc/Memory.h @@ -1,9 +1,10 @@ /*! - \file Memory.h - \brief Basic TLM-2 memory model - \author Màrius Montón - \date August 2018 -*/ + \file Memory.h + \brief Basic TLM-2 memory model + \author Màrius Montón + \date August 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later #ifndef __MEMORY_H__ #define __MEMORY_H__ @@ -20,69 +21,68 @@ #include "Log.h" -using namespace sc_core; -using namespace sc_dt; -using namespace std; - /** * @brief Basic TLM-2 memory */ -class Memory: sc_module { +class Memory: sc_core::sc_module { public: - // TLM-2 socket, defaults to 32-bits wide, base protocol - tlm_utils::simple_target_socket socket; + // TLM-2 socket, defaults to 32-bits wide, base protocol + tlm_utils::simple_target_socket socket; - //enum { SIZE = 0x90000000 }; - enum { SIZE = 0x10000000 }; - const sc_time LATENCY; + //enum { SIZE = 0x90000000 }; + enum { + SIZE = 0x10000000 + }; + const sc_core::sc_time LATENCY; - Memory(sc_module_name name, string filename); - Memory(sc_module_name name, bool use_file); + Memory(sc_core::sc_module_name name, std::string filename); + Memory(sc_core::sc_module_name name, bool use_file); - ~Memory(void); - - /** - * @brief Returns Program Counter read from hexfile - * @return Initial PC - */ - virtual uint32_t getPCfromHEX(); + ~Memory(void); - // TLM-2 blocking transport method - virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ); + /** + * @brief Returns Program Counter read from hexfile + * @return Initial PC + */ + virtual 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); + + // ********************************************* + // TLM-2 debug transport method + // ********************************************* + virtual unsigned int transport_dbg(tlm::tlm_generic_payload &trans); private: - /** - * @brief Memory array in bytes - */ - //uint8_t mem[SIZE]; - uint8_t *mem; + /** + * @brief Memory array in bytes + */ + uint8_t *mem; - /** - * @brief Log classe - */ - Log *log; - /** - * @brief Program counter (PC) read from hex file - */ - uint32_t program_counter; + /** + * @brief Log class + */ + Log *log; - uint32_t memory_offset; - /** - * @brief Read Intel hex file - * @param filename file name to read - */ - virtual void readHexFile(string filename); + /** + * @brief Program counter (PC) read from hex file + */ + uint32_t program_counter; + + uint32_t memory_offset; + /** + * @brief Read Intel hex file + * @param filename file name to read + */ + virtual void readHexFile(std::string filename); }; - #endif /* __MEMORY_H__ */ +#endif /* __MEMORY_H__ */ diff --git a/inc/MemoryInterface.h b/inc/MemoryInterface.h new file mode 100644 index 0000000..d0753f5 --- /dev/null +++ b/inc/MemoryInterface.h @@ -0,0 +1,34 @@ +/*! + \file MemoryInterface.h + \brief CPU to Memory Interface class + \author Màrius Montón + \date May 2020 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef INC_MEMORYINTERFACE_H_ +#define INC_MEMORYINTERFACE_H_ + +#include "systemc" + +#include "tlm.h" +#include "tlm_utils/simple_initiator_socket.h" +#include "tlm_utils/tlm_quantumkeeper.h" + +#include "memory.h" +#include "Log.h" + +/** + * @brief Memory Interface + */ +class MemoryInterface { +public: + + tlm_utils::simple_initiator_socket data_bus; + + MemoryInterface(); + uint32_t readDataMem(uint32_t addr, int size); + void writeDataMem(uint32_t addr, uint32_t data, int size); +}; + +#endif /* INC_MEMORYINTERFACE_H_ */ diff --git a/inc/Performance.h b/inc/Performance.h index 5e5ef56..354af6d 100644 --- a/inc/Performance.h +++ b/inc/Performance.h @@ -1,9 +1,10 @@ /*! - \file Performance.h - \brief Class to store performance of CPU - \author Màrius Montón - \date Aug 2018 -*/ + \file Performance.h + \brief Class to store performance of CPU + \author Màrius Montón + \date Aug 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later #ifndef PERFORMANCE_H #define PERFORMANCE_H @@ -14,89 +15,85 @@ #include "tlm.h" -using namespace sc_core; -using namespace sc_dt; -using namespace std; - /** * @brief Performance indicators class * * Singleton class to be shared among all other classes */ -class Performance{ +class Performance { public: - /** - * @brief Get an instance of the class - * @return pointer to Performance class - */ - static Performance* getInstance(); + /** + * @brief Get an instance of the class + * @return pointer to Performance class + */ + static Performance* getInstance(); - /** - * @brief Increment data memory read counter - */ - inline void dataMemoryRead() { - data_memory_read++; - } + /** + * @brief Increment data memory read counter + */ + inline void dataMemoryRead() { + data_memory_read++; + } - /** - * @brief Increment data memory write counter - */ - inline void dataMemoryWrite() { - data_memory_write++; - } + /** + * @brief Increment data memory write counter + */ + inline void dataMemoryWrite() { + data_memory_write++; + } - /** - * @brief Increment code memory read counter - */ - inline void codeMemoryRead() { - code_memory_read++; - } + /** + * @brief Increment code memory read counter + */ + inline void codeMemoryRead() { + code_memory_read++; + } - /** - * @brief Increment code memory write counter - */ - inline void codeMemoryWrite() { - code_memory_write++; - } + /** + * @brief Increment code memory write counter + */ + inline void codeMemoryWrite() { + code_memory_write++; + } - /** - * @brief Increment register read counter - */ - inline void registerRead() { - register_read++; - } + /** + * @brief Increment register read counter + */ + inline void registerRead() { + register_read++; + } - /** - * @brief Increment register write counter - */ - inline void registerWrite() { - register_write++; - } + /** + * @brief Increment register write counter + */ + inline void registerWrite() { + register_write++; + } - /** - * @brief Increment instructions executed counter - */ - inline void instructionsInc() { - instructions_executed++; - } + /** + * @brief Increment instructions executed counter + */ + inline void instructionsInc() { + instructions_executed++; + } - /** - * @brief Dump counters to cout - */ - void dump(); + /** + * @brief Dump counters to cout + */ + void dump(); private: - static Performance* instance; - Performance(); + static Performance *instance; + Performance(); - uint64_t data_memory_read; - uint64_t data_memory_write; - uint64_t code_memory_read; - uint64_t code_memory_write; - uint64_t register_read; - uint64_t register_write; - uint64_t instructions_executed; + uint64_t data_memory_read; + uint64_t data_memory_write; + uint64_t code_memory_read; + uint64_t code_memory_write; + uint64_t register_read; + uint64_t register_write; + uint64_t instructions_executed; }; #endif diff --git a/inc/Registers.h b/inc/Registers.h index 12d9cb1..f2d1194 100644 --- a/inc/Registers.h +++ b/inc/Registers.h @@ -1,9 +1,11 @@ /*! - \file Registers.h - \brief Basic register file - \author Màrius Montón - \date August 2018 -*/ + \file Registers.h + \brief Basic register file + \author Màrius Montón + \date August 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef REGISTERS_H #define REGISTERS_H @@ -23,7 +25,6 @@ #define MISA_M_EXTENSION (1 << 12) #define MISA_MXL (1 << 30) - #define CSR_MVENDORID (0xF11) #define CSR_MARCHID (0xF12) #define CSR_MIMPID (0xF13) @@ -65,7 +66,6 @@ #define CSR_STVEC (0x105) - #define MSTATUS_UIE (1 << 0) #define MSTATUS_SIE (1 << 1) #define MSTATUS_MIE (1 << 3) @@ -103,166 +103,161 @@ #define MIE_SEIE (1 << 9) #define MIE_MEIE (1 << 11) - /* 1 ns tick in CYCLE & TIME counters */ #define TICKS_PER_SECOND (1000000) -using namespace sc_core; -using namespace sc_dt; -using namespace std; - /** * @brief Register file implementation */ 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 + }; + /** + * Default constructor + */ + Registers(); - /** - * Set value for a register - * @param reg_num register number - * @param value register value - */ - void setValue(int reg_num, int32_t value); + /** + * Set value for a register + * @param reg_num register number + * @param value register value + */ + void setValue(int reg_num, int32_t value); - /** - * Returns register value - * @param reg_num register number - * @return register value - */ - int32_t getValue(int reg_num); + /** + * Returns register value + * @param reg_num register number + * @return register value + */ + int32_t getValue(int reg_num); - /** - * Returns PC value - * @return PC value - */ - uint32_t getPC(); + /** + * Returns PC value + * @return PC value + */ + uint32_t getPC(); - /** - * Sets arbitraty value to PC - * @param new_pc new address to PC - */ - void setPC(uint32_t new_pc); + /** + * Sets arbitraty value to PC + * @param new_pc new address to PC + */ + void setPC(uint32_t new_pc); - /** - * Increments PC couunter to next address - */ - inline void incPC(bool C_ext=false) { - if (C_ext == true) { - register_PC += 2; - } else { - register_PC += 4; - } + /** + * Increments PC couunter to next address + */ + inline void incPC(bool C_ext = false) { + if (C_ext == true) { + register_PC += 2; + } else { + register_PC += 4; + } - } + } - /** - * @brief Get CSR value - * @param csr CSR number to access - * @return CSR value - */ - uint32_t getCSR(int csr); + /** + * @brief Get CSR value + * @param csr CSR number to access + * @return CSR value + */ + uint32_t getCSR(int csr); - /** - * @brief Set CSR value - * @param csr CSR number to access - * @param value new value to register - */ - void setCSR(int csr, uint32_t value); + /** + * @brief Set CSR value + * @param csr CSR number to access + * @param value new value to register + */ + void setCSR(int csr, uint32_t value); - /** - * Dump register data to console - */ - void dump(); + /** + * Dump register data to console + */ + void dump(); private: - /** - * bank of registers (32 regs of 32bits each) - */ - int32_t register_bank[32]; + /** + * bank of registers (32 regs of 32bits each) + */ + int32_t register_bank[32]; - /** - * Program counter (32 bits width) - */ - uint32_t register_PC; + /** + * Program counter (32 bits width) + */ + uint32_t register_PC; - /** - * CSR registers (4096 maximum) - */ - uint32_t CSR[4096]; - Performance *perf; + /** + * CSR registers (4096 maximum) + */ + uint32_t CSR[4096]; + Performance *perf; - void initCSR(void); + void initCSR(void); }; #endif diff --git a/inc/Timer.h b/inc/Timer.h index 55a8de8..720c8b3 100644 --- a/inc/Timer.h +++ b/inc/Timer.h @@ -1,9 +1,10 @@ /*! - \file Timer.h - \brief Basic TLM-2 Timer module - \author Màrius Montón - \date January 2019 -*/ + \file Timer.h + \brief Basic TLM-2 Timer module + \author Màrius Montón + \date January 2019 + */ +// SPDX-License-Identifier: GPL-3.0-or-later #ifndef __TIMER_H__ #define __TIMER_H__ @@ -20,54 +21,50 @@ #include "BusCtrl.h" -using namespace sc_core; -using namespace sc_dt; -using namespace std; - /** * @brief Simple timer peripheral * * It runs a 1 ns (nanoseconds) pace * */ -class Timer: sc_module { +class Timer: sc_core::sc_module { public: - // TLM-2 socket, defaults to 32-bits wide, base protocol - tlm_utils::simple_target_socket socket; + // TLM-2 socket, defaults to 32-bits wide, base protocol + tlm_utils::simple_target_socket socket; - tlm_utils::simple_initiator_socket irq_line; - //sc_out timer_irq; + tlm_utils::simple_initiator_socket irq_line; - /** - * - * @brief Constructor - * @param name module name - */ - Timer(sc_module_name name); + /** + * + * @brief Constructor + * @param name module name + */ + Timer(sc_core::sc_module_name 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. - * - */ - 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. + * + */ + 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_time& delay ); + /** + * + * @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_uint<64> m_mtime; /**< mtime register */ - sc_uint<64> m_mtimecmp; /**< mtimecmp register */ - sc_event timer_event; /**< event */ + 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 fb69f92..f1ac37d 100644 --- a/inc/Trace.h +++ b/inc/Trace.h @@ -1,9 +1,10 @@ /*! - \file Trace.h - \brief Basic TLM-2 Trace module - \author Màrius Montón - \date September 2018 -*/ + \file Trace.h + \brief Basic TLM-2 Trace module + \author Màrius Montón + \date September 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later #ifndef __TRACE_H__ #define __TRACE_H__ @@ -18,46 +19,43 @@ #include "tlm.h" #include "tlm_utils/simple_target_socket.h" -using namespace sc_core; -using namespace sc_dt; -using namespace std; - /** * @brief Simple trace peripheral * * This peripheral outputs to cout any character written to its unique register */ -class Trace: sc_module { +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 + */ + Trace(sc_core::sc_module_name name); + + /** + * @brief Destructor + */ + ~Trace(); - /** - * @brief Constructor - * @param name Module name - */ - Trace(sc_module_name name); - - /** - * @brief Destructor - */ - ~Trace(); - private: - - // TLM-2 blocking transport method - virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ); - - void xtermLaunch(char *slaveName); - void xtermKill( const char *mess ); - void xtermSetup(void); - - int ptSlave; - int ptMaster; - int xtermPid; + + // TLM-2 blocking transport method + virtual void b_transport(tlm::tlm_generic_payload &trans, + sc_core::sc_time &delay); + + void xtermLaunch(char *slaveName); + void xtermKill(const char *mess); + void xtermSetup(void); + + int ptSlave; + int ptMaster; + int xtermPid; }; #endif diff --git a/inc/extension_base.h b/inc/extension_base.h new file mode 100644 index 0000000..e95ad13 --- /dev/null +++ b/inc/extension_base.h @@ -0,0 +1,58 @@ +/*! + \file extension_base.h + \brief Base class for ISA extensions + \author Màrius Montón + \date May 2020 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef INC_EXTENSION_BASE_H_ +#define INC_EXTENSION_BASE_H_ + +#include "systemc" + +#include "Instruction.h" +#include "Registers.h" +#include "Log.h" +#include "MemoryInterface.h" + +#define EXCEPTION_CAUSE_INSTRUCTION_MISALIGN 0 +#define EXCEPTION_CAUSE_INSTRUCTION_ACCESS 1 +#define EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION 2 +#define EXCEPTION_CAUSE_BREAKPOINT 3 +#define EXCEPTION_CAUSE_LOAD_ADDR_MISALIGN 4 +#define EXCEPTION_CAUSE_LOAD_ACCESS_FAULT 5 + +class extension_base { + +public: + extension_base(sc_dt::sc_uint<32> instr, Registers *register_bank, + MemoryInterface *mem_interface); + virtual ~extension_base() = 0; + + void setInstr(uint32_t p_instr); + void RaiseException(uint32_t cause, uint32_t inst); + bool NOP(); + + /* pure virtual functions */ + virtual int32_t opcode() = 0; + virtual int32_t get_rd() = 0; + virtual void set_rd(int32_t value) = 0; + virtual int32_t get_rs1() = 0; + virtual void set_rs1(int32_t value) = 0; + virtual int32_t get_rs2() = 0; + virtual void set_rs2(int32_t value) = 0; + virtual int32_t get_funct3() = 0; + virtual void set_funct3(int32_t value) = 0; + + void dump(); + +protected: + sc_dt::sc_uint<32> m_instr; + Registers *regs; + Performance *perf; + Log *log; + MemoryInterface *mem_intf; +}; + +#endif /* INC_EXTENSION_BASE_H_ */ diff --git a/src/A_Instruction.cpp b/src/A_Instruction.cpp deleted file mode 100644 index 7293534..0000000 --- a/src/A_Instruction.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "A_Instruction.h" - - -A_Instruction::A_Instruction(sc_uint<32> instr) { - a_instr = instr; -} - -op_A_Codes A_Instruction::decode() { - - 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; - default: - return OP_A_ERROR; - break; - - } - - return OP_A_ERROR; -} diff --git a/src/A_extension.cpp b/src/A_extension.cpp new file mode 100644 index 0000000..d1ebc95 --- /dev/null +++ b/src/A_extension.cpp @@ -0,0 +1,416 @@ +/*! + \file A_extension.h + \brief Implement A extensions part of the RISC-V + \author Màrius Montón + \date December 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "A_extension.h" + +op_A_Codes A_extension::decode() { + + 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; + default: + return OP_A_ERROR; + break; + + } + + return OP_A_ERROR; +} + +bool A_extension::Exec_A_LR() { + uint32_t mem_addr = 0; + int rd, rs1, rs2; + 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); + regs->setValue(rd, data); + + TLB_reserve(mem_addr); + + log->SC_log(Log::INFO) << std::dec << "LR.W: x" << rs1 << " (@0x" + << std::hex << mem_addr << std::dec << ") -> x" << rd << std::endl; + + return true; +} + +bool A_extension::Exec_A_SC() { + uint32_t mem_addr = 0; + int rd, rs1, rs2; + 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) == true) { + mem_intf->writeDataMem(mem_addr, data, 4); + regs->setValue(rd, 0); // SC writes 0 to rd on success + } else { + regs->setValue(rd, 1); // SC writes nonzero on failure + } + + log->SC_log(Log::INFO) << std::dec << "SC.W: (@0x" << std::hex << mem_addr + << std::dec << ") <- x" << rs2 << std::hex << "(0x" << data << ")" + << std::endl; + + return true; +} + +bool A_extension::Exec_A_AMOSWAP() { + uint32_t mem_addr = 0; + int rd, rs1, rs2; + uint32_t data; + 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); + + regs->setValue(rd, data); + + // swap + aux = regs->getValue(rs2); + regs->setValue(rs2, data); + + mem_intf->writeDataMem(mem_addr, aux, 4); + + log->SC_log(Log::INFO) << std::dec << "AMOSWAP " << std::endl; + return true; +} + +bool A_extension::Exec_A_AMOADD() { + uint32_t mem_addr = 0; + int rd, rs1, rs2; + uint32_t data; + + /* 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); + + regs->setValue(rd, data); + + // add + data = data + regs->getValue(rs2); + + mem_intf->writeDataMem(mem_addr, data, 4); + + log->SC_log(Log::INFO) << std::dec << "AMOADD " << std::endl; + + return true; +} + +bool A_extension::Exec_A_AMOXOR() { + uint32_t mem_addr = 0; + int rd, rs1, rs2; + uint32_t data; + + /* 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); + + regs->setValue(rd, data); + + // add + data = data ^ regs->getValue(rs2); + + mem_intf->writeDataMem(mem_addr, data, 4); + + log->SC_log(Log::INFO) << std::dec << "AMOXOR " << std::endl; + + return true; +} +bool A_extension::Exec_A_AMOAND() { + uint32_t mem_addr = 0; + int rd, rs1, rs2; + uint32_t data; + + /* 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); + + regs->setValue(rd, data); + + // add + data = data & regs->getValue(rs2); + + mem_intf->writeDataMem(mem_addr, data, 4); + + log->SC_log(Log::INFO) << std::dec << "AMOAND " << std::endl; + + return true; +} + +bool A_extension::Exec_A_AMOOR() { + uint32_t mem_addr = 0; + int rd, rs1, rs2; + uint32_t data; + + /* 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); + + regs->setValue(rd, data); + + // add + data = data | regs->getValue(rs2); + + mem_intf->writeDataMem(mem_addr, data, 4); + + log->SC_log(Log::INFO) << std::dec << "AMOOR " << std::endl; + return true; +} +bool A_extension::Exec_A_AMOMIN() { + uint32_t mem_addr = 0; + int rd, rs1, rs2; + uint32_t data; + 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); + + regs->setValue(rd, data); + + // min + aux = regs->getValue(rs2); + if ((int32_t) data < (int32_t) aux) { + aux = data; + } + + mem_intf->writeDataMem(mem_addr, aux, 4); + + log->SC_log(Log::INFO) << std::dec << "AMOMIN " << std::endl; + + return true; +} +bool A_extension::Exec_A_AMOMAX() { + uint32_t mem_addr = 0; + int rd, rs1, rs2; + uint32_t data; + 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); + + regs->setValue(rd, data); + + // > + aux = regs->getValue(rs2); + if ((int32_t) data > (int32_t) aux) { + aux = data; + } + + mem_intf->writeDataMem(mem_addr, aux, 4); + + log->SC_log(Log::INFO) << std::dec << "AMOMAX " << std::endl; + + return true; +} +bool A_extension::Exec_A_AMOMINU() { + uint32_t mem_addr = 0; + int rd, rs1, rs2; + uint32_t data; + 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); + + regs->setValue(rd, data); + + // min + aux = regs->getValue(rs2); + if (data < aux) { + aux = data; + } + + mem_intf->writeDataMem(mem_addr, aux, 4); + + log->SC_log(Log::INFO) << std::dec << "AMOMINU " << std::endl; + + return true; +} +bool A_extension::Exec_A_AMOMAXU() { + uint32_t mem_addr = 0; + int rd, rs1, rs2; + uint32_t data; + 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); + + regs->setValue(rd, data); + + // max + aux = regs->getValue(rs2); + if (data > aux) { + aux = data; + } + + mem_intf->writeDataMem(mem_addr, aux, 4); + + log->SC_log(Log::INFO) << std::dec << "AMOMAXU " << std::endl; + + return true; +} + +void A_extension::TLB_reserve(uint32_t address) { + TLB_A_Entries.insert(address); + return; +} + +bool A_extension::TLB_reserved(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; + default: + std::cout << "A instruction not implemented yet" << std::endl; + inst.dump(); + NOP(); + break; + } + + return PC_not_affected; +} diff --git a/src/BASE_ISA.cpp b/src/BASE_ISA.cpp new file mode 100644 index 0000000..196e90b --- /dev/null +++ b/src/BASE_ISA.cpp @@ -0,0 +1,1489 @@ +/*! + \file BASE_ISA.cpp + \brief RISC-V ISA implementation + \author Màrius Montón + \date August 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "BASE_ISA.h" + +typedef enum { + LUI = 0b0110111, + AUIPC = 0b0010111, + JAL = 0b1101111, + JALR = 0b1100111, + + BEQ = 0b1100011, + BEQ_F = 0b000, + BNE_F = 0b001, + BLT_F = 0b100, + BGE_F = 0b101, + BLTU_F = 0b110, + BGEU_F = 0b111, + + LB = 0b0000011, + LB_F = 0b000, + LH_F = 0b001, + LW_F = 0b010, + LBU_F = 0b100, + LHU_F = 0b101, + + SB = 0b0100011, + SB_F = 0b000, + SH_F = 0b001, + SW_F = 0b010, + + ADDI = 0b0010011, + ADDI_F = 0b000, + SLTI_F = 0b010, + SLTIU_F = 0b011, + XORI_F = 0b100, + ORI_F = 0b110, + ANDI_F = 0b111, + SLLI_F = 0b001, + SRLI_F = 0b101, + SRLI_F7 = 0b0000000, + SRAI_F7 = 0b0100000, + + ADD = 0b0110011, + ADD_F = 0b000, + SUB_F = 0b000, + ADD_F7 = 0b0000000, + SUB_F7 = 0b0100000, + + SLL_F = 0b001, + SLT_F = 0b010, + SLTU_F = 0b011, + XOR_F = 0b100, + SRL_F = 0b101, + SRA_F = 0b101, + SRL_F7 = 0b0000000, + SRA_F7 = 0b0100000, + OR_F = 0b110, + AND_F = 0b111, + + FENCE = 0b0001111, + ECALL = 0b1110011, + ECALL_F = 0b000000000000, + EBREAK_F = 0b000000000001, + URET_F = 0b000000000010, + SRET_F = 0b000100000010, + MRET_F = 0b001100000010, + WFI_F = 0b000100000101, + SFENCE_F = 0b0001001, + + ECALL_F3 = 0b000, + CSRRW = 0b001, + CSRRS = 0b010, + CSRRC = 0b011, + CSRRWI = 0b101, + CSRRSI = 0b110, + CSRRCI = 0b111, +} Codes; + +bool BASE_ISA::Exec_LUI() { + int rd; + uint32_t imm = 0; + + rd = get_rd(); + imm = get_imm_U() << 12; + regs->setValue(rd, imm); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "LUI x" << std::dec << rd << " <- 0x" << std::hex + << imm << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_AUIPC() { + int rd; + uint32_t imm = 0; + int new_pc; + + rd = get_rd(); + imm = get_imm_U() << 12; + new_pc = regs->getPC() + imm; + + regs->setValue(rd, new_pc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "AUIPC x" << std::dec << rd << " <- 0x" + << std::hex << imm << " + PC (0x" << new_pc << ")" << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_JAL() { + int32_t mem_addr = 0; + int rd; + int new_pc, old_pc; + + rd = get_rd(); + mem_addr = get_imm_J(); + old_pc = regs->getPC(); + new_pc = old_pc + mem_addr; + + regs->setPC(new_pc); + + old_pc = old_pc + 4; + regs->setValue(rd, old_pc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "JAL: x" << std::dec << rd << " <- 0x" << std::hex + << old_pc << std::dec << ". PC + 0x" << std::hex << mem_addr + << " -> PC (0x" << new_pc << ")" << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_JALR() { + uint32_t mem_addr = 0; + int rd, rs1; + int new_pc, old_pc; + + rd = get_rd(); + rs1 = get_rs1(); + mem_addr = get_imm_I(); + + old_pc = regs->getPC(); + regs->setValue(rd, old_pc + 4); + + new_pc = (regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE; + regs->setPC(new_pc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "JALR: x" << std::dec << rd << " <- 0x" + << std::hex << old_pc + 4 << " PC <- 0x" << new_pc << std::endl; + } + return true; +} + +bool BASE_ISA::Exec_BEQ() { + int rs1, rs2; + int new_pc = 0; + + rs1 = get_rs1(); + rs2 = get_rs2(); + + if (regs->getValue(rs1) == regs->getValue(rs2)) { + new_pc = regs->getPC() + get_imm_B(); + regs->setPC(new_pc); + } else { + regs->incPC(); + new_pc = regs->getPC(); + } + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "BEQ x" << std::dec << rs1 << "(0x" << std::hex + << regs->getValue(rs1) << ") == x" << std::dec << rs2 << "(0x" + << std::hex << regs->getValue(rs2) << ")? -> PC (0x" << std::hex + << new_pc << ")" << std::dec << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_BNE() { + int rs1, rs2; + int new_pc = 0; + uint32_t val1, val2; + + rs1 = get_rs1(); + rs2 = get_rs2(); + + val1 = regs->getValue(rs1); + val2 = regs->getValue(rs2); + + if (val1 != val2) { + new_pc = regs->getPC() + get_imm_B(); + regs->setPC(new_pc); + } else { + regs->incPC(); + new_pc = regs->getPC(); + } + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "BNE: x" << std::dec << rs1 << "(0x" << std::hex + << val1 << ") == x" << std::dec << rs2 << "(0x" << std::hex << val2 + << ")? -> PC (0x" << std::hex << new_pc << ")" << std::dec + << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_BLT() { + int rs1, rs2; + int new_pc = 0; + + rs1 = get_rs1(); + rs2 = get_rs2(); + + if ((int32_t) regs->getValue(rs1) < (int32_t) regs->getValue(rs2)) { + new_pc = regs->getPC() + get_imm_B(); + regs->setPC(new_pc); + } else { + regs->incPC(); + } + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "BLT x" << std::dec << rs1 << "(0x" << std::hex + << (int32_t) regs->getValue(rs1) << ") < x" << std::dec << rs2 + << "(0x" << std::hex << (int32_t) regs->getValue(rs2) + << ")? -> PC (0x" << std::hex << new_pc << ")" << std::dec + << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_BGE() { + int rs1, rs2; + int new_pc = 0; + + rs1 = get_rs1(); + rs2 = get_rs2(); + + if ((int32_t) regs->getValue(rs1) >= (int32_t) regs->getValue(rs2)) { + new_pc = regs->getPC() + get_imm_B(); + regs->setPC(new_pc); + } else { + regs->incPC(); + } + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "BGE x" << std::dec << rs1 << "(0x" << std::hex + << (int32_t) regs->getValue(rs1) << ") > x" << std::dec << rs2 + << "(0x" << std::hex << (int32_t) regs->getValue(rs2) + << ")? -> PC (0x" << std::hex << new_pc << ")" << std::dec + << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_BLTU() { + int rs1, rs2; + int new_pc = 0; + + rs1 = get_rs1(); + rs2 = get_rs2(); + + if ((uint32_t) regs->getValue(rs1) < (uint32_t) regs->getValue(rs2)) { + new_pc = regs->getPC() + get_imm_B(); + regs->setPC(new_pc); + } else { + regs->incPC(); + new_pc = regs->getPC(); + } + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "BLTU x" << std::dec << rs1 << "(0x" << std::hex + << regs->getValue(rs1) << ") < x" << std::dec << rs2 << "(0x" + << std::hex << regs->getValue(rs2) << ")? -> PC (0x" << std::hex + << new_pc << ")" << std::dec << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_BGEU() { + int rs1, rs2; + int new_pc = 0; + + rs1 = get_rs1(); + rs2 = get_rs2(); + + if ((uint32_t) regs->getValue(rs1) >= (uint32_t) regs->getValue(rs2)) { + new_pc = regs->getPC() + get_imm_B(); + regs->setPC(new_pc); + } else { + regs->incPC(); + } + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "BGEU x" << std::dec << rs1 << "(0x" << std::hex + << regs->getValue(rs1) << ") > x" << std::dec << rs2 << "(0x" + << std::hex << regs->getValue(rs2) << ")? -> PC (0x" << std::hex + << new_pc << ")" << std::dec << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_LB() { + uint32_t mem_addr = 0; + int rd, rs1; + int32_t imm = 0; + int8_t data; + + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); + + mem_addr = imm + regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 1); + regs->setValue(rd, data); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "LB: x" << rs1 << " + " << imm << " (@0x" + << std::hex << mem_addr << std::dec << ") -> x" << rd << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_LH() { + uint32_t mem_addr = 0; + int rd, rs1; + int32_t imm = 0; + int16_t data; + + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); + + mem_addr = imm + regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 2); + regs->setValue(rd, data); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "LH: x" << rs1 << " + " << imm << " (@0x" + << std::hex << mem_addr << std::dec << ") -> x" << rd << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_LW() { + uint32_t mem_addr = 0; + int rd, rs1; + int32_t imm = 0; + uint32_t data; + + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); + + mem_addr = imm + regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 4); + regs->setValue(rd, data); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << std::dec << "LW: x" << rs1 << "(0x" << std::hex + << regs->getValue(rs1) << ") + " << std::dec << imm << " (@0x" + << std::hex << mem_addr << std::dec << ") -> x" << rd << std::hex + << " (0x" << data << ")" << std::endl; + } + return true; +} + +bool BASE_ISA::Exec_LBU() { + uint32_t mem_addr = 0; + int rd, rs1; + int32_t imm = 0; + uint8_t data; + + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); + + mem_addr = imm + regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 1); + regs->setValue(rd, data); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "LBU: x" << rs1 << " + " << imm << " (@0x" + << std::hex << mem_addr << std::dec << ") -> x" << rd << std::endl; + } + return true; +} + +bool BASE_ISA::Exec_LHU() { + uint32_t mem_addr = 0; + int rd, rs1; + int32_t imm = 0; + uint16_t data; + + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); + + mem_addr = imm + regs->getValue(rs1); + data = mem_intf->readDataMem(mem_addr, 2); + regs->setValue(rd, data); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "LHU: x" << std::dec << rs1 << " + " << imm + << " (@0x" << std::hex << mem_addr << std::dec << ") -> x" << rd + << "(0x" << std::hex << data << ")" << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_SB() { + uint32_t mem_addr = 0; + int rs1, rs2; + int32_t imm = 0; + 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); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "SB: x" << std::dec << rs2 << " -> x" << rs1 + << " + 0x" << std::hex << imm << " (@0x" << std::hex << mem_addr + << std::dec << ")" << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_SH() { + uint32_t mem_addr = 0; + int rs1, rs2; + int32_t imm = 0; + 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); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "SH: x" << std::dec << rs2 << " -> x" << rs1 + << " + 0x" << std::hex << imm << " (@0x" << std::hex << mem_addr + << std::dec << ")" << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_SW() { + uint32_t mem_addr = 0; + int rs1, rs2; + int32_t imm = 0; + 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); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "SW: x" << std::dec << rs2 << "(0x" << std::hex + << data << ") -> x" << std::dec << rs1 << " + 0x" << std::hex << imm + << " (@0x" << std::hex << mem_addr << std::dec << ")" << std::endl; + } + return true; +} + +bool BASE_ISA::Exec_ADDI() { + int rd, rs1; + int32_t imm = 0; + int32_t calc; + + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); + + calc = regs->getValue(rs1) + imm; + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "ADDI: x" << std::dec << rs1 << " + " << imm + << " -> x" << std::dec << rd << "(0x" << std::hex << calc << ")" + << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_SLTI() { + int rd, rs1; + int32_t imm; + + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); + + if (regs->getValue(rs1) < imm) { + regs->setValue(rd, 1); + log->SC_log(Log::INFO) << "SLTI: x" << rs1 << " < " << imm << " => " + << "1 -> x" << rd << std::endl; + } else { + regs->setValue(rd, 0); + log->SC_log(Log::INFO) << "SLTI: x" << rs1 << " < " << imm << " => " + << "0 -> x" << rd << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_SLTIU() { + int rd, rs1; + int32_t imm; + + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); + + if ((uint32_t) regs->getValue(rs1) < (uint32_t) imm) { + regs->setValue(rd, 1); + log->SC_log(Log::INFO) << "SLTIU: x" << rs1 << " < " << imm << " => " + << "1 -> x" << rd << std::endl; + } else { + regs->setValue(rd, 0); + log->SC_log(Log::INFO) << "SLTIU: x" << rs1 << " < " << imm << " => " + << "0 -> x" << rd << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_XORI() { + int rd, rs1; + int32_t imm; + uint32_t calc; + + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); + + calc = regs->getValue(rs1) ^ imm; + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "XORI: x" << rs1 << " XOR " << imm << "-> x" << rd + << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_ORI() { + int rd, rs1; + int32_t imm; + uint32_t calc; + + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); + + calc = regs->getValue(rs1) | imm; + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "ORI: x" << rs1 << " OR " << imm << "-> x" << rd + << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_ANDI() { + int rd, rs1; + uint32_t imm; + uint32_t calc; + uint32_t aux; + + rd = get_rd(); + rs1 = get_rs1(); + imm = get_imm_I(); + + aux = regs->getValue(rs1); + calc = aux & imm; + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "ANDI: x" << rs1 << "(0x" << std::hex << aux + << ") AND 0x" << imm << " -> x" << std::dec << rd << "(0x" + << std::hex << calc << ")" << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_SLLI() { + int rd, rs1, rs2; + uint32_t shift; + uint32_t calc; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_shamt(); + + if (rs2 >= 0x20) { + std::cout << "ILEGAL INSTRUCTION, shamt[5] != 0" << std::endl; + RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr); + + return false; + } + + shift = rs2 & 0x1F; + + calc = ((uint32_t) regs->getValue(rs1)) << shift; + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "SLLI: x" << std::dec << rs1 << " << " << shift + << " -> x" << rd << "(0x" << std::hex << calc << ")" << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_SRLI() { + int rd, rs1, rs2; + uint32_t shift; + uint32_t calc; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + shift = rs2 & 0x1F; + + calc = ((uint32_t) regs->getValue(rs1)) >> shift; + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "SRLI: x" << std::dec << rs1 << " >> " << shift + << " -> x" << rd << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_SRAI() { + int rd, rs1, rs2; + uint32_t shift; + int32_t calc; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + shift = rs2 & 0x1F; + + calc = regs->getValue(rs1) >> shift; + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "SRAI: x" << std::dec << rs1 << " >> " << shift + << " -> x" << rd << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_ADD() { + int rd, rs1, rs2; + uint32_t calc; + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + calc = regs->getValue(rs1) + regs->getValue(rs2); + + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "ADD: x" << std::dec << rs1 << " + x" << rs2 + << " -> x" << rd << std::hex << "(0x" << calc << ")" << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_SUB() { + int rd, rs1, rs2; + uint32_t calc; + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + calc = regs->getValue(rs1) - regs->getValue(rs2); + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "SUB: x" << rs1 << " - x" << rs2 << " -> x" << rd + << "(" << calc << ")" << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_SLL() { + int rd, rs1, rs2; + uint32_t shift; + uint32_t calc; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + shift = regs->getValue(rs2) & 0x1F; + + calc = ((uint32_t) regs->getValue(rs1)) << shift; + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "SLL: x" << rs1 << " << " << shift << " -> x" + << rd << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_SLT() { + int rd, rs1, rs2; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + if (regs->getValue(rs1) < regs->getValue(rs2)) { + regs->setValue(rd, 1); + log->SC_log(Log::INFO) << "SLT: x" << rs1 << " < x" << rs2 << " => " + << "1 -> x" << rd << std::endl; + } else { + regs->setValue(rd, 0); + log->SC_log(Log::INFO) << "SLT: x" << rs1 << " < x" << rs2 << " => " + << "0 -> x" << rd << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_SLTU() { + int rd, rs1, rs2; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + if ((uint32_t) regs->getValue(rs1) < (uint32_t) regs->getValue(rs2)) { + regs->setValue(rd, 1); + log->SC_log(Log::INFO) << "SLTU: x" << rs1 << " < x" << rs2 << " => " + << "1 -> x" << rd << std::endl; + } else { + regs->setValue(rd, 0); + log->SC_log(Log::INFO) << "SLTU: x" << rs1 << " < x" << rs2 << " => " + << "0 -> x" << rd << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_XOR() { + int rd, rs1, rs2; + uint32_t calc; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + calc = regs->getValue(rs1) ^ regs->getValue(rs2); + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "XOR: x" << rs1 << " XOR x" << rs2 << "-> x" << rd + << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_SRL() { + int rd, rs1, rs2; + uint32_t shift; + uint32_t calc; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + shift = regs->getValue(rs2) & 0x1F; + + calc = ((uint32_t) regs->getValue(rs1)) >> shift; + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "SRL: x" << rs1 << " >> " << shift << " -> x" + << rd << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_SRA() { + int rd, rs1, rs2; + uint32_t shift; + int32_t calc; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + shift = regs->getValue(rs2) & 0x1F; + + calc = regs->getValue(rs1) >> shift; + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "SRA: x" << rs1 << " >> " << shift << " -> x" + << rd << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_OR() { + int rd, rs1, rs2; + uint32_t calc; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + calc = regs->getValue(rs1) | regs->getValue(rs2); + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "OR: x" << rs1 << " OR x" << rs2 << "-> x" << rd + << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_AND() { + int rd, rs1, rs2; + uint32_t calc; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + calc = regs->getValue(rs1) & regs->getValue(rs2); + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "AND: x" << rs1 << " AND x" << rs2 << "-> x" << rd + << std::endl; + } + + return true; +} + +bool BASE_ISA::Exec_FENCE() { + log->SC_log(Log::INFO) << "FENCE" << std::endl; + + return true; +} + +bool BASE_ISA::Exec_ECALL() { + + log->SC_log(Log::INFO) << "ECALL" << std::endl; + std::cout << std::endl << "ECALL Instruction called, stopping simulation" + << std::endl; + regs->dump(); + std::cout << "Simulation time " << sc_core::sc_time_stamp() << std::endl; + perf->dump(); + + uint32_t gp_value = regs->getValue(Registers::gp); + if (gp_value == 1) { + std::cout << "GP value is 1, test result is OK" << std::endl; + } else { + std::cout << "GP value is " << gp_value << std::endl; + } + //SC_REPORT_ERROR("Execute", "ECALL"); + sc_core::sc_stop(); + return true; +} + +bool BASE_ISA::Exec_EBREAK() { + + log->SC_log(Log::INFO) << "EBREAK" << std::endl; + std::cout << std::endl << "EBRAK Instruction called, dumping information" + << std::endl; + regs->dump(); + std::cout << "Simulation time " << sc_core::sc_time_stamp() << std::endl; + perf->dump(); + + RaiseException(EXCEPTION_CAUSE_BREAKPOINT, m_instr); + + return true; +} + +bool BASE_ISA::Exec_CSRRW() { + int rd, rs1; + int csr; + uint32_t aux; + + rd = get_rd(); + rs1 = get_rs1(); + csr = get_csr(); + + /* These operations must be atomical */ + if (rd != 0) { + aux = regs->getCSR(csr); + regs->setValue(rd, aux); + } + + aux = regs->getValue(rs1); + regs->setCSR(csr, aux); + + log->SC_log(Log::INFO) << std::hex << "CSRRW: CSR #" << csr << " -> x" + << std::dec << rd << ". x" << rs1 << "-> CSR #" << std::hex << csr + << " (0x" << aux << ")" << std::endl; + + return true; +} + +bool BASE_ISA::Exec_CSRRS() { + int rd, rs1; + int csr; + uint32_t bitmask, aux, aux2; + + rd = get_rd(); + rs1 = get_rs1(); + csr = get_csr(); + + if (rd == 0) { + log->SC_log(Log::INFO) << "CSRRS with rd1 == 0, doing nothing." + << std::endl; + return false; + } + + /* These operations must be atomical */ + aux = regs->getCSR(csr); + bitmask = regs->getValue(rs1); + + regs->setValue(rd, aux); + + aux2 = aux | bitmask; + regs->setCSR(csr, aux2); + + log->SC_log(Log::INFO) << "CSRRS: CSR #" << csr << "(0x" << std::hex << aux + << ") -> x" << std::dec << rd << ". x" << rs1 << " & CSR #" << csr + << " <- 0x" << std::hex << aux2 << std::endl; + + return true; +} + +bool BASE_ISA::Exec_CSRRC() { + int rd, rs1; + int csr; + uint32_t bitmask, aux, aux2; + + rd = get_rd(); + rs1 = get_rs1(); + csr = get_csr(); + + if (rd == 0) { + log->SC_log(Log::INFO) << "CSRRC with rd1 == 0, doing nothing." + << std::endl; + return true; + } + + /* These operations must be atomical */ + aux = regs->getCSR(csr); + bitmask = regs->getValue(rs1); + + regs->setValue(rd, aux); + + aux2 = aux & ~bitmask; + regs->setCSR(csr, aux2); + + log->SC_log(Log::INFO) << "CSRRC: CSR #" << csr << "(0x" << std::hex << aux + << ") -> x" << std::dec << rd << ". x" << rs1 << " & CSR #" << csr + << " <- 0x" << std::hex << aux2 << std::endl; + + return true; +} + +bool BASE_ISA::Exec_CSRRWI() { + int rd, rs1; + int csr; + uint32_t aux; + + rd = get_rd(); + rs1 = get_rs1(); + csr = get_csr(); + + /* These operations must be atomical */ + if (rd != 0) { + aux = regs->getCSR(csr); + regs->setValue(rd, aux); + } + aux = rs1; + regs->setCSR(csr, aux); + + log->SC_log(Log::INFO) << "CSRRWI: CSR #" << csr << " -> x" << rd << ". x" + << rs1 << "-> CSR #" << csr << std::endl; + + return true; +} + +bool BASE_ISA::Exec_CSRRSI() { + int rd, rs1; + int csr; + uint32_t bitmask, aux; + + rd = get_rd(); + rs1 = get_rs1(); + csr = get_csr(); + + if (rs1 == 0) { + return true; + } + + /* These operations must be atomical */ + aux = regs->getCSR(csr); + regs->setValue(rd, aux); + + bitmask = rs1; + aux = aux | bitmask; + regs->setCSR(csr, aux); + + log->SC_log(Log::INFO) << "CSRRSI: CSR #" << csr << " -> x" << rd << ". x" + << rs1 << " & CSR #" << csr << "(0x" << std::hex << aux << ")" + << std::endl; + + return true; +} + +bool BASE_ISA::Exec_CSRRCI() { + int rd, rs1; + int csr; + uint32_t bitmask, aux; + + rd = get_rd(); + rs1 = get_rs1(); + csr = get_csr(); + + if (rs1 == 0) { + return true; + } + + /* These operations must be atomical */ + aux = regs->getCSR(csr); + regs->setValue(rd, aux); + + bitmask = rs1; + aux = aux & ~bitmask; + regs->setCSR(csr, aux); + + log->SC_log(Log::INFO) << "CSRRCI: CSR #" << csr << " -> x" << rd << ". x" + << rs1 << " & CSR #" << csr << "(0x" << std::hex << aux << ")" + << std::endl; + + return true; +} + +/*********************** Privileged Instructions ******************************/ + +bool BASE_ISA::Exec_MRET() { + uint32_t new_pc = 0; + + new_pc = regs->getCSR(CSR_MEPC); + regs->setPC(new_pc); + + log->SC_log(Log::INFO) << "MRET: PC <- 0x" << std::hex << new_pc + << std::endl; + + // update mstatus + 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; +} + +bool BASE_ISA::Exec_SRET() { + uint32_t new_pc = 0; + + new_pc = regs->getCSR(CSR_SEPC); + regs->setPC(new_pc); + + log->SC_log(Log::INFO) << "SRET: PC <- 0x" << std::hex << new_pc + << std::endl; + + return true; +} + +bool BASE_ISA::Exec_WFI() { + log->SC_log(Log::INFO) << "WFI" << std::endl; + + return true; +} + +bool BASE_ISA::Exec_SFENCE() { + log->SC_log(Log::INFO) << "SFENCE" << std::endl; + + return true; +} + +bool BASE_ISA::process_instruction(Instruction &inst) { + bool PC_not_affected = true; + + 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(); + break; + case OP_EBREAK: + Exec_EBREAK(); + 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; + default: + std::cout << "Wrong instruction" << std::endl; + inst.dump(); + NOP(); + //sc_stop(); + break; + } + + 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; + } + ; + 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; + } + case OR_F: + return OP_OR; + case AND_F: + return OP_AND; + } + } /* 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; +} diff --git a/src/BusCtrl.cpp b/src/BusCtrl.cpp index de6d7ef..cc5c6ef 100644 --- a/src/BusCtrl.cpp +++ b/src/BusCtrl.cpp @@ -1,38 +1,46 @@ +/** + @file BusCtrl.cpp + @brief Basic TLM-2 Bus controller + @author Màrius Montón + @date September 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + #include "BusCtrl.h" SC_HAS_PROCESS(BusCtrl); -BusCtrl::BusCtrl(sc_module_name 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); - log = Log::getInstance(); - 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); - } +BusCtrl::BusCtrl(sc_core::sc_module_name 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); + log = Log::getInstance(); + 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); +} +void BusCtrl::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() / 4; -void BusCtrl::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) { - //tlm::tlm_command cmd = trans.get_command(); - sc_dt::uint64 adr = trans.get_address() / 4; - - 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; - default: - memory_socket->b_transport(trans, delay); - break; - } + 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; + default: + memory_socket->b_transport(trans, delay); + break; + } #if 0 if (cmd == tlm::TLM_READ_COMMAND) { @@ -42,14 +50,16 @@ void BusCtrl::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) { } #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) { +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) { +void BusCtrl::invalidate_direct_mem_ptr(sc_dt::uint64 start, + sc_dt::uint64 end) { cpu_instr_socket->invalidate_direct_mem_ptr(start, end); } diff --git a/src/CPU.cpp b/src/CPU.cpp index a5f8c32..7587ca4 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -1,10 +1,20 @@ +/*! + \file CPU.cpp + \brief Main CPU class + \author Màrius Montón + \date August 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + #include "CPU.h" SC_HAS_PROCESS(CPU); -CPU::CPU(sc_module_name name, uint32_t PC) : - sc_module(name), instr_bus("instr_bus"), default_time(10, SC_NS) { +CPU::CPU(sc_core::sc_module_name name, uint32_t PC) : + sc_module(name), instr_bus("instr_bus"), default_time(10, + sc_core::SC_NS) { register_bank = new Registers(); - exec = new Execute("Execute", register_bank); + mem_intf = new MemoryInterface(); + perf = Performance::getInstance(); log = Log::getInstance(); @@ -23,10 +33,11 @@ CPU::CPU(sc_module_name name, uint32_t PC) : instr_bus.register_invalidate_direct_mem_ptr(this, &CPU::invalidate_direct_mem_ptr); - inst = new Instruction(0); - c_inst = new C_Instruction(0); - m_inst = new M_Instruction(0); - a_inst = new A_Instruction(0); + inst = new Instruction(0); + 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); m_qk = new tlm_utils::tlm_quantumkeeper(); @@ -34,11 +45,19 @@ CPU::CPU(sc_module_name name, uint32_t PC) : } CPU::~CPU() { - cout << "*********************************************" << endl; + std::cout << "*********************************************" << std::endl; register_bank->dump(); - cout << "end time: " << sc_time_stamp() << endl; + std::cout << "end time: " << sc_core::sc_time_stamp() << std::endl; perf->dump(); - cout << "*********************************************" << endl; + std::cout << "*********************************************" << std::endl; + delete register_bank; + delete mem_intf; + delete inst; + delete exec; + delete c_inst; + delete m_inst; + delete a_inst; + delete m_qk; } bool CPU::cpu_process_IRQ() { @@ -49,7 +68,7 @@ bool CPU::cpu_process_IRQ() { if (interrupt == true) { csr_temp = register_bank->getCSR(CSR_MSTATUS); if ((csr_temp & MSTATUS_MIE) == 0) { - log->SC_log(Log::DEBUG) << "interrupt delayed" << endl; + log->SC_log(Log::DEBUG) << "interrupt delayed" << std::endl; return ret_value; } @@ -58,13 +77,13 @@ bool CPU::cpu_process_IRQ() { if ((csr_temp & MIP_MEIP) == 0) { csr_temp |= MIP_MEIP; // MEIP bit in MIP register (11th bit) register_bank->setCSR(CSR_MIP, csr_temp); - log->SC_log(Log::DEBUG) << "Interrupt!" << endl; + log->SC_log(Log::DEBUG) << "Interrupt!" << std::endl; /* updated MEPC register */ old_pc = register_bank->getPC(); register_bank->setCSR(CSR_MEPC, old_pc); - log->SC_log(Log::INFO) << "Old PC Value 0x" << hex << old_pc - << endl; + log->SC_log(Log::INFO) << "Old PC Value 0x" << std::hex << old_pc + << std::endl; /* update MCAUSE register */ register_bank->setCSR(CSR_MCAUSE, 0x80000000); @@ -72,8 +91,8 @@ bool CPU::cpu_process_IRQ() { /* set new PC address */ new_pc = register_bank->getCSR(CSR_MTVEC); //new_pc = new_pc & 0xFFFFFFFC; // last two bits always to 0 - log->SC_log(Log::DEBUG) << "NEW PC Value 0x" << hex << new_pc - << endl; + log->SC_log(Log::DEBUG) << "NEW PC Value 0x" << std::hex << new_pc + << std::endl; register_bank->setPC(new_pc); ret_value = true; @@ -92,376 +111,11 @@ bool CPU::cpu_process_IRQ() { return ret_value; } -bool CPU::process_c_instruction(Instruction &inst) { - bool PC_not_affected = true; - - c_inst->setInstr(inst.getInstr()); - - switch (c_inst->decode()) { - case OP_C_ADDI4SPN: - PC_not_affected = exec->C_ADDI4SPN(inst); - break; - case OP_C_LW: - exec->LW(inst, true); - break; - case OP_C_SW: - exec->SW(inst, true); - break; - case OP_C_ADDI: - exec->ADDI(inst, true); - break; - case OP_C_JAL: - exec->JAL(inst, true, 1); - PC_not_affected = false; - break; - case OP_C_J: - exec->JAL(inst, true, 0); - PC_not_affected = false; - break; - case OP_C_LI: - exec->C_LI(inst); - break; - case OP_C_SLLI: - exec->C_SLLI(inst); - break; - case OP_C_LWSP: - exec->C_LWSP(inst); - break; - case OP_C_JR: - exec->C_JR(inst); - PC_not_affected = false; - break; - case OP_C_MV: - exec->C_MV(inst); - break; - case OP_C_JALR: - exec->JALR(inst, true); - PC_not_affected = false; - break; - case OP_C_ADD: - exec->C_ADD(inst); - break; - case OP_C_SWSP: - exec->C_SWSP(inst); - break; - case OP_C_ADDI16SP: - exec->C_ADDI16SP(inst); - break; - case OP_C_BEQZ: - exec->C_BEQZ(inst); - PC_not_affected = false; - break; - case OP_C_BNEZ: - exec->C_BNEZ(inst); - PC_not_affected = false; - break; - case OP_C_SRLI: - exec->C_SRLI(inst); - break; - case OP_C_SRAI: - exec->C_SRAI(inst); - break; - case OP_C_ANDI: - exec->C_ANDI(inst); - break; - case OP_C_SUB: - exec->C_SUB(inst); - break; - case OP_C_XOR: - exec->C_XOR(inst); - break; - case OP_C_OR: - exec->C_OR(inst); - break; - case OP_C_AND: - exec->C_AND(inst); - break; - default: - std::cout << "C instruction not implemented yet" << endl; - inst.dump(); - exec->NOP(inst); - //sc_stop(); - break; - - } - - return PC_not_affected; -} - -bool CPU::process_m_instruction(Instruction &inst) { - bool PC_not_affected = true; - - m_inst->setInstr(inst.getInstr()); - - switch (m_inst->decode()) { - case OP_M_MUL: - exec->M_MUL(inst); - break; - case OP_M_MULH: - exec->M_MULH(inst); - break; - case OP_M_MULHSU: - exec->M_MULHSU(inst); - break; - case OP_M_MULHU: - exec->M_MULHU(inst); - break; - case OP_M_DIV: - exec->M_DIV(inst); - break; - case OP_M_DIVU: - exec->M_DIVU(inst); - break; - case OP_M_REM: - exec->M_REM(inst); - break; - case OP_M_REMU: - exec->M_REMU(inst); - break; - default: - std::cout << "M instruction not implemented yet" << endl; - inst.dump(); - exec->NOP(inst); - break; - } - - return PC_not_affected; -} - -bool CPU::process_a_instruction(Instruction inst) { - bool PC_not_affected = true; - - a_inst->setInstr(inst.getInstr()); - - switch (a_inst->decode()) { - case OP_A_LR: - exec->A_LR(inst); - break; - case OP_A_SC: - exec->A_SC(inst); - break; - case OP_A_AMOSWAP: - exec->A_AMOSWAP(inst); - break; - case OP_A_AMOADD: - exec->A_AMOADD(inst); - break; - case OP_A_AMOXOR: - exec->A_AMOXOR(inst); - break; - case OP_A_AMOAND: - exec->A_AMOAND(inst); - break; - case OP_A_AMOOR: - exec->A_AMOOR(inst); - break; - case OP_A_AMOMIN: - exec->A_AMOMIN(inst); - break; - case OP_A_AMOMAX: - exec->A_AMOMAX(inst); - break; - case OP_A_AMOMINU: - exec->A_AMOMINU(inst); - break; - case OP_A_AMOMAXU: - exec->A_AMOMAXU(inst); - break; - default: - std::cout << "A instruction not implemented yet" << endl; - inst.dump(); - exec->NOP(inst); - break; - } - - return PC_not_affected; -} - -bool CPU::process_base_instruction(Instruction &inst) { - bool PC_not_affected = true; - - switch (inst.decode()) { - case OP_LUI: - exec->LUI(inst); - break; - case OP_AUIPC: - exec->AUIPC(inst); - break; - case OP_JAL: - exec->JAL(inst); - PC_not_affected = false; - break; - case OP_JALR: - exec->JALR(inst); - PC_not_affected = false; - break; - case OP_BEQ: - exec->BEQ(inst); - PC_not_affected = false; - break; - case OP_BNE: - exec->BNE(inst); - PC_not_affected = false; - break; - case OP_BLT: - exec->BLT(inst); - PC_not_affected = false; - break; - case OP_BGE: - exec->BGE(inst); - PC_not_affected = false; - break; - case OP_BLTU: - exec->BLTU(inst); - PC_not_affected = false; - break; - case OP_BGEU: - exec->BGEU(inst); - PC_not_affected = false; - break; - case OP_LB: - exec->LB(inst); - break; - case OP_LH: - exec->LH(inst); - break; - case OP_LW: - exec->LW(inst); - break; - case OP_LBU: - exec->LBU(inst); - break; - case OP_LHU: - exec->LHU(inst); - break; - case OP_SB: - exec->SB(inst); - break; - case OP_SH: - exec->SH(inst); - break; - case OP_SW: - exec->SW(inst); - break; - case OP_ADDI: - exec->ADDI(inst); - break; - case OP_SLTI: - exec->SLTI(inst); - break; - case OP_SLTIU: - exec->SLTIU(inst); - break; - case OP_XORI: - exec->XORI(inst); - break; - case OP_ORI: - exec->ORI(inst); - break; - case OP_ANDI: - exec->ANDI(inst); - break; - case OP_SLLI: - PC_not_affected = exec->SLLI(inst); - break; - case OP_SRLI: - exec->SRLI(inst); - break; - case OP_SRAI: - exec->SRAI(inst); - break; - case OP_ADD: - exec->ADD(inst); - break; - case OP_SUB: - exec->SUB(inst); - break; - case OP_SLL: - exec->SLL(inst); - break; - case OP_SLT: - exec->SLT(inst); - break; - case OP_SLTU: - exec->SLTU(inst); - break; - case OP_XOR: - exec->XOR(inst); - break; - case OP_SRL: - exec->SRL(inst); - break; - case OP_SRA: - exec->SRA(inst); - break; - case OP_OR: - exec->OR(inst); - break; - case OP_AND: - exec->AND(inst); - break; - case OP_FENCE: - exec->FENCE(inst); - break; - case OP_ECALL: - exec->ECALL(inst); - break; - case OP_EBREAK: - exec->EBREAK(inst); - break; - case OP_CSRRW: - exec->CSRRW(inst); - break; - case OP_CSRRS: - exec->CSRRS(inst); - break; - case OP_CSRRC: - exec->CSRRC(inst); - break; - case OP_CSRRWI: - exec->CSRRWI(inst); - break; - case OP_CSRRSI: - exec->CSRRSI(inst); - break; - case OP_CSRRCI: - exec->CSRRCI(inst); - break; - - case OP_MRET: - exec->MRET(inst); - PC_not_affected = false; - break; - case OP_SRET: - exec->SRET(inst); - PC_not_affected = false; - break; - case OP_WFI: - exec->WFI(inst); - break; - case OP_SFENCE: - exec->SFENCE(inst); - break; - default: - std::cout << "Wrong instruction" << endl; - inst.dump(); - exec->NOP(inst); - //sc_stop(); - break; - } - - return PC_not_affected; -} - -/** - * main thread for CPU simulation - * @brief CPU mai thread - */ void CPU::CPU_thread(void) { tlm::tlm_generic_payload *trans = new tlm::tlm_generic_payload; uint32_t INSTR; - sc_time delay = SC_ZERO_TIME; + sc_core::sc_time delay = sc_core::SC_ZERO_TIME; bool PC_not_affected = false; bool incPCby2 = false; tlm::tlm_dmi dmi_data; @@ -475,7 +129,6 @@ void CPU::CPU_thread(void) { trans->set_dmi_allowed(false); // Mandatory initial value trans->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); - //Instruction inst(0); m_qk->reset(); while (1) { @@ -502,7 +155,7 @@ void CPU::CPU_thread(void) { perf->codeMemoryRead(); - log->SC_log(Log::INFO) << "PC: 0x" << hex << register_bank->getPC() + log->SC_log(Log::INFO) << "PC: 0x" << std::hex << register_bank->getPC() << ". "; inst->setInstr(INSTR); @@ -510,26 +163,26 @@ void CPU::CPU_thread(void) { /* check what type of instruction is and execute it */ switch (inst->check_extension()) { case BASE_EXTENSION: - PC_not_affected = process_base_instruction(*inst); + PC_not_affected = exec->process_instruction(*inst); incPCby2 = false; break; case C_EXTENSION: - PC_not_affected = process_c_instruction(*inst); + PC_not_affected = c_inst->process_instruction(*inst); incPCby2 = true; break; case M_EXTENSION: - PC_not_affected = process_m_instruction(*inst); + PC_not_affected = m_inst->process_instruction(*inst); incPCby2 = false; break; case A_EXTENSION: - PC_not_affected = process_a_instruction(*inst); + PC_not_affected = a_inst->process_instruction(*inst); incPCby2 = false; break; default: std::cout << "Extension not implemented yet" << std::endl; inst->dump(); - exec->NOP(*inst); - } // switch (inst.check_extension()) + exec->NOP(); + } perf->instructionsInc(); @@ -549,14 +202,15 @@ void CPU::CPU_thread(void) { m_qk->sync(); } #else - sc_core::wait(10, SC_NS); + sc_core::wait(10, sc_core::SC_NS); #endif } // while(1) } // CPU_thread -void CPU::call_interrupt(tlm::tlm_generic_payload &trans, sc_time &delay) { +void CPU::call_interrupt(tlm::tlm_generic_payload &trans, + sc_core::sc_time &delay) { interrupt = true; /* Socket caller send a cause (its id) */ memcpy(&int_cause, trans.get_data_ptr(), sizeof(uint32_t)); diff --git a/src/C_Instruction.cpp b/src/C_Instruction.cpp deleted file mode 100644 index ac5bbec..0000000 --- a/src/C_Instruction.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include "C_Instruction.h" - - -C_Instruction::C_Instruction(sc_uint<32> instr) { - m_instr = instr; -} - -op_C_Codes C_Instruction::decode() { - - 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; - 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; - 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: - default: - return OP_C_ERROR; - break; - } - break; - - default: - return OP_C_ERROR; - break; - - } - - return OP_C_ERROR; -} diff --git a/src/C_extension.cpp b/src/C_extension.cpp new file mode 100644 index 0000000..c211610 --- /dev/null +++ b/src/C_extension.cpp @@ -0,0 +1,756 @@ +/*! + \file C_extension.cpp + \brief Implement C extensions part of the RISC-V + \author Màrius Montón + \date August 2018 +*/ +#include "C_extension.h" + +op_C_Codes C_extension::decode() { + + 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; + 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; + 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: + default: + return OP_C_ERROR; + break; + } + break; + + default: + return OP_C_ERROR; + break; + + } + + return OP_C_ERROR; +} + +bool C_extension::Exec_C_JR() { + uint32_t mem_addr = 0; + int rs1; + int new_pc; + + rs1 = get_rs1(); + mem_addr = 0; + + new_pc = (regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE; + regs->setPC(new_pc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "JR: PC <- 0x" << std::hex << new_pc << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_MV() { + int rd, rs1, rs2; + uint32_t calc; + + rd = get_rd(); + rs1 = 0; + rs2 = get_rs2(); + + calc = regs->getValue(rs1) + regs->getValue(rs2); + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "C.MV: x" << std::dec << rs1 << "(0x" << std::hex + << regs->getValue(rs1) << ") + x" << std::dec << rs2 << "(0x" + << std::hex << regs->getValue(rs2) << ") -> x" << std::dec << rd + << "(0x" << std::hex << calc << ")" << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_ADD() { + int rd, rs1, rs2; + uint32_t calc; + + rd = get_rs1(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + calc = regs->getValue(rs1) + regs->getValue(rs2); + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "C.ADD: x" << std::dec << rs1 << " + x" << rs2 + << " -> x" << rd << "(0x" << std::hex << calc << ")" << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_LWSP() { + uint32_t mem_addr = 0; + int rd, rs1; + int32_t imm = 0; + 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); + + regs->setValue(rd, data); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "C.LWSP: x" << std::dec << rs1 << " + " << imm + << " (@0x" << std::hex << mem_addr << std::dec << ") -> x" << rd + << "(" << std::hex << data << ")" << std::dec << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_ADDI4SPN() { + int rd, rs1; + int32_t imm = 0; + int32_t calc; + + rd = get_rdp(); + rs1 = 2; + imm = get_imm_ADDI4SPN(); + + if (imm == 0) { + RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr); + return false; + } + + calc = regs->getValue(rs1) + imm; + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << std::dec << "C.ADDI4SPN: x" << rs1 << "(0x" + << std::hex << regs->getValue(rs1) << ") + " << std::dec << imm + << " -> x" << rd << "(0x" << std::hex << calc << ")" << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_ADDI16SP() { + // addi x2, x2, nzimm[9:4] + int rd, rs1; + int32_t imm = 0; + int32_t calc; + + if (get_rd() == 2) { + rd = 2; + rs1 = 2; + imm = get_imm_ADDI16SP(); + + calc = regs->getValue(rs1) + imm; + regs->setValue(rd, calc); + + log->SC_log(Log::INFO) << std::dec << "C.ADDI16SP: x" << rs1 << " + " + << std::dec << imm << " -> x" << rd << "(0x" << std::hex << calc + << ")" << std::endl; + } else { + /* C.LUI OPCODE */ + rd = get_rd(); + imm = get_imm_LUI(); + regs->setValue(rd, imm); + log->SC_log(Log::INFO) << std::dec << "C.LUI x" << rd << " <- 0x" + << std::hex << imm << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_SWSP() { + // sw rs2, offset(x2) + uint32_t mem_addr = 0; + int rs1, rs2; + int32_t imm = 0; + uint32_t data; + + rs1 = 2; + rs2 = get_rs2(); + imm = get_imm_CSS(); + + mem_addr = imm + regs->getValue(rs1); + data = regs->getValue(rs2); + + mem_intf->writeDataMem(mem_addr, data, 4); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << std::dec << "C.SWSP: x" << rs2 << "(0x" + << std::hex << data << ") -> x" << std::dec << rs1 << " + " << imm + << " (@0x" << std::hex << mem_addr << std::dec << ")" << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_BEQZ() { + int rs1; + int new_pc = 0; + uint32_t val1; + + rs1 = get_rs1p(); + val1 = regs->getValue(rs1); + + if (val1 == 0) { + new_pc = regs->getPC() + get_imm_CB(); + regs->setPC(new_pc); + } else { + regs->incPC(true); //PC <- PC + 2 + new_pc = regs->getPC(); + } + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "C.BEQZ: x" << std::dec << rs1 << "(" << val1 + << ") == 0? -> PC (0x" << std::hex << new_pc << ")" << std::dec + << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_BNEZ() { + int rs1; + int new_pc = 0; + uint32_t val1; + + rs1 = get_rs1p(); + val1 = regs->getValue(rs1); + + if (val1 != 0) { + new_pc = regs->getPC() + get_imm_CB(); + regs->setPC(new_pc); + } else { + regs->incPC(true); //PC <- PC +2 + new_pc = regs->getPC(); + } + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "C.BNEZ: x" << std::dec << rs1 << "(0x" + << std::hex << val1 << ") != 0? -> PC (0x" << std::hex << new_pc + << ")" << std::dec << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_LI() { + int rd, rs1; + int32_t imm = 0; + int32_t calc; + + rd = get_rd(); + rs1 = 0; + imm = get_imm_ADDI(); + + calc = regs->getValue(rs1) + imm; + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << std::dec << "C.LI: x" << rs1 << "(" + << regs->getValue(rs1) << ") + " << imm << " -> x" << rd << "(" + << calc << ")" << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_SRLI() { + int rd, rs1, rs2; + uint32_t shift; + uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2(); + + shift = rs2 & 0x1F; + + calc = ((uint32_t) regs->getValue(rs1)) >> shift; + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "C.SRLI: x" << rs1 << " >> " << shift << " -> x" + << rd << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_SRAI() { + int rd, rs1, rs2; + uint32_t shift; + int32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2(); + + shift = rs2 & 0x1F; + + calc = (int32_t) regs->getValue(rs1) >> shift; + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "C.SRAI: x" << rs1 << " >> " << std::dec << shift + << " -> x" << rd << "(" << calc << ")" << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_SLLI() { + int rd, rs1, rs2; + uint32_t shift; + uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_imm_ADDI(); + + shift = rs2 & 0x1F; + + calc = ((uint32_t) regs->getValue(rs1)) << shift; + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "C.SLLI: x" << std::dec << rs1 << " << " << shift + << " -> x" << rd << "(0x" << calc << ")" << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_ANDI() { + int rd, rs1; + uint32_t imm; + uint32_t aux; + uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + imm = get_imm_ADDI(); + + aux = regs->getValue(rs1); + calc = aux & imm; + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "C.ANDI: x" << rs1 << "(" << aux << ") AND " + << imm << " -> x" << rd << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_SUB() { + int rd, rs1, rs2; + uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); + + calc = regs->getValue(rs1) - regs->getValue(rs2); + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "C.SUB: x" << std::dec << rs1 << " - x" << rs2 + << " -> x" << rd << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_XOR() { + int rd, rs1, rs2; + uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); + + calc = regs->getValue(rs1) ^ regs->getValue(rs2); + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "C.XOR: x" << std::dec << rs1 << " XOR x" << rs2 + << "-> x" << rd << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_OR() { + int rd, rs1, rs2; + uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); + + calc = regs->getValue(rs1) | regs->getValue(rs2); + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "C_OR: x" << std::dec << rs1 << " OR x" << rs2 + << "-> x" << rd << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_AND() { + int rd, rs1, rs2; + uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); + + calc = regs->getValue(rs1) & regs->getValue(rs2); + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "C.AND: x" << std::dec << rs1 << " AND x" << rs2 + << "-> x" << rd << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_ADDI() { + int rd, rs1; + int32_t imm = 0; + int32_t calc; + + rd = get_rd(); + rs1 = rd; + imm = get_imm_ADDI(); + + calc = regs->getValue(rs1) + imm; + regs->setValue(rd, calc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "C.ADDI: x" << std::dec << rs1 << " + " << imm + << " -> x" << std::dec << rd << "(0x" << std::hex << calc << ")" + << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_JALR() { + uint32_t mem_addr = 0; + int rd, rs1; + int new_pc, old_pc; + + rd = 1; + rs1 = get_rs1(); + + old_pc = regs->getPC(); + regs->setValue(rd, old_pc + 2); + + new_pc = (regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE; + regs->setPC(new_pc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "C.JALR: x" << std::dec << rd << " <- 0x" + << std::hex << old_pc + 4 << " PC <- 0x" << std::hex << new_pc + << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_LW() { + uint32_t mem_addr = 0; + int rd, rs1; + int32_t imm = 0; + 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); + regs->setValue(rd, data); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << std::dec << "C.LW: x" << rs1 << "(0x" << std::hex + << regs->getValue(rs1) << ") + " << std::dec << imm << " (@0x" + << std::hex << mem_addr << std::dec << ") -> x" << rd << std::hex + << " (0x" << data << ")" << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_SW() { + uint32_t mem_addr = 0; + int rs1, rs2; + int32_t imm = 0; + 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); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "C.SW: x" << std::dec << rs2 << "(0x" << std::hex + << data << ") -> x" << std::dec << rs1 << " + 0x" << std::hex << imm + << " (@0x" << std::hex << mem_addr << std::dec << ")" << std::endl; + } + + return true; +} + +bool C_extension::Exec_C_JAL(int m_rd) { + int32_t mem_addr = 0; + int rd; + int new_pc, old_pc; + + rd = m_rd; + mem_addr = get_imm_J(); + old_pc = regs->getPC(); + + new_pc = old_pc + mem_addr; + regs->setPC(new_pc); + + old_pc = old_pc + 2; + regs->setValue(rd, old_pc); + + if (log->getLogLevel() > Log::INFO) { + log->SC_log(Log::INFO) << "C.JAL: x" << std::dec << rd << " <- 0x" + << std::hex << old_pc << std::dec << ". PC + 0x" << std::hex + << mem_addr << " -> PC (0x" << new_pc << ")" << std::endl; + } + + return true; +} + +bool C_extension::process_instruction(Instruction &inst) { + bool PC_not_affected = true; + + 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; + default: + std::cout << "C instruction not implemented yet" << std::endl; + inst.dump(); + NOP(); + break; + } + + return PC_not_affected; +} diff --git a/src/Execute.cpp b/src/Execute.cpp deleted file mode 100644 index e097713..0000000 --- a/src/Execute.cpp +++ /dev/null @@ -1,2193 +0,0 @@ -#include "Execute.h" - -SC_HAS_PROCESS(Execute); -Execute::Execute(sc_module_name name - , Registers *register_bank) - : sc_module(name) - , data_bus("data_bus") - , regs(register_bank) { - perf = Performance::getInstance(); - log = Log::getInstance(); -} - -bool Execute::LUI(Instruction &inst) { - int rd; - uint32_t imm = 0; - - rd = inst.get_rd(); - imm = inst.get_imm_U() << 12; - regs->setValue(rd, imm); - log->SC_log(Log::INFO) << "LUI x" << dec - << rd << " <- 0x" << hex << imm << endl; - - return true; -} - -bool Execute::AUIPC(Instruction &inst) { - int rd; - uint32_t imm = 0; - int new_pc; - - rd = inst.get_rd(); - imm = inst.get_imm_U() << 12; - new_pc = regs->getPC() + imm; - - regs->setValue(rd, new_pc); - - log->SC_log(Log::INFO) << "AUIPC x" << dec - << rd << " <- 0x" << hex << imm << " + PC (0x" - << new_pc << ")" << endl; - - return true; -} - -bool Execute::JAL(Instruction &inst, bool c_extension, int m_rd) { - int32_t mem_addr = 0; - int rd; - int new_pc, old_pc; - - if (c_extension == false) { - rd = inst.get_rd(); - mem_addr = inst.get_imm_J(); - old_pc = regs->getPC(); - new_pc = old_pc + mem_addr; - - regs->setPC(new_pc); - - old_pc = old_pc + 4; - regs->setValue(rd, old_pc); - } else { - C_Instruction c_inst(inst.getInstr()); - - rd = m_rd; - mem_addr = c_inst.get_imm_J(); - old_pc = regs->getPC(); - - new_pc = old_pc + mem_addr; - regs->setPC(new_pc); - - old_pc = old_pc + 2; - regs->setValue(rd, old_pc); - } - - log->SC_log(Log::INFO) << "JAL: x" << dec - << rd << " <- 0x" << hex << old_pc << dec - << ". PC + 0x" << hex << mem_addr << " -> PC (0x" - << new_pc << ")" << endl; - - return true; -} - -bool Execute::JALR(Instruction &inst, bool c_extension) { - uint32_t mem_addr = 0; - int rd, rs1; - int new_pc, old_pc; - - if (c_extension == false) { - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - mem_addr = inst.get_imm_I(); - - old_pc = regs->getPC(); - regs->setValue(rd, old_pc + 4); - - new_pc = (regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE; - regs->setPC(new_pc); - - log->SC_log(Log::INFO) << "JALR: x" << dec - << rd << " <- 0x" << hex << old_pc + 4 - << " PC <- 0x" << new_pc << endl; - - } else { - C_Instruction c_inst(inst.getInstr()); - - rd = 1; - rs1 = c_inst.get_rs1(); - - old_pc = regs->getPC(); - regs->setValue(rd, old_pc + 2); - - new_pc = (regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE; - regs->setPC(new_pc); - - log->SC_log(Log::INFO) << "C.JALR: x" << dec - << rd << " <- 0x" << hex << old_pc + 4 - << " PC <- 0x" << hex << new_pc << endl; - } - - return true; -} - -bool Execute::BEQ(Instruction &inst) { - int rs1, rs2; - int new_pc = 0; - - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - if (regs->getValue(rs1) == regs->getValue(rs2)) { - new_pc = regs->getPC() + inst.get_imm_B(); - regs->setPC(new_pc); - } else { - regs->incPC(); - new_pc = regs->getPC(); - } - - log->SC_log(Log::INFO) << "BEQ x" << dec - << rs1 << "(0x" << hex << regs->getValue(rs1) << ") == x" << dec - << rs2 << "(0x" << hex << regs->getValue(rs2) << ")? -> PC (0x" - << hex << new_pc << ")" << dec << endl; - - return true; -} - -bool Execute::BNE(Instruction &inst) { - int rs1, rs2; - int new_pc = 0; - uint32_t val1, val2; - - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - val1 = regs->getValue(rs1); - val2 = regs->getValue(rs2); - - if (val1 != val2) { - new_pc = regs->getPC() + inst.get_imm_B(); - regs->setPC(new_pc); - } else { - regs->incPC(); - new_pc = regs->getPC(); - } - - log->SC_log(Log::INFO) << "BNE: x" << dec - << rs1 << "(0x" << hex << val1 << ") == x" << dec - << rs2 << "(0x" << hex << val2 << ")? -> PC (0x" - << hex << new_pc << ")" << dec << endl; - - return true; -} - -bool Execute::BLT(Instruction &inst) { - int rs1, rs2; - int new_pc = 0; - - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - if ((int32_t)regs->getValue(rs1) < (int32_t)regs->getValue(rs2)) { - new_pc = regs->getPC() + inst.get_imm_B(); - regs->setPC(new_pc); - } else { - regs->incPC(); - } - - log->SC_log(Log::INFO) << "BLT x" << dec - << rs1 << "(0x" << hex << (int32_t)regs->getValue(rs1) << ") < x" << dec - << rs2 << "(0x" << hex << (int32_t)regs->getValue(rs2) << ")? -> PC (0x" - << hex << new_pc << ")" << dec << endl; - - return true; -} - -bool Execute::BGE(Instruction &inst) { - int rs1, rs2; - int new_pc = 0; - - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - if ((int32_t)regs->getValue(rs1) >= (int32_t)regs->getValue(rs2)) { - new_pc = regs->getPC() + inst.get_imm_B(); - regs->setPC(new_pc); - } else { - regs->incPC(); - } - - log->SC_log(Log::INFO) << "BGE x" << dec - << rs1 << "(0x" << hex << (int32_t)regs->getValue(rs1) << ") > x" << dec - << rs2 << "(0x" << hex << (int32_t)regs->getValue(rs2) << ")? -> PC (0x" - << hex << new_pc << ")" << dec << endl; - - return true; -} - -bool Execute::BLTU(Instruction &inst) { - int rs1, rs2; - int new_pc = 0; - - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - if ((uint32_t) regs->getValue(rs1) < (uint32_t) regs->getValue(rs2)) { - new_pc = regs->getPC() + inst.get_imm_B(); - regs->setPC(new_pc); - } else { - regs->incPC(); - new_pc = regs->getPC(); - } - - log->SC_log(Log::INFO) << "BLTU x" << dec - << rs1 << "(0x" << hex << regs->getValue(rs1) << ") < x" << dec - << rs2 << "(0x" << hex << regs->getValue(rs2) << ")? -> PC (0x" - << hex << new_pc << ")" << dec << endl; - - return true; -} - -bool Execute::BGEU(Instruction &inst) { - int rs1, rs2; - int new_pc = 0; - - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - if ((uint32_t) regs->getValue(rs1) >= (uint32_t) regs->getValue(rs2)) { - new_pc = regs->getPC() + inst.get_imm_B(); - regs->setPC(new_pc); - } else { - regs->incPC(); - } - - log->SC_log(Log::INFO) << "BGEU x" << dec - << rs1 << "(0x" << hex << regs->getValue(rs1) << ") > x" << dec - << rs2 << "(0x" << hex << regs->getValue(rs2) << ")? -> PC (0x" - << hex << new_pc << ")" << dec << endl; - - return true; -} - -bool Execute::LB(Instruction &inst) { - uint32_t mem_addr = 0; - int rd, rs1; - int32_t imm = 0; - int8_t data; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - imm = inst.get_imm_I(); - - mem_addr = imm + regs->getValue(rs1); - data = readDataMem(mem_addr, 1); - regs->setValue(rd, data); - - log->SC_log(Log::INFO) << "LB: x" - << rs1 << " + " << imm << " (@0x" - << hex << mem_addr << dec << ") -> x" << rd << endl; - - return true; -} - -bool Execute::LH(Instruction &inst) { - uint32_t mem_addr = 0; - int rd, rs1; - int32_t imm = 0; - int16_t data; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - imm = inst.get_imm_I(); - - mem_addr = imm + regs->getValue(rs1); - data = readDataMem(mem_addr, 2); - regs->setValue(rd, data); - - log->SC_log(Log::INFO) << "LH: x" - << rs1 << " + " << imm << " (@0x" - << hex << mem_addr << dec << ") -> x" << rd << endl; - - return true; -} - -bool Execute::LW(Instruction &inst, bool c_extension) { - uint32_t mem_addr = 0; - int rd, rs1; - int32_t imm = 0; - uint32_t data; - - if (c_extension == false) { - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - imm = inst.get_imm_I(); - } else { - C_Instruction c_inst(inst.getInstr()); - - rd = c_inst.get_rdp(); - rs1 = c_inst.get_rs1p(); - imm = c_inst.get_imm_L(); - } - - mem_addr = imm + regs->getValue(rs1); - data = readDataMem(mem_addr, 4); - regs->setValue(rd, data); - - log->SC_log(Log::INFO) << dec << "C.LW: x" - << rs1 << "(0x" << hex << regs->getValue(rs1) << ") + " - << dec << imm << " (@0x" << hex << mem_addr << dec << ") -> x" << rd << hex - << " (0x" << data << ")"<< endl; - - return true; -} - -bool Execute::LBU(Instruction &inst) { - uint32_t mem_addr = 0; - int rd, rs1; - int32_t imm = 0; - uint8_t data; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - imm = inst.get_imm_I(); - - mem_addr = imm + regs->getValue(rs1); - data = readDataMem(mem_addr, 1); - regs->setValue(rd, data); - - log->SC_log(Log::INFO) << "LBU: x" - << rs1 << " + " << imm << " (@0x" - << hex << mem_addr << dec << ") -> x" << rd << endl; - - return true; -} - -bool Execute::LHU(Instruction &inst) { - uint32_t mem_addr = 0; - int rd, rs1; - int32_t imm = 0; - uint16_t data; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - imm = inst.get_imm_I(); - - mem_addr = imm + regs->getValue(rs1); - data = readDataMem(mem_addr, 2); - regs->setValue(rd, data); - - log->SC_log(Log::INFO) << "LHU: x" << dec - << rs1 << " + " << imm << " (@0x" - << hex << mem_addr << dec << ") -> x" - << rd << "(0x" << hex << data << ")"<< endl; - - return true; -} - -bool Execute::SB(Instruction &inst) { - uint32_t mem_addr = 0; - int rs1, rs2; - int32_t imm = 0; - uint32_t data; - - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - imm = inst.get_imm_S(); - - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); - - writeDataMem(mem_addr, data, 1); - - log->SC_log(Log::INFO) << "SB: x" << dec - << rs2 << " -> x" << rs1 << " + 0x" << hex << imm - << " (@0x" << hex << mem_addr << dec << ")" << endl; - - return true; -} - -bool Execute::SH(Instruction &inst) { - uint32_t mem_addr = 0; - int rs1, rs2; - int32_t imm = 0; - uint32_t data; - - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - imm = inst.get_imm_S(); - - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); - - writeDataMem(mem_addr, data, 2); - - log->SC_log(Log::INFO) << "SH: x" << dec - << rs2 << " -> x" - << rs1 << " + 0x" << hex << imm << " (@0x" << hex - << mem_addr << dec << ")" << endl; - - return true; -} - -bool Execute::SW(Instruction &inst, bool c_extension) { - uint32_t mem_addr = 0; - int rs1, rs2; - int32_t imm = 0; - uint32_t data; - - if (c_extension == false) { - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - imm = inst.get_imm_S(); - } else { - C_Instruction c_inst(inst.getInstr()); - rs1 = c_inst.get_rs1p(); - rs2 = c_inst.get_rs2p(); - imm = c_inst.get_imm_L(); - } - - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); - - writeDataMem(mem_addr, data, 4); - - log->SC_log(Log::INFO) << "SW: x" << dec - << rs2 << "(0x" << hex << data << ") -> x" << dec - << rs1 << " + 0x" << hex << imm << " (@0x" << hex - << mem_addr << dec << ")" << endl; - - return true; -} - -bool Execute::ADDI(Instruction &inst, bool c_extension) { - int rd, rs1; - int32_t imm = 0; - int32_t calc; - - if (c_extension == false) { - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - imm = inst.get_imm_I(); - } else { - C_Instruction c_inst(inst.getInstr()); - - rd = c_inst.get_rd(); - rs1 = rd; - imm = c_inst.get_imm_ADDI(); - } - - calc = regs->getValue(rs1) + imm; - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "ADDI: x" << dec - << rs1 << " + " << imm << " -> x" << dec - << rd << "(0x" << hex << calc << ")"<< endl; - - return true; -} - -bool Execute::SLTI(Instruction &inst) { - int rd, rs1; - int32_t imm; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - imm = inst.get_imm_I(); - - if (regs->getValue(rs1) < imm) { - regs->setValue(rd, 1); - log->SC_log(Log::INFO) << "SLTI: x" - << rs1 << " < " - << imm << " => " << "1 -> x" - << rd << endl; - } else { - regs->setValue(rd, 0); - log->SC_log(Log::INFO) << "SLTI: x" - << rs1 << " < " - << imm << " => " << "0 -> x" - << rd << endl; - } - - return true; -} - -bool Execute::SLTIU(Instruction &inst) { - int rd, rs1; - int32_t imm; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - imm = inst.get_imm_I(); - - if ((uint32_t) regs->getValue(rs1) < (uint32_t)imm) { - regs->setValue(rd, 1); - log->SC_log(Log::INFO) << "SLTIU: x" - << rs1 << " < " - << imm << " => " << "1 -> x" - << rd << endl; - } else { - regs->setValue(rd, 0); - log->SC_log(Log::INFO) << "SLTIU: x" - << rs1 << " < " - << imm << " => " << "0 -> x" - << rd << endl; - } - - return true; -} - -bool Execute::XORI(Instruction &inst) { - int rd, rs1; - int32_t imm; - uint32_t calc; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - imm = inst.get_imm_I(); - - calc = regs->getValue(rs1) ^ imm; - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "XORI: x" - << rs1 << " XOR " - << imm << "-> x" - << rd << endl; - - return true; -} - -bool Execute::ORI(Instruction &inst) { - int rd, rs1; - int32_t imm; - uint32_t calc; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - imm = inst.get_imm_I(); - - calc = regs->getValue(rs1) | imm; - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "ORI: x" - << rs1 << " OR " - << imm << "-> x" - << rd << endl; - - return true; -} - -bool Execute::ANDI(Instruction &inst) { - int rd, rs1; - uint32_t imm; - uint32_t calc; - uint32_t aux; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - imm = inst.get_imm_I(); - - aux = regs->getValue(rs1); - calc = aux & imm; - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "ANDI: x" - << rs1 << "(0x" << hex << aux << ") AND 0x" - << imm << " -> x" - << dec << rd << "(0x" << hex << calc << ")" << endl; - - return true; -} - -bool Execute::SLLI(Instruction &inst) { - int rd, rs1, rs2; - uint32_t shift; - uint32_t calc; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - rs2 = inst.get_shamt(); - - if (rs2 >= 0x20) { - // raise an exception, but how? - cout << "ILEGAL INSTRUCTION, shamt[5] != 0" << endl; - RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION); - - return false; - } - - shift = rs2 & 0x1F; - - calc = ((uint32_t)regs->getValue(rs1)) << shift; - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "SLLI: x" << dec - << rs1 << " << " << shift << " -> x" - << rd << "(0x" << hex << calc << ")" << endl; - - return true; -} - -bool Execute::SRLI(Instruction &inst) { - int rd, rs1, rs2; - uint32_t shift; - uint32_t calc; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - shift = rs2 & 0x1F; - - calc = ((uint32_t)regs->getValue(rs1)) >> shift; - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "SRLI: x" << dec - << rs1 << " >> " << shift << " -> x" - << rd << endl; - - return true; -} - -bool Execute::SRAI(Instruction &inst) { - int rd, rs1, rs2; - uint32_t shift; - int32_t calc; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - shift = rs2 & 0x1F; - - calc = regs->getValue(rs1) >> shift; - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "SRAI: x" << dec - << rs1 << " >> " << shift << " -> x" - << rd << endl; - - return true; -} - -bool Execute::ADD(Instruction &inst) { - int rd, rs1, rs2; - uint32_t calc; - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - calc = regs->getValue(rs1) + regs->getValue(rs2); - - // log->SC_log(Log::INFO) << "ADD 0x" << hex << regs->getValue(rs1) - // << " + 0x" << regs->getValue(rs2) << " = " << calc << endl; - - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "ADD: x" << dec - << rs1 << " + x" - << rs2 << " -> x" - << rd << hex << "(0x" << calc << ")"<< endl; - - return true; -} - -bool Execute::SUB(Instruction &inst) { - int rd, rs1, rs2; - uint32_t calc; - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - calc = regs->getValue(rs1) - regs->getValue(rs2); - regs->setValue(rd, calc); - - /* Can insert some arbitrary execution time */ - //wait(sc_time(10, SC_NS)); - - log->SC_log(Log::INFO) << "SUB: x" - << rs1 << " - x" - << rs2 << " -> x" - << rd << "("<< calc << ")" << endl; - - return true; -} - -bool Execute::SLL(Instruction &inst) { - int rd, rs1, rs2; - uint32_t shift; - uint32_t calc; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - shift = regs->getValue(rs2) & 0x1F; - - calc = ((uint32_t)regs->getValue(rs1)) << shift; - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "SLL: x" - << rs1 << " << " << shift << " -> x" - << rd << endl; - - return true; -} - -bool Execute::SLT(Instruction &inst) { - int rd, rs1, rs2; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - if (regs->getValue(rs1) < regs->getValue(rs2)) { - regs->setValue(rd, 1); - log->SC_log(Log::INFO) << "SLT: x" - << rs1 << " < x" - << rs2 << " => " << "1 -> x" - << rd << endl; - } else { - regs->setValue(rd, 0); - log->SC_log(Log::INFO) << "SLT: x" - << rs1 << " < x" - << rs2 << " => " << "0 -> x" - << rd << endl; - } - - return true; -} - -bool Execute::SLTU(Instruction &inst) { - int rd, rs1, rs2; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - if ( (uint32_t)regs->getValue(rs1) < (uint32_t)regs->getValue(rs2)) { - regs->setValue(rd, 1); - log->SC_log(Log::INFO) << "SLTU: x" - << rs1 << " < x" - << rs2 << " => " << "1 -> x" - << rd << endl; - } else { - regs->setValue(rd, 0); - log->SC_log(Log::INFO) << "SLTU: x" - << rs1 << " < x" - << rs2 << " => " << "0 -> x" - << rd << endl; - } - - return true; -} - -bool Execute::XOR(Instruction &inst) { - int rd, rs1, rs2; - uint32_t calc; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - calc = regs->getValue(rs1) ^ regs->getValue(rs2); - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "XOR: x" - << rs1 << " XOR x" - << rs2 << "-> x" - << rd << endl; - - return true; -} - -bool Execute::SRL(Instruction &inst) { - int rd, rs1, rs2; - uint32_t shift; - uint32_t calc; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - shift = regs->getValue(rs2) & 0x1F; - - calc = ((uint32_t)regs->getValue(rs1)) >> shift; - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "SRL: x" - << rs1 << " >> " << shift << " -> x" << rd << endl; - - return true; -} - -bool Execute::SRA(Instruction &inst) { - int rd, rs1, rs2; - uint32_t shift; - int32_t calc; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - shift = regs->getValue(rs2) & 0x1F; - - calc = regs->getValue(rs1) >> shift; - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "SRA: x" - << rs1 << " >> " << shift << " -> x" << rd << endl; - - return true; -} - -bool Execute::OR(Instruction &inst) { - int rd, rs1, rs2; - uint32_t calc; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - calc = regs->getValue(rs1) | regs->getValue(rs2); - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "OR: x" << rs1 << " OR x" << rs2 - << "-> x" << rd << endl; - - return true; -} - -bool Execute::AND(Instruction &inst) { - int rd, rs1, rs2; - uint32_t calc; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - rs2 = inst.get_rs2(); - - calc = regs->getValue(rs1) & regs->getValue(rs2); - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "AND: x" << rs1 << " AND x" << rs2 - << "-> x" << rd << endl; - - return true; -} - -bool Execute::FENCE(Instruction &inst) { - log->SC_log(Log::INFO) << "FENCE" << endl; - - return true; -} - -bool Execute::ECALL(Instruction &inst) { - - log->SC_log(Log::INFO) << "ECALL" << endl; - std::cout << endl << "ECALL Instruction called, stopping simulation" << endl; - regs->dump(); - cout << "Simulation time " << sc_time_stamp() << endl; - perf->dump(); - - uint32_t gp_value = regs->getValue(Registers::gp); - if ( gp_value == 1) { - cout << "GP value is 1, test result is OK" << endl; - } else { - cout << "GP value is " << gp_value << endl; - } - //SC_REPORT_ERROR("Execute", "ECALL"); - sc_stop(); - return true; -} - -bool Execute::EBREAK(Instruction &inst) { - - log->SC_log(Log::INFO) << "EBREAK" << endl; - std::cout << endl << "EBRAK Instruction called, dumping information" << endl; - regs->dump(); - cout << "Simulation time " << sc_time_stamp() << endl; - perf->dump(); - - RaiseException(EXCEPTION_CAUSE_BREAKPOINT); - - return true; -} - -bool Execute::CSRRW(Instruction &inst) { - int rd, rs1; - int csr; - uint32_t aux; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - csr = inst.get_csr(); - - /* These operations must be atomical */ - if (rd != 0) { - aux = regs->getCSR(csr); - regs->setValue(rd, aux); - } - - aux = regs->getValue(rs1); - regs->setCSR(csr, aux); - - log->SC_log(Log::INFO) << hex << "CSRRW: CSR #" - << csr << " -> x" << dec << rd - << ". x" << rs1 << "-> CSR #" << hex << csr << " (0x" - << aux << ")" << endl; - - return true; -} - -bool Execute::CSRRS(Instruction &inst) { - int rd, rs1; - int csr; - uint32_t bitmask, aux, aux2; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - csr = inst.get_csr(); - - if (rd == 0) { - log->SC_log(Log::INFO) << "CSRRS with rd1 == 0, doing nothing." << endl; - return false; - } - - /* These operations must be atomical */ - aux = regs->getCSR(csr); - bitmask = regs->getValue(rs1); - - regs->setValue(rd, aux); - - aux2 = aux | bitmask; - regs->setCSR(csr, aux2); - - log->SC_log(Log::INFO) << "CSRRS: CSR #" - << csr << "(0x" << hex << aux << ") -> x" << dec << rd - << ". x" << rs1 << " & CSR #" << csr - << " <- 0x" << hex << aux2 << endl; - - return true; -} - -bool Execute::CSRRC(Instruction &inst) { - int rd, rs1; - int csr; - uint32_t bitmask, aux, aux2; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - csr = inst.get_csr(); - - if (rd == 0) { - log->SC_log(Log::INFO) << "CSRRC with rd1 == 0, doing nothing." << endl; - return true; - } - - /* These operations must be atomical */ - aux = regs->getCSR(csr); - bitmask = regs->getValue(rs1); - - regs->setValue(rd, aux); - - aux2 = aux & ~bitmask; - regs->setCSR(csr, aux2); - - log->SC_log(Log::INFO) << "CSRRC: CSR #" - << csr << "(0x" << hex << aux << ") -> x" << dec << rd - << ". x" << rs1 << " & CSR #" << csr - << " <- 0x" << hex << aux2 << endl; - - return true; -} - -bool Execute::CSRRWI(Instruction &inst) { - int rd, rs1; - int csr; - uint32_t aux; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - csr = inst.get_csr(); - - - /* These operations must be atomical */ - if (rd != 0) { - aux = regs->getCSR(csr); - regs->setValue(rd, aux); - } - aux = rs1; - regs->setCSR(csr, aux); - - log->SC_log(Log::INFO) << "CSRRWI: CSR #" - << csr << " -> x" << rd - << ". x" << rs1 << "-> CSR #" << csr << endl; - - return true; -} - -bool Execute::CSRRSI(Instruction &inst) { - int rd, rs1; - int csr; - uint32_t bitmask, aux; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - csr = inst.get_csr(); - - if (rs1 == 0) { - return true; - } - - /* These operations must be atomical */ - aux = regs->getCSR(csr); - regs->setValue(rd, aux); - - bitmask = rs1; - aux = aux | bitmask; - regs->setCSR(csr, aux); - - log->SC_log(Log::INFO) << "CSRRSI: CSR #" - << csr << " -> x" << rd - << ". x" << rs1 << " & CSR #" << csr - << "(0x" << hex << aux << ")"<< endl; - - return true; -} - -bool Execute::CSRRCI(Instruction &inst) { - int rd, rs1; - int csr; - uint32_t bitmask, aux; - - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - csr = inst.get_csr(); - - if (rs1 == 0) { - return true; - } - - /* These operations must be atomical */ - aux = regs->getCSR(csr); - regs->setValue(rd, aux); - - bitmask = rs1; - aux = aux & ~bitmask; - regs->setCSR(csr, aux); - - log->SC_log(Log::INFO) << "CSRRCI: CSR #" - << csr << " -> x" << rd - << ". x" << rs1 << " & CSR #" << csr - << "(0x" << hex << aux << ")"<< endl; - - return true; -} - -/*********************** Privileged Instructions ******************************/ - -bool Execute::MRET(Instruction &inst) { - uint32_t new_pc = 0; - - new_pc = regs->getCSR(CSR_MEPC); - regs->setPC(new_pc); - - log->SC_log(Log::INFO) << "MRET: PC <- 0x" << hex << new_pc << endl; - - // update mstatus - 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; -} - -bool Execute::SRET(Instruction &inst) { - uint32_t new_pc = 0; - - new_pc = regs->getCSR(CSR_SEPC); - regs->setPC(new_pc); - - log->SC_log(Log::INFO) << "SRET: PC <- 0x" << hex << new_pc << endl; - - return true; -} - -bool Execute::WFI(Instruction &inst) { - log->SC_log(Log::INFO) << "WFI" << endl; - - return true; -} - -bool Execute::SFENCE(Instruction &inst) { - log->SC_log(Log::INFO) << "SFENCE" << endl; - - return true; -} - -/**************************** C Instructions **********************************/ - -bool Execute::C_JR(Instruction &inst) { - uint32_t mem_addr = 0; - int rs1; - int new_pc; - - C_Instruction c_inst(inst.getInstr()); - - rs1 = c_inst.get_rs1(); - mem_addr = 0; - - new_pc = (regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE; - regs->setPC(new_pc); - - log->SC_log(Log::INFO) << "JR: PC <- 0x" << hex << new_pc << endl; - - return true; -} - -bool Execute::C_MV(Instruction &inst) { - int rd, rs1, rs2; - uint32_t calc; - - C_Instruction c_inst(inst.getInstr()); - - rd = c_inst.get_rd(); - rs1 = 0; - rs2 = c_inst.get_rs2(); - - calc = regs->getValue(rs1) + regs->getValue(rs2); - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "C.MV: x" << dec - << rs1 << "(0x" << hex << regs->getValue(rs1) << ") + x" << dec - << rs2 << "(0x" << hex << regs->getValue(rs2) << ") -> x" << dec - << rd << "(0x" << hex << calc << ")" << endl; - - return true; -} - -bool Execute::C_ADD(Instruction &inst) { - int rd, rs1, rs2; - uint32_t calc; - - C_Instruction c_inst(inst.getInstr()); - - rd = c_inst.get_rs1(); - rs1 = c_inst.get_rs1(); - rs2 = c_inst.get_rs2(); - - calc = regs->getValue(rs1) + regs->getValue(rs2); - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "C.ADD: x" - << dec << rs1 << " + x" - << rs2 << " -> x" - << rd << "(0x" << hex << calc << ")" << endl; - - return true; -} - -bool Execute::C_LWSP(Instruction &inst) { - uint32_t mem_addr = 0; - int rd, rs1; - int32_t imm = 0; - uint32_t data; - - // lw rd, offset[7:2](x2) - C_Instruction c_inst(inst.getInstr()); - - rd = c_inst.get_rd(); - rs1 = 2; - imm = c_inst.get_imm_LWSP(); - - mem_addr = imm + regs->getValue(rs1); - data = readDataMem(mem_addr, 4); - - regs->setValue(rd, data); - - log->SC_log(Log::INFO) << "C.LWSP: x" << dec - << rs1 << " + " << imm - << " (@0x" << hex << mem_addr << dec << ") -> x" - << rd << "(" << hex << data << ")"<< dec << endl; - - return true; -} - -bool Execute::C_ADDI4SPN(Instruction &inst) { - int rd, rs1; - int32_t imm = 0; - int32_t calc; - - C_Instruction c_inst(inst.getInstr()); - - rd = c_inst.get_rdp(); - rs1 = 2; - imm = c_inst.get_imm_ADDI4SPN(); - - if (imm == 0) { - RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, inst.getInstr() ); - return false; - } - - calc = regs->getValue(rs1) + imm; - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << dec << "ADDI4SPN: x" - << rs1 << "(0x" << hex << regs->getValue(rs1) << ") + " - << dec << imm << " -> x" - << rd << "(0x" << hex << calc << ")" << endl; - - return true; -} - -bool Execute::C_ADDI16SP(Instruction &inst) { - // addi x2, x2, nzimm[9:4] - int rd, rs1; - int32_t imm = 0; - int32_t calc; - - C_Instruction c_inst(inst.getInstr()); - - if (c_inst.get_rd() == 2) { - rd = 2; - rs1 = 2; - imm = c_inst.get_imm_ADDI16SP(); - - calc = regs->getValue(rs1) + imm; - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << dec << "ADDI16SP: x" - << rs1 << " + " - << dec << imm << " -> x" - << rd << "(0x" << hex << calc << ")" << endl; - } else { - /* C.LUI OPCODE */ - rd = c_inst.get_rd(); - imm = c_inst.get_imm_LUI(); - regs->setValue(rd, imm); - log->SC_log(Log::INFO) << dec << "C.LUI x" - << rd << " <- 0x" << hex << imm << endl; - } - - return true; -} - -bool Execute::C_SWSP(Instruction &inst) { - // sw rs2, offset(x2) - uint32_t mem_addr = 0; - int rs1, rs2; - int32_t imm = 0; - uint32_t data; - - C_Instruction c_inst(inst.getInstr()); - - rs1 = 2; - rs2 = c_inst.get_rs2(); - imm = c_inst.get_imm_CSS(); - - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); - - writeDataMem(mem_addr, data, 4); - - log->SC_log(Log::INFO) << dec << "SWSP: x" - << rs2 << "(0x" << hex << data << ") -> x" << dec - << rs1 << " + " << imm << " (@0x" << hex - << mem_addr << dec << ")" << endl; - - return true; -} - -bool Execute::C_BEQZ(Instruction &inst) { - int rs1; - int new_pc = 0; - uint32_t val1; - C_Instruction c_inst(inst.getInstr()); - - rs1 = c_inst.get_rs1p(); - val1 = regs->getValue(rs1); - - if (val1 == 0) { - new_pc = regs->getPC() + c_inst.get_imm_CB(); - regs->setPC(new_pc); - } else { - regs->incPC(true); //PC <- PC + 2 - new_pc = regs->getPC(); - } - - log->SC_log(Log::INFO) << "C.BEQZ: x" << dec - << rs1 << "(" << val1 << ") == 0? -> PC (0x" - << hex << new_pc << ")" << dec << endl; - - return true; -} - -bool Execute::C_BNEZ(Instruction &inst) { - int rs1; - int new_pc = 0; - uint32_t val1; - C_Instruction c_inst(inst.getInstr()); - - rs1 = c_inst.get_rs1p(); - val1 = regs->getValue(rs1); - - if (val1 != 0) { - new_pc = regs->getPC() + c_inst.get_imm_CB(); - regs->setPC(new_pc); - } else { - regs->incPC(true); //PC <- PC +2 - new_pc = regs->getPC(); - } - - log->SC_log(Log::INFO) << "C.BNEZ: x" << dec - << rs1 << "(0x" << hex << val1 << ") != 0? -> PC (0x" - << hex << new_pc << ")" << dec << endl; - - return true; -} - -bool Execute::C_LI(Instruction &inst) { - int rd, rs1; - int32_t imm = 0; - int32_t calc; - - C_Instruction c_inst(inst.getInstr()); - - rd = c_inst.get_rd(); - rs1 = 0; - imm = c_inst.get_imm_ADDI(); - - calc = regs->getValue(rs1) + imm; - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << dec << "LI: x" - << rs1 << "(" << regs->getValue(rs1) << ") + " - << imm << " -> x" << rd << "(" << calc << ")" << endl; - - return true; -} - -bool Execute::C_SRLI(Instruction &inst) { - int rd, rs1, rs2; - uint32_t shift; - uint32_t calc; - - C_Instruction c_inst(inst.getInstr()); - - rd = c_inst.get_rs1p(); - rs1 = c_inst.get_rs1p(); - rs2 = c_inst.get_rs2(); - - shift = rs2 & 0x1F; - - calc = ((uint32_t)regs->getValue(rs1)) >> shift; - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "C.SRLI: x" - << rs1 << " >> " << shift << " -> x" - << rd << endl; - - return true; -} - -bool Execute::C_SRAI(Instruction &inst) { - int rd, rs1, rs2; - uint32_t shift; - int32_t calc; - - C_Instruction c_inst(inst.getInstr()); - - rd = c_inst.get_rs1p(); - rs1 = c_inst.get_rs1p(); - rs2 = c_inst.get_rs2(); - - shift = rs2 & 0x1F; - - calc = (int32_t)regs->getValue(rs1) >> shift; - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "C.SRAI: x" - << rs1 << " >> " << dec << shift << " -> x" - << rd << "("<< calc << ")" << endl; - - return true; -} - -bool Execute::C_SLLI(Instruction &inst) { - int rd, rs1, rs2; - uint32_t shift; - uint32_t calc; - - C_Instruction c_inst(inst.getInstr()); - - rd = c_inst.get_rs1p(); - rs1 = c_inst.get_rs1p(); - rs2 = c_inst.get_imm_ADDI(); - - shift = rs2 & 0x1F; - - calc = ((uint32_t)regs->getValue(rs1)) << shift; - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "C.SLLI: x" - << dec << rs1 << " << " - << shift << " -> x" - << rd << "(0x" << calc << ")"<< endl; - - return true; -} - - -bool Execute::C_ANDI(Instruction &inst) { - int rd, rs1; - uint32_t imm; - uint32_t aux; - uint32_t calc; - - C_Instruction c_inst(inst.getInstr()); - - rd = c_inst.get_rs1p(); - rs1 = c_inst.get_rs1p(); - imm = c_inst.get_imm_ADDI(); - - aux = regs->getValue(rs1); - calc = aux & imm; - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "C.ANDI: x" - << rs1 << "(" << aux << ") AND " - << imm << " -> x" - << rd << endl; - - return true; -} - -bool Execute::C_SUB(Instruction &inst) { - int rd, rs1, rs2; - uint32_t calc; - - C_Instruction c_inst(inst.getInstr()); - - rd = c_inst.get_rs1p(); - rs1 = c_inst.get_rs1p(); - rs2 = c_inst.get_rs2p(); - - calc = regs->getValue(rs1) - regs->getValue(rs2); - regs->setValue(rd, calc); - - /* Can insert some arbitrary execution time */ - //wait(sc_time(10, SC_NS)); - - log->SC_log(Log::INFO) << "C.SUB: x" - << dec << rs1 << " - x" - << rs2 << " -> x" - << rd << endl; - - return true; -} - - -bool Execute::C_XOR(Instruction &inst) { - int rd, rs1, rs2; - uint32_t calc; - - C_Instruction c_inst(inst.getInstr()); - - rd = c_inst.get_rs1p(); - rs1 = c_inst.get_rs1p(); - rs2 = c_inst.get_rs2p(); - - calc = regs->getValue(rs1) ^ regs->getValue(rs2); - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "C.XOR: x" - << dec << rs1 << " XOR x" - << rs2 << "-> x" - << rd << endl; - - return true; -} - -bool Execute::C_OR(Instruction &inst) { - int rd, rs1, rs2; - uint32_t calc; - - C_Instruction c_inst(inst.getInstr()); - - rd = c_inst.get_rs1p(); - rs1 = c_inst.get_rs1p(); - rs2 = c_inst.get_rs2p(); - - calc = regs->getValue(rs1) | regs->getValue(rs2); - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "C_OR: x" - << dec << rs1 << " OR x" - << rs2 << "-> x" - << rd << endl; - - return true; -} - -bool Execute::C_AND(Instruction &inst) { - int rd, rs1, rs2; - uint32_t calc; - - C_Instruction c_inst(inst.getInstr()); - - rd = c_inst.get_rs1p(); - rs1 = c_inst.get_rs1p(); - rs2 = c_inst.get_rs2p(); - - calc = regs->getValue(rs1) & regs->getValue(rs2); - regs->setValue(rd, calc); - - log->SC_log(Log::INFO) << "C.AND: x" - << dec << rs1 << " AND x" - << rs2 << "-> x" - << rd << endl; - - return true; -} - -/******************************************************************************/ -/* M Extensions */ -/******************************************************************************/ -bool Execute::M_MUL(Instruction &inst) { - int rd, rs1, rs2; - int32_t multiplier, multiplicand; - int64_t result; - - M_Instruction m_inst(inst.getInstr()); - - rd = m_inst.get_rd(); - rs1 = m_inst.get_rs1(); - rs2 = m_inst.get_rs2(); - - multiplier = regs->getValue(rs1); - multiplicand = regs->getValue(rs2); - - result = (int64_t) multiplier * multiplicand; - result = result & 0x00000000FFFFFFFF; - regs->setValue(rd, result); - - log->SC_log(Log::INFO) << dec << "MUL: x" << rs1 << " * x" << rs2 - << " -> x" << rd << "(" << result << ")" << endl; - - return true; -} - -bool Execute::M_MULH(Instruction &inst) { - int rd, rs1, rs2; - int32_t multiplier, multiplicand; - int64_t result; - int32_t ret_value; - - M_Instruction m_inst(inst.getInstr()); - - rd = m_inst.get_rd(); - rs1 = m_inst.get_rs1(); - rs2 = m_inst.get_rs2(); - - multiplier = regs->getValue(rs1); - multiplicand = regs->getValue(rs2); - - result = (int64_t) multiplier * (int64_t) multiplicand; - - ret_value = (int32_t)((result >> 32) & 0x00000000FFFFFFFF); - regs->setValue(rd, ret_value); - - log->SC_log(Log::INFO) << dec << "MULH: x" << rs1 << " * x" << rs2 - << " -> x" << rd << "(" << result << ")" << endl; - - return true; -} - -bool Execute::M_MULHSU(Instruction &inst) { - int rd, rs1, rs2; - int32_t multiplier; - uint32_t multiplicand; - int64_t result; - - M_Instruction m_inst(inst.getInstr()); - - rd = m_inst.get_rd(); - rs1 = m_inst.get_rs1(); - rs2 = m_inst.get_rs2(); - - multiplier = regs->getValue(rs1); - multiplicand = regs->getValue(rs2); - - result = (int64_t) multiplier * (uint64_t) multiplicand; - result = (result >> 32) & 0x00000000FFFFFFFF; - regs->setValue(rd, result); - - log->SC_log(Log::INFO) << dec << "MULHSU: x" << rs1 << " * x" << rs2 - << " -> x" << rd << "(" << result << ")" << endl; - - return true; -} - -bool Execute::M_MULHU(Instruction &inst) { - int rd, rs1, rs2; - uint32_t multiplier, multiplicand; - uint64_t result; - int32_t ret_value; - - M_Instruction m_inst(inst.getInstr()); - - rd = m_inst.get_rd(); - rs1 = m_inst.get_rs1(); - rs2 = m_inst.get_rs2(); - - multiplier = (uint32_t) regs->getValue(rs1); - multiplicand = (uint32_t) regs->getValue(rs2); - - result = (uint64_t) multiplier * (uint64_t) multiplicand; - ret_value = (uint32_t)(result >> 32) & 0x00000000FFFFFFFF; - regs->setValue(rd, ret_value); - - log->SC_log(Log::INFO) << dec << "MULHU: x" << rs1 << " * x" << rs2 - << " -> x" << rd << "(" << ret_value << ")" << endl; - - return true; -} - -bool Execute::M_DIV(Instruction &inst) { - int rd, rs1, rs2; - int32_t divisor, dividend; - int64_t result; - - M_Instruction m_inst(inst.getInstr()); - - rd = m_inst.get_rd(); - rs1 = m_inst.get_rs1(); - rs2 = m_inst.get_rs2(); - - dividend = regs->getValue(rs1); - divisor = regs->getValue(rs2); - - if (divisor == 0) { - result = - 1; - } else if ( (divisor == -1) && (dividend == (int32_t)0x80000000) ) { - result = 0x0000000080000000; - } else { - result = dividend / divisor; - result = result & 0x00000000FFFFFFFF; - } - - regs->setValue(rd, result); - - log->SC_log(Log::INFO) << dec << "DIV: x" << rs1 << " / x" << rs2 - << " -> x" << rd << "(" << result << ")" << endl; - - return true; -} - -bool Execute::M_DIVU(Instruction &inst) { - int rd, rs1, rs2; - uint32_t divisor, dividend; - uint64_t result; - - M_Instruction m_inst(inst.getInstr()); - - rd = m_inst.get_rd(); - rs1 = m_inst.get_rs1(); - rs2 = m_inst.get_rs2(); - - dividend = regs->getValue(rs1); - divisor = regs->getValue(rs2); - - if (divisor == 0) { - result = -1; - } else { - result = dividend / divisor; - result = result & 0x00000000FFFFFFFF; - } - - regs->setValue(rd, result); - - log->SC_log(Log::INFO) << dec << "DIVU: x" << rs1 << " / x" << rs2 - << " -> x" << rd << "(" << result << ")" << endl; - - return true; -} - -bool Execute::M_REM(Instruction &inst) { - int rd, rs1, rs2; - int32_t divisor, dividend; - int32_t result; - - M_Instruction m_inst(inst.getInstr()); - - rd = m_inst.get_rd(); - rs1 = m_inst.get_rs1(); - rs2 = m_inst.get_rs2(); - - dividend = regs->getValue(rs1); - divisor = regs->getValue(rs2); - - if (divisor == 0) { - result = dividend; - } else if ( (divisor == -1) && (dividend == (int32_t)0x80000000) ) { - result = 0; - } else { - result = dividend % divisor; - } - - regs->setValue(rd, result); - - log->SC_log(Log::INFO) << dec << "REM: x" << rs1 << " / x" << rs2 - << " -> x" << rd << "(" << result << ")" << endl; - - return true; -} - -bool Execute::M_REMU(Instruction &inst) { - int rd, rs1, rs2; - uint32_t divisor, dividend; - uint32_t result; - - M_Instruction m_inst(inst.getInstr()); - - rd = m_inst.get_rd(); - rs1 = m_inst.get_rs1(); - rs2 = m_inst.get_rs2(); - - dividend = regs->getValue(rs1); - divisor = regs->getValue(rs2); - - if (divisor == 0) { - result = dividend; - } else { - result = dividend % divisor; - } - - regs->setValue(rd, result); - - log->SC_log(Log::INFO) << dec << "REMU: x" << rs1 << " / x" << rs2 - << " -> x" << rd << "(" << result << ")" << endl; - - return true; -} - - -bool Execute::A_LR(Instruction &inst) { - uint32_t mem_addr = 0; - int rd, rs1, rs2; - uint32_t data; - - A_Instruction a_inst(inst.getInstr()); - - rd = a_inst.get_rd(); - rs1 = a_inst.get_rs1(); - rs2 = a_inst.get_rs2(); - - if (rs2 != 0) { - cout << "ILEGAL INSTRUCTION, LR.W: rs2 != 0" << endl; - RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION); - - return false; - } - - mem_addr = regs->getValue(rs1); - data = readDataMem(mem_addr, 4); - regs->setValue(rd, data); - - TLB_reserve(mem_addr); - - log->SC_log(Log::INFO) << dec << "LR.W: x" - << rs1 << " (@0x" << hex << mem_addr - << dec << ") -> x" << rd << endl; - - return true; -} - -bool Execute::A_SC(Instruction &inst) { - uint32_t mem_addr = 0; - int rd, rs1, rs2; - uint32_t data; - - A_Instruction a_inst(inst.getInstr()); - - rd = a_inst.get_rd(); - rs1 = a_inst.get_rs1(); - rs2 = a_inst.get_rs2(); - - mem_addr = regs->getValue(rs1); - data = regs->getValue(rs2); - - if (TLB_reserved(mem_addr) == true) { - writeDataMem(mem_addr, data, 4); - regs->setValue(rd, 0); // SC writes 0 to rd on success - } else { - regs->setValue(rd, 1); // SC writes nonzero on failure - } - - log->SC_log(Log::INFO) << dec << "SC.W: (@0x" << - hex << mem_addr << dec << ") <- x" << rs2 << - hex << "(0x" << data << ")" << endl; - - return true; -} - -bool Execute::A_AMOSWAP(Instruction &inst) { - uint32_t mem_addr = 0; - int rd, rs1, rs2; - uint32_t data; - uint32_t aux; - - A_Instruction a_inst(inst.getInstr()); - - /* These instructions must be atomic */ - - rd = a_inst.get_rd(); - rs1 = a_inst.get_rs1(); - rs2 = a_inst.get_rs2(); - - mem_addr = regs->getValue(rs1); - data = readDataMem(mem_addr, 4); - - regs->setValue(rd, data); - - // swap - aux = regs->getValue(rs2); - regs->setValue(rs2, data); - - writeDataMem(mem_addr, aux, 4); - - log->SC_log(Log::INFO) << dec << "AMOSWAP " << endl; - return true; -} - -bool Execute::A_AMOADD(Instruction &inst) { - uint32_t mem_addr = 0; - int rd, rs1, rs2; - uint32_t data; - - A_Instruction a_inst(inst.getInstr()); - - /* These instructions must be atomic */ - - rd = a_inst.get_rd(); - rs1 = a_inst.get_rs1(); - rs2 = a_inst.get_rs2(); - - mem_addr = regs->getValue(rs1); - data = readDataMem(mem_addr, 4); - - regs->setValue(rd, data); - - // add - data = data + regs->getValue(rs2); - - writeDataMem(mem_addr, data, 4); - - log->SC_log(Log::INFO) << dec << "AMOADD " << endl; - - return true; -} - -bool Execute::A_AMOXOR(Instruction &inst) { - uint32_t mem_addr = 0; - int rd, rs1, rs2; - uint32_t data; - - A_Instruction a_inst(inst.getInstr()); - - /* These instructions must be atomic */ - - rd = a_inst.get_rd(); - rs1 = a_inst.get_rs1(); - rs2 = a_inst.get_rs2(); - - mem_addr = regs->getValue(rs1); - data = readDataMem(mem_addr, 4); - - regs->setValue(rd, data); - - // add - data = data ^ regs->getValue(rs2); - - writeDataMem(mem_addr, data, 4); - - log->SC_log(Log::INFO) << dec << "AMOXOR " << endl; - - return true; -} -bool Execute::A_AMOAND(Instruction &inst) { - uint32_t mem_addr = 0; - int rd, rs1, rs2; - uint32_t data; - - A_Instruction a_inst(inst.getInstr()); - - /* These instructions must be atomic */ - - rd = a_inst.get_rd(); - rs1 = a_inst.get_rs1(); - rs2 = a_inst.get_rs2(); - - mem_addr = regs->getValue(rs1); - data = readDataMem(mem_addr, 4); - - regs->setValue(rd, data); - - // add - data = data & regs->getValue(rs2); - - writeDataMem(mem_addr, data, 4); - - log->SC_log(Log::INFO) << dec << "AMOAND " << endl; - - return true; -} -bool Execute::A_AMOOR(Instruction &inst) { - uint32_t mem_addr = 0; - int rd, rs1, rs2; - uint32_t data; - - A_Instruction a_inst(inst.getInstr()); - - /* These instructions must be atomic */ - - rd = a_inst.get_rd(); - rs1 = a_inst.get_rs1(); - rs2 = a_inst.get_rs2(); - - mem_addr = regs->getValue(rs1); - data = readDataMem(mem_addr, 4); - - regs->setValue(rd, data); - - // add - data = data | regs->getValue(rs2); - - writeDataMem(mem_addr, data, 4); - - log->SC_log(Log::INFO) << dec << "AMOOR " << endl; - return true; -} -bool Execute::A_AMOMIN(Instruction &inst) { - uint32_t mem_addr = 0; - int rd, rs1, rs2; - uint32_t data; - uint32_t aux; - - A_Instruction a_inst(inst.getInstr()); - - /* These instructions must be atomic */ - - rd = a_inst.get_rd(); - rs1 = a_inst.get_rs1(); - rs2 = a_inst.get_rs2(); - - mem_addr = regs->getValue(rs1); - data = readDataMem(mem_addr, 4); - - regs->setValue(rd, data); - - // min - aux = regs->getValue(rs2); - if ((int32_t)data < (int32_t)aux) { - aux = data; - } - - writeDataMem(mem_addr, aux, 4); - - log->SC_log(Log::INFO) << dec << "AMOMIN " << endl; - - return true; -} -bool Execute::A_AMOMAX(Instruction &inst) { - uint32_t mem_addr = 0; - int rd, rs1, rs2; - uint32_t data; - uint32_t aux; - - A_Instruction a_inst(inst.getInstr()); - - /* These instructions must be atomic */ - - rd = a_inst.get_rd(); - rs1 = a_inst.get_rs1(); - rs2 = a_inst.get_rs2(); - - mem_addr = regs->getValue(rs1); - data = readDataMem(mem_addr, 4); - - regs->setValue(rd, data); - - // > - aux = regs->getValue(rs2); - if ((int32_t)data > (int32_t)aux) { - aux = data; - } - - writeDataMem(mem_addr, aux, 4); - - log->SC_log(Log::INFO) << dec << "AMOMAX " << endl; - - return true; -} -bool Execute::A_AMOMINU(Instruction &inst) { - uint32_t mem_addr = 0; - int rd, rs1, rs2; - uint32_t data; - uint32_t aux; - - A_Instruction a_inst(inst.getInstr()); - - /* These instructions must be atomic */ - - rd = a_inst.get_rd(); - rs1 = a_inst.get_rs1(); - rs2 = a_inst.get_rs2(); - - mem_addr = regs->getValue(rs1); - data = readDataMem(mem_addr, 4); - - regs->setValue(rd, data); - - // min - aux = regs->getValue(rs2); - if (data < aux) { - aux = data; - } - - writeDataMem(mem_addr, aux, 4); - - log->SC_log(Log::INFO) << dec << "AMOMINU " << endl; - - return true; -} -bool Execute::A_AMOMAXU(Instruction &inst) { - uint32_t mem_addr = 0; - int rd, rs1, rs2; - uint32_t data; - uint32_t aux; - - A_Instruction a_inst(inst.getInstr()); - - /* These instructions must be atomic */ - - rd = a_inst.get_rd(); - rs1 = a_inst.get_rs1(); - rs2 = a_inst.get_rs2(); - - mem_addr = regs->getValue(rs1); - data = readDataMem(mem_addr, 4); - - regs->setValue(rd, data); - - // max - aux = regs->getValue(rs2); - if (data > aux) { - aux = data; - } - - writeDataMem(mem_addr, aux, 4); - - log->SC_log(Log::INFO) << dec << "AMOMAXU " << endl; - - return true; -} - - -bool Execute::NOP(Instruction &inst) { - cout << endl; - regs->dump(); - cout << "Simulation time " << sc_time_stamp() << endl; - perf->dump(); - - SC_REPORT_ERROR("Execute", "NOP"); - - return true; -} - -/** - * Access data memory to get data for LOAD OPs - * @param addr address to access to - * @param size size of the data to read in bytes - * @return data value read - */ -uint32_t Execute::readDataMem(uint32_t addr, int size) { - uint32_t data; - tlm::tlm_generic_payload trans; - sc_time delay = 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( 0 ); // 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); - - if ( trans.is_response_error() ) { - SC_REPORT_ERROR("Memory", "Read memory"); - } - return data; -} - -/** - * Acces data memory to write data for STORE ops - * @brief - * @param addr addr address to access to - * @param data data to write - * @param size size of the data to write in bytes - */ -void Execute::writeDataMem(uint32_t addr, uint32_t data, int size) { - tlm::tlm_generic_payload trans; - sc_time delay = 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( 0 ); // 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); -} - -void Execute::RaiseException(uint32_t cause, uint32_t inst) { - uint32_t new_pc, current_pc, m_cause; - - current_pc = regs->getPC(); - m_cause = regs->getCSR(CSR_MSTATUS); - m_cause |= cause; - - new_pc = regs->getCSR(CSR_MTVEC); - - regs->setCSR(CSR_MEPC, current_pc ); - - if (cause == EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION) { - regs->setCSR(CSR_MTVAL, inst); - } else { - regs->setCSR(CSR_MTVAL, current_pc ); - } - - regs->setCSR(CSR_MCAUSE, cause); - regs->setCSR(CSR_MSTATUS, m_cause); - - regs->setPC( new_pc); - - log->SC_log(Log::ERROR) << "Exception! new PC 0x" << hex << new_pc << endl; - - regs->dump(); - cout << "Simulation time " << sc_time_stamp() << endl; - perf->dump(); - SC_REPORT_ERROR("Exception" , "Exception"); -} - - -void Execute::TLB_reserve(uint32_t address) { - TLB_A_Entries.insert(address); - return; -} - -bool Execute::TLB_reserved(uint32_t address) { - if (TLB_A_Entries.count(address) == 1) { - TLB_A_Entries.erase(address); - return true; - } else { - return false; - } -} diff --git a/src/Instruction.cpp b/src/Instruction.cpp index 7e3e8bb..42fe19e 100644 --- a/src/Instruction.cpp +++ b/src/Instruction.cpp @@ -1,186 +1,33 @@ +/*! + \file Instruction.cpp + \brief Decode instructions part of the RISC-V + \author Màrius Montón + \date August 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + #include "Instruction.h" - -Instruction::Instruction(sc_uint<32> instr) { - m_instr = instr; +Instruction::Instruction(sc_dt::sc_uint<32> instr) { + m_instr = instr; } -opCodes Instruction::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; - }; - 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; - } - case OR_F: - return OP_OR; - case AND_F: - return OP_AND; - } - } /* 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; -} - - extension_t Instruction::check_extension() { - if ( (m_instr.range(6,0) == 0b0110011) && - (m_instr.range(31,25) == 0b0000001) ){ - return M_EXTENSION; - } else if (m_instr.range(6,0) == 0b0101111) { - return A_EXTENSION; - } else if (m_instr.range(1,0) == 0b11) { - return BASE_EXTENSION; - } else if (m_instr.range(1,0) == 0b00) { - return C_EXTENSION; - } else if (m_instr.range(1,0) == 0b01) { - return C_EXTENSION; - } else if (m_instr.range(1,0) == 0b10) { - return C_EXTENSION; - } else { - return UNKNOWN_EXTENSION; - } + if ((m_instr.range(6, 0) == 0b0110011) + && (m_instr.range(31, 25) == 0b0000001)) { + return M_EXTENSION; + } else if (m_instr.range(6, 0) == 0b0101111) { + return A_EXTENSION; + } else if (m_instr.range(1, 0) == 0b11) { + return BASE_EXTENSION; + } else if (m_instr.range(1, 0) == 0b00) { + return C_EXTENSION; + } else if (m_instr.range(1, 0) == 0b01) { + return C_EXTENSION; + } else if (m_instr.range(1, 0) == 0b10) { + return C_EXTENSION; + } else { + return UNKNOWN_EXTENSION; + } } + diff --git a/src/Log.cpp b/src/Log.cpp index 9a4b257..b34f38c 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -1,41 +1,52 @@ +/*! + \file Log.cpp + \brief Class to manage Log + \author Màrius Montón + \date Aug 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + #include "Log.h" -Log* Log::getInstance() -{ - if (instance == 0) { - instance = new Log("Log.txt"); - } +Log* Log::getInstance() { + if (instance == 0) { + instance = new Log("Log.txt"); + } - return instance; + return instance; } -Log::Log(const char* filename) { - m_stream.open(filename); - currentLogLevel = Log::INFO; +Log::Log(const char *filename) { + m_stream.open(filename); + currentLogLevel = Log::INFO; } void Log::SC_log(std::string msg, enum LogLevel level) { - if (level <= currentLogLevel) { - m_stream << "time " << sc_core::sc_time_stamp() << ": " << msg << std::endl; - } + if (level <= currentLogLevel) { + m_stream << "time " << sc_core::sc_time_stamp() << ": " << msg + << std::endl; + } } std::ofstream& Log::SC_log(enum LogLevel level) { - if (level <= currentLogLevel) { - m_stream << "time " << sc_core::sc_time_stamp() << ": "; - return m_stream; - } else { - return m_sink; - } - + if (level <= currentLogLevel) { + m_stream << "time " << sc_core::sc_time_stamp() << ": "; + return m_stream; + } else { + return m_sink; + } } void Log::setLogLevel(enum LogLevel newLevel) { - std::cout << "LogLevel set to " << newLevel << std::endl; - currentLogLevel = newLevel; + std::cout << "LogLevel set to " << newLevel << std::endl; + currentLogLevel = newLevel; } -Log* Log::instance = 0; +enum Log::LogLevel Log::getLogLevel() { + return currentLogLevel; +} + +Log *Log::instance = 0; diff --git a/src/M_Instruction.cpp b/src/M_Instruction.cpp deleted file mode 100644 index 7bc22b8..0000000 --- a/src/M_Instruction.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "M_Instruction.h" - - -M_Instruction::M_Instruction(sc_uint<32> instr) { - m_instr = instr; -} - -op_M_Codes M_Instruction::decode() { - - 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; - default: - return OP_M_ERROR; - break; - - } - - return OP_M_ERROR; -} diff --git a/src/M_extension.cpp b/src/M_extension.cpp new file mode 100644 index 0000000..ef59fd6 --- /dev/null +++ b/src/M_extension.cpp @@ -0,0 +1,287 @@ +/*! + \file M_extension.h + \brief Implement M extensions part of the RISC-V + \author Màrius Montón + \date November 2018 +*/ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "M_extension.h" + +op_M_Codes M_extension::decode() { + + 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; + default: + return OP_M_ERROR; + break; + } + + return OP_M_ERROR; +} + +bool M_extension::Exec_M_MUL() { + int rd, rs1, rs2; + int32_t multiplier, multiplicand; + int64_t result; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + multiplier = regs->getValue(rs1); + multiplicand = regs->getValue(rs2); + + result = (int64_t) multiplier * multiplicand; + result = result & 0x00000000FFFFFFFF; + regs->setValue(rd, result); + + log->SC_log(Log::INFO) << std::dec << "MUL: x" << rs1 << " * x" << rs2 + << " -> x" << rd << "(" << result << ")" << std::endl; + + return true; +} + +bool M_extension::Exec_M_MULH() { + int rd, rs1, rs2; + int32_t multiplier, multiplicand; + int64_t result; + int32_t ret_value; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + multiplier = regs->getValue(rs1); + multiplicand = regs->getValue(rs2); + + result = (int64_t) multiplier * (int64_t) multiplicand; + + ret_value = (int32_t) ((result >> 32) & 0x00000000FFFFFFFF); + regs->setValue(rd, ret_value); + + log->SC_log(Log::INFO) << std::dec << "MULH: x" << rs1 << " * x" << rs2 + << " -> x" << rd << "(" << result << ")" << std::endl; + + return true; +} + +bool M_extension::Exec_M_MULHSU() { + int rd, rs1, rs2; + int32_t multiplier; + uint32_t multiplicand; + int64_t result; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + multiplier = regs->getValue(rs1); + multiplicand = regs->getValue(rs2); + + result = (int64_t) multiplier * (uint64_t) multiplicand; + result = (result >> 32) & 0x00000000FFFFFFFF; + regs->setValue(rd, result); + + log->SC_log(Log::INFO) << std::dec << "MULHSU: x" << rs1 << " * x" << rs2 + << " -> x" << rd << "(" << result << ")" << std::endl; + + return true; +} + +bool M_extension::Exec_M_MULHU() { + int rd, rs1, rs2; + uint32_t multiplier, multiplicand; + uint64_t result; + int32_t ret_value; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + multiplier = (uint32_t) regs->getValue(rs1); + multiplicand = (uint32_t) regs->getValue(rs2); + + result = (uint64_t) multiplier * (uint64_t) multiplicand; + ret_value = (uint32_t) (result >> 32) & 0x00000000FFFFFFFF; + regs->setValue(rd, ret_value); + + log->SC_log(Log::INFO) << std::dec << "MULHU: x" << rs1 << " * x" << rs2 + << " -> x" << rd << "(" << ret_value << ")" << std::endl; + + return true; +} + +bool M_extension::Exec_M_DIV() { + int rd, rs1, rs2; + int32_t divisor, dividend; + int64_t result; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + dividend = regs->getValue(rs1); + divisor = regs->getValue(rs2); + + if (divisor == 0) { + result = -1; + } else if ((divisor == -1) && (dividend == (int32_t) 0x80000000)) { + result = 0x0000000080000000; + } else { + result = dividend / divisor; + result = result & 0x00000000FFFFFFFF; + } + + regs->setValue(rd, result); + + log->SC_log(Log::INFO) << std::dec << "DIV: x" << rs1 << " / x" << rs2 + << " -> x" << rd << "(" << result << ")" << std::endl; + + return true; +} + +bool M_extension::Exec_M_DIVU() { + int rd, rs1, rs2; + uint32_t divisor, dividend; + uint64_t result; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + dividend = regs->getValue(rs1); + divisor = regs->getValue(rs2); + + if (divisor == 0) { + result = -1; + } else { + result = dividend / divisor; + result = result & 0x00000000FFFFFFFF; + } + + regs->setValue(rd, result); + + log->SC_log(Log::INFO) << std::dec << "DIVU: x" << rs1 << " / x" << rs2 + << " -> x" << rd << "(" << result << ")" << std::endl; + + return true; +} + +bool M_extension::Exec_M_REM() { + int rd, rs1, rs2; + int32_t divisor, dividend; + int32_t result; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + dividend = regs->getValue(rs1); + divisor = regs->getValue(rs2); + + if (divisor == 0) { + result = dividend; + } else if ((divisor == -1) && (dividend == (int32_t) 0x80000000)) { + result = 0; + } else { + result = dividend % divisor; + } + + regs->setValue(rd, result); + + log->SC_log(Log::INFO) << std::dec << "REM: x" << rs1 << " / x" << rs2 + << " -> x" << rd << "(" << result << ")" << std::endl; + + return true; +} + +bool M_extension::Exec_M_REMU() { + int rd, rs1, rs2; + uint32_t divisor, dividend; + uint32_t result; + + rd = get_rd(); + rs1 = get_rs1(); + rs2 = get_rs2(); + + dividend = regs->getValue(rs1); + divisor = regs->getValue(rs2); + + if (divisor == 0) { + result = dividend; + } else { + result = dividend % divisor; + } + + regs->setValue(rd, result); + + log->SC_log(Log::INFO) << std::dec << "REMU: x" << rs1 << " / x" << rs2 + << " -> x" << rd << "(" << result << ")" << std::endl; + + return true; +} + +bool M_extension::process_instruction(Instruction &inst) { + bool PC_not_affected = true; + + setInstr(inst.getInstr()); + + 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; + default: + std::cout << "M instruction not implemented yet" << std::endl; + inst.dump(); + //NOP(inst); + sc_core::sc_stop(); + break; + } + + return PC_not_affected; +} diff --git a/src/Memory.cpp b/src/Memory.cpp index b28b872..cad9da0 100644 --- a/src/Memory.cpp +++ b/src/Memory.cpp @@ -1,191 +1,200 @@ +/*! + \file Memory.cpp + \brief Basic TLM-2 memory model + \author Màrius Montón + \date August 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + #include "Memory.h" - SC_HAS_PROCESS(Memory); -Memory::Memory(sc_module_name name, string filename): sc_module(name) - ,socket("socket") - ,LATENCY(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 name, std::string 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); - mem = new uint8_t[SIZE]; - //memset(mem, 0, SIZE*sizeof(uint8_t)); + mem = new uint8_t[SIZE]; + //memset(mem, 0, SIZE*sizeof(uint8_t)); - memory_offset = 0; - readHexFile(filename); + memory_offset = 0; + readHexFile(filename); - log = Log::getInstance(); - log->SC_log(Log::INFO) << "Using file: " << filename << endl; + log = Log::getInstance(); + log->SC_log(Log::INFO) << "Using file: " << filename << std::endl; } -Memory::Memory(sc_module_name name, bool use_file): sc_module(name) - ,socket("socket") - ,LATENCY(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); - memory_offset = 0; - program_counter = 0; - //memset(mem, 0, SIZE*sizeof(uint8_t)); - // - mem = new uint8_t[SIZE]; - log = Log::getInstance(); - log->SC_log(Log::INFO) << "Memory instantiated wihtout file" << endl; - } +Memory::Memory(sc_core::sc_module_name name, bool use_file) : + 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); + memory_offset = 0; + program_counter = 0; + + mem = new uint8_t[SIZE]; + + log = Log::getInstance(); + log->SC_log(Log::INFO) << "Memory instantiated wihtout file" << std::endl; +} - Memory::~Memory() { - delete mem; + delete[] mem; } uint32_t Memory::getPCfromHEX() { - return program_counter; + return program_counter; } -void Memory::b_transport( tlm::tlm_generic_payload& trans, 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(); +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(); - adr = adr - memory_offset; - // Obliged to check address range and check for unsupported features, - // i.e. byte enables, streaming, and bursts - // Can ignore extensions + adr = adr - memory_offset; + // Obliged to check address range and check for unsupported features, + // i.e. byte enables, streaming, and bursts + // Can ignore extensions - // ********************************************* - // Generate the appropriate error response - // ********************************************* + // ********************************************* + // Generate the appropriate error response + // ********************************************* - if (adr >= sc_dt::uint64(SIZE)) { - trans.set_response_status( tlm::TLM_ADDRESS_ERROR_RESPONSE ); - return; - } - if (byt != 0) { - 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; - } + if (adr >= sc_dt::uint64(SIZE)) { + trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE); + return; + } + if (byt != 0) { + 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 ) - memcpy(ptr, &mem[adr], len); - else if ( cmd == tlm::TLM_WRITE_COMMAND ) - memcpy(&mem[adr], ptr, len); + // Obliged to implement read and write commands + if (cmd == tlm::TLM_READ_COMMAND) + memcpy(ptr, &mem[adr], len); + else if (cmd == tlm::TLM_WRITE_COMMAND) + memcpy(&mem[adr], ptr, len); - // Illustrates that b_transport may block - wait(delay); + // Illustrates that b_transport may block + wait(delay); - // Reset timing annotation after waiting - delay = SC_ZERO_TIME; + // Reset timing annotation after waiting + delay = sc_core::SC_ZERO_TIME; - // ********************************************* - // Set DMI hint to indicated that DMI is supported - // ********************************************* + // ********************************************* + // Set DMI hint to indicated that DMI is supported + // ********************************************* - if (memory_offset == 0) { - trans.set_dmi_allowed(true); - } else { - trans.set_dmi_allowed(false); - } + if (memory_offset == 0) { + trans.set_dmi_allowed(true); + } else { + trans.set_dmi_allowed(false); + } - // Obliged to set response status to indicate successful completion - trans.set_response_status( tlm::TLM_OK_RESPONSE ); + // 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) -{ - if (memory_offset != 0) { - return false; - } - - // Permit read and write access - dmi_data.allow_read_write(); +bool Memory::get_direct_mem_ptr(tlm::tlm_generic_payload &trans, + tlm::tlm_dmi &dmi_data) { + if (memory_offset != 0) { + return false; + } - // 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( SIZE*4-1 ); - dmi_data.set_read_latency( LATENCY ); - dmi_data.set_write_latency( LATENCY ); + // Permit read and write access + dmi_data.allow_read_write(); - return true; + // 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(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(); +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(); - // Calculate the number of bytes to be actually copied - unsigned int num_bytes = (len < (SIZE - adr) * 4) ? len : (SIZE - adr) * 4; + // Calculate the number of bytes to be actually copied + unsigned int num_bytes = (len < (SIZE - adr) * 4) ? len : (SIZE - adr) * 4; - if ( cmd == tlm::TLM_READ_COMMAND ) - memcpy(ptr, &mem[adr], num_bytes); - else if ( cmd == tlm::TLM_WRITE_COMMAND ) - memcpy(&mem[adr], ptr, num_bytes); + if (cmd == tlm::TLM_READ_COMMAND) + memcpy(ptr, &mem[adr], num_bytes); + else if (cmd == tlm::TLM_WRITE_COMMAND) + memcpy(&mem[adr], ptr, num_bytes); - return num_bytes; + return num_bytes; } -void Memory::readHexFile(string filename) { - ifstream hexfile; - string line; - int byte_count; - uint32_t address; - int i = 0; - uint32_t extended_address = 0; +void Memory::readHexFile(std::string filename) { + std::ifstream hexfile; + std::string line; + int byte_count; + uint32_t address; + int i = 0; + uint32_t extended_address = 0; - hexfile.open(filename); + hexfile.open(filename); - if (hexfile.is_open()) { - while(getline(hexfile, line) ) { - if (line[0] == ':') { - if (line.substr(7,2) == "00") { - /* Data */ - byte_count = stol(line.substr(1,2), nullptr, 16); - address = stol(line.substr(3,4), nullptr, 16); - address = address + extended_address; - //cout << "00 address 0x" << hex << address << endl; - for (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; - cout << "02 extended address 0x" << hex << extended_address << dec << endl; - } else if (line.substr(7,2) == "03") { - /* Start segment address */ - 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; - cout << "03 PC set to 0x" << hex << program_counter << dec << endl; - } else if (line.substr(7,2) == "04") { - /* Start segment address */ - memory_offset = stol(line.substr(9,4), nullptr, 16) << 16; - extended_address = 0; - cout << "04 address set to 0x" << hex << extended_address << dec << endl; - cout << "04 offset set to 0x" << hex << memory_offset << dec << endl; - } else if (line.substr(7,2) == "05") { - program_counter = stol(line.substr(9,8), nullptr, 16); - cout << "05 PC set to 0x" << hex << program_counter << dec << endl; - } - } - } - hexfile.close(); - } else { - SC_REPORT_ERROR("Memory", "Open file error"); - } + if (hexfile.is_open()) { + while (getline(hexfile, line)) { + if (line[0] == ':') { + if (line.substr(7, 2) == "00") { + /* Data */ + byte_count = stol(line.substr(1, 2), nullptr, 16); + address = stol(line.substr(3, 4), nullptr, 16); + address = address + extended_address; + //cout << "00 address 0x" << hex << address << endl; + for (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 */ + 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(); + } else { + SC_REPORT_ERROR("Memory", "Open file error"); + } } diff --git a/src/MemoryInterface.cpp b/src/MemoryInterface.cpp new file mode 100644 index 0000000..c2043e4 --- /dev/null +++ b/src/MemoryInterface.cpp @@ -0,0 +1,66 @@ +/*! + \file MemoryInterface.cpp + \brief CPU to Memory Interface class + \author Màrius Montón + \date May 2020 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "MemoryInterface.h" + + +MemoryInterface::MemoryInterface() : + data_bus("data_bus") { + +} + +/** + * Access data memory to get data + * @param addr address to access to + * @param size size of the data to read in bytes + * @return data value read + */ +uint32_t MemoryInterface::readDataMem(uint32_t addr, int size) { + 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(0); // 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); + + if (trans.is_response_error()) { + SC_REPORT_ERROR("Memory", "Read memory"); + } + return data; +} + +/** + * Acces data memory to write data + * @brief + * @param addr addr address to access to + * @param data data to write + * @param size size of the data to write in bytes + */ +void MemoryInterface::writeDataMem(uint32_t addr, 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(0); // 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); +} diff --git a/src/Performance.cpp b/src/Performance.cpp index 6259af9..360d88b 100644 --- a/src/Performance.cpp +++ b/src/Performance.cpp @@ -1,34 +1,41 @@ +/*! + \file Performance.cpp + \brief Class to store performance of CPU + \author Màrius Montón + \date Aug 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + #include "Performance.h" -Performance* Performance::getInstance() -{ - if (instance == 0) - { - instance = new Performance(); - } +Performance* Performance::getInstance() { + if (instance == 0) { + instance = new Performance(); + } - return instance; + return instance; } -Performance::Performance() -{ - data_memory_read = 0; - data_memory_write = 0; - code_memory_read = 0; - code_memory_write = 0; - register_read = 0; - register_write = 0; - instructions_executed = 0; +Performance::Performance() { + data_memory_read = 0; + data_memory_write = 0; + code_memory_read = 0; + code_memory_write = 0; + register_read = 0; + register_write = 0; + instructions_executed = 0; } void Performance::dump() { - cout << dec << "# data memory reads: " << data_memory_read << endl; - cout << "# data memory writes: " << data_memory_write << endl; - cout << "# code memory reads: " << code_memory_read << endl; - cout << "# code memory writes: " << code_memory_write << endl; - cout << "# registers read: " << register_read << endl; - cout << "# registers write: " << register_write << endl; - cout << "# instructions executed: " << instructions_executed << endl; + std::cout << std::dec << "# data memory reads: " << data_memory_read + << std::endl; + std::cout << "# data memory writes: " << data_memory_write << std::endl; + std::cout << "# code memory reads: " << code_memory_read << std::endl; + std::cout << "# code memory writes: " << code_memory_write << std::endl; + std::cout << "# registers read: " << register_read << std::endl; + std::cout << "# registers write: " << register_write << std::endl; + std::cout << "# instructions executed: " << instructions_executed + << std::endl; } -Performance* Performance::instance = 0; +Performance *Performance::instance = 0; diff --git a/src/Registers.cpp b/src/Registers.cpp index f1e8e78..b49f6f8 100644 --- a/src/Registers.cpp +++ b/src/Registers.cpp @@ -1,141 +1,180 @@ /*! - \file Registers.cpp - \brief Basic register file implementation - \author Màrius Montón - \date August 2018 -*/ + \file Registers.cpp + \brief Basic register file implementation + \author Màrius Montón + \date August 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later #include "Registers.h" Registers::Registers() { - memset(register_bank, 0, sizeof(uint32_t)*32); // 32 registers of 32 bits each - memset(CSR, 0, sizeof(uint32_t)*4096); - perf = Performance::getInstance(); + memset(register_bank, 0, sizeof(uint32_t) * 32); // 32 registers of 32 bits each + memset(CSR, 0, sizeof(uint32_t) * 4096); + perf = Performance::getInstance(); - initCSR(); + initCSR(); - //cout << "Memory size: 0x" << hex << Memory::SIZE << endl; - //cout << "SP address: 0x" << hex << (0x10000000 / 4) - 1 << endl; + //std::cout << "Memory size: 0x" << std::hex << Memory::SIZE << std::endl; + //std::cout << "SP address: 0x" << std::hex << (0x10000000 / 4) - 1 << std::endl; - register_bank[sp] = Memory::SIZE-4; // default stack at the end of the memory - register_PC = 0x80000000; // default _start address + register_bank[sp] = Memory::SIZE - 4; // default stack at the end of the memory + register_PC = 0x80000000; // default _start address } void Registers::dump(void) { - cout << "************************************" << endl; - cout << "Registers dump" << dec << endl; - cout << "x0 (zero): " << right << setw(11) << register_bank[0]; - cout << " x1 (ra): " << right << setw(11) << register_bank[1]; - cout << " x2 (sp): " << right << setw(11) << register_bank[2]; - cout << " x3 (gp): " << right << setw(11) << register_bank[3] << endl; + std::cout << "************************************" << std::endl; + std::cout << "Registers dump" << std::dec << std::endl; + std::cout << "x0 (zero): " << std::right << std::setw(11) + << register_bank[0]; + std::cout << " x1 (ra): " << std::right << std::setw(11) + << register_bank[1]; + std::cout << " x2 (sp): " << std::right << std::setw(11) + << register_bank[2]; + std::cout << " x3 (gp): " << std::right << std::setw(11) + << register_bank[3] << std::endl; - cout << "x4 (tp): " << right << setw(11) << register_bank[4]; - cout << " x5 (t0): " << right << setw(11) << register_bank[5]; - cout << " x6 (t1): " << right << setw(11) << register_bank[6]; - cout << " x7 (t2): " << right << setw(11) << register_bank[7] << endl; + std::cout << "x4 (tp): " << std::right << std::setw(11) + << register_bank[4]; + std::cout << " x5 (t0): " << std::right << std::setw(11) + << register_bank[5]; + std::cout << " x6 (t1): " << std::right << std::setw(11) + << register_bank[6]; + std::cout << " x7 (t2): " << std::right << std::setw(11) + << register_bank[7] << std::endl; - cout << "x8 (s0/fp): " << right << setw(11) << register_bank[8]; - cout << " x9 (s1): " << right << setw(11) << register_bank[9]; - cout << " x10 (a0): " << right << setw(11) << register_bank[10]; - cout << " x11 (a1): " << right << setw(11) << register_bank[11] << endl; + std::cout << "x8 (s0/fp): " << std::right << std::setw(11) + << register_bank[8]; + std::cout << " x9 (s1): " << std::right << std::setw(11) + << register_bank[9]; + std::cout << " x10 (a0): " << std::right << std::setw(11) + << register_bank[10]; + std::cout << " x11 (a1): " << std::right << std::setw(11) + << register_bank[11] << std::endl; - cout << "x12 (a2): " << right << setw(11) << register_bank[12]; - cout << " x13 (a3): " << right << setw(11) << register_bank[13]; - cout << " x14 (a4): " << right << setw(11) << register_bank[14]; - cout << " x15 (a5): " << right << setw(11) << register_bank[15] << endl; + std::cout << "x12 (a2): " << std::right << std::setw(11) + << register_bank[12]; + std::cout << " x13 (a3): " << std::right << std::setw(11) + << register_bank[13]; + std::cout << " x14 (a4): " << std::right << std::setw(11) + << register_bank[14]; + std::cout << " x15 (a5): " << std::right << std::setw(11) + << register_bank[15] << std::endl; - cout << "x16 (a6): " << right << setw(11) << register_bank[16]; - cout << " x17 (a7): " << right << setw(11) << register_bank[17]; - cout << " x18 (s2): " << right << setw(11) << register_bank[18]; - cout << " x19 (s3): " << right << setw(11) << register_bank[19] << endl; + std::cout << "x16 (a6): " << std::right << std::setw(11) + << register_bank[16]; + std::cout << " x17 (a7): " << std::right << std::setw(11) + << register_bank[17]; + std::cout << " x18 (s2): " << std::right << std::setw(11) + << register_bank[18]; + std::cout << " x19 (s3): " << std::right << std::setw(11) + << register_bank[19] << std::endl; - cout << "x20 (s4): " << right << setw(11) << register_bank[20]; - cout << " x21 (s5): " << right << setw(11) << register_bank[21]; - cout << " x22 (s6): " << right << setw(11) << register_bank[22]; - cout << " x23 (s7): " << right << setw(11) << register_bank[23] << endl; + std::cout << "x20 (s4): " << std::right << std::setw(11) + << register_bank[20]; + std::cout << " x21 (s5): " << std::right << std::setw(11) + << register_bank[21]; + std::cout << " x22 (s6): " << std::right << std::setw(11) + << register_bank[22]; + std::cout << " x23 (s7): " << std::right << std::setw(11) + << register_bank[23] << std::endl; - cout << "x24 (s8): " << right << setw(11) << register_bank[24]; - cout << " x25 (s9): " << right << setw(11) << register_bank[25]; - cout << " x26 (s10): " << right << setw(11) << register_bank[26]; - cout << " x27 (s11): " << right << setw(11) << register_bank[27] << endl; + std::cout << "x24 (s8): " << std::right << std::setw(11) + << register_bank[24]; + std::cout << " x25 (s9): " << std::right << std::setw(11) + << register_bank[25]; + std::cout << " x26 (s10): " << std::right << std::setw(11) + << register_bank[26]; + std::cout << " x27 (s11): " << std::right << std::setw(11) + << register_bank[27] << std::endl; - cout << "x28 (t3): " << right << setw(11) << register_bank[28]; - cout << " x29 (t4): " << right << setw(11) << register_bank[29]; - cout << " x30 (t5): " << right << setw(11) << register_bank[30]; - cout << " x31 (t6): " << right << setw(11) << register_bank[31] << endl; + std::cout << "x28 (t3): " << std::right << std::setw(11) + << register_bank[28]; + std::cout << " x29 (t4): " << std::right << std::setw(11) + << register_bank[29]; + std::cout << " x30 (t5): " << std::right << std::setw(11) + << register_bank[30]; + std::cout << " x31 (t6): " << std::right << std::setw(11) + << register_bank[31] << std::endl; - cout << "PC: 0x" << hex << register_PC << dec << endl; - cout << "************************************" << endl; + std::cout << "PC: 0x" << std::hex << register_PC << std::dec << std::endl; + std::cout << "************************************" << std::endl; } - void Registers::setValue(int reg_num, int32_t value) { - if ((reg_num != 0) && (reg_num < 32)) { - register_bank[reg_num] = value; - perf->registerWrite(); - } + if ((reg_num != 0) && (reg_num < 32)) { + register_bank[reg_num] = value; + perf->registerWrite(); + } } int32_t Registers::getValue(int reg_num) { - if ((reg_num >= 0) && (reg_num < 32)){ - perf->registerRead(); - return register_bank[reg_num]; - } else { - return 0xFFFFFFFF; - } + if ((reg_num >= 0) && (reg_num < 32)) { + perf->registerRead(); + return register_bank[reg_num]; + } else { + return 0xFFFFFFFF; + } } uint32_t Registers::getPC() { - return register_PC; + return register_PC; } void Registers::setPC(uint32_t new_pc) { - register_PC = new_pc; + register_PC = new_pc; } uint32_t Registers::getCSR(int csr) { - uint32_t ret_value = 0; + uint32_t ret_value = 0; - switch (csr) { - case CSR_CYCLE: - case CSR_MCYCLE: - ret_value = (uint64_t)(sc_time(sc_time_stamp() - - sc_time(SC_ZERO_TIME)).to_double()) & 0x00000000FFFFFFFF; - break; - case CSR_CYCLEH: - case CSR_MCYCLEH: - ret_value = (uint32_t)((uint64_t)(sc_time(sc_time_stamp() - - sc_time(SC_ZERO_TIME)).to_double()) >> 32 & 0x00000000FFFFFFFF); - break; - case CSR_TIME: - ret_value = (uint64_t)(sc_time(sc_time_stamp() - - sc_time(SC_ZERO_TIME)).to_double()) & 0x00000000FFFFFFFF; - break; - case CSR_TIMEH: - ret_value = (uint32_t)((uint64_t)(sc_time(sc_time_stamp() - - sc_time(SC_ZERO_TIME)).to_double()) >> 32 & 0x00000000FFFFFFFF); - break; - default: - ret_value = CSR[csr]; - break; - } - return ret_value; + switch (csr) { + case CSR_CYCLE: + case CSR_MCYCLE: + ret_value = (uint64_t) (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 = (uint32_t) ((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 = (uint64_t) (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 = (uint32_t) ((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; + default: + ret_value = CSR[csr]; + break; + } + return ret_value; } - void Registers::setCSR(int csr, uint32_t value) { - /* @FIXME: rv32mi-p-ma_fetch tests doesn't allow MISA to writable, - * but Volume II: Privileged Architectura v1.10 says MISRA is writable (?) - */ - if (csr != CSR_MISA) { - CSR[csr] = value; - } + /* @FIXME: rv32mi-p-ma_fetch tests doesn't allow MISA to writable, + * but Volume II: Privileged Architectura v1.10 says MISRA 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 ; + CSR[CSR_MISA] = MISA_MXL | MISA_M_EXTENSION | MISA_C_EXTENSION + | MISA_A_EXTENSION | MISA_I_BASE; + CSR[CSR_MSTATUS] = MISA_MXL; } diff --git a/src/Simulator.cpp b/src/Simulator.cpp index 8c24c68..2cc2320 100644 --- a/src/Simulator.cpp +++ b/src/Simulator.cpp @@ -1,9 +1,9 @@ /*! - \file Simulator.cpp - \brief Top level simulation entity - \author Màrius Montón - \date September 2018 -*/ + \file Simulator.cpp + \brief Top level simulation entity + \author Màrius Montón + \date September 2018 + */ #define SC_INCLUDE_DYNAMIC_PROCESSES @@ -21,11 +21,7 @@ #include "Trace.h" #include "Timer.h" -using namespace sc_core; -using namespace sc_dt; -using namespace std; - -string filename; +std::string filename; /** * @class Simulator @@ -34,57 +30,55 @@ string filename; * * @brief Top simulation entity */ -SC_MODULE(Simulator) -{ - CPU *cpu; - Memory *MainMemory; - BusCtrl* Bus; - Trace *trace; - Timer *timer; +SC_MODULE(Simulator) { + CPU *cpu; + Memory *MainMemory; + BusCtrl *Bus; + Trace *trace; + Timer *timer; - uint32_t start_PC; + uint32_t start_PC; - SC_CTOR(Simulator) - { - MainMemory = new Memory("Main_Memory", filename); - start_PC = MainMemory->getPCfromHEX(); + SC_CTOR(Simulator) { + MainMemory = new Memory("Main_Memory", filename); + start_PC = MainMemory->getPCfromHEX(); - cpu = new CPU("cpu", start_PC); + cpu = new CPU("cpu", start_PC); - Bus = new BusCtrl("BusCtrl"); - trace = new Trace("Trace"); - timer = new Timer("Timer"); + Bus = new BusCtrl("BusCtrl"); + trace = new Trace("Trace"); + timer = new Timer("Timer"); - cpu->instr_bus.bind(Bus->cpu_instr_socket); - cpu->exec->data_bus.bind(Bus->cpu_data_socket); + cpu->instr_bus.bind(Bus->cpu_instr_socket); + cpu->mem_intf->data_bus.bind(Bus->cpu_data_socket); - Bus->memory_socket.bind(MainMemory->socket); - Bus->trace_socket.bind(trace->socket); - Bus->timer_socket.bind(timer->socket); + Bus->memory_socket.bind(MainMemory->socket); + Bus->trace_socket.bind(trace->socket); + Bus->timer_socket.bind(timer->socket); - //timer->timer_irq.bind(IRQ); - // cpu->interrupt.bind(IRQ); - timer->irq_line.bind(cpu->irq_line_socket); - } + //timer->timer_irq.bind(IRQ); + // cpu->interrupt.bind(IRQ); + timer->irq_line.bind(cpu->irq_line_socket); + } - ~Simulator() { - delete cpu; - delete MainMemory; - delete Bus; - delete trace; - delete timer; - } + ~Simulator() { + delete MainMemory; + delete cpu; + delete Bus; + delete trace; + delete timer; + } }; Simulator *top; void intHandler(int dummy) { - delete top; - //sc_stop(); - exit(-1); + delete top; + //sc_stop(); + exit(-1); } -void process_arguments(int argc, char* argv[]) { +void process_arguments(int argc, char *argv[]) { int c; int debug_level; @@ -92,35 +86,36 @@ void process_arguments(int argc, char* argv[]) { log = Log::getInstance(); log->setLogLevel(Log::ERROR); - while ((c = getopt (argc, argv, "D:f:?")) != -1) { + while ((c = getopt(argc, argv, "D:f:?")) != -1) { switch (c) { - case 'D': - debug_level = atoi(optarg); + case 'D': + debug_level = atoi(optarg); - switch (debug_level) { - case 3: - log->setLogLevel(Log::INFO); - break; - case 2: - log->setLogLevel(Log::WARNING); - break; - case 1: - log->setLogLevel(Log::DEBUG); - break; - case 0: - log->setLogLevel(Log::ERROR); - break; - default: - log->setLogLevel(Log::INFO); - break; - } + switch (debug_level) { + case 3: + log->setLogLevel(Log::INFO); break; - case 'f' : - filename = std::string(optarg); + case 2: + log->setLogLevel(Log::WARNING); break; - case '?' : - std::cout << "Call ./RISCV_TLM -D (0..3) filename.hex" << std::endl; + case 1: + log->setLogLevel(Log::DEBUG); break; + case 0: + log->setLogLevel(Log::ERROR); + break; + default: + log->setLogLevel(Log::INFO); + break; + } + break; + case 'f': + filename = std::string(optarg); + break; + case '?': + std::cout << "Call ./RISCV_TLM -D (0..3) filename.hex" + << std::endl; + break; } } @@ -129,26 +124,25 @@ void process_arguments(int argc, char* argv[]) { } } -int sc_main(int argc, char* argv[]) -{ +int sc_main(int argc, char *argv[]) { - /* Capture Ctrl+C and finish the simulation */ - signal(SIGINT, intHandler); + /* Capture Ctrl+C and finish the simulation */ + signal(SIGINT, intHandler); - /* SystemC time resolution set to 1 ns*/ - sc_set_time_resolution(1, SC_NS); + /* SystemC time resolution set to 1 ns*/ + sc_core::sc_set_time_resolution(1, sc_core::SC_NS); - /* Parse and process program arguments. -f is mandatory */ - process_arguments(argc, argv); + /* Parse and process program arguments. -f is mandatory */ + process_arguments(argc, argv); - top = new Simulator("top"); - sc_start(); - - cout << "Press Enter to finish" << endl; - cin.ignore(); - - // call all destructors, clean exit. - delete top; - - return 0; + top = new Simulator("top"); + sc_core::sc_start(); + + std::cout << "Press Enter to finish" << std::endl; + std::cin.ignore(); + + // call all destructors, clean exit. + delete top; + + return 0; } diff --git a/src/Timer.cpp b/src/Timer.cpp index b396a38..cad358a 100644 --- a/src/Timer.cpp +++ b/src/Timer.cpp @@ -1,84 +1,93 @@ +/*! + \file Timer.cpp + \brief Basic TLM-2 Timer module + \author Màrius Montón + \date January 2019 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + #include "Timer.h" SC_HAS_PROCESS(Timer); -Timer::Timer(sc_module_name name): sc_module(name) - ,socket("timer_socket"), m_mtime(0), m_mtimecmp(0) { +Timer::Timer(sc_core::sc_module_name name) : + sc_module(name), socket("timer_socket"), m_mtime(0), m_mtimecmp(0) { - socket.register_b_transport(this, &Timer::b_transport); + socket.register_b_transport(this, &Timer::b_transport); - SC_THREAD(run); - } + SC_THREAD(run); +} void Timer::run() { - tlm::tlm_generic_payload* irq_trans = new tlm::tlm_generic_payload; - sc_time delay = SC_ZERO_TIME; - 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( 0 ); - irq_trans->set_dmi_allowed(false); - irq_trans->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); - irq_trans->set_address( 0 ); + tlm::tlm_generic_payload *irq_trans = new tlm::tlm_generic_payload; + sc_core::sc_time delay = sc_core::SC_ZERO_TIME; + 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(0); + irq_trans->set_dmi_allowed(false); + irq_trans->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); + irq_trans->set_address(0); - while(true) { - wait(timer_event); - irq_line->b_transport(*irq_trans, delay); - } + while (true) { + wait(timer_event); + irq_line->b_transport(*irq_trans, delay); + } } -void Timer::b_transport( tlm::tlm_generic_payload& trans, sc_time& 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(); - //unsigned char* byt = trans.get_byte_enable_ptr(); - //unsigned int wid = trans.get_streaming_width(); +void Timer::b_transport(tlm::tlm_generic_payload &trans, + sc_core::sc_time &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(); + //unsigned char* byt = trans.get_byte_enable_ptr(); + //unsigned int wid = trans.get_streaming_width(); - uint32_t aux_value = 0; - uint64_t notify_time = 0; + uint32_t aux_value = 0; + uint64_t notify_time = 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; - // notify needs relative time, mtimecmp works in absolute time - notify_time = m_mtimecmp - m_mtime; + // notify needs relative time, mtimecmp works in absolute time + notify_time = m_mtimecmp - m_mtime; - timer_event.notify( sc_time(notify_time, SC_NS) ); - break; - } - } else { // TLM_READ_COMMAND - switch (addr) { - case TIMER_MEMORY_ADDRESS_LO: - m_mtime = 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; - } - memcpy(ptr, &aux_value, len); - } + timer_event.notify(sc_core::sc_time(notify_time, sc_core::SC_NS)); + break; + } + } 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; + } + memcpy(ptr, &aux_value, len); + } - trans.set_response_status( tlm::TLM_OK_RESPONSE ); + trans.set_response_status(tlm::TLM_OK_RESPONSE); } diff --git a/src/Trace.cpp b/src/Trace.cpp index a656b91..699a210 100644 --- a/src/Trace.cpp +++ b/src/Trace.cpp @@ -1,3 +1,11 @@ +/*! + \file Trace.cpp + \brief Basic TLM-2 Trace module + \author Màrius Montón + \date September 2018 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + #include #include #include @@ -10,105 +18,100 @@ #include #include -// Code taken from +// Code partially taken from // https://github.com/embecosm/esp1-systemc-tlm/blob/master/sysc-models/simple-soc/TermSC.h #include "Trace.h" -void Trace::xtermLaunch( char *slaveName ) { - char *arg; - char *fin = &(slaveName[strlen( slaveName ) - 2]); - - if( NULL == 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 ); - } - - char *argv[3]; - argv[0] = (char *)( "xterm" ); - argv[1] = arg; - argv[2] = NULL; - - execvp( "xterm", argv ); +void Trace::xtermLaunch(char *slaveName) { + char *arg; + char *fin = &(slaveName[strlen(slaveName) - 2]); + + if ( NULL == 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); + } + + char *argv[3]; + argv[0] = (char*) ("xterm"); + argv[1] = arg; + argv[2] = NULL; + + execvp("xterm", argv); } -void Trace::xtermKill( const char *mess ) { - - - if( -1 != ptSlave ) { // Close down the slave - - close( ptSlave ); // Close the FD - ptSlave = -1; - } - - if( -1 != ptMaster ) { // Close down the master - close( ptMaster ); - ptMaster = -1; - } - - if( xtermPid > 0 ) { // Kill the terminal - kill( xtermPid, SIGKILL ); - waitpid( xtermPid, NULL, 0 ); - } - - if( NULL != mess ) { // If we really want a message - perror( mess ); - } - - +void Trace::xtermKill(const char *mess) { + + if (-1 != ptSlave) { // Close down the slave + close(ptSlave); // Close the FD + ptSlave = -1; + } + + if (-1 != ptMaster) { // Close down the master + close(ptMaster); + ptMaster = -1; + } + + if (xtermPid > 0) { // Kill the terminal + kill(xtermPid, SIGKILL); + waitpid(xtermPid, NULL, 0); + } + + if ( NULL != mess) { // If we really want a message + perror(mess); + } + } void Trace::xtermSetup(void) { - ptMaster = open("/dev/ptmx", O_RDWR); + ptMaster = open("/dev/ptmx", O_RDWR); - if (ptMaster != -1) { - grantpt( ptMaster ); - - unlockpt( ptMaster ); - - char *ptSlaveName = ptsname( ptMaster ); - ptSlave = open( ptSlaveName, O_RDWR ); // In and out are the same - - struct termios termInfo; - tcgetattr( ptSlave, &termInfo ); - - termInfo.c_lflag &= ~ECHO; - termInfo.c_lflag &= ~ICANON; - tcsetattr( ptSlave, TCSADRAIN, &termInfo ); - - xtermPid = fork(); - - if (xtermPid == 0) { - xtermLaunch( ptSlaveName ); - } - } + if (ptMaster != -1) { + grantpt(ptMaster); + + unlockpt(ptMaster); + + char *ptSlaveName = ptsname(ptMaster); + ptSlave = open(ptSlaveName, O_RDWR); // In and out are the same + + struct termios termInfo; + tcgetattr(ptSlave, &termInfo); + + termInfo.c_lflag &= ~ECHO; + termInfo.c_lflag &= ~ICANON; + tcsetattr(ptSlave, TCSADRAIN, &termInfo); + + xtermPid = fork(); + + if (xtermPid == 0) { + xtermLaunch(ptSlaveName); + } + } } SC_HAS_PROCESS(Trace); -Trace::Trace(sc_module_name name): sc_module(name) -,socket("socket") { - - socket.register_b_transport(this, &Trace::b_transport); - - xtermSetup(); +Trace::Trace(sc_core::sc_module_name name) : + sc_module(name), socket("socket") { + + socket.register_b_transport(this, &Trace::b_transport); + + xtermSetup(); } Trace::~Trace() { - xtermKill( NULL ); + xtermKill( NULL); } -void Trace::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) { - //tlm::tlm_command cmd = trans.get_command(); - //sc_dt::uint64 adr = trans.get_address() / 4; - 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(); - - write(ptSlave, ptr, 1); - - trans.set_response_status( tlm::TLM_OK_RESPONSE ); + +void Trace::b_transport(tlm::tlm_generic_payload &trans, + sc_core::sc_time &delay) { + + unsigned char *ptr = trans.get_data_ptr(); + + write(ptSlave, ptr, 1); + + trans.set_response_status(tlm::TLM_OK_RESPONSE); } diff --git a/src/extension_base.cpp b/src/extension_base.cpp new file mode 100644 index 0000000..10dbca4 --- /dev/null +++ b/src/extension_base.cpp @@ -0,0 +1,70 @@ +/*! + \file extension_base.h + \brief Base class for ISA extensions + \author Màrius Montón + \date May 2020 + */ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "extension_base.h" + +extension_base::extension_base(sc_dt::sc_uint<32> instr, + Registers *register_bank, MemoryInterface *mem_interface) : + m_instr(instr), regs(register_bank), mem_intf(mem_interface) { + + perf = Performance::getInstance(); + log = Log::getInstance(); +} + +extension_base::~extension_base() { + +} +void extension_base::setInstr(uint32_t p_instr) { + m_instr = sc_dt::sc_uint<32>(p_instr); +} + +void extension_base::dump() { + std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; +} + +void extension_base::RaiseException(uint32_t cause, uint32_t inst) { + uint32_t new_pc, current_pc, m_cause; + + current_pc = regs->getPC(); + m_cause = regs->getCSR(CSR_MSTATUS); + m_cause |= cause; + + new_pc = regs->getCSR(CSR_MTVEC); + + regs->setCSR(CSR_MEPC, current_pc); + + if (cause == EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION) { + regs->setCSR(CSR_MTVAL, inst); + } else { + regs->setCSR(CSR_MTVAL, current_pc); + } + + regs->setCSR(CSR_MCAUSE, cause); + regs->setCSR(CSR_MSTATUS, m_cause); + + regs->setPC(new_pc); + + log->SC_log(Log::ERROR) << "Exception! new PC 0x" << std::hex << new_pc + << std::endl; + + regs->dump(); + std::cout << "Simulation time " << sc_core::sc_time_stamp() << std::endl; + perf->dump(); + SC_REPORT_ERROR("Exception", "Exception"); +} + +bool extension_base::NOP() { + std::cout << std::endl; + regs->dump(); + std::cout << "Simulation time " << sc_core::sc_time_stamp() << std::endl; + perf->dump(); + + SC_REPORT_ERROR("Execute", "NOP"); + + return true; +}