From d1fa3c752eeb2270c72a700173a5298c85d09d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Sun, 6 Feb 2022 11:41:37 +0100 Subject: [PATCH 01/17] Register class changed to templated to prepare for rv64 code --- inc/A_extension.h | 2 +- inc/BASE_ISA.h | 4 +- inc/CPU.h | 4 +- inc/C_extension.h | 2 +- inc/M_extension.h | 2 +- inc/Registers.h | 173 +++++++++++++++++++++++++++++++++++++---- inc/extension_base.h | 54 +++++++++++-- src/BASE_ISA.cpp | 4 +- src/CPU.cpp | 4 +- src/Debug.cpp | 2 +- src/Registers.cpp | 167 --------------------------------------- src/extension_base.cpp | 54 ------------- 12 files changed, 218 insertions(+), 254 deletions(-) diff --git a/inc/A_extension.h b/inc/A_extension.h index 019c243..8d7d569 100644 --- a/inc/A_extension.h +++ b/inc/A_extension.h @@ -52,7 +52,7 @@ namespace riscv_tlm { /** * @brief Instruction decoding and fields access */ - class A_extension : public extension_base { + class A_extension : public extension_base { public: /** diff --git a/inc/BASE_ISA.h b/inc/BASE_ISA.h index 6822149..3c2ec3a 100644 --- a/inc/BASE_ISA.h +++ b/inc/BASE_ISA.h @@ -92,13 +92,13 @@ namespace riscv_tlm { /** * @brief Risc_V execute module */ - class BASE_ISA : public extension_base { + class BASE_ISA : public extension_base { public: /** * @brief Constructor, same as base class */ - using extension_base::extension_base; + using extension_base::extension_base; /** * @brief Access to funct7 field diff --git a/inc/CPU.h b/inc/CPU.h index 2781383..054c442 100644 --- a/inc/CPU.h +++ b/inc/CPU.h @@ -67,10 +67,10 @@ namespace riscv_tlm { bool CPU_step(); - Registers *getRegisterBank() { return register_bank; } + Registers *getRegisterBank() { return register_bank; } private: - Registers *register_bank; + Registers *register_bank; Performance *perf; std::shared_ptr logger; C_extension *c_inst; diff --git a/inc/C_extension.h b/inc/C_extension.h index 3501bd6..7da29f1 100644 --- a/inc/C_extension.h +++ b/inc/C_extension.h @@ -95,7 +95,7 @@ namespace riscv_tlm { /** * @brief Instruction decoding and fields access */ - class C_extension : public extension_base { + class C_extension : public extension_base { public: /** diff --git a/inc/M_extension.h b/inc/M_extension.h index f1db0d4..073cd85 100644 --- a/inc/M_extension.h +++ b/inc/M_extension.h @@ -43,7 +43,7 @@ namespace riscv_tlm { /** * @brief Instruction decoding and fields access */ - class M_extension : public extension_base { + class M_extension : public extension_base { public: /** diff --git a/inc/Registers.h b/inc/Registers.h index d9e4a38..0812cf5 100644 --- a/inc/Registers.h +++ b/inc/Registers.h @@ -112,6 +112,7 @@ namespace riscv_tlm { /** * @brief Register file implementation */ + template class Registers { public: @@ -186,33 +187,56 @@ namespace riscv_tlm { /** * Default constructor */ - Registers(); + Registers() { + perf = Performance::getInstance(); + + initCSR(); + register_bank[sp] = Memory::SIZE - 4; // default stack at the end of the memory + register_PC = 0x80000000; // default _start address + }; /** * Set value for a register * @param reg_num register number * @param value register value */ - void setValue(int reg_num, std::int32_t value); + void setValue(int reg_num, T value) { + if ((reg_num != 0) && (reg_num < 32)) { + register_bank[reg_num] = value; + perf->registerWrite(); + } + } /** * Returns register value * @param reg_num register number * @return register value */ - std::uint32_t getValue(int reg_num) const; + T getValue(int reg_num) const { + if ((reg_num >= 0) && (reg_num < 32)) { + perf->registerRead(); + return register_bank[reg_num]; + } else { + /* TODO Exten sign for any possible T type */ + return static_cast(0xFFFFFFFF); + } + } /** * Returns PC value * @return PC value */ - std::uint32_t getPC() const; + T getPC() const { + return register_PC; + } /** * Sets arbitraty value to PC * @param new_pc new address to PC */ - void setPC(std::uint32_t new_pc); + void setPC(T new_pc) { + register_PC = new_pc; + } /** * Increments PC couunter to next address @@ -230,40 +254,163 @@ namespace riscv_tlm { * @param csr CSR number to access * @return CSR value */ - std::uint32_t getCSR(int csr); + T getCSR(int csr) { + T ret_value; + + switch (csr) { + case CSR_CYCLE: + case CSR_MCYCLE: + ret_value = static_cast(sc_core::sc_time( + sc_core::sc_time_stamp() + - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) + & 0x00000000FFFFFFFF; + break; + case CSR_CYCLEH: + case CSR_MCYCLEH: + ret_value = static_cast((std::uint64_t) (sc_core::sc_time( + sc_core::sc_time_stamp() + - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) + >> 32 & 0x00000000FFFFFFFF); + break; + case CSR_TIME: + ret_value = static_cast(sc_core::sc_time( + sc_core::sc_time_stamp() + - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) + & 0x00000000FFFFFFFF; + break; + case CSR_TIMEH: + ret_value = static_cast((std::uint64_t) (sc_core::sc_time( + sc_core::sc_time_stamp() + - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) + >> 32 & 0x00000000FFFFFFFF); + break; + [[likely]] default: + ret_value = CSR[csr]; + break; + } + return ret_value; + } /** * @brief Set CSR value * @param csr CSR number to access * @param value new value to register */ - void setCSR(int csr, std::uint32_t value); + void setCSR(int csr, T value) { + /* @FIXME: rv32mi-p-ma_fetch tests doesn't allow MISA to be writable, + * but Volume II: Privileged Architecture v1.10 says MISA is writable (?) + */ + if (csr != CSR_MISA) { + CSR[csr] = value; + } + } /** * Dump register data to console */ - void dump(); + void dump() { + std::cout << "************************************" << std::endl; + std::cout << "Registers dump" << std::dec << std::endl; + std::cout << std::setfill('0') << std::uppercase; + std::cout << "x0 (zero): 0x" << std::right << std::setw(8) + << std::hex << register_bank[0]; + std::cout << " x1 (ra): 0x" << std::right << std::setw(8) + << std::hex << register_bank[1]; + std::cout << " x2 (sp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[2]; + std::cout << " x3 (gp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[3] << std::endl; + + std::cout << "x4 (tp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[4]; + std::cout << " x5 (t0): 0x" << std::right << std::setw(8) + << std::hex << register_bank[5]; + std::cout << " x6 (t1): 0x" << std::right << std::setw(8) + << std::hex << register_bank[6]; + std::cout << " x7 (t2): 0x" << std::right << std::setw(8) + << std::hex << register_bank[7] << std::endl; + + std::cout << "x8 (s0/fp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[8]; + std::cout << " x9 (s1): 0x" << std::right << std::setw(8) + << std::hex << register_bank[9]; + std::cout << " x10 (a0): 0x" << std::right << std::setw(8) + << std::hex << register_bank[10]; + std::cout << " x11 (a1): 0x" << std::right << std::setw(8) + << std::hex << register_bank[11] << std::endl; + + std::cout << "x12 (a2): 0x" << std::right << std::setw(8) + << std::hex << register_bank[12]; + std::cout << " x13 (a3): 0x" << std::right << std::setw(8) + << std::hex << register_bank[13]; + std::cout << " x14 (a4): 0x" << std::right << std::setw(8) + << std::hex << register_bank[14]; + std::cout << " x15 (a5): 0x" << std::right << std::setw(8) + << std::hex << register_bank[15] << std::endl; + + std::cout << "x16 (a6): 0x" << std::right << std::setw(8) + << std::hex << register_bank[16]; + std::cout << " x17 (a7): 0x" << std::right << std::setw(8) + << std::hex << register_bank[17]; + std::cout << " x18 (s2): 0x" << std::right << std::setw(8) + << std::hex << register_bank[18]; + std::cout << " x19 (s3): 0x" << std::right << std::setw(8) + << std::hex << register_bank[19] << std::endl; + + std::cout << "x20 (s4): 0x" << std::right << std::setw(8) + << std::hex << register_bank[20]; + std::cout << " x21 (s5): 0x" << std::right << std::setw(8) + << std::hex << register_bank[21]; + std::cout << " x22 (s6): 0x" << std::right << std::setw(8) + << std::hex << register_bank[22]; + std::cout << " x23 (s7): 0x" << std::right << std::setw(8) + << std::hex << register_bank[23] << std::endl; + + std::cout << "x24 (s8): 0x" << std::right << std::setw(8) + << std::hex << register_bank[24]; + std::cout << " x25 (s9): 0x" << std::right << std::setw(8) + << std::hex << register_bank[25]; + std::cout << " x26 (s10): 0x" << std::right << std::setw(8) + << std::hex << register_bank[26]; + std::cout << " x27 (s11): 0x" << std::right << std::setw(8) + << std::hex << register_bank[27] << std::endl; + + std::cout << "x28 (t3): 0x" << std::right << std::setw(8) + << std::hex << register_bank[28]; + std::cout << " x29 (t4): 0x" << std::right << std::setw(8) + << std::hex << register_bank[29]; + std::cout << " x30 (t5): 0x" << std::right << std::setw(8) + << std::hex << register_bank[30]; + std::cout << " x31 (t6): 0x" << std::right << std::setw(8) + << std::hex << register_bank[31] << std::endl; + + std::cout << "PC: 0x" << std::setw(8) << std::hex << register_PC << std::dec << std::endl; + std::cout << "************************************" << std::endl; + } private: /** * bank of registers (32 regs of 32bits each) */ - std::array register_bank = {{0}}; + std::array register_bank = {{0}}; /** * Program counter (32 bits width) */ - std::uint32_t register_PC; + T register_PC; /** * CSR registers (4096 maximum) */ - std::unordered_map CSR; - + std::unordered_map CSR; Performance *perf; - void initCSR(); + void initCSR() { + CSR[CSR_MISA] = MISA_MXL | MISA_M_EXTENSION | MISA_C_EXTENSION + | MISA_A_EXTENSION | MISA_I_BASE; + CSR[CSR_MSTATUS] = MISA_MXL; + } }; } #endif diff --git a/inc/extension_base.h b/inc/extension_base.h index 2b2ffe9..2ae1473 100644 --- a/inc/extension_base.h +++ b/inc/extension_base.h @@ -28,19 +28,55 @@ namespace riscv_tlm { + template class extension_base { public: - extension_base(const sc_dt::sc_uint<32> &instr, Registers *register_bank, - MemoryInterface *mem_interface); + extension_base(const T &instr, Registers *register_bank, + MemoryInterface *mem_interface) : + m_instr(instr), regs(register_bank), mem_intf(mem_interface) { - virtual ~extension_base() = 0; + perf = Performance::getInstance(); + logger = spdlog::get("my_logger"); + } - void setInstr(std::uint32_t p_instr); + virtual ~extension_base() = default; - void RaiseException(std::uint32_t cause, std::uint32_t inst); + void setInstr(std::uint32_t p_instr) { + m_instr = sc_dt::sc_uint<32>(p_instr); + } - bool NOP(); + void RaiseException(std::uint32_t cause, std::uint32_t inst) { + std::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); + + logger->debug("{} ns. PC: 0x{:x}. Exception! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC(), + new_pc); + } + + bool NOP() { + logger->debug("{} ns. PC: 0x{:x}. NOP! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC()); + sc_core::sc_stop(); + return true; + } /* pure virtual functions */ virtual std::int32_t opcode() const = 0; @@ -77,11 +113,13 @@ namespace riscv_tlm { m_instr.range(14, 12) = value; } - virtual void dump() const; + virtual void dump() const { + std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; + } protected: sc_dt::sc_uint<32> m_instr; - Registers *regs; + Registers *regs; Performance *perf; MemoryInterface *mem_intf; std::shared_ptr logger; diff --git a/src/BASE_ISA.cpp b/src/BASE_ISA.cpp index 8ca35bb..3c48db6 100644 --- a/src/BASE_ISA.cpp +++ b/src/BASE_ISA.cpp @@ -126,7 +126,7 @@ namespace riscv_tlm { rd = get_rd(); mem_addr = get_imm_J(); - old_pc = static_cast(regs->getPC()); + old_pc = regs->getPC(); new_pc = old_pc + mem_addr; regs->setPC(new_pc); @@ -150,7 +150,7 @@ namespace riscv_tlm { rs1 = get_rs1(); mem_addr = get_imm_I(); - old_pc = static_cast(regs->getPC()); + old_pc = regs->getPC(); regs->setValue(rd, old_pc + 4); new_pc = static_cast((regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); diff --git a/src/CPU.cpp b/src/CPU.cpp index 02b0d50..31a1e4b 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -14,13 +14,13 @@ namespace riscv_tlm { CPU::CPU(sc_core::sc_module_name const &name, std::uint32_t PC, bool debug) : sc_module(name), instr_bus("instr_bus"), inst(0), default_time(10, sc_core::SC_NS), INSTR(0) { - register_bank = new Registers(); + register_bank = new Registers(); mem_intf = new MemoryInterface(); perf = Performance::getInstance(); register_bank->setPC(PC); - register_bank->setValue(Registers::sp, (Memory::SIZE / 4) - 1); + register_bank->setValue(Registers::sp, (Memory::SIZE / 4) - 1); irq_line_socket.register_b_transport(this, &CPU::call_interrupt); interrupt = false; diff --git a/src/Debug.cpp b/src/Debug.cpp index af42fd7..51f4153 100644 --- a/src/Debug.cpp +++ b/src/Debug.cpp @@ -77,7 +77,7 @@ namespace riscv_tlm { void Debug::handle_gdb_loop() { std::cout << "Handle_GDB_Loop\n"; - Registers *register_bank = dbg_cpu->getRegisterBank(); + Registers *register_bank = dbg_cpu->getRegisterBank(); while (true) { std::string msg = receive_packet(); diff --git a/src/Registers.cpp b/src/Registers.cpp index c1d168e..2b289ad 100644 --- a/src/Registers.cpp +++ b/src/Registers.cpp @@ -6,171 +6,4 @@ */ // SPDX-License-Identifier: GPL-3.0-or-later -#include "Registers.h" -namespace riscv_tlm { - - Registers::Registers() { - perf = Performance::getInstance(); - - initCSR(); - register_bank[sp] = Memory::SIZE - 4; // default stack at the end of the memory - register_PC = 0x80000000; // default _start address - } - - void Registers::dump() { - std::cout << "************************************" << std::endl; - std::cout << "Registers dump" << std::dec << std::endl; - std::cout << std::setfill('0') << std::uppercase; - std::cout << "x0 (zero): 0x" << std::right << std::setw(8) - << std::hex << register_bank[0]; - std::cout << " x1 (ra): 0x" << std::right << std::setw(8) - << std::hex << register_bank[1]; - std::cout << " x2 (sp): 0x" << std::right << std::setw(8) - << std::hex << register_bank[2]; - std::cout << " x3 (gp): 0x" << std::right << std::setw(8) - << std::hex << register_bank[3] << std::endl; - - std::cout << "x4 (tp): 0x" << std::right << std::setw(8) - << std::hex << register_bank[4]; - std::cout << " x5 (t0): 0x" << std::right << std::setw(8) - << std::hex << register_bank[5]; - std::cout << " x6 (t1): 0x" << std::right << std::setw(8) - << std::hex << register_bank[6]; - std::cout << " x7 (t2): 0x" << std::right << std::setw(8) - << std::hex << register_bank[7] << std::endl; - - std::cout << "x8 (s0/fp): 0x" << std::right << std::setw(8) - << std::hex << register_bank[8]; - std::cout << " x9 (s1): 0x" << std::right << std::setw(8) - << std::hex << register_bank[9]; - std::cout << " x10 (a0): 0x" << std::right << std::setw(8) - << std::hex << register_bank[10]; - std::cout << " x11 (a1): 0x" << std::right << std::setw(8) - << std::hex << register_bank[11] << std::endl; - - std::cout << "x12 (a2): 0x" << std::right << std::setw(8) - << std::hex << register_bank[12]; - std::cout << " x13 (a3): 0x" << std::right << std::setw(8) - << std::hex << register_bank[13]; - std::cout << " x14 (a4): 0x" << std::right << std::setw(8) - << std::hex << register_bank[14]; - std::cout << " x15 (a5): 0x" << std::right << std::setw(8) - << std::hex << register_bank[15] << std::endl; - - std::cout << "x16 (a6): 0x" << std::right << std::setw(8) - << std::hex << register_bank[16]; - std::cout << " x17 (a7): 0x" << std::right << std::setw(8) - << std::hex << register_bank[17]; - std::cout << " x18 (s2): 0x" << std::right << std::setw(8) - << std::hex << register_bank[18]; - std::cout << " x19 (s3): 0x" << std::right << std::setw(8) - << std::hex << register_bank[19] << std::endl; - - std::cout << "x20 (s4): 0x" << std::right << std::setw(8) - << std::hex << register_bank[20]; - std::cout << " x21 (s5): 0x" << std::right << std::setw(8) - << std::hex << register_bank[21]; - std::cout << " x22 (s6): 0x" << std::right << std::setw(8) - << std::hex << register_bank[22]; - std::cout << " x23 (s7): 0x" << std::right << std::setw(8) - << std::hex << register_bank[23] << std::endl; - - std::cout << "x24 (s8): 0x" << std::right << std::setw(8) - << std::hex << register_bank[24]; - std::cout << " x25 (s9): 0x" << std::right << std::setw(8) - << std::hex << register_bank[25]; - std::cout << " x26 (s10): 0x" << std::right << std::setw(8) - << std::hex << register_bank[26]; - std::cout << " x27 (s11): 0x" << std::right << std::setw(8) - << std::hex << register_bank[27] << std::endl; - - std::cout << "x28 (t3): 0x" << std::right << std::setw(8) - << std::hex << register_bank[28]; - std::cout << " x29 (t4): 0x" << std::right << std::setw(8) - << std::hex << register_bank[29]; - std::cout << " x30 (t5): 0x" << std::right << std::setw(8) - << std::hex << register_bank[30]; - std::cout << " x31 (t6): 0x" << std::right << std::setw(8) - << std::hex << register_bank[31] << std::endl; - - std::cout << "PC: 0x" << std::setw(8) << std::hex << register_PC << std::dec << std::endl; - std::cout << "************************************" << std::endl; - } - - void Registers::setValue(int reg_num, std::int32_t value) { - if ((reg_num != 0) && (reg_num < 32)) { - register_bank[reg_num] = value; - perf->registerWrite(); - } - } - - std::uint32_t Registers::getValue(int reg_num) const { - if ((reg_num >= 0) && (reg_num < 32)) { - perf->registerRead(); - return register_bank[reg_num]; - } else { - return static_cast(0xFFFFFFFF); - } - } - - std::uint32_t Registers::getPC() const { - return register_PC; - } - - void Registers::setPC(std::uint32_t new_pc) { - register_PC = new_pc; - } - - std::uint32_t Registers::getCSR(const int csr) { - std::uint32_t ret_value; - - switch (csr) { - case CSR_CYCLE: - case CSR_MCYCLE: - ret_value = static_cast(sc_core::sc_time( - sc_core::sc_time_stamp() - - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) - & 0x00000000FFFFFFFF; - break; - case CSR_CYCLEH: - case CSR_MCYCLEH: - ret_value = static_cast((std::uint64_t) (sc_core::sc_time( - sc_core::sc_time_stamp() - - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) - >> 32 & 0x00000000FFFFFFFF); - break; - case CSR_TIME: - ret_value = static_cast(sc_core::sc_time( - sc_core::sc_time_stamp() - - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) - & 0x00000000FFFFFFFF; - break; - case CSR_TIMEH: - ret_value = static_cast((std::uint64_t) (sc_core::sc_time( - sc_core::sc_time_stamp() - - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) - >> 32 & 0x00000000FFFFFFFF); - break; - [[likely]] default: - ret_value = CSR[csr]; - break; - } - return ret_value; - } - - void Registers::setCSR(int csr, std::uint32_t value) { - /* @FIXME: rv32mi-p-ma_fetch tests doesn't allow MISA to be writable, - * but Volume II: Privileged Architecture v1.10 says MISA is writable (?) - */ - if (csr != CSR_MISA) { - CSR[csr] = value; - } - } - - void Registers::initCSR() { - CSR[CSR_MISA] = MISA_MXL | MISA_M_EXTENSION | MISA_C_EXTENSION - | MISA_A_EXTENSION | MISA_I_BASE; - CSR[CSR_MSTATUS] = MISA_MXL; - } -} \ No newline at end of file diff --git a/src/extension_base.cpp b/src/extension_base.cpp index 2905ddb..aa28374 100644 --- a/src/extension_base.cpp +++ b/src/extension_base.cpp @@ -7,57 +7,3 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "extension_base.h" - -namespace riscv_tlm { - - extension_base::extension_base(const sc_dt::sc_uint<32> &instr, - Registers *register_bank, MemoryInterface *mem_interface) : - m_instr(instr), regs(register_bank), mem_intf(mem_interface) { - - perf = Performance::getInstance(); - logger = spdlog::get("my_logger"); - } - - extension_base::~extension_base() = default; - - void extension_base::setInstr(std::uint32_t p_instr) { - m_instr = sc_dt::sc_uint<32>(p_instr); - } - - void extension_base::dump() const { - std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; - } - - void extension_base::RaiseException(std::uint32_t cause, std::uint32_t inst) { - std::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); - - logger->debug("{} ns. PC: 0x{:x}. Exception! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC(), - new_pc); - } - - bool extension_base::NOP() { - - logger->debug("{} ns. PC: 0x{:x}. NOP! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC()); - sc_core::sc_stop(); - return true; - } -} \ No newline at end of file From 10ed1fa65379e1730dc484ca47d0bd095c04cb9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Sun, 20 Feb 2022 11:23:58 +0100 Subject: [PATCH 02/17] Changed to template classe to prepare for 64bits version --- inc/A_extension.h | 448 +++++++++++- inc/BASE_ISA.h | 1580 +++++++++++++++++++++++++++++++++++++++--- inc/CPU.h | 8 +- inc/C_extension.h | 983 ++++++++++++++++++++++---- inc/M_extension.h | 289 +++++++- inc/Registers.h | 251 +++---- inc/extension_base.h | 63 +- src/A_extension.cpp | 438 +----------- src/BASE_ISA.cpp | 1475 --------------------------------------- src/CPU.cpp | 12 +- src/C_extension.cpp | 746 -------------------- src/M_extension.cpp | 289 -------- 12 files changed, 3202 insertions(+), 3380 deletions(-) diff --git a/inc/A_extension.h b/inc/A_extension.h index 8d7d569..b2d08ad 100644 --- a/inc/A_extension.h +++ b/inc/A_extension.h @@ -52,59 +52,465 @@ namespace riscv_tlm { /** * @brief Instruction decoding and fields access */ - class A_extension : public extension_base { + template + class A_extension : public extension_base { public: /** * @brief Constructor, same as base class */ - using extension_base::extension_base; + using extension_base::extension_base; /** * @brief Access to opcode field * @return return opcode field */ - inline int32_t opcode() const override { - return static_cast(m_instr.range(31, 27)); + inline std::uint32_t opcode() const override { + return static_cast(this->m_instr.range(31, 27)); } /** * @brief Decodes opcode of instruction * @return opcode of instruction */ - op_A_Codes decode() const; + op_A_Codes decode() const { - inline void dump() const override { - std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; + switch (opcode()) { + case A_LR: + return OP_A_LR; + break; + case A_SC: + return OP_A_SC; + break; + case A_AMOSWAP: + return OP_A_AMOSWAP; + break; + case A_AMOADD: + return OP_A_AMOADD; + break; + case A_AMOXOR: + return OP_A_AMOXOR; + break; + case A_AMOAND: + return OP_A_AMOAND; + break; + case A_AMOOR: + return OP_A_AMOOR; + break; + case A_AMOMIN: + return OP_A_AMOMIN; + break; + case A_AMOMAX: + return OP_A_AMOMAX; + break; + case A_AMOMINU: + return OP_A_AMOMINU; + break; + case A_AMOMAXU: + return OP_A_AMOMAXU; + break; + [[unlikely]] default: + return OP_A_ERROR; + break; + + } + + return OP_A_ERROR; } - bool Exec_A_LR(); + inline void dump() const override { + std::cout << std::hex << "0x" << this->m_instr << std::dec << std::endl; + } - bool Exec_A_SC(); + bool Exec_A_LR() { + std::uint32_t mem_addr = 0; + int rd, rs1, rs2; + std::uint32_t data; - bool Exec_A_AMOSWAP() const; + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool Exec_A_AMOADD() const; + if (rs2 != 0) { + std::cout << "ILEGAL INSTRUCTION, LR.W: rs2 != 0" << std::endl; + this->RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, this->m_instr); - bool Exec_A_AMOXOR() const; + return false; + } - bool Exec_A_AMOAND() const; + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + this->regs->setValue(rd, static_cast(data)); - bool Exec_A_AMOOR() const; + TLB_reserve(mem_addr); - bool Exec_A_AMOMIN() const; + this->logger->debug("{} ns. PC: 0x{:x}. A.LR.W: x{:d}(0x{:x}) -> x{:d}(0x{:x}) ", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, mem_addr, rd, data); - bool Exec_A_AMOMAX() const; + return true; + } - bool Exec_A_AMOMINU() const; + bool Exec_A_SC() { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; - bool Exec_A_AMOMAXU() const; + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool process_instruction(Instruction &inst); + mem_addr = this->regs->getValue(rs1); + data = this->regs->getValue(rs2); - void TLB_reserve(std::uint32_t address); + if (TLB_reserved(mem_addr)) { + this->mem_intf->writeDataMem(mem_addr, data, 4); + this->perf->dataMemoryWrite(); + this->regs->setValue(rd, 0); // SC writes 0 to rd on success + } else { + this->regs->setValue(rd, 1); // SC writes nonzero on failure + } - bool TLB_reserved(std::uint32_t address); + this->logger->debug("{} ns. PC: 0x{:x}. A.SC.W: (0x{:x}) <- x{:d}(0x{:x}) ", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + mem_addr, rs2, data); + + return true; + } + + bool Exec_A_AMOSWAP() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + std::uint32_t aux; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + this->regs->setValue(rd, static_cast(data)); + + // swap + aux = this->regs->getValue(rs2); + this->regs->setValue(rs2, static_cast(data)); + + this->mem_intf->writeDataMem(mem_addr, aux, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOSWAP"); + + return true; + } + + bool Exec_A_AMOADD() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, static_cast(data)); + + // add + data = data + this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOADD"); + + return true; + } + + bool Exec_A_AMOXOR() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, static_cast(data)); + + // add + data = data ^ this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOXOR"); + + return true; + } + + bool Exec_A_AMOAND() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, static_cast(data)); + + // add + data = data & this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOAND"); + + return true; + } + + bool Exec_A_AMOOR() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, static_cast(data)); + + // add + data = data | this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOOR"); + + return true; + } + + bool Exec_A_AMOMIN() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + std::uint32_t aux; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, static_cast(data)); + + // min + aux = this->regs->getValue(rs2); + if ((int32_t) data < (int32_t) aux) { + aux = data; + } + + this->mem_intf->writeDataMem(mem_addr, aux, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOMIN"); + + return true; + } + + bool Exec_A_AMOMAX() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + std::uint32_t aux; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, static_cast(data)); + + // > + aux = this->regs->getValue(rs2); + if ((int32_t) data > (int32_t) aux) { + aux = data; + } + + this->mem_intf->writeDataMem(mem_addr, aux, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOMAX"); + + return true; + } + + bool Exec_A_AMOMINU() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + std::uint32_t aux; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, static_cast(data)); + + // min + aux = this->regs->getValue(rs2); + if (data < aux) { + aux = data; + } + + this->mem_intf->writeDataMem(mem_addr, aux, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOMINU"); + + return true; + } + + bool Exec_A_AMOMAXU() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + std::uint32_t aux; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, static_cast(data)); + + // max + aux = this->regs->getValue(rs2); + if (data > aux) { + aux = data; + } + + this->mem_intf->writeDataMem(mem_addr, aux, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOMAXU"); + + return true; + } + + void TLB_reserve(std::uint32_t address) { + TLB_A_Entries.insert(address); + } + + bool TLB_reserved(std::uint32_t address) { + if (TLB_A_Entries.count(address) == 1) { + TLB_A_Entries.erase(address); + return true; + } else { + return false; + } + } + + bool process_instruction(Instruction &inst) { + bool PC_not_affected = true; + + this->setInstr(inst.getInstr()); + + switch (decode()) { + case OP_A_LR: + Exec_A_LR(); + break; + case OP_A_SC: + Exec_A_SC(); + break; + case OP_A_AMOSWAP: + Exec_A_AMOSWAP(); + break; + case OP_A_AMOADD: + Exec_A_AMOADD(); + break; + case OP_A_AMOXOR: + Exec_A_AMOXOR(); + break; + case OP_A_AMOAND: + Exec_A_AMOAND(); + break; + case OP_A_AMOOR: + Exec_A_AMOOR(); + break; + case OP_A_AMOMIN: + Exec_A_AMOMIN(); + break; + case OP_A_AMOMAX: + Exec_A_AMOMAX(); + break; + case OP_A_AMOMINU: + Exec_A_AMOMINU(); + break; + case OP_A_AMOMAXU: + Exec_A_AMOMAXU(); + break; + [[unlikely]] default: + std::cout << "A instruction not implemented yet" << std::endl; + inst.dump(); + this->NOP(); + break; + } + + return PC_not_affected; + } private: std::unordered_set TLB_A_Entries; diff --git a/inc/BASE_ISA.h b/inc/BASE_ISA.h index 3c2ec3a..5fb79df 100644 --- a/inc/BASE_ISA.h +++ b/inc/BASE_ISA.h @@ -89,23 +89,98 @@ namespace riscv_tlm { OP_ERROR } opCodes; + enum Codes { + 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, + }; + /** * @brief Risc_V execute module */ - class BASE_ISA : public extension_base { + template + class BASE_ISA : public extension_base { public: /** * @brief Constructor, same as base class */ - using extension_base::extension_base; + using extension_base::extension_base; /** * @brief Access to funct7 field * @return funct7 field */ inline std::int32_t get_funct7() const { - return m_instr.range(31, 25); + return this->m_instr.range(31, 25); } /** @@ -113,7 +188,7 @@ namespace riscv_tlm { * @param value desired func7 value */ inline void set_func7(std::int32_t value) { - m_instr.range(31, 25) = value; + this->m_instr.range(31, 25) = value; } /** @@ -123,10 +198,10 @@ namespace riscv_tlm { inline std::int32_t get_imm_I() const { std::uint32_t aux = 0; - aux = m_instr.range(31, 20); + aux = this->m_instr.range(31, 20); /* sign extension (optimize) */ - if (m_instr[31] == 1) { + if (this->m_instr[31] == 1) { aux |= (0b11111111111111111111) << 12; } @@ -138,7 +213,7 @@ namespace riscv_tlm { * @param value desired I value */ inline void set_imm_I(std::int32_t value) { - m_instr.range(31, 20) = value; + this->m_instr.range(31, 20) = value; } /** @@ -148,10 +223,10 @@ namespace riscv_tlm { inline std::int32_t get_imm_S() const { std::uint32_t aux = 0; - aux = m_instr.range(31, 25) << 5; - aux |= m_instr.range(11, 7); + aux = this->m_instr.range(31, 25) << 5; + aux |= this->m_instr.range(11, 7); - if (m_instr[31] == 1) { + if (this->m_instr[31] == 1) { aux |= (0b11111111111111111111) << 12; } @@ -163,7 +238,7 @@ namespace riscv_tlm { * @return immediate_U field */ inline std::int32_t get_imm_U() const { - return static_cast(m_instr.range(31, 12)); + return static_cast(this->m_instr.range(31, 12)); } /** @@ -171,7 +246,7 @@ namespace riscv_tlm { * @param value desired U value */ inline void set_imm_U(std::int32_t value) { - m_instr.range(31, 12) = (value << 12); + this->m_instr.range(31, 12) = (value << 12); } /** @@ -181,12 +256,12 @@ namespace riscv_tlm { inline std::int32_t get_imm_B() const { std::int32_t aux = 0; - aux |= m_instr[7] << 11; - aux |= m_instr.range(30, 25) << 5; - aux |= m_instr[31] << 12; - aux |= m_instr.range(11, 8) << 1; + aux |= this->m_instr[7] << 11; + aux |= this->m_instr.range(30, 25) << 5; + aux |= this->m_instr[31] << 12; + aux |= this->m_instr.range(11, 8) << 1; - if (m_instr[31] == 1) { + if (this->m_instr[31] == 1) { aux |= (0b11111111111111111111) << 12; } @@ -200,10 +275,10 @@ namespace riscv_tlm { inline void set_imm_B(std::int32_t value) { sc_dt::sc_uint<32> aux = value; - m_instr[31] = aux[12]; - m_instr.range(30, 25) = aux.range(10, 5); - m_instr.range(11, 7) = aux.range(4, 1); - m_instr[6] = aux[11]; + this->m_instr[31] = aux[12]; + this->m_instr.range(30, 25) = aux.range(10, 5); + this->m_instr.range(11, 7) = aux.range(4, 1); + this->m_instr[6] = aux[11]; } /** @@ -213,13 +288,13 @@ namespace riscv_tlm { inline std::int32_t get_imm_J() const { std::int32_t aux = 0; - aux = m_instr[31] << 20; - aux |= m_instr.range(19, 12) << 12; - aux |= m_instr[20] << 11; - aux |= m_instr.range(30, 21) << 1; + aux = this->m_instr[31] << 20; + aux |= this->m_instr.range(19, 12) << 12; + aux |= this->m_instr[20] << 11; + aux |= this->m_instr.range(30, 21) << 1; /* bit extension (better way to do that?) */ - if (m_instr[31] == 1) { + if (this->m_instr[31] == 1) { aux |= (0b111111111111) << 20; } @@ -233,10 +308,10 @@ namespace riscv_tlm { inline void set_imm_J(std::int32_t value) { sc_dt::sc_uint<32> aux = (value << 20); - m_instr[31] = aux[20]; - m_instr.range(30, 21) = aux.range(10, 1); - m_instr[20] = aux[11]; - m_instr.range(19, 12) = aux.range(19, 12); + this->m_instr[31] = aux[20]; + this->m_instr.range(30, 21) = aux.range(10, 1); + this->m_instr[20] = aux[11]; + this->m_instr.range(19, 12) = aux.range(19, 12); } /** @@ -244,7 +319,7 @@ namespace riscv_tlm { * @return value corresponding to inst(25:20) */ inline std::int32_t get_shamt() const { - return static_cast(m_instr.range(25, 20)); + return static_cast(this->m_instr.range(25, 20)); } /** @@ -254,7 +329,7 @@ namespace riscv_tlm { inline std::int32_t get_csr() const { std::int32_t aux = 0; - aux = static_cast(m_instr.range(31, 20)); + aux = static_cast(this->m_instr.range(31, 20)); return aux; } @@ -263,127 +338,1454 @@ namespace riscv_tlm { * @brief Access to opcode field * @return return opcode field */ - inline std::int32_t opcode() const override { - return static_cast(m_instr.range(6, 0)); + inline std::uint32_t opcode() const override { + return static_cast(this->m_instr.range(6, 0)); } - bool Exec_LUI() const; + bool Exec_LUI() const { + unsigned int rd; + std::uint32_t imm; - bool Exec_AUIPC() const; + rd = this->get_rd(); + imm = get_imm_U() << 12; + this->regs->setValue(rd, static_cast(imm)); - bool Exec_JAL() const; + this->logger->debug("{} ns. PC: 0x{:x}. LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rd, imm); - bool Exec_JALR(); + return true; + } - bool Exec_BEQ() const; + bool Exec_AUIPC() const { + unsigned int rd; + std::uint32_t imm; + std::uint32_t new_pc; - bool Exec_BNE() const; + rd = this->get_rd(); + imm = get_imm_U() << 12; + new_pc = static_cast(this->regs->getPC() + imm); - bool Exec_BLT() const; + this->regs->setValue(rd, new_pc); - bool Exec_BGE() const; + this->logger->debug("{} ns. PC: 0x{:x}. AUIPC: x{:d} <- 0x{:x} + PC (0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rd, imm, new_pc); - bool Exec_BLTU() const; + return true; + } - bool Exec_BGEU() const; + bool Exec_JAL() const { + std::int32_t mem_addr; + unsigned int rd; + std::uint32_t new_pc, old_pc; - bool Exec_LB() const; + rd = this->get_rd(); + mem_addr = get_imm_J(); + old_pc = this->regs->getPC(); + new_pc = old_pc + mem_addr; - bool Exec_LH() const; + this->regs->setPC(new_pc); - bool Exec_LW() const; + old_pc = old_pc + 4; + this->regs->setValue(rd, old_pc); - bool Exec_LBU() const; + this->logger->debug("{} ns. PC: 0x{:x}. JAL: x{:d} <- 0x{:x}. PC + 0x{:x} -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rd, old_pc, mem_addr, new_pc); - bool Exec_LHU() const; + return true; + } - bool Exec_SB() const; + bool Exec_JALR() { + std::uint32_t mem_addr; + unsigned int rd, rs1; + std::uint32_t new_pc, old_pc; - bool Exec_SH() const; + rd = this->get_rd(); + rs1 = this->get_rs1(); + mem_addr = get_imm_I(); - bool Exec_SW() const; + old_pc = this->regs->getPC(); + this->regs->setValue(rd, old_pc + 4); - bool Exec_SBU() const; + new_pc = static_cast((this->regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); - bool Exec_SHU() const; + if ((new_pc & 0x00000003) != 0) { + // not aligned + this->logger->debug("{} ns. PC: 0x{:x}. JALR: x{:d} <- 0x{:x} PC <- 0x{:x}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rd, old_pc + 4, new_pc); - bool Exec_ADDI() const; + this->logger->debug("{} ns. PC: 0x{:x}. JALR : Exception"); + this->RaiseException(EXCEPTION_CAUSE_LOAD_ADDR_MISALIGN, this->m_instr); + } else { + this->regs->setPC(new_pc); + } - bool Exec_SLTI() const; + this->logger->debug("{} ns. PC: 0x{:x}. JALR: x{:d} <- 0x{:x}. PC <- 0x{:x}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rd, old_pc + 4, new_pc); - bool Exec_SLTIU() const; + return true; + } - bool Exec_XORI() const; + bool Exec_BEQ() const { + unsigned int rs1, rs2; + std::uint32_t new_pc; - bool Exec_ORI() const; + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool Exec_ANDI() const; + if (this->regs->getValue(rs1) == this->regs->getValue(rs2)) { + new_pc = static_cast(this->regs->getPC() + get_imm_B()); + this->regs->setPC(new_pc); + } else { + this->regs->incPC(); + new_pc = static_cast(this->regs->getPC()); + } - bool Exec_SLLI(); + this->logger->debug("{} ns. PC: 0x{:x}. BEQ: x{:d}(0x{:x}) == x{:d}(0x{:x})? -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), new_pc); - bool Exec_SRLI() const; + return true; + } - bool Exec_SRAI() const; + bool Exec_BNE() const { + unsigned int rs1, rs2; + std::uint32_t new_pc; + std::uint32_t val1, val2; - bool Exec_ADD() const; + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool Exec_SUB() const; + val1 = this->regs->getValue(rs1); + val2 = this->regs->getValue(rs2); - bool Exec_SLL() const; + if (val1 != val2) { + new_pc = static_cast(this->regs->getPC() + get_imm_B()); + this->regs->setPC(new_pc); + } else { + this->regs->incPC(); + new_pc = static_cast(this->regs->getPC()); + } - bool Exec_SLT() const; + this->logger->debug("{} ns. PC: 0x{:x}. BNE: x{:d}(0x{:x}) != x{:d}(0x{:x})? -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, val1, rs2, val2, new_pc); - bool Exec_SLTU() const; + return true; + } - bool Exec_XOR() const; + bool Exec_BLT() const { + unsigned int rs1, rs2; + std::uint32_t new_pc = 0; - bool Exec_SRL() const; + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool Exec_SRA() const; + if (static_cast(this->regs->getValue(rs1)) + < static_cast(this->regs->getValue(rs2))) { + new_pc = static_cast(this->regs->getPC() + get_imm_B()); + this->regs->setPC(new_pc); + } else { + this->regs->incPC(); + } - bool Exec_OR() const; + this->logger->debug("{} ns. PC: 0x{:x}. BLT: x{:d}(0x{:x}) < x{:d}(0x{:x})? -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), new_pc); - bool Exec_AND() const; + return true; + } - bool Exec_FENCE() const; + bool Exec_BGE() const { + unsigned int rs1, rs2; + std::uint32_t new_pc = 0; - bool Exec_ECALL(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool Exec_EBREAK(); + if (static_cast(this->regs->getValue(rs1)) + >= static_cast( this->regs->getValue(rs2))) { + new_pc = static_cast(this->regs->getPC() + get_imm_B()); + this->regs->setPC(new_pc); + } else { + this->regs->incPC(); + } - bool Exec_CSRRW() const; + this->logger->debug("{} ns. PC: 0x{:x}. BGE: x{:d}(0x{:x}) > x{:d}(0x{:x})? -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), new_pc); - bool Exec_CSRRS() const; + return true; + } - bool Exec_CSRRC() const; + bool Exec_BLTU() const { + unsigned int rs1, rs2; + std::uint32_t new_pc; - bool Exec_CSRRWI() const; + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool Exec_CSRRSI() const; + if (static_cast(this->regs->getValue(rs1)) + < static_cast(this->regs->getValue(rs2))) { + new_pc = static_cast(this->regs->getPC() + get_imm_B()); + this->regs->setPC(new_pc); + } else { + this->regs->incPC(); + new_pc = static_cast(this->regs->getPC()); + } - bool Exec_CSRRCI() const; + this->logger->debug("{} ns. PC: 0x{:x}. BLTU: x{:d}(0x{:x}) < x{:d}(0x{:x})? -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), new_pc); - /*********************** Privileged Instructions ******************************/ - bool Exec_MRET() const; + return true; + } - bool Exec_SRET() const; + bool Exec_BGEU() const { + unsigned int rs1, rs2; - bool Exec_WFI() const; + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool Exec_SFENCE() const; + if (static_cast(this->regs->getValue(rs1)) + >= static_cast(this->regs->getValue(rs2))) { + std::uint32_t new_pc; + new_pc = static_cast(this->regs->getPC() + get_imm_B()); + + this->logger->debug("{} ns. PC: 0x{:x}. BGEU: x{:d}(0x{:x}) > x{:d}(0x{:x}) -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), new_pc); + + this->regs->setPC(new_pc); + } else { + this->logger->debug("{} ns. PC: 0x{:x}. BGEU: x{:d}(0x{:x}) > x{:d}(0x{:x}) -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), + this->regs->getPC() + 4); + this->regs->incPC(); + } + + return true; + } + + bool Exec_LB() const { + std::uint32_t mem_addr; + unsigned int rd, rs1; + std::int32_t imm; + std::int8_t data; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + mem_addr = imm + this->regs->getValue(rs1); + data = static_cast(this->mem_intf->readDataMem(mem_addr, 1)); + this->perf->dataMemoryRead(); + this->regs->setValue(rd, data); + + this->logger->debug("{} ns. PC: 0x{:x}. LB: x{:d} + x{:d}(0x{:x}) -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, mem_addr, rd); + + return true; + } + + bool Exec_LH() const { + std::uint32_t mem_addr; + unsigned int rd, rs1; + std::int32_t imm; + int16_t data; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + mem_addr = imm + this->regs->getValue(rs1); + data = static_cast(this->mem_intf->readDataMem(mem_addr, 2)); + this->perf->dataMemoryRead(); + this->regs->setValue(rd, data); + + this->logger->debug("{} ns. PC: 0x{:x}. LH: x{:d} + x{:d}(0x{:x}) -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, mem_addr, rd); + + return true; + } + + bool Exec_LW() const { + std::uint32_t mem_addr; + unsigned int rd, rs1; + std::int32_t imm; + std::uint32_t data; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + this->regs->setValue(rd, static_cast(data)); + + this->logger->debug("{} ns. PC: 0x{:x}. LW: x{:d} + x{:d}(0x{:x}) -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, mem_addr, rd); + + return true; + } + + bool Exec_LBU() const { + std::uint32_t mem_addr; + unsigned int rd, rs1; + std::int32_t imm; + std::uint8_t data; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 1); + this->perf->dataMemoryRead(); + this->regs->setValue(rd, static_cast(data)); + + this->logger->debug("{} ns. PC: 0x{:x}. LBU: x{:d} + x{:d}(0x{:x}) -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, mem_addr, rd); + + return true; + } + + bool Exec_LHU() const { + std::uint32_t mem_addr; + unsigned int rd, rs1; + std::int32_t imm; + uint16_t data; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 2); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, data); + + this->logger->debug("{} ns. PC: 0x{:x}. LHU: x{:d} + x{:d}(0x{:x}) -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, mem_addr, rd); + + return true; + } + + bool Exec_SB() const { + std::uint32_t mem_addr; + unsigned int rs1, rs2; + std::int32_t imm; + std::uint32_t data; + + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + imm = get_imm_S(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 1); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. SB: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs2, rs1, imm, mem_addr); + + return true; + } + + bool Exec_SH() const { + std::uint32_t mem_addr; + unsigned int rs1, rs2; + std::int32_t imm; + std::uint32_t data; + + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + imm = get_imm_S(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 2); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. SH: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs2, rs1, imm, mem_addr); + + return true; + } + + bool Exec_SW() const { + std::uint32_t mem_addr; + unsigned int rs1, rs2; + std::int32_t imm; + std::uint32_t data; + + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + imm = get_imm_S(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. SW: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs2, rs1, imm, mem_addr); + + return true; + } + + bool Exec_ADDI() const { + unsigned int rd, rs1; + std::int32_t imm; + std::int32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + calc = static_cast(this->regs->getValue(rs1)) + imm; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. ADDI: x{:d} + x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, rd, calc); + + return true; + } + + bool Exec_SLTI() const { + unsigned int rd, rs1; + std::int32_t imm; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + if (static_cast(this->regs->getValue(rs1)) < imm) { + this->regs->setValue(rd, 1); + + this->logger->debug("{} ns. PC: 0x{:x}. SLTI: x{:d} < x{:d} => 1 -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, rd); + } else { + this->regs->setValue(rd, 0); + this->logger->debug("{} ns. PC: 0x{:x}. SLTI: x{:d} < x{:d} => 0 -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, rd); + } + + return true; + } + + bool Exec_SLTIU() const { + unsigned int rd, rs1; + std::int32_t imm; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + if (static_cast(this->regs->getValue(rs1)) < static_cast(imm)) { + this->regs->setValue(rd, 1); + this->logger->debug("{} ns. PC: 0x{:x}. SLTIU: x{:d} < x{:d} => 1 -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, rd); + } else { + this->regs->setValue(rd, 0); + this->logger->debug("{} ns. PC: 0x{:x}. SLTIU: x{:d} < x{:d} => 0 -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, rd); + } + + return true; + } + + bool Exec_XORI() const { + unsigned int rd, rs1; + std::int32_t imm; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + calc = this->regs->getValue(rs1) ^ imm; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. XORI: x{:d} XOR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, rd); + + return true; + } + + bool Exec_ORI() const { + unsigned int rd, rs1; + std::int32_t imm; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + calc = this->regs->getValue(rs1) | imm; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. ORI: x{:d} OR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, rd); + + return true; + } + + bool Exec_ANDI() const { + unsigned int rd, rs1; + std::uint32_t imm; + std::uint32_t calc; + std::uint32_t aux; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + aux = this->regs->getValue(rs1); + calc = aux & imm; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. ANDI: x{:d}(0x{:x}) AND 0x{:x} -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, aux, imm, rd); + + return true; + } + + bool Exec_SLLI() { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = get_shamt(); + + if (rs2 >= 0x20) { + std::cout << "ILEGAL INSTRUCTION, shamt[5] != 0" << "\n"; + this->RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, this->m_instr); + + return false; + } + + shift = rs2 & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) << shift; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. SLLI: x{:d} << {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + bool Exec_SRLI() const { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = rs2 & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. SRLI: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + bool Exec_SRAI() const { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::int32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = rs2 & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SRAI: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + bool Exec_ADD() const { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + calc = this->regs->getValue(rs1) + this->regs->getValue(rs2); + + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. ADD: x{:d} + x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); + + return true; + } + + bool Exec_SUB() const { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + calc = this->regs->getValue(rs1) - this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. SUB: x{:d} - x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); + + return true; + } + + bool Exec_SLL() const { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = this->regs->getValue(rs2) & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) << shift; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. SLL: x{:d} << x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + bool Exec_SLT() const { + unsigned int rd, rs1, rs2; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + if (this->regs->getValue(rs1) < this->regs->getValue(rs2)) { + this->regs->setValue(rd, 1); + this->logger->debug("{} ns. PC: 0x{:x}. SLT: x{:d} < x{:d} => 1 -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd); + } else { + this->regs->setValue(rd, 0); + this->logger->debug("{} ns. PC: 0x{:x}. SLT: x{:d} < x{:d} => 0 -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd); + } + + return true; + } + + bool Exec_SLTU() const { + unsigned int rd, rs1, rs2; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + if (static_cast(this->regs->getValue(rs1)) + < static_cast(this->regs->getValue(rs2))) { + this->regs->setValue(rd, 1); + this->logger->debug("{} ns. PC: 0x{:x}. SLTU: x{:d} < x{:d} => 1 -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd); + } else { + this->regs->setValue(rd, 0); + this->logger->debug("{} ns. PC: 0x{:x}. SLTU: x{:d} < x{:d} => 0 -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd); + } + + return true; + } + + bool Exec_XOR() const { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + calc = this->regs->getValue(rs1) ^ this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. XOR: x{:d} XOR x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); + + return true; + } + + bool Exec_SRL() const { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = this->regs->getValue(rs2) & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. SRL: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + bool Exec_SRA() const { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::int32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = this->regs->getValue(rs2) & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SRA: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + bool Exec_OR() const { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + calc = this->regs->getValue(rs1) | this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. OR: x{:d} OR x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); + + return true; + } + + bool Exec_AND() const { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + calc = this->regs->getValue(rs1) & this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. AND: x{:d} AND x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); + + return true; + } + + bool Exec_FENCE() const { + this->logger->debug("{} ns. PC: 0x{:x}. FENCE"); + + return true; + } + + bool Exec_ECALL() { + + this->logger->debug("{} ns. PC: 0x{:x}. ECALL"); + + std::cout << std::endl << "ECALL Instruction called, stopping simulation" + << std::endl; + this->regs->dump(); + std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; + this->perf->dump(); + +#if 0 + std::uint32_t gp_value = this->regs->getValue(Registers::gp); + if (gp_value == 1) { + std::cout << "GP value is 1, test result is OK" << "\n"; + } else { + std::cout << "GP value is " << gp_value << "\n"; + } + + sc_core::sc_stop(); +#else + this->RaiseException(11, this->m_instr); +#endif + return true; + } + + bool Exec_EBREAK() { + + this->logger->debug("{} ns. PC: 0x{:x}. EBREAK"); + std::cout << std::endl << "EBRAK Instruction called, dumping information" + << std::endl; + this->regs->dump(); + std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; + this->perf->dump(); + + this->RaiseException(11, this->m_instr); + + return false; + } + + bool Exec_CSRRW() const { + unsigned int rd, rs1; + int csr; + std::uint32_t aux; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + csr = get_csr(); + + /* These operations must be atomical */ + if (rd != 0) { + aux = this->regs->getCSR(csr); + this->regs->setValue(rd, static_cast(aux)); + } + + aux = this->regs->getValue(rs1); + this->regs->setCSR(csr, aux); + + this->logger->debug("{} ns. PC: 0x{:x}. CSRRW: CSR #{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + csr, rd, aux); + + return true; + } + + bool Exec_CSRRS() const { + unsigned int rd, rs1; + int csr; + std::uint32_t bitmask, aux, aux2; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + csr = get_csr(); + + if (rd == 0) { + this->logger->debug("{} ns. PC: 0x{:x}. CSRRS with rd1 == 0, doing nothing."); + return false; + } + + /* These operations must be atomical */ + aux = this->regs->getCSR(csr); + bitmask = this->regs->getValue(rs1); + + this->regs->setValue(rd, static_cast(aux)); + + aux2 = aux | bitmask; + this->regs->setCSR(csr, aux2); + + this->logger->debug("{} ns. PC: 0x{:x}. CSRRS: CSR #{:d}(0x{:x}) -> x{:d}(0x{:x}) & CSR #{:d} <- 0x{:x}", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + csr, aux, rd, rs1, csr, aux2); + + return true; + } + + bool Exec_CSRRC() const { + unsigned int rd, rs1; + int csr; + std::uint32_t bitmask, aux, aux2; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + csr = get_csr(); + + if (rd == 0) { + this->logger->debug("{} ns. PC: 0x{:x}. CSRRC with rd1 == 0, doing nothing."); + return true; + } + + /* These operations must be atomical */ + aux = this->regs->getCSR(csr); + bitmask = this->regs->getValue(rs1); + + this->regs->setValue(rd, static_cast(aux)); + + aux2 = aux & ~bitmask; + this->regs->setCSR(csr, aux2); + + this->logger->debug("{} ns. PC: 0x{:x}. CSRRC: CSR #{:d}(0x{:x}) -> x{:d}(0x{:x}) & CSR #{:d} <- 0x{:x}", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + csr, aux, rd, rs1, csr, aux2); + + return true; + } + + bool Exec_CSRRWI() const { + unsigned int rd, rs1; + int csr; + std::uint32_t aux; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + csr = get_csr(); + + /* These operations must be atomical */ + if (rd != 0) { + aux = this->regs->getCSR(csr); + this->regs->setValue(rd, static_cast(aux)); + } + aux = rs1; + this->regs->setCSR(csr, aux); + + this->logger->debug("{} ns. PC: 0x{:x}. CSRRWI: CSR #{:d} -> x{:d}. x{:d} -> CSR #{:d}", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + csr, rd, rs1, csr); + + return true; + } + + bool Exec_CSRRSI() const { + unsigned int rd, rs1; + int csr; + std::uint32_t bitmask, aux; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + csr = get_csr(); + + if (rs1 == 0) { + return true; + } + + /* These operations must be atomical */ + aux = this->regs->getCSR(csr); + this->regs->setValue(rd, static_cast(aux)); + + bitmask = rs1; + aux = aux | bitmask; + this->regs->setCSR(csr, aux); + + this->logger->debug("{} ns. PC: 0x{:x}. CSRRSI: CSR #{:d} -> x{:d}. x{:d} & CSR #{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + csr, rd, rs1, csr, aux); + + return true; + } + + bool Exec_CSRRCI() const { + unsigned rd, rs1; + int csr; + std::uint32_t bitmask, aux; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + csr = get_csr(); + + if (rs1 == 0) { + return true; + } + + /* These operations must be atomical */ + aux = this->regs->getCSR(csr); + this->regs->setValue(rd, static_cast(aux)); + + bitmask = rs1; + aux = aux & ~bitmask; + this->regs->setCSR(csr, aux); + + this->logger->debug("{} ns. PC: 0x{:x}. CSRRCI: CSR #{:d} -> x{:d}. x{:d} & CSR #{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + csr, rd, rs1, csr, aux); + + return true; + } + +/*********************** Privileged Instructions ******************************/ + + bool Exec_MRET() const { + std::uint32_t new_pc = 0; + + new_pc = this->regs->getCSR(CSR_MEPC); + this->regs->setPC(new_pc); + + this->logger->debug("{} ns. PC: 0x{:x}. MRET: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), new_pc); + + // update mstatus + std::uint32_t csr_temp; + csr_temp = this->regs->getCSR(CSR_MSTATUS); + if (csr_temp & MSTATUS_MPIE) { + csr_temp |= MSTATUS_MIE; + } + csr_temp |= MSTATUS_MPIE; + this->regs->setCSR(CSR_MSTATUS, csr_temp); + + return true; + } + + bool Exec_SRET() const { + std::uint32_t new_pc = 0; + + new_pc = this->regs->getCSR(CSR_SEPC); + this->regs->setPC(new_pc); + + this->logger->debug("{} ns. PC: 0x{:x}. SRET: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), + this->regs->getPC()); + return true; + } + + bool Exec_WFI() const { + this->logger->debug("{} ns. PC: 0x{:x}. WFI"); + return true; + } + + bool Exec_SFENCE() const { + this->logger->debug("{} ns. PC: 0x{:x}. SFENCE"); + return true; + } /** * @brief Executes default ISA instruction * @param inst instruction to execute * @return true if PC is affected by instruction */ - bool process_instruction(Instruction &inst, bool *breakpoint = nullptr); + bool process_instruction(Instruction &inst, bool *breakpoint = nullptr) { + bool PC_not_affected = true; + + *breakpoint = false; + this->setInstr(inst.getInstr()); + + switch (decode()) { + case OP_LUI: + Exec_LUI(); + break; + case OP_AUIPC: + Exec_AUIPC(); + break; + case OP_JAL: + Exec_JAL(); + PC_not_affected = false; + break; + case OP_JALR: + Exec_JALR(); + PC_not_affected = false; + break; + case OP_BEQ: + Exec_BEQ(); + PC_not_affected = false; + break; + case OP_BNE: + Exec_BNE(); + PC_not_affected = false; + break; + case OP_BLT: + Exec_BLT(); + PC_not_affected = false; + break; + case OP_BGE: + Exec_BGE(); + PC_not_affected = false; + break; + case OP_BLTU: + Exec_BLTU(); + PC_not_affected = false; + break; + case OP_BGEU: + Exec_BGEU(); + PC_not_affected = false; + break; + case OP_LB: + Exec_LB(); + break; + case OP_LH: + Exec_LH(); + break; + case OP_LW: + Exec_LW(); + break; + case OP_LBU: + Exec_LBU(); + break; + case OP_LHU: + Exec_LHU(); + break; + case OP_SB: + Exec_SB(); + break; + case OP_SH: + Exec_SH(); + break; + case OP_SW: + Exec_SW(); + break; + case OP_ADDI: + Exec_ADDI(); + break; + case OP_SLTI: + Exec_SLTI(); + break; + case OP_SLTIU: + Exec_SLTIU(); + break; + case OP_XORI: + Exec_XORI(); + break; + case OP_ORI: + Exec_ORI(); + break; + case OP_ANDI: + Exec_ANDI(); + break; + case OP_SLLI: + PC_not_affected = Exec_SLLI(); + break; + case OP_SRLI: + Exec_SRLI(); + break; + case OP_SRAI: + Exec_SRAI(); + break; + case OP_ADD: + Exec_ADD(); + break; + case OP_SUB: + Exec_SUB(); + break; + case OP_SLL: + Exec_SLL(); + break; + case OP_SLT: + Exec_SLT(); + break; + case OP_SLTU: + Exec_SLTU(); + break; + case OP_XOR: + Exec_XOR(); + break; + case OP_SRL: + Exec_SRL(); + break; + case OP_SRA: + Exec_SRA(); + break; + case OP_OR: + Exec_OR(); + break; + case OP_AND: + Exec_AND(); + break; + case OP_FENCE: + Exec_FENCE(); + break; + case OP_ECALL: + Exec_ECALL(); + *breakpoint = true; + std::cout << "ECALL" << std::endl; + break; + case OP_EBREAK: + PC_not_affected = Exec_EBREAK(); +// *breakpoint = true; + break; + case OP_CSRRW: + Exec_CSRRW(); + break; + case OP_CSRRS: + Exec_CSRRS(); + break; + case OP_CSRRC: + Exec_CSRRC(); + break; + case OP_CSRRWI: + Exec_CSRRWI(); + break; + case OP_CSRRSI: + Exec_CSRRSI(); + break; + case OP_CSRRCI: + Exec_CSRRCI(); + break; + case OP_MRET: + Exec_MRET(); + PC_not_affected = false; + break; + case OP_SRET: + Exec_SRET(); + PC_not_affected = false; + break; + case OP_WFI: + Exec_WFI(); + break; + case OP_SFENCE: + Exec_SFENCE(); + break; + [[unlikely]] default: + std::cout << "Wrong instruction" << "\n"; + inst.dump(); + this->NOP(); + //sc_stop(); + break; + } + + return PC_not_affected; + } /** * @brief Decodes opcode of instruction * @return opcode of instruction */ - opCodes decode(); + opCodes 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 (this->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 (this->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 (this->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 (this->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 (this->get_funct7()) { + case SRLI_F7: + return OP_SRLI; + case SRAI_F7: + return OP_SRAI; + } + return OP_ERROR; + } + return OP_ERROR; + case ADD: { + switch (this->get_funct3()) { + case ADD_F: + switch (this->get_funct7()) { + case ADD_F7: + return OP_ADD; + case SUB_F7: + return OP_SUB; + default: + return OP_ADD; + } + break; + case SLL_F: + return OP_SLL; + case SLT_F: + return OP_SLT; + case SLTU_F: + return OP_SLTU; + case XOR_F: + return OP_XOR; + case SRL_F: + switch (this->get_funct7()) { + case SRL_F7: + return OP_SRL; + case SRA_F7: + return OP_SRA; + default: + return OP_ERROR; + } + case OR_F: + return OP_OR; + case AND_F: + return OP_AND; + default: + return OP_ERROR; + } + } /* ADD */ + case FENCE: + return OP_FENCE; + case ECALL: { + switch (this->get_funct3()) { + case ECALL_F3: + switch (this->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 (this->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; + } }; } #endif diff --git a/inc/CPU.h b/inc/CPU.h index 054c442..b3d7a12 100644 --- a/inc/CPU.h +++ b/inc/CPU.h @@ -73,10 +73,10 @@ namespace riscv_tlm { Registers *register_bank; Performance *perf; std::shared_ptr logger; - C_extension *c_inst; - M_extension *m_inst; - A_extension *a_inst; - BASE_ISA *exec; + C_extension *c_inst; + M_extension *m_inst; + A_extension *a_inst; + BASE_ISA *exec; tlm_utils::tlm_quantumkeeper *m_qk; Instruction inst; diff --git a/inc/C_extension.h b/inc/C_extension.h index 7da29f1..23f0d1d 100644 --- a/inc/C_extension.h +++ b/inc/C_extension.h @@ -95,284 +95,285 @@ namespace riscv_tlm { /** * @brief Instruction decoding and fields access */ - class C_extension : public extension_base { + template + class C_extension : public extension_base { public: /** * @brief Constructor, same as base clase */ - using extension_base::extension_base; + using extension_base::extension_base; /** * @brief Access to opcode field * @return return opcode field */ - inline std::int32_t opcode() const override { - return static_cast(m_instr.range(1, 0)); + [[nodiscard]] inline std::uint32_t opcode() const override { + return static_cast(this->m_instr.range(1, 0)); } - inline std::int32_t get_rdp() const { - return static_cast(m_instr.range(4, 2) + 8); + [[nodiscard]] inline std::uint32_t get_rdp() const { + return static_cast(this->m_instr.range(4, 2) + 8); } /** * @brief Access to rs1 field * @return rs1 field */ - inline std::int32_t get_rs1() const override { - return static_cast(m_instr.range(11, 7)); + [[nodiscard]] inline std::uint32_t get_rs1() const override { + return static_cast(this->m_instr.range(11, 7)); } - inline void set_rs1(std::int32_t value) override { - m_instr.range(11, 7) = value; + inline void set_rs1(std::uint32_t value) override { + this->m_instr.range(11, 7) = value; } - inline std::int32_t get_rs1p() const { - return static_cast(m_instr.range(9, 7) + 8); + [[nodiscard]] inline std::uint32_t get_rs1p() const { + return static_cast(this->m_instr.range(9, 7) + 8); } /** * @brief Access to rs2 field * @return rs2 field */ - inline std::int32_t get_rs2() const override { - return static_cast(m_instr.range(6, 2)); + [[nodiscard]] inline std::uint32_t get_rs2() const override { + return static_cast(this->m_instr.range(6, 2)); } - inline void set_rs2(std::int32_t value) override { - m_instr.range(6, 2) = value; + inline void set_rs2(std::uint32_t value) override { + this->m_instr.range(6, 2) = value; } - inline std::int32_t get_rs2p() const { - return static_cast(m_instr.range(4, 2) + 8); + [[nodiscard]] inline std::uint32_t get_rs2p() const { + return static_cast(this->m_instr.range(4, 2) + 8); } - inline std::int32_t get_funct3() const override { - return static_cast(m_instr.range(15, 13)); + [[nodiscard]] inline std::uint32_t get_funct3() const override { + return static_cast(this->m_instr.range(15, 13)); } - inline void set_funct3(std::int32_t value) override { - m_instr.range(15, 13) = value; + inline void set_funct3(std::uint32_t value) override { + this->m_instr.range(15, 13) = value; } /** * @brief Access to immediate field for I-type * @return immediate_I field */ - inline std::int32_t get_imm_I() const { + [[nodiscard]] inline std::int32_t get_imm_I() const { std::int32_t aux = 0; - aux = static_cast(m_instr.range(31, 20)); + aux = static_cast(this->m_instr.range(31, 20)); /* sign extension (optimize) */ - if (m_instr[31] == 1) { + if (this->m_instr[31] == 1) { aux |= (0b11111111111111111111) << 12; } return aux; } - inline void set_imm_I(std::int32_t value) { - m_instr.range(31, 20) = value; + inline void set_imm_I(std::uint32_t value) { + this->m_instr.range(31, 20) = value; } /** * @brief Access to immediate field for S-type * @return immediate_S field */ - inline std::int32_t get_imm_S() const { + [[nodiscard]] inline std::int32_t get_imm_S() const { std::int32_t aux = 0; - aux = static_cast(m_instr.range(31, 25) << 5); - aux |= static_cast(m_instr.range(11, 7)); + aux = static_cast(this->m_instr.range(31, 25) << 5); + aux |= static_cast(this->m_instr.range(11, 7)); - if (m_instr[31] == 1) { + if (this->m_instr[31] == 1) { aux |= (0b11111111111111111111) << 12; } return aux; } - inline void set_imm_S(std::int32_t value) { + inline void set_imm_S(std::uint32_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); + this->m_instr.range(31, 25) = aux.range(11, 5); + this->m_instr.range(11, 7) = aux.range(4, 0); } /** * @brief Access to immediate field for U-type * @return immediate_U field */ - inline std::int32_t get_imm_U() const { - return static_cast(m_instr.range(31, 12)); + [[nodiscard]] inline std::uint32_t get_imm_U() const { + return static_cast(this->m_instr.range(31, 12)); } - inline void set_imm_U(std::int32_t value) { - m_instr.range(31, 12) = (value << 12); + inline void set_imm_U(std::uint32_t value) { + this->m_instr.range(31, 12) = (value << 12); } /** * @brief Access to immediate field for B-type * @return immediate_B field */ - inline std::int32_t get_imm_B() const { + [[nodiscard]] inline std::int32_t get_imm_B() const { std::int32_t aux = 0; - aux |= static_cast(m_instr[7] << 11); - aux |= static_cast(m_instr.range(30, 25) << 5); - aux |= static_cast(m_instr[31] << 12); - aux |= static_cast(m_instr.range(11, 8) << 1); + aux |= static_cast(this->m_instr[7] << 11); + aux |= static_cast(this->m_instr.range(30, 25) << 5); + aux |= static_cast(this->m_instr[31] << 12); + aux |= static_cast(this->m_instr.range(11, 8) << 1); - if (m_instr[31] == 1) { + if (this->m_instr[31] == 1) { aux |= (0b11111111111111111111) << 12; } return aux; } - inline void set_imm_B(std::int32_t value) { + inline void set_imm_B(std::uint32_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]; + this->m_instr[31] = aux[12]; + this->m_instr.range(30, 25) = aux.range(10, 5); + this->m_instr.range(11, 7) = aux.range(4, 1); + this->m_instr[6] = aux[11]; } /** * @brief Access to immediate field for J-type * @return immediate_J field */ - inline std::int32_t get_imm_J() const { + [[nodiscard]] inline std::int32_t get_imm_J() const { std::int32_t aux = 0; - aux = static_cast(m_instr[12] << 11); - aux |= static_cast(m_instr[11] << 4); - aux |= static_cast(m_instr[10] << 9); - aux |= static_cast(m_instr[9] << 8); - aux |= static_cast(m_instr[8] << 10); - aux |= static_cast(m_instr[7] << 6); - aux |= static_cast(m_instr[6] << 7); - aux |= static_cast(m_instr.range(5, 3) << 1); - aux |= static_cast(m_instr[2] << 5); + aux = static_cast(this->m_instr[12] << 11); + aux |= static_cast(this->m_instr[11] << 4); + aux |= static_cast(this->m_instr[10] << 9); + aux |= static_cast(this->m_instr[9] << 8); + aux |= static_cast(this->m_instr[8] << 10); + aux |= static_cast(this->m_instr[7] << 6); + aux |= static_cast(this->m_instr[6] << 7); + aux |= static_cast(this->m_instr.range(5, 3) << 1); + aux |= static_cast(this->m_instr[2] << 5); - if (m_instr[12] == 1) { + if (this->m_instr[12] == 1) { aux |= 0b11111111111111111111 << 12; } return aux; } - inline void set_imm_J(std::int32_t value) { + inline void set_imm_J(std::uint32_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); + this->m_instr[31] = aux[20]; + this->m_instr.range(30, 21) = aux.range(10, 1); + this->m_instr[20] = aux[11]; + this->m_instr.range(19, 12) = aux.range(19, 12); } - inline std::int32_t get_imm_L() const { + [[nodiscard]] inline std::int32_t get_imm_L() const { std::int32_t aux = 0; - aux = static_cast(m_instr.range(12, 10) << 3); - aux |= static_cast(m_instr[6] << 2); - aux |= static_cast(m_instr[5] << 6); + aux = static_cast(this->m_instr.range(12, 10) << 3); + aux |= static_cast(this->m_instr[6] << 2); + aux |= static_cast(this->m_instr[5] << 6); return aux; } - inline std::int32_t get_imm_LWSP() const { - std::int32_t aux = 0; + [[nodiscard]] inline std::uint32_t get_imm_LWSP() const { + std::uint32_t aux = 0; - aux = static_cast(m_instr[12] << 5); - aux |= static_cast(m_instr.range(6, 4) << 2); - aux |= static_cast(m_instr.range(3, 2) << 6); + aux = static_cast(this->m_instr[12] << 5); + aux |= static_cast(this->m_instr.range(6, 4) << 2); + aux |= static_cast(this->m_instr.range(3, 2) << 6); return aux; } - inline std::int32_t get_imm_ADDI() const { - std::int32_t aux = 0; + [[nodiscard]] inline std::uint32_t get_imm_ADDI() const { + std::uint32_t aux = 0; - aux = static_cast(m_instr[12] << 5); - aux |= static_cast(m_instr.range(6, 2)); + aux = static_cast(this->m_instr[12] << 5); + aux |= static_cast(this->m_instr.range(6, 2)); - if (m_instr[12] == 1) { + if (this->m_instr[12] == 1) { aux |= 0b11111111111111111111111111 << 6; } return aux; } - inline std::int32_t get_imm_ADDI4SPN() const { - std::int32_t aux = 0; + [[nodiscard]] inline std::uint32_t get_imm_ADDI4SPN() const { + std::uint32_t aux = 0; - aux = static_cast(m_instr.range(12, 11) << 4); - aux |= static_cast(m_instr.range(10, 7) << 6); - aux |= static_cast(m_instr[6] << 2); - aux |= static_cast(m_instr[5] << 3); + aux = static_cast(this->m_instr.range(12, 11) << 4); + aux |= static_cast(this->m_instr.range(10, 7) << 6); + aux |= static_cast(this->m_instr[6] << 2); + aux |= static_cast(this->m_instr[5] << 3); return aux; } - inline std::int32_t get_imm_ADDI16SP() const { - std::int32_t aux = 0; + [[nodiscard]] inline std::uint32_t get_imm_ADDI16SP() const { + std::uint32_t aux = 0; - aux = static_cast(m_instr[12] << 9); - aux |= static_cast(m_instr[6] << 4); - aux |= static_cast(m_instr[5] << 6); - aux |= static_cast(m_instr[4] << 8); - aux |= static_cast(m_instr[3] << 7); - aux |= static_cast(m_instr[2] << 5); + aux = static_cast(this->m_instr[12] << 9); + aux |= static_cast(this->m_instr[6] << 4); + aux |= static_cast(this->m_instr[5] << 6); + aux |= static_cast(this->m_instr[4] << 8); + aux |= static_cast(this->m_instr[3] << 7); + aux |= static_cast(this->m_instr[2] << 5); - if (m_instr[12] == 1) { + if (this->m_instr[12] == 1) { aux |= 0b1111111111111111111111 << 10; } return aux; } - inline std::int32_t get_imm_CSS() const { - std::int32_t aux = 0; - aux = static_cast(m_instr.range(12, 9) << 2); - aux |= static_cast(m_instr.range(8, 7) << 6); + [[nodiscard]] inline std::uint32_t get_imm_CSS() const { + std::uint32_t aux = 0; + aux = static_cast(this->m_instr.range(12, 9) << 2); + aux |= static_cast(this->m_instr.range(8, 7) << 6); return aux; } - inline std::int32_t get_imm_CB() const { - std::int32_t aux = 0; + [[nodiscard]] inline std::uint32_t get_imm_CB() const { + std::uint32_t aux = 0; - aux = static_cast(m_instr[12] << 8); - aux |= static_cast(m_instr[11] << 4); - aux |= static_cast(m_instr[10] << 3); - aux |= static_cast(m_instr[6] << 7); - aux |= static_cast(m_instr[5] << 6); - aux |= static_cast(m_instr[4] << 2); - aux |= static_cast(m_instr[3] << 1); - aux |= static_cast(m_instr[2] << 5); + aux = static_cast(this->m_instr[12] << 8); + aux |= static_cast(this->m_instr[11] << 4); + aux |= static_cast(this->m_instr[10] << 3); + aux |= static_cast(this->m_instr[6] << 7); + aux |= static_cast(this->m_instr[5] << 6); + aux |= static_cast(this->m_instr[4] << 2); + aux |= static_cast(this->m_instr[3] << 1); + aux |= static_cast(this->m_instr[2] << 5); - if (m_instr[12] == 1) { + if (this->m_instr[12] == 1) { aux |= 0b11111111111111111111111 << 9; } return aux; } - inline std::int32_t get_imm_LUI() const { - std::int32_t aux = 0; + [[nodiscard]] inline std::uint32_t get_imm_LUI() const { + std::uint32_t aux = 0; - aux = static_cast(m_instr[12] << 17); - aux |= static_cast(m_instr.range(6, 2) << 12); + aux = static_cast(this->m_instr[12] << 17); + aux |= static_cast(this->m_instr.range(6, 2) << 12); - if (m_instr[12] == 1) { + if (this->m_instr[12] == 1) { aux |= 0b111111111111111 << 17; } return aux; } - inline std::int32_t get_csr() const { + [[nodiscard]] inline std::uint32_t get_csr() const { return get_imm_I(); } @@ -380,57 +381,757 @@ namespace riscv_tlm { * @brief Decodes opcode of instruction * @return opcode of instruction */ - op_C_Codes decode() const; + [[nodiscard]] op_C_Codes decode() const { - bool Exec_C_JR(); + switch (opcode()) { - bool Exec_C_MV(); + case 0b00: + switch (get_funct3()) { + case C_ADDI4SPN: + return OP_C_ADDI4SPN; + break; + case C_FLD: + return OP_C_FLD; + break; + case C_LW: + return OP_C_LW; + break; + case C_FLW: + return OP_C_FLW; + break; + case C_FSD: + return OP_C_FSD; + break; + case C_SW: + return OP_C_SW; + break; + case C_FSW: + return OP_C_FSW; + break; + [[unlikely]] default: + return OP_C_ERROR; + break; + } + break; - bool Exec_C_LWSP(); + 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 (this->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 (this->m_instr.range(6, 5)) { + case C_3_SUB: + return OP_C_SUB; + break; + case C_3_XOR: + return OP_C_XOR; + break; + case C_3_OR: + return OP_C_OR; + break; + case C_3_AND: + return OP_C_AND; + break; + } + } + break; + case C_J: + return OP_C_J; + break; + case C_BEQZ: + return OP_C_BEQZ; + break; + case C_BNEZ: + return OP_C_BNEZ; + break; + [[unlikely]] default: + return OP_C_ERROR; + break; + } + break; - bool Exec_C_ADDI4SPN(); + 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 (this->m_instr[12] == 0) { + if (this->m_instr.range(6, 2) == 0) { + return OP_C_JR; + } else { + return OP_C_MV; + } + } else { + if (this->m_instr.range(11, 2) == 0) { + return OP_C_EBREAK; + } else if (this->m_instr.range(6, 2) == 0) { + return OP_C_JALR; + } else { + return OP_C_ADD; + } + } + break; + case C_FDSP: + break; + case C_SWSP: + return OP_C_SWSP; + break; + case C_FWWSP: + [[unlikely]] + default: + return OP_C_ERROR; + break; + } + break; - bool Exec_C_SLLI(); + [[unlikely]] default: - bool Exec_C_ADDI16SP(); + return OP_C_ERROR; + break; + } + return OP_C_ERROR; + } - bool Exec_C_SWSP(); + bool Exec_C_JR() { + std::uint32_t mem_addr; + unsigned int rs1; + std::uint32_t new_pc; - bool Exec_C_BEQZ(); + rs1 = get_rs1(); + mem_addr = 0; - bool Exec_C_BNEZ(); + new_pc = static_cast( + static_cast((this->regs->getValue(rs1)) + static_cast(mem_addr)) & + 0xFFFFFFFE); - bool Exec_C_LI(); + this->logger->debug("{} ns. PC: 0x{:x}. C.JR: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), new_pc); - bool Exec_C_SRLI(); + this->regs->setPC(new_pc); - bool Exec_C_SRAI(); + return true; + } - bool Exec_C_ANDI(); + bool Exec_C_MV() { + unsigned int rd, rs1, rs2; + std::uint32_t calc; - bool Exec_C_ADD(); + rd = this->get_rd(); + rs1 = 0; + rs2 = get_rs2(); - bool Exec_C_SUB(); + calc = this->regs->getValue(rs1) + this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); - bool Exec_C_XOR(); + this->logger->debug("{} ns. PC: 0x{:x}. C.MV: x{:d}(0x{:x}) + x{:d}(0x{:x}) -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), rd, calc); - bool Exec_C_OR(); + return true; + } - bool Exec_C_AND(); + bool Exec_C_ADD() { + unsigned int rd, rs1, rs2; + std::uint32_t calc; - bool Exec_C_ADDI() const; + rd = get_rs1(); + rs1 = get_rs1(); + rs2 = get_rs2(); - bool Exec_C_JALR(); + calc = this->regs->getValue(rs1) + this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); - bool Exec_C_LW(); + this->logger->debug("{} ns. PC: 0x{:x}. C.ADD: x{:d} + x{} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); - bool Exec_C_SW(); + return true; + } - bool Exec_C_JAL(int m_rd); + bool Exec_C_LWSP() { + std::uint32_t mem_addr; + unsigned int rd, rs1; + std::int32_t imm; + std::uint32_t data; - bool Exec_C_EBREAK(); + // lw rd, offset[7:2](x2) + + rd = this->get_rd(); + rs1 = 2; + imm = static_cast(get_imm_LWSP()); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + this->regs->setValue(rd, static_cast(data)); + + this->regs->setValue(rd, data); + + this->logger->debug("{} ns. PC: 0x{:x}. C.LWSP: x{:d} + {:d}(@0x{:x}) -> x{:d}({:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, imm, mem_addr, rd, data); + + return true; + } + + bool Exec_C_ADDI4SPN() { + unsigned int rd, rs1; + std::int32_t imm; + std::int32_t calc; + + rd = get_rdp(); + rs1 = 2; + imm = static_cast(get_imm_ADDI4SPN()); + + if (imm == 0) { + this->RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, this->m_instr); + return false; + } + + calc = static_cast(this->regs->getValue(rs1)) + imm; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. C.ADDI4SN: x{:d} + (0x{:x}) + {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), imm, rd, calc); + + return true; + } + + bool Exec_C_ADDI16SP() { + // addi x2, x2, nzimm[9:4] + unsigned int rd; + std::int32_t imm; + + if (this->get_rd() == 2) { + int rs1; + std::int32_t calc; + + rd = 2; + rs1 = 2; + imm = static_cast(get_imm_ADDI16SP()); + calc = static_cast(this->regs->getValue(rs1)) + imm; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. C.ADDI16SP: x{:d} + {:d} -> x{:d} (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, imm, rd, calc); + } else { + /* C.LUI OPCODE */ + rd = this->get_rd(); + imm = static_cast(get_imm_LUI()); + this->regs->setValue(rd, imm); + + this->logger->debug("{} ns. PC: 0x{:x}. C.LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rd, imm); + } + + return true; + } + + bool Exec_C_SWSP() { + // sw rs2, offset(x2) + std::uint32_t mem_addr; + unsigned int rs1, rs2; + std::int32_t imm; + std::uint32_t data; + + rs1 = 2; + rs2 = get_rs2(); + imm = static_cast(get_imm_CSS()); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. C.SWSP: x{:d}(0x{:x}) -> x{:d} + {} (@0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs2, data, rs1, imm, mem_addr); + + return true; + } + + bool Exec_C_BEQZ() { + unsigned int rs1; + std::uint32_t new_pc; + std::uint32_t val1; + + rs1 = get_rs1p(); + val1 = this->regs->getValue(rs1); + + if (val1 == 0) { + new_pc = static_cast(this->regs->getPC()) + get_imm_CB(); + this->regs->setPC(new_pc); + } else { + this->regs->incPCby2(); + new_pc = static_cast(this->regs->getPC()); + } + + this->logger->debug("{} ns. PC: 0x{:x}. C.BEQZ: x{:d}(0x{:x}) == 0? -> PC (0xx{:d})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, val1, new_pc); + + return true; + } + + bool Exec_C_BNEZ() { + unsigned int rs1; + std::uint32_t new_pc; + std::uint32_t val1; + + rs1 = get_rs1p(); + val1 = this->regs->getValue(rs1); + + if (val1 != 0) { + new_pc = static_cast(this->regs->getPC()) + get_imm_CB(); + this->regs->setPC(new_pc); + } else { + this->regs->incPCby2(); //PC <- PC +2 + new_pc = static_cast(this->regs->getPC()); + } + + this->logger->debug("{} ns. PC: 0x{:x}. C.BNEZ: x{:d}(0x{:x}) != 0? -> PC (0xx{:d})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, val1, new_pc); + + return true; + } + + bool Exec_C_LI() { + unsigned int rd, rs1; + std::int32_t imm; + std::int32_t calc; + + rd = this->get_rd(); + rs1 = 0; + imm = static_cast(get_imm_ADDI()); + calc = static_cast(this->regs->getValue(rs1)) + imm; + + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. C.LI: x{:d} ({:d}) + {:d} -> x{:d}(0x{:x}) ", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), imm, rd, calc); + + return true; + } + + bool Exec_C_SRLI() { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2(); + + shift = rs2 & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. C.SRLI: x{:d} >> {} -> x{:d}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd); + + return true; + } + + bool Exec_C_SRAI() { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::int32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2(); + + shift = rs2 & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. C.SRAI: x{:d} >> {} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + bool Exec_C_SLLI() { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_imm_ADDI(); + + shift = rs2 & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) << shift; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. C.SLLI: x{:d} << {} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + bool Exec_C_ANDI() { + unsigned int rd, rs1; + std::uint32_t imm; + std::uint32_t aux; + std::uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + imm = get_imm_ADDI(); + + aux = this->regs->getValue(rs1); + calc = aux & imm; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. C.ANDI: x{:d}(0x{:x}) AND 0x{:x} -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, aux, imm, rd); + + return true; + } + + bool Exec_C_SUB() { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); + + calc = this->regs->getValue(rs1) - this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. C.SUB: x{:d} - x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); + + return true; + } + + bool Exec_C_XOR() { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); + + calc = this->regs->getValue(rs1) ^ this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. C.XOR: x{:d} XOR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd); + + return true; + } + + bool Exec_C_OR() { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); + + calc = this->regs->getValue(rs1) | this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. C.OR: x{:d} OR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd); + + return true; + } + + bool Exec_C_AND() { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); + + calc = this->regs->getValue(rs1) & this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. C.AND: x{:d} AND x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd); + + return true; + } + + bool Exec_C_ADDI() const { + unsigned int rd, rs1; + std::int32_t imm; + std::int32_t calc; + + rd = this->get_rd(); + rs1 = rd; + imm = static_cast(get_imm_ADDI()); + + calc = static_cast(this->regs->getValue(rs1)) + imm; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. C.ADDI: x{:d} + {} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), rs1, imm, rd, calc); + + return true; + } + + bool Exec_C_JALR() { + std::uint32_t mem_addr = 0; + unsigned int rd, rs1; + std::uint32_t new_pc, old_pc; + + rd = 1; + rs1 = get_rs1(); + + old_pc = static_cast(this->regs->getPC()); + this->regs->setValue(rd, old_pc + 2); + + new_pc = static_cast((this->regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); + this->regs->setPC(new_pc); + + this->logger->debug("{} ns. PC: 0x{:x}. C.JALR: x{:d} <- 0x{:x} PC <- 0xx{:x}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rd, old_pc + 4, new_pc); + + return true; + } + + bool Exec_C_LW() { + std::uint32_t mem_addr; + unsigned int rd, rs1; + std::int32_t imm; + std::uint32_t data; + + rd = get_rdp(); + rs1 = get_rs1p(); + imm = get_imm_L(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + this->regs->setValue(rd, static_cast(data)); + + this->logger->debug("{} ns. PC: 0x{:x}. C.LW: x{:d}(0x{:x}) + {:d} (@0x{:x}) -> {:d} (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), imm, mem_addr, rd, data); + + return true; + } + + bool Exec_C_SW() { + std::uint32_t mem_addr; + unsigned int rs1, rs2; + std::int32_t imm; + std::uint32_t data; + + rs1 = get_rs1p(); + rs2 = get_rs2p(); + imm = get_imm_L(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. C.SW: x{:d}(0x{:x}) -> x{:d} + 0x{:x}(@0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs2, data, rs1, imm, mem_addr); + + return true; + } + + bool Exec_C_JAL(int m_rd) { + std::int32_t mem_addr; + unsigned int rd; + std::uint32_t new_pc, old_pc; + + rd = m_rd; + mem_addr = get_imm_J(); + old_pc = static_cast(this->regs->getPC()); + + new_pc = old_pc + mem_addr; + this->regs->setPC(new_pc); + + old_pc = old_pc + 2; + this->regs->setValue(rd, old_pc); + + this->logger->debug("{} ns. PC: 0x{:x}. C.JAL: x{:d} <- 0x{:x}. PC + 0x{:x} -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rd, old_pc, mem_addr, new_pc); + + return true; + } + + bool Exec_C_EBREAK() { + + this->logger->debug("C.EBREAK"); + std::cout << "\n" << "C.EBRAK Instruction called, dumping information" + << "\n"; + this->regs->dump(); + std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; + this->perf->dump(); + + sc_core::sc_stop(); + + return true; + } + + bool process_instruction(Instruction &inst, bool *breakpoint) { + bool PC_not_affected = true; + + *breakpoint = false; + + this->setInstr(inst.getInstr()); + + switch (decode()) { + case OP_C_ADDI4SPN: + PC_not_affected = Exec_C_ADDI4SPN(); + break; + case OP_C_LW: + Exec_C_LW(); + break; + case OP_C_SW: + Exec_C_SW(); + break; + case OP_C_ADDI: + Exec_C_ADDI(); + break; + case OP_C_JAL: + Exec_C_JAL(1); + PC_not_affected = false; + break; + case OP_C_J: + Exec_C_JAL(0); + PC_not_affected = false; + break; + case OP_C_LI: + Exec_C_LI(); + break; + case OP_C_SLLI: + Exec_C_SLLI(); + break; + case OP_C_LWSP: + Exec_C_LWSP(); + break; + case OP_C_JR: + Exec_C_JR(); + PC_not_affected = false; + break; + case OP_C_MV: + Exec_C_MV(); + break; + case OP_C_JALR: + Exec_C_JALR(); + PC_not_affected = false; + break; + case OP_C_ADD: + Exec_C_ADD(); + break; + case OP_C_SWSP: + Exec_C_SWSP(); + break; + case OP_C_ADDI16SP: + Exec_C_ADDI16SP(); + break; + case OP_C_BEQZ: + Exec_C_BEQZ(); + PC_not_affected = false; + break; + case OP_C_BNEZ: + Exec_C_BNEZ(); + PC_not_affected = false; + break; + case OP_C_SRLI: + Exec_C_SRLI(); + break; + case OP_C_SRAI: + Exec_C_SRAI(); + break; + case OP_C_ANDI: + Exec_C_ANDI(); + break; + case OP_C_SUB: + Exec_C_SUB(); + break; + case OP_C_XOR: + Exec_C_XOR(); + break; + case OP_C_OR: + Exec_C_OR(); + break; + case OP_C_AND: + Exec_C_AND(); + break; + case OP_C_EBREAK: + Exec_C_EBREAK(); + std::cout << "C_EBREAK" << std::endl; + *breakpoint = true; + break; + [[unlikely]] default: + std::cout << "C instruction not implemented yet" << "\n"; + inst.dump(); + this->NOP(); + break; + } + + return PC_not_affected; + } - bool process_instruction(Instruction &inst, bool *breakpoint = nullptr); }; } diff --git a/inc/M_extension.h b/inc/M_extension.h index 073cd85..0871853 100644 --- a/inc/M_extension.h +++ b/inc/M_extension.h @@ -43,41 +43,298 @@ namespace riscv_tlm { /** * @brief Instruction decoding and fields access */ - class M_extension : public extension_base { + template + class M_extension : public extension_base { public: /** * @brief Constructor, same as base clase */ - using extension_base::extension_base; + using extension_base::extension_base; /** * @brief Decodes opcode of instruction * @return opcode of instruction */ - op_M_Codes decode() const; + [[nodiscard]] op_M_Codes decode() const { - inline void dump() const override { - std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; + switch (opcode()) { + case M_MUL: + return OP_M_MUL; + break; + case M_MULH: + return OP_M_MULH; + break; + case M_MULHSU: + return OP_M_MULHSU; + break; + case M_MULHU: + return OP_M_MULHU; + break; + case M_DIV: + return OP_M_DIV; + break; + case M_DIVU: + return OP_M_DIVU; + break; + case M_REM: + return OP_M_REM; + break; + case M_REMU: + return OP_M_REMU; + break; + [[unlikely]] default: + return OP_M_ERROR; + break; + } + + return OP_M_ERROR; } - bool Exec_M_MUL() const; + inline void dump() const override { + std::cout << std::hex << "0x" << this->m_instr << std::dec << std::endl; + } - bool Exec_M_MULH() const; + void Exec_M_MUL() const { + unsigned int rd, rs1, rs2; + std::int32_t multiplier, multiplicand; + std::int64_t result; - bool Exec_M_MULHSU() const; + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool Exec_M_MULHU() const; + multiplier = static_cast(extension_base::regs->getValue(rs1)); + multiplicand = static_cast(extension_base::regs->getValue(rs2)); - bool Exec_M_DIV() const; + result = static_cast(multiplier * multiplicand); + result = result & 0x00000000FFFFFFFF; + this->regs->setValue(rd, static_cast(result)); - bool Exec_M_DIVU() const; + this->logger->debug("{} ns. PC: 0x{:x}. M.MUL: x{:d} * x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + extension_base::regs->getPC(), + rs1, rs2, rd, result); + } - bool Exec_M_REM() const; + void Exec_M_MULH() const { + unsigned int rd, rs1, rs2; + std::int32_t multiplier, multiplicand; + std::int64_t result; + std::int32_t ret_value; - bool Exec_M_REMU() const; + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool process_instruction(Instruction &inst); + multiplier = static_cast(this->regs->getValue(rs1)); + multiplicand = static_cast(this->regs->getValue(rs2)); + + result = static_cast(multiplier) * static_cast(multiplicand); + + ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); + this->regs->setValue(rd, ret_value); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULH: x{:d} * x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_MULHSU() const { + unsigned int rd, rs1, rs2; + std::int32_t multiplier; + std::uint32_t multiplicand; + std::int64_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = static_cast(this->regs->getValue(rs1)); + multiplicand = this->regs->getValue(rs2); + + result = static_cast(multiplier * static_cast(multiplicand)); + result = (result >> 32) & 0x00000000FFFFFFFF; + this->regs->setValue(rd, static_cast(result)); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULHSU: x{:d} * x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_MULHU() const { + unsigned int rd, rs1, rs2; + std::uint32_t multiplier, multiplicand; + std::uint64_t result; + std::int32_t ret_value; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = static_cast(this->regs->getValue(rs1)); + multiplicand = static_cast(this->regs->getValue(rs2)); + + result = static_cast(multiplier) * static_cast(multiplicand); + ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); + this->regs->setValue(rd, ret_value); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULHU: x{:d} * x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_DIV() const { + unsigned int rd, rs1, rs2; + std::int32_t divisor, dividend; + std::int64_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + dividend = static_cast(this->regs->getValue(rs1)); + divisor = static_cast(this->regs->getValue(rs2)); + + if (divisor == 0) { + result = -1; + } else if ((divisor == -1) && (dividend == static_cast(0x80000000))) { + result = 0x0000000080000000; + } else { + result = dividend / divisor; + result = result & 0x00000000FFFFFFFF; + } + + this->regs->setValue(rd, static_cast(result)); + + this->logger->debug("{} ns. PC: 0x{:x}. M.DIV: x{:d} / x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_DIVU() const { + unsigned int rd, rs1, rs2; + std::uint32_t divisor, dividend; + std::uint64_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + dividend = this->regs->getValue(rs1); + divisor = this->regs->getValue(rs2); + + if (divisor == 0) { + result = -1; + } else { + result = dividend / divisor; + result = result & 0x00000000FFFFFFFF; + } + + this->regs->setValue(rd, static_cast(result)); + + this->logger->debug("{} ns. PC: 0x{:x}. M.DIVU: x{:d} / x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_REM() const { + unsigned int rd, rs1, rs2; + std::int32_t divisor, dividend; + std::int32_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + dividend = static_cast(this->regs->getValue(rs1)); + divisor = static_cast(this->regs->getValue(rs2)); + + if (divisor == 0) { + result = dividend; + } else if ((divisor == -1) && (dividend == static_cast(0x80000000))) { + result = 0; + } else { + result = dividend % divisor; + } + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.REM: x{:d} / x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_REMU() const { + unsigned int rd, rs1, rs2; + std::uint32_t divisor, dividend; + std::uint32_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + dividend = static_cast(this->regs->getValue(rs1)); + divisor = static_cast(this->regs->getValue(rs2)); + + if (divisor == 0) { + result = dividend; + } else { + result = dividend % divisor; + } + + this->regs->setValue(rd, static_cast(result)); + + this->logger->debug("{} ns. PC: 0x{:x}. M.REMU: x{:d} / x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + bool process_instruction(Instruction &inst) { + this->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; + [[unlikely]] default: + std::cout << "M instruction not implemented yet" << "\n"; + inst.dump(); + //NOP(inst); + sc_core::sc_stop(); + break; + } + + return true; + } private: @@ -85,8 +342,8 @@ namespace riscv_tlm { * @brief Access to opcode field * @return return opcode field */ - inline std::int32_t opcode() const override { - return static_cast(m_instr.range(14, 12)); + [[nodiscard]] inline std::uint32_t opcode() const override { + return static_cast(this->m_instr.range(14, 12)); } }; diff --git a/inc/Registers.h b/inc/Registers.h index 0812cf5..bcd0b28 100644 --- a/inc/Registers.h +++ b/inc/Registers.h @@ -10,6 +10,7 @@ #define REGISTERS_H #define SC_INCLUDE_DYNAMIC_PROCESSES + #include #include @@ -188,11 +189,11 @@ namespace riscv_tlm { * Default constructor */ Registers() { - perf = Performance::getInstance(); + perf = Performance::getInstance(); - initCSR(); - register_bank[sp] = Memory::SIZE - 4; // default stack at the end of the memory - register_PC = 0x80000000; // default _start address + initCSR(); + register_bank[sp] = Memory::SIZE - 4; // default stack at the end of the memory + register_PC = 0x80000000; // default _start address }; /** @@ -200,10 +201,10 @@ namespace riscv_tlm { * @param reg_num register number * @param value register value */ - void setValue(int reg_num, T value) { - if ((reg_num != 0) && (reg_num < 32)) { - register_bank[reg_num] = value; - perf->registerWrite(); + void setValue(unsigned int reg_num, T value) { + if ((reg_num != 0) && (reg_num < 32)) { + register_bank[reg_num] = value; + perf->registerWrite(); } } @@ -212,13 +213,13 @@ namespace riscv_tlm { * @param reg_num register number * @return register value */ - T getValue(int reg_num) const { - if ((reg_num >= 0) && (reg_num < 32)) { - perf->registerRead(); - return register_bank[reg_num]; + T getValue(unsigned int reg_num) const { + if (reg_num < 32) { + perf->registerRead(); + return register_bank[reg_num]; } else { - /* TODO Exten sign for any possible T type */ - return static_cast(0xFFFFFFFF); + /* Extend sign for any possible T type */ + return static_cast(std::numeric_limits::max()); } } @@ -227,7 +228,7 @@ namespace riscv_tlm { * @return PC value */ T getPC() const { - return register_PC; + return register_PC; } /** @@ -235,7 +236,7 @@ namespace riscv_tlm { * @param new_pc new address to PC */ void setPC(T new_pc) { - register_PC = new_pc; + register_PC = new_pc; } /** @@ -255,40 +256,40 @@ namespace riscv_tlm { * @return CSR value */ T getCSR(int csr) { - T ret_value; + T ret_value; - switch (csr) { - case CSR_CYCLE: - case CSR_MCYCLE: - ret_value = static_cast(sc_core::sc_time( - sc_core::sc_time_stamp() - - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) - & 0x00000000FFFFFFFF; - break; - case CSR_CYCLEH: - case CSR_MCYCLEH: - ret_value = static_cast((std::uint64_t) (sc_core::sc_time( - sc_core::sc_time_stamp() - - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) - >> 32 & 0x00000000FFFFFFFF); - break; - case CSR_TIME: - ret_value = static_cast(sc_core::sc_time( - sc_core::sc_time_stamp() - - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) - & 0x00000000FFFFFFFF; - break; - case CSR_TIMEH: - ret_value = static_cast((std::uint64_t) (sc_core::sc_time( - sc_core::sc_time_stamp() - - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) - >> 32 & 0x00000000FFFFFFFF); - break; - [[likely]] default: - ret_value = CSR[csr]; - break; + switch (csr) { + case CSR_CYCLE: + case CSR_MCYCLE: + ret_value = static_cast(sc_core::sc_time( + sc_core::sc_time_stamp() + - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) + & 0x00000000FFFFFFFF; + break; + case CSR_CYCLEH: + case CSR_MCYCLEH: + ret_value = static_cast((std::uint64_t) (sc_core::sc_time( + sc_core::sc_time_stamp() + - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) + >> 32 & 0x00000000FFFFFFFF); + break; + case CSR_TIME: + ret_value = static_cast(sc_core::sc_time( + sc_core::sc_time_stamp() + - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) + & 0x00000000FFFFFFFF; + break; + case CSR_TIMEH: + ret_value = static_cast((std::uint64_t) (sc_core::sc_time( + sc_core::sc_time_stamp() + - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) + >> 32 & 0x00000000FFFFFFFF); + break; + [[likely]] default: + ret_value = CSR[csr]; + break; } - return ret_value; + return ret_value; } /** @@ -297,11 +298,11 @@ namespace riscv_tlm { * @param value new value to register */ void setCSR(int csr, T value) { - /* @FIXME: rv32mi-p-ma_fetch tests doesn't allow MISA to be writable, - * but Volume II: Privileged Architecture v1.10 says MISA is writable (?) - */ - if (csr != CSR_MISA) { - CSR[csr] = value; + /* @FIXME: rv32mi-p-ma_fetch tests doesn't allow MISA to be writable, + * but Volume II: Privileged Architecture v1.10 says MISA is writable (?) + */ + if (csr != CSR_MISA) { + CSR[csr] = value; } } @@ -309,83 +310,83 @@ namespace riscv_tlm { * Dump register data to console */ void dump() { - std::cout << "************************************" << std::endl; - std::cout << "Registers dump" << std::dec << std::endl; - std::cout << std::setfill('0') << std::uppercase; - std::cout << "x0 (zero): 0x" << std::right << std::setw(8) - << std::hex << register_bank[0]; - std::cout << " x1 (ra): 0x" << std::right << std::setw(8) - << std::hex << register_bank[1]; - std::cout << " x2 (sp): 0x" << std::right << std::setw(8) - << std::hex << register_bank[2]; - std::cout << " x3 (gp): 0x" << std::right << std::setw(8) - << std::hex << register_bank[3] << std::endl; + std::cout << "************************************" << std::endl; + std::cout << "Registers dump" << std::dec << std::endl; + std::cout << std::setfill('0') << std::uppercase; + std::cout << "x0 (zero): 0x" << std::right << std::setw(8) + << std::hex << register_bank[0]; + std::cout << " x1 (ra): 0x" << std::right << std::setw(8) + << std::hex << register_bank[1]; + std::cout << " x2 (sp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[2]; + std::cout << " x3 (gp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[3] << std::endl; - std::cout << "x4 (tp): 0x" << std::right << std::setw(8) - << std::hex << register_bank[4]; - std::cout << " x5 (t0): 0x" << std::right << std::setw(8) - << std::hex << register_bank[5]; - std::cout << " x6 (t1): 0x" << std::right << std::setw(8) - << std::hex << register_bank[6]; - std::cout << " x7 (t2): 0x" << std::right << std::setw(8) - << std::hex << register_bank[7] << std::endl; + std::cout << "x4 (tp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[4]; + std::cout << " x5 (t0): 0x" << std::right << std::setw(8) + << std::hex << register_bank[5]; + std::cout << " x6 (t1): 0x" << std::right << std::setw(8) + << std::hex << register_bank[6]; + std::cout << " x7 (t2): 0x" << std::right << std::setw(8) + << std::hex << register_bank[7] << std::endl; - std::cout << "x8 (s0/fp): 0x" << std::right << std::setw(8) - << std::hex << register_bank[8]; - std::cout << " x9 (s1): 0x" << std::right << std::setw(8) - << std::hex << register_bank[9]; - std::cout << " x10 (a0): 0x" << std::right << std::setw(8) - << std::hex << register_bank[10]; - std::cout << " x11 (a1): 0x" << std::right << std::setw(8) - << std::hex << register_bank[11] << std::endl; + std::cout << "x8 (s0/fp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[8]; + std::cout << " x9 (s1): 0x" << std::right << std::setw(8) + << std::hex << register_bank[9]; + std::cout << " x10 (a0): 0x" << std::right << std::setw(8) + << std::hex << register_bank[10]; + std::cout << " x11 (a1): 0x" << std::right << std::setw(8) + << std::hex << register_bank[11] << std::endl; - std::cout << "x12 (a2): 0x" << std::right << std::setw(8) - << std::hex << register_bank[12]; - std::cout << " x13 (a3): 0x" << std::right << std::setw(8) - << std::hex << register_bank[13]; - std::cout << " x14 (a4): 0x" << std::right << std::setw(8) - << std::hex << register_bank[14]; - std::cout << " x15 (a5): 0x" << std::right << std::setw(8) - << std::hex << register_bank[15] << std::endl; + std::cout << "x12 (a2): 0x" << std::right << std::setw(8) + << std::hex << register_bank[12]; + std::cout << " x13 (a3): 0x" << std::right << std::setw(8) + << std::hex << register_bank[13]; + std::cout << " x14 (a4): 0x" << std::right << std::setw(8) + << std::hex << register_bank[14]; + std::cout << " x15 (a5): 0x" << std::right << std::setw(8) + << std::hex << register_bank[15] << std::endl; - std::cout << "x16 (a6): 0x" << std::right << std::setw(8) - << std::hex << register_bank[16]; - std::cout << " x17 (a7): 0x" << std::right << std::setw(8) - << std::hex << register_bank[17]; - std::cout << " x18 (s2): 0x" << std::right << std::setw(8) - << std::hex << register_bank[18]; - std::cout << " x19 (s3): 0x" << std::right << std::setw(8) - << std::hex << register_bank[19] << std::endl; + std::cout << "x16 (a6): 0x" << std::right << std::setw(8) + << std::hex << register_bank[16]; + std::cout << " x17 (a7): 0x" << std::right << std::setw(8) + << std::hex << register_bank[17]; + std::cout << " x18 (s2): 0x" << std::right << std::setw(8) + << std::hex << register_bank[18]; + std::cout << " x19 (s3): 0x" << std::right << std::setw(8) + << std::hex << register_bank[19] << std::endl; - std::cout << "x20 (s4): 0x" << std::right << std::setw(8) - << std::hex << register_bank[20]; - std::cout << " x21 (s5): 0x" << std::right << std::setw(8) - << std::hex << register_bank[21]; - std::cout << " x22 (s6): 0x" << std::right << std::setw(8) - << std::hex << register_bank[22]; - std::cout << " x23 (s7): 0x" << std::right << std::setw(8) - << std::hex << register_bank[23] << std::endl; + std::cout << "x20 (s4): 0x" << std::right << std::setw(8) + << std::hex << register_bank[20]; + std::cout << " x21 (s5): 0x" << std::right << std::setw(8) + << std::hex << register_bank[21]; + std::cout << " x22 (s6): 0x" << std::right << std::setw(8) + << std::hex << register_bank[22]; + std::cout << " x23 (s7): 0x" << std::right << std::setw(8) + << std::hex << register_bank[23] << std::endl; - std::cout << "x24 (s8): 0x" << std::right << std::setw(8) - << std::hex << register_bank[24]; - std::cout << " x25 (s9): 0x" << std::right << std::setw(8) - << std::hex << register_bank[25]; - std::cout << " x26 (s10): 0x" << std::right << std::setw(8) - << std::hex << register_bank[26]; - std::cout << " x27 (s11): 0x" << std::right << std::setw(8) - << std::hex << register_bank[27] << std::endl; + std::cout << "x24 (s8): 0x" << std::right << std::setw(8) + << std::hex << register_bank[24]; + std::cout << " x25 (s9): 0x" << std::right << std::setw(8) + << std::hex << register_bank[25]; + std::cout << " x26 (s10): 0x" << std::right << std::setw(8) + << std::hex << register_bank[26]; + std::cout << " x27 (s11): 0x" << std::right << std::setw(8) + << std::hex << register_bank[27] << std::endl; - std::cout << "x28 (t3): 0x" << std::right << std::setw(8) - << std::hex << register_bank[28]; - std::cout << " x29 (t4): 0x" << std::right << std::setw(8) - << std::hex << register_bank[29]; - std::cout << " x30 (t5): 0x" << std::right << std::setw(8) - << std::hex << register_bank[30]; - std::cout << " x31 (t6): 0x" << std::right << std::setw(8) - << std::hex << register_bank[31] << std::endl; + std::cout << "x28 (t3): 0x" << std::right << std::setw(8) + << std::hex << register_bank[28]; + std::cout << " x29 (t4): 0x" << std::right << std::setw(8) + << std::hex << register_bank[29]; + std::cout << " x30 (t5): 0x" << std::right << std::setw(8) + << std::hex << register_bank[30]; + std::cout << " x31 (t6): 0x" << std::right << std::setw(8) + << std::hex << register_bank[31] << std::endl; - std::cout << "PC: 0x" << std::setw(8) << std::hex << register_PC << std::dec << std::endl; - std::cout << "************************************" << std::endl; + std::cout << "PC: 0x" << std::setw(8) << std::hex << register_PC << std::dec << std::endl; + std::cout << "************************************" << std::endl; } private: @@ -407,9 +408,9 @@ namespace riscv_tlm { Performance *perf; void 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/inc/extension_base.h b/inc/extension_base.h index 2ae1473..3abf2e6 100644 --- a/inc/extension_base.h +++ b/inc/extension_base.h @@ -34,87 +34,88 @@ namespace riscv_tlm { public: extension_base(const T &instr, Registers *register_bank, MemoryInterface *mem_interface) : - m_instr(instr), regs(register_bank), mem_intf(mem_interface) { + m_instr(instr), regs(register_bank), mem_intf(mem_interface) { - perf = Performance::getInstance(); - logger = spdlog::get("my_logger"); + perf = Performance::getInstance(); + logger = spdlog::get("my_logger"); } virtual ~extension_base() = default; void setInstr(std::uint32_t p_instr) { - m_instr = sc_dt::sc_uint<32>(p_instr); + m_instr = sc_dt::sc_uint<32>(p_instr); } void RaiseException(std::uint32_t cause, std::uint32_t inst) { - std::uint32_t new_pc, current_pc, m_cause; + std::uint32_t new_pc, current_pc, m_cause; - current_pc = regs->getPC(); - m_cause = regs->getCSR(CSR_MSTATUS); - m_cause |= cause; + current_pc = regs->getPC(); + m_cause = regs->getCSR(CSR_MSTATUS); + m_cause |= cause; - new_pc = regs->getCSR(CSR_MTVEC); + new_pc = regs->getCSR(CSR_MTVEC); - regs->setCSR(CSR_MEPC, current_pc); + regs->setCSR(CSR_MEPC, current_pc); - if (cause == EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION) { - regs->setCSR(CSR_MTVAL, inst); + if (cause == EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION) { + regs->setCSR(CSR_MTVAL, inst); } else { - regs->setCSR(CSR_MTVAL, current_pc); + regs->setCSR(CSR_MTVAL, current_pc); } - regs->setCSR(CSR_MCAUSE, cause); - regs->setCSR(CSR_MSTATUS, m_cause); + regs->setCSR(CSR_MCAUSE, cause); + regs->setCSR(CSR_MSTATUS, m_cause); - regs->setPC(new_pc); + regs->setPC(new_pc); - logger->debug("{} ns. PC: 0x{:x}. Exception! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC(), - new_pc); + logger->debug("{} ns. PC: 0x{:x}. Exception! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), + regs->getPC(), + new_pc); } bool NOP() { - logger->debug("{} ns. PC: 0x{:x}. NOP! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC()); - sc_core::sc_stop(); - return true; + logger->debug("{} ns. PC: 0x{:x}. NOP! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC()); + sc_core::sc_stop(); + return true; } /* pure virtual functions */ - virtual std::int32_t opcode() const = 0; + virtual T opcode() const = 0; - virtual std::int32_t get_rd() const { + virtual unsigned int get_rd() const { return m_instr.range(11, 7); } - virtual void set_rd(std::int32_t value) { + virtual void set_rd(unsigned int value) { m_instr.range(11, 7) = value; } - virtual std::int32_t get_rs1() const { + virtual unsigned int get_rs1() const { return m_instr.range(19, 15); } - virtual void set_rs1(std::int32_t value) { + virtual void set_rs1(unsigned int value) { m_instr.range(19, 15) = value; } - virtual std::int32_t get_rs2() const { + virtual unsigned int get_rs2() const { return m_instr.range(24, 20); } - virtual void set_rs2(std::int32_t value) { + virtual void set_rs2(unsigned int value) { m_instr.range(24, 20) = value; } - virtual std::int32_t get_funct3() const { + virtual unsigned int get_funct3() const { return m_instr.range(14, 12); } - virtual void set_funct3(std::int32_t value) { + virtual void set_funct3(unsigned int value) { m_instr.range(14, 12) = value; } virtual void dump() const { - std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; + std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; } protected: diff --git a/src/A_extension.cpp b/src/A_extension.cpp index b603772..5b83563 100644 --- a/src/A_extension.cpp +++ b/src/A_extension.cpp @@ -6,440 +6,4 @@ */ // SPDX-License-Identifier: GPL-3.0-or-later -#include "A_extension.h" - -namespace riscv_tlm { - - op_A_Codes A_extension::decode() const { - - switch (opcode()) { - case A_LR: - return OP_A_LR; - break; - case A_SC: - return OP_A_SC; - break; - case A_AMOSWAP: - return OP_A_AMOSWAP; - break; - case A_AMOADD: - return OP_A_AMOADD; - break; - case A_AMOXOR: - return OP_A_AMOXOR; - break; - case A_AMOAND: - return OP_A_AMOAND; - break; - case A_AMOOR: - return OP_A_AMOOR; - break; - case A_AMOMIN: - return OP_A_AMOMIN; - break; - case A_AMOMAX: - return OP_A_AMOMAX; - break; - case A_AMOMINU: - return OP_A_AMOMINU; - break; - case A_AMOMAXU: - return OP_A_AMOMAXU; - break; - [[unlikely]] default: - return OP_A_ERROR; - break; - - } - - return OP_A_ERROR; - } - - bool A_extension::Exec_A_LR() { - std::uint32_t mem_addr = 0; - int rd, rs1, rs2; - std::uint32_t data; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (rs2 != 0) { - std::cout << "ILEGAL INSTRUCTION, LR.W: rs2 != 0" << std::endl; - RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr); - - return false; - } - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); - - TLB_reserve(mem_addr); - - logger->debug("{} ns. PC: 0x{:x}. A.LR.W: x{:d}(0x{:x}) -> x{:d}(0x{:x}) ", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, mem_addr, rd, data); - - return true; - } - - bool A_extension::Exec_A_SC() { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = regs->getValue(rs2); - - if (TLB_reserved(mem_addr)) { - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); - regs->setValue(rd, 0); // SC writes 0 to rd on success - } else { - regs->setValue(rd, 1); // SC writes nonzero on failure - } - - logger->debug("{} ns. PC: 0x{:x}. A.SC.W: (0x{:x}) <- x{:d}(0x{:x}) ", sc_core::sc_time_stamp().value(), - regs->getPC(), - mem_addr, rs2, data); - - return true; - } - - bool A_extension::Exec_A_AMOSWAP() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - std::uint32_t aux; - - /* These instructions must be atomic */ - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); - - // swap - aux = regs->getValue(rs2); - regs->setValue(rs2, static_cast(data)); - - mem_intf->writeDataMem(mem_addr, aux, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOSWAP"); - - return true; - } - - bool A_extension::Exec_A_AMOADD() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::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); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // add - data = data + regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOADD"); - - return true; - } - - bool A_extension::Exec_A_AMOXOR() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::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); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // add - data = data ^ regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOXOR"); - - return true; - } - - bool A_extension::Exec_A_AMOAND() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::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); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // add - data = data & regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOAND"); - - return true; - } - - bool A_extension::Exec_A_AMOOR() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::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); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // add - data = data | regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOOR"); - - return true; - } - - bool A_extension::Exec_A_AMOMIN() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - std::uint32_t aux; - - /* These instructions must be atomic */ - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // min - aux = regs->getValue(rs2); - if ((int32_t) data < (int32_t) aux) { - aux = data; - } - - mem_intf->writeDataMem(mem_addr, aux, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOMIN"); - - return true; - } - - bool A_extension::Exec_A_AMOMAX() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - std::uint32_t aux; - - /* These instructions must be atomic */ - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // > - aux = regs->getValue(rs2); - if ((int32_t) data > (int32_t) aux) { - aux = data; - } - - mem_intf->writeDataMem(mem_addr, aux, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOMAX"); - - return true; - } - - bool A_extension::Exec_A_AMOMINU() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - std::uint32_t aux; - - /* These instructions must be atomic */ - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // min - aux = regs->getValue(rs2); - if (data < aux) { - aux = data; - } - - mem_intf->writeDataMem(mem_addr, aux, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOMINU"); - - return true; - } - - bool A_extension::Exec_A_AMOMAXU() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - std::uint32_t aux; - - /* These instructions must be atomic */ - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // max - aux = regs->getValue(rs2); - if (data > aux) { - aux = data; - } - - mem_intf->writeDataMem(mem_addr, aux, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOMAXU"); - - return true; - } - - void A_extension::TLB_reserve(std::uint32_t address) { - TLB_A_Entries.insert(address); - } - - bool A_extension::TLB_reserved(std::uint32_t address) { - if (TLB_A_Entries.count(address) == 1) { - TLB_A_Entries.erase(address); - return true; - } else { - return false; - } - } - - bool A_extension::process_instruction(Instruction &inst) { - bool PC_not_affected = true; - - setInstr(inst.getInstr()); - - switch (decode()) { - case OP_A_LR: - Exec_A_LR(); - break; - case OP_A_SC: - Exec_A_SC(); - break; - case OP_A_AMOSWAP: - Exec_A_AMOSWAP(); - break; - case OP_A_AMOADD: - Exec_A_AMOADD(); - break; - case OP_A_AMOXOR: - Exec_A_AMOXOR(); - break; - case OP_A_AMOAND: - Exec_A_AMOAND(); - break; - case OP_A_AMOOR: - Exec_A_AMOOR(); - break; - case OP_A_AMOMIN: - Exec_A_AMOMIN(); - break; - case OP_A_AMOMAX: - Exec_A_AMOMAX(); - break; - case OP_A_AMOMINU: - Exec_A_AMOMINU(); - break; - case OP_A_AMOMAXU: - Exec_A_AMOMAXU(); - break; - [[unlikely]] default: - std::cout << "A instruction not implemented yet" << std::endl; - inst.dump(); - NOP(); - break; - } - - return PC_not_affected; - } -} \ No newline at end of file +#include "A_extension.h" \ No newline at end of file diff --git a/src/BASE_ISA.cpp b/src/BASE_ISA.cpp index 3c48db6..1e65da0 100644 --- a/src/BASE_ISA.cpp +++ b/src/BASE_ISA.cpp @@ -6,1478 +6,3 @@ */ // SPDX-License-Identifier: GPL-3.0-or-later -#include "spdlog/spdlog.h" - - -#include "BASE_ISA.h" - -namespace riscv_tlm { - - enum Codes { - 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, - }; - - bool BASE_ISA::Exec_LUI() const { - int rd; - std::uint32_t imm; - - rd = get_rd(); - imm = get_imm_U() << 12; - regs->setValue(rd, static_cast(imm)); - - logger->debug("{} ns. PC: 0x{:x}. LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), - rd, imm); - - return true; - } - - bool BASE_ISA::Exec_AUIPC() const { - int rd; - std::uint32_t imm; - std::uint32_t new_pc; - - rd = get_rd(); - imm = get_imm_U() << 12; - new_pc = static_cast(regs->getPC() + imm); - - regs->setValue(rd, new_pc); - - logger->debug("{} ns. PC: 0x{:x}. AUIPC: x{:d} <- 0x{:x} + PC (0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rd, imm, new_pc); - - return true; - } - - bool BASE_ISA::Exec_JAL() const { - std::int32_t mem_addr; - int rd; - std::uint32_t 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); - - logger->debug("{} ns. PC: 0x{:x}. JAL: x{:d} <- 0x{:x}. PC + 0x{:x} -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rd, old_pc, mem_addr, new_pc); - - return true; - } - - bool BASE_ISA::Exec_JALR() { - std::uint32_t mem_addr; - int rd, rs1; - std::uint32_t new_pc, old_pc; - - rd = get_rd(); - rs1 = get_rs1(); - mem_addr = get_imm_I(); - - old_pc = regs->getPC(); - regs->setValue(rd, old_pc + 4); - - new_pc = static_cast((regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); - - if ((new_pc & 0x00000003) != 0) { - // not aligned - logger->debug("{} ns. PC: 0x{:x}. JALR: x{:d} <- 0x{:x} PC <- 0x{:x}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rd, old_pc + 4, new_pc); - - logger->debug("{} ns. PC: 0x{:x}. JALR : Exception"); - RaiseException(EXCEPTION_CAUSE_LOAD_ADDR_MISALIGN, m_instr); - } else { - regs->setPC(new_pc); - } - - logger->debug("{} ns. PC: 0x{:x}. JALR: x{:d} <- 0x{:x}. PC <- 0x{:x}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rd, old_pc + 4, new_pc); - - return true; - } - - bool BASE_ISA::Exec_BEQ() const { - int rs1, rs2; - std::uint32_t new_pc; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (regs->getValue(rs1) == regs->getValue(rs2)) { - new_pc = static_cast(regs->getPC() + get_imm_B()); - regs->setPC(new_pc); - } else { - regs->incPC(); - new_pc = static_cast(regs->getPC()); - } - - logger->debug("{} ns. PC: 0x{:x}. BEQ: x{:d}(0x{:x}) == x{:d}(0x{:x})? -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - - return true; - } - - bool BASE_ISA::Exec_BNE() const { - int rs1, rs2; - std::uint32_t new_pc; - std::uint32_t val1, val2; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - val1 = regs->getValue(rs1); - val2 = regs->getValue(rs2); - - if (val1 != val2) { - new_pc = static_cast(regs->getPC() + get_imm_B()); - regs->setPC(new_pc); - } else { - regs->incPC(); - new_pc = static_cast(regs->getPC()); - } - - logger->debug("{} ns. PC: 0x{:x}. BNE: x{:d}(0x{:x}) != x{:d}(0x{:x})? -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, val1, rs2, val2, new_pc); - - return true; - } - - bool BASE_ISA::Exec_BLT() const { - int rs1, rs2; - std::uint32_t new_pc = 0; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (static_cast(regs->getValue(rs1)) < static_cast(regs->getValue(rs2))) { - new_pc = static_cast(regs->getPC() + get_imm_B()); - regs->setPC(new_pc); - } else { - regs->incPC(); - } - - logger->debug("{} ns. PC: 0x{:x}. BLT: x{:d}(0x{:x}) < x{:d}(0x{:x})? -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - - return true; - } - - bool BASE_ISA::Exec_BGE() const { - int rs1, rs2; - std::uint32_t new_pc = 0; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (static_cast(regs->getValue(rs1)) >= static_cast( regs->getValue(rs2))) { - new_pc = static_cast(regs->getPC() + get_imm_B()); - regs->setPC(new_pc); - } else { - regs->incPC(); - } - - logger->debug("{} ns. PC: 0x{:x}. BGE: x{:d}(0x{:x}) > x{:d}(0x{:x})? -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - - return true; - } - - bool BASE_ISA::Exec_BLTU() const { - int rs1, rs2; - std::uint32_t new_pc; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (static_cast(regs->getValue(rs1)) < static_cast(regs->getValue(rs2))) { - new_pc = static_cast(regs->getPC() + get_imm_B()); - regs->setPC(new_pc); - } else { - regs->incPC(); - new_pc = static_cast(regs->getPC()); - } - - logger->debug("{} ns. PC: 0x{:x}. BLTU: x{:d}(0x{:x}) < x{:d}(0x{:x})? -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - - return true; - } - - bool BASE_ISA::Exec_BGEU() const { - int rs1, rs2; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (static_cast(regs->getValue(rs1)) >= static_cast(regs->getValue(rs2))) { - std::uint32_t new_pc; - new_pc = static_cast(regs->getPC() + get_imm_B()); - - logger->debug("{} ns. PC: 0x{:x}. BGEU: x{:d}(0x{:x}) > x{:d}(0x{:x}) -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - - regs->setPC(new_pc); - } else { - logger->debug("{} ns. PC: 0x{:x}. BGEU: x{:d}(0x{:x}) > x{:d}(0x{:x}) -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), regs->getPC() + 4); - regs->incPC(); - } - - return true; - } - - bool BASE_ISA::Exec_LB() const { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - std::int8_t data; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - mem_addr = imm + regs->getValue(rs1); - data = static_cast(mem_intf->readDataMem(mem_addr, 1)); - perf->dataMemoryRead(); - regs->setValue(rd, data); - - logger->debug("{} ns. PC: 0x{:x}. LB: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, mem_addr, rd); - - return true; - } - - bool BASE_ISA::Exec_LH() const { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - int16_t data; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - mem_addr = imm + regs->getValue(rs1); - data = static_cast(mem_intf->readDataMem(mem_addr, 2)); - perf->dataMemoryRead(); - regs->setValue(rd, data); - - logger->debug("{} ns. PC: 0x{:x}. LH: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, mem_addr, rd); - - return true; - } - - bool BASE_ISA::Exec_LW() const { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - std::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); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); - - logger->debug("{} ns. PC: 0x{:x}. LW: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, mem_addr, rd); - - return true; - } - - bool BASE_ISA::Exec_LBU() const { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - std::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); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); - - logger->debug("{} ns. PC: 0x{:x}. LBU: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, mem_addr, rd); - - return true; - } - - bool BASE_ISA::Exec_LHU() const { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - 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); - perf->dataMemoryRead(); - - regs->setValue(rd, data); - - logger->debug("{} ns. PC: 0x{:x}. LHU: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, mem_addr, rd); - - return true; - } - - bool BASE_ISA::Exec_SB() const { - std::uint32_t mem_addr; - int rs1, rs2; - std::int32_t imm; - std::uint32_t data; - - rs1 = get_rs1(); - rs2 = get_rs2(); - imm = get_imm_S(); - - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 1); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. SB: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs2, rs1, imm, mem_addr); - - return true; - } - - bool BASE_ISA::Exec_SH() const { - std::uint32_t mem_addr; - int rs1, rs2; - std::int32_t imm; - std::uint32_t data; - - rs1 = get_rs1(); - rs2 = get_rs2(); - imm = get_imm_S(); - - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 2); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. SH: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs2, rs1, imm, mem_addr); - - return true; - } - - bool BASE_ISA::Exec_SW() const { - std::uint32_t mem_addr; - int rs1, rs2; - std::int32_t imm; - std::uint32_t data; - - rs1 = get_rs1(); - rs2 = get_rs2(); - imm = get_imm_S(); - - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. SW: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs2, rs1, imm, mem_addr); - - return true; - } - - bool BASE_ISA::Exec_ADDI() const { - int rd, rs1; - std::int32_t imm; - std::int32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - calc = static_cast(regs->getValue(rs1)) + imm; - regs->setValue(rd, calc); - - logger->debug("{} ns. PC: 0x{:x}. ADDI: x{:d} + x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_SLTI() const { - int rd, rs1; - std::int32_t imm; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - if (static_cast(regs->getValue(rs1)) < imm) { - regs->setValue(rd, 1); - - logger->debug("{} ns. PC: 0x{:x}. SLTI: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, rd); - } else { - regs->setValue(rd, 0); - logger->debug("{} ns. PC: 0x{:x}. SLTI: x{:d} < x{:d} => 0 -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, rd); - } - - return true; - } - - bool BASE_ISA::Exec_SLTIU() const { - int rd, rs1; - std::int32_t imm; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - if (static_cast(regs->getValue(rs1)) < static_cast(imm)) { - regs->setValue(rd, 1); - logger->debug("{} ns. PC: 0x{:x}. SLTIU: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, rd); - } else { - regs->setValue(rd, 0); - logger->debug("{} ns. PC: 0x{:x}. SLTIU: x{:d} < x{:d} => 0 -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, rd); - } - - return true; - } - - bool BASE_ISA::Exec_XORI() const { - int rd, rs1; - std::int32_t imm; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - calc = regs->getValue(rs1) ^ imm; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. XORI: x{:d} XOR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, rd); - - return true; - } - - bool BASE_ISA::Exec_ORI() const { - int rd, rs1; - std::int32_t imm; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - calc = regs->getValue(rs1) | imm; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. ORI: x{:d} OR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, rd); - - return true; - } - - bool BASE_ISA::Exec_ANDI() const { - int rd, rs1; - std::uint32_t imm; - std::uint32_t calc; - std::uint32_t aux; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - aux = regs->getValue(rs1); - calc = aux & imm; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. ANDI: x{:d}(0x{:x}) AND 0x{:x} -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, aux, imm, rd); - - return true; - } - - bool BASE_ISA::Exec_SLLI() { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_shamt(); - - if (rs2 >= 0x20) { - std::cout << "ILEGAL INSTRUCTION, shamt[5] != 0" << "\n"; - RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr); - - return false; - } - - shift = rs2 & 0x1F; - - calc = static_cast(regs->getValue(rs1)) << shift; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. SLLI: x{:d} << {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_SRLI() const { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - shift = rs2 & 0x1F; - - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. SRLI: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_SRAI() const { - int rd, rs1, rs2; - std::uint32_t shift; - std::int32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - shift = rs2 & 0x1F; - - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, calc); - - logger->debug("{} ns. PC: 0x{:x}. SRAI: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_ADD() const { - int rd, rs1, rs2; - std::uint32_t calc; - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - calc = regs->getValue(rs1) + regs->getValue(rs2); - - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. ADD: x{:d} + x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_SUB() const { - int rd, rs1, rs2; - std::uint32_t calc; - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - calc = regs->getValue(rs1) - regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. SUB: x{:d} - x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_SLL() const { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - shift = regs->getValue(rs2) & 0x1F; - - calc = static_cast(regs->getValue(rs1)) << shift; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. SLL: x{:d} << x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_SLT() const { - int rd, rs1, rs2; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (regs->getValue(rs1) < regs->getValue(rs2)) { - regs->setValue(rd, 1); - logger->debug("{} ns. PC: 0x{:x}. SLT: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd); - } else { - regs->setValue(rd, 0); - logger->debug("{} ns. PC: 0x{:x}. SLT: x{:d} < x{:d} => 0 -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd); - } - - return true; - } - - bool BASE_ISA::Exec_SLTU() const { - int rd, rs1, rs2; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (static_cast(regs->getValue(rs1)) < static_cast(regs->getValue(rs2))) { - regs->setValue(rd, 1); - logger->debug("{} ns. PC: 0x{:x}. SLTU: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd); - } else { - regs->setValue(rd, 0); - logger->debug("{} ns. PC: 0x{:x}. SLTU: x{:d} < x{:d} => 0 -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd); - } - - return true; - } - - bool BASE_ISA::Exec_XOR() const { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - calc = regs->getValue(rs1) ^ regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. XOR: x{:d} XOR x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_SRL() const { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - shift = regs->getValue(rs2) & 0x1F; - - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. SRL: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_SRA() const { - int rd, rs1, rs2; - std::uint32_t shift; - std::int32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - shift = regs->getValue(rs2) & 0x1F; - - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, calc); - - logger->debug("{} ns. PC: 0x{:x}. SRA: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_OR() const { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - calc = regs->getValue(rs1) | regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. OR: x{:d} OR x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_AND() const { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - calc = regs->getValue(rs1) & regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. AND: x{:d} AND x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_FENCE() const { - logger->debug("{} ns. PC: 0x{:x}. FENCE"); - - return true; - } - - bool BASE_ISA::Exec_ECALL() { - - logger->debug("{} ns. PC: 0x{:x}. ECALL"); - - std::cout << std::endl << "ECALL Instruction called, stopping simulation" - << std::endl; - regs->dump(); - std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; - perf->dump(); - -#if 0 - std::uint32_t gp_value = regs->getValue(Registers::gp); - if (gp_value == 1) { - std::cout << "GP value is 1, test result is OK" << "\n"; - } else { - std::cout << "GP value is " << gp_value << "\n"; - } - - sc_core::sc_stop(); -#else - RaiseException(11, m_instr); -#endif - return true; - } - - bool BASE_ISA::Exec_EBREAK() { - - logger->debug("{} ns. PC: 0x{:x}. EBREAK"); - std::cout << std::endl << "EBRAK Instruction called, dumping information" - << std::endl; - regs->dump(); - std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; - perf->dump(); - - RaiseException(11, m_instr); - - return false; - } - - bool BASE_ISA::Exec_CSRRW() const { - int rd, rs1; - int csr; - std::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, static_cast(aux)); - } - - aux = regs->getValue(rs1); - regs->setCSR(csr, aux); - - logger->debug("{} ns. PC: 0x{:x}. CSRRW: CSR #{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - csr, rd, aux); - - return true; - } - - bool BASE_ISA::Exec_CSRRS() const { - int rd, rs1; - int csr; - std::uint32_t bitmask, aux, aux2; - - rd = get_rd(); - rs1 = get_rs1(); - csr = get_csr(); - - if (rd == 0) { - logger->debug("{} ns. PC: 0x{:x}. CSRRS with rd1 == 0, doing nothing."); - return false; - } - - /* These operations must be atomical */ - aux = regs->getCSR(csr); - bitmask = regs->getValue(rs1); - - regs->setValue(rd, static_cast(aux)); - - aux2 = aux | bitmask; - regs->setCSR(csr, aux2); - - logger->debug("{} ns. PC: 0x{:x}. CSRRS: CSR #{:d}(0x{:x}) -> x{:d}(0x{:x}) & CSR #{:d} <- 0x{:x}", - sc_core::sc_time_stamp().value(), regs->getPC(), - csr, aux, rd, rs1, csr, aux2); - - return true; - } - - bool BASE_ISA::Exec_CSRRC() const { - int rd, rs1; - int csr; - std::uint32_t bitmask, aux, aux2; - - rd = get_rd(); - rs1 = get_rs1(); - csr = get_csr(); - - if (rd == 0) { - logger->debug("{} ns. PC: 0x{:x}. CSRRC with rd1 == 0, doing nothing."); - return true; - } - - /* These operations must be atomical */ - aux = regs->getCSR(csr); - bitmask = regs->getValue(rs1); - - regs->setValue(rd, static_cast(aux)); - - aux2 = aux & ~bitmask; - regs->setCSR(csr, aux2); - - logger->debug("{} ns. PC: 0x{:x}. CSRRC: CSR #{:d}(0x{:x}) -> x{:d}(0x{:x}) & CSR #{:d} <- 0x{:x}", - sc_core::sc_time_stamp().value(), regs->getPC(), - csr, aux, rd, rs1, csr, aux2); - - return true; - } - - bool BASE_ISA::Exec_CSRRWI() const { - int rd, rs1; - int csr; - std::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, static_cast(aux)); - } - aux = rs1; - regs->setCSR(csr, aux); - - logger->debug("{} ns. PC: 0x{:x}. CSRRWI: CSR #{:d} -> x{:d}. x{:d} -> CSR #{:d}", - sc_core::sc_time_stamp().value(), regs->getPC(), - csr, rd, rs1, csr); - - return true; - } - - bool BASE_ISA::Exec_CSRRSI() const { - int rd, rs1; - int csr; - std::uint32_t bitmask, aux; - - rd = get_rd(); - rs1 = get_rs1(); - csr = get_csr(); - - if (rs1 == 0) { - return true; - } - - /* These operations must be atomical */ - aux = regs->getCSR(csr); - regs->setValue(rd, static_cast(aux)); - - bitmask = rs1; - aux = aux | bitmask; - regs->setCSR(csr, aux); - - logger->debug("{} ns. PC: 0x{:x}. CSRRSI: CSR #{:d} -> x{:d}. x{:d} & CSR #{:d}(0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - csr, rd, rs1, csr, aux); - - return true; - } - - bool BASE_ISA::Exec_CSRRCI() const { - int rd, rs1; - int csr; - std::uint32_t bitmask, aux; - - rd = get_rd(); - rs1 = get_rs1(); - csr = get_csr(); - - if (rs1 == 0) { - return true; - } - - /* These operations must be atomical */ - aux = regs->getCSR(csr); - regs->setValue(rd, static_cast(aux)); - - bitmask = rs1; - aux = aux & ~bitmask; - regs->setCSR(csr, aux); - - logger->debug("{} ns. PC: 0x{:x}. CSRRCI: CSR #{:d} -> x{:d}. x{:d} & CSR #{:d}(0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - csr, rd, rs1, csr, aux); - - return true; - } - -/*********************** Privileged Instructions ******************************/ - - bool BASE_ISA::Exec_MRET() const { - std::uint32_t new_pc = 0; - - new_pc = regs->getCSR(CSR_MEPC); - regs->setPC(new_pc); - - logger->debug("{} ns. PC: 0x{:x}. MRET: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), new_pc); - - // update mstatus - std::uint32_t csr_temp; - csr_temp = regs->getCSR(CSR_MSTATUS); - if (csr_temp & MSTATUS_MPIE) { - csr_temp |= MSTATUS_MIE; - } - csr_temp |= MSTATUS_MPIE; - regs->setCSR(CSR_MSTATUS, csr_temp); - - return true; - } - - bool BASE_ISA::Exec_SRET() const { - std::uint32_t new_pc = 0; - - new_pc = regs->getCSR(CSR_SEPC); - regs->setPC(new_pc); - - logger->debug("{} ns. PC: 0x{:x}. SRET: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC()); - return true; - } - - bool BASE_ISA::Exec_WFI() const { - logger->debug("{} ns. PC: 0x{:x}. WFI"); - return true; - } - - bool BASE_ISA::Exec_SFENCE() const { - logger->debug("{} ns. PC: 0x{:x}. SFENCE"); - return true; - } - - bool BASE_ISA::process_instruction(Instruction &inst, bool *breakpoint) { - bool PC_not_affected = true; - - *breakpoint = false; - setInstr(inst.getInstr()); - - switch (decode()) { - case OP_LUI: - Exec_LUI(); - break; - case OP_AUIPC: - Exec_AUIPC(); - break; - case OP_JAL: - Exec_JAL(); - PC_not_affected = false; - break; - case OP_JALR: - Exec_JALR(); - PC_not_affected = false; - break; - case OP_BEQ: - Exec_BEQ(); - PC_not_affected = false; - break; - case OP_BNE: - Exec_BNE(); - PC_not_affected = false; - break; - case OP_BLT: - Exec_BLT(); - PC_not_affected = false; - break; - case OP_BGE: - Exec_BGE(); - PC_not_affected = false; - break; - case OP_BLTU: - Exec_BLTU(); - PC_not_affected = false; - break; - case OP_BGEU: - Exec_BGEU(); - PC_not_affected = false; - break; - case OP_LB: - Exec_LB(); - break; - case OP_LH: - Exec_LH(); - break; - case OP_LW: - Exec_LW(); - break; - case OP_LBU: - Exec_LBU(); - break; - case OP_LHU: - Exec_LHU(); - break; - case OP_SB: - Exec_SB(); - break; - case OP_SH: - Exec_SH(); - break; - case OP_SW: - Exec_SW(); - break; - case OP_ADDI: - Exec_ADDI(); - break; - case OP_SLTI: - Exec_SLTI(); - break; - case OP_SLTIU: - Exec_SLTIU(); - break; - case OP_XORI: - Exec_XORI(); - break; - case OP_ORI: - Exec_ORI(); - break; - case OP_ANDI: - Exec_ANDI(); - break; - case OP_SLLI: - PC_not_affected = Exec_SLLI(); - break; - case OP_SRLI: - Exec_SRLI(); - break; - case OP_SRAI: - Exec_SRAI(); - break; - case OP_ADD: - Exec_ADD(); - break; - case OP_SUB: - Exec_SUB(); - break; - case OP_SLL: - Exec_SLL(); - break; - case OP_SLT: - Exec_SLT(); - break; - case OP_SLTU: - Exec_SLTU(); - break; - case OP_XOR: - Exec_XOR(); - break; - case OP_SRL: - Exec_SRL(); - break; - case OP_SRA: - Exec_SRA(); - break; - case OP_OR: - Exec_OR(); - break; - case OP_AND: - Exec_AND(); - break; - case OP_FENCE: - Exec_FENCE(); - break; - case OP_ECALL: - Exec_ECALL(); - *breakpoint = true; - std::cout << "ECALL" << std::endl; - break; - case OP_EBREAK: - PC_not_affected = Exec_EBREAK(); -// *breakpoint = true; - break; - case OP_CSRRW: - Exec_CSRRW(); - break; - case OP_CSRRS: - Exec_CSRRS(); - break; - case OP_CSRRC: - Exec_CSRRC(); - break; - case OP_CSRRWI: - Exec_CSRRWI(); - break; - case OP_CSRRSI: - Exec_CSRRSI(); - break; - case OP_CSRRCI: - Exec_CSRRCI(); - break; - case OP_MRET: - Exec_MRET(); - PC_not_affected = false; - break; - case OP_SRET: - Exec_SRET(); - PC_not_affected = false; - break; - case OP_WFI: - Exec_WFI(); - break; - case OP_SFENCE: - Exec_SFENCE(); - break; - [[unlikely]] default: - std::cout << "Wrong instruction" << "\n"; - inst.dump(); - NOP(); - //sc_stop(); - break; - } - - return PC_not_affected; - } - - opCodes BASE_ISA::decode() { - switch (opcode()) { - case LUI: - return OP_LUI; - case AUIPC: - return OP_AUIPC; - case JAL: - return OP_JAL; - case JALR: - return OP_JALR; - case BEQ: - switch (get_funct3()) { - case BEQ_F: - return OP_BEQ; - case BNE_F: - return OP_BNE; - case BLT_F: - return OP_BLT; - case BGE_F: - return OP_BGE; - case BLTU_F: - return OP_BLTU; - case BGEU_F: - return OP_BGEU; - } - return OP_ERROR; - case LB: - switch (get_funct3()) { - case LB_F: - return OP_LB; - case LH_F: - return OP_LH; - case LW_F: - return OP_LW; - case LBU_F: - return OP_LBU; - case LHU_F: - return OP_LHU; - } - return OP_ERROR; - case SB: - switch (get_funct3()) { - case SB_F: - return OP_SB; - case SH_F: - return OP_SH; - case SW_F: - return OP_SW; - } - return OP_ERROR; - case ADDI: - switch (get_funct3()) { - case ADDI_F: - return OP_ADDI; - case SLTI_F: - return OP_SLTI; - case SLTIU_F: - return OP_SLTIU; - case XORI_F: - return OP_XORI; - case ORI_F: - return OP_ORI; - case ANDI_F: - return OP_ANDI; - case SLLI_F: - return OP_SLLI; - case SRLI_F: - switch (get_funct7()) { - case SRLI_F7: - return OP_SRLI; - case SRAI_F7: - return OP_SRAI; - } - return OP_ERROR; - } - return OP_ERROR; - case ADD: { - switch (get_funct3()) { - case ADD_F: - switch (get_funct7()) { - case ADD_F7: - return OP_ADD; - case SUB_F7: - return OP_SUB; - default: - return OP_ADD; - } - break; - case SLL_F: - return OP_SLL; - case SLT_F: - return OP_SLT; - case SLTU_F: - return OP_SLTU; - case XOR_F: - return OP_XOR; - case SRL_F: - switch (get_funct7()) { - case SRL_F7: - return OP_SRL; - case SRA_F7: - return OP_SRA; - default: - return OP_ERROR; - } - case OR_F: - return OP_OR; - case AND_F: - return OP_AND; - default: - return OP_ERROR; - } - } /* ADD */ - case FENCE: - return OP_FENCE; - case ECALL: { - switch (get_funct3()) { - case ECALL_F3: - switch (get_csr()) { - case ECALL_F: - return OP_ECALL; - case EBREAK_F: - return OP_EBREAK; - case URET_F: - return OP_URET; - case SRET_F: - return OP_SRET; - case MRET_F: - return OP_MRET; - case WFI_F: - return OP_WFI; - case SFENCE_F: - return OP_SFENCE; - } - if (m_instr.range(31, 25) == 0b0001001) { - return OP_SFENCE; - } - break; - case CSRRW: - return OP_CSRRW; - break; - case CSRRS: - return OP_CSRRS; - break; - case CSRRC: - return OP_CSRRC; - break; - case CSRRWI: - return OP_CSRRWI; - break; - case CSRRSI: - return OP_CSRRSI; - break; - case CSRRCI: - return OP_CSRRCI; - break; - } - } - break; - default: - return OP_ERROR; - } - - return OP_ERROR; - } -} \ No newline at end of file diff --git a/src/CPU.cpp b/src/CPU.cpp index 31a1e4b..6289e49 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -12,8 +12,8 @@ namespace riscv_tlm { SC_HAS_PROCESS(CPU); CPU::CPU(sc_core::sc_module_name const &name, std::uint32_t PC, bool debug) : - sc_module(name), instr_bus("instr_bus"), inst(0), default_time(10, - sc_core::SC_NS), INSTR(0) { + sc_module(name), instr_bus("instr_bus"), inst(0), + default_time(10, sc_core::SC_NS), INSTR(0) { register_bank = new Registers(); mem_intf = new MemoryInterface(); @@ -32,10 +32,10 @@ namespace riscv_tlm { instr_bus.register_invalidate_direct_mem_ptr(this, &CPU::invalidate_direct_mem_ptr); - 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); + 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(); m_qk->reset(); diff --git a/src/C_extension.cpp b/src/C_extension.cpp index e70f446..1c34c72 100644 --- a/src/C_extension.cpp +++ b/src/C_extension.cpp @@ -5,749 +5,3 @@ \date August 2018 */ #include "C_extension.h" - -namespace riscv_tlm { - - op_C_Codes C_extension::decode() const { - - switch (opcode()) { - - case 0b00: - switch (get_funct3()) { - case C_ADDI4SPN: - return OP_C_ADDI4SPN; - break; - case C_FLD: - return OP_C_FLD; - break; - case C_LW: - return OP_C_LW; - break; - case C_FLW: - return OP_C_FLW; - break; - case C_FSD: - return OP_C_FSD; - break; - case C_SW: - return OP_C_SW; - break; - case C_FSW: - return OP_C_FSW; - break; - [[unlikely]] default: - return OP_C_ERROR; - break; - } - break; - - case 0b01: - switch (get_funct3()) { - case C_ADDI: - return OP_C_ADDI; - break; - case C_JAL: - return OP_C_JAL; - break; - case C_LI: - return OP_C_LI; - break; - case C_ADDI16SP: - return OP_C_ADDI16SP; - break; - case C_SRLI: - switch (m_instr.range(11, 10)) { - case C_2_SRLI: - return OP_C_SRLI; - break; - case C_2_SRAI: - return OP_C_SRAI; - break; - case C_2_ANDI: - return OP_C_ANDI; - break; - case C_2_SUB: - switch (m_instr.range(6, 5)) { - case C_3_SUB: - return OP_C_SUB; - break; - case C_3_XOR: - return OP_C_XOR; - break; - case C_3_OR: - return OP_C_OR; - break; - case C_3_AND: - return OP_C_AND; - break; - } - } - break; - case C_J: - return OP_C_J; - break; - case C_BEQZ: - return OP_C_BEQZ; - break; - case C_BNEZ: - return OP_C_BNEZ; - break; - [[unlikely]] default: - return OP_C_ERROR; - break; - } - break; - - case 0b10: - switch (get_funct3()) { - case C_SLLI: - return OP_C_SLLI; - break; - case C_FLDSP: - case C_LWSP: - return OP_C_LWSP; - break; - case C_FLWSP: - return OP_C_FLWSP; - break; - case C_JR: - if (m_instr[12] == 0) { - if (m_instr.range(6, 2) == 0) { - return OP_C_JR; - } else { - return OP_C_MV; - } - } else { - if (m_instr.range(11, 2) == 0) { - return OP_C_EBREAK; - } else if (m_instr.range(6, 2) == 0) { - return OP_C_JALR; - } else { - return OP_C_ADD; - } - } - break; - case C_FDSP: - break; - case C_SWSP: - return OP_C_SWSP; - break; - case C_FWWSP: - [[unlikely]] - default: - return OP_C_ERROR; - break; - } - break; - - [[unlikely]] default: - - return OP_C_ERROR; - break; - } - return OP_C_ERROR; - } - - bool C_extension::Exec_C_JR() { - std::uint32_t mem_addr; - int rs1; - int new_pc; - - rs1 = get_rs1(); - mem_addr = 0; - - new_pc = static_cast( - static_cast((regs->getValue(rs1)) + static_cast(mem_addr)) & 0xFFFFFFFE); - - logger->debug("{} ns. PC: 0x{:x}. C.JR: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), new_pc); - - regs->setPC(new_pc); - - return true; - } - - bool C_extension::Exec_C_MV() { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rd(); - rs1 = 0; - rs2 = get_rs2(); - - calc = regs->getValue(rs1) + regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.MV: x{:d}(0x{:x}) + x{:d}(0x{:x}) -> x{:d}(0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), rd, calc); - - return true; - } - - bool C_extension::Exec_C_ADD() { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rs1(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - calc = regs->getValue(rs1) + regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.ADD: x{:d} + x{} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, calc); - - return true; - } - - bool C_extension::Exec_C_LWSP() { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - std::uint32_t data; - - // lw rd, offset[7:2](x2) - - rd = get_rd(); - rs1 = 2; - imm = get_imm_LWSP(); - - mem_addr = imm + regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); - - regs->setValue(rd, data); - - logger->debug("{} ns. PC: 0x{:x}. C.LWSP: x{:d} + {:d}(@0x{:x}) -> x{:d}({:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, imm, mem_addr, rd, data); - - return true; - } - - bool C_extension::Exec_C_ADDI4SPN() { - int rd, rs1; - std::int32_t imm; - std::int32_t calc; - - rd = get_rdp(); - rs1 = 2; - imm = get_imm_ADDI4SPN(); - - if (imm == 0) { - RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr); - return false; - } - - calc = static_cast(regs->getValue(rs1)) + imm; - regs->setValue(rd, calc); - - logger->debug("{} ns. PC: 0x{:x}. C.ADDI4SN: x{:d} + (0x{:x}) + {:d} -> x{:d}(0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), imm, rd, calc); - - return true; - } - - bool C_extension::Exec_C_ADDI16SP() { - // addi x2, x2, nzimm[9:4] - int rd; - std::int32_t imm; - - if (get_rd() == 2) { - int rs1; - std::int32_t calc; - - rd = 2; - rs1 = 2; - imm = get_imm_ADDI16SP(); - - calc = static_cast(regs->getValue(rs1)) + imm; - regs->setValue(rd, calc); - - logger->debug("{} ns. PC: 0x{:x}. C.ADDI16SP: x{:d} + {:d} -> x{:d} (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, imm, rd, calc); - } else { - /* C.LUI OPCODE */ - rd = get_rd(); - imm = get_imm_LUI(); - regs->setValue(rd, imm); - - logger->debug("{} ns. PC: 0x{:x}. C.LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), - rd, imm); - } - - return true; - } - - bool C_extension::Exec_C_SWSP() { - // sw rs2, offset(x2) - std::uint32_t mem_addr; - int rs1, rs2; - std::int32_t imm; - std::uint32_t data; - - rs1 = 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); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. C.SWSP: x{:d}(0x{:x}) -> x{:d} + {} (@0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs2, data, rs1, imm, mem_addr); - - return true; - } - - bool C_extension::Exec_C_BEQZ() { - int rs1; - int new_pc; - std::uint32_t val1; - - rs1 = get_rs1p(); - val1 = regs->getValue(rs1); - - if (val1 == 0) { - new_pc = static_cast(regs->getPC()) + get_imm_CB(); - regs->setPC(new_pc); - } else { - regs->incPCby2(); - new_pc = static_cast(regs->getPC()); - } - - logger->debug("{} ns. PC: 0x{:x}. C.BEQZ: x{:d}(0x{:x}) == 0? -> PC (0xx{:d})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, val1, new_pc); - - return true; - } - - bool C_extension::Exec_C_BNEZ() { - int rs1; - int new_pc; - std::uint32_t val1; - - rs1 = get_rs1p(); - val1 = regs->getValue(rs1); - - if (val1 != 0) { - new_pc = static_cast(regs->getPC()) + get_imm_CB(); - regs->setPC(new_pc); - } else { - regs->incPCby2(); //PC <- PC +2 - new_pc = static_cast(regs->getPC()); - } - - logger->debug("{} ns. PC: 0x{:x}. C.BNEZ: x{:d}(0x{:x}) != 0? -> PC (0xx{:d})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, val1, new_pc); - - return true; - } - - bool C_extension::Exec_C_LI() { - int rd, rs1; - std::int32_t imm; - std::int32_t calc; - - rd = get_rd(); - rs1 = 0; - imm = get_imm_ADDI(); - - calc = static_cast(regs->getValue(rs1)) + imm; - regs->setValue(rd, calc); - - logger->debug("{} ns. PC: 0x{:x}. C.LI: x{:d} ({:d}) + {:d} -> x{:d}(0x{:x}) ", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), imm, rd, calc); - - return true; - } - - bool C_extension::Exec_C_SRLI() { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; - - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2(); - - shift = rs2 & 0x1F; - - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.SRLI: x{:d} >> {} -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd); - - return true; - } - - bool C_extension::Exec_C_SRAI() { - int rd, rs1, rs2; - std::uint32_t shift; - std::int32_t calc; - - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2(); - - shift = rs2 & 0x1F; - - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, calc); - - logger->debug("{} ns. PC: 0x{:x}. C.SRAI: x{:d} >> {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd, calc); - - return true; - } - - bool C_extension::Exec_C_SLLI() { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; - - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_imm_ADDI(); - - shift = rs2 & 0x1F; - - calc = static_cast(regs->getValue(rs1)) << shift; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.SLLI: x{:d} << {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd, calc); - - return true; - } - - bool C_extension::Exec_C_ANDI() { - int rd, rs1; - std::uint32_t imm; - std::uint32_t aux; - std::uint32_t calc; - - rd = get_rs1p(); - rs1 = get_rs1p(); - imm = get_imm_ADDI(); - - aux = regs->getValue(rs1); - calc = aux & imm; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.ANDI: x{:d}(0x{:x}) AND 0x{:x} -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, aux, imm, rd); - - return true; - } - - bool C_extension::Exec_C_SUB() { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2p(); - - calc = regs->getValue(rs1) - regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.SUB: x{:d} - x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, calc); - - return true; - } - - bool C_extension::Exec_C_XOR() { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2p(); - - calc = regs->getValue(rs1) ^ regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.XOR: x{:d} XOR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd); - - return true; - } - - bool C_extension::Exec_C_OR() { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2p(); - - calc = regs->getValue(rs1) | regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.OR: x{:d} OR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd); - - return true; - } - - bool C_extension::Exec_C_AND() { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2p(); - - calc = regs->getValue(rs1) & regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.AND: x{:d} AND x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd); - - return true; - } - - bool C_extension::Exec_C_ADDI() const { - int rd, rs1; - std::int32_t imm; - std::int32_t calc; - - rd = get_rd(); - rs1 = rd; - imm = get_imm_ADDI(); - - calc = static_cast(regs->getValue(rs1)) + imm; - regs->setValue(rd, calc); - - logger->debug("{} ns. PC: 0x{:x}. C.ADDI: x{:d} + {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), rs1, imm, rd, calc); - - return true; - } - - bool C_extension::Exec_C_JALR() { - std::uint32_t mem_addr = 0; - int rd, rs1; - int new_pc, old_pc; - - rd = 1; - rs1 = get_rs1(); - - old_pc = static_cast(regs->getPC()); - regs->setValue(rd, old_pc + 2); - - new_pc = static_cast((regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); - regs->setPC(new_pc); - - logger->debug("{} ns. PC: 0x{:x}. C.JALR: x{:d} <- 0x{:x} PC <- 0xx{:x}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rd, old_pc + 4, new_pc); - - return true; - } - - bool C_extension::Exec_C_LW() { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - std::uint32_t data; - - rd = get_rdp(); - rs1 = get_rs1p(); - imm = get_imm_L(); - - mem_addr = imm + regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); - - logger->debug("{} ns. PC: 0x{:x}. C.LW: x{:d}(0x{:x}) + {:d} (@0x{:x}) -> {:d} (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), imm, mem_addr, rd, data); - - return true; - } - - bool C_extension::Exec_C_SW() { - std::uint32_t mem_addr; - int rs1, rs2; - std::int32_t imm; - std::uint32_t data; - - rs1 = get_rs1p(); - rs2 = get_rs2p(); - imm = get_imm_L(); - - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. C.SW: x{:d}(0x{:x}) -> x{:d} + 0x{:x}(@0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs2, data, rs1, imm, mem_addr); - - return true; - } - - bool C_extension::Exec_C_JAL(int m_rd) { - std::int32_t mem_addr; - int rd; - int new_pc, old_pc; - - rd = m_rd; - mem_addr = get_imm_J(); - old_pc = static_cast(regs->getPC()); - - new_pc = old_pc + mem_addr; - regs->setPC(new_pc); - - old_pc = old_pc + 2; - regs->setValue(rd, old_pc); - - logger->debug("{} ns. PC: 0x{:x}. C.JAL: x{:d} <- 0x{:x}. PC + 0x{:x} -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rd, old_pc, mem_addr, new_pc); - - return true; - } - - bool C_extension::Exec_C_EBREAK() { - - logger->debug("C.EBREAK"); - std::cout << "\n" << "C.EBRAK Instruction called, dumping information" - << "\n"; - regs->dump(); - std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; - perf->dump(); - - sc_core::sc_stop(); - - return true; - } - - bool C_extension::process_instruction(Instruction &inst, bool *breakpoint) { - bool PC_not_affected = true; - - *breakpoint = false; - - setInstr(inst.getInstr()); - - switch (decode()) { - case OP_C_ADDI4SPN: - PC_not_affected = Exec_C_ADDI4SPN(); - break; - case OP_C_LW: - Exec_C_LW(); - break; - case OP_C_SW: - Exec_C_SW(); - break; - case OP_C_ADDI: - Exec_C_ADDI(); - break; - case OP_C_JAL: - Exec_C_JAL(1); - PC_not_affected = false; - break; - case OP_C_J: - Exec_C_JAL(0); - PC_not_affected = false; - break; - case OP_C_LI: - Exec_C_LI(); - break; - case OP_C_SLLI: - Exec_C_SLLI(); - break; - case OP_C_LWSP: - Exec_C_LWSP(); - break; - case OP_C_JR: - Exec_C_JR(); - PC_not_affected = false; - break; - case OP_C_MV: - Exec_C_MV(); - break; - case OP_C_JALR: - Exec_C_JALR(); - PC_not_affected = false; - break; - case OP_C_ADD: - Exec_C_ADD(); - break; - case OP_C_SWSP: - Exec_C_SWSP(); - break; - case OP_C_ADDI16SP: - Exec_C_ADDI16SP(); - break; - case OP_C_BEQZ: - Exec_C_BEQZ(); - PC_not_affected = false; - break; - case OP_C_BNEZ: - Exec_C_BNEZ(); - PC_not_affected = false; - break; - case OP_C_SRLI: - Exec_C_SRLI(); - break; - case OP_C_SRAI: - Exec_C_SRAI(); - break; - case OP_C_ANDI: - Exec_C_ANDI(); - break; - case OP_C_SUB: - Exec_C_SUB(); - break; - case OP_C_XOR: - Exec_C_XOR(); - break; - case OP_C_OR: - Exec_C_OR(); - break; - case OP_C_AND: - Exec_C_AND(); - break; - case OP_C_EBREAK: - Exec_C_EBREAK(); - std::cout << "C_EBREAK" << std::endl; - *breakpoint = true; - break; - [[unlikely]] default: - std::cout << "C instruction not implemented yet" << "\n"; - inst.dump(); - NOP(); - break; - } - - return PC_not_affected; - } - -} \ No newline at end of file diff --git a/src/M_extension.cpp b/src/M_extension.cpp index a29d544..4e8fee2 100644 --- a/src/M_extension.cpp +++ b/src/M_extension.cpp @@ -8,292 +8,3 @@ #include "M_extension.h" -namespace riscv_tlm { - - op_M_Codes M_extension::decode() const { - - switch (opcode()) { - case M_MUL: - return OP_M_MUL; - break; - case M_MULH: - return OP_M_MULH; - break; - case M_MULHSU: - return OP_M_MULHSU; - break; - case M_MULHU: - return OP_M_MULHU; - break; - case M_DIV: - return OP_M_DIV; - break; - case M_DIVU: - return OP_M_DIVU; - break; - case M_REM: - return OP_M_REM; - break; - case M_REMU: - return OP_M_REMU; - break; - [[unlikely]] default: - return OP_M_ERROR; - break; - } - - return OP_M_ERROR; - } - - bool M_extension::Exec_M_MUL() const { - int rd, rs1, rs2; - std::int32_t multiplier, multiplicand; - std::int64_t result; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - multiplier = static_cast(regs->getValue(rs1)); - multiplicand = static_cast(regs->getValue(rs2)); - - result = static_cast(multiplier * multiplicand); - result = result & 0x00000000FFFFFFFF; - regs->setValue(rd, static_cast(result)); - - logger->debug("{} ns. PC: 0x{:x}. M.MUL: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, result); - - return true; - } - - bool M_extension::Exec_M_MULH() const { - int rd, rs1, rs2; - std::int32_t multiplier, multiplicand; - std::int64_t result; - std::int32_t ret_value; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - multiplier = static_cast(regs->getValue(rs1)); - multiplicand = static_cast(regs->getValue(rs2)); - - result = static_cast(multiplier) * static_cast(multiplicand); - - ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); - regs->setValue(rd, ret_value); - - logger->debug("{} ns. PC: 0x{:x}. M.MULH: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, result); - - return true; - } - - bool M_extension::Exec_M_MULHSU() const { - int rd, rs1, rs2; - std::int32_t multiplier; - std::uint32_t multiplicand; - std::int64_t result; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - multiplier = static_cast(regs->getValue(rs1)); - multiplicand = regs->getValue(rs2); - - result = static_cast(multiplier * static_cast(multiplicand)); - result = (result >> 32) & 0x00000000FFFFFFFF; - regs->setValue(rd, static_cast(result)); - - logger->debug("{} ns. PC: 0x{:x}. M.MULHSU: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, result); - - return true; - } - - bool M_extension::Exec_M_MULHU() const { - int rd, rs1, rs2; - std::uint32_t multiplier, multiplicand; - std::uint64_t result; - std::int32_t ret_value; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - multiplier = static_cast(regs->getValue(rs1)); - multiplicand = static_cast(regs->getValue(rs2)); - - result = static_cast(multiplier) * static_cast(multiplicand); - ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); - regs->setValue(rd, ret_value); - - logger->debug("{} ns. PC: 0x{:x}. M.MULHU: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, result); - - return true; - } - - bool M_extension::Exec_M_DIV() const { - int rd, rs1, rs2; - std::int32_t divisor, dividend; - std::int64_t result; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - dividend = static_cast(regs->getValue(rs1)); - divisor = static_cast(regs->getValue(rs2)); - - if (divisor == 0) { - result = -1; - } else if ((divisor == -1) && (dividend == static_cast(0x80000000))) { - result = 0x0000000080000000; - } else { - result = dividend / divisor; - result = result & 0x00000000FFFFFFFF; - } - - regs->setValue(rd, static_cast(result)); - - logger->debug("{} ns. PC: 0x{:x}. M.DIV: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, result); - - return true; - } - - bool M_extension::Exec_M_DIVU() const { - int rd, rs1, rs2; - std::uint32_t divisor, dividend; - std::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, static_cast(result)); - - logger->debug("{} ns. PC: 0x{:x}. M.DIVU: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, result); - - return true; - } - - bool M_extension::Exec_M_REM() const { - int rd, rs1, rs2; - std::int32_t divisor, dividend; - std::int32_t result; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - dividend = static_cast(regs->getValue(rs1)); - divisor = static_cast(regs->getValue(rs2)); - - if (divisor == 0) { - result = dividend; - } else if ((divisor == -1) && (dividend == static_cast(0x80000000))) { - result = 0; - } else { - result = dividend % divisor; - } - - regs->setValue(rd, result); - - logger->debug("{} ns. PC: 0x{:x}. M.REM: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, result); - - return true; - } - - bool M_extension::Exec_M_REMU() const { - int rd, rs1, rs2; - std::uint32_t divisor, dividend; - std::uint32_t result; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - dividend = static_cast(regs->getValue(rs1)); - divisor = static_cast(regs->getValue(rs2)); - - if (divisor == 0) { - result = dividend; - } else { - result = dividend % divisor; - } - - regs->setValue(rd, static_cast(result)); - - logger->debug("{} ns. PC: 0x{:x}. M.REMU: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, result); - - 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; - [[unlikely]] default: - std::cout << "M instruction not implemented yet" << "\n"; - inst.dump(); - //NOP(inst); - sc_core::sc_stop(); - break; - } - - return PC_not_affected; - } - -} \ No newline at end of file From acf38332d52c6a4b11ab3d2f298664038574d5ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Fri, 8 Jul 2022 12:02:30 +0200 Subject: [PATCH 03/17] cast to u32 --- inc/BASE_ISA.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/inc/BASE_ISA.h b/inc/BASE_ISA.h index 5fb79df..9e21d9e 100644 --- a/inc/BASE_ISA.h +++ b/inc/BASE_ISA.h @@ -10,6 +10,7 @@ #define Execute_H #define SC_INCLUDE_DYNAMIC_PROCESSES +#include #include "systemc" #include "tlm.h" @@ -175,6 +176,12 @@ namespace riscv_tlm { */ using extension_base::extension_base; + /** + * @brief Deduce signed type for T type + */ + using signed_T = typename std::make_signed::type; + + /** * @brief Access to funct7 field * @return funct7 field @@ -348,7 +355,7 @@ namespace riscv_tlm { rd = this->get_rd(); imm = get_imm_U() << 12; - this->regs->setValue(rd, static_cast(imm)); + this->regs->setValue(rd, static_cast(imm)); this->logger->debug("{} ns. PC: 0x{:x}. LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), this->regs->getPC(), @@ -360,11 +367,11 @@ namespace riscv_tlm { bool Exec_AUIPC() const { unsigned int rd; std::uint32_t imm; - std::uint32_t new_pc; + T new_pc; rd = this->get_rd(); imm = get_imm_U() << 12; - new_pc = static_cast(this->regs->getPC() + imm); + new_pc = static_cast(this->regs->getPC() + imm); this->regs->setValue(rd, new_pc); @@ -379,7 +386,7 @@ namespace riscv_tlm { bool Exec_JAL() const { std::int32_t mem_addr; unsigned int rd; - std::uint32_t new_pc, old_pc; + T new_pc, old_pc; rd = this->get_rd(); mem_addr = get_imm_J(); @@ -401,7 +408,7 @@ namespace riscv_tlm { bool Exec_JALR() { std::uint32_t mem_addr; unsigned int rd, rs1; - std::uint32_t new_pc, old_pc; + T new_pc, old_pc; rd = this->get_rd(); rs1 = this->get_rs1(); From fc85c603d4de1141ce275c369e28b58bba395f4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Thu, 21 Jul 2022 15:33:23 +0200 Subject: [PATCH 04/17] Two instances of CPU (RV32, RV64). Need to implement RV64 specific instructions. --- inc/CPU.h | 176 +++++++++++++++++++++++++++++---------- inc/Debug.h | 4 +- inc/Registers.h | 3 + inc/extension_base.h | 2 +- src/CPU.cpp | 194 ++++--------------------------------------- src/Debug.cpp | 4 +- src/RV32.cpp | 187 +++++++++++++++++++++++++++++++++++++++++ src/RV64.cpp | 183 ++++++++++++++++++++++++++++++++++++++++ src/Registers.cpp | 17 ++++ src/Simulator.cpp | 32 +++++-- 10 files changed, 565 insertions(+), 237 deletions(-) create mode 100644 src/RV32.cpp create mode 100644 src/RV64.cpp diff --git a/inc/CPU.h b/inc/CPU.h index b3d7a12..c59f179 100644 --- a/inc/CPU.h +++ b/inc/CPU.h @@ -28,13 +28,28 @@ namespace riscv_tlm { -/** - * @brief ISC_V CPU model - * @param name name of the module - */ - class CPU : sc_core::sc_module { + + class CPU : sc_core::sc_module { public: + /* Constructors */ + explicit CPU(sc_core::sc_module_name const &name, bool debug); + + CPU() noexcept = delete; + CPU(const CPU& other) noexcept = delete; + CPU(CPU && other) noexcept = delete; + CPU& operator=(const CPU& other) noexcept = delete; + CPU& operator=(CPU&& other) noexcept = delete; + + /* Destructors */ + ~CPU() override = default; + + /** + * @brief Perform one instruction step + * @return Breackpoint found (TBD, always true) + */ + virtual bool CPU_step() = 0; + /** * @brief Instruction Memory bus socket * @param trans transction to perfoem @@ -49,60 +64,87 @@ namespace riscv_tlm { */ tlm_utils::simple_target_socket irq_line_socket; + /** + * @brief 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); + + /** + * @brief CPU main thread + */ + [[noreturn]] void CPU_thread(); + + /** + * @brief Process and triggers IRQ if all conditions met + * @return true if IRQ is triggered, false otherwise + */ + virtual bool cpu_process_IRQ() = 0; + + /** + * @brief callback for IRQ simple socket + * @param trans transaction to perform (empty) + * @param delay time to annotate + * + * it triggers an IRQ when called + */ + virtual void call_interrupt(tlm::tlm_generic_payload &trans, + sc_core::sc_time &delay) = 0; + public: + MemoryInterface *mem_intf; + protected: + Performance *perf; + std::shared_ptr logger; + tlm_utils::tlm_quantumkeeper *m_qk; + Instruction inst; + bool interrupt; + bool irq_already_down; + sc_core::sc_time default_time; + bool dmi_ptr_valid; + tlm::tlm_generic_payload trans; + unsigned char *dmi_ptr = nullptr; + }; + + /** + * @brief RISC_V CPU 32 bits model + * @param name name of the module + */ + class RV32 : public CPU { + public: + using BaseType = std::uint32_t; + /** * @brief Constructor * @param name Module name * @param PC Program Counter initialize value * @param debug To start debugging */ - CPU(sc_core::sc_module_name const &name, std::uint32_t PC, bool debug); + RV32(sc_core::sc_module_name const &name, BaseType PC, bool debug); /** * @brief Destructor */ - ~CPU() override; + ~RV32() override; - MemoryInterface *mem_intf; - - bool CPU_step(); - - - Registers *getRegisterBank() { return register_bank; } + bool CPU_step() override; + Registers *getRegisterBank() { return register_bank; } private: - Registers *register_bank; - Performance *perf; - std::shared_ptr logger; - C_extension *c_inst; - M_extension *m_inst; - A_extension *a_inst; - BASE_ISA *exec; - tlm_utils::tlm_quantumkeeper *m_qk; - - Instruction inst; - bool interrupt; - std::uint32_t int_cause; - bool irq_already_down; - sc_core::sc_time default_time; - bool dmi_ptr_valid; - - tlm::tlm_generic_payload trans; - std::uint32_t INSTR; - unsigned char *dmi_ptr = nullptr; - + Registers *register_bank; + C_extension *c_inst; + M_extension *m_inst; + A_extension *a_inst; + BASE_ISA *exec; + BaseType int_cause; + BaseType INSTR; /** * * @brief Process and triggers IRQ if all conditions met * @return true if IRQ is triggered, false otherwise */ - bool cpu_process_IRQ(); - - /** - * main thread for CPU simulation - * @brief CPU mai thread - */ - [[noreturn]] void CPU_thread(); + bool cpu_process_IRQ() override; /** * @brief callback for IRQ simple socket @@ -113,14 +155,58 @@ namespace riscv_tlm { */ void call_interrupt(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay); + }; // RV32 class + + /** + * @brief RISC_V CPU 64 bits model + * @param name name of the module + */ + class RV64 : public CPU { + public: + using BaseType = std::uint64_t; /** - * DMI pointer is not longer valid - * @param start memory address region start - * @param end memory address region end + * @brief Constructor + * @param name Module name + * @param PC Program Counter initialize value + * @param debug To start debugging */ - void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end); - }; + RV64(sc_core::sc_module_name const &name, BaseType PC, bool debug); + + /** + * @brief Destructor + */ + ~RV64() override; + + bool CPU_step() override; + Registers *getRegisterBank() { return register_bank; } + + private: + Registers *register_bank; + C_extension *c_inst; + M_extension *m_inst; + A_extension *a_inst; + BASE_ISA *exec; + BaseType int_cause; + BaseType INSTR; + + /** + * + * @brief Process and triggers IRQ if all conditions met + * @return true if IRQ is triggered, false otherwise + */ + bool cpu_process_IRQ() override; + + /** + * @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); + }; // RV64 class } #endif diff --git a/inc/Debug.h b/inc/Debug.h index ea838d4..390e0a9 100644 --- a/inc/Debug.h +++ b/inc/Debug.h @@ -25,7 +25,7 @@ namespace riscv_tlm { class Debug : sc_core::sc_module { public: - Debug(riscv_tlm::CPU *cpu, Memory *mem); + Debug(riscv_tlm::RV32 *cpu, Memory *mem); ~Debug() override; @@ -41,7 +41,7 @@ namespace riscv_tlm { static constexpr size_t bufsize = 1024 * 8; char iobuf[bufsize]{}; int conn; - riscv_tlm::CPU *dbg_cpu; + riscv_tlm::RV32 *dbg_cpu; Memory *dbg_mem; tlm::tlm_generic_payload dbg_trans; unsigned char pyld_array[128]{}; diff --git a/inc/Registers.h b/inc/Registers.h index bcd0b28..84a4d1b 100644 --- a/inc/Registers.h +++ b/inc/Registers.h @@ -407,11 +407,14 @@ namespace riscv_tlm { Performance *perf; + void initCSR(); + /* void initCSR() { CSR[CSR_MISA] = MISA_MXL | MISA_M_EXTENSION | MISA_C_EXTENSION | MISA_A_EXTENSION | MISA_I_BASE; CSR[CSR_MSTATUS] = MISA_MXL; } + */ }; } #endif diff --git a/inc/extension_base.h b/inc/extension_base.h index 3abf2e6..4adb9e1 100644 --- a/inc/extension_base.h +++ b/inc/extension_base.h @@ -80,7 +80,7 @@ namespace riscv_tlm { } /* pure virtual functions */ - virtual T opcode() const = 0; + virtual std::uint32_t opcode() const = 0; virtual unsigned int get_rd() const { return m_instr.range(11, 7); diff --git a/src/CPU.cpp b/src/CPU.cpp index 6289e49..a1a00d8 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -11,37 +11,22 @@ namespace riscv_tlm { SC_HAS_PROCESS(CPU); - CPU::CPU(sc_core::sc_module_name const &name, std::uint32_t PC, bool debug) : - sc_module(name), instr_bus("instr_bus"), inst(0), - default_time(10, sc_core::SC_NS), INSTR(0) { - register_bank = new Registers(); - mem_intf = new MemoryInterface(); - + CPU::CPU(sc_core::sc_module_name const &name, bool debug) : sc_module(name), instr_bus("instr_bus"), inst(0), default_time(10, sc_core::SC_NS) { perf = Performance::getInstance(); - - register_bank->setPC(PC); - register_bank->setValue(Registers::sp, (Memory::SIZE / 4) - 1); - - irq_line_socket.register_b_transport(this, &CPU::call_interrupt); - interrupt = false; - - int_cause = 0; - irq_already_down = false; - - dmi_ptr_valid = false; - instr_bus.register_invalidate_direct_mem_ptr(this, - &CPU::invalidate_direct_mem_ptr); - - 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); + logger = spdlog::get("my_logger"); m_qk = new tlm_utils::tlm_quantumkeeper(); m_qk->reset(); + dmi_ptr_valid = false; + + irq_already_down = false; + interrupt = false; + + irq_line_socket.register_b_transport(this, &CPU::call_interrupt); + trans.set_command(tlm::TLM_READ_COMMAND); - trans.set_data_ptr(reinterpret_cast(&INSTR)); + trans.set_data_length(4); trans.set_streaming_width(4); // = data_length to indicate no streaming trans.set_byte_enable_ptr(nullptr); // 0 indicates unused @@ -51,147 +36,12 @@ namespace riscv_tlm { if (!debug) { SC_THREAD(CPU_thread); } + }; - logger = spdlog::get("my_logger"); - } - - CPU::~CPU() { - delete register_bank; - delete mem_intf; - delete exec; - delete c_inst; - delete m_inst; - delete a_inst; - delete m_qk; - } - - bool CPU::cpu_process_IRQ() { - std::uint32_t csr_temp; - bool ret_value = false; - - if (interrupt) { - csr_temp = register_bank->getCSR(CSR_MSTATUS); - if ((csr_temp & MSTATUS_MIE) == 0) { - logger->debug("{} ns. PC: 0x{:x}. Interrupt delayed", sc_core::sc_time_stamp().value(), - register_bank->getPC()); - - return ret_value; - } - - csr_temp = register_bank->getCSR(CSR_MIP); - - if ((csr_temp & MIP_MEIP) == 0) { - csr_temp |= MIP_MEIP; // MEIP bit in MIP register (11th bit) - register_bank->setCSR(CSR_MIP, csr_temp); - - logger->debug("{} ns. PC: 0x{:x}. Interrupt!", sc_core::sc_time_stamp().value(), - register_bank->getPC()); - - - /* updated MEPC register */ - std::uint32_t old_pc = register_bank->getPC(); - register_bank->setCSR(CSR_MEPC, old_pc); - - logger->debug("{} ns. PC: 0x{:x}. Old PC Value 0x{:x}", sc_core::sc_time_stamp().value(), - register_bank->getPC(), - old_pc); - - /* update MCAUSE register */ - register_bank->setCSR(CSR_MCAUSE, 0x80000000); - - /* set new PC address */ - std::uint32_t new_pc = register_bank->getCSR(CSR_MTVEC); - //new_pc = new_pc & 0xFFFFFFFC; // last two bits always to 0 - logger->debug("{} ns. PC: 0x{:x}. NEW PC Value 0x{:x}", sc_core::sc_time_stamp().value(), - register_bank->getPC(), - new_pc); - register_bank->setPC(new_pc); - - ret_value = true; - interrupt = false; - irq_already_down = false; - } - } else { - if (!irq_already_down) { - csr_temp = register_bank->getCSR(CSR_MIP); - csr_temp &= ~MIP_MEIP; - register_bank->setCSR(CSR_MIP, csr_temp); - irq_already_down = true; - } - } - - return ret_value; - } - - bool CPU::CPU_step() { - bool PC_not_affected = false; - - /* Get new PC value */ - if (dmi_ptr_valid) { - /* if memory_offset at Memory module is set, this won't work */ - std::memcpy(&INSTR, dmi_ptr + register_bank->getPC(), 4); - } else { - sc_core::sc_time delay = sc_core::SC_ZERO_TIME; - tlm::tlm_dmi dmi_data; - trans.set_address(register_bank->getPC()); - instr_bus->b_transport(trans, delay); - - if (trans.is_response_error()) { - SC_REPORT_ERROR("CPU base", "Read memory"); - } - - if (trans.is_dmi_allowed()) { - dmi_ptr_valid = instr_bus->get_direct_mem_ptr(trans, dmi_data); - if (dmi_ptr_valid) { - std::cout << "Get DMI_PTR " << std::endl; - dmi_ptr = dmi_data.get_dmi_ptr(); - } - } - } - - perf->codeMemoryRead(); - inst.setInstr(INSTR); - bool breakpoint = false; - - /* check what type of instruction is and execute it */ - switch (inst.check_extension()) { - [[likely]] case BASE_EXTENSION: - PC_not_affected = exec->process_instruction(inst, &breakpoint); - if (PC_not_affected) { - register_bank->incPC(); - } - break; - case C_EXTENSION: - PC_not_affected = c_inst->process_instruction(inst, &breakpoint); - if (PC_not_affected) { - register_bank->incPCby2(); - } - break; - case M_EXTENSION: - PC_not_affected = m_inst->process_instruction(inst); - if (PC_not_affected) { - register_bank->incPC(); - } - break; - case A_EXTENSION: - PC_not_affected = a_inst->process_instruction(inst); - if (PC_not_affected) { - register_bank->incPC(); - } - break; - [[unlikely]] default: - std::cout << "Extension not implemented yet" << std::endl; - inst.dump(); - exec->NOP(); - } - - if (breakpoint) { - std::cout << "Breakpoint set to true\n"; - } - - perf->instructionsInc(); - - return breakpoint; + void CPU::invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end) { + (void) start; + (void) end; + dmi_ptr_valid = false; } [[noreturn]] void CPU::CPU_thread() { @@ -219,18 +69,4 @@ namespace riscv_tlm { #endif } // while(1) } // CPU_thread - - void CPU::call_interrupt(tlm::tlm_generic_payload &m_trans, - sc_core::sc_time &delay) { - interrupt = true; - /* Socket caller send a cause (its id) */ - memcpy(&int_cause, m_trans.get_data_ptr(), sizeof(std::uint32_t)); - delay = sc_core::SC_ZERO_TIME; - } - - void CPU::invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end) { - (void) start; - (void) end; - dmi_ptr_valid = false; - } } \ No newline at end of file diff --git a/src/Debug.cpp b/src/Debug.cpp index 51f4153..dfe4933 100644 --- a/src/Debug.cpp +++ b/src/Debug.cpp @@ -23,7 +23,7 @@ namespace riscv_tlm { constexpr char nibble_to_hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - Debug::Debug(riscv_tlm::CPU *cpu, Memory *mem) : sc_module(sc_core::sc_module_name("Debug")) { + Debug::Debug(riscv_tlm::RV32 *cpu, Memory *mem) : sc_module(sc_core::sc_module_name("Debug")) { dbg_cpu = cpu; dbg_mem = mem; @@ -120,7 +120,7 @@ namespace riscv_tlm { send_packet(conn, stream.str()); } else if (boost::starts_with(msg, "p")) { long n = strtol(msg.c_str() + 1, 0, 16); - unsigned int reg_value; + std::uint64_t reg_value; if (n < 32) { reg_value = register_bank->getValue(n); } else if (n == 32) { diff --git a/src/RV32.cpp b/src/RV32.cpp new file mode 100644 index 0000000..f239e08 --- /dev/null +++ b/src/RV32.cpp @@ -0,0 +1,187 @@ +/*! + \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" + +namespace riscv_tlm { + + SC_HAS_PROCESS(RV32); + + RV32::RV32(sc_core::sc_module_name const &name, BaseType PC, bool debug) : + CPU(name, debug), INSTR(0) { + + register_bank = new Registers(); + mem_intf = new MemoryInterface(); + register_bank->setPC(PC); + register_bank->setValue(Registers::sp, (Memory::SIZE / 4) - 1); + + int_cause = 0; + + instr_bus.register_invalidate_direct_mem_ptr(this, + &RV32::invalidate_direct_mem_ptr); + + 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); + + trans.set_data_ptr(reinterpret_cast(&INSTR)); + + logger->info("Created RV32 CPU"); + std::cout << "Created RV32 CPU" << std::endl; + } + + RV32::~RV32() { + delete register_bank; + delete mem_intf; + delete exec; + delete c_inst; + delete m_inst; + delete a_inst; + delete m_qk; + } + + bool RV32::cpu_process_IRQ() { + BaseType csr_temp; + bool ret_value = false; + + if (interrupt) { + csr_temp = register_bank->getCSR(CSR_MSTATUS); + if ((csr_temp & MSTATUS_MIE) == 0) { + logger->debug("{} ns. PC: 0x{:x}. Interrupt delayed", sc_core::sc_time_stamp().value(), + register_bank->getPC()); + + return ret_value; + } + + csr_temp = register_bank->getCSR(CSR_MIP); + + if ((csr_temp & MIP_MEIP) == 0) { + csr_temp |= MIP_MEIP; // MEIP bit in MIP register (11th bit) + register_bank->setCSR(CSR_MIP, csr_temp); + + logger->debug("{} ns. PC: 0x{:x}. Interrupt!", sc_core::sc_time_stamp().value(), + register_bank->getPC()); + + /* updated MEPC register */ + BaseType old_pc = register_bank->getPC(); + register_bank->setCSR(CSR_MEPC, old_pc); + + logger->debug("{} ns. PC: 0x{:x}. Old PC Value 0x{:x}", sc_core::sc_time_stamp().value(), + register_bank->getPC(), + old_pc); + + /* update MCAUSE register */ + register_bank->setCSR(CSR_MCAUSE, 0x80000000); + + /* set new PC address */ + BaseType new_pc = register_bank->getCSR(CSR_MTVEC); + //new_pc = new_pc & 0xFFFFFFFC; // last two bits always to 0 + logger->debug("{} ns. PC: 0x{:x}. NEW PC Value 0x{:x}", sc_core::sc_time_stamp().value(), + register_bank->getPC(), + new_pc); + register_bank->setPC(new_pc); + + ret_value = true; + interrupt = false; + irq_already_down = false; + } + } else { + if (!irq_already_down) { + csr_temp = register_bank->getCSR(CSR_MIP); + csr_temp &= ~MIP_MEIP; + register_bank->setCSR(CSR_MIP, csr_temp); + irq_already_down = true; + } + } + + return ret_value; + } + + bool RV32::CPU_step() { + bool PC_not_affected = false; + + /* Get new PC value */ + if (dmi_ptr_valid) { + /* if memory_offset at Memory module is set, this won't work */ + std::memcpy(&INSTR, dmi_ptr + register_bank->getPC(), 4); + } else { + sc_core::sc_time delay = sc_core::SC_ZERO_TIME; + tlm::tlm_dmi dmi_data; + trans.set_address(register_bank->getPC()); + instr_bus->b_transport(trans, delay); + + if (trans.is_response_error()) { + SC_REPORT_ERROR("CPU base", "Read memory"); + } + + if (trans.is_dmi_allowed()) { + dmi_ptr_valid = instr_bus->get_direct_mem_ptr(trans, dmi_data); + if (dmi_ptr_valid) { + std::cout << "Get DMI_PTR " << std::endl; + dmi_ptr = dmi_data.get_dmi_ptr(); + } + } + } + + perf->codeMemoryRead(); + inst.setInstr(INSTR); + bool breakpoint = false; + + /* check what type of instruction is and execute it */ + switch (inst.check_extension()) { + [[likely]] case BASE_EXTENSION: + PC_not_affected = exec->process_instruction(inst, &breakpoint); + if (PC_not_affected) { + register_bank->incPC(); + } + break; + case C_EXTENSION: + PC_not_affected = c_inst->process_instruction(inst, &breakpoint); + if (PC_not_affected) { + register_bank->incPCby2(); + } + break; + case M_EXTENSION: + PC_not_affected = m_inst->process_instruction(inst); + if (PC_not_affected) { + register_bank->incPC(); + } + break; + case A_EXTENSION: + PC_not_affected = a_inst->process_instruction(inst); + if (PC_not_affected) { + register_bank->incPC(); + } + break; + [[unlikely]] default: + std::cout << "Extension not implemented yet" << std::endl; + inst.dump(); + exec->NOP(); + } + + if (breakpoint) { + std::cout << "Breakpoint set to true\n"; + } + + perf->instructionsInc(); + + return breakpoint; + } + + + + void RV32::call_interrupt(tlm::tlm_generic_payload &m_trans, + sc_core::sc_time &delay) { + interrupt = true; + /* Socket caller send a cause (its id) */ + memcpy(&int_cause, m_trans.get_data_ptr(), sizeof(BaseType)); + delay = sc_core::SC_ZERO_TIME; + } + + +} \ No newline at end of file diff --git a/src/RV64.cpp b/src/RV64.cpp new file mode 100644 index 0000000..ced5f80 --- /dev/null +++ b/src/RV64.cpp @@ -0,0 +1,183 @@ +/*! + \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" + +namespace riscv_tlm { + + RV64::RV64(sc_core::sc_module_name const &name, BaseType PC, bool debug) : + CPU(name, debug), INSTR(0) { + + register_bank = new Registers(); + mem_intf = new MemoryInterface(); + register_bank->setPC(PC); + register_bank->setValue(Registers::sp, (Memory::SIZE / 4) - 1); + + int_cause = 0; + + instr_bus.register_invalidate_direct_mem_ptr(this, + &RV64::invalidate_direct_mem_ptr); + + 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); + + trans.set_data_ptr(reinterpret_cast(&INSTR)); + + logger->info("Created RV64 CPU"); + std::cout << "Created RV64 CPU" << std::endl; + } + + RV64::~RV64() { + delete register_bank; + delete mem_intf; + delete exec; + delete c_inst; + delete m_inst; + delete a_inst; + delete m_qk; + } + + bool RV64::cpu_process_IRQ() { + BaseType csr_temp; + bool ret_value = false; + + if (interrupt) { + csr_temp = register_bank->getCSR(CSR_MSTATUS); + if ((csr_temp & MSTATUS_MIE) == 0) { + logger->debug("{} ns. PC: 0x{:x}. Interrupt delayed", sc_core::sc_time_stamp().value(), + register_bank->getPC()); + + return ret_value; + } + + csr_temp = register_bank->getCSR(CSR_MIP); + + if ((csr_temp & MIP_MEIP) == 0) { + csr_temp |= MIP_MEIP; // MEIP bit in MIP register (11th bit) + register_bank->setCSR(CSR_MIP, csr_temp); + + logger->debug("{} ns. PC: 0x{:x}. Interrupt!", sc_core::sc_time_stamp().value(), + register_bank->getPC()); + + /* updated MEPC register */ + BaseType old_pc = register_bank->getPC(); + register_bank->setCSR(CSR_MEPC, old_pc); + + logger->debug("{} ns. PC: 0x{:x}. Old PC Value 0x{:x}", sc_core::sc_time_stamp().value(), + register_bank->getPC(), + old_pc); + + /* update MCAUSE register */ + register_bank->setCSR(CSR_MCAUSE, 0x80000000); + + /* set new PC address */ + BaseType new_pc = register_bank->getCSR(CSR_MTVEC); + //new_pc = new_pc & 0xFFFFFFFC; // last two bits always to 0 + logger->debug("{} ns. PC: 0x{:x}. NEW PC Value 0x{:x}", sc_core::sc_time_stamp().value(), + register_bank->getPC(), + new_pc); + register_bank->setPC(new_pc); + + ret_value = true; + interrupt = false; + irq_already_down = false; + } + } else { + if (!irq_already_down) { + csr_temp = register_bank->getCSR(CSR_MIP); + csr_temp &= ~MIP_MEIP; + register_bank->setCSR(CSR_MIP, csr_temp); + irq_already_down = true; + } + } + + return ret_value; + } + + bool RV64::CPU_step() { + bool PC_not_affected = false; + + /* Get new PC value */ + if (dmi_ptr_valid) { + /* if memory_offset at Memory module is set, this won't work */ + std::memcpy(&INSTR, dmi_ptr + register_bank->getPC(), 4); + } else { + sc_core::sc_time delay = sc_core::SC_ZERO_TIME; + tlm::tlm_dmi dmi_data; + trans.set_address(register_bank->getPC()); + instr_bus->b_transport(trans, delay); + + if (trans.is_response_error()) { + SC_REPORT_ERROR("CPU base", "Read memory"); + } + + if (trans.is_dmi_allowed()) { + dmi_ptr_valid = instr_bus->get_direct_mem_ptr(trans, dmi_data); + if (dmi_ptr_valid) { + std::cout << "Get DMI_PTR " << std::endl; + dmi_ptr = dmi_data.get_dmi_ptr(); + } + } + } + + perf->codeMemoryRead(); + inst.setInstr(INSTR); + bool breakpoint = false; + + /* check what type of instruction is and execute it */ + switch (inst.check_extension()) { + [[likely]] case BASE_EXTENSION: + PC_not_affected = exec->process_instruction(inst, &breakpoint); + if (PC_not_affected) { + register_bank->incPC(); + } + break; + case C_EXTENSION: + PC_not_affected = c_inst->process_instruction(inst, &breakpoint); + if (PC_not_affected) { + register_bank->incPCby2(); + } + break; + case M_EXTENSION: + PC_not_affected = m_inst->process_instruction(inst); + if (PC_not_affected) { + register_bank->incPC(); + } + break; + case A_EXTENSION: + PC_not_affected = a_inst->process_instruction(inst); + if (PC_not_affected) { + register_bank->incPC(); + } + break; + [[unlikely]] default: + std::cout << "Extension not implemented yet" << std::endl; + inst.dump(); + exec->NOP(); + } + + if (breakpoint) { + std::cout << "Breakpoint set to true\n"; + } + + perf->instructionsInc(); + + return breakpoint; + } + + void RV64::call_interrupt(tlm::tlm_generic_payload &m_trans, + sc_core::sc_time &delay) { + interrupt = true; + /* Socket caller send a cause (its id) */ + memcpy(&int_cause, m_trans.get_data_ptr(), sizeof(BaseType)); + delay = sc_core::SC_ZERO_TIME; + } + + +} \ No newline at end of file diff --git a/src/Registers.cpp b/src/Registers.cpp index 2b289ad..bc58468 100644 --- a/src/Registers.cpp +++ b/src/Registers.cpp @@ -6,4 +6,21 @@ */ // SPDX-License-Identifier: GPL-3.0-or-later +#include "Registers.h" +namespace riscv_tlm { + /* Specialization for each XLEN (RV32, RV64)*/ + template<> + 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; + } + + template<> + void Registers::initCSR() { + CSR[CSR_MISA] = (((std::uint64_t) 0x02) << 30) | MISA_M_EXTENSION | MISA_C_EXTENSION + | MISA_A_EXTENSION | MISA_I_BASE; + CSR[CSR_MSTATUS] = MISA_MXL; + } +} \ No newline at end of file diff --git a/src/Simulator.cpp b/src/Simulator.cpp index 50d81a6..973f7f4 100644 --- a/src/Simulator.cpp +++ b/src/Simulator.cpp @@ -24,12 +24,16 @@ #include "spdlog/spdlog.h" #include "spdlog/sinks/basic_file_sink.h" +typedef enum {RV32, RV64} cpu_types_t; + std::string filename; bool debug_session = false; bool mem_dump = false; uint32_t dump_addr_st = 0; uint32_t dump_addr_end = 0; +cpu_types_t cpu_type_opt = RV32; + /** * @class Simulator * This class instantiates all necessary modules, connects its ports and starts @@ -45,13 +49,17 @@ public: riscv_tlm::peripherals::Trace *trace; riscv_tlm::peripherals::Timer *timer; - explicit Simulator(sc_core::sc_module_name const &name): sc_module(name) { + explicit Simulator(sc_core::sc_module_name const &name, cpu_types_t cpu_type): sc_module(name) { std::uint32_t start_PC; MainMemory = new riscv_tlm::Memory("Main_Memory", filename); start_PC = MainMemory->getPCfromHEX(); - cpu = new riscv_tlm::CPU("cpu", start_PC, debug_session); + if (cpu_type == RV32) { + cpu = new riscv_tlm::RV32("cpu", start_PC, debug_session); + } else { + cpu = new riscv_tlm::RV64("cpu", start_PC, debug_session); + } Bus = new riscv_tlm::BusCtrl("BusCtrl"); trace = new riscv_tlm::peripherals::Trace("Trace"); @@ -67,7 +75,7 @@ public: timer->irq_line.bind(cpu->irq_line_socket); if (debug_session) { - riscv_tlm::Debug debug(cpu, MainMemory); + //riscv_tlm::Debug debug(cpu, MainMemory); } } @@ -83,7 +91,7 @@ public: } private: - void MemoryDump() { + void MemoryDump() const { std::cout << "********** MEMORY DUMP ***********\n"; tlm::tlm_generic_payload trans; tlm::tlm_dmi dmi_data; @@ -134,8 +142,9 @@ void process_arguments(int argc, char *argv[]) { int debug_level; debug_session = false; + cpu_type_opt = RV32; - while ((c = getopt(argc, argv, "DTE:B:L:f:?")) != -1) { + while ((c = getopt(argc, argv, "DTE:B:L:f:R:?")) != -1) { switch (c) { case 'D': debug_session = true; @@ -173,6 +182,13 @@ void process_arguments(int argc, char *argv[]) { case 'f': filename = std::string(optarg); break; + case 'R': + if (strcmp(optarg, "RV32") == 0) { + cpu_type_opt = RV32; + } else { + cpu_type_opt = RV64; + } + break; case '?': std::cout << "Call ./RISCV_TLM -D -L (0..3) filename.hex" << std::endl; @@ -199,15 +215,15 @@ int sc_main(int argc, char *argv[]) { /* SystemC time resolution set to 1 ns*/ sc_core::sc_set_time_resolution(1, sc_core::SC_NS); - spdlog::filename_t filename = SPDLOG_FILENAME_T("newlog.txt"); - logger = spdlog::create("my_logger", filename); + spdlog::filename_t log_filename = SPDLOG_FILENAME_T("newlog.txt"); + logger = spdlog::create("my_logger", log_filename); logger->set_pattern("%v"); logger->set_level(spdlog::level::info); /* Parse and process program arguments. -f is mandatory */ process_arguments(argc, argv); - top = new Simulator("top"); + top = new Simulator("top", cpu_type_opt); auto start = std::chrono::steady_clock::now(); sc_core::sc_start(); From 2615ccc8f8f8147ef965e81046705af4d48eb9d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Fri, 22 Jul 2022 13:28:36 +0200 Subject: [PATCH 05/17] Some specializations, removed lot of useless casts. --- inc/A_extension.h | 7 +- inc/BASE_ISA.h | 412 ++++++++++++++++++------------------------- inc/CPU.h | 4 +- inc/C_extension.h | 11 +- inc/M_extension.h | 9 +- inc/extension_base.h | 5 +- src/BASE_ISA.cpp | 132 ++++++++++++++ src/CPU.cpp | 2 +- 8 files changed, 325 insertions(+), 257 deletions(-) diff --git a/inc/A_extension.h b/inc/A_extension.h index b2d08ad..908aa84 100644 --- a/inc/A_extension.h +++ b/inc/A_extension.h @@ -61,12 +61,15 @@ namespace riscv_tlm { */ using extension_base::extension_base; + using signed_T = typename std::make_signed::type; + using unsigned_T = typename std::make_unsigned::type; + /** * @brief Access to opcode field * @return return opcode field */ - inline std::uint32_t opcode() const override { - return static_cast(this->m_instr.range(31, 27)); + inline unsigned_T opcode() const override { + return static_cast(this->m_instr.range(31, 27)); } /** diff --git a/inc/BASE_ISA.h b/inc/BASE_ISA.h index 9e21d9e..3e96301 100644 --- a/inc/BASE_ISA.h +++ b/inc/BASE_ISA.h @@ -11,6 +11,7 @@ #define SC_INCLUDE_DYNAMIC_PROCESSES #include +#include #include "systemc" #include "tlm.h" @@ -181,6 +182,10 @@ namespace riscv_tlm { */ using signed_T = typename std::make_signed::type; + /** + * @brief Deduce unsigned type for T type + */ + using unsigned_T = typename std::make_unsigned::type; /** * @brief Access to funct7 field @@ -190,172 +195,73 @@ namespace riscv_tlm { return this->m_instr.range(31, 25); } - /** - * @brief Sets func7 field - * @param value desired func7 value - */ - inline void set_func7(std::int32_t value) { - this->m_instr.range(31, 25) = value; - } - /** * @brief Gets immediate field value for I-type * @return immediate_I field + * @note Specialized */ - inline std::int32_t get_imm_I() const { - std::uint32_t aux = 0; - - aux = this->m_instr.range(31, 20); - - /* sign extension (optimize) */ - if (this->m_instr[31] == 1) { - aux |= (0b11111111111111111111) << 12; - } - - return static_cast(aux); - } - - /** - * @brief Sets immediate field for I-type - * @param value desired I value - */ - inline void set_imm_I(std::int32_t value) { - this->m_instr.range(31, 20) = value; - } + signed_T get_imm_I() const; /** * @brief Gets immediate field value for S-type * @return immediate_S field + * @note Specialized */ - inline std::int32_t get_imm_S() const { - std::uint32_t aux = 0; - - aux = this->m_instr.range(31, 25) << 5; - aux |= this->m_instr.range(11, 7); - - if (this->m_instr[31] == 1) { - aux |= (0b11111111111111111111) << 12; - } - - return static_cast(aux); - } + signed_T get_imm_S() const; /** * @brief Gets immediate field value for U-type * @return immediate_U field */ - inline std::int32_t get_imm_U() const { - return static_cast(this->m_instr.range(31, 12)); - } - - /** - * @brief Sets immediate field for U-type - * @param value desired U value - */ - inline void set_imm_U(std::int32_t value) { - this->m_instr.range(31, 12) = (value << 12); + inline unsigned_T get_imm_U() const { + return this->m_instr.range(31, 12); } /** * @brief Gets immediate field value for B-type * @return immediate_B field + * @note Specialized */ - inline std::int32_t get_imm_B() const { - std::int32_t aux = 0; - - aux |= this->m_instr[7] << 11; - aux |= this->m_instr.range(30, 25) << 5; - aux |= this->m_instr[31] << 12; - aux |= this->m_instr.range(11, 8) << 1; - - if (this->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(std::int32_t value) { - sc_dt::sc_uint<32> aux = value; - - this->m_instr[31] = aux[12]; - this->m_instr.range(30, 25) = aux.range(10, 5); - this->m_instr.range(11, 7) = aux.range(4, 1); - this->m_instr[6] = aux[11]; - } + signed_T get_imm_B() const; /** * @brief Gets immediate field value for J-type * @return immediate_J field + * @note Specialized */ - inline std::int32_t get_imm_J() const { - std::int32_t aux = 0; - - aux = this->m_instr[31] << 20; - aux |= this->m_instr.range(19, 12) << 12; - aux |= this->m_instr[20] << 11; - aux |= this->m_instr.range(30, 21) << 1; - - /* bit extension (better way to do that?) */ - if (this->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(std::int32_t value) { - sc_dt::sc_uint<32> aux = (value << 20); - - this->m_instr[31] = aux[20]; - this->m_instr.range(30, 21) = aux.range(10, 1); - this->m_instr[20] = aux[11]; - this->m_instr.range(19, 12) = aux.range(19, 12); - } + signed_T get_imm_J() const; /** * @brief Returns shamt field for Shifts instructions * @return value corresponding to inst(25:20) */ - inline std::int32_t get_shamt() const { - return static_cast(this->m_instr.range(25, 20)); + inline unsigned_T get_shamt() const { + return this->m_instr.range(25, 20); } /** * @brief Returns CSR field for CSR instructions * @return value corresponding to instr(31:20) */ - inline std::int32_t get_csr() const { - std::int32_t aux = 0; - - aux = static_cast(this->m_instr.range(31, 20)); - - return aux; + inline unsigned_T get_csr() const { + return this->m_instr.range(31, 20); } /** * @brief Access to opcode field * @return return opcode field */ - inline std::uint32_t opcode() const override { - return static_cast(this->m_instr.range(6, 0)); + inline unsigned_T opcode() const override { + return this->m_instr.range(6, 0); } bool Exec_LUI() const { unsigned int rd; - std::uint32_t imm; + unsigned_T imm; rd = this->get_rd(); imm = get_imm_U() << 12; - this->regs->setValue(rd, static_cast(imm)); + this->regs->setValue(rd, imm); this->logger->debug("{} ns. PC: 0x{:x}. LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), this->regs->getPC(), @@ -366,12 +272,12 @@ namespace riscv_tlm { bool Exec_AUIPC() const { unsigned int rd; - std::uint32_t imm; - T new_pc; + unsigned_T imm; + unsigned_T new_pc; rd = this->get_rd(); imm = get_imm_U() << 12; - new_pc = static_cast(this->regs->getPC() + imm); + new_pc = this->regs->getPC() + imm; this->regs->setValue(rd, new_pc); @@ -386,7 +292,7 @@ namespace riscv_tlm { bool Exec_JAL() const { std::int32_t mem_addr; unsigned int rd; - T new_pc, old_pc; + unsigned_T new_pc, old_pc; rd = this->get_rd(); mem_addr = get_imm_J(); @@ -406,9 +312,9 @@ namespace riscv_tlm { } bool Exec_JALR() { - std::uint32_t mem_addr; + signed_T mem_addr; unsigned int rd, rs1; - T new_pc, old_pc; + unsigned_T new_pc, old_pc; rd = this->get_rd(); rs1 = this->get_rs1(); @@ -417,7 +323,7 @@ namespace riscv_tlm { old_pc = this->regs->getPC(); this->regs->setValue(rd, old_pc + 4); - new_pc = static_cast((this->regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); + new_pc = static_cast((this->regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); if ((new_pc & 0x00000003) != 0) { // not aligned @@ -442,30 +348,7 @@ namespace riscv_tlm { bool Exec_BEQ() const { unsigned int rs1, rs2; - std::uint32_t new_pc; - - rs1 = this->get_rs1(); - rs2 = this->get_rs2(); - - if (this->regs->getValue(rs1) == this->regs->getValue(rs2)) { - new_pc = static_cast(this->regs->getPC() + get_imm_B()); - this->regs->setPC(new_pc); - } else { - this->regs->incPC(); - new_pc = static_cast(this->regs->getPC()); - } - - this->logger->debug("{} ns. PC: 0x{:x}. BEQ: x{:d}(0x{:x}) == x{:d}(0x{:x})? -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), this->regs->getPC(), - rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), new_pc); - - return true; - } - - bool Exec_BNE() const { - unsigned int rs1, rs2; - std::uint32_t new_pc; - std::uint32_t val1, val2; + unsigned_T val1, val2; rs1 = this->get_rs1(); rs2 = this->get_rs2(); @@ -473,31 +356,59 @@ namespace riscv_tlm { val1 = this->regs->getValue(rs1); val2 = this->regs->getValue(rs2); - if (val1 != val2) { - new_pc = static_cast(this->regs->getPC() + get_imm_B()); + if (val1 == val2) { + unsigned_T new_pc; + new_pc = static_cast(this->regs->getPC() + get_imm_B()); + this->regs->setPC(new_pc); + } else { + this->regs->incPC(); + } + + this->logger->debug("{} ns. PC: 0x{:x}. BEQ: x{:d}(0x{:x}) == x{:d}(0x{:x})? -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), this->regs->getPC()); + + return true; + } + + bool Exec_BNE() const { + unsigned int rs1, rs2; + signed_T val1, val2; + + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + val1 = static_cast(this->regs->getValue(rs1)); + val2 = static_cast(this->regs->getValue(rs2)); + + if (val1 != val2) { + unsigned_T new_pc; + new_pc = static_cast(this->regs->getPC() + get_imm_B()); this->regs->setPC(new_pc); } else { this->regs->incPC(); - new_pc = static_cast(this->regs->getPC()); } this->logger->debug("{} ns. PC: 0x{:x}. BNE: x{:d}(0x{:x}) != x{:d}(0x{:x})? -> PC (0x{:x})", sc_core::sc_time_stamp().value(), this->regs->getPC(), - rs1, val1, rs2, val2, new_pc); + rs1, val1, rs2, val2, this->regs->getPC()); return true; } bool Exec_BLT() const { unsigned int rs1, rs2; - std::uint32_t new_pc = 0; + signed_T val1, val2; rs1 = this->get_rs1(); rs2 = this->get_rs2(); - if (static_cast(this->regs->getValue(rs1)) - < static_cast(this->regs->getValue(rs2))) { - new_pc = static_cast(this->regs->getPC() + get_imm_B()); + val1 = static_cast(this->regs->getValue(rs1)); + val2 = static_cast(this->regs->getValue(rs2)); + + if (val1 < val2) { + unsigned_T new_pc; + new_pc = static_cast(this->regs->getPC() + get_imm_B()); this->regs->setPC(new_pc); } else { this->regs->incPC(); @@ -505,21 +416,24 @@ namespace riscv_tlm { this->logger->debug("{} ns. PC: 0x{:x}. BLT: x{:d}(0x{:x}) < x{:d}(0x{:x})? -> PC (0x{:x})", sc_core::sc_time_stamp().value(), this->regs->getPC(), - rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), new_pc); + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), this->regs->getPC()); return true; } bool Exec_BGE() const { unsigned int rs1, rs2; - std::uint32_t new_pc = 0; + signed_T val1, val2; rs1 = this->get_rs1(); rs2 = this->get_rs2(); - if (static_cast(this->regs->getValue(rs1)) - >= static_cast( this->regs->getValue(rs2))) { - new_pc = static_cast(this->regs->getPC() + get_imm_B()); + val1 = static_cast(this->regs->getValue(rs1)); + val2 = static_cast(this->regs->getValue(rs2)); + + if (val1 >= val2) { + unsigned_T new_pc; + new_pc = static_cast(this->regs->getPC() + get_imm_B()); this->regs->setPC(new_pc); } else { this->regs->incPC(); @@ -527,63 +441,63 @@ namespace riscv_tlm { this->logger->debug("{} ns. PC: 0x{:x}. BGE: x{:d}(0x{:x}) > x{:d}(0x{:x})? -> PC (0x{:x})", sc_core::sc_time_stamp().value(), this->regs->getPC(), - rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), new_pc); + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), this->regs->getPC()); return true; } bool Exec_BLTU() const { unsigned int rs1, rs2; - std::uint32_t new_pc; + unsigned_T val1, val2; rs1 = this->get_rs1(); rs2 = this->get_rs2(); - if (static_cast(this->regs->getValue(rs1)) - < static_cast(this->regs->getValue(rs2))) { - new_pc = static_cast(this->regs->getPC() + get_imm_B()); + val1 = this->regs->getValue(rs1); + val2 = this->regs->getValue(rs2); + + if (val1 < val2) { + unsigned_T new_pc; + new_pc = static_cast(this->regs->getPC() + get_imm_B()); this->regs->setPC(new_pc); } else { this->regs->incPC(); - new_pc = static_cast(this->regs->getPC()); } this->logger->debug("{} ns. PC: 0x{:x}. BLTU: x{:d}(0x{:x}) < x{:d}(0x{:x})? -> PC (0x{:x})", sc_core::sc_time_stamp().value(), this->regs->getPC(), - rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), new_pc); + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), this->regs->getPC()); return true; } bool Exec_BGEU() const { unsigned int rs1, rs2; + unsigned_T val1, val2; rs1 = this->get_rs1(); rs2 = this->get_rs2(); - if (static_cast(this->regs->getValue(rs1)) - >= static_cast(this->regs->getValue(rs2))) { - std::uint32_t new_pc; - new_pc = static_cast(this->regs->getPC() + get_imm_B()); - - this->logger->debug("{} ns. PC: 0x{:x}. BGEU: x{:d}(0x{:x}) > x{:d}(0x{:x}) -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), this->regs->getPC(), - rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), new_pc); + val1 = this->regs->getValue(rs1); + val2 = this->regs->getValue(rs2); + if (val1 >= val2) { + unsigned_T new_pc; + new_pc = static_cast(this->regs->getPC() + get_imm_B()); this->regs->setPC(new_pc); } else { - this->logger->debug("{} ns. PC: 0x{:x}. BGEU: x{:d}(0x{:x}) > x{:d}(0x{:x}) -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), this->regs->getPC(), - rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), - this->regs->getPC() + 4); this->regs->incPC(); } + this->logger->debug("{} ns. PC: 0x{:x}. BGEU: x{:d}(0x{:x}) > x{:d}(0x{:x}) -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), this->regs->getPC()); + return true; } bool Exec_LB() const { - std::uint32_t mem_addr; + unsigned_T mem_addr; unsigned int rd, rs1; std::int32_t imm; std::int8_t data; @@ -606,7 +520,7 @@ namespace riscv_tlm { } bool Exec_LH() const { - std::uint32_t mem_addr; + unsigned_T mem_addr; unsigned int rd, rs1; std::int32_t imm; int16_t data; @@ -629,7 +543,7 @@ namespace riscv_tlm { } bool Exec_LW() const { - std::uint32_t mem_addr; + unsigned_T mem_addr; unsigned int rd, rs1; std::int32_t imm; std::uint32_t data; @@ -652,7 +566,7 @@ namespace riscv_tlm { } bool Exec_LBU() const { - std::uint32_t mem_addr; + unsigned_T mem_addr; unsigned int rd, rs1; std::int32_t imm; std::uint8_t data; @@ -675,7 +589,7 @@ namespace riscv_tlm { } bool Exec_LHU() const { - std::uint32_t mem_addr; + unsigned_T mem_addr; unsigned int rd, rs1; std::int32_t imm; uint16_t data; @@ -699,7 +613,7 @@ namespace riscv_tlm { } bool Exec_SB() const { - std::uint32_t mem_addr; + unsigned_T mem_addr; unsigned int rs1, rs2; std::int32_t imm; std::uint32_t data; @@ -723,7 +637,7 @@ namespace riscv_tlm { } bool Exec_SH() const { - std::uint32_t mem_addr; + unsigned_T mem_addr; unsigned int rs1, rs2; std::int32_t imm; std::uint32_t data; @@ -747,7 +661,7 @@ namespace riscv_tlm { } bool Exec_SW() const { - std::uint32_t mem_addr; + unsigned_T mem_addr; unsigned int rs1, rs2; std::int32_t imm; std::uint32_t data; @@ -773,13 +687,13 @@ namespace riscv_tlm { bool Exec_ADDI() const { unsigned int rd, rs1; std::int32_t imm; - std::int32_t calc; + signed_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); imm = get_imm_I(); - calc = static_cast(this->regs->getValue(rs1)) + imm; + calc = static_cast(this->regs->getValue(rs1)) + imm; this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. ADDI: x{:d} + x{:d} -> x{:d}(0x{:x})", @@ -793,14 +707,16 @@ namespace riscv_tlm { bool Exec_SLTI() const { unsigned int rd, rs1; std::int32_t imm; + signed_T val1; rd = this->get_rd(); rs1 = this->get_rs1(); imm = get_imm_I(); - if (static_cast(this->regs->getValue(rs1)) < imm) { - this->regs->setValue(rd, 1); + val1 = static_cast(this->regs->getValue(rs1)); + if (val1 < imm) { + this->regs->setValue(rd, 1); this->logger->debug("{} ns. PC: 0x{:x}. SLTI: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), this->regs->getPC(), @@ -818,13 +734,15 @@ namespace riscv_tlm { bool Exec_SLTIU() const { unsigned int rd, rs1; - std::int32_t imm; + unsigned_T imm; + unsigned_T val1; rd = this->get_rd(); rs1 = this->get_rs1(); - imm = get_imm_I(); + imm = static_cast(get_imm_I()); + val1 = static_cast(this->regs->getValue(rs1)); - if (static_cast(this->regs->getValue(rs1)) < static_cast(imm)) { + if (val1 < imm) { this->regs->setValue(rd, 1); this->logger->debug("{} ns. PC: 0x{:x}. SLTIU: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), @@ -843,15 +761,15 @@ namespace riscv_tlm { bool Exec_XORI() const { unsigned int rd, rs1; - std::int32_t imm; - std::uint32_t calc; + unsigned_T imm; + unsigned_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); imm = get_imm_I(); calc = this->regs->getValue(rs1) ^ imm; - this->regs->setValue(rd, static_cast(calc)); + this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. XORI: x{:d} XOR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), this->regs->getPC(), @@ -862,15 +780,15 @@ namespace riscv_tlm { bool Exec_ORI() const { unsigned int rd, rs1; - std::int32_t imm; - std::uint32_t calc; + unsigned_T imm; + unsigned_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); imm = get_imm_I(); calc = this->regs->getValue(rs1) | imm; - this->regs->setValue(rd, static_cast(calc)); + this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. ORI: x{:d} OR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), this->regs->getPC(), @@ -881,30 +799,28 @@ namespace riscv_tlm { bool Exec_ANDI() const { unsigned int rd, rs1; - std::uint32_t imm; - std::uint32_t calc; - std::uint32_t aux; + unsigned_T imm; + unsigned_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); imm = get_imm_I(); - aux = this->regs->getValue(rs1); - calc = aux & imm; - this->regs->setValue(rd, static_cast(calc)); + calc = this->regs->getValue(rs1) & imm; + this->regs->setValue(rd, calc); - this->logger->debug("{} ns. PC: 0x{:x}. ANDI: x{:d}(0x{:x}) AND 0x{:x} -> x{:d}", + this->logger->debug("{} ns. PC: 0x{:x}. ANDI: x{:d} AND 0x{:x} -> x{:d}", sc_core::sc_time_stamp().value(), this->regs->getPC(), - rs1, aux, imm, rd); + rs1, imm, rd); return true; } bool Exec_SLLI() { unsigned int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; + unsigned_T shift; + unsigned_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); @@ -919,8 +835,8 @@ namespace riscv_tlm { shift = rs2 & 0x1F; - calc = static_cast(this->regs->getValue(rs1)) << shift; - this->regs->setValue(rd, static_cast(calc)); + calc = static_cast(this->regs->getValue(rs1)) << shift; + this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. SLLI: x{:d} << {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), @@ -932,8 +848,8 @@ namespace riscv_tlm { bool Exec_SRLI() const { unsigned int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; + unsigned_T shift; + unsigned_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); @@ -941,8 +857,8 @@ namespace riscv_tlm { shift = rs2 & 0x1F; - calc = static_cast(this->regs->getValue(rs1)) >> shift; - this->regs->setValue(rd, static_cast(calc)); + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. SRLI: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), @@ -954,8 +870,8 @@ namespace riscv_tlm { bool Exec_SRAI() const { unsigned int rd, rs1, rs2; - std::uint32_t shift; - std::int32_t calc; + unsigned_T shift; + signed_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); @@ -963,7 +879,7 @@ namespace riscv_tlm { shift = rs2 & 0x1F; - calc = static_cast(this->regs->getValue(rs1)) >> shift; + calc = static_cast(this->regs->getValue(rs1)) >> shift; this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. SRAI: x{:d} >> {:d} -> x{:d}(0x{:x})", @@ -976,14 +892,14 @@ namespace riscv_tlm { bool Exec_ADD() const { unsigned int rd, rs1, rs2; - std::uint32_t calc; + unsigned_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); calc = this->regs->getValue(rs1) + this->regs->getValue(rs2); - this->regs->setValue(rd, static_cast(calc)); + this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. ADD: x{:d} + x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), @@ -995,13 +911,13 @@ namespace riscv_tlm { bool Exec_SUB() const { unsigned int rd, rs1, rs2; - std::uint32_t calc; + unsigned_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); calc = this->regs->getValue(rs1) - this->regs->getValue(rs2); - this->regs->setValue(rd, static_cast(calc)); + this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. SUB: x{:d} - x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), @@ -1013,8 +929,8 @@ namespace riscv_tlm { bool Exec_SLL() const { unsigned int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; + unsigned_T shift; + unsigned_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); @@ -1022,8 +938,8 @@ namespace riscv_tlm { shift = this->regs->getValue(rs2) & 0x1F; - calc = static_cast(this->regs->getValue(rs1)) << shift; - this->regs->setValue(rd, static_cast(calc)); + calc = this->regs->getValue(rs1) << shift; + this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. SLL: x{:d} << x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), @@ -1035,12 +951,16 @@ namespace riscv_tlm { bool Exec_SLT() const { unsigned int rd, rs1, rs2; + signed_T val1, val2; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); - if (this->regs->getValue(rs1) < this->regs->getValue(rs2)) { + val1 = static_cast(this->regs->getValue(rs1)); + val2 = static_cast(this->regs->getValue(rs2)); + + if (val1 < val2) { this->regs->setValue(rd, 1); this->logger->debug("{} ns. PC: 0x{:x}. SLT: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), @@ -1059,13 +979,16 @@ namespace riscv_tlm { bool Exec_SLTU() const { unsigned int rd, rs1, rs2; + unsigned_T val1, val2; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); - if (static_cast(this->regs->getValue(rs1)) - < static_cast(this->regs->getValue(rs2))) { + val1 = this->regs->getValue(rs1); + val2 = this->regs->getValue(rs2); + + if (val1 < val2) { this->regs->setValue(rd, 1); this->logger->debug("{} ns. PC: 0x{:x}. SLTU: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), @@ -1084,14 +1007,14 @@ namespace riscv_tlm { bool Exec_XOR() const { unsigned int rd, rs1, rs2; - std::uint32_t calc; + unsigned_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); calc = this->regs->getValue(rs1) ^ this->regs->getValue(rs2); - this->regs->setValue(rd, static_cast(calc)); + this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. XOR: x{:d} XOR x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), @@ -1103,17 +1026,17 @@ namespace riscv_tlm { bool Exec_SRL() const { unsigned int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; + unsigned_T shift; + unsigned_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); shift = this->regs->getValue(rs2) & 0x1F; + calc = this->regs->getValue(rs1) >> shift; - calc = static_cast(this->regs->getValue(rs1)) >> shift; - this->regs->setValue(rd, static_cast(calc)); + this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. SRL: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), @@ -1125,16 +1048,15 @@ namespace riscv_tlm { bool Exec_SRA() const { unsigned int rd, rs1, rs2; - std::uint32_t shift; - std::int32_t calc; + unsigned_T shift; + signed_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); shift = this->regs->getValue(rs2) & 0x1F; - - calc = static_cast(this->regs->getValue(rs1)) >> shift; + calc = static_cast(this->regs->getValue(rs1)) >> shift; this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. SRA: x{:d} >> {:d} -> x{:d}(0x{:x})", @@ -1147,14 +1069,14 @@ namespace riscv_tlm { bool Exec_OR() const { unsigned int rd, rs1, rs2; - std::uint32_t calc; + unsigned_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); calc = this->regs->getValue(rs1) | this->regs->getValue(rs2); - this->regs->setValue(rd, static_cast(calc)); + this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. OR: x{:d} OR x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), @@ -1166,14 +1088,14 @@ namespace riscv_tlm { bool Exec_AND() const { unsigned int rd, rs1, rs2; - std::uint32_t calc; + unsigned_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); calc = this->regs->getValue(rs1) & this->regs->getValue(rs2); - this->regs->setValue(rd, static_cast(calc)); + this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. AND: x{:d} AND x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), diff --git a/inc/CPU.h b/inc/CPU.h index c59f179..f82b5a1 100644 --- a/inc/CPU.h +++ b/inc/CPU.h @@ -154,7 +154,7 @@ namespace riscv_tlm { * it triggers an IRQ when called */ void call_interrupt(tlm::tlm_generic_payload &trans, - sc_core::sc_time &delay); + sc_core::sc_time &delay) override; }; // RV32 class /** @@ -205,7 +205,7 @@ namespace riscv_tlm { * it triggers an IRQ when called */ void call_interrupt(tlm::tlm_generic_payload &trans, - sc_core::sc_time &delay); + sc_core::sc_time &delay) override; }; // RV64 class } diff --git a/inc/C_extension.h b/inc/C_extension.h index 23f0d1d..0b02515 100644 --- a/inc/C_extension.h +++ b/inc/C_extension.h @@ -100,16 +100,19 @@ namespace riscv_tlm { public: /** - * @brief Constructor, same as base clase + * @brief Constructor, same as base class */ using extension_base::extension_base; + using signed_T = typename std::make_signed::type; + using unsigned_T = typename std::make_unsigned::type; + /** * @brief Access to opcode field * @return return opcode field */ - [[nodiscard]] inline std::uint32_t opcode() const override { - return static_cast(this->m_instr.range(1, 0)); + [[nodiscard]] inline unsigned_T opcode() const override { + return static_cast(this->m_instr.range(1, 0)); } [[nodiscard]] inline std::uint32_t get_rdp() const { @@ -507,6 +510,8 @@ namespace riscv_tlm { break; case C_FWWSP: [[unlikely]] + return OP_C_FSWSP; + break; default: return OP_C_ERROR; break; diff --git a/inc/M_extension.h b/inc/M_extension.h index 0871853..8355ba3 100644 --- a/inc/M_extension.h +++ b/inc/M_extension.h @@ -48,10 +48,13 @@ namespace riscv_tlm { public: /** - * @brief Constructor, same as base clase + * @brief Constructor, same as base class */ using extension_base::extension_base; + using signed_T = typename std::make_signed::type; + using unsigned_T = typename std::make_unsigned::type; + /** * @brief Decodes opcode of instruction * @return opcode of instruction @@ -342,8 +345,8 @@ namespace riscv_tlm { * @brief Access to opcode field * @return return opcode field */ - [[nodiscard]] inline std::uint32_t opcode() const override { - return static_cast(this->m_instr.range(14, 12)); + [[nodiscard]] inline unsigned_T opcode() const override { + return static_cast(this->m_instr.range(14, 12)); } }; diff --git a/inc/extension_base.h b/inc/extension_base.h index 4adb9e1..f4500a4 100644 --- a/inc/extension_base.h +++ b/inc/extension_base.h @@ -31,6 +31,9 @@ namespace riscv_tlm { template class extension_base { + using signed_T = typename std::make_signed::type; + using unsigned_T = typename std::make_unsigned::type; + public: extension_base(const T &instr, Registers *register_bank, MemoryInterface *mem_interface) : @@ -80,7 +83,7 @@ namespace riscv_tlm { } /* pure virtual functions */ - virtual std::uint32_t opcode() const = 0; + virtual unsigned_T opcode() const = 0; virtual unsigned int get_rd() const { return m_instr.range(11, 7); diff --git a/src/BASE_ISA.cpp b/src/BASE_ISA.cpp index 1e65da0..2506026 100644 --- a/src/BASE_ISA.cpp +++ b/src/BASE_ISA.cpp @@ -6,3 +6,135 @@ */ // SPDX-License-Identifier: GPL-3.0-or-later +#include "BASE_ISA.h" + +namespace riscv_tlm { + + ///// RV32 Specialization + template<> + int32_t BASE_ISA::get_imm_I() const { + std::uint32_t aux = 0; + + aux = this->m_instr.range(31, 20); + + /* sign extension (optimize) */ + if (this->m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + } + + return static_cast(aux); + } + + template<> + std::int32_t BASE_ISA::get_imm_S() const { + std::uint32_t aux = 0; + + aux = this->m_instr.range(31, 25) << 5; + aux |= this->m_instr.range(11, 7); + + if (this->m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + } + + return static_cast(aux); + } + + template<> + std::int32_t BASE_ISA::get_imm_B() const { + std::uint32_t aux = 0; + + aux |= this->m_instr[7] << 11; + aux |= this->m_instr.range(30, 25) << 5; + aux |= this->m_instr[31] << 12; + aux |= this->m_instr.range(11, 8) << 1; + + if (this->m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + } + + return static_cast(aux); + } + + + template<> + std::int32_t BASE_ISA::get_imm_J() const { + std::uint32_t aux = 0; + + aux = this->m_instr[31] << 20; + aux |= this->m_instr.range(19, 12) << 12; + aux |= this->m_instr[20] << 11; + aux |= this->m_instr.range(30, 21) << 1; + + /* bit extension (better way to do that?) */ + if (this->m_instr[31] == 1) { + aux |= (0b111111111111) << 20; + } + + return static_cast(aux); + } + + ///// RV64 Specialization + template<> + int64_t BASE_ISA::get_imm_I() const { + std::uint64_t aux = 0; + + aux = this->m_instr.range(31, 20); + + /* sign extension (optimize) */ + if (this->m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + aux |= 0xFFFFFFFFULL << 32; + } + + return static_cast(aux); + } + + template<> + std::int64_t BASE_ISA::get_imm_S() const { + std::uint64_t aux = 0; + + aux = this->m_instr.range(31, 25) << 5; + aux |= this->m_instr.range(11, 7); + + if (this->m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + aux |= 0xFFFFFFFFULL << 32; + } + + return static_cast(aux); + } + + template<> + std::int64_t BASE_ISA::get_imm_B() const { + std::uint64_t aux = 0; + + aux |= this->m_instr[7] << 11; + aux |= this->m_instr.range(30, 25) << 5; + aux |= this->m_instr[31] << 12; + aux |= this->m_instr.range(11, 8) << 1; + + if (this->m_instr[31] == 1) { + aux |= (0b11111111111111111111) << 12; + aux |= 0xFFFFFFFFULL << 32; + } + + return static_cast(aux); + } + + template<> + std::int64_t BASE_ISA::get_imm_J() const { + std::uint64_t aux = 0; + + aux = this->m_instr[31] << 20; + aux |= this->m_instr.range(19, 12) << 12; + aux |= this->m_instr[20] << 11; + aux |= this->m_instr.range(30, 21) << 1; + + /* bit extension (better way to do that?) */ + if (this->m_instr[31] == 1) { + aux |= (0b111111111111) << 20; + } + + return static_cast(aux); + } +} \ No newline at end of file diff --git a/src/CPU.cpp b/src/CPU.cpp index a1a00d8..c57c43f 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -17,7 +17,7 @@ namespace riscv_tlm { m_qk = new tlm_utils::tlm_quantumkeeper(); m_qk->reset(); - + mem_intf = nullptr; dmi_ptr_valid = false; irq_already_down = false; From d6f799e412cbbcb8ea7734409d27a5454f133dce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Fri, 22 Jul 2022 13:29:09 +0200 Subject: [PATCH 06/17] Minor changes --- src/Simulator.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Simulator.cpp b/src/Simulator.cpp index 973f7f4..2d8421f 100644 --- a/src/Simulator.cpp +++ b/src/Simulator.cpp @@ -15,7 +15,6 @@ #include #include "CPU.h" -#include "Memory.h" #include "BusCtrl.h" #include "Trace.h" #include "Timer.h" @@ -94,7 +93,6 @@ private: void MemoryDump() const { std::cout << "********** MEMORY DUMP ***********\n"; tlm::tlm_generic_payload trans; - tlm::tlm_dmi dmi_data; sc_core::sc_time delay; std::uint32_t data[4]; @@ -139,7 +137,7 @@ void intHandler(int dummy) { void process_arguments(int argc, char *argv[]) { int c; - int debug_level; + long int debug_level; debug_session = false; cpu_type_opt = RV32; @@ -153,13 +151,13 @@ void process_arguments(int argc, char *argv[]) { mem_dump = true; break; case 'B': - dump_addr_st = std::strtoul (optarg, 0, 16); + dump_addr_st = std::strtoul (optarg, nullptr, 16); break; case 'E': - dump_addr_end = std::strtoul(optarg, 0, 16); + dump_addr_end = std::strtoul(optarg, nullptr, 16); break; case 'L': - debug_level = std::atoi(optarg); + debug_level = std::strtol(optarg, nullptr, 10); switch (debug_level) { case 3: From 56b00aecd81d6239b398db4744a56d4085186489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Wed, 14 Sep 2022 20:01:36 +0200 Subject: [PATCH 07/17] Helper parameter for test-suite --- inc/CPU.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/inc/CPU.h b/inc/CPU.h index f82b5a1..794419f 100644 --- a/inc/CPU.h +++ b/inc/CPU.h @@ -91,6 +91,10 @@ namespace riscv_tlm { */ virtual void call_interrupt(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) = 0; + + virtual std::uint64_t getStartDumpAddress() = 0; + virtual std::uint64_t getEndDumpAddress() = 0; + public: MemoryInterface *mem_intf; protected: @@ -155,6 +159,9 @@ namespace riscv_tlm { */ void call_interrupt(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) override; + + std::uint64_t getStartDumpAddress() override; + std::uint64_t getEndDumpAddress() override; }; // RV32 class /** @@ -206,6 +213,9 @@ namespace riscv_tlm { */ void call_interrupt(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) override; + + std::uint64_t getStartDumpAddress() override; + std::uint64_t getEndDumpAddress() override; }; // RV64 class } From 643b880be3204be1791e17af96cfb5ad18655b14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Wed, 14 Sep 2022 20:02:07 +0200 Subject: [PATCH 08/17] M extension for RV64 --- inc/M_extension.h | 356 +++++++++++++++++++++++++++++--------------- src/Instruction.cpp | 2 +- src/M_extension.cpp | 158 ++++++++++++++++++++ 3 files changed, 393 insertions(+), 123 deletions(-) diff --git a/inc/M_extension.h b/inc/M_extension.h index 8355ba3..9e17057 100644 --- a/inc/M_extension.h +++ b/inc/M_extension.h @@ -25,7 +25,11 @@ namespace riscv_tlm { OP_M_DIVU, OP_M_REM, OP_M_REMU, - + OP_M_MULW, + OP_M_DIVW, + OP_M_DIVUW, + OP_M_REMW, + OP_M_REMUW, OP_M_ERROR } op_M_Codes; @@ -38,6 +42,11 @@ namespace riscv_tlm { M_DIVU = 0b101, M_REM = 0b110, M_REMU = 0b111, + M_MULW = 0b000, + M_DIVW = 0b100, + M_DIVUW = 0b101, + M_REMW = 0b110, + M_REMUW = 0b111, } M_Codes; /** @@ -61,34 +70,58 @@ namespace riscv_tlm { */ [[nodiscard]] op_M_Codes decode() const { - 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; + if (this->m_instr.range(6,0) == 0b110011) { + switch (opcode()) { + case M_MUL: + return OP_M_MUL; + break; + case M_MULH: + return OP_M_MULH; + break; + case M_MULHSU: + return OP_M_MULHSU; + break; + case M_MULHU: + return OP_M_MULHU; + break; + case M_DIV: + return OP_M_DIV; + break; + case M_DIVU: + return OP_M_DIVU; + break; + case M_REM: + return OP_M_REM; + break; + case M_REMU: + return OP_M_REMU; + break; + [[unlikely]] default: + return OP_M_ERROR; + break; + } + } else { + switch (opcode()) { + case M_MULW: + return OP_M_MULW; + break; + case M_DIVW: + return OP_M_DIVW; + break; + case M_DIVUW: + return OP_M_DIVUW; + break; + case M_REMW: + return OP_M_REMW; + break; + case M_REMUW: + return OP_M_REMUW; + break; [[unlikely]] default: - return OP_M_ERROR; - break; + return OP_M_ERROR; + break; + + } } return OP_M_ERROR; @@ -100,107 +133,42 @@ namespace riscv_tlm { void Exec_M_MUL() const { unsigned int rd, rs1, rs2; - std::int32_t multiplier, multiplicand; + signed_T multiplier, multiplicand; std::int64_t result; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); - multiplier = static_cast(extension_base::regs->getValue(rs1)); - multiplicand = static_cast(extension_base::regs->getValue(rs2)); - + multiplier = static_cast(this->regs->getValue(rs1)); + multiplicand = static_cast(this->regs->getValue(rs2)); result = static_cast(multiplier * multiplicand); - result = result & 0x00000000FFFFFFFF; - this->regs->setValue(rd, static_cast(result)); - this->logger->debug("{} ns. PC: 0x{:x}. M.MUL: x{:d} * x{:d} -> x{:d}({:d})", - sc_core::sc_time_stamp().value(), - extension_base::regs->getPC(), - rs1, rs2, rd, result); - } + this->regs->setValue(rd, static_cast(result)); - void Exec_M_MULH() const { - unsigned int rd, rs1, rs2; - std::int32_t multiplier, multiplicand; - std::int64_t result; - std::int32_t ret_value; - - rd = this->get_rd(); - rs1 = this->get_rs1(); - rs2 = this->get_rs2(); - - multiplier = static_cast(this->regs->getValue(rs1)); - multiplicand = static_cast(this->regs->getValue(rs2)); - - result = static_cast(multiplier) * static_cast(multiplicand); - - ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); - this->regs->setValue(rd, ret_value); - - this->logger->debug("{} ns. PC: 0x{:x}. M.MULH: x{:d} * x{:d} -> x{:d}({:d})", + this->logger->debug("{} ns. PC: 0x{:x}. M.MUL: x{:d}({:d}) * x{:d}({:d}) -> x{:d}({:d})", sc_core::sc_time_stamp().value(), this->regs->getPC(), - rs1, rs2, rd, result); + rs1, rs2, multiplier, multiplicand, rd, result); } - void Exec_M_MULHSU() const { - unsigned int rd, rs1, rs2; - std::int32_t multiplier; - std::uint32_t multiplicand; - std::int64_t result; + void Exec_M_MULH() const; - rd = this->get_rd(); - rs1 = this->get_rs1(); - rs2 = this->get_rs2(); + void Exec_M_MULHSU() const; - multiplier = static_cast(this->regs->getValue(rs1)); - multiplicand = this->regs->getValue(rs2); - - result = static_cast(multiplier * static_cast(multiplicand)); - result = (result >> 32) & 0x00000000FFFFFFFF; - this->regs->setValue(rd, static_cast(result)); - - this->logger->debug("{} ns. PC: 0x{:x}. M.MULHSU: x{:d} * x{:d} -> x{:d}({:d})", - sc_core::sc_time_stamp().value(), - this->regs->getPC(), - rs1, rs2, rd, result); - } - - void Exec_M_MULHU() const { - unsigned int rd, rs1, rs2; - std::uint32_t multiplier, multiplicand; - std::uint64_t result; - std::int32_t ret_value; - - rd = this->get_rd(); - rs1 = this->get_rs1(); - rs2 = this->get_rs2(); - - multiplier = static_cast(this->regs->getValue(rs1)); - multiplicand = static_cast(this->regs->getValue(rs2)); - - result = static_cast(multiplier) * static_cast(multiplicand); - ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); - this->regs->setValue(rd, ret_value); - - this->logger->debug("{} ns. PC: 0x{:x}. M.MULHU: x{:d} * x{:d} -> x{:d}({:d})", - sc_core::sc_time_stamp().value(), - this->regs->getPC(), - rs1, rs2, rd, result); - } + void Exec_M_MULHU() const; void Exec_M_DIV() const { unsigned int rd, rs1, rs2; - std::int32_t divisor, dividend; + signed_T divisor, dividend; std::int64_t result; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); - dividend = static_cast(this->regs->getValue(rs1)); - divisor = static_cast(this->regs->getValue(rs2)); + dividend = this->regs->getValue(rs1); + divisor = this->regs->getValue(rs2); if (divisor == 0) { result = -1; @@ -208,10 +176,9 @@ namespace riscv_tlm { result = 0x0000000080000000; } else { result = dividend / divisor; - result = result & 0x00000000FFFFFFFF; } - this->regs->setValue(rd, static_cast(result)); + this->regs->setValue(rd, result); this->logger->debug("{} ns. PC: 0x{:x}. M.DIV: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), @@ -221,7 +188,7 @@ namespace riscv_tlm { void Exec_M_DIVU() const { unsigned int rd, rs1, rs2; - std::uint32_t divisor, dividend; + unsigned_T divisor, dividend; std::uint64_t result; rd = this->get_rd(); @@ -235,10 +202,9 @@ namespace riscv_tlm { result = -1; } else { result = dividend / divisor; - result = result & 0x00000000FFFFFFFF; } - this->regs->setValue(rd, static_cast(result)); + this->regs->setValue(rd, result); this->logger->debug("{} ns. PC: 0x{:x}. M.DIVU: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), @@ -248,15 +214,15 @@ namespace riscv_tlm { void Exec_M_REM() const { unsigned int rd, rs1, rs2; - std::int32_t divisor, dividend; - std::int32_t result; + signed_T divisor, dividend; + signed_T result; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); - dividend = static_cast(this->regs->getValue(rs1)); - divisor = static_cast(this->regs->getValue(rs2)); + dividend = this->regs->getValue(rs1); + divisor = this->regs->getValue(rs2); if (divisor == 0) { result = dividend; @@ -268,7 +234,7 @@ namespace riscv_tlm { this->regs->setValue(rd, result); - this->logger->debug("{} ns. PC: 0x{:x}. M.REM: x{:d} / x{:d} -> x{:d}({:d})", + this->logger->debug("{} ns. PC: 0x{:x}. M.REM: x{:d} % x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), this->regs->getPC(), rs1, rs2, rd, result); @@ -276,15 +242,15 @@ namespace riscv_tlm { void Exec_M_REMU() const { unsigned int rd, rs1, rs2; - std::uint32_t divisor, dividend; - std::uint32_t result; + unsigned_T divisor, dividend; + unsigned_T result; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); - dividend = static_cast(this->regs->getValue(rs1)); - divisor = static_cast(this->regs->getValue(rs2)); + dividend = this->regs->getValue(rs1); + divisor = this->regs->getValue(rs2); if (divisor == 0) { result = dividend; @@ -292,14 +258,145 @@ namespace riscv_tlm { result = dividend % divisor; } - this->regs->setValue(rd, static_cast(result)); + this->regs->setValue(rd, result); - this->logger->debug("{} ns. PC: 0x{:x}. M.REMU: x{:d} / x{:d} -> x{:d}({:d})", + this->logger->debug("{} ns. PC: 0x{:x}. M.REMU: x{:d} % x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), this->regs->getPC(), rs1, rs2, rd, result); } + void Exec_M_MULW() const { + unsigned int rd, rs1, rs2; + std::uint32_t multiplier, multiplicand; + std::int64_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = static_cast(this->regs->getValue(rs1) & 0x00000000FFFFFFFF); + multiplicand = static_cast(this->regs->getValue(rs2) & 0x00000000FFFFFFFF); + result = static_cast((multiplier * multiplicand) & 0x00000000FFFFFFFF); + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULW: x{:d}({:d}) * x{:d}({:d}) -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, multiplier, multiplicand, rd, result); + } + + void Exec_M_DIVW() const { + unsigned int rd, rs1, rs2; + std::int32_t divisor, dividend; + std::int64_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + dividend = static_cast(this->regs->getValue(rs1) & 0x00000000FFFFFFFF); + divisor = static_cast(this->regs->getValue(rs2) & 0x00000000FFFFFFFF); + + if (divisor == 0) { + result = -1; + } else if ((divisor == -1) && (dividend == static_cast(0x80000000))) { + result = 0x0000000080000000; + } else { + result = dividend / divisor; + } + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.DIVW: x{:d} / x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_DIVUW() const { + unsigned int rd, rs1, rs2; + std::uint32_t divisor, dividend; + std::int64_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + dividend = static_cast(this->regs->getValue(rs1) & 0x00000000FFFFFFFF); + divisor = static_cast(this->regs->getValue(rs2) & 0x00000000FFFFFFFF); + + if (divisor == 0) { + result = -1; + } else if ((divisor == 0xFFFFFFFF) && (dividend == static_cast(0x80000000))) { + result = 0x0000000080000000; + } else { + result = static_cast(dividend / divisor); + } + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.DIVUW: x{:d} / x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_REMW() const { + unsigned int rd, rs1, rs2; + std::int32_t divisor, dividend; + signed_T result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + dividend = static_cast(this->regs->getValue(rs1) & 0x00000000FFFFFFFF); + divisor = static_cast(this->regs->getValue(rs2) & 0x00000000FFFFFFFF); + + if (divisor == 0) { + result = dividend; + } else if (divisor == -1) { + result = 0; + } else { + result = dividend % divisor; + } + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.REMW: x{:d} % x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_REMUW() const { + unsigned int rd, rs1, rs2; + std::uint32_t divisor, dividend; + std::int64_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + dividend = static_cast(this->regs->getValue(rs1) & 0x00000000FFFFFFFF); + divisor = static_cast(this->regs->getValue(rs2) & 0x00000000FFFFFFFF); + + if (divisor == 0) { + result = static_cast(dividend); + } else { + result = static_cast(dividend % divisor); + } + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.REMUW: x{:d}({:d}) % x{:d}({:d}) -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, dividend, rs2, divisor, rd, result); + } + bool process_instruction(Instruction &inst) { this->setInstr(inst.getInstr()); @@ -328,7 +425,22 @@ namespace riscv_tlm { case OP_M_REMU: Exec_M_REMU(); break; - [[unlikely]] default: + case OP_M_MULW: + Exec_M_MULW(); + break; + case OP_M_DIVW: + Exec_M_DIVW(); + break; + case OP_M_DIVUW: + Exec_M_DIVUW(); + break; + case OP_M_REMW: + Exec_M_REMW(); + break; + case OP_M_REMUW: + Exec_M_REMUW(); + break; + [[unlikely]] default: std::cout << "M instruction not implemented yet" << "\n"; inst.dump(); //NOP(inst); diff --git a/src/Instruction.cpp b/src/Instruction.cpp index 3886289..d8caeee 100644 --- a/src/Instruction.cpp +++ b/src/Instruction.cpp @@ -15,7 +15,7 @@ namespace riscv_tlm { } extension_t Instruction::check_extension() const { - if (((m_instr & 0x0000007F) == 0b0110011) + if ((((m_instr & 0x0000007F) == 0b0110011) || ((m_instr & 0x0000007F) == 0b0111011)) && (((m_instr & 0x7F000000) >> 25) == 0b0000001)) { return M_EXTENSION; } else if ((m_instr & 0x0000007F) == 0b0101111) { diff --git a/src/M_extension.cpp b/src/M_extension.cpp index 4e8fee2..a6838b3 100644 --- a/src/M_extension.cpp +++ b/src/M_extension.cpp @@ -7,4 +7,162 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "M_extension.h" +namespace riscv_tlm { + // RV32 + template<> + void M_extension::Exec_M_MULH() const { + unsigned int rd, rs1, rs2; + signed_T multiplier, multiplicand; + std::int64_t result; + signed_T ret_value; + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = this->regs->getValue(rs1); + multiplicand = this->regs->getValue(rs2); + + + result = static_cast(multiplier) * static_cast(multiplicand); + ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); + + this->regs->setValue(rd, ret_value); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULH: x{:d}({:d}) * x{:d}({:d}) -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, multiplier, rs2, multiplicand, rd, result); + } + + template<> + void M_extension::Exec_M_MULHSU() const { + unsigned int rd, rs1, rs2; + std::int32_t multiplier; + std::uint32_t multiplicand; + std::int64_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = static_cast(this->regs->getValue(rs1)); + multiplicand = this->regs->getValue(rs2); + + result = static_cast(multiplier * static_cast(multiplicand)); + result = (result >> 32) & 0x00000000FFFFFFFF; + this->regs->setValue(rd, static_cast(result)); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULHSU: x{:d} * x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + template<> + void M_extension::Exec_M_MULHU() const { + unsigned int rd, rs1, rs2; + std::uint32_t multiplier, multiplicand; + std::uint64_t result; + std::int32_t ret_value; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = static_cast(this->regs->getValue(rs1)); + multiplicand = static_cast(this->regs->getValue(rs2)); + + result = static_cast(multiplier) * static_cast(multiplicand); + ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); + this->regs->setValue(rd, ret_value); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULHU: x{:d} * x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + + // RV64 + // I need to use SystemC bigint with 128 bits to perform 64 x 64 bits multiplication and keep the high half + template<> + void M_extension::Exec_M_MULH() const { + unsigned int rd, rs1, rs2; + signed_T multiplier, multiplicand; + signed_T result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = this->regs->getValue(rs1); + multiplicand = this->regs->getValue(rs2); + + sc_dt::sc_bigint<128> mul = multiplier; + sc_dt::sc_bigint<128> muld = multiplicand; + sc_dt::sc_bigint<128> res = mul * muld; + result = res.range(127, 64).to_int64(); + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULH: x{:d}({:d}) * x{:d}({:d}) -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, multiplier, rs2, multiplicand, rd, result); + } + + template<> + void M_extension::Exec_M_MULHSU() const { + unsigned int rd, rs1, rs2; + signed_T multiplier; + unsigned_T multiplicand; + signed_T result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = this->regs->getValue(rs1); + multiplicand = this->regs->getValue(rs2); + + sc_dt::sc_bigint<128> mul = multiplier; + sc_dt::sc_bigint<128> muld = multiplicand; + sc_dt::sc_bigint<128> res = mul * muld; + result = res.range(127, 64).to_int64(); + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULHSU: x{:d} * x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + template<> + void M_extension::Exec_M_MULHU() const { + unsigned int rd, rs1, rs2; + unsigned_T multiplier, multiplicand; + unsigned_T result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = this->regs->getValue(rs1); + multiplicand = this->regs->getValue(rs2); + + sc_dt::sc_bigint<128> mul = multiplier; + sc_dt::sc_bigint<128> muld = multiplicand; + sc_dt::sc_bigint<128> res = mul * muld; + result = res.range(127, 64).to_uint64(); + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULHU: x{:d} * x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + +} \ No newline at end of file From 89f9293ff39ee2c3e2fbf54fa4d85b2031a2e93c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Wed, 14 Sep 2022 20:02:43 +0200 Subject: [PATCH 09/17] Helper functions for test-suite --- src/RV32.cpp | 6 ++++++ src/RV64.cpp | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/RV32.cpp b/src/RV32.cpp index f239e08..9d2cfd9 100644 --- a/src/RV32.cpp +++ b/src/RV32.cpp @@ -183,5 +183,11 @@ namespace riscv_tlm { delay = sc_core::SC_ZERO_TIME; } + std::uint64_t RV32::getStartDumpAddress() { + return register_bank->getValue(Registers::t0); + } + std::uint64_t RV32::getEndDumpAddress() { + return register_bank->getValue(Registers::t1); + } } \ No newline at end of file diff --git a/src/RV64.cpp b/src/RV64.cpp index ced5f80..524e92e 100644 --- a/src/RV64.cpp +++ b/src/RV64.cpp @@ -179,5 +179,11 @@ namespace riscv_tlm { delay = sc_core::SC_ZERO_TIME; } + std::uint64_t RV64::getStartDumpAddress() { + return register_bank->getValue(Registers::t0); + } + std::uint64_t RV64::getEndDumpAddress() { + return register_bank->getValue(Registers::t1); + } } \ No newline at end of file From 0e2f1f7874e5a186f4ab83cc2e3d04adb5776d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Wed, 14 Sep 2022 20:03:01 +0200 Subject: [PATCH 10/17] Helper functions for test-suite --- src/Simulator.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/Simulator.cpp b/src/Simulator.cpp index 2d8421f..a181b74 100644 --- a/src/Simulator.cpp +++ b/src/Simulator.cpp @@ -48,12 +48,14 @@ public: riscv_tlm::peripherals::Trace *trace; riscv_tlm::peripherals::Timer *timer; - explicit Simulator(sc_core::sc_module_name const &name, cpu_types_t cpu_type): sc_module(name) { + explicit Simulator(sc_core::sc_module_name const &name, cpu_types_t cpu_type_m): sc_module(name) { std::uint32_t start_PC; MainMemory = new riscv_tlm::Memory("Main_Memory", filename); start_PC = MainMemory->getPCfromHEX(); + cpu_type = cpu_type_m; + if (cpu_type == RV32) { cpu = new riscv_tlm::RV32("cpu", start_PC, debug_session); } else { @@ -92,6 +94,16 @@ public: private: void MemoryDump() const { std::cout << "********** MEMORY DUMP ***********\n"; + + if (dump_addr_st == 0) { + dump_addr_st = cpu->getStartDumpAddress(); + } + + if (dump_addr_end == 0) { + dump_addr_end = cpu->getEndDumpAddress(); + } + + std::cout << "from 0x" << std::hex << dump_addr_st << " to 0x" << dump_addr_end << "\n"; tlm::tlm_generic_payload trans; sc_core::sc_time delay; std::uint32_t data[4]; @@ -122,6 +134,9 @@ private: signature_file.close(); } + +private: + cpu_types_t cpu_type; }; Simulator *top; @@ -181,7 +196,7 @@ void process_arguments(int argc, char *argv[]) { filename = std::string(optarg); break; case 'R': - if (strcmp(optarg, "RV32") == 0) { + if (strcmp(optarg, "32") == 0) { cpu_type_opt = RV32; } else { cpu_type_opt = RV64; @@ -214,7 +229,7 @@ int sc_main(int argc, char *argv[]) { sc_core::sc_set_time_resolution(1, sc_core::SC_NS); spdlog::filename_t log_filename = SPDLOG_FILENAME_T("newlog.txt"); - logger = spdlog::create("my_logger", log_filename); + logger = spdlog::create("my_logger", log_filename, true); logger->set_pattern("%v"); logger->set_level(spdlog::level::info); @@ -233,7 +248,8 @@ int sc_main(int argc, char *argv[]) { std::cout << "Total elapsed time: " << elapsed_seconds.count() << "s" << std::endl; std::cout << "Simulated " << int(std::round(instructions)) << " instr/sec" << std::endl; - if (!mem_dump) { + if (!mem_dump) + { std::cout << "Press Enter to finish" << std::endl; std::cin.ignore(); } From 9bf2fc7712ab6d6db9c6c0d73ab48984d37bc3a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Wed, 14 Sep 2022 20:03:43 +0200 Subject: [PATCH 11/17] dump function for RV64 --- inc/Registers.h | 80 +---------------------- src/Registers.cpp | 162 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 79 deletions(-) diff --git a/inc/Registers.h b/inc/Registers.h index 84a4d1b..a252b5f 100644 --- a/inc/Registers.h +++ b/inc/Registers.h @@ -309,85 +309,7 @@ namespace riscv_tlm { /** * Dump register data to console */ - void dump() { - std::cout << "************************************" << std::endl; - std::cout << "Registers dump" << std::dec << std::endl; - std::cout << std::setfill('0') << std::uppercase; - std::cout << "x0 (zero): 0x" << std::right << std::setw(8) - << std::hex << register_bank[0]; - std::cout << " x1 (ra): 0x" << std::right << std::setw(8) - << std::hex << register_bank[1]; - std::cout << " x2 (sp): 0x" << std::right << std::setw(8) - << std::hex << register_bank[2]; - std::cout << " x3 (gp): 0x" << std::right << std::setw(8) - << std::hex << register_bank[3] << std::endl; - - std::cout << "x4 (tp): 0x" << std::right << std::setw(8) - << std::hex << register_bank[4]; - std::cout << " x5 (t0): 0x" << std::right << std::setw(8) - << std::hex << register_bank[5]; - std::cout << " x6 (t1): 0x" << std::right << std::setw(8) - << std::hex << register_bank[6]; - std::cout << " x7 (t2): 0x" << std::right << std::setw(8) - << std::hex << register_bank[7] << std::endl; - - std::cout << "x8 (s0/fp): 0x" << std::right << std::setw(8) - << std::hex << register_bank[8]; - std::cout << " x9 (s1): 0x" << std::right << std::setw(8) - << std::hex << register_bank[9]; - std::cout << " x10 (a0): 0x" << std::right << std::setw(8) - << std::hex << register_bank[10]; - std::cout << " x11 (a1): 0x" << std::right << std::setw(8) - << std::hex << register_bank[11] << std::endl; - - std::cout << "x12 (a2): 0x" << std::right << std::setw(8) - << std::hex << register_bank[12]; - std::cout << " x13 (a3): 0x" << std::right << std::setw(8) - << std::hex << register_bank[13]; - std::cout << " x14 (a4): 0x" << std::right << std::setw(8) - << std::hex << register_bank[14]; - std::cout << " x15 (a5): 0x" << std::right << std::setw(8) - << std::hex << register_bank[15] << std::endl; - - std::cout << "x16 (a6): 0x" << std::right << std::setw(8) - << std::hex << register_bank[16]; - std::cout << " x17 (a7): 0x" << std::right << std::setw(8) - << std::hex << register_bank[17]; - std::cout << " x18 (s2): 0x" << std::right << std::setw(8) - << std::hex << register_bank[18]; - std::cout << " x19 (s3): 0x" << std::right << std::setw(8) - << std::hex << register_bank[19] << std::endl; - - std::cout << "x20 (s4): 0x" << std::right << std::setw(8) - << std::hex << register_bank[20]; - std::cout << " x21 (s5): 0x" << std::right << std::setw(8) - << std::hex << register_bank[21]; - std::cout << " x22 (s6): 0x" << std::right << std::setw(8) - << std::hex << register_bank[22]; - std::cout << " x23 (s7): 0x" << std::right << std::setw(8) - << std::hex << register_bank[23] << std::endl; - - std::cout << "x24 (s8): 0x" << std::right << std::setw(8) - << std::hex << register_bank[24]; - std::cout << " x25 (s9): 0x" << std::right << std::setw(8) - << std::hex << register_bank[25]; - std::cout << " x26 (s10): 0x" << std::right << std::setw(8) - << std::hex << register_bank[26]; - std::cout << " x27 (s11): 0x" << std::right << std::setw(8) - << std::hex << register_bank[27] << std::endl; - - std::cout << "x28 (t3): 0x" << std::right << std::setw(8) - << std::hex << register_bank[28]; - std::cout << " x29 (t4): 0x" << std::right << std::setw(8) - << std::hex << register_bank[29]; - std::cout << " x30 (t5): 0x" << std::right << std::setw(8) - << std::hex << register_bank[30]; - std::cout << " x31 (t6): 0x" << std::right << std::setw(8) - << std::hex << register_bank[31] << std::endl; - - std::cout << "PC: 0x" << std::setw(8) << std::hex << register_PC << std::dec << std::endl; - std::cout << "************************************" << std::endl; - } + void dump() const; private: /** diff --git a/src/Registers.cpp b/src/Registers.cpp index bc58468..c30da84 100644 --- a/src/Registers.cpp +++ b/src/Registers.cpp @@ -17,10 +17,172 @@ namespace riscv_tlm { CSR[CSR_MSTATUS] = MISA_MXL; } + template<> + void Registers::dump() const { + std::cout << "************************************" << std::endl; + std::cout << "Registers dump" << std::dec << std::endl; + std::cout << std::setfill('0') << std::uppercase; + std::cout << "x0 (zero): 0x" << std::right << std::setw(8) + << std::hex << register_bank[0]; + std::cout << " x1 (ra): 0x" << std::right << std::setw(8) + << std::hex << register_bank[1]; + std::cout << " x2 (sp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[2]; + std::cout << " x3 (gp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[3] << std::endl; + + std::cout << "x4 (tp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[4]; + std::cout << " x5 (t0): 0x" << std::right << std::setw(8) + << std::hex << register_bank[5]; + std::cout << " x6 (t1): 0x" << std::right << std::setw(8) + << std::hex << register_bank[6]; + std::cout << " x7 (t2): 0x" << std::right << std::setw(8) + << std::hex << register_bank[7] << std::endl; + + std::cout << "x8 (s0/fp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[8]; + std::cout << " x9 (s1): 0x" << std::right << std::setw(8) + << std::hex << register_bank[9]; + std::cout << " x10 (a0): 0x" << std::right << std::setw(8) + << std::hex << register_bank[10]; + std::cout << " x11 (a1): 0x" << std::right << std::setw(8) + << std::hex << register_bank[11] << std::endl; + + std::cout << "x12 (a2): 0x" << std::right << std::setw(8) + << std::hex << register_bank[12]; + std::cout << " x13 (a3): 0x" << std::right << std::setw(8) + << std::hex << register_bank[13]; + std::cout << " x14 (a4): 0x" << std::right << std::setw(8) + << std::hex << register_bank[14]; + std::cout << " x15 (a5): 0x" << std::right << std::setw(8) + << std::hex << register_bank[15] << std::endl; + + std::cout << "x16 (a6): 0x" << std::right << std::setw(8) + << std::hex << register_bank[16]; + std::cout << " x17 (a7): 0x" << std::right << std::setw(8) + << std::hex << register_bank[17]; + std::cout << " x18 (s2): 0x" << std::right << std::setw(8) + << std::hex << register_bank[18]; + std::cout << " x19 (s3): 0x" << std::right << std::setw(8) + << std::hex << register_bank[19] << std::endl; + + std::cout << "x20 (s4): 0x" << std::right << std::setw(8) + << std::hex << register_bank[20]; + std::cout << " x21 (s5): 0x" << std::right << std::setw(8) + << std::hex << register_bank[21]; + std::cout << " x22 (s6): 0x" << std::right << std::setw(8) + << std::hex << register_bank[22]; + std::cout << " x23 (s7): 0x" << std::right << std::setw(8) + << std::hex << register_bank[23] << std::endl; + + std::cout << "x24 (s8): 0x" << std::right << std::setw(8) + << std::hex << register_bank[24]; + std::cout << " x25 (s9): 0x" << std::right << std::setw(8) + << std::hex << register_bank[25]; + std::cout << " x26 (s10): 0x" << std::right << std::setw(8) + << std::hex << register_bank[26]; + std::cout << " x27 (s11): 0x" << std::right << std::setw(8) + << std::hex << register_bank[27] << std::endl; + + std::cout << "x28 (t3): 0x" << std::right << std::setw(8) + << std::hex << register_bank[28]; + std::cout << " x29 (t4): 0x" << std::right << std::setw(8) + << std::hex << register_bank[29]; + std::cout << " x30 (t5): 0x" << std::right << std::setw(8) + << std::hex << register_bank[30]; + std::cout << " x31 (t6): 0x" << std::right << std::setw(8) + << std::hex << register_bank[31] << std::endl; + + std::cout << "PC: 0x" << std::setw(8) << std::hex << register_PC << std::dec << std::endl; + std::cout << "************************************" << std::endl; + } + template<> void Registers::initCSR() { CSR[CSR_MISA] = (((std::uint64_t) 0x02) << 30) | MISA_M_EXTENSION | MISA_C_EXTENSION | MISA_A_EXTENSION | MISA_I_BASE; CSR[CSR_MSTATUS] = MISA_MXL; } + + template<> + void Registers::dump() const { + std::cout << "************************************" << std::endl; + std::cout << "Registers dump" << std::dec << std::endl; + std::cout << std::setfill('0') << std::uppercase; + std::cout << "x0 (zero): 0x" << std::right << std::setw(16) + << std::hex << register_bank[0]; + std::cout << " x1 (ra): 0x" << std::right << std::setw(16) + << std::hex << register_bank[1]; + std::cout << " x2 (sp): 0x" << std::right << std::setw(16) + << std::hex << register_bank[2]; + std::cout << " x3 (gp): 0x" << std::right << std::setw(16) + << std::hex << register_bank[3] << std::endl; + + std::cout << "x4 (tp): 0x" << std::right << std::setw(16) + << std::hex << register_bank[4]; + std::cout << " x5 (t0): 0x" << std::right << std::setw(16) + << std::hex << register_bank[5]; + std::cout << " x6 (t1): 0x" << std::right << std::setw(16) + << std::hex << register_bank[6]; + std::cout << " x7 (t2): 0x" << std::right << std::setw(16) + << std::hex << register_bank[7] << std::endl; + + std::cout << "x8 (s0/fp): 0x" << std::right << std::setw(16) + << std::hex << register_bank[8]; + std::cout << " x9 (s1): 0x" << std::right << std::setw(16) + << std::hex << register_bank[9]; + std::cout << " x10 (a0): 0x" << std::right << std::setw(16) + << std::hex << register_bank[10]; + std::cout << " x11 (a1): 0x" << std::right << std::setw(16) + << std::hex << register_bank[11] << std::endl; + + std::cout << "x12 (a2): 0x" << std::right << std::setw(16) + << std::hex << register_bank[12]; + std::cout << " x13 (a3): 0x" << std::right << std::setw(16) + << std::hex << register_bank[13]; + std::cout << " x14 (a4): 0x" << std::right << std::setw(16) + << std::hex << register_bank[14]; + std::cout << " x15 (a5): 0x" << std::right << std::setw(16) + << std::hex << register_bank[15] << std::endl; + + std::cout << "x16 (a6): 0x" << std::right << std::setw(16) + << std::hex << register_bank[16]; + std::cout << " x17 (a7): 0x" << std::right << std::setw(16) + << std::hex << register_bank[17]; + std::cout << " x18 (s2): 0x" << std::right << std::setw(16) + << std::hex << register_bank[18]; + std::cout << " x19 (s3): 0x" << std::right << std::setw(16) + << std::hex << register_bank[19] << std::endl; + + std::cout << "x20 (s4): 0x" << std::right << std::setw(16) + << std::hex << register_bank[20]; + std::cout << " x21 (s5): 0x" << std::right << std::setw(16) + << std::hex << register_bank[21]; + std::cout << " x22 (s6): 0x" << std::right << std::setw(16) + << std::hex << register_bank[22]; + std::cout << " x23 (s7): 0x" << std::right << std::setw(16) + << std::hex << register_bank[23] << std::endl; + + std::cout << "x24 (s8): 0x" << std::right << std::setw(16) + << std::hex << register_bank[24]; + std::cout << " x25 (s9): 0x" << std::right << std::setw(16) + << std::hex << register_bank[25]; + std::cout << " x26 (s10): 0x" << std::right << std::setw(16) + << std::hex << register_bank[26]; + std::cout << " x27 (s11): 0x" << std::right << std::setw(16) + << std::hex << register_bank[27] << std::endl; + + std::cout << "x28 (t3): 0x" << std::right << std::setw(16) + << std::hex << register_bank[28]; + std::cout << " x29 (t4): 0x" << std::right << std::setw(16) + << std::hex << register_bank[29]; + std::cout << " x30 (t5): 0x" << std::right << std::setw(16) + << std::hex << register_bank[30]; + std::cout << " x31 (t6): 0x" << std::right << std::setw(16) + << std::hex << register_bank[31] << std::endl; + + std::cout << "PC: 0x" << std::setw(16) << std::hex << register_PC << std::dec << std::endl; + std::cout << "************************************" << std::endl; + } } \ No newline at end of file From 9176dbb2ed211e92ab29c0c184648b9fc2d471e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Wed, 14 Sep 2022 20:04:17 +0200 Subject: [PATCH 12/17] stop simulation in case of transaction error --- src/MemoryInterface.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/MemoryInterface.cpp b/src/MemoryInterface.cpp index 46a6c29..0fdbf7f 100644 --- a/src/MemoryInterface.cpp +++ b/src/MemoryInterface.cpp @@ -7,6 +7,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "MemoryInterface.h" +#include +#include namespace riscv_tlm { @@ -36,8 +38,11 @@ namespace riscv_tlm { data_bus->b_transport(trans, delay); if (trans.is_response_error()) { - SC_REPORT_ERROR("Memory", "Read memory"); + std::stringstream error_msg; + error_msg << "Read memory: 0x" << std::hex << addr; + SC_REPORT_ERROR("Memory", error_msg.str().c_str()); } + return data; } @@ -62,5 +67,11 @@ namespace riscv_tlm { trans.set_address(addr); data_bus->b_transport(trans, delay); + + if (trans.is_response_error()) { + std::stringstream error_msg; + error_msg << "Write memory: 0x" << std::hex << addr; + SC_REPORT_ERROR("Memory", error_msg.str().c_str()); + } } } \ No newline at end of file From ab2d5139c2c9cbb3d4c388d478e1630635560b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Thu, 15 Sep 2022 12:48:22 +0200 Subject: [PATCH 13/17] Add full RV64 simulation. It passes almost all tests. --- inc/BASE_ISA.h | 623 ++++++++++++++++++++++++++++++++----------- inc/C_extension.h | 561 ++++++++++++++++++++++++++++---------- inc/extension_base.h | 5 + src/BASE_ISA.cpp | 314 +++++++++++++++++++++- 4 files changed, 1211 insertions(+), 292 deletions(-) diff --git a/inc/BASE_ISA.h b/inc/BASE_ISA.h index 3e96301..a246175 100644 --- a/inc/BASE_ISA.h +++ b/inc/BASE_ISA.h @@ -88,6 +88,20 @@ namespace riscv_tlm { OP_WFI, OP_SFENCE, + /* RV64 */ + OP_LWU, + OP_LD, + OP_SD, + OP_ADDIW, + OP_SLLIW, + OP_SRLIW, + OP_SRAIW, + OP_ADDW, + OP_SUBW, + OP_SLLW, + OP_SRLW, + OP_SRAW, + OP_ERROR } opCodes; @@ -111,11 +125,14 @@ namespace riscv_tlm { LW_F = 0b010, LBU_F = 0b100, LHU_F = 0b101, + LWU_F = 0b110, + LD_F = 0b011, SB = 0b0100011, SB_F = 0b000, SH_F = 0b001, SW_F = 0b010, + SD_F = 0b011, ADDI = 0b0010011, ADDI_F = 0b000, @@ -126,8 +143,8 @@ namespace riscv_tlm { ANDI_F = 0b111, SLLI_F = 0b001, SRLI_F = 0b101, - SRLI_F7 = 0b0000000, - SRAI_F7 = 0b0100000, + SRLI_F7 = 0b000000, + SRAI_F7 = 0b010000, ADD = 0b0110011, ADD_F = 0b000, @@ -163,6 +180,21 @@ namespace riscv_tlm { CSRRWI = 0b101, CSRRSI = 0b110, CSRRCI = 0b111, + + ADDIW = 0b0011011, + ADDIW_F = 0b000, + SLLIW_F = 0b001, + SRLIW_F = 0b101, + SRLIW_F7 = 0b000000, + SRAIW_F7 = 0b010000, + ADDW = 0b0111011, + ADDW_F = 0b000, + ADDW_F7 = 0b000000, + SUBW_F7 = 0b010000, + SLLW = 0b001, + SRLW = 0b101, + SRLW_F7 = 0b000000, + SRAW_F7 = 0b010000, }; /** @@ -191,10 +223,16 @@ namespace riscv_tlm { * @brief Access to funct7 field * @return funct7 field */ - inline std::int32_t get_funct7() const { + inline std::uint32_t get_funct7() const { return this->m_instr.range(31, 25); } + /** + * @brief Access to funct7 field in case of RV64 SLLL, SRLI, SRAI is different + * @return funct7 field + */ + std::uint32_t get_funct7b() const; + /** * @brief Gets immediate field value for I-type * @return immediate_I field @@ -260,7 +298,7 @@ namespace riscv_tlm { unsigned_T imm; rd = this->get_rd(); - imm = get_imm_U() << 12; + imm = static_cast(get_imm_U() << 12); this->regs->setValue(rd, imm); this->logger->debug("{} ns. PC: 0x{:x}. LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), @@ -276,7 +314,7 @@ namespace riscv_tlm { unsigned_T new_pc; rd = this->get_rd(); - imm = get_imm_U() << 12; + imm = static_cast(get_imm_U() << 12); new_pc = this->regs->getPC() + imm; this->regs->setValue(rd, new_pc); @@ -290,8 +328,8 @@ namespace riscv_tlm { } bool Exec_JAL() const { - std::int32_t mem_addr; unsigned int rd; + signed_T mem_addr; unsigned_T new_pc, old_pc; rd = this->get_rd(); @@ -305,44 +343,41 @@ namespace riscv_tlm { this->regs->setValue(rd, old_pc); this->logger->debug("{} ns. PC: 0x{:x}. JAL: x{:d} <- 0x{:x}. PC + 0x{:x} -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), this->regs->getPC(), + sc_core::sc_time_stamp().value(), old_pc - 4, rd, old_pc, mem_addr, new_pc); return true; } bool Exec_JALR() { - signed_T mem_addr; + signed_T offset; unsigned int rd, rs1; unsigned_T new_pc, old_pc; rd = this->get_rd(); rs1 = this->get_rs1(); - mem_addr = get_imm_I(); - + offset = get_imm_I(); old_pc = this->regs->getPC(); - this->regs->setValue(rd, old_pc + 4); - new_pc = static_cast((this->regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); + new_pc = static_cast((this->regs->getValue(rs1) + offset) & ~1); + this->regs->setValue(rd, old_pc + 4); if ((new_pc & 0x00000003) != 0) { // not aligned - this->logger->debug("{} ns. PC: 0x{:x}. JALR: x{:d} <- 0x{:x} PC <- 0x{:x}", + this->logger->debug("{} ns. PC: 0x{:x}. JALR: x{:d} <- 0x{:x} PC <- 0x{:x} (0x{:x})", sc_core::sc_time_stamp().value(), - this->regs->getPC(), - rd, old_pc + 4, new_pc); - - this->logger->debug("{} ns. PC: 0x{:x}. JALR : Exception"); + old_pc, + rd, old_pc + 4, new_pc, offset); + this->logger->debug("{} ns. PC: 0x{:x}. JALR : Exception", + sc_core::sc_time_stamp().value(), old_pc); this->RaiseException(EXCEPTION_CAUSE_LOAD_ADDR_MISALIGN, this->m_instr); } else { this->regs->setPC(new_pc); + this->logger->debug("{} ns. PC: 0x{:x}. JALR: x{:d} <- 0x{:x}. PC <- 0x{:x}", + sc_core::sc_time_stamp().value(), + old_pc, rd, old_pc + 4, new_pc); } - this->logger->debug("{} ns. PC: 0x{:x}. JALR: x{:d} <- 0x{:x}. PC <- 0x{:x}", - sc_core::sc_time_stamp().value(), - this->regs->getPC(), - rd, old_pc + 4, new_pc); - return true; } @@ -373,13 +408,13 @@ namespace riscv_tlm { bool Exec_BNE() const { unsigned int rs1, rs2; - signed_T val1, val2; + unsigned_T val1, val2; rs1 = this->get_rs1(); rs2 = this->get_rs2(); - val1 = static_cast(this->regs->getValue(rs1)); - val2 = static_cast(this->regs->getValue(rs2)); + val1 = this->regs->getValue(rs1); + val2 = this->regs->getValue(rs2); if (val1 != val2) { unsigned_T new_pc; @@ -399,15 +434,16 @@ namespace riscv_tlm { bool Exec_BLT() const { unsigned int rs1, rs2; signed_T val1, val2; + unsigned_T new_pc, old_pc; rs1 = this->get_rs1(); rs2 = this->get_rs2(); val1 = static_cast(this->regs->getValue(rs1)); val2 = static_cast(this->regs->getValue(rs2)); + old_pc = static_cast(this->regs->getPC()); if (val1 < val2) { - unsigned_T new_pc; new_pc = static_cast(this->regs->getPC() + get_imm_B()); this->regs->setPC(new_pc); } else { @@ -415,7 +451,7 @@ namespace riscv_tlm { } this->logger->debug("{} ns. PC: 0x{:x}. BLT: x{:d}(0x{:x}) < x{:d}(0x{:x})? -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), this->regs->getPC(), + sc_core::sc_time_stamp().value(), old_pc, rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), this->regs->getPC()); return true; @@ -449,6 +485,7 @@ namespace riscv_tlm { bool Exec_BLTU() const { unsigned int rs1, rs2; unsigned_T val1, val2; + unsigned_T new_pc, old_pc; rs1 = this->get_rs1(); rs2 = this->get_rs2(); @@ -456,16 +493,17 @@ namespace riscv_tlm { val1 = this->regs->getValue(rs1); val2 = this->regs->getValue(rs2); + old_pc = static_cast(this->regs->getPC()); + if (val1 < val2) { - unsigned_T new_pc; - new_pc = static_cast(this->regs->getPC() + get_imm_B()); + new_pc = static_cast(old_pc + get_imm_B()); this->regs->setPC(new_pc); } else { this->regs->incPC(); } this->logger->debug("{} ns. PC: 0x{:x}. BLTU: x{:d}(0x{:x}) < x{:d}(0x{:x})? -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), this->regs->getPC(), + sc_core::sc_time_stamp().value(), old_pc, rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), this->regs->getPC()); return true; @@ -499,7 +537,7 @@ namespace riscv_tlm { bool Exec_LB() const { unsigned_T mem_addr; unsigned int rd, rs1; - std::int32_t imm; + signed_T imm; std::int8_t data; rd = this->get_rd(); @@ -522,15 +560,15 @@ namespace riscv_tlm { bool Exec_LH() const { unsigned_T mem_addr; unsigned int rd, rs1; - std::int32_t imm; - int16_t data; + signed_T imm; + std::int16_t data; rd = this->get_rd(); rs1 = this->get_rs1(); imm = get_imm_I(); mem_addr = imm + this->regs->getValue(rs1); - data = static_cast(this->mem_intf->readDataMem(mem_addr, 2)); + data = static_cast(this->mem_intf->readDataMem(mem_addr, 2)); this->perf->dataMemoryRead(); this->regs->setValue(rd, data); @@ -545,17 +583,18 @@ namespace riscv_tlm { bool Exec_LW() const { unsigned_T mem_addr; unsigned int rd, rs1; - std::int32_t imm; - std::uint32_t data; + signed_T imm; + std::int32_t data; rd = this->get_rd(); rs1 = this->get_rs1(); imm = get_imm_I(); mem_addr = imm + this->regs->getValue(rs1); - data = this->mem_intf->readDataMem(mem_addr, 4); + data = static_cast(this->mem_intf->readDataMem(mem_addr, 4)); + this->perf->dataMemoryRead(); - this->regs->setValue(rd, static_cast(data)); + this->regs->setValue(rd, data); this->logger->debug("{} ns. PC: 0x{:x}. LW: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), @@ -568,7 +607,7 @@ namespace riscv_tlm { bool Exec_LBU() const { unsigned_T mem_addr; unsigned int rd, rs1; - std::int32_t imm; + signed_T imm; std::uint8_t data; rd = this->get_rd(); @@ -576,9 +615,10 @@ namespace riscv_tlm { imm = get_imm_I(); mem_addr = imm + this->regs->getValue(rs1); - data = this->mem_intf->readDataMem(mem_addr, 1); + data = static_cast(this->mem_intf->readDataMem(mem_addr, 1)); + this->perf->dataMemoryRead(); - this->regs->setValue(rd, static_cast(data)); + this->regs->setValue(rd, data); this->logger->debug("{} ns. PC: 0x{:x}. LBU: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), @@ -591,17 +631,17 @@ namespace riscv_tlm { bool Exec_LHU() const { unsigned_T mem_addr; unsigned int rd, rs1; - std::int32_t imm; - uint16_t data; + signed_T imm; + std::uint16_t data; rd = this->get_rd(); rs1 = this->get_rs1(); imm = get_imm_I(); mem_addr = imm + this->regs->getValue(rs1); - data = this->mem_intf->readDataMem(mem_addr, 2); - this->perf->dataMemoryRead(); + data = static_cast(this->mem_intf->readDataMem(mem_addr, 2)); + this->perf->dataMemoryRead(); this->regs->setValue(rd, data); this->logger->debug("{} ns. PC: 0x{:x}. LHU: x{:d} + x{:d}(0x{:x}) -> x{:d}", @@ -612,10 +652,90 @@ namespace riscv_tlm { return true; } + bool Exec_LWU() const { + unsigned_T mem_addr; + unsigned int rd, rs1; + signed_T imm; + std::uint32_t data; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + + this->perf->dataMemoryRead(); + this->regs->setValue(rd, data); + + this->logger->debug("{} ns. PC: 0x{:x}. LWU: x{:d} + x{:d}(0x{:x}) -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, mem_addr, rd); + + return true; + } + + bool Exec_LD() const { + unsigned_T mem_addr; + unsigned int rd, rs1; + signed_T imm; + signed_T offset; + + std::uint64_t data; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + offset = this->regs->getValue(rs1); + mem_addr = imm + offset; + + data = static_cast(this->mem_intf->readDataMem(mem_addr, 4)); + std::uint64_t aux = static_cast(this->mem_intf->readDataMem(mem_addr + 4, 4)); + data |= aux << 32; + + this->perf->dataMemoryRead(); + this->regs->setValue(rd, data); + + this->logger->debug("{} ns. PC: 0x{:x}. LD: 0x{:x}({:d}) + {:d}(0x{:x}) -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, offset, imm, mem_addr, rd, data); + return true; + } + + + bool Exec_SD() const { + unsigned_T mem_addr; + unsigned int rs1, rs2; + signed_T imm; + std::uint64_t data; + + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + imm = get_imm_S(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->regs->getValue(rs2); + + this->logger->debug("{} ns. PC: 0x{:x}. SD: 0x{:x} -> x{:d} + 0x{:x}(@0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs2, rs1, imm, mem_addr); + + this->mem_intf->writeDataMem(mem_addr, data & 0xFFFFFFFF, 4); + this->mem_intf->writeDataMem(mem_addr + 4, data >> 32, 4); + this->perf->dataMemoryWrite(); + + return true; + } + + bool Exec_SB() const { unsigned_T mem_addr; unsigned int rs1, rs2; - std::int32_t imm; + signed_T imm; std::uint32_t data; rs1 = this->get_rs1(); @@ -636,10 +756,11 @@ namespace riscv_tlm { return true; } + bool Exec_SH() const { unsigned_T mem_addr; unsigned int rs1, rs2; - std::int32_t imm; + signed_T imm; std::uint32_t data; rs1 = this->get_rs1(); @@ -660,10 +781,11 @@ namespace riscv_tlm { return true; } + bool Exec_SW() const { unsigned_T mem_addr; unsigned int rs1, rs2; - std::int32_t imm; + signed_T imm; std::uint32_t data; rs1 = this->get_rs1(); @@ -686,17 +808,41 @@ namespace riscv_tlm { bool Exec_ADDI() const { unsigned int rd, rs1; - std::int32_t imm; - signed_T calc; + signed_T imm; + unsigned_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); imm = get_imm_I(); - calc = static_cast(this->regs->getValue(rs1)) + imm; + calc = this->regs->getValue(rs1) + imm; + this->regs->setValue(rd, calc); - this->logger->debug("{} ns. PC: 0x{:x}. ADDI: x{:d} + x{:d} -> x{:d}(0x{:x})", + this->logger->debug("{} ns. PC: 0x{:x}. ADDI: x{:d}(0x{:x}) + {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, this->regs->getValue(rs1), imm, rd, calc); + + return true; + } + + bool Exec_ADDIW() const { + unsigned int rd, rs1; + std::int32_t imm; + std::int32_t aux; + std::int64_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + aux = static_cast(this->regs->getValue(rs1) & 0xFFFFFFFF); + aux = static_cast(aux + imm); + calc = static_cast(aux); + + this->regs->setValue(rd, calc); + this->logger->debug("{} ns. PC: 0x{:x}. ADDIW: x{:d} + {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), this->regs->getPC(), rs1, imm, rd, calc); @@ -706,7 +852,7 @@ namespace riscv_tlm { bool Exec_SLTI() const { unsigned int rd, rs1; - std::int32_t imm; + signed_T imm; signed_T val1; rd = this->get_rd(); @@ -761,7 +907,7 @@ namespace riscv_tlm { bool Exec_XORI() const { unsigned int rd, rs1; - unsigned_T imm; + signed_T imm; unsigned_T calc; rd = this->get_rd(); @@ -780,7 +926,7 @@ namespace riscv_tlm { bool Exec_ORI() const { unsigned int rd, rs1; - unsigned_T imm; + signed_T imm; unsigned_T calc; rd = this->get_rd(); @@ -799,7 +945,7 @@ namespace riscv_tlm { bool Exec_ANDI() const { unsigned int rd, rs1; - unsigned_T imm; + signed_T imm; unsigned_T calc; rd = this->get_rd(); @@ -817,7 +963,17 @@ namespace riscv_tlm { return true; } - bool Exec_SLLI() { + + bool Exec_SLLI(); + + + bool Exec_SRLI() const; + + + bool Exec_SRAI() const; + + + bool Exec_SLLIW() { unsigned int rd, rs1, rs2; unsigned_T shift; unsigned_T calc; @@ -827,7 +983,8 @@ namespace riscv_tlm { rs2 = get_shamt(); if (rs2 >= 0x20) { - std::cout << "ILEGAL INSTRUCTION, shamt[5] != 0" << "\n"; + std::cout << "ILLEGAL INSTRUCTION, shamt[5] != 0" << "\n"; + sc_core::sc_stop(); this->RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, this->m_instr); return false; @@ -835,10 +992,10 @@ namespace riscv_tlm { shift = rs2 & 0x1F; - calc = static_cast(this->regs->getValue(rs1)) << shift; + calc = static_cast(static_cast(this->regs->getValue(rs1)) << shift); this->regs->setValue(rd, calc); - this->logger->debug("{} ns. PC: 0x{:x}. SLLI: x{:d} << {:d} -> x{:d}(0x{:x})", + this->logger->debug("{} ns. PC: 0x{:x}. SLLIW: x{:d} << {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), this->regs->getPC(), rs1, shift, rd, calc); @@ -846,7 +1003,100 @@ namespace riscv_tlm { return true; } - bool Exec_SRLI() const { + + bool Exec_SRLIW() { + unsigned int rd, rs1, rs2; + unsigned_T shift; + unsigned_T calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = get_shamt(); + + if (rs2 >= 0x20) { + std::cout << "ILLEGAL INSTRUCTION, shamt[5] != 0" << "\n"; + sc_core::sc_stop(); + this->RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, this->m_instr); + + return false; + } + + shift = rs2 & 0x1F; + + calc = static_cast(static_cast(this->regs->getValue(rs1) & 0xFFFFFFFF) >> shift); + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SRLIW: x{:d} << {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + + bool Exec_SRAIW() const { + unsigned int rd, rs1, rs2; + unsigned_T shift; + signed_T calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_shamt_slli(); + + shift = rs2 & 0x1F; + + calc = static_cast(static_cast(this->regs->getValue(rs1)) >> shift); + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SRAIW: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + bool Exec_ADDW() const { + unsigned int rd, rs1, rs2; + unsigned_T calc; + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + calc = static_cast((this->regs->getValue(rs1) + this->regs->getValue(rs2)) & 0xFFFFFFFF); + + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. ADDW: x{:d} + x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); + + return true; + } + + bool Exec_SUBW() const { + unsigned int rd, rs1, rs2; + unsigned_T calc; + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + calc = static_cast((this->regs->getValue(rs1) - this->regs->getValue(rs2)) & 0xFFFFFFFF); + + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SUBW: x{:d} + x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); + + return true; + } + + + bool Exec_SLLW() const { unsigned int rd, rs1, rs2; unsigned_T shift; unsigned_T calc; @@ -855,12 +1105,12 @@ namespace riscv_tlm { rs1 = this->get_rs1(); rs2 = this->get_rs2(); - shift = rs2 & 0x1F; + shift = this->regs->getValue(rs2) & 0x1F; + calc = static_cast(this->regs->getValue(rs1) & 0xFFFFFFFF) << shift; - calc = static_cast(this->regs->getValue(rs1)) >> shift; this->regs->setValue(rd, calc); - this->logger->debug("{} ns. PC: 0x{:x}. SRLI: x{:d} >> {:d} -> x{:d}(0x{:x})", + this->logger->debug("{} ns. PC: 0x{:x}. SLLW: x{:d} << x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), this->regs->getPC(), rs1, shift, rd, calc); @@ -868,7 +1118,31 @@ namespace riscv_tlm { return true; } - bool Exec_SRAI() const { + + bool Exec_SRLW() const { + unsigned int rd, rs1, rs2; + unsigned_T shift; + unsigned_T calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = this->regs->getValue(rs2) & 0x1F; + calc = static_cast(static_cast(this->regs->getValue(rs1) & 0xFFFFFFFF) >> shift); + + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SRLW: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + + bool Exec_SRAW() const { unsigned int rd, rs1, rs2; unsigned_T shift; signed_T calc; @@ -877,12 +1151,12 @@ namespace riscv_tlm { rs1 = this->get_rs1(); rs2 = this->get_rs2(); - shift = rs2 & 0x1F; + shift = this->regs->getValue(rs2) & 0x1F; + calc = static_cast(this->regs->getValue(rs1) & 0xFFFFFFFF) >> shift; - calc = static_cast(this->regs->getValue(rs1)) >> shift; this->regs->setValue(rd, calc); - this->logger->debug("{} ns. PC: 0x{:x}. SRAI: x{:d} >> {:d} -> x{:d}(0x{:x})", + this->logger->debug("{} ns. PC: 0x{:x}. SRAW: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), this->regs->getPC(), rs1, shift, rd, calc); @@ -892,12 +1166,12 @@ namespace riscv_tlm { bool Exec_ADD() const { unsigned int rd, rs1, rs2; - unsigned_T calc; + signed_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); - calc = this->regs->getValue(rs1) + this->regs->getValue(rs2); + calc = static_cast(this->regs->getValue(rs1)) + static_cast(this->regs->getValue(rs2)); this->regs->setValue(rd, calc); @@ -911,12 +1185,12 @@ namespace riscv_tlm { bool Exec_SUB() const { unsigned int rd, rs1, rs2; - unsigned_T calc; + signed_T calc; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); - calc = this->regs->getValue(rs1) - this->regs->getValue(rs2); + calc = static_cast(this->regs->getValue(rs1)) - static_cast(this->regs->getValue(rs2)); this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. SUB: x{:d} - x{:d} -> x{:d}(0x{:x})", @@ -927,27 +1201,8 @@ namespace riscv_tlm { return true; } - bool Exec_SLL() const { - unsigned int rd, rs1, rs2; - unsigned_T shift; - unsigned_T calc; - rd = this->get_rd(); - rs1 = this->get_rs1(); - rs2 = this->get_rs2(); - - shift = this->regs->getValue(rs2) & 0x1F; - - calc = this->regs->getValue(rs1) << shift; - this->regs->setValue(rd, calc); - - this->logger->debug("{} ns. PC: 0x{:x}. SLL: x{:d} << x{:d} -> x{:d}(0x{:x})", - sc_core::sc_time_stamp().value(), - this->regs->getPC(), - rs1, shift, rd, calc); - - return true; - } + bool Exec_SLL() const; bool Exec_SLT() const { unsigned int rd, rs1, rs2; @@ -1024,48 +1279,11 @@ namespace riscv_tlm { return true; } - bool Exec_SRL() const { - unsigned int rd, rs1, rs2; - unsigned_T shift; - unsigned_T calc; - rd = this->get_rd(); - rs1 = this->get_rs1(); - rs2 = this->get_rs2(); + bool Exec_SRL() const; - shift = this->regs->getValue(rs2) & 0x1F; - calc = this->regs->getValue(rs1) >> shift; - this->regs->setValue(rd, calc); - - this->logger->debug("{} ns. PC: 0x{:x}. SRL: x{:d} >> {:d} -> x{:d}(0x{:x})", - sc_core::sc_time_stamp().value(), - this->regs->getPC(), - rs1, shift, rd, calc); - - return true; - } - - bool Exec_SRA() const { - unsigned int rd, rs1, rs2; - unsigned_T shift; - signed_T calc; - - rd = this->get_rd(); - rs1 = this->get_rs1(); - rs2 = this->get_rs2(); - - shift = this->regs->getValue(rs2) & 0x1F; - calc = static_cast(this->regs->getValue(rs1)) >> shift; - this->regs->setValue(rd, calc); - - this->logger->debug("{} ns. PC: 0x{:x}. SRA: x{:d} >> {:d} -> x{:d}(0x{:x})", - sc_core::sc_time_stamp().value(), - this->regs->getPC(), - rs1, shift, rd, calc); - - return true; - } + bool Exec_SRA() const; bool Exec_OR() const { unsigned int rd, rs1, rs2; @@ -1132,6 +1350,7 @@ namespace riscv_tlm { sc_core::sc_stop(); #else this->RaiseException(11, this->m_instr); + sc_core::sc_stop(); #endif return true; } @@ -1153,7 +1372,7 @@ namespace riscv_tlm { bool Exec_CSRRW() const { unsigned int rd, rs1; int csr; - std::uint32_t aux; + unsigned_T aux; rd = this->get_rd(); rs1 = this->get_rs1(); @@ -1162,7 +1381,7 @@ namespace riscv_tlm { /* These operations must be atomical */ if (rd != 0) { aux = this->regs->getCSR(csr); - this->regs->setValue(rd, static_cast(aux)); + this->regs->setValue(rd, aux); } aux = this->regs->getValue(rs1); @@ -1179,14 +1398,15 @@ namespace riscv_tlm { bool Exec_CSRRS() const { unsigned int rd, rs1; int csr; - std::uint32_t bitmask, aux, aux2; + unsigned_T bitmask, aux, aux2; rd = this->get_rd(); rs1 = this->get_rs1(); csr = get_csr(); if (rd == 0) { - this->logger->debug("{} ns. PC: 0x{:x}. CSRRS with rd1 == 0, doing nothing."); + this->logger->debug("{} ns. PC: 0x{:x}. CSRRS with rd1 == 0, doing nothing.", + sc_core::sc_time_stamp().value(), this->regs->getPC()); return false; } @@ -1194,7 +1414,7 @@ namespace riscv_tlm { aux = this->regs->getCSR(csr); bitmask = this->regs->getValue(rs1); - this->regs->setValue(rd, static_cast(aux)); + this->regs->setValue(rd, aux); aux2 = aux | bitmask; this->regs->setCSR(csr, aux2); @@ -1209,14 +1429,15 @@ namespace riscv_tlm { bool Exec_CSRRC() const { unsigned int rd, rs1; int csr; - std::uint32_t bitmask, aux, aux2; + unsigned_T bitmask, aux, aux2; rd = this->get_rd(); rs1 = this->get_rs1(); csr = get_csr(); if (rd == 0) { - this->logger->debug("{} ns. PC: 0x{:x}. CSRRC with rd1 == 0, doing nothing."); + this->logger->debug("{} ns. PC: 0x{:x}. CSRRC with rd1 == 0, doing nothing.", + sc_core::sc_time_stamp().value(), this->regs->getPC()); return true; } @@ -1224,7 +1445,7 @@ namespace riscv_tlm { aux = this->regs->getCSR(csr); bitmask = this->regs->getValue(rs1); - this->regs->setValue(rd, static_cast(aux)); + this->regs->setValue(rd, aux); aux2 = aux & ~bitmask; this->regs->setCSR(csr, aux2); @@ -1239,7 +1460,7 @@ namespace riscv_tlm { bool Exec_CSRRWI() const { unsigned int rd, rs1; int csr; - std::uint32_t aux; + unsigned_T aux; rd = this->get_rd(); rs1 = this->get_rs1(); @@ -1248,7 +1469,7 @@ namespace riscv_tlm { /* These operations must be atomical */ if (rd != 0) { aux = this->regs->getCSR(csr); - this->regs->setValue(rd, static_cast(aux)); + this->regs->setValue(rd, aux); } aux = rs1; this->regs->setCSR(csr, aux); @@ -1263,7 +1484,7 @@ namespace riscv_tlm { bool Exec_CSRRSI() const { unsigned int rd, rs1; int csr; - std::uint32_t bitmask, aux; + unsigned_T bitmask, aux; rd = this->get_rd(); rs1 = this->get_rs1(); @@ -1275,7 +1496,7 @@ namespace riscv_tlm { /* These operations must be atomical */ aux = this->regs->getCSR(csr); - this->regs->setValue(rd, static_cast(aux)); + this->regs->setValue(rd, aux); bitmask = rs1; aux = aux | bitmask; @@ -1291,7 +1512,7 @@ namespace riscv_tlm { bool Exec_CSRRCI() const { unsigned rd, rs1; int csr; - std::uint32_t bitmask, aux; + unsigned_T bitmask, aux; rd = this->get_rd(); rs1 = this->get_rs1(); @@ -1303,7 +1524,7 @@ namespace riscv_tlm { /* These operations must be atomical */ aux = this->regs->getCSR(csr); - this->regs->setValue(rd, static_cast(aux)); + this->regs->setValue(rd, aux); bitmask = rs1; aux = aux & ~bitmask; @@ -1319,7 +1540,7 @@ namespace riscv_tlm { /*********************** Privileged Instructions ******************************/ bool Exec_MRET() const { - std::uint32_t new_pc = 0; + unsigned_T new_pc = 0; new_pc = this->regs->getCSR(CSR_MEPC); this->regs->setPC(new_pc); @@ -1328,7 +1549,7 @@ namespace riscv_tlm { this->regs->getPC(), new_pc); // update mstatus - std::uint32_t csr_temp; + unsigned_T csr_temp; csr_temp = this->regs->getCSR(CSR_MSTATUS); if (csr_temp & MSTATUS_MPIE) { csr_temp |= MSTATUS_MIE; @@ -1340,7 +1561,7 @@ namespace riscv_tlm { } bool Exec_SRET() const { - std::uint32_t new_pc = 0; + unsigned_T new_pc = 0; new_pc = this->regs->getCSR(CSR_SEPC); this->regs->setPC(new_pc); @@ -1425,6 +1646,12 @@ namespace riscv_tlm { case OP_LHU: Exec_LHU(); break; + case OP_LWU: + Exec_LWU(); + break; + case OP_LD: + Exec_LD(); + break; case OP_SB: Exec_SB(); break; @@ -1434,6 +1661,9 @@ namespace riscv_tlm { case OP_SW: Exec_SW(); break; + case OP_SD: + Exec_SD(); + break; case OP_ADDI: Exec_ADDI(); break; @@ -1535,7 +1765,34 @@ namespace riscv_tlm { case OP_SFENCE: Exec_SFENCE(); break; - [[unlikely]] default: + case OP_ADDIW: + Exec_ADDIW(); + break; + case OP_SLLIW: + Exec_SLLIW(); + break; + case OP_SRLIW: + Exec_SRLIW(); + break; + case OP_SRAIW: + Exec_SRAIW(); + break; + case OP_ADDW: + Exec_ADDW(); + break; + case OP_SUBW: + Exec_SUBW(); + break; + case OP_SLLW: + Exec_SLLW(); + break; + case OP_SRLW: + Exec_SRLW(); + break; + case OP_SRAW: + Exec_SRAW(); + break; + [[unlikely]] default: std::cout << "Wrong instruction" << "\n"; inst.dump(); this->NOP(); @@ -1588,6 +1845,10 @@ namespace riscv_tlm { return OP_LBU; case LHU_F: return OP_LHU; + case LWU_F: + return OP_LWU; + case LD_F: + return OP_LD; } return OP_ERROR; case SB: @@ -1598,6 +1859,8 @@ namespace riscv_tlm { return OP_SH; case SW_F: return OP_SW; + case SD_F: + return OP_SD; } return OP_ERROR; case ADDI: @@ -1617,7 +1880,9 @@ namespace riscv_tlm { case SLLI_F: return OP_SLLI; case SRLI_F: - switch (this->get_funct7()) { + // TODO: Why funct7b is not working? + //switch (this->get_funct7b()) { + switch(this->m_instr.to_uint() >> 26) { case SRLI_F7: return OP_SRLI; case SRAI_F7: @@ -1709,6 +1974,64 @@ namespace riscv_tlm { } } break; + case ADDIW: + switch (this->get_funct3()) { + case ADDIW_F: + return OP_ADDIW; + break; + case SLLIW_F: + return OP_SLLIW; + break; + case SRLIW_F: + switch (this->m_instr.to_uint() >> 26) { + case SRLIW_F7: + return OP_SRLIW; + break; + case SRAIW_F7: + return OP_SRAIW; + break; + default: + return OP_ERROR; + } + break; + default: + return OP_ERROR; + } + break; + case ADDW: + switch (this->get_funct3()) { + case ADDW_F: + switch (this->m_instr.to_uint() >> 26) { + case ADDW_F7: + return OP_ADDW; + break; + case SUBW_F7: + return OP_SUBW; + break; + default: + return OP_ERROR; + break; + } + break; + case SLLW: + return OP_SLLW; + break; + case SRLW: + switch (this->m_instr.to_uint() >> 26) { + case SRLW_F7: + return OP_SRLW; + break; + case SRAW_F7: + return OP_SRAW; + break; + default: + return OP_ERROR; + break; + } + default: + return OP_ERROR; + } + default: return OP_ERROR; } diff --git a/inc/C_extension.h b/inc/C_extension.h index 0b02515..331e7d0 100644 --- a/inc/C_extension.h +++ b/inc/C_extension.h @@ -19,13 +19,16 @@ namespace riscv_tlm { OP_C_FLD, OP_C_LW, OP_C_FLW, + OP_C_LD, OP_C_FSD, OP_C_SW, OP_C_FSW, + OP_C_SD, OP_C_NOP, OP_C_ADDI, OP_C_JAL, + OP_C_ADDIW, OP_C_LI, OP_C_ADDI16SP, OP_C_LUI, @@ -33,7 +36,9 @@ namespace riscv_tlm { OP_C_SRAI, OP_C_ANDI, OP_C_SUB, + OP_C_SUBW, OP_C_XOR, + OP_C_ADDW, OP_C_OR, OP_C_AND, OP_C_J, @@ -44,6 +49,7 @@ namespace riscv_tlm { OP_C_FLDSP, OP_C_LWSP, OP_C_FLWSP, + OP_C_LDSP, OP_C_JR, OP_C_MV, OP_C_EBREAK, @@ -52,7 +58,7 @@ namespace riscv_tlm { OP_C_FSDSP, OP_C_SWSP, OP_C_FSWSP, - + OP_C_SDSP, OP_C_ERROR } op_C_Codes; @@ -197,7 +203,7 @@ namespace riscv_tlm { return aux; } - inline void set_imm_S(std::uint32_t value) { + inline void set_imm_S(std::uint32_t value) const { sc_dt::sc_uint<32> aux = value; this->m_instr.range(31, 25) = aux.range(11, 5); @@ -212,7 +218,7 @@ namespace riscv_tlm { return static_cast(this->m_instr.range(31, 12)); } - inline void set_imm_U(std::uint32_t value) { + inline void set_imm_U(std::uint32_t value) const { this->m_instr.range(31, 12) = (value << 12); } @@ -235,7 +241,7 @@ namespace riscv_tlm { return aux; } - inline void set_imm_B(std::uint32_t value) { + inline void set_imm_B(std::uint32_t value) const { sc_dt::sc_uint<32> aux = value; this->m_instr[31] = aux[12]; @@ -268,7 +274,7 @@ namespace riscv_tlm { return aux; } - inline void set_imm_J(std::uint32_t value) { + inline void set_imm_J(std::uint32_t value) const { sc_dt::sc_uint<32> aux = (value << 20); this->m_instr[31] = aux[20]; @@ -277,12 +283,12 @@ namespace riscv_tlm { this->m_instr.range(19, 12) = aux.range(19, 12); } - [[nodiscard]] inline std::int32_t get_imm_L() const { - std::int32_t aux = 0; + [[nodiscard]] inline std::uint32_t get_imm_L() const { + std::uint32_t aux = 0; - aux = static_cast(this->m_instr.range(12, 10) << 3); - aux |= static_cast(this->m_instr[6] << 2); - aux |= static_cast(this->m_instr[5] << 6); + aux = this->m_instr.range(12, 10) << 3; + aux |= this->m_instr[6] << 2; + aux |= this->m_instr[5] << 6; return aux; } @@ -290,14 +296,24 @@ namespace riscv_tlm { [[nodiscard]] inline std::uint32_t get_imm_LWSP() const { std::uint32_t aux = 0; - aux = static_cast(this->m_instr[12] << 5); - aux |= static_cast(this->m_instr.range(6, 4) << 2); - aux |= static_cast(this->m_instr.range(3, 2) << 6); + aux = this->m_instr[12] << 5; + aux |= this->m_instr.range(6, 4) << 2; + aux |= this->m_instr.range(3, 2) << 6; return aux; } - [[nodiscard]] inline std::uint32_t get_imm_ADDI() const { + [[nodiscard]] inline std::uint32_t get_imm_LDSP() const { + std::uint32_t aux = 0; + + aux = static_cast(this->m_instr[12] << 5); + aux |= static_cast(this->m_instr.range(6, 5) << 3); + aux |= static_cast(this->m_instr.range(4, 2) << 6); + + return aux; + } + + [[nodiscard]] inline std::int32_t get_imm_ADDI() const { std::uint32_t aux = 0; aux = static_cast(this->m_instr[12] << 5); @@ -306,7 +322,7 @@ namespace riscv_tlm { if (this->m_instr[12] == 1) { aux |= 0b11111111111111111111111111 << 6; } - return aux; + return static_cast(aux); } [[nodiscard]] inline std::uint32_t get_imm_ADDI4SPN() const { @@ -320,7 +336,7 @@ namespace riscv_tlm { return aux; } - [[nodiscard]] inline std::uint32_t get_imm_ADDI16SP() const { + [[nodiscard]] inline std::int32_t get_imm_ADDI16SP() const { std::uint32_t aux = 0; aux = static_cast(this->m_instr[12] << 9); @@ -344,6 +360,14 @@ namespace riscv_tlm { return aux; } + [[nodiscard]] inline std::uint32_t get_imm_CSDSP() const { + std::uint32_t aux = 0; + aux = static_cast(this->m_instr.range(12, 10) << 3); + aux |= static_cast(this->m_instr.range(9, 7) << 6); + + return aux; + } + [[nodiscard]] inline std::uint32_t get_imm_CB() const { std::uint32_t aux = 0; @@ -363,11 +387,20 @@ namespace riscv_tlm { return aux; } - [[nodiscard]] inline std::uint32_t get_imm_LUI() const { + [[nodiscard]] inline std::uint32_t get_imm_CL() const { std::uint32_t aux = 0; - aux = static_cast(this->m_instr[12] << 17); - aux |= static_cast(this->m_instr.range(6, 2) << 12); + aux = this->m_instr.range(12, 10) << 3; + aux |= this->m_instr.range(6, 5) << 6; + + return aux; + } + + [[nodiscard]] inline std::int32_t get_imm_LUI() const { + std::int32_t aux = 0; + + aux = this->m_instr[12] << 17; + aux |= this->m_instr.range(6, 2) << 12; if (this->m_instr[12] == 1) { aux |= 0b111111111111111 << 17; @@ -400,7 +433,13 @@ namespace riscv_tlm { return OP_C_LW; break; case C_FLW: - return OP_C_FLW; + if (sizeof(signed_T) == 4) { + // RV32 + return OP_C_FLW; + } else { + // RV64 + return OP_C_LD; + } break; case C_FSD: return OP_C_FSD; @@ -409,7 +448,11 @@ namespace riscv_tlm { return OP_C_SW; break; case C_FSW: - return OP_C_FSW; + if (sizeof(signed_T) == 4) { + return OP_C_FSW; + } else { + return OP_C_SD; + } break; [[unlikely]] default: return OP_C_ERROR; @@ -423,7 +466,11 @@ namespace riscv_tlm { return OP_C_ADDI; break; case C_JAL: - return OP_C_JAL; + if (sizeof(signed_T) == 4) { + return OP_C_JAL; + } else { + return OP_C_ADDIW; + } break; case C_LI: return OP_C_LI; @@ -445,10 +492,18 @@ namespace riscv_tlm { case C_2_SUB: switch (this->m_instr.range(6, 5)) { case C_3_SUB: - return OP_C_SUB; + if (this->m_instr[12] == 0) { + return OP_C_SUB; + } else { + return OP_C_SUBW; + } break; case C_3_XOR: - return OP_C_XOR; + if (this->m_instr[12] == 0) { + return OP_C_XOR; + } else { + return OP_C_ADDW; + } break; case C_3_OR: return OP_C_OR; @@ -484,7 +539,11 @@ namespace riscv_tlm { return OP_C_LWSP; break; case C_FLWSP: - return OP_C_FLWSP; + if (sizeof(signed_T) == 4) { + return OP_C_FLWSP; + } else { + return OP_C_LDSP; + } break; case C_JR: if (this->m_instr[12] == 0) { @@ -509,8 +568,11 @@ namespace riscv_tlm { return OP_C_SWSP; break; case C_FWWSP: - [[unlikely]] - return OP_C_FSWSP; + if (sizeof(signed_T) == 4) { + return OP_C_FSWSP; + } else { + return OP_C_SDSP; + } break; default: return OP_C_ERROR; @@ -526,54 +588,54 @@ namespace riscv_tlm { return OP_C_ERROR; } - bool Exec_C_JR() { + // PASS + bool Exec_C_JR() const { std::uint32_t mem_addr; unsigned int rs1; - std::uint32_t new_pc; + unsigned_T new_pc; rs1 = get_rs1(); mem_addr = 0; - new_pc = static_cast( - static_cast((this->regs->getValue(rs1)) + static_cast(mem_addr)) & + new_pc = static_cast( + static_cast((this->regs->getValue(rs1)) + static_cast(mem_addr)) & 0xFFFFFFFE); - this->logger->debug("{} ns. PC: 0x{:x}. C.JR: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), - this->regs->getPC(), new_pc); + this->logger->debug("{} ns. PC: 0x{:x}. C.JR: PC <- 0x{:x}. x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), + this->regs->getPC(), new_pc, rs1, this->regs->getValue(rs1)); this->regs->setPC(new_pc); return true; } - bool Exec_C_MV() { - unsigned int rd, rs1, rs2; - std::uint32_t calc; + bool Exec_C_MV() const { + unsigned int rd, rs2; + unsigned_T calc; rd = this->get_rd(); - rs1 = 0; rs2 = get_rs2(); - calc = this->regs->getValue(rs1) + this->regs->getValue(rs2); - this->regs->setValue(rd, static_cast(calc)); + calc = this->regs->getValue(rs2); + this->regs->setValue(rd, calc); - this->logger->debug("{} ns. PC: 0x{:x}. C.MV: x{:d}(0x{:x}) + x{:d}(0x{:x}) -> x{:d}(0x{:x})", + this->logger->debug("{} ns. PC: 0x{:x}. C.MV: x{:d}(0x{:x}) -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), this->regs->getPC(), - rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), rd, calc); + rs2, this->regs->getValue(rs2), rd, calc); return true; } - bool Exec_C_ADD() { + bool Exec_C_ADD() const { unsigned int rd, rs1, rs2; - std::uint32_t calc; + unsigned_T calc; rd = get_rs1(); rs1 = get_rs1(); rs2 = get_rs2(); calc = this->regs->getValue(rs1) + this->regs->getValue(rs2); - this->regs->setValue(rd, static_cast(calc)); + this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. C.ADD: x{:d} + x{} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), @@ -583,20 +645,21 @@ namespace riscv_tlm { return true; } - bool Exec_C_LWSP() { - std::uint32_t mem_addr; + bool Exec_C_LWSP() const { + unsigned_T mem_addr; unsigned int rd, rs1; - std::int32_t imm; - std::uint32_t data; + std::uint32_t imm; + unsigned_T data; // lw rd, offset[7:2](x2) rd = this->get_rd(); rs1 = 2; - imm = static_cast(get_imm_LWSP()); + imm = static_cast(get_imm_LWSP()); mem_addr = imm + this->regs->getValue(rs1); - data = this->mem_intf->readDataMem(mem_addr, 4); + data = static_cast(this->mem_intf->readDataMem(mem_addr, 4)); + this->perf->dataMemoryRead(); this->regs->setValue(rd, static_cast(data)); @@ -611,19 +674,19 @@ namespace riscv_tlm { bool Exec_C_ADDI4SPN() { unsigned int rd, rs1; - std::int32_t imm; - std::int32_t calc; + signed_T imm; + signed_T calc; rd = get_rdp(); rs1 = 2; - imm = static_cast(get_imm_ADDI4SPN()); + imm = static_cast(get_imm_ADDI4SPN()); if (imm == 0) { this->RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, this->m_instr); return false; } - calc = static_cast(this->regs->getValue(rs1)) + imm; + calc = static_cast(this->regs->getValue(rs1)) + imm; this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. C.ADDI4SN: x{:d} + (0x{:x}) + {:d} -> x{:d}(0x{:x})", @@ -633,19 +696,18 @@ namespace riscv_tlm { return true; } - bool Exec_C_ADDI16SP() { - // addi x2, x2, nzimm[9:4] + bool Exec_C_ADDI16SP() const { unsigned int rd; - std::int32_t imm; + signed_T imm; if (this->get_rd() == 2) { int rs1; - std::int32_t calc; + unsigned_T calc; rd = 2; rs1 = 2; - imm = static_cast(get_imm_ADDI16SP()); - calc = static_cast(this->regs->getValue(rs1)) + imm; + imm = get_imm_ADDI16SP(); + calc = this->regs->getValue(rs1) + imm; this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. C.ADDI16SP: x{:d} + {:d} -> x{:d} (0x{:x})", @@ -654,7 +716,7 @@ namespace riscv_tlm { } else { /* C.LUI OPCODE */ rd = this->get_rd(); - imm = static_cast(get_imm_LUI()); + imm = get_imm_LUI(); this->regs->setValue(rd, imm); this->logger->debug("{} ns. PC: 0x{:x}. C.LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), @@ -665,8 +727,7 @@ namespace riscv_tlm { return true; } - bool Exec_C_SWSP() { - // sw rs2, offset(x2) + bool Exec_C_SWSP() const { std::uint32_t mem_addr; unsigned int rs1, rs2; std::int32_t imm; @@ -689,61 +750,63 @@ namespace riscv_tlm { return true; } - bool Exec_C_BEQZ() { + bool Exec_C_BEQZ() const { unsigned int rs1; - std::uint32_t new_pc; - std::uint32_t val1; + unsigned_T new_pc, old_pc; + unsigned_T val1; rs1 = get_rs1p(); val1 = this->regs->getValue(rs1); + old_pc = this->regs->getPC(); if (val1 == 0) { - new_pc = static_cast(this->regs->getPC()) + get_imm_CB(); + new_pc = static_cast(this->regs->getPC()) + static_cast(get_imm_CB()); this->regs->setPC(new_pc); } else { this->regs->incPCby2(); - new_pc = static_cast(this->regs->getPC()); + new_pc = static_cast(this->regs->getPC()); } this->logger->debug("{} ns. PC: 0x{:x}. C.BEQZ: x{:d}(0x{:x}) == 0? -> PC (0xx{:d})", - sc_core::sc_time_stamp().value(), this->regs->getPC(), + sc_core::sc_time_stamp().value(), old_pc, rs1, val1, new_pc); return true; } - bool Exec_C_BNEZ() { + bool Exec_C_BNEZ() const { unsigned int rs1; - std::uint32_t new_pc; - std::uint32_t val1; + unsigned_T new_pc, old_pc; + unsigned_T val1; rs1 = get_rs1p(); val1 = this->regs->getValue(rs1); + old_pc = this->regs->getPC(); if (val1 != 0) { - new_pc = static_cast(this->regs->getPC()) + get_imm_CB(); + new_pc = static_cast(this->regs->getPC()) + static_cast(get_imm_CB()); this->regs->setPC(new_pc); } else { this->regs->incPCby2(); //PC <- PC +2 - new_pc = static_cast(this->regs->getPC()); + new_pc = static_cast(this->regs->getPC()); } - this->logger->debug("{} ns. PC: 0x{:x}. C.BNEZ: x{:d}(0x{:x}) != 0? -> PC (0xx{:d})", - sc_core::sc_time_stamp().value(), this->regs->getPC(), + this->logger->debug("{} ns. PC: 0x{:x}. C.BNEZ: x{:d}(0x{:x}) != 0? -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), old_pc, rs1, val1, new_pc); return true; } - bool Exec_C_LI() { + bool Exec_C_LI() const { unsigned int rd, rs1; std::int32_t imm; - std::int32_t calc; + unsigned_T calc; rd = this->get_rd(); rs1 = 0; imm = static_cast(get_imm_ADDI()); - calc = static_cast(this->regs->getValue(rs1)) + imm; + calc = this->regs->getValue(rs1) + imm; this->regs->setValue(rd, calc); @@ -754,19 +817,19 @@ namespace riscv_tlm { return true; } - bool Exec_C_SRLI() { + bool Exec_C_SRLI() const { unsigned int rd, rs1, rs2; std::uint32_t shift; - std::uint32_t calc; + unsigned_T calc; rd = get_rs1p(); rs1 = get_rs1p(); - rs2 = get_rs2(); + rs2 = get_imm_ADDI(); - shift = rs2 & 0x1F; + shift = rs2; - calc = static_cast(this->regs->getValue(rs1)) >> shift; - this->regs->setValue(rd, static_cast(calc)); + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. C.SRLI: x{:d} >> {} -> x{:d}", sc_core::sc_time_stamp().value(), this->regs->getPC(), @@ -775,18 +838,18 @@ namespace riscv_tlm { return true; } - bool Exec_C_SRAI() { + bool Exec_C_SRAI() const { unsigned int rd, rs1, rs2; std::uint32_t shift; - std::int32_t calc; + unsigned_T calc; rd = get_rs1p(); rs1 = get_rs1p(); - rs2 = get_rs2(); + rs2 = get_imm_ADDI(); - shift = rs2 & 0x1F; + shift = rs2; - calc = static_cast(this->regs->getValue(rs1)) >> shift; + calc = static_cast(this->regs->getValue(rs1)) >> shift; this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. C.SRAI: x{:d} >> {} -> x{:d}(0x{:x})", @@ -797,19 +860,17 @@ namespace riscv_tlm { return true; } - bool Exec_C_SLLI() { - unsigned int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; + bool Exec_C_SLLI() const { + unsigned int rd, rs1; + unsigned_T shift; + unsigned_T calc; - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_imm_ADDI(); + rd = get_rs1(); + rs1 = get_rs1(); + shift = get_imm_ADDI(); - shift = rs2 & 0x1F; - - calc = static_cast(this->regs->getValue(rs1)) << shift; - this->regs->setValue(rd, static_cast(calc)); + calc = this->regs->getValue(rs1) << shift; + this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. C.SLLI: x{:d} << {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), @@ -819,38 +880,36 @@ namespace riscv_tlm { return true; } - bool Exec_C_ANDI() { + bool Exec_C_ANDI() const { unsigned int rd, rs1; - std::uint32_t imm; - std::uint32_t aux; - std::uint32_t calc; + signed_T imm; + unsigned_T calc; rd = get_rs1p(); rs1 = get_rs1p(); imm = get_imm_ADDI(); - aux = this->regs->getValue(rs1); - calc = aux & imm; - this->regs->setValue(rd, static_cast(calc)); + calc = this->regs->getValue(rs1) & imm; + this->regs->setValue(rd, calc); - this->logger->debug("{} ns. PC: 0x{:x}. C.ANDI: x{:d}(0x{:x}) AND 0x{:x} -> x{:d}", + this->logger->debug("{} ns. PC: 0x{:x}. ANDI: x{:d} C.AND 0x{:x} -> x{:d}", sc_core::sc_time_stamp().value(), this->regs->getPC(), - rs1, aux, imm, rd); + rs1, imm, rd); return true; } - bool Exec_C_SUB() { + bool Exec_C_SUB() const { unsigned int rd, rs1, rs2; - std::uint32_t calc; + unsigned_T calc; rd = get_rs1p(); rs1 = get_rs1p(); rs2 = get_rs2p(); calc = this->regs->getValue(rs1) - this->regs->getValue(rs2); - this->regs->setValue(rd, static_cast(calc)); + this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. C.SUB: x{:d} - x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), @@ -860,7 +919,7 @@ namespace riscv_tlm { return true; } - bool Exec_C_XOR() { + bool Exec_C_SUBW() const { unsigned int rd, rs1, rs2; std::uint32_t calc; @@ -868,9 +927,72 @@ namespace riscv_tlm { rs1 = get_rs1p(); rs2 = get_rs2p(); - calc = this->regs->getValue(rs1) ^ this->regs->getValue(rs2); + calc = static_cast((this->regs->getValue(rs1) - this->regs->getValue(rs2)) & 0xFFFFFFFF); this->regs->setValue(rd, static_cast(calc)); + this->logger->debug("{} ns. PC: 0x{:x}. C.SUBW: x{:d} - x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); + + return true; + } + + bool Exec_C_ADDW() const { + unsigned int rd, rs1, rs2; + unsigned_T calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); + + calc = static_cast((this->regs->getValue(rs1) + this->regs->getValue(rs2)) & 0xFFFFFFFF); + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. C.ADDW: x{:d} + x{} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); + + return true; + } + + bool Exec_C_SDSP() const { + unsigned_T mem_addr; + unsigned int rs1, rs2; + signed_T imm; + std::uint64_t data; + + rs1 = 2; + rs2 = get_rs2(); + imm = get_imm_CSDSP(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->regs->getValue(rs2); + + this->logger->debug("{} ns. PC: 0x{:x}. C.SDSP: 0x{:x} -> x{:d} + 0x{:x}(@0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs2, rs1, imm, mem_addr); + + this->mem_intf->writeDataMem(mem_addr, data & 0xFFFFFFFF, 4); + this->mem_intf->writeDataMem(mem_addr + 4, data >> 32, 4); + this->perf->dataMemoryWrite(); + + return true; + } + + bool Exec_C_XOR() const { + unsigned int rd, rs1, rs2; + unsigned_T calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); + + calc = this->regs->getValue(rs1) ^ this->regs->getValue(rs2); + this->regs->setValue(rd, calc); + this->logger->debug("{} ns. PC: 0x{:x}. C.XOR: x{:d} XOR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), this->regs->getPC(), rs1, rs2, rd); @@ -878,16 +1000,16 @@ namespace riscv_tlm { return true; } - bool Exec_C_OR() { + bool Exec_C_OR() const { unsigned int rd, rs1, rs2; - std::uint32_t calc; + unsigned_T calc; rd = get_rs1p(); rs1 = get_rs1p(); rs2 = get_rs2p(); calc = this->regs->getValue(rs1) | this->regs->getValue(rs2); - this->regs->setValue(rd, static_cast(calc)); + this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. C.OR: x{:d} OR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), this->regs->getPC(), @@ -896,16 +1018,16 @@ namespace riscv_tlm { return true; } - bool Exec_C_AND() { + bool Exec_C_AND() const { unsigned int rd, rs1, rs2; - std::uint32_t calc; + unsigned_T calc; rd = get_rs1p(); rs1 = get_rs1p(); rs2 = get_rs2p(); calc = this->regs->getValue(rs1) & this->regs->getValue(rs2); - this->regs->setValue(rd, static_cast(calc)); + this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. C.AND: x{:d} AND x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), this->regs->getPC(), @@ -916,14 +1038,14 @@ namespace riscv_tlm { bool Exec_C_ADDI() const { unsigned int rd, rs1; - std::int32_t imm; - std::int32_t calc; + signed_T imm; + unsigned_T calc; rd = this->get_rd(); rs1 = rd; - imm = static_cast(get_imm_ADDI()); + imm = static_cast(get_imm_ADDI()); - calc = static_cast(this->regs->getValue(rs1)) + imm; + calc = this->regs->getValue(rs1) + imm; this->regs->setValue(rd, calc); this->logger->debug("{} ns. PC: 0x{:x}. C.ADDI: x{:d} + {} -> x{:d}(0x{:x})", @@ -933,7 +1055,29 @@ namespace riscv_tlm { return true; } - bool Exec_C_JALR() { + bool Exec_C_ADDIW() const { + unsigned int rd, rs1; + std::int32_t imm; + std::int32_t aux; + std::int64_t calc; + + rd = this->get_rd(); + rs1 = rd; + imm = get_imm_ADDI(); + + aux = static_cast(this->regs->getValue(rs1) & 0xFFFFFFFF); + aux = static_cast(aux + imm); + calc = static_cast(aux); + + this->regs->setValue(rd, calc); + this->logger->debug("{} ns. PC: 0x{:x}. C.ADDIW: x{:d} + {} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), rs1, imm, rd, calc); + + return true; + } + + bool Exec_C_JALR() const { std::uint32_t mem_addr = 0; unsigned int rd, rs1; std::uint32_t new_pc, old_pc; @@ -942,9 +1086,9 @@ namespace riscv_tlm { rs1 = get_rs1(); old_pc = static_cast(this->regs->getPC()); - this->regs->setValue(rd, old_pc + 2); - new_pc = static_cast((this->regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); + + this->regs->setValue(rd, old_pc + 2); this->regs->setPC(new_pc); this->logger->debug("{} ns. PC: 0x{:x}. C.JALR: x{:d} <- 0x{:x} PC <- 0xx{:x}", @@ -955,20 +1099,21 @@ namespace riscv_tlm { return true; } - bool Exec_C_LW() { - std::uint32_t mem_addr; + bool Exec_C_LW() const { + unsigned_T mem_addr; unsigned int rd, rs1; - std::int32_t imm; - std::uint32_t data; + unsigned_T imm; + signed_T data; rd = get_rdp(); rs1 = get_rs1p(); imm = get_imm_L(); mem_addr = imm + this->regs->getValue(rs1); - data = this->mem_intf->readDataMem(mem_addr, 4); + data = static_cast(this->mem_intf->readDataMem(mem_addr, 4)); + this->perf->dataMemoryRead(); - this->regs->setValue(rd, static_cast(data)); + this->regs->setValue(rd, data); this->logger->debug("{} ns. PC: 0x{:x}. C.LW: x{:d}(0x{:x}) + {:d} (@0x{:x}) -> {:d} (0x{:x})", sc_core::sc_time_stamp().value(), this->regs->getPC(), @@ -977,7 +1122,58 @@ namespace riscv_tlm { return true; } - bool Exec_C_SW() { + bool Exec_C_LD() const { + unsigned_T mem_addr; + unsigned int rd, rs1; + unsigned_T imm; + std::uint64_t data; + + rd = get_rdp(); + rs1 = get_rs1p(); + imm = get_imm_CL(); + + mem_addr = imm + this->regs->getValue(rs1); + data = static_cast(this->mem_intf->readDataMem(mem_addr, 4)); + std::uint64_t aux = static_cast(this->mem_intf->readDataMem(mem_addr + 4, 4)); + data |= aux << 32; + + this->perf->dataMemoryRead(); + this->regs->setValue(rd, data); + + this->logger->debug("{} ns. PC: 0x{:x}. C.LD: 0x{:x} + x{:d} (0x{:x}) -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, mem_addr, rd, data); + + return true; + } + + bool Exec_C_SD() const { + unsigned_T mem_addr; + unsigned int rs1, rs2; + signed_T imm; + std::uint64_t data; + + rs1 = get_rs1p(); + rs2 = get_rs2p(); + imm = get_imm_CL(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->regs->getValue(rs2); + + this->logger->debug("{} ns. PC: 0x{:x}. C.SD: 0x{:x} -> x{:d} + 0x{:x}(@0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs2, rs1, imm, mem_addr); + + this->mem_intf->writeDataMem(mem_addr, data & 0xFFFFFFFF, 4); + this->mem_intf->writeDataMem(mem_addr + 4, data >> 32, 4); + this->perf->dataMemoryWrite(); + + return true; + } + + bool Exec_C_SW() const { std::uint32_t mem_addr; unsigned int rs1, rs2; std::int32_t imm; @@ -1000,7 +1196,67 @@ namespace riscv_tlm { return true; } - bool Exec_C_JAL(int m_rd) { + bool Exec_C_FSW_SD() const { + std::uint32_t mem_addr; + unsigned int rs1, rs2; + std::int32_t imm; + std::uint64_t data; + std::uint32_t aux; + + rs1 = get_rs1p(); + rs2 = get_rs2p(); + imm = get_imm_L(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->regs->getValue(rs2); + + aux = data >> 32; + this->mem_intf->writeDataMem(mem_addr, aux, 4); + + aux = data & 0x00000000FFFFFFFF; + this->mem_intf->writeDataMem(mem_addr+4, aux, 4); + + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. C.SD: x{:d}(0x{:x}) -> x{:d} + 0x{:x}(@0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs2, data, rs1, imm, mem_addr); + return true; + } + + // Implemented RV64 C.LDSP only (FLWSP is for RV32 with F extension) + bool Exec_C_LDSP() const { + unsigned_T mem_addr; + unsigned int rd, rs1; + unsigned_T imm; + std::uint64_t data; + std::uint64_t aux; + + rd = this->get_rd(); + rs1 = 2; + imm = get_imm_LDSP(); + + if (rd == 0) { + // Error + std::cout << "C.LDSP Error!\n"; + } + + mem_addr = imm + this->regs->getValue(rs1); + data = static_cast(this->mem_intf->readDataMem(mem_addr, 4)); + aux = static_cast(this->mem_intf->readDataMem(mem_addr + 4, 4)); + data |= aux << 32; + + this->perf->dataMemoryRead(); + this->regs->setValue(rd, data); + + this->logger->debug("{} ns. PC: 0x{:x}. C.LDSP: x{:d}(0x{:x}) -> x{:d} + 0x{:x}(@0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + 2, data, rs1, imm, mem_addr); + return true; + } + + + bool Exec_C_JAL(int m_rd) const { std::int32_t mem_addr; unsigned int rd; std::uint32_t new_pc, old_pc; @@ -1016,13 +1272,13 @@ namespace riscv_tlm { this->regs->setValue(rd, old_pc); this->logger->debug("{} ns. PC: 0x{:x}. C.JAL: x{:d} <- 0x{:x}. PC + 0x{:x} -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), this->regs->getPC(), + sc_core::sc_time_stamp().value(), old_pc - 2, rd, old_pc, mem_addr, new_pc); return true; } - bool Exec_C_EBREAK() { + bool Exec_C_EBREAK() const { this->logger->debug("C.EBREAK"); std::cout << "\n" << "C.EBRAK Instruction called, dumping information" @@ -1122,12 +1378,39 @@ namespace riscv_tlm { case OP_C_AND: Exec_C_AND(); break; + case OP_C_FSW: + Exec_C_FSW_SD(); + break; + case OP_C_FLWSP: + //Exec_C_FLWSP_LDSP(); + break; case OP_C_EBREAK: Exec_C_EBREAK(); std::cout << "C_EBREAK" << std::endl; *breakpoint = true; break; - [[unlikely]] default: + case OP_C_LD: + Exec_C_LD(); + break; + case OP_C_SD: + Exec_C_SD(); + break; + case OP_C_ADDIW: + Exec_C_ADDIW(); + break; + case OP_C_ADDW: + Exec_C_ADDW(); + break; + case OP_C_SUBW: + Exec_C_SUBW(); + break; + case OP_C_SDSP: + Exec_C_SDSP(); + break; + case OP_C_LDSP: + Exec_C_LDSP(); + break; + [[unlikely]] default: std::cout << "C instruction not implemented yet" << "\n"; inst.dump(); this->NOP(); diff --git a/inc/extension_base.h b/inc/extension_base.h index f4500a4..d64ac95 100644 --- a/inc/extension_base.h +++ b/inc/extension_base.h @@ -78,6 +78,7 @@ namespace riscv_tlm { bool NOP() { logger->debug("{} ns. PC: 0x{:x}. NOP! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC()); + logger->flush(); sc_core::sc_stop(); return true; } @@ -117,6 +118,10 @@ namespace riscv_tlm { m_instr.range(14, 12) = value; } + // For RV64 SLLI, SRLI & SRAI + virtual unsigned int get_shamt_slli() const { + return m_instr.range(25, 20); + } virtual void dump() const { std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; } diff --git a/src/BASE_ISA.cpp b/src/BASE_ISA.cpp index 2506026..873a2a1 100644 --- a/src/BASE_ISA.cpp +++ b/src/BASE_ISA.cpp @@ -12,7 +12,7 @@ namespace riscv_tlm { ///// RV32 Specialization template<> - int32_t BASE_ISA::get_imm_I() const { + std::int32_t BASE_ISA::get_imm_I() const { std::uint32_t aux = 0; aux = this->m_instr.range(31, 20); @@ -73,9 +73,160 @@ namespace riscv_tlm { return static_cast(aux); } + template<> + std::uint32_t BASE_ISA::get_funct7b() const { + return this->m_instr.range(31, 25); + } + + // SLLI, SRLI and SRAI get different shamt field depending on RV32 or RV64 + template<> + bool BASE_ISA::Exec_SLLI() { + unsigned int rd, rs1, rs2; + unsigned_T shift; + unsigned_T calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = get_shamt(); + + if (rs2 >= 0x20) { + std::cout << "ILLEGAL INSTRUCTION, shamt[5] != 0" << "\n"; + sc_core::sc_stop(); + this->RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, this->m_instr); + + return false; + } + + shift = rs2 & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) << shift; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SLLI: x{:d} << {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + template<> + bool BASE_ISA::Exec_SRLI() const { + unsigned int rd, rs1, rs2; + unsigned_T shift; + unsigned_T calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = rs2 & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SRLI: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + template<> + bool BASE_ISA::Exec_SRAI() const { + unsigned int rd, rs1, rs2; + unsigned_T shift; + signed_T calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = rs2 & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SRAI: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + template<> + bool BASE_ISA::Exec_SRL() const { + unsigned int rd, rs1, rs2; + unsigned_T shift; + unsigned_T calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = this->regs->getValue(rs2) & 0x1F; + calc = this->regs->getValue(rs1) >> shift; + + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SRL: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + template<> + bool BASE_ISA::Exec_SRA() const { + unsigned int rd, rs1, rs2; + unsigned_T shift; + signed_T calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = this->regs->getValue(rs2) & 0x1F; + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SRA: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + template<> + bool BASE_ISA::Exec_SLL() const { + unsigned int rd, rs1, rs2; + unsigned_T shift; + unsigned_T calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = this->regs->getValue(rs2) & 0x1F; + + calc = this->regs->getValue(rs1) << shift; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SLL: x{:d} << x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + ///// RV64 Specialization template<> - int64_t BASE_ISA::get_imm_I() const { + std::int64_t BASE_ISA::get_imm_I() const { std::uint64_t aux = 0; aux = this->m_instr.range(31, 20); @@ -137,4 +288,161 @@ namespace riscv_tlm { return static_cast(aux); } -} \ No newline at end of file + + template<> + std::uint32_t BASE_ISA::get_funct7b() const { + return this->m_instr.range(31, 26); + } + + // PASS + template<> + bool BASE_ISA::Exec_SLLI() { + unsigned int rd, rs1, rs2; + unsigned_T shift; + unsigned_T calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_shamt_slli(); + + if (rs2 >= 0x40) { + std::cout << "ILLEGAL INSTRUCTION, shamt[5] > 0x40" << "\n"; + sc_core::sc_stop(); + this->RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, this->m_instr); + + return false; + } + + shift = rs2 & 0x3F; + calc = this->regs->getValue(rs1) << shift; + + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SLLI: x{:d} << {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + // PASS + template<> + bool BASE_ISA::Exec_SRLI() const { + unsigned int rd, rs1, rs2; + unsigned_T shift; + unsigned_T calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_shamt_slli(); + + shift = rs2 & 0x3F; + + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SRLI: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + // PASS + template<> + bool BASE_ISA::Exec_SRAI() const { + unsigned int rd, rs1, rs2; + unsigned_T shift; + signed_T calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_shamt_slli(); + + shift = rs2 & 0x3F; + + calc = static_cast(static_cast(this->regs->getValue(rs1)) >> shift); + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SRAI: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + // PASS + template<> + bool BASE_ISA::Exec_SRL() const { + unsigned int rd, rs1, rs2; + unsigned_T shift; + unsigned_T calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = this->regs->getValue(rs2) & 0x3F; + calc = this->regs->getValue(rs1) >> shift; + + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SRL: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + // PASS + template<> + bool BASE_ISA::Exec_SRA() const { + unsigned int rd, rs1, rs2; + unsigned_T shift; + signed_T calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = this->regs->getValue(rs2) & 0x3F; + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SRA: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + // PASS + template<> + bool BASE_ISA::Exec_SLL() const { + unsigned int rd, rs1, rs2; + unsigned_T shift; + unsigned_T calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = this->regs->getValue(rs2) & 0x3F; + + calc = this->regs->getValue(rs1) << shift; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SLL: x{:d} << x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } +} + From a1098ad81fa94686bc70a136d02f1d20279f153d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Thu, 15 Sep 2022 12:49:12 +0200 Subject: [PATCH 14/17] Better git and compile options --- .gitignore | 4 ++++ CMakeLists.txt | 1 + 2 files changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 43431c8..e431479 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,7 @@ doc/Drawings.odg doc/html env.sh gh-md-toc +*.dump +*.log +.idea/ +.vscode/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 8de7d65..656e9d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ set(CMAKE_C_STANDARD 17) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_PREFIX_PATH ../systemc-2.3.3/build/ ../spdlog/install/) +add_definitions(-DCMAKE_EXPORT_COMPILE_COMMANDS=ON) add_compile_options(-O3 -g -Wall -Wextra -Wunused-function -Wpedantic) From e37f35c717af3c181006a078612d51ad83a6b8e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Thu, 15 Sep 2022 12:51:26 +0200 Subject: [PATCH 15/17] using spdlog submodule --- .gitmodules | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..0f4533c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "spdlog"] + path = spdlog + url = https://github.com/gabime/spdlog From 06400d692c3df4e3c98f046865388619bd0ce135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Thu, 15 Sep 2022 15:34:17 +0200 Subject: [PATCH 16/17] test results --- doc/passed_tests.md | 244 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 doc/passed_tests.md diff --git a/doc/passed_tests.md b/doc/passed_tests.md new file mode 100644 index 0000000..0ae0ce8 --- /dev/null +++ b/doc/passed_tests.md @@ -0,0 +1,244 @@ +# Tests + +Using riscv-arch-test (commit #acf857c68f3e5a476da24cff653b51176ac14dbf) + +## Setup + ++ Copy doc/riscv-arch-test/RISCV-TLM to riscv-arch-test/riscv-target/ ++ Run tests + +```make verify``` + +## Results +### RV 64 + +#### I Extension ++ Check add-01 ... OK ++ Check addi-01 ... OK ++ Check addiw-01 ... OK ++ Check addw-01 ... OK ++ Check and-01 ... OK ++ Check andi-01 ... OK ++ Check auipc-01 ... OK ++ Check beq-01 ... OK ++ Check bge-01 ... OK ++ Check bgeu-01 ... OK ++ Check blt-01 ... OK ++ Check bltu-01 ... OK ++ Check bne-01 ... OK ++ Check fence-01 ... OK ++ Check jal-01 ... OK ++ Check jalr-01 ... OK ++ Check lb-align-01 ... OK ++ Check lbu-align-01 ... OK ++ Check ld-align-01 ... OK ++ Check lh-align-01 ... OK ++ Check lhu-align-01 ... OK ++ Check lui-01 ... OK ++ Check lw-align-01 ... OK ++ Check lwu-align-01 ... OK ++ Check or-01 ... OK ++ Check ori-01 ... OK ++ Check sb-align-01 ... OK ++ Check sd-align-01 ... OK ++ Check sh-align-01 ... OK ++ Check sll-01 ... OK ++ Check slli-01 ... OK ++ Check slliw-01 ... OK ++ Check sllw-01 ... OK ++ Check slt-01 ... OK ++ Check slti-01 ... OK ++ Check sltiu-01 ... OK ++ Check sltu-01 ... OK ++ Check sra-01 ... OK ++ Check srai-01 ... OK ++ Check sraiw-01 ... OK ++ Check sraw-01 ... OK ++ Check srl-01 ... OK ++ Check srli-01 ... OK ++ Check srliw-01 ... OK ++ Check srlw-01 ... OK ++ Check sub-01 ... OK ++ Check subw-01 ... OK ++ Check sw-align-01 ... OK ++ Check xor-01 ... OK ++ Check xori-01 ... OK + +#### C Extension ++ Check cadd-01 ... OK ++ Check caddi-01 ... OK ++ Check caddi16sp-01 ... OK ++ Check caddi4spn-01 ... OK ++ Check caddiw-01 ... OK ++ Check caddw-01 ... OK ++ Check cand-01 ... OK ++ Check candi-01 ... OK ++ Check cbeqz-01 ... OK ++ Check cbnez-01 ... OK ++ Check cebreak-01 ... FAIL ++ Check cj-01 ... OK ++ Check cjalr-01 ... OK ++ Check cjr-01 ... OK ++ Check cld-01 ... OK ++ Check cldsp-01 ... OK ++ Check cli-01 ... OK ++ Check clui-01 ... OK ++ Check clw-01 ... OK ++ Check clwsp-01 ... OK ++ Check cmv-01 ... OK ++ Check cnop-01 ... OK ++ Check cor-01 ... OK ++ Check csd-01 ... OK ++ Check csdsp-01 ... OK ++ Check cslli-01 ... OK ++ Check csrai-01 ... OK ++ Check csrli-01 ... OK ++ Check csub-01 ... OK ++ Check csubw-01 ... OK ++ Check csw-01 ... OK ++ Check cswsp-01 ... OK ++ Check cxor-01 ... OK + +#### M Extension ++ Check div-01 ... OK ++ Check divu-01 ... OK ++ Check divuw-01 ... OK ++ Check divw-01 ... OK ++ Check mul-01 ... OK ++ Check mulh-01 ... OK ++ Check mulhsu-01 ... OK ++ Check mulhu-01 ... OK ++ Check mulw-01 ... OK ++ Check rem-01 ... OK ++ Check remu-01 ... OK ++ Check remuw-01 ... OK ++ Check remw-01 ... OK + +#### Privilege ++ Check ebreak ... FAIL ++ Check ecall ... FAIL ++ Check misalign1-jalr-01 ... OK ++ Check misalign2-jalr-01 ... FAIL ++ Check misalign-beq-01 ... OK ++ Check misalign-bge-01 ... OK ++ Check misalign-bgeu-01 ... OK ++ Check misalign-blt-01 ... OK ++ Check misalign-bltu-01 ... OK ++ Check misalign-bne-01 ... OK ++ Check misalign-jal-01 ... OK ++ Check misalign-ld-01 ... FAIL ++ Check misalign-lh-01 ... FAIL ++ Check misalign-lhu-01 ... FAIL ++ Check misalign-lw-01 ... FAIL ++ Check misalign-lwu-01 ... FAIL ++ Check misalign-sd-01 ... FAIL ++ Check misalign-sh-01 ... FAIL ++ Check misalign-sw-01 ... FAIL + +#### Zfencei ++ Check Fencei ... OK + + +### RV32 + +#### I Extension ++ Check add-01 ... OK ++ Check addi-01 ... OK ++ Check and-01 ... OK ++ Check andi-01 ... OK ++ Check auipc-01 ... OK ++ Check beq-01 ... OK ++ Check bge-01 ... OK ++ Check bgeu-01 ... OK ++ Check blt-01 ... OK ++ Check bltu-01 ... OK ++ Check bne-01 ... OK ++ Check fence-01 ... OK ++ Check jal-01 ... OK ++ Check jalr-01 ... OK ++ Check lb-align-01 ... OK ++ Check lbu-align-01 ... OK ++ Check lh-align-01 ... OK ++ Check lhu-align-01 ... OK ++ Check lui-01 ... OK ++ Check lw-align-01 ... OK ++ Check or-01 ... OK ++ Check ori-01 ... OK ++ Check sb-align-01 ... OK ++ Check sh-align-01 ... OK ++ Check sll-01 ... OK ++ Check slli-01 ... OK ++ Check slt-01 ... OK ++ Check slti-01 ... OK ++ Check sltiu-01 ... OK ++ Check sltu-01 ... OK ++ Check sra-01 ... OK ++ Check srai-01 ... OK ++ Check srl-01 ... OK ++ Check srli-01 ... OK ++ Check sub-01 ... OK ++ Check sw-align-01 ... OK ++ Check xor-01 ... OK ++ Check xori-01 ... OK + + +#### C Extension ++ Check cadd-01 ... OK ++ Check caddi-01 ... OK ++ Check caddi16sp-01 ... OK ++ Check caddi4spn-01 ... OK ++ Check cand-01 ... OK ++ Check candi-01 ... OK ++ Check cbeqz-01 ... OK ++ Check cbnez-01 ... OK ++ Check cebreak-01 ... FAIL ++ Check cj-01 ... OK ++ Check cjal-01 ... OK ++ Check cjalr-01 ... OK ++ Check cjr-01 ... OK ++ Check cli-01 ... OK ++ Check clui-01 ... OK ++ Check clw-01 ... OK ++ Check clwsp-01 ... OK ++ Check cmv-01 ... OK ++ Check cnop-01 ... OK ++ Check cor-01 ... OK ++ Check cslli-01 ... OK ++ Check csrai-01 ... OK ++ Check csrli-01 ... OK ++ Check csub-01 ... OK ++ Check csw-01 ... OK ++ Check cswsp-01 ... OK ++ Check cxor-01 ... OK + +#### M Extension ++ Check div-01 ... OK ++ Check divu-01 ... OK ++ Check mul-01 ... OK ++ Check mulh-01 ... OK ++ Check mulhsu-01 ... OK ++ Check mulhu-01 ... OK ++ Check rem-01 ... OK ++ Check remu-01 ... OK + +#### Privilage ++ Check ebreak ... FAIL ++ Check ecall ... FAIL ++ Check misalign1-jalr-01 ... OK ++ Check misalign2-jalr-01 ... FAIL ++ Check misalign-beq-01 ... OK ++ Check misalign-bge-01 ... OK ++ Check misalign-bgeu-01 ... OK ++ Check misalign-blt-01 ... OK ++ Check misalign-bltu-01 ... OK ++ Check misalign-bne-01 ... OK ++ Check misalign-jal-01 ... OK ++ Check misalign-lh-01 ... FAIL ++ Check misalign-lhu-01 ... FAIL ++ Check misalign-lw-01 ... FAIL ++ Check misalign-sh-01 ... FAIL ++ Check misalign-sw-01 ... FAIL + +### Zifencei Extension ++ Check Fencei ... OK + From fdbee47efc4fff5298a387a7a92a12e13ca47e60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0rius=20Mont=C3=B3n?= Date: Thu, 15 Sep 2022 15:34:58 +0200 Subject: [PATCH 17/17] files for test suite --- .../device/rv32i_m/C/Makefile.include | 37 ++ .../device/rv32i_m/I/Makefile.include | 34 ++ .../device/rv32i_m/M/Makefile.include | 37 ++ .../device/rv32i_m/Zifencei/Makefile.include | 37 ++ .../device/rv32i_m/privilege/Makefile.include | 37 ++ .../device/rv64i_m/C/Makefile.include | 35 ++ .../device/rv64i_m/I/Makefile.include | 34 ++ .../device/rv64i_m/M/Makefile.include | 35 ++ .../device/rv64i_m/Zifencei/Makefile.include | 34 ++ .../device/rv64i_m/privilege/Makefile.include | 34 ++ doc/riscv-arch-test/RISCV_TLM/link.ld | 18 + doc/riscv-arch-test/RISCV_TLM/model_test.h | 349 ++++++++++++++++++ 12 files changed, 721 insertions(+) create mode 100644 doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/C/Makefile.include create mode 100644 doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/I/Makefile.include create mode 100644 doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/M/Makefile.include create mode 100644 doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/Zifencei/Makefile.include create mode 100644 doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/privilege/Makefile.include create mode 100644 doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/C/Makefile.include create mode 100644 doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/I/Makefile.include create mode 100644 doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/M/Makefile.include create mode 100644 doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/Zifencei/Makefile.include create mode 100644 doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/privilege/Makefile.include create mode 100644 doc/riscv-arch-test/RISCV_TLM/link.ld create mode 100644 doc/riscv-arch-test/RISCV_TLM/model_test.h diff --git a/doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/C/Makefile.include b/doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/C/Makefile.include new file mode 100644 index 0000000..dd7f8df --- /dev/null +++ b/doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/C/Makefile.include @@ -0,0 +1,37 @@ +TARGET_SIM ?= /home/marius/Work/RISC-V/RISC-V-TLM/RISCV_TLM +TARGET_FLAGS ?= $(RISCV_TARGET_FLAGS) +ifeq ($(shell command -v $(TARGET_SIM) 2> /dev/null),) + $(error Target simulator executable '$(TARGET_SIM)` not found) +endif + +START_ADDRES := $(shell readelf -s $(<) | grep "begin_signature" | awk '{print "0x"$2 }') +END_ADDRES := $(shell readelf -s $(<) | grep "end_signature" | awk '{print "0x"$2 }') + +RUN_TARGET=\ + $(TARGET_SIM) $(TARGET_FLAGS) \ + -B `readelf -s $(<) | grep "begin_signature" | awk '{print "0x"$$2 }'`\ + -E `readelf -s $(<) | grep "end_signature" | awk '{print "0x"$$2 }'` -T \ + $(<).hex ;\ + mv *output $(work_dir_isa)/ + +RISCV_PREFIX ?= riscv32-unknown-elf- +RISCV_GCC ?= $(RISCV_PREFIX)gcc +RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump +RISCV_GCC_OPTS ?= -g -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles $(RVTEST_DEFINES) + +COMPILE_CMD = $$(RISCV_GCC) $(1) $$(RISCV_GCC_OPTS) \ + -I$(ROOTDIR)/riscv-test-suite/env/ \ + -I$(TARGETDIR)/$(RISCV_TARGET)/ \ + -T$(TARGETDIR)/$(RISCV_TARGET)/link.ld \ + $$(<) -o $$@ + +OBJ_CMD = $$(RISCV_OBJDUMP) $$@ -D > $$@.objdump; \ + $$(RISCV_OBJDUMP) $$@ --source > $$@.debug + +OBJ_HEX = riscv32-unknown-elf-objcopy -Oihex $$@ $$@.hex + +COMPILE_TARGET=\ + $(COMPILE_CMD); \ + $(OBJ_CMD);\ + $(OBJ_HEX) + diff --git a/doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/I/Makefile.include b/doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/I/Makefile.include new file mode 100644 index 0000000..b4044e2 --- /dev/null +++ b/doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/I/Makefile.include @@ -0,0 +1,34 @@ +TARGET_SIM ?= /home/marius/Work/RISC-V/RISC-V-TLM/RISCV_TLM +TARGET_FLAGS ?= $(RISCV_TARGET_FLAGS) +ifeq ($(shell command -v $(TARGET_SIM) 2> /dev/null),) + $(error Target simulator executable '$(TARGET_SIM)` not found) +endif + +RUN_TARGET=\ + $(TARGET_SIM) $(TARGET_FLAGS) \ + -B `readelf -s $(<) | grep "begin_signature" | awk '{print "0x"$$2 }'`\ + -E `readelf -s $(<) | grep "end_signature" | awk '{print "0x"$$2 }'` -T \ + $(<).hex ;\ + mv *output $(work_dir_isa)/ + +RISCV_PREFIX ?= riscv32-unknown-elf- +RISCV_GCC ?= $(RISCV_PREFIX)gcc +RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump +RISCV_GCC_OPTS ?= -g -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles $(RVTEST_DEFINES) + +COMPILE_CMD = $$(RISCV_GCC) $(1) $$(RISCV_GCC_OPTS) \ + -I$(ROOTDIR)/riscv-test-suite/env/ \ + -I$(TARGETDIR)/$(RISCV_TARGET)/ \ + -T$(TARGETDIR)/$(RISCV_TARGET)/link.ld \ + $$(<) -o $$@ + +OBJ_CMD = $$(RISCV_OBJDUMP) $$@ -D > $$@.objdump; \ + $$(RISCV_OBJDUMP) $$@ --source > $$@.debug + +OBJ_HEX = riscv32-unknown-elf-objcopy -Oihex $$@ $$@.hex + +COMPILE_TARGET=\ + $(COMPILE_CMD); \ + $(OBJ_CMD);\ + $(OBJ_HEX) + diff --git a/doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/M/Makefile.include b/doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/M/Makefile.include new file mode 100644 index 0000000..dd7f8df --- /dev/null +++ b/doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/M/Makefile.include @@ -0,0 +1,37 @@ +TARGET_SIM ?= /home/marius/Work/RISC-V/RISC-V-TLM/RISCV_TLM +TARGET_FLAGS ?= $(RISCV_TARGET_FLAGS) +ifeq ($(shell command -v $(TARGET_SIM) 2> /dev/null),) + $(error Target simulator executable '$(TARGET_SIM)` not found) +endif + +START_ADDRES := $(shell readelf -s $(<) | grep "begin_signature" | awk '{print "0x"$2 }') +END_ADDRES := $(shell readelf -s $(<) | grep "end_signature" | awk '{print "0x"$2 }') + +RUN_TARGET=\ + $(TARGET_SIM) $(TARGET_FLAGS) \ + -B `readelf -s $(<) | grep "begin_signature" | awk '{print "0x"$$2 }'`\ + -E `readelf -s $(<) | grep "end_signature" | awk '{print "0x"$$2 }'` -T \ + $(<).hex ;\ + mv *output $(work_dir_isa)/ + +RISCV_PREFIX ?= riscv32-unknown-elf- +RISCV_GCC ?= $(RISCV_PREFIX)gcc +RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump +RISCV_GCC_OPTS ?= -g -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles $(RVTEST_DEFINES) + +COMPILE_CMD = $$(RISCV_GCC) $(1) $$(RISCV_GCC_OPTS) \ + -I$(ROOTDIR)/riscv-test-suite/env/ \ + -I$(TARGETDIR)/$(RISCV_TARGET)/ \ + -T$(TARGETDIR)/$(RISCV_TARGET)/link.ld \ + $$(<) -o $$@ + +OBJ_CMD = $$(RISCV_OBJDUMP) $$@ -D > $$@.objdump; \ + $$(RISCV_OBJDUMP) $$@ --source > $$@.debug + +OBJ_HEX = riscv32-unknown-elf-objcopy -Oihex $$@ $$@.hex + +COMPILE_TARGET=\ + $(COMPILE_CMD); \ + $(OBJ_CMD);\ + $(OBJ_HEX) + diff --git a/doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/Zifencei/Makefile.include b/doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/Zifencei/Makefile.include new file mode 100644 index 0000000..dd7f8df --- /dev/null +++ b/doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/Zifencei/Makefile.include @@ -0,0 +1,37 @@ +TARGET_SIM ?= /home/marius/Work/RISC-V/RISC-V-TLM/RISCV_TLM +TARGET_FLAGS ?= $(RISCV_TARGET_FLAGS) +ifeq ($(shell command -v $(TARGET_SIM) 2> /dev/null),) + $(error Target simulator executable '$(TARGET_SIM)` not found) +endif + +START_ADDRES := $(shell readelf -s $(<) | grep "begin_signature" | awk '{print "0x"$2 }') +END_ADDRES := $(shell readelf -s $(<) | grep "end_signature" | awk '{print "0x"$2 }') + +RUN_TARGET=\ + $(TARGET_SIM) $(TARGET_FLAGS) \ + -B `readelf -s $(<) | grep "begin_signature" | awk '{print "0x"$$2 }'`\ + -E `readelf -s $(<) | grep "end_signature" | awk '{print "0x"$$2 }'` -T \ + $(<).hex ;\ + mv *output $(work_dir_isa)/ + +RISCV_PREFIX ?= riscv32-unknown-elf- +RISCV_GCC ?= $(RISCV_PREFIX)gcc +RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump +RISCV_GCC_OPTS ?= -g -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles $(RVTEST_DEFINES) + +COMPILE_CMD = $$(RISCV_GCC) $(1) $$(RISCV_GCC_OPTS) \ + -I$(ROOTDIR)/riscv-test-suite/env/ \ + -I$(TARGETDIR)/$(RISCV_TARGET)/ \ + -T$(TARGETDIR)/$(RISCV_TARGET)/link.ld \ + $$(<) -o $$@ + +OBJ_CMD = $$(RISCV_OBJDUMP) $$@ -D > $$@.objdump; \ + $$(RISCV_OBJDUMP) $$@ --source > $$@.debug + +OBJ_HEX = riscv32-unknown-elf-objcopy -Oihex $$@ $$@.hex + +COMPILE_TARGET=\ + $(COMPILE_CMD); \ + $(OBJ_CMD);\ + $(OBJ_HEX) + diff --git a/doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/privilege/Makefile.include b/doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/privilege/Makefile.include new file mode 100644 index 0000000..dd7f8df --- /dev/null +++ b/doc/riscv-arch-test/RISCV_TLM/device/rv32i_m/privilege/Makefile.include @@ -0,0 +1,37 @@ +TARGET_SIM ?= /home/marius/Work/RISC-V/RISC-V-TLM/RISCV_TLM +TARGET_FLAGS ?= $(RISCV_TARGET_FLAGS) +ifeq ($(shell command -v $(TARGET_SIM) 2> /dev/null),) + $(error Target simulator executable '$(TARGET_SIM)` not found) +endif + +START_ADDRES := $(shell readelf -s $(<) | grep "begin_signature" | awk '{print "0x"$2 }') +END_ADDRES := $(shell readelf -s $(<) | grep "end_signature" | awk '{print "0x"$2 }') + +RUN_TARGET=\ + $(TARGET_SIM) $(TARGET_FLAGS) \ + -B `readelf -s $(<) | grep "begin_signature" | awk '{print "0x"$$2 }'`\ + -E `readelf -s $(<) | grep "end_signature" | awk '{print "0x"$$2 }'` -T \ + $(<).hex ;\ + mv *output $(work_dir_isa)/ + +RISCV_PREFIX ?= riscv32-unknown-elf- +RISCV_GCC ?= $(RISCV_PREFIX)gcc +RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump +RISCV_GCC_OPTS ?= -g -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles $(RVTEST_DEFINES) + +COMPILE_CMD = $$(RISCV_GCC) $(1) $$(RISCV_GCC_OPTS) \ + -I$(ROOTDIR)/riscv-test-suite/env/ \ + -I$(TARGETDIR)/$(RISCV_TARGET)/ \ + -T$(TARGETDIR)/$(RISCV_TARGET)/link.ld \ + $$(<) -o $$@ + +OBJ_CMD = $$(RISCV_OBJDUMP) $$@ -D > $$@.objdump; \ + $$(RISCV_OBJDUMP) $$@ --source > $$@.debug + +OBJ_HEX = riscv32-unknown-elf-objcopy -Oihex $$@ $$@.hex + +COMPILE_TARGET=\ + $(COMPILE_CMD); \ + $(OBJ_CMD);\ + $(OBJ_HEX) + diff --git a/doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/C/Makefile.include b/doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/C/Makefile.include new file mode 100644 index 0000000..d754164 --- /dev/null +++ b/doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/C/Makefile.include @@ -0,0 +1,35 @@ +TARGET_SIM ?= /home/marius/Work/RISC-V/RISC-V-TLM/RISCV_TLM +TARGET_FLAGS ?= $(RISCV_TARGET_FLAGS) +ifeq ($(shell command -v $(TARGET_SIM) 2> /dev/null),) + $(error Target simulator executable '$(TARGET_SIM)` not found) +endif + +START_ADDRES := $(shell readelf -s $(<) | grep "begin_signature" | awk '{print "0x"$2 }') +END_ADDRES := $(shell readelf -s $(<) | grep "end_signature" | awk '{print "0x"$2 }') + +RUN_TARGET=\ + $(TARGET_SIM) $(TARGET_FLAGS) -R64 -T \ + $(<).hex ;\ + mv *output $(work_dir_isa)/ + +RISCV_PREFIX ?= riscv64-unknown-elf- +RISCV_GCC ?= $(RISCV_PREFIX)gcc +RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump +RISCV_GCC_OPTS ?= -g -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles $(RVTEST_DEFINES) + +COMPILE_CMD = $$(RISCV_GCC) $(1) $$(RISCV_GCC_OPTS) \ + -I$(ROOTDIR)/riscv-test-suite/env/ \ + -I$(TARGETDIR)/$(RISCV_TARGET)/ \ + -T$(TARGETDIR)/$(RISCV_TARGET)/link.ld \ + $$(<) -o $$@ + +OBJ_CMD = $$(RISCV_OBJDUMP) $$@ -D > $$@.objdump; \ + $$(RISCV_OBJDUMP) $$@ --source > $$@.debug + +OBJ_HEX = riscv64-unknown-elf-objcopy -Oihex $$@ $$@.hex + +COMPILE_TARGET=\ + $(COMPILE_CMD); \ + $(OBJ_CMD);\ + $(OBJ_HEX) + diff --git a/doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/I/Makefile.include b/doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/I/Makefile.include new file mode 100644 index 0000000..54c96dd --- /dev/null +++ b/doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/I/Makefile.include @@ -0,0 +1,34 @@ +TARGET_SIM ?= /home/marius/Work/RISC-V/RISC-V-TLM/RISCV_TLM +TARGET_FLAGS ?= $(RISCV_TARGET_FLAGS) +ifeq ($(shell command -v $(TARGET_SIM) 2> /dev/null),) + $(error Target simulator executable '$(TARGET_SIM)` not found) +endif + +RUN_TARGET=\ + $(TARGET_SIM) $(TARGET_FLAGS) -R64 -T \ + $(<).hex ;\ + mv *output $(work_dir_isa)/ + +RISCV_PREFIX ?= riscv64-unknown-elf- +RISCV_GCC ?= $(RISCV_PREFIX)gcc +RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump +RISCV_GCC_OPTS ?= -g -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles $(RVTEST_DEFINES) + +COMPILE_CMD = $$(RISCV_GCC) $(1) $$(RISCV_GCC_OPTS) \ + -I$(ROOTDIR)/riscv-test-suite/env/ \ + -I$(TARGETDIR)/$(RISCV_TARGET)/ \ + -T$(TARGETDIR)/$(RISCV_TARGET)/link.ld \ + $$(<) -o $$@ + + + +OBJ_CMD = $$(RISCV_OBJDUMP) $$@ -D > $$@.objdump; \ + $$(RISCV_OBJDUMP) $$@ --source > $$@.debug + +OBJ_HEX = riscv64-unknown-elf-objcopy -Oihex $$@ $$@.hex + +COMPILE_TARGET=\ + $(COMPILE_CMD); \ + $(OBJ_CMD);\ + $(OBJ_HEX) + diff --git a/doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/M/Makefile.include b/doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/M/Makefile.include new file mode 100644 index 0000000..d754164 --- /dev/null +++ b/doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/M/Makefile.include @@ -0,0 +1,35 @@ +TARGET_SIM ?= /home/marius/Work/RISC-V/RISC-V-TLM/RISCV_TLM +TARGET_FLAGS ?= $(RISCV_TARGET_FLAGS) +ifeq ($(shell command -v $(TARGET_SIM) 2> /dev/null),) + $(error Target simulator executable '$(TARGET_SIM)` not found) +endif + +START_ADDRES := $(shell readelf -s $(<) | grep "begin_signature" | awk '{print "0x"$2 }') +END_ADDRES := $(shell readelf -s $(<) | grep "end_signature" | awk '{print "0x"$2 }') + +RUN_TARGET=\ + $(TARGET_SIM) $(TARGET_FLAGS) -R64 -T \ + $(<).hex ;\ + mv *output $(work_dir_isa)/ + +RISCV_PREFIX ?= riscv64-unknown-elf- +RISCV_GCC ?= $(RISCV_PREFIX)gcc +RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump +RISCV_GCC_OPTS ?= -g -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles $(RVTEST_DEFINES) + +COMPILE_CMD = $$(RISCV_GCC) $(1) $$(RISCV_GCC_OPTS) \ + -I$(ROOTDIR)/riscv-test-suite/env/ \ + -I$(TARGETDIR)/$(RISCV_TARGET)/ \ + -T$(TARGETDIR)/$(RISCV_TARGET)/link.ld \ + $$(<) -o $$@ + +OBJ_CMD = $$(RISCV_OBJDUMP) $$@ -D > $$@.objdump; \ + $$(RISCV_OBJDUMP) $$@ --source > $$@.debug + +OBJ_HEX = riscv64-unknown-elf-objcopy -Oihex $$@ $$@.hex + +COMPILE_TARGET=\ + $(COMPILE_CMD); \ + $(OBJ_CMD);\ + $(OBJ_HEX) + diff --git a/doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/Zifencei/Makefile.include b/doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/Zifencei/Makefile.include new file mode 100644 index 0000000..54c96dd --- /dev/null +++ b/doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/Zifencei/Makefile.include @@ -0,0 +1,34 @@ +TARGET_SIM ?= /home/marius/Work/RISC-V/RISC-V-TLM/RISCV_TLM +TARGET_FLAGS ?= $(RISCV_TARGET_FLAGS) +ifeq ($(shell command -v $(TARGET_SIM) 2> /dev/null),) + $(error Target simulator executable '$(TARGET_SIM)` not found) +endif + +RUN_TARGET=\ + $(TARGET_SIM) $(TARGET_FLAGS) -R64 -T \ + $(<).hex ;\ + mv *output $(work_dir_isa)/ + +RISCV_PREFIX ?= riscv64-unknown-elf- +RISCV_GCC ?= $(RISCV_PREFIX)gcc +RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump +RISCV_GCC_OPTS ?= -g -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles $(RVTEST_DEFINES) + +COMPILE_CMD = $$(RISCV_GCC) $(1) $$(RISCV_GCC_OPTS) \ + -I$(ROOTDIR)/riscv-test-suite/env/ \ + -I$(TARGETDIR)/$(RISCV_TARGET)/ \ + -T$(TARGETDIR)/$(RISCV_TARGET)/link.ld \ + $$(<) -o $$@ + + + +OBJ_CMD = $$(RISCV_OBJDUMP) $$@ -D > $$@.objdump; \ + $$(RISCV_OBJDUMP) $$@ --source > $$@.debug + +OBJ_HEX = riscv64-unknown-elf-objcopy -Oihex $$@ $$@.hex + +COMPILE_TARGET=\ + $(COMPILE_CMD); \ + $(OBJ_CMD);\ + $(OBJ_HEX) + diff --git a/doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/privilege/Makefile.include b/doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/privilege/Makefile.include new file mode 100644 index 0000000..54c96dd --- /dev/null +++ b/doc/riscv-arch-test/RISCV_TLM/device/rv64i_m/privilege/Makefile.include @@ -0,0 +1,34 @@ +TARGET_SIM ?= /home/marius/Work/RISC-V/RISC-V-TLM/RISCV_TLM +TARGET_FLAGS ?= $(RISCV_TARGET_FLAGS) +ifeq ($(shell command -v $(TARGET_SIM) 2> /dev/null),) + $(error Target simulator executable '$(TARGET_SIM)` not found) +endif + +RUN_TARGET=\ + $(TARGET_SIM) $(TARGET_FLAGS) -R64 -T \ + $(<).hex ;\ + mv *output $(work_dir_isa)/ + +RISCV_PREFIX ?= riscv64-unknown-elf- +RISCV_GCC ?= $(RISCV_PREFIX)gcc +RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump +RISCV_GCC_OPTS ?= -g -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles $(RVTEST_DEFINES) + +COMPILE_CMD = $$(RISCV_GCC) $(1) $$(RISCV_GCC_OPTS) \ + -I$(ROOTDIR)/riscv-test-suite/env/ \ + -I$(TARGETDIR)/$(RISCV_TARGET)/ \ + -T$(TARGETDIR)/$(RISCV_TARGET)/link.ld \ + $$(<) -o $$@ + + + +OBJ_CMD = $$(RISCV_OBJDUMP) $$@ -D > $$@.objdump; \ + $$(RISCV_OBJDUMP) $$@ --source > $$@.debug + +OBJ_HEX = riscv64-unknown-elf-objcopy -Oihex $$@ $$@.hex + +COMPILE_TARGET=\ + $(COMPILE_CMD); \ + $(OBJ_CMD);\ + $(OBJ_HEX) + diff --git a/doc/riscv-arch-test/RISCV_TLM/link.ld b/doc/riscv-arch-test/RISCV_TLM/link.ld new file mode 100644 index 0000000..fb0bf0c --- /dev/null +++ b/doc/riscv-arch-test/RISCV_TLM/link.ld @@ -0,0 +1,18 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(rvtest_entry_point) + +SECTIONS +{ + . = 0x00000000; + .text.init : { *(.text.init) } + . = ALIGN(0x1000); +/* .tohost : { *(.tohost) } */ + . = ALIGN(0x1000); + .text : { *(.text) } + . = ALIGN(0x1000); + .data : { *(.data) } + .data.string : { *(.data.string)} + .bss : { *(.bss) } + _end = .; +} + diff --git a/doc/riscv-arch-test/RISCV_TLM/model_test.h b/doc/riscv-arch-test/RISCV_TLM/model_test.h new file mode 100644 index 0000000..b329d29 --- /dev/null +++ b/doc/riscv-arch-test/RISCV_TLM/model_test.h @@ -0,0 +1,349 @@ +#ifndef _COMPLIANCE_MODEL_H +#define _COMPLIANCE_MODEL_H + +#define TESTNUM gp + +#if XLEN == 64 + #define ALIGNMENT 3 +#else + #define ALIGNMENT 2 +#endif + +//RV_COMPLIANCE_HALT + +#define RVMODEL_HALT \ + la t0, begin_signature; \ + la t1, end_signature; \ + fence; \ + ecall + +#define RVMODEL_BOOT \ + .align 6; \ + .weak stvec_handler; \ + .weak mtvec_handler; \ + /* reset vector */ \ + j reset_vector; \ + .align 2; \ +trap_vector: \ + /* test whether the test came from pass/fail */ \ + csrr t5, mcause; \ + li t6, CAUSE_USER_ECALL; \ + beq t5, t6, write_tohost; \ + li t6, CAUSE_SUPERVISOR_ECALL; \ + beq t5, t6, write_tohost; \ + li t6, CAUSE_MACHINE_ECALL; \ + beq t5, t6, write_tohost; \ + /* if an mtvec_handler is defined, jump to it */ \ + la t5, mtvec_handler; \ + beqz t5, 1f; \ + jr t5; \ + /* was it an interrupt or an exception? */ \ + 1: csrr t5, mcause; \ + bgez t5, handle_exception; \ +handle_exception: \ + /* we don't know how to handle whatever the exception was */ \ + other_exception: \ + /* some unhandlable exception occurred */ \ + 1: ori gp, gp, 1337; \ + write_tohost: \ + sw gp, tohost, t5; \ + j write_tohost; \ +reset_vector: \ + li a0, MSTATUS_MPP; \ + csrs mstatus, a0; \ + la t0, trap_vector; \ + csrw mtvec, t0; \ + la t0, rvtest_init; \ + csrw mepc, t0; \ + csrr a0, mhartid; \ + mret; \ +1: \ + +//RV_COMPLIANCE_DATA_BEGIN +#define RVMODEL_DATA_BEGIN \ + .align 4; .global begin_signature; begin_signature: + +//RV_COMPLIANCE_DATA_END +#define RVMODEL_DATA_END \ + .align 4; .global end_signature; end_signature: \ + .pushsection .tohost,"aw",@progbits; \ + .align 8; .global tohost; tohost: .dword 0; \ + .align 8; .global fromhost; fromhost: .dword 0; \ + .popsection; \ + .align 8; .global begin_regstate; begin_regstate: \ + .word 128; \ + .align 8; .global end_regstate; end_regstate: \ + .word 4; \ + .align ALIGNMENT;\ + +#define RVMODEL_IO_INIT + +#define RVMODEL_SET_MSW_INT + + +#define RVMODEL_CLEAR_MSW_INT + +#define RVMODEL_CLEAR_MTIMER_INT + +#define RVMODEL_CLEAR_MEXT_INT + +#endif // _COMPLIANCE_MODEL_H + +// RISC-V Compliance IO Test Header File + +/* + * Copyright (c) 2005-2018 Imperas Software Ltd., www.imperas.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +// +// In general the following registers are reserved +// ra, a0, t0, t1 +// x1, x10 x5, x6 +// new reserve x31 +// + +#ifndef _COMPLIANCE_IO_H +#define _COMPLIANCE_IO_H + + +#ifndef RVMODEL_ASSERT +# define RVMODEL_IO_QUIET +#endif + +//----------------------------------------------------------------------- +// RV IO Macros (Character transfer by custom instruction) +//----------------------------------------------------------------------- +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + +#define RVTEST_CUSTOM1 0x40000000 + +#ifdef RVMODEL_IO_QUIET + +#define RVMODEL_IO_INIT +#define RVMODEL_IO_WRITE_STR(_SP, _STR) +#define RVMODEL_IO_CHECK() +#define RVMODEL_IO_ASSERT_GPR_EQ(_SP, _R, _I) +#define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _R, _I) +#define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I) + +#else + +#define RVMODEL_IO_INIT + +#if (__riscv_xlen==32) +# define RSIZE 4 +# define SX sw +# define LX lw +#endif +#if (__riscv_xlen==64) +# define RSIZE 8 +# define SX sd +# define LX ld +#endif + +// _SP = (volatile register) +#define LOCAL_IO_PUSH(_SP) \ + la _SP, begin_regstate; \ + SX x1, (1*RSIZE)(_SP); \ + SX x5, (5*RSIZE)(_SP); \ + SX x6, (6*RSIZE)(_SP); \ + SX x8, (8*RSIZE)(_SP); \ + SX x10, (10*RSIZE)(_SP); + +// _SP = (volatile register) +#define LOCAL_IO_POP(_SP) \ + la _SP, begin_regstate; \ + LX x1, (1*RSIZE)(_SP); \ + LX x5, (5*RSIZE)(_SP); \ + LX x6, (6*RSIZE)(_SP); \ + LX x8, (8*RSIZE)(_SP); \ + LX x10, (10*RSIZE)(_SP); + +#define LOCAL_IO_WRITE_GPR(_R) \ + mv a0, _R; \ + la t0, FN_WriteA0; \ + jalr t0; + +#define LOCAL_IO_WRITE_FPR(_F) \ + fmv.x.s a0, _F; \ + jal FN_WriteA0; + +#define LOCAL_IO_WRITE_DFPR(_V1, _V2) \ + mv a0, _V1; \ + jal FN_WriteA0; \ + mv a0, _V2; \ + jal FN_WriteA0; \ + +#define LOCAL_IO_PUTC(_R) \ + la t3, RVTEST_CUSTOM1; \ + sw _R, (0)(t3); + + +// Assertion violation: file file.c, line 1234: (expr) +// _SP = (volatile register) +// _R = GPR +// _I = Immediate +#define RVMODEL_IO_ASSERT_GPR_EQ(_SP, _R, _I) \ + LOCAL_IO_PUSH(_SP) \ + mv s0, _R; \ + li t0, _I; \ + beq s0, t0, 20002f; \ + LOCAL_IO_WRITE_STR("Assertion violation: file "); \ + LOCAL_IO_WRITE_STR(__FILE__); \ + LOCAL_IO_WRITE_STR(", line "); \ + LOCAL_IO_WRITE_STR(TOSTRING(__LINE__)); \ + LOCAL_IO_WRITE_STR(": "); \ + LOCAL_IO_WRITE_STR(# _R); \ + LOCAL_IO_WRITE_STR("("); \ + LOCAL_IO_WRITE_GPR(s0); \ + LOCAL_IO_WRITE_STR(") != "); \ + LOCAL_IO_WRITE_STR(# _I); \ + LOCAL_IO_WRITE_STR("\n"); \ + li TESTNUM, 100; \ + j rvtest_code_end; \ +20002: \ + LOCAL_IO_POP(_SP) + + +// _F = FPR +// _C = GPR +// _I = Immediate +#define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _C, _I) \ + fmv.x.s t0, _F; \ + beq _C, t0, 20003f; \ + LOCAL_IO_WRITE_STR("Assertion violation: file "); \ + LOCAL_IO_WRITE_STR(__FILE__); \ + LOCAL_IO_WRITE_STR(", line "); \ + LOCAL_IO_WRITE_STR(TOSTRING(__LINE__)); \ + LOCAL_IO_WRITE_STR(": "); \ + LOCAL_IO_WRITE_STR(# _F); \ + LOCAL_IO_WRITE_STR("("); \ + LOCAL_IO_WRITE_FPR(_F); \ + LOCAL_IO_WRITE_STR(") != "); \ + LOCAL_IO_WRITE_STR(# _I); \ + LOCAL_IO_WRITE_STR("\n"); \ + li TESTNUM, 100; \ + j rvtest_code_end; \ +20003: + +// _D = DFPR +// _R = GPR +// _I = Immediate +#define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I) \ + fmv.x.d t0, _D; \ + beq _R, t0, 20005f; \ + LOCAL_IO_WRITE_STR("Assertion violation: file "); \ + LOCAL_IO_WRITE_STR(__FILE__); \ + LOCAL_IO_WRITE_STR(", line "); \ + LOCAL_IO_WRITE_STR(TOSTRING(__LINE__)); \ + LOCAL_IO_WRITE_STR(": "); \ + LOCAL_IO_WRITE_STR(# _D); \ + LOCAL_IO_WRITE_STR("("); \ + LOCAL_IO_WRITE_DFPR(_D); \ + LOCAL_IO_WRITE_STR(") != "); \ + LOCAL_IO_WRITE_STR(# _I); \ + LOCAL_IO_WRITE_STR("\n"); \ + li TESTNUM, 100; \ + j rvtest_code_end; \ +20005: + +// _SP = (volatile register) +#define LOCAL_IO_WRITE_STR(_STR) RVMODEL_IO_WRITE_STR(x31, _STR) +#define RVMODEL_IO_WRITE_STR(_SP, _STR) \ + LOCAL_IO_PUSH(_SP) \ + .section .data.string; \ +20001: \ + .string _STR; \ + .section .text.init; \ + la a0, 20001b; \ + la t0, FN_WriteStr; \ + jalr t0; \ + LOCAL_IO_POP(_SP) + +// generate assertion listing +#define LOCAL_CHECK() RVMODEL_IO_CHECK() +#define RVMODEL_IO_CHECK() \ + li zero, -1; \ + +// +// FN_WriteStr: Uses a0, t0 +// +FN_WriteStr: + mv t0, a0; +10000: + lbu a0, (t0); + addi t0, t0, 1; + beq a0, zero, 10000f; + LOCAL_IO_PUTC(a0); + j 10000b; +10000: + ret; + +// +// FN_WriteA0: write register a0(x10) (destroys a0(x10), t0-t2(x5-x7)) +// +FN_WriteA0: + mv t0, a0 + // determine architectural register width + li a0, -1 + srli a0, a0, 31 + srli a0, a0, 1 + bnez a0, FN_WriteA0_64 + +FN_WriteA0_32: + // reverse register when xlen is 32 + li t1, 8 +10000: slli t2, t2, 4 + andi a0, t0, 0xf + srli t0, t0, 4 + or t2, t2, a0 + addi t1, t1, -1 + bnez t1, 10000b + li t1, 8 + j FN_WriteA0_common + +FN_WriteA0_64: + // reverse register when xlen is 64 + li t1, 16 +10000: slli t2, t2, 4 + andi a0, t0, 0xf + srli t0, t0, 4 + or t2, t2, a0 + addi t1, t1, -1 + bnez t1, 10000b + li t1, 16 + +FN_WriteA0_common: + // write reversed characters + li t0, 10 +10000: andi a0, t2, 0xf + blt a0, t0, 10001f + addi a0, a0, 'a'-10 + j 10002f +10001: addi a0, a0, '0' +10002: LOCAL_IO_PUTC(a0) + srli t2, t2, 4 + addi t1, t1, -1 + bnez t1, 10000b + ret + +#endif // RVMODEL_IO_QUIET + +#endif // _COMPLIANCE_IO_H