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