make cpu type in core_complex configurable

This commit is contained in:
2021-05-16 15:06:42 +02:00
parent 9c456ba8f2
commit a35974c9f5
7 changed files with 1746 additions and 543 deletions

View File

@ -31,17 +31,20 @@
*******************************************************************************/
#include "sysc/core_complex.h"
#ifdef CORE_TGC_B
#include "iss/arch/riscv_hart_m_p.h"
#include "iss/arch/tgc_b.h"
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
#endif
#ifdef CORE_TGC_C
#include "iss/arch/riscv_hart_m_p.h"
#include "iss/arch/tgc_c.h"
using core_type = iss::arch::tgc_c;
using plat_type = iss::arch::riscv_hart_m_p<core_type>;
using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
#endif
#ifdef CORE_TGC_D
#include "iss/arch/riscv_hart_mu_p.h"
#include "iss/arch/tgc_d.h"
using core_type = iss::arch::tgc_d;
using plat_type = iss::arch::riscv_hart_mu_p<core_type>;
using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d>;
#endif
#include "iss/debugger/encoderdecoder.h"
#include "iss/debugger/gdb_session.h"
@ -53,6 +56,10 @@ using plat_type = iss::arch::riscv_hart_mu_p<core_type>;
#include <iostream>
#include <sstream>
#define STR(X) #X
#define CREATE_CORE(CN) \
else if (type == STR(CN)) { std::tie(cpu, vm) = create_core<CN ## _plat_type>(backend, gdb_port, hart_id); }
#ifdef WITH_SCV
#include <array>
#include <scv.h>
@ -67,41 +74,17 @@ using namespace sc_core;
namespace {
iss::debugger::encoder_decoder encdec;
}
namespace {
std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
std::array<const char*, 16> trap_str = { {
"Instruction address misaligned",
"Instruction access fault",
"Illegal instruction",
"Breakpoint",
"Load address misaligned",
"Load access fault",
"Store/AMO address misaligned",
"Store/AMO access fault",
"Environment call from U-mode",
"Environment call from S-mode",
"Reserved",
"Environment call from M-mode",
"Instruction page fault",
"Load page fault",
"Reserved",
"Store/AMO page fault"
} };
std::array<const char*, 12> irq_str = { {
"User software interrupt", "Supervisor software interrupt", "Reserved", "Machine software interrupt",
"User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt",
"User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt" } };
}
class core_wrapper : public plat_type {
template<typename PLAT>
class core_wrapper_t : public PLAT {
public:
using phys_addr_t = typename arch::traits<core_type>::phys_addr_t;
core_wrapper(core_complex *owner)
using reg_t = typename arch::traits<typename PLAT::super>::reg_t;
using phys_addr_t = typename arch::traits<typename PLAT::super>::phys_addr_t;
using heart_state_t = typename PLAT::hart_state_type;
core_wrapper_t(core_complex *owner)
: owner(owner) { }
uint32_t get_mode() { return this->reg.PRIV; }
@ -110,10 +93,10 @@ public:
inline bool get_interrupt_execution() { return this->interrupt_sim; }
plat_type::hart_state<plat_type::reg_t> &get_state() { return this->state; }
heart_state_t &get_state() { return this->state; }
void notify_phase(exec_phase p) override {
if (p == ISTART) owner->sync(this->reg.icount + cycle_offset);
void notify_phase(iss::arch_if::exec_phase p) override {
if (p == iss::arch_if::ISTART) owner->sync(this->reg.icount);
}
sync_type needed_sync() const override { return PRE_SYNC; }
@ -122,7 +105,7 @@ public:
if (INFO <= Log<Output2FILE<disass>>::reporting_level() && Output2FILE<disass>::stream()) {
std::stringstream s;
s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0')
<< std::setw(sizeof(reg_t) * 2) << (reg_t)state.mstatus << std::dec << ";c:" << this->reg.icount << "]";
<< std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:" << this->reg.icount << "]";
Log<Output2FILE<disass>>().get(INFO, "disass")
<< "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40)
<< std::setfill(' ') << std::left << instr << s.str();
@ -165,7 +148,7 @@ public:
}
return ret?Ok:Err;
} else {
return plat_type::read_csr(addr, val);
return PLAT::read_csr(addr, val);
}
}
@ -174,11 +157,11 @@ public:
do {
wait(wfi_evt);
} while (this->reg.pending_trap == 0);
plat_type::wait_until(flags);
PLAT::wait_until(flags);
}
void local_irq(short id, bool value) {
plat_type::reg_t mask = 0;
reg_t mask = 0;
switch (id) {
case 16: // SW
mask = 1 << 3;
@ -238,11 +221,82 @@ int cmd_sysc(int argc, char *argv[], debugger::out_func of, debugger::data_func
return Err;
}
using cpu_ptr = std::unique_ptr<iss::arch_if>;
using vm_ptr= std::unique_ptr<iss::vm_if>;
class core_wrapper {
public:
core_wrapper(core_complex *owner) : owner(owner) { }
void reset(uint64_t addr){vm->reset(addr);}
inline void start(){vm->start();}
inline std::pair<uint64_t, bool> load_file(std::string const& name){ return cpu->load_file(name);};
std::function<unsigned(void)> get_mode;
std::function<uint64_t(void)> get_state;
std::function<bool(void)> get_interrupt_execution;
std::function<void(bool)> set_interrupt_execution;
std::function<void(short, bool)> local_irq;
template<typename PLAT>
std::tuple<cpu_ptr, vm_ptr> create_core(std::string const& backend, unsigned gdb_port, uint32_t hart_id){
auto* lcpu = new core_wrapper_t<PLAT>(owner);
lcpu->set_mhartid(hart_id);
get_mode = [lcpu]() { return lcpu->get_mode(); };
get_state = [lcpu]() { return lcpu->get_state().mstatus.backing.val; };
get_interrupt_execution = [lcpu]() { return lcpu->get_interrupt_execution(); };
set_interrupt_execution = [lcpu](bool b) { return lcpu->set_interrupt_execution(b); };
local_irq = [lcpu](short s, bool b) { return lcpu->local_irq(s, b); };
if(backend == "interp")
return {cpu_ptr{lcpu}, vm_ptr{iss::interp::create(lcpu, gdb_port)}};
#ifdef WITH_LLVM
if(backend == "llvm")
return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}};
#endif
#ifdef WITH_TCC
if(backend == "tcc")
s return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}};
#endif
return {nullptr, nullptr};
}
void create_cpu(std::string const& type, std::string const& backend, unsigned gdb_port, uint32_t hart_id){
if (type == "") {
LOG(ERROR) << "Illegal argument value for core type: " << type << std::endl;
}
#ifdef CORE_TGC_B
CREATE_CORE(tgc_c)
#endif
#ifdef CORE_TGC_C
CREATE_CORE(tgc_c)
#endif
#ifdef CORE_TGC_D
CREATE_CORE(tgc_d)
#endif
else {
LOG(ERROR) << "Illegal argument value for core type: " << type << std::endl;
}
auto *srv = debugger::server<debugger::gdb_session>::get();
if (srv) tgt_adapter = srv->get_target();
if (tgt_adapter)
tgt_adapter->add_custom_command(
{"sysc", [this](int argc, char *argv[], debugger::out_func of,
debugger::data_func df) -> int { return cmd_sysc(argc, argv, of, df, tgt_adapter); },
"SystemC sub-commands: break <time>, print_time"});
}
core_complex * const owner;
vm_ptr vm{nullptr};
cpu_ptr cpu{nullptr};
iss::debugger::target_adapter_if *tgt_adapter{nullptr};
};
core_complex::core_complex(sc_module_name name)
: sc_module(name)
, read_lut(tlm_dmi_ext())
, write_lut(tlm_dmi_ext())
, tgt_adapter(nullptr)
#ifdef WITH_SCV
, m_db(scv_tr_db::get_default_db())
, stream_handle(nullptr)
@ -279,40 +333,16 @@ core_complex::~core_complex() = default;
void core_complex::trace(sc_trace_file *trf) const {}
using vm_ptr= std::unique_ptr<iss::vm_if>;
vm_ptr create_cpu(core_wrapper* cpu, std::string const& backend, unsigned gdb_port){
if(backend == "interp")
return vm_ptr{iss::interp::create<core_type>(cpu, gdb_port)};
#ifdef WITH_LLVM
if(backend == "llvm")
return vm_ptr{iss::llvm::create(lcpu, gdb_port)};
#endif
#ifdef WITH_TCC
if(backend == "tcc")
return vm_ptr{iss::tcc::create<core_type>(cpu, gdb_port)};
#endif
return {nullptr};
}
void core_complex::before_end_of_elaboration() {
SCCDEBUG(SCMOD)<<"instantiating iss::arch::tgf with "<<backend.get_value()<<" backend";
cpu = scc::make_unique<core_wrapper>(this);
cpu->set_mhartid(mhartid.get_value());
vm = create_cpu(cpu.get(), backend.get_value(), gdb_server_port.get_value());
sc_assert(vm!=nullptr);
cpu->create_cpu(core_type.get_value(), backend.get_value(), gdb_server_port.get_value(), mhartid.get_value());
sc_assert(cpu->vm!=nullptr);
#ifdef WITH_SCV
vm->setDisassEnabled(enable_disass.get_value() || m_db != nullptr);
cpu->vm->setDisassEnabled(enable_disass.get_value() || m_db != nullptr);
#else
vm->setDisassEnabled(enable_disass.get_value());
#endif
auto *srv = debugger::server<debugger::gdb_session>::get();
if (srv) tgt_adapter = srv->get_target();
if (tgt_adapter)
tgt_adapter->add_custom_command(
{"sysc", [this](int argc, char *argv[], debugger::out_func of,
debugger::data_func df) -> int { return cmd_sysc(argc, argv, of, df, tgt_adapter); },
"SystemC sub-commands: break <time>, print_time"});
}
void core_complex::start_of_simulation() {
@ -344,7 +374,7 @@ void core_complex::disass_output(uint64_t pc, const std::string instr_str) {
tr_handle.record_attribute("PC", pc);
tr_handle.record_attribute("INSTR", instr_str);
tr_handle.record_attribute("MODE", lvl[cpu->get_mode()]);
tr_handle.record_attribute("MSTATUS", cpu->get_state().mstatus.backing.val);
tr_handle.record_attribute("MSTATUS", cpu->get_state());
tr_handle.record_attribute("LTIME_START", quantum_keeper.get_current_time().value() / 1000);
#endif
}
@ -375,7 +405,7 @@ void core_complex::run() {
wait(clk_i.value_changed_event());
}
cpu->set_interrupt_execution(false);
vm->start();
cpu->start();
} while (cpu->get_interrupt_execution());
sc_stop();
}