Register class changed to templated to prepare for rv64 code
This commit is contained in:
parent
a82938bb61
commit
d1fa3c752e
|
@ -52,7 +52,7 @@ namespace riscv_tlm {
|
||||||
/**
|
/**
|
||||||
* @brief Instruction decoding and fields access
|
* @brief Instruction decoding and fields access
|
||||||
*/
|
*/
|
||||||
class A_extension : public extension_base {
|
class A_extension : public extension_base<std::uint32_t> {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -92,13 +92,13 @@ namespace riscv_tlm {
|
||||||
/**
|
/**
|
||||||
* @brief Risc_V execute module
|
* @brief Risc_V execute module
|
||||||
*/
|
*/
|
||||||
class BASE_ISA : public extension_base {
|
class BASE_ISA : public extension_base<std::uint32_t> {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Constructor, same as base class
|
* @brief Constructor, same as base class
|
||||||
*/
|
*/
|
||||||
using extension_base::extension_base;
|
using extension_base<std::uint32_t>::extension_base;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Access to funct7 field
|
* @brief Access to funct7 field
|
||||||
|
|
|
@ -67,10 +67,10 @@ namespace riscv_tlm {
|
||||||
bool CPU_step();
|
bool CPU_step();
|
||||||
|
|
||||||
|
|
||||||
Registers *getRegisterBank() { return register_bank; }
|
Registers<std::uint32_t> *getRegisterBank() { return register_bank; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Registers *register_bank;
|
Registers<std::uint32_t> *register_bank;
|
||||||
Performance *perf;
|
Performance *perf;
|
||||||
std::shared_ptr<spdlog::logger> logger;
|
std::shared_ptr<spdlog::logger> logger;
|
||||||
C_extension *c_inst;
|
C_extension *c_inst;
|
||||||
|
|
|
@ -95,7 +95,7 @@ namespace riscv_tlm {
|
||||||
/**
|
/**
|
||||||
* @brief Instruction decoding and fields access
|
* @brief Instruction decoding and fields access
|
||||||
*/
|
*/
|
||||||
class C_extension : public extension_base {
|
class C_extension : public extension_base<std::uint32_t> {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace riscv_tlm {
|
||||||
/**
|
/**
|
||||||
* @brief Instruction decoding and fields access
|
* @brief Instruction decoding and fields access
|
||||||
*/
|
*/
|
||||||
class M_extension : public extension_base {
|
class M_extension : public extension_base<std::uint32_t> {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
173
inc/Registers.h
173
inc/Registers.h
|
@ -112,6 +112,7 @@ namespace riscv_tlm {
|
||||||
/**
|
/**
|
||||||
* @brief Register file implementation
|
* @brief Register file implementation
|
||||||
*/
|
*/
|
||||||
|
template<typename T>
|
||||||
class Registers {
|
class Registers {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -186,33 +187,56 @@ namespace riscv_tlm {
|
||||||
/**
|
/**
|
||||||
* Default constructor
|
* 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
|
* Set value for a register
|
||||||
* @param reg_num register number
|
* @param reg_num register number
|
||||||
* @param value register value
|
* @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
|
* Returns register value
|
||||||
* @param reg_num register number
|
* @param reg_num register number
|
||||||
* @return register value
|
* @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<T>(0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns PC value
|
* Returns PC value
|
||||||
* @return PC value
|
* @return PC value
|
||||||
*/
|
*/
|
||||||
std::uint32_t getPC() const;
|
T getPC() const {
|
||||||
|
return register_PC;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets arbitraty value to PC
|
* Sets arbitraty value to PC
|
||||||
* @param new_pc new address 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
|
* Increments PC couunter to next address
|
||||||
|
@ -230,40 +254,163 @@ namespace riscv_tlm {
|
||||||
* @param csr CSR number to access
|
* @param csr CSR number to access
|
||||||
* @return CSR value
|
* @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<std::uint64_t>(sc_core::sc_time(
|
||||||
|
sc_core::sc_time_stamp()
|
||||||
|
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
|
||||||
|
& 0x00000000FFFFFFFF;
|
||||||
|
break;
|
||||||
|
case CSR_CYCLEH:
|
||||||
|
case CSR_MCYCLEH:
|
||||||
|
ret_value = static_cast<std::uint32_t>((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<std::uint64_t>(sc_core::sc_time(
|
||||||
|
sc_core::sc_time_stamp()
|
||||||
|
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
|
||||||
|
& 0x00000000FFFFFFFF;
|
||||||
|
break;
|
||||||
|
case CSR_TIMEH:
|
||||||
|
ret_value = static_cast<std::uint32_t>((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
|
* @brief Set CSR value
|
||||||
* @param csr CSR number to access
|
* @param csr CSR number to access
|
||||||
* @param value new value to register
|
* @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
|
* 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:
|
private:
|
||||||
/**
|
/**
|
||||||
* bank of registers (32 regs of 32bits each)
|
* bank of registers (32 regs of 32bits each)
|
||||||
*/
|
*/
|
||||||
std::array<std::uint32_t, 32> register_bank = {{0}};
|
std::array<T, 32> register_bank = {{0}};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Program counter (32 bits width)
|
* Program counter (32 bits width)
|
||||||
*/
|
*/
|
||||||
std::uint32_t register_PC;
|
T register_PC;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CSR registers (4096 maximum)
|
* CSR registers (4096 maximum)
|
||||||
*/
|
*/
|
||||||
std::unordered_map<std::uint32_t, unsigned int> CSR;
|
std::unordered_map<T, unsigned int> CSR;
|
||||||
|
|
||||||
|
|
||||||
Performance *perf;
|
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
|
#endif
|
||||||
|
|
|
@ -28,19 +28,55 @@
|
||||||
|
|
||||||
namespace riscv_tlm {
|
namespace riscv_tlm {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
class extension_base {
|
class extension_base {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
extension_base(const sc_dt::sc_uint<32> &instr, Registers *register_bank,
|
extension_base(const T &instr, Registers<T> *register_bank,
|
||||||
MemoryInterface *mem_interface);
|
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 */
|
/* pure virtual functions */
|
||||||
virtual std::int32_t opcode() const = 0;
|
virtual std::int32_t opcode() const = 0;
|
||||||
|
@ -77,11 +113,13 @@ namespace riscv_tlm {
|
||||||
m_instr.range(14, 12) = value;
|
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:
|
protected:
|
||||||
sc_dt::sc_uint<32> m_instr;
|
sc_dt::sc_uint<32> m_instr;
|
||||||
Registers *regs;
|
Registers<T> *regs;
|
||||||
Performance *perf;
|
Performance *perf;
|
||||||
MemoryInterface *mem_intf;
|
MemoryInterface *mem_intf;
|
||||||
std::shared_ptr<spdlog::logger> logger;
|
std::shared_ptr<spdlog::logger> logger;
|
||||||
|
|
|
@ -126,7 +126,7 @@ namespace riscv_tlm {
|
||||||
|
|
||||||
rd = get_rd();
|
rd = get_rd();
|
||||||
mem_addr = get_imm_J();
|
mem_addr = get_imm_J();
|
||||||
old_pc = static_cast<std::uint32_t>(regs->getPC());
|
old_pc = regs->getPC();
|
||||||
new_pc = old_pc + mem_addr;
|
new_pc = old_pc + mem_addr;
|
||||||
|
|
||||||
regs->setPC(new_pc);
|
regs->setPC(new_pc);
|
||||||
|
@ -150,7 +150,7 @@ namespace riscv_tlm {
|
||||||
rs1 = get_rs1();
|
rs1 = get_rs1();
|
||||||
mem_addr = get_imm_I();
|
mem_addr = get_imm_I();
|
||||||
|
|
||||||
old_pc = static_cast<std::uint32_t>(regs->getPC());
|
old_pc = regs->getPC();
|
||||||
regs->setValue(rd, old_pc + 4);
|
regs->setValue(rd, old_pc + 4);
|
||||||
|
|
||||||
new_pc = static_cast<std::uint32_t>((regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE);
|
new_pc = static_cast<std::uint32_t>((regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE);
|
||||||
|
|
|
@ -14,13 +14,13 @@ namespace riscv_tlm {
|
||||||
CPU::CPU(sc_core::sc_module_name const &name, std::uint32_t PC, bool debug) :
|
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_module(name), instr_bus("instr_bus"), inst(0), default_time(10,
|
||||||
sc_core::SC_NS), INSTR(0) {
|
sc_core::SC_NS), INSTR(0) {
|
||||||
register_bank = new Registers();
|
register_bank = new Registers<std::uint32_t>();
|
||||||
mem_intf = new MemoryInterface();
|
mem_intf = new MemoryInterface();
|
||||||
|
|
||||||
perf = Performance::getInstance();
|
perf = Performance::getInstance();
|
||||||
|
|
||||||
register_bank->setPC(PC);
|
register_bank->setPC(PC);
|
||||||
register_bank->setValue(Registers::sp, (Memory::SIZE / 4) - 1);
|
register_bank->setValue(Registers<std::uint32_t>::sp, (Memory::SIZE / 4) - 1);
|
||||||
|
|
||||||
irq_line_socket.register_b_transport(this, &CPU::call_interrupt);
|
irq_line_socket.register_b_transport(this, &CPU::call_interrupt);
|
||||||
interrupt = false;
|
interrupt = false;
|
||||||
|
|
|
@ -77,7 +77,7 @@ namespace riscv_tlm {
|
||||||
void Debug::handle_gdb_loop() {
|
void Debug::handle_gdb_loop() {
|
||||||
std::cout << "Handle_GDB_Loop\n";
|
std::cout << "Handle_GDB_Loop\n";
|
||||||
|
|
||||||
Registers *register_bank = dbg_cpu->getRegisterBank();
|
Registers<std::uint32_t> *register_bank = dbg_cpu->getRegisterBank();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
std::string msg = receive_packet();
|
std::string msg = receive_packet();
|
||||||
|
|
|
@ -6,171 +6,4 @@
|
||||||
*/
|
*/
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// 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<std::int32_t>(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<std::uint64_t>(sc_core::sc_time(
|
|
||||||
sc_core::sc_time_stamp()
|
|
||||||
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
|
|
||||||
& 0x00000000FFFFFFFF;
|
|
||||||
break;
|
|
||||||
case CSR_CYCLEH:
|
|
||||||
case CSR_MCYCLEH:
|
|
||||||
ret_value = static_cast<std::uint32_t>((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<std::uint64_t>(sc_core::sc_time(
|
|
||||||
sc_core::sc_time_stamp()
|
|
||||||
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
|
|
||||||
& 0x00000000FFFFFFFF;
|
|
||||||
break;
|
|
||||||
case CSR_TIMEH:
|
|
||||||
ret_value = static_cast<std::uint32_t>((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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,57 +7,3 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#include "extension_base.h"
|
#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;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue