Two instances of CPU (RV32, RV64). Need to implement RV64 specific instructions.
This commit is contained in:
parent
acf38332d5
commit
fc85c603d4
174
inc/CPU.h
174
inc/CPU.h
|
@ -28,13 +28,28 @@
|
||||||
|
|
||||||
|
|
||||||
namespace riscv_tlm {
|
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:
|
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
|
* @brief Instruction Memory bus socket
|
||||||
* @param trans transction to perfoem
|
* @param trans transction to perfoem
|
||||||
|
@ -49,60 +64,87 @@ namespace riscv_tlm {
|
||||||
*/
|
*/
|
||||||
tlm_utils::simple_target_socket<CPU> irq_line_socket;
|
tlm_utils::simple_target_socket<CPU> 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<spdlog::logger> 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
|
* @brief Constructor
|
||||||
* @param name Module name
|
* @param name Module name
|
||||||
* @param PC Program Counter initialize value
|
* @param PC Program Counter initialize value
|
||||||
* @param debug To start debugging
|
* @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
|
* @brief Destructor
|
||||||
*/
|
*/
|
||||||
~CPU() override;
|
~RV32() override;
|
||||||
|
|
||||||
MemoryInterface *mem_intf;
|
bool CPU_step() override;
|
||||||
|
Registers<BaseType> *getRegisterBank() { return register_bank; }
|
||||||
bool CPU_step();
|
|
||||||
|
|
||||||
|
|
||||||
Registers<std::uint32_t> *getRegisterBank() { return register_bank; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Registers<std::uint32_t> *register_bank;
|
Registers<BaseType> *register_bank;
|
||||||
Performance *perf;
|
C_extension<BaseType> *c_inst;
|
||||||
std::shared_ptr<spdlog::logger> logger;
|
M_extension<BaseType> *m_inst;
|
||||||
C_extension<std::uint32_t> *c_inst;
|
A_extension<BaseType> *a_inst;
|
||||||
M_extension<std::uint32_t> *m_inst;
|
BASE_ISA<BaseType> *exec;
|
||||||
A_extension<std::uint32_t> *a_inst;
|
BaseType int_cause;
|
||||||
BASE_ISA<std::uint32_t> *exec;
|
BaseType INSTR;
|
||||||
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;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @brief Process and triggers IRQ if all conditions met
|
* @brief Process and triggers IRQ if all conditions met
|
||||||
* @return true if IRQ is triggered, false otherwise
|
* @return true if IRQ is triggered, false otherwise
|
||||||
*/
|
*/
|
||||||
bool cpu_process_IRQ();
|
bool cpu_process_IRQ() override;
|
||||||
|
|
||||||
/**
|
|
||||||
* main thread for CPU simulation
|
|
||||||
* @brief CPU mai thread
|
|
||||||
*/
|
|
||||||
[[noreturn]] void CPU_thread();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief callback for IRQ simple socket
|
* @brief callback for IRQ simple socket
|
||||||
|
@ -113,14 +155,58 @@ namespace riscv_tlm {
|
||||||
*/
|
*/
|
||||||
void call_interrupt(tlm::tlm_generic_payload &trans,
|
void call_interrupt(tlm::tlm_generic_payload &trans,
|
||||||
sc_core::sc_time &delay);
|
sc_core::sc_time &delay);
|
||||||
|
}; // RV32 class
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DMI pointer is not longer valid
|
* @brief RISC_V CPU 64 bits model
|
||||||
* @param start memory address region start
|
* @param name name of the module
|
||||||
* @param end memory address region end
|
|
||||||
*/
|
*/
|
||||||
void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end);
|
class RV64 : public CPU {
|
||||||
};
|
public:
|
||||||
|
using BaseType = std::uint64_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
* @param name Module name
|
||||||
|
* @param PC Program Counter initialize value
|
||||||
|
* @param debug To start debugging
|
||||||
|
*/
|
||||||
|
RV64(sc_core::sc_module_name const &name, BaseType PC, bool debug);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destructor
|
||||||
|
*/
|
||||||
|
~RV64() override;
|
||||||
|
|
||||||
|
bool CPU_step() override;
|
||||||
|
Registers<BaseType> *getRegisterBank() { return register_bank; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Registers<BaseType> *register_bank;
|
||||||
|
C_extension<BaseType> *c_inst;
|
||||||
|
M_extension<BaseType> *m_inst;
|
||||||
|
A_extension<BaseType> *a_inst;
|
||||||
|
BASE_ISA<BaseType> *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
|
#endif
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace riscv_tlm {
|
||||||
class Debug : sc_core::sc_module {
|
class Debug : sc_core::sc_module {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Debug(riscv_tlm::CPU *cpu, Memory *mem);
|
Debug(riscv_tlm::RV32 *cpu, Memory *mem);
|
||||||
|
|
||||||
~Debug() override;
|
~Debug() override;
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ namespace riscv_tlm {
|
||||||
static constexpr size_t bufsize = 1024 * 8;
|
static constexpr size_t bufsize = 1024 * 8;
|
||||||
char iobuf[bufsize]{};
|
char iobuf[bufsize]{};
|
||||||
int conn;
|
int conn;
|
||||||
riscv_tlm::CPU *dbg_cpu;
|
riscv_tlm::RV32 *dbg_cpu;
|
||||||
Memory *dbg_mem;
|
Memory *dbg_mem;
|
||||||
tlm::tlm_generic_payload dbg_trans;
|
tlm::tlm_generic_payload dbg_trans;
|
||||||
unsigned char pyld_array[128]{};
|
unsigned char pyld_array[128]{};
|
||||||
|
|
|
@ -407,11 +407,14 @@ namespace riscv_tlm {
|
||||||
|
|
||||||
Performance *perf;
|
Performance *perf;
|
||||||
|
|
||||||
|
void initCSR();
|
||||||
|
/*
|
||||||
void initCSR() {
|
void initCSR() {
|
||||||
CSR[CSR_MISA] = MISA_MXL | MISA_M_EXTENSION | MISA_C_EXTENSION
|
CSR[CSR_MISA] = MISA_MXL | MISA_M_EXTENSION | MISA_C_EXTENSION
|
||||||
| MISA_A_EXTENSION | MISA_I_BASE;
|
| MISA_A_EXTENSION | MISA_I_BASE;
|
||||||
CSR[CSR_MSTATUS] = MISA_MXL;
|
CSR[CSR_MSTATUS] = MISA_MXL;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -80,7 +80,7 @@ namespace riscv_tlm {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pure virtual functions */
|
/* pure virtual functions */
|
||||||
virtual T opcode() const = 0;
|
virtual std::uint32_t opcode() const = 0;
|
||||||
|
|
||||||
virtual unsigned int get_rd() const {
|
virtual unsigned int get_rd() const {
|
||||||
return m_instr.range(11, 7);
|
return m_instr.range(11, 7);
|
||||||
|
|
194
src/CPU.cpp
194
src/CPU.cpp
|
@ -11,37 +11,22 @@ namespace riscv_tlm {
|
||||||
|
|
||||||
SC_HAS_PROCESS(CPU);
|
SC_HAS_PROCESS(CPU);
|
||||||
|
|
||||||
CPU::CPU(sc_core::sc_module_name const &name, std::uint32_t PC, bool debug) :
|
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) {
|
||||||
sc_module(name), instr_bus("instr_bus"), inst(0),
|
|
||||||
default_time(10, sc_core::SC_NS), INSTR(0) {
|
|
||||||
register_bank = new Registers<std::uint32_t>();
|
|
||||||
mem_intf = new MemoryInterface();
|
|
||||||
|
|
||||||
perf = Performance::getInstance();
|
perf = Performance::getInstance();
|
||||||
|
logger = spdlog::get("my_logger");
|
||||||
register_bank->setPC(PC);
|
|
||||||
register_bank->setValue(Registers<std::uint32_t>::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<std::uint32_t>(0, register_bank, mem_intf);
|
|
||||||
c_inst = new C_extension<std::uint32_t>(0, register_bank, mem_intf);
|
|
||||||
m_inst = new M_extension<std::uint32_t>(0, register_bank, mem_intf);
|
|
||||||
a_inst = new A_extension<std::uint32_t>(0, register_bank, mem_intf);
|
|
||||||
|
|
||||||
m_qk = new tlm_utils::tlm_quantumkeeper();
|
m_qk = new tlm_utils::tlm_quantumkeeper();
|
||||||
m_qk->reset();
|
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_command(tlm::TLM_READ_COMMAND);
|
||||||
trans.set_data_ptr(reinterpret_cast<unsigned char *>(&INSTR));
|
|
||||||
trans.set_data_length(4);
|
trans.set_data_length(4);
|
||||||
trans.set_streaming_width(4); // = data_length to indicate no streaming
|
trans.set_streaming_width(4); // = data_length to indicate no streaming
|
||||||
trans.set_byte_enable_ptr(nullptr); // 0 indicates unused
|
trans.set_byte_enable_ptr(nullptr); // 0 indicates unused
|
||||||
|
@ -51,147 +36,12 @@ namespace riscv_tlm {
|
||||||
if (!debug) {
|
if (!debug) {
|
||||||
SC_THREAD(CPU_thread);
|
SC_THREAD(CPU_thread);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
logger = spdlog::get("my_logger");
|
void CPU::invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end) {
|
||||||
}
|
(void) start;
|
||||||
|
(void) end;
|
||||||
CPU::~CPU() {
|
dmi_ptr_valid = false;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] void CPU::CPU_thread() {
|
[[noreturn]] void CPU::CPU_thread() {
|
||||||
|
@ -219,18 +69,4 @@ namespace riscv_tlm {
|
||||||
#endif
|
#endif
|
||||||
} // while(1)
|
} // while(1)
|
||||||
} // CPU_thread
|
} // 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -23,7 +23,7 @@ namespace riscv_tlm {
|
||||||
constexpr char nibble_to_hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
constexpr char nibble_to_hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
'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_cpu = cpu;
|
||||||
dbg_mem = mem;
|
dbg_mem = mem;
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ namespace riscv_tlm {
|
||||||
send_packet(conn, stream.str());
|
send_packet(conn, stream.str());
|
||||||
} else if (boost::starts_with(msg, "p")) {
|
} else if (boost::starts_with(msg, "p")) {
|
||||||
long n = strtol(msg.c_str() + 1, 0, 16);
|
long n = strtol(msg.c_str() + 1, 0, 16);
|
||||||
unsigned int reg_value;
|
std::uint64_t reg_value;
|
||||||
if (n < 32) {
|
if (n < 32) {
|
||||||
reg_value = register_bank->getValue(n);
|
reg_value = register_bank->getValue(n);
|
||||||
} else if (n == 32) {
|
} else if (n == 32) {
|
||||||
|
|
|
@ -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<BaseType>();
|
||||||
|
mem_intf = new MemoryInterface();
|
||||||
|
register_bank->setPC(PC);
|
||||||
|
register_bank->setValue(Registers<BaseType>::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<BaseType>(0, register_bank, mem_intf);
|
||||||
|
c_inst = new C_extension<BaseType>(0, register_bank, mem_intf);
|
||||||
|
m_inst = new M_extension<BaseType>(0, register_bank, mem_intf);
|
||||||
|
a_inst = new A_extension<BaseType>(0, register_bank, mem_intf);
|
||||||
|
|
||||||
|
trans.set_data_ptr(reinterpret_cast<unsigned char *>(&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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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<BaseType>();
|
||||||
|
mem_intf = new MemoryInterface();
|
||||||
|
register_bank->setPC(PC);
|
||||||
|
register_bank->setValue(Registers<BaseType>::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<BaseType>(0, register_bank, mem_intf);
|
||||||
|
c_inst = new C_extension<BaseType>(0, register_bank, mem_intf);
|
||||||
|
m_inst = new M_extension<BaseType>(0, register_bank, mem_intf);
|
||||||
|
a_inst = new A_extension<BaseType>(0, register_bank, mem_intf);
|
||||||
|
|
||||||
|
trans.set_data_ptr(reinterpret_cast<unsigned char *>(&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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -6,4 +6,21 @@
|
||||||
*/
|
*/
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "Registers.h"
|
||||||
|
|
||||||
|
namespace riscv_tlm {
|
||||||
|
/* Specialization for each XLEN (RV32, RV64)*/
|
||||||
|
template<>
|
||||||
|
void Registers<std::uint32_t>::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<std::uint64_t>::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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,12 +24,16 @@
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
#include "spdlog/sinks/basic_file_sink.h"
|
#include "spdlog/sinks/basic_file_sink.h"
|
||||||
|
|
||||||
|
typedef enum {RV32, RV64} cpu_types_t;
|
||||||
|
|
||||||
std::string filename;
|
std::string filename;
|
||||||
bool debug_session = false;
|
bool debug_session = false;
|
||||||
bool mem_dump = false;
|
bool mem_dump = false;
|
||||||
uint32_t dump_addr_st = 0;
|
uint32_t dump_addr_st = 0;
|
||||||
uint32_t dump_addr_end = 0;
|
uint32_t dump_addr_end = 0;
|
||||||
|
|
||||||
|
cpu_types_t cpu_type_opt = RV32;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Simulator
|
* @class Simulator
|
||||||
* This class instantiates all necessary modules, connects its ports and starts
|
* This class instantiates all necessary modules, connects its ports and starts
|
||||||
|
@ -45,13 +49,17 @@ public:
|
||||||
riscv_tlm::peripherals::Trace *trace;
|
riscv_tlm::peripherals::Trace *trace;
|
||||||
riscv_tlm::peripherals::Timer *timer;
|
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;
|
std::uint32_t start_PC;
|
||||||
|
|
||||||
MainMemory = new riscv_tlm::Memory("Main_Memory", filename);
|
MainMemory = new riscv_tlm::Memory("Main_Memory", filename);
|
||||||
start_PC = MainMemory->getPCfromHEX();
|
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");
|
Bus = new riscv_tlm::BusCtrl("BusCtrl");
|
||||||
trace = new riscv_tlm::peripherals::Trace("Trace");
|
trace = new riscv_tlm::peripherals::Trace("Trace");
|
||||||
|
@ -67,7 +75,7 @@ public:
|
||||||
timer->irq_line.bind(cpu->irq_line_socket);
|
timer->irq_line.bind(cpu->irq_line_socket);
|
||||||
|
|
||||||
if (debug_session) {
|
if (debug_session) {
|
||||||
riscv_tlm::Debug debug(cpu, MainMemory);
|
//riscv_tlm::Debug debug(cpu, MainMemory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +91,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void MemoryDump() {
|
void MemoryDump() const {
|
||||||
std::cout << "********** MEMORY DUMP ***********\n";
|
std::cout << "********** MEMORY DUMP ***********\n";
|
||||||
tlm::tlm_generic_payload trans;
|
tlm::tlm_generic_payload trans;
|
||||||
tlm::tlm_dmi dmi_data;
|
tlm::tlm_dmi dmi_data;
|
||||||
|
@ -134,8 +142,9 @@ void process_arguments(int argc, char *argv[]) {
|
||||||
int debug_level;
|
int debug_level;
|
||||||
|
|
||||||
debug_session = false;
|
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) {
|
switch (c) {
|
||||||
case 'D':
|
case 'D':
|
||||||
debug_session = true;
|
debug_session = true;
|
||||||
|
@ -173,6 +182,13 @@ void process_arguments(int argc, char *argv[]) {
|
||||||
case 'f':
|
case 'f':
|
||||||
filename = std::string(optarg);
|
filename = std::string(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'R':
|
||||||
|
if (strcmp(optarg, "RV32") == 0) {
|
||||||
|
cpu_type_opt = RV32;
|
||||||
|
} else {
|
||||||
|
cpu_type_opt = RV64;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
std::cout << "Call ./RISCV_TLM -D -L <debuglevel> (0..3) filename.hex"
|
std::cout << "Call ./RISCV_TLM -D -L <debuglevel> (0..3) filename.hex"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
@ -199,15 +215,15 @@ int sc_main(int argc, char *argv[]) {
|
||||||
/* SystemC time resolution set to 1 ns*/
|
/* SystemC time resolution set to 1 ns*/
|
||||||
sc_core::sc_set_time_resolution(1, sc_core::SC_NS);
|
sc_core::sc_set_time_resolution(1, sc_core::SC_NS);
|
||||||
|
|
||||||
spdlog::filename_t filename = SPDLOG_FILENAME_T("newlog.txt");
|
spdlog::filename_t log_filename = SPDLOG_FILENAME_T("newlog.txt");
|
||||||
logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("my_logger", filename);
|
logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("my_logger", log_filename);
|
||||||
logger->set_pattern("%v");
|
logger->set_pattern("%v");
|
||||||
logger->set_level(spdlog::level::info);
|
logger->set_level(spdlog::level::info);
|
||||||
|
|
||||||
/* Parse and process program arguments. -f is mandatory */
|
/* Parse and process program arguments. -f is mandatory */
|
||||||
process_arguments(argc, argv);
|
process_arguments(argc, argv);
|
||||||
|
|
||||||
top = new Simulator("top");
|
top = new Simulator("top", cpu_type_opt);
|
||||||
|
|
||||||
auto start = std::chrono::steady_clock::now();
|
auto start = std::chrono::steady_clock::now();
|
||||||
sc_core::sc_start();
|
sc_core::sc_start();
|
||||||
|
|
Loading…
Reference in New Issue