From 2f8ee6e89dde2d74d9277a979dd6eff21060b40b Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Thu, 6 Jul 2023 08:02:48 +0200 Subject: [PATCH] extends factory to support SystemC core wrapper --- CMakeLists.txt | 5 +- gen_input/templates/interp/CORENAME.cpp.gtl | 21 ++- gen_input/templates/tcc/CORENAME.cpp.gtl | 21 ++- src/iss/factory.h | 48 +++++++ src/main.cpp | 59 ++------ src/sysc/register_tgc_c.cpp | 33 +++++ src/sysc/sc_core_adapter.h | 148 ++++++++++++++++++++ src/vm/interp/vm_tgc_c.cpp | 21 ++- src/vm/tcc/vm_tgc_c.cpp | 23 ++- 9 files changed, 325 insertions(+), 54 deletions(-) create mode 100644 src/sysc/register_tgc_c.cpp create mode 100644 src/sysc/sc_core_adapter.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a36dad..c79d882 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,7 +186,10 @@ install(TARGETS tgc-sim ############################################################################### if(TARGET scc-sysc) project(dbt-rise-tgc_sc VERSION 1.0.0) - add_library(${PROJECT_NAME} src/sysc/core_complex.cpp) + add_library(${PROJECT_NAME} + src/sysc/core_complex.cpp + src/sysc/register_tgc_c.cpp + ) target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC) target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME}) foreach(F IN LISTS TGC_SOURCES) diff --git a/gen_input/templates/interp/CORENAME.cpp.gtl b/gen_input/templates/interp/CORENAME.cpp.gtl index acf7afd..6db2e4a 100644 --- a/gen_input/templates/interp/CORENAME.cpp.gtl +++ b/gen_input/templates/interp/CORENAME.cpp.gtl @@ -34,10 +34,9 @@ def nativeTypeSize(int size){ if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64; } %> +#include #include #include -#include -#include #include #include #include @@ -315,3 +314,21 @@ std::unique_ptr create(arch::${coreD } } // namespace interp } // namespace iss + +#include +#include +#include +namespace iss { +namespace { +volatile std::array dummy = { + core_factory::instance().register_creator("${coreDef.name.toLowerCase()|m_p|interp", [](unsigned gdb_port) -> std::tuple{ + auto* lcpu = new iss::arch::riscv_hart_m_p(); + return {cpu_ptr{lcpu}, vm_ptr{iss::interp::create(lcpu, gdb_port)}}; + }), + core_factory::instance().register_creator("${coreDef.name.toLowerCase()|mu_p|interp", [](unsigned gdb_port) -> std::tuple{ + auto* lcpu = new iss::arch::riscv_hart_mu_p(); + return {cpu_ptr{lcpu}, vm_ptr{iss::interp::create(lcpu, gdb_port)}}; + }) +}; +} +} diff --git a/gen_input/templates/tcc/CORENAME.cpp.gtl b/gen_input/templates/tcc/CORENAME.cpp.gtl index 9ce0e26..efdb396 100644 --- a/gen_input/templates/tcc/CORENAME.cpp.gtl +++ b/gen_input/templates/tcc/CORENAME.cpp.gtl @@ -31,7 +31,6 @@ *******************************************************************************/ #include -#include #include #include #include @@ -310,5 +309,23 @@ std::unique_ptr create(arch::${coreD if (port != 0) debugger::server::run_server(ret, port); return std::unique_ptr(ret); } -} +} // namesapce tcc } // namespace iss + +#include +#include +#include +namespace iss { +namespace { +volatile std::array dummy = { + core_factory::instance().register_creator("${coreDef.name.toLowerCase()|m_p|interp", [](unsigned gdb_port) -> std::tuple{ + auto* lcpu = new iss::arch::riscv_hart_m_p(); + return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}}; + }), + core_factory::instance().register_creator("${coreDef.name.toLowerCase()|mu_p|interp", [](unsigned gdb_port) -> std::tuple{ + auto* lcpu = new iss::arch::riscv_hart_mu_p(); + return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}}; + }) +}; +} +} diff --git a/src/iss/factory.h b/src/iss/factory.h index 0d43538..7e45838 100644 --- a/src/iss/factory.h +++ b/src/iss/factory.h @@ -34,6 +34,12 @@ #define _ISS_FACTORY_H_ #include +#include +#include +#include +#include +#include +#include namespace iss { @@ -57,6 +63,48 @@ std::tuple create_cpu(std::string const& backend, unsigned gdb_ return {nullptr, nullptr}; } + +class core_factory { + using cpu_ptr = std::unique_ptr; + using vm_ptr= std::unique_ptr; + using base_t = std::tuple; + using create_fn = std::function; + using registry_t = std::unordered_map ; + + registry_t registry; + + core_factory() = default; + core_factory(const core_factory &) = delete; + core_factory & operator=(const core_factory &) = delete; + +public: + static core_factory & instance() { static core_factory bf; return bf; } + + bool register_creator(const std::string &, create_fn const&); + + base_t create(const std::string &, unsigned gdb_port=0, void* init_data=nullptr) const; + + std::vector get_names() { + std::vector keys{registry.size()}; + std::transform(std::begin(registry), std::end(registry), std::begin(keys), [](std::pair const& p){ + return p.first; + }); + return keys; + } +}; + +inline bool core_factory::register_creator(const std::string & className, create_fn const& fn) { + registry[className] = fn; + return true; +} + +inline core_factory::base_t core_factory::create(const std::string &className, unsigned gdb_port, void* data) const { + registry_t::const_iterator regEntry = registry.find(className); + if (regEntry != registry.end()) + return regEntry->second(gdb_port, data); + return {nullptr, nullptr}; +} + } #endif /* _ISS_FACTORY_H_ */ diff --git a/src/main.cpp b/src/main.cpp index 5aeb3f8..02ec210 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -33,7 +33,7 @@ #include #include #include -#include "iss/factory.h" +#include #include #include @@ -113,53 +113,24 @@ int main(int argc, char *argv[]) { iss::init_jit_debug(argc, argv); #endif bool dump = clim.count("dump-ir"); + auto & f = iss::core_factory::instance(); // instantiate the simulator iss::vm_ptr vm{nullptr}; iss::cpu_ptr cpu{nullptr}; std::string isa_opt(clim["isa"].as()); - if (isa_opt == "tgc_c") { - std::tie(cpu, vm) = - iss::create_cpu(clim["backend"].as(), clim["gdb-port"].as()); - } else -#ifdef CORE_TGC_B - if (isa_opt == "tgc_b") { - std::tie(cpu, vm) = - iss::create_cpu(clim["backend"].as(), clim["gdb-port"].as()); - } else -#endif -#ifdef CORE_TGC_C_XRB_NN - if (isa_opt == "tgc_c_xrb_nn") { - std::tie(cpu, vm) = - iss::create_cpu(clim["backend"].as(), clim["gdb-port"].as()); - } else -#endif -#ifdef CORE_TGC_D - if (isa_opt == "tgc_d") { - std::tie(cpu, vm) = - iss::create_cpu(clim["backend"].as(), clim["gdb-port"].as()); - } else -#endif -#ifdef CORE_TGC_D_XRB_MAC - if (isa_opt == "tgc_d_xrb_mac") { - std::tie(cpu, vm) = - iss::create_cpu(clim["backend"].as(), clim["gdb-port"].as()); - } else -#endif -#ifdef CORE_TGC_D_XRB_NN - if (isa_opt == "tgc_d_xrb_nn") { - std::tie(cpu, vm) = - iss::create_cpu(clim["backend"].as(), clim["gdb-port"].as()); - } else -#endif -#ifdef CORE_TGC_E - if (isa_opt == "tgc_e") { - std::tie(cpu, vm) = - iss::create_cpu(clim["backend"].as(), clim["gdb-port"].as()); - } else -#endif - { - LOG(ERR) << "Illegal argument value for '--isa': " << isa_opt << std::endl; - return 127; + if(isa_opt.size()==0 || isa_opt == "?") { + std::cout<<"Available cores: "<(), clim["gdb-port"].as()); + } else { + auto base_isa = isa_opt.substr(0, 5); + if(base_isa=="tgc_d" || base_isa=="tgc_e") { + isa_opt += "|mu_p_clic_pmp|"+clim["backend"].as(); + } else { + isa_opt += "|m_p|"+clim["backend"].as(); + } + std::tie(cpu, vm) = f.create(isa_opt, clim["gdb-port"].as()); } if(!cpu ){ LOG(ERR) << "Could not create cpu for isa " << isa_opt << " and backend " <()<< std::endl; diff --git a/src/sysc/register_tgc_c.cpp b/src/sysc/register_tgc_c.cpp new file mode 100644 index 0000000..2394afe --- /dev/null +++ b/src/sysc/register_tgc_c.cpp @@ -0,0 +1,33 @@ +/* + * register_tgc_c.cpp + * + * Created on: Jul 5, 2023 + * Author: eyck + */ + + + + +#include +#include +#include +#include +#include "sc_core_adapter.h" +#include "core_complex.h" + +namespace iss { +namespace { +volatile std::array dummy = { + core_factory::instance().register_creator("tgc_c|m_p|interp", [](unsigned gdb_port, void* data) -> std::tuple{ + auto cc = reinterpret_cast(data); + arch::tgc_c* lcpu = new sc_core_adapter>(cc); + return {cpu_ptr{lcpu}, vm_ptr{interp::create(lcpu, gdb_port)}}; + }), + core_factory::instance().register_creator("tgc_c|mu_p|interp", [](unsigned gdb_port, void* data) -> std::tuple{ + auto cc = reinterpret_cast(data); + arch::tgc_c* lcpu = new sc_core_adapter>(cc); + return {cpu_ptr{lcpu}, vm_ptr{interp::create(lcpu, gdb_port)}}; + }) +}; +} +} diff --git a/src/sysc/sc_core_adapter.h b/src/sysc/sc_core_adapter.h new file mode 100644 index 0000000..baaa43b --- /dev/null +++ b/src/sysc/sc_core_adapter.h @@ -0,0 +1,148 @@ +/* + * sc_core_adapter.h + * + * Created on: Jul 5, 2023 + * Author: eyck + */ + +#ifndef _SYSC_SC_CORE_ADAPTER_H_ +#define _SYSC_SC_CORE_ADAPTER_H_ + + +#include +#include +#include "core_complex.h" +#include +#include +#include + + +template +class sc_core_adapter : public PLAT { +public: + using reg_t = typename iss::arch::traits::reg_t; + using phys_addr_t = typename iss::arch::traits::phys_addr_t; + using heart_state_t = typename PLAT::hart_state_type; + sc_core_adapter(sysc::tgfs::core_complex *owner) + : owner(owner) { } + + uint32_t get_mode() { return this->reg.PRIV; } + + inline void set_interrupt_execution(bool v) { this->interrupt_sim = v?1:0; } + + inline bool get_interrupt_execution() { return this->interrupt_sim; } + + heart_state_t &get_state() { return this->state; } + + void notify_phase(iss::arch_if::exec_phase p) override { + if (p == iss::arch_if::ISTART) + owner->sync(this->instr_if.get_total_cycles()); + } + + iss::sync_type needed_sync() const override { return iss::PRE_SYNC; } + + void disass_output(uint64_t pc, const std::string instr) override { + static constexpr std::array lvl = {{'U', 'S', 'H', 'M'}}; + if (!owner->disass_output(pc, instr)) { + std::stringstream s; + s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0') + << std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:" + << this->reg.icount + this->cycle_offset << "]"; + SCCDEBUG(owner->name())<<"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(); + } + }; + + iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data) override { + if (addr.access && iss::access_type::DEBUG) + return owner->read_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err; + else { + return owner->read_mem(addr.val, length, data, is_fetch(addr.access)) ? iss::Ok : iss::Err; + } + } + + iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data) override { + if (addr.access && iss::access_type::DEBUG) + return owner->write_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err; + else { + auto res = owner->write_mem(addr.val, length, data) ? iss::Ok : iss::Err; + // clear MTIP on mtimecmp write + if (addr.val == 0x2004000) { + reg_t val; + this->read_csr(iss::arch::mip, val); + if (val & (1ULL << 7)) this->write_csr(iss::arch::mip, val & ~(1ULL << 7)); + } + return res; + } + } + + iss::status read_csr(unsigned addr, reg_t &val) override { +#ifndef CWR_SYSTEMC + if((addr==iss::arch::time || addr==iss::arch::timeh) && owner->mtime_o.get_interface(0)){ + uint64_t time_val; + bool ret = owner->mtime_o->nb_peek(time_val); + if (addr == iss::arch::time) { + val = static_cast(time_val); + } else if (addr == iss::arch::timeh) { + if (sizeof(reg_t) != 4) return iss::Err; + val = static_cast(time_val >> 32); + } + return ret?Ok:Err; +#else + if((addr==iss::arch::time || addr==iss::arch::timeh)){ + uint64_t time_val = owner->mtime_i.read(); + if (addr == iss::arch::time) { + val = static_cast(time_val); + } else if (addr == iss::arch::timeh) { + if (sizeof(reg_t) != 4) return iss::Err; + val = static_cast(time_val >> 32); + } + return iss::Ok; +#endif + } else { + return PLAT::read_csr(addr, val); + } + } + + void wait_until(uint64_t flags) override { + SCCDEBUG(owner->name()) << "Sleeping until interrupt"; + while(this->reg.pending_trap == 0 && (this->csr[iss::arch::mip] & this->csr[iss::arch::mie]) == 0) { + sc_core::wait(wfi_evt); + } + PLAT::wait_until(flags); + } + + void local_irq(short id, bool value) { + reg_t mask = 0; + switch (id) { + case 3: // SW + mask = 1 << 3; + break; + case 7: // timer + mask = 1 << 7; + break; + case 11: // external + mask = 1 << 11; + break; + default: + if(id>15) mask = 1 << id; + break; + } + if (value) { + this->csr[iss::arch::mip] |= mask; + wfi_evt.notify(); + } else + this->csr[iss::arch::mip] &= ~mask; + this->check_interrupt(); + if(value) + SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap; + } + +private: + sysc::tgfs::core_complex *const owner; + sc_event wfi_evt; +}; + + +#endif /* _SYSC_SC_CORE_ADAPTER_H_ */ diff --git a/src/vm/interp/vm_tgc_c.cpp b/src/vm/interp/vm_tgc_c.cpp index e59d80d..f4ea755 100644 --- a/src/vm/interp/vm_tgc_c.cpp +++ b/src/vm/interp/vm_tgc_c.cpp @@ -30,10 +30,9 @@ * *******************************************************************************/ +#include #include #include -#include -#include #include #include #include @@ -2646,3 +2645,21 @@ std::unique_ptr create(arch::tgc_c *core, unsigned short por } } // namespace interp } // namespace iss + +#include +#include +#include +namespace iss { +namespace { +volatile std::array dummy = { + core_factory::instance().register_creator("tgc_c|m_p|interp", [](unsigned gdb_port, void*) -> std::tuple{ + arch::tgc_c* lcpu = new arch::riscv_hart_m_p(); + return {cpu_ptr{lcpu}, vm_ptr{interp::create(lcpu, gdb_port)}}; + }), + core_factory::instance().register_creator("tgc_c|mu_p|interp", [](unsigned gdb_port, void*) -> std::tuple{ + arch::tgc_c* lcpu = new arch::riscv_hart_mu_p(); + return {cpu_ptr{lcpu}, vm_ptr{interp::create(lcpu, gdb_port)}}; + }) +}; +} +} diff --git a/src/vm/tcc/vm_tgc_c.cpp b/src/vm/tcc/vm_tgc_c.cpp index f68372f..c33bea5 100644 --- a/src/vm/tcc/vm_tgc_c.cpp +++ b/src/vm/tcc/vm_tgc_c.cpp @@ -31,7 +31,6 @@ *******************************************************************************/ #include -#include #include #include #include @@ -3211,7 +3210,7 @@ template void vm_impl::gen_trap_behavior(tu_builder& tu) { tu("return *next_pc;"); } -} // namespace mnrv32 +} // namespace tgc_c template <> std::unique_ptr create(arch::tgc_c *core, unsigned short port, bool dump) { @@ -3219,5 +3218,23 @@ std::unique_ptr create(arch::tgc_c *core, unsigned short por if (port != 0) debugger::server::run_server(ret, port); return std::unique_ptr(ret); } -} +} // namesapce tcc } // namespace iss + +#include +#include +#include +namespace iss { +namespace { +volatile std::array dummy = { + core_factory::instance().register_creator("tgc_c|m_p|tcc", [](unsigned gdb_port, void*) -> std::tuple{ + arch::tgc_c* lcpu = new arch::riscv_hart_m_p(); + return {cpu_ptr{lcpu}, vm_ptr{tcc::create(lcpu, gdb_port)}}; + }), + core_factory::instance().register_creator("tgc_c|mu_p|tcc", [](unsigned gdb_port, void*) -> std::tuple{ + arch::tgc_c* lcpu = new arch::riscv_hart_mu_p(); + return {cpu_ptr{lcpu}, vm_ptr{tcc::create(lcpu, gdb_port)}}; + }) +}; +} +}