From 957145ca84a08c957950a7ff832182862e9a0728 Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Fri, 14 Jul 2023 11:11:03 +0200 Subject: [PATCH 01/14] add SystemC ISS factory --- CMakeLists.txt | 33 ++------ gen_input/templates/interp/CORENAME.cpp.gtl | 4 +- gen_input/templates/tcc/CORENAME.cpp.gtl | 4 +- src/iss/factory.h | 24 +++--- src/sysc/core_complex.cpp | 27 ++++--- src/sysc/iss_factory.h | 88 +++++++++++++++++++++ src/sysc/register_tgc_c.cpp | 19 ++--- src/sysc/sc_core_adapter.h | 6 +- src/sysc/sc_core_adapter_if.h | 5 +- src/vm/tcc/vm_tgc_c.cpp | 4 +- 10 files changed, 144 insertions(+), 70 deletions(-) create mode 100644 src/sysc/iss_factory.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d7977b3..a2a546f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -177,40 +177,32 @@ install(TARGETS tgc-sim # ############################################################################### if(TARGET scc-sysc) - if(BUILD_SHARED_LIBS) - set(DBT_RISE_SC_LIB_NAME dbt-rise-tgc_sc) - else() - set(DBT_RISE_SC_LIB_NAME dbt-rise-tgc_sc_lib) - set(CREATE_INTERFACE_LIB ON) - endif() project(dbt-rise-tgc_sc VERSION 1.0.0) - - add_library(${DBT_RISE_SC_LIB_NAME} + add_library(${PROJECT_NAME} src/sysc/core_complex.cpp src/sysc/register_tgc_c.cpp ) - target_include_directories(${DBT_RISE_SC_LIB_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) - target_compile_definitions(${DBT_RISE_SC_LIB_NAME} PUBLIC WITH_SYSTEMC) - target_compile_definitions(${DBT_RISE_SC_LIB_NAME} PRIVATE CORE_${CORE_NAME}) + target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC) + target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME}) foreach(F IN LISTS TGC_SOURCES) if (${F} MATCHES ".*/arch/([^/]*)\.cpp") string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F}) string(TOUPPER ${CORE_NAME_LC} CORE_NAME) - target_compile_definitions(${DBT_RISE_SC_LIB_NAME} PRIVATE CORE_${CORE_NAME}) + target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME}) endif() endforeach() - target_link_libraries(${DBT_RISE_SC_LIB_NAME} PUBLIC dbt-rise-tgc scc-sysc) + target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc-sysc) if(WITH_LLVM) - target_link_libraries(${DBT_RISE_SC_LIB_NAME} PUBLIC ${llvm_libs}) + target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs}) endif() set(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/sysc/core_complex.h) - set_target_properties(${DBT_RISE_SC_LIB_NAME} PROPERTIES + set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION} FRAMEWORK FALSE PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers ) - install(TARGETS ${DBT_RISE_SC_LIB_NAME} COMPONENT ${PROJECT_NAME} + install(TARGETS ${PROJECT_NAME} COMPONENT ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Targets # for downstream dependencies ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # static lib RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # binaries @@ -219,14 +211,5 @@ if(TARGET scc-sysc) PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sysc # headers for mac (note the different component -> different package) INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers ) - if(CREATE_INTERFACE_LIB) - add_library(dbt-rise-tgc_sc INTERFACE) - target_include_directories(dbt-rise-tgc_sc INTERFACE - $) - target_link_libraries(dbt-rise-tgc_sc INTERFACE - -Wl,--whole-archive,$,--no-whole-archive - $ - scc-sysc) - endif() endif() diff --git a/gen_input/templates/interp/CORENAME.cpp.gtl b/gen_input/templates/interp/CORENAME.cpp.gtl index 5d6cc35..5629249 100644 --- a/gen_input/templates/interp/CORENAME.cpp.gtl +++ b/gen_input/templates/interp/CORENAME.cpp.gtl @@ -321,13 +321,13 @@ std::unique_ptr create(arch::${coreD namespace iss { namespace { volatile std::array dummy = { - core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned port, void*) -> std::tuple{ + core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned port, void*) -> std::tuple{ auto* cpu = new iss::arch::riscv_hart_m_p(); auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl(*cpu, false); if (port != 0) debugger::server::run_server(vm, port); return {cpu_ptr{cpu}, vm_ptr{vm}}; }), - core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned port, void*) -> std::tuple{ + core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned port, void*) -> std::tuple{ auto* cpu = new iss::arch::riscv_hart_mu_p(); auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl(*cpu, false); if (port != 0) debugger::server::run_server(vm, port); diff --git a/gen_input/templates/tcc/CORENAME.cpp.gtl b/gen_input/templates/tcc/CORENAME.cpp.gtl index 1b000ea..2121964 100644 --- a/gen_input/templates/tcc/CORENAME.cpp.gtl +++ b/gen_input/templates/tcc/CORENAME.cpp.gtl @@ -318,13 +318,13 @@ std::unique_ptr create(arch::${coreD namespace iss { namespace { volatile std::array dummy = { - core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned port, void*) -> std::tuple{ + core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned port, void*) -> std::tuple{ auto* cpu = new iss::arch::riscv_hart_m_p(); auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl(*cpu, false); if (port != 0) debugger::server::run_server(vm, port); return {cpu_ptr{cpu}, vm_ptr{vm}}; }), - core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned port, void*) -> std::tuple{ + core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned port, void*) -> std::tuple{ auto* cpu = new iss::arch::riscv_hart_mu_p(); auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl(*cpu, false); if (port != 0) debugger::server::run_server(vm, port); diff --git a/src/iss/factory.h b/src/iss/factory.h index 7e45838..c24fefb 100644 --- a/src/iss/factory.h +++ b/src/iss/factory.h @@ -80,9 +80,17 @@ class core_factory { public: static core_factory & instance() { static core_factory bf; return bf; } - bool register_creator(const std::string &, create_fn const&); + bool register_creator(const std::string & className, create_fn const& fn) { + registry[className] = fn; + return true; + } - base_t create(const std::string &, unsigned gdb_port=0, void* init_data=nullptr) const; + base_t create(std::string const& className, unsigned gdb_port=0, void* init_data=nullptr) const { + registry_t::const_iterator regEntry = registry.find(className); + if (regEntry != registry.end()) + return regEntry->second(gdb_port, init_data); + return {nullptr, nullptr}; + } std::vector get_names() { std::vector keys{registry.size()}; @@ -93,18 +101,6 @@ public: } }; -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/sysc/core_complex.cpp b/src/sysc/core_complex.cpp index e3b0433..be25f53 100644 --- a/src/sysc/core_complex.cpp +++ b/src/sysc/core_complex.cpp @@ -37,7 +37,7 @@ #include #include #include -#include +#include "iss_factory.h" #ifndef WIN32 #include #endif @@ -128,7 +128,9 @@ public: void reset(uint64_t addr){vm->reset(addr);} inline void start(){vm->start();} - inline std::pair load_file(std::string const& name){ return cpu->load_file(name);}; + inline std::pair load_file(std::string const& name){ + iss::arch_if* cc = cpu->get_arch_if(); + return cc->load_file(name);}; std::function get_mode; std::function get_state; @@ -137,7 +139,7 @@ public: std::function local_irq; void create_cpu(std::string const& type, std::string const& backend, unsigned gdb_port, uint32_t hart_id){ - auto & f = iss::core_factory::instance(); + auto & f = sysc::iss_factory::instance(); if(type.size()==0 || type == "?") { std::cout<<"Available cores: "<(*cpu).set_mhartid(hart_id); - get_mode = [this]() { return reinterpret_cast(*cpu).get_mode(); }; - get_state = [this]() { return reinterpret_cast(*cpu).get_state(); }; - get_interrupt_execution = [this]() { return reinterpret_cast(*cpu).get_interrupt_execution(); }; - set_interrupt_execution = [this](bool b) { return reinterpret_cast(*cpu).set_interrupt_execution(b); }; - local_irq = [this](short s, bool b) { return reinterpret_cast(*cpu).local_irq(s, b); }; + auto* sc_cpu_if = reinterpret_cast(cpu.get()); + sc_cpu_if->set_mhartid(hart_id); + get_mode = [sc_cpu_if]() { return sc_cpu_if->get_mode(); }; + get_state = [sc_cpu_if]() { return sc_cpu_if->get_state(); }; + get_interrupt_execution = [sc_cpu_if]() { return sc_cpu_if->get_interrupt_execution(); }; + set_interrupt_execution = [sc_cpu_if](bool b) { return sc_cpu_if->set_interrupt_execution(b); }; + local_irq = [sc_cpu_if](short s, bool b) { return sc_cpu_if->local_irq(s, b); }; auto *srv = debugger::server::get(); if (srv) tgt_adapter = srv->get_target(); @@ -176,7 +179,7 @@ public: core_complex * const owner; vm_ptr vm{nullptr}; - cpu_ptr cpu{nullptr}; + sc_cpu_ptr cpu{nullptr}; iss::debugger::target_adapter_if *tgt_adapter{nullptr}; }; diff --git a/src/sysc/iss_factory.h b/src/sysc/iss_factory.h new file mode 100644 index 0000000..f29a5b0 --- /dev/null +++ b/src/sysc/iss_factory.h @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (C) 2021 MINRES Technologies GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************************/ + +#ifndef _ISS_FACTORY_H_ +#define _ISS_FACTORY_H_ + +#include +#include "sc_core_adapter_if.h" +#include +#include +#include +#include +#include +#include + +namespace sysc { + +using sc_cpu_ptr = std::unique_ptr; +using vm_ptr= std::unique_ptr; + +class iss_factory { +public: + using base_t = std::tuple; + using create_fn = std::function; + using registry_t = std::unordered_map ; + + iss_factory() = default; + iss_factory(const iss_factory &) = delete; + iss_factory & operator=(const iss_factory &) = delete; + + static iss_factory & instance() { static iss_factory bf; return bf; } + + bool register_creator(const std::string & className, create_fn const& fn) { + registry[className] = fn; + return true; + } + + base_t create(std::string const& className, unsigned gdb_port=0, void* init_data=nullptr) const { + registry_t::const_iterator regEntry = registry.find(className); + if (regEntry != registry.end()) + return regEntry->second(gdb_port, init_data); + return {nullptr, nullptr}; + } + + 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; + } +private: + registry_t registry; + +}; + +} + +#endif /* _ISS_FACTORY_H_ */ diff --git a/src/sysc/register_tgc_c.cpp b/src/sysc/register_tgc_c.cpp index 1fe4194..efd46b0 100644 --- a/src/sysc/register_tgc_c.cpp +++ b/src/sysc/register_tgc_c.cpp @@ -30,7 +30,7 @@ * *******************************************************************************/ -#include +#include "iss_factory.h" #include #include #include @@ -39,16 +39,17 @@ namespace iss { namespace interp { +using namespace sysc; volatile std::array tgc_init = { - 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* cpu = new sc_core_adapter>(cc); - return {cpu_ptr{cpu}, vm_ptr{create(cpu, gdb_port)}}; + iss_factory::instance().register_creator("tgc_c|m_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t { + auto* cc = reinterpret_cast(data); + auto* cpu = new sc_core_adapter>(cc); + return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), 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* cpu = new sc_core_adapter>(cc); - return {cpu_ptr{cpu}, vm_ptr{create(cpu, gdb_port)}}; + iss_factory::instance().register_creator("tgc_c|mu_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t { + auto* cc = reinterpret_cast(data); + auto* cpu = new sc_core_adapter>(cc); + return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; }) }; } diff --git a/src/sysc/sc_core_adapter.h b/src/sysc/sc_core_adapter.h index 77c293f..bbd1465 100644 --- a/src/sysc/sc_core_adapter.h +++ b/src/sysc/sc_core_adapter.h @@ -16,6 +16,7 @@ #include #include +namespace sysc { template class sc_core_adapter : public PLAT, public sc_core_adapter_if { public: @@ -25,6 +26,8 @@ public: sc_core_adapter(sysc::tgfs::core_complex *owner) : owner(owner) { } + iss::arch_if* get_arch_if() override { return this;} + void set_mhartid(unsigned id) override { PLAT::set_mhartid(id); } uint32_t get_mode() override { return this->reg.PRIV; } @@ -144,6 +147,5 @@ private: sysc::tgfs::core_complex *const owner; sc_core::sc_event wfi_evt; }; - - +} #endif /* _SYSC_SC_CORE_ADAPTER_H_ */ diff --git a/src/sysc/sc_core_adapter_if.h b/src/sysc/sc_core_adapter_if.h index 5445ee0..05a2c61 100644 --- a/src/sysc/sc_core_adapter_if.h +++ b/src/sysc/sc_core_adapter_if.h @@ -16,7 +16,9 @@ #include #include +namespace sysc { struct sc_core_adapter_if { + virtual iss::arch_if* get_arch_if() = 0; virtual void set_mhartid(unsigned) = 0; virtual uint32_t get_mode() = 0; virtual uint64_t get_state() = 0; @@ -25,6 +27,5 @@ struct sc_core_adapter_if { virtual void local_irq(short id, bool value) = 0; virtual ~sc_core_adapter_if() = default; }; - - +} #endif /* _SYSC_SC_CORE_ADAPTER_IF_H_ */ diff --git a/src/vm/tcc/vm_tgc_c.cpp b/src/vm/tcc/vm_tgc_c.cpp index 371aa95..fee3a87 100644 --- a/src/vm/tcc/vm_tgc_c.cpp +++ b/src/vm/tcc/vm_tgc_c.cpp @@ -3229,13 +3229,13 @@ namespace { volatile std::array dummy = { core_factory::instance().register_creator("tgc_c|m_p|tcc", [](unsigned port, void*) -> std::tuple{ auto* cpu = new iss::arch::riscv_hart_m_p(); - auto vm = new tcc::tgc_c::vm_impl(*cpu, false); + auto* vm = new tcc::tgc_c::vm_impl(*cpu, false); if (port != 0) debugger::server::run_server(vm, port); return {cpu_ptr{cpu}, vm_ptr{vm}}; }), core_factory::instance().register_creator("tgc_c|mu_p|tcc", [](unsigned port, void*) -> std::tuple{ auto* cpu = new iss::arch::riscv_hart_mu_p(); - auto vm = new tcc::tgc_c::vm_impl(*cpu, false); + auto* vm = new tcc::tgc_c::vm_impl(*cpu, false); if (port != 0) debugger::server::run_server(vm, port); return {cpu_ptr{cpu}, vm_ptr{vm}}; }) From 720236ec3faf87246d15252278532a054c042875 Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Fri, 14 Jul 2023 12:51:51 +0200 Subject: [PATCH 02/14] add generated core registration --- CMakeLists.txt | 11 +++- gen_input/templates/CORENAME_sysc.cpp.gtl | 72 +++++++++++++++++++++++ src-gen/.gitignore | 3 +- src/sysc/register_tgc_c.cpp | 8 +-- 4 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 gen_input/templates/CORENAME_sysc.cpp.gtl diff --git a/CMakeLists.txt b/CMakeLists.txt index a2a546f..0f07fd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,10 @@ find_package(elfio QUIET) find_package(Boost COMPONENTS coroutine) find_package(jsoncpp) +if(TARGET tcc::tcc) + set(WITH_TCC ON) +endif() + if(WITH_LLVM) if(DEFINED ENV{LLVM_HOME}) find_path (LLVM_DIR LLVM-Config.cmake $ENV{LLVM_HOME}/lib/cmake/llvm) @@ -178,10 +182,13 @@ install(TARGETS tgc-sim ############################################################################### if(TARGET scc-sysc) project(dbt-rise-tgc_sc VERSION 1.0.0) - add_library(${PROJECT_NAME} + set(LIB_SOURCES src/sysc/core_complex.cpp src/sysc/register_tgc_c.cpp - ) + ) + FILE(GLOB GEN_SC_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/sysc/register_*.cpp) + list(APPEND LIB_SOURCES ${GEN_SC_SOURCES}) + add_library(${PROJECT_NAME} ${LIB_SOURCES}) 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/CORENAME_sysc.cpp.gtl b/gen_input/templates/CORENAME_sysc.cpp.gtl new file mode 100644 index 0000000..e56e7db --- /dev/null +++ b/gen_input/templates/CORENAME_sysc.cpp.gtl @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (C) 2023 MINRES Technologies GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************************/ + +#include "iss_factory.h" +#include +#include +#include +#include "sc_core_adapter.h" +#include "core_complex.h" + +namespace iss { +namespace interp { +using namespace sysc; +volatile std::array ${coreDef.name.toLowerCase()}_init = { + iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t { + auto* cc = reinterpret_cast(data); + auto* cpu = new sc_core_adapter>(cc); + return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; + }), + iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t { + auto* cc = reinterpret_cast(data); + auto* cpu = new sc_core_adapter>(cc); + return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; + }) +}; +} +#if defined(WITH_TCC) +namespace tcc { +volatile std::array ${coreDef.name.toLowerCase()}_init = { + core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned gdb_port, void* data) -> std::tuple{ + auto cc = reinterpret_cast(data); + auto* cpu = new sc_core_adapter>(cc); + return {cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; + }), + core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned gdb_port, void* data) -> std::tuple{ + auto cc = reinterpret_cast(data); + auto* cpu = new sc_core_adapter>(cc); + return {cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; + }) +}; +} +#endif +} diff --git a/src-gen/.gitignore b/src-gen/.gitignore index d3fcb35..454f93f 100644 --- a/src-gen/.gitignore +++ b/src-gen/.gitignore @@ -1,2 +1,3 @@ /iss -/vm \ No newline at end of file +/vm +/sysc \ No newline at end of file diff --git a/src/sysc/register_tgc_c.cpp b/src/sysc/register_tgc_c.cpp index efd46b0..31a99a5 100644 --- a/src/sysc/register_tgc_c.cpp +++ b/src/sysc/register_tgc_c.cpp @@ -58,13 +58,13 @@ namespace tcc { volatile std::array tgc_init = { core_factory::instance().register_creator("tgc_c|m_p|tcc", [](unsigned gdb_port, void* data) -> std::tuple{ auto cc = reinterpret_cast(data); - arch::tgc_c* cpu = new sc_core_adapter>(cc); - return {cpu_ptr{cpu}, vm_ptr{create(cpu, gdb_port)}}; + auto* cpu = new sc_core_adapter>(cc); + return {cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; }), core_factory::instance().register_creator("tgc_c|mu_p|tcc", [](unsigned gdb_port, void* data) -> std::tuple{ auto cc = reinterpret_cast(data); - arch::tgc_c* cpu = new sc_core_adapter>(cc); - return {cpu_ptr{cpu}, vm_ptr{create(cpu, gdb_port)}}; + auto* cpu = new sc_core_adapter>(cc); + return {cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; }) }; } From a0ca3cdfa53bea29a20e6abf532afb7980f5bdb2 Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Thu, 13 Jul 2023 09:42:39 +0200 Subject: [PATCH 03/14] revive LLVM support (WIP) --- CMakeLists.txt | 18 +++++++++++------- src/main.cpp | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f07fd8..bc11091 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,13 +15,17 @@ if(TARGET tcc::tcc) endif() if(WITH_LLVM) - if(DEFINED ENV{LLVM_HOME}) - find_path (LLVM_DIR LLVM-Config.cmake $ENV{LLVM_HOME}/lib/cmake/llvm) - endif(DEFINED ENV{LLVM_HOME}) - find_package(LLVM REQUIRED CONFIG) - message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") - message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") - llvm_map_components_to_libnames(llvm_libs support core mcjit x86codegen x86asmparser) + if(FALSE) + if(DEFINED ENV{LLVM_HOME}) + find_path (LLVM_DIR LLVM-Config.cmake $ENV{LLVM_HOME}/lib/cmake/llvm) + endif(DEFINED ENV{LLVM_HOME}) + find_package(LLVM REQUIRED CONFIG) + message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") + message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + llvm_map_components_to_libnames(llvm_libs support core mcjit x86codegen x86asmparser) + else() + find_package(LLVM REQUIRED LLVMSupport LLVMCore LLVMMCJIT LLVMX86CodeGen LLVMX86AsmParser) + endif() endif() #Mac needed variables (adapt for your needs - http://www.cmake.org/Wiki/CMake_RPATH_handling#Mac_OS_X_and_the_RPATH) diff --git a/src/main.cpp b/src/main.cpp index 02ec210..0452578 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -39,7 +39,7 @@ #include #include "iss/arch/tgc_mapper.h" #ifdef WITH_LLVM -#include +#include #endif #include #include "iss/plugin/cycle_estimate.h" From 9459632f6cdc01a8e5bc323eb3ca457733d7d66b Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Mon, 17 Jul 2023 19:52:50 +0200 Subject: [PATCH 04/14] adds llvm build support incl. conan --- CMakeLists.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bc11091..c8fe6a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,14 +15,14 @@ if(TARGET tcc::tcc) endif() if(WITH_LLVM) - if(FALSE) - if(DEFINED ENV{LLVM_HOME}) - find_path (LLVM_DIR LLVM-Config.cmake $ENV{LLVM_HOME}/lib/cmake/llvm) - endif(DEFINED ENV{LLVM_HOME}) - find_package(LLVM REQUIRED CONFIG) - message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") - message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") - llvm_map_components_to_libnames(llvm_libs support core mcjit x86codegen x86asmparser) + if(DEFINED ENV{LLVM_HOME}) + find_path (LLVM_DIR LLVM-Config.cmake $ENV{LLVM_HOME}/lib/cmake/llvm) + endif(DEFINED ENV{LLVM_HOME}) + find_package(LLVM QUIET CONFIG) + if(LLVM_FOUND) + message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") + message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + llvm_map_components_to_libnames(llvm_libs support core mcjit x86codegen x86asmparser) else() find_package(LLVM REQUIRED LLVMSupport LLVMCore LLVMMCJIT LLVMX86CodeGen LLVMX86AsmParser) endif() From 94e46b996884f9836f8b2adbe13f7e5c2671faa6 Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Mon, 17 Jul 2023 19:57:09 +0200 Subject: [PATCH 05/14] adds some cleanup --- CMakeLists.txt | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c8fe6a4..5ad2123 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ endif() if(WITH_LLVM) if(DEFINED ENV{LLVM_HOME}) find_path (LLVM_DIR LLVM-Config.cmake $ENV{LLVM_HOME}/lib/cmake/llvm) - endif(DEFINED ENV{LLVM_HOME}) + endif() find_package(LLVM QUIET CONFIG) if(LLVM_FOUND) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") @@ -28,13 +28,6 @@ if(WITH_LLVM) endif() endif() -#Mac needed variables (adapt for your needs - http://www.cmake.org/Wiki/CMake_RPATH_handling#Mac_OS_X_and_the_RPATH) -#set(CMAKE_MACOSX_RPATH ON) -#set(CMAKE_SKIP_BUILD_RPATH FALSE) -#set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) -#set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") -#set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) - add_subdirectory(softfloat) set(LIB_SOURCES From edba497fa16ae0f56a5a9e043af62d09484c0e33 Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Wed, 19 Jul 2023 08:19:38 +0200 Subject: [PATCH 06/14] fixes linker isseu using whole-archive --- CMakeLists.txt | 8 +++++--- cmake/flink.cmake | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 cmake/flink.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ad2123..8559904 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,12 @@ cmake_minimum_required(VERSION 3.12) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) ############################################################################### # ############################################################################### project(dbt-rise-tgc VERSION 1.0.0) include(GNUInstallDirs) +include(flink) find_package(elfio QUIET) find_package(Boost COMPONENTS coroutine) @@ -82,8 +84,8 @@ if(TARGET jsoncpp::jsoncpp) else() target_link_libraries(${PROJECT_NAME} PUBLIC jsoncpp) endif() -if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND BUILD_SHARED_LIBS) - target_link_libraries(${PROJECT_NAME} PUBLIC -Wl,--whole-archive dbt-rise-core -Wl,--no-whole-archive) +if(BUILD_SHARED_LIBS) + target_force_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-core) else() target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-core) endif() @@ -154,7 +156,7 @@ if(WITH_TCC) target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_TCC) endif() # Links the target exe against the libraries -target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc) +target_force_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc) if(TARGET Boost::program_options) target_link_libraries(${PROJECT_NAME} PUBLIC Boost::program_options) else() diff --git a/cmake/flink.cmake b/cmake/flink.cmake new file mode 100644 index 0000000..69b5c9f --- /dev/null +++ b/cmake/flink.cmake @@ -0,0 +1,35 @@ +# according to https://github.com/horance-liu/flink.cmake/tree/master +# SPDX-License-Identifier: Apache-2.0 + +include(CMakeParseArguments) + +function(target_do_force_link_libraries target visibility lib) + if(MSVC) + target_link_libraries(${target} ${visibility} "/WHOLEARCHIVE:${lib}") + elseif(APPLE) + target_link_libraries(${target} ${visibility} -Wl,-force_load ${lib}) + else() + target_link_libraries(${target} ${visibility} -Wl,--whole-archive ${lib} -Wl,--no-whole-archive) + endif() +endfunction() + +function(target_force_link_libraries target) + cmake_parse_arguments(FLINK + "" + "" + "PUBLIC;INTERFACE;PRIVATE" + ${ARGN} + ) + + foreach(lib IN LISTS FLINK_PUBLIC) + target_do_force_link_libraries(${target} PUBLIC ${lib}) + endforeach() + + foreach(lib IN LISTS FLINK_INTERFACE) + target_do_force_link_libraries(${target} INTERFACE ${lib}) + endforeach() + + foreach(lib IN LISTS FLINK_PRIVATE) + target_do_force_link_libraries(${target} PRIVATE ${lib}) + endforeach() +endfunction() \ No newline at end of file From c78026b720d2fa548c502a8b77d5fe9a6534e382 Mon Sep 17 00:00:00 2001 From: Eyck-Alexander Jentzsch Date: Sun, 23 Jul 2023 08:05:15 +0200 Subject: [PATCH 07/14] adds faster instruction decoding --- src/vm/interp/vm_tgc_c.cpp | 93 +++++++++++++++++++++++++++----------- 1 file changed, 66 insertions(+), 27 deletions(-) diff --git a/src/vm/interp/vm_tgc_c.cpp b/src/vm/interp/vm_tgc_c.cpp index c94b716..2525a37 100644 --- a/src/vm/interp/vm_tgc_c.cpp +++ b/src/vm/interp/vm_tgc_c.cpp @@ -153,14 +153,22 @@ private: /**************************************************************************** * start opcode definitions ****************************************************************************/ - struct InstructionDesriptor { + struct instruction_descriptor { size_t length; uint32_t value; uint32_t mask; typename arch::traits::opcode_e op; }; - - const std::array instr_descr = {{ + struct decoding_tree_node{ + std::vector instrs; + std::vector children; + uint32_t submask = std::numeric_limits::max(); + uint32_t value; + decoding_tree_node(uint32_t value) : value(value){} + }; + + decoding_tree_node* root {nullptr}; + const std::array instr_descr = {{ /* entries are: size, valid value, valid mask, function ptr */ {32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, arch::traits::opcode_e::LUI}, {32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, arch::traits::opcode_e::AUIPC}, @@ -251,18 +259,61 @@ private: {16, 0b0000000000000000, 0b1111111111111111, arch::traits::opcode_e::DII}, }}; - //static constexpr typename traits::addr_t upper_bits = ~traits::PGMASK; iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ auto phys_pc = this->core.v2p(pc); - //if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary - // if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err; - // if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction - // if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) return iss::Err; - //} else { if (this->core.read(phys_pc, 4, data) != iss::Ok) return iss::Err; - //} return iss::Ok; } + void populate_decoding_tree(decoding_tree_node* root){ + //create submask + for(auto instr: root->instrs){ + root->submask &= instr.mask; + } + //put each instr according to submask&encoding into children + for(auto instr: root->instrs){ + bool foundMatch = false; + for(auto child: root->children){ + //use value as identifying trait + if(child->value == (instr.value&root->submask)){ + child->instrs.push_back(instr); + foundMatch = true; + } + } + if(!foundMatch){ + decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask); + child->instrs.push_back(instr); + root->children.push_back(child); + } + } + root->instrs.clear(); + //call populate_decoding_tree for all children + if(root->children.size() >1) + for(auto child: root->children){ + populate_decoding_tree(child); + } + else{ + //sort instrs by value of the mask, this works bc we want to have the least restrictive one last + std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) { + return instr1.mask > instr2.mask; + }); + } + } + typename arch::traits::opcode_e decodeInstr(decoding_tree_node* node, code_word_t word){ + if(!node->children.size()){ + if(node->instrs.size() == 1) return node->instrs[0].op; + for(auto instr : node->instrs){ + if((instr.mask&word) == instr.value) return instr.op; + } + } + else{ + for(auto child : node->children){ + if (child->value == (node->submask&word)){ + return decodeInstr(child, word); + } + } + } + return arch::traits::opcode_e::MAX_OPCODE; + } }; template void debug_fn(CODE_WORD insn) { @@ -290,15 +341,11 @@ template vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) : vm_base(core, core_id, cluster_id) { unsigned id=0; - for (auto instr : instr_descr) { - auto quadrant = instr.value & 0x3; - qlut[quadrant].push_back(instruction_pattern{instr.value, instr.mask, instr.op}); - } - for(auto& lut: qlut){ - std::sort(std::begin(lut), std::end(lut), [](instruction_pattern const& a, instruction_pattern const& b){ - return bit_count(a.mask) > bit_count(b.mask); - }); + root = new decoding_tree_node(std::numeric_limits::max()); + for(auto instr:instr_descr){ + root->instrs.push_back(instr); } + populate_decoding_tree(root); } inline bool is_count_limit_enabled(finish_cond_e cond){ @@ -309,14 +356,6 @@ inline bool is_jump_to_self_enabled(finish_cond_e cond){ return (cond & finish_cond_e::JUMP_TO_SELF) == finish_cond_e::JUMP_TO_SELF; } -template -typename arch::traits::opcode_e vm_impl::decode_inst_id(code_word_t instr){ - for(auto& e: qlut[instr&0x3]){ - if(!((instr&e.mask) ^ e.value )) return e.id; - } - return arch::traits::opcode_e::MAX_OPCODE; -} - template typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){ auto pc=start; @@ -338,7 +377,7 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co } else { if (is_jump_to_self_enabled(cond) && (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' - auto inst_id = decode_inst_id(instr); + auto inst_id = decodeInstr(root, instr); // pre execution stuff this->core.reg.last_branch = 0; if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast(inst_id)); From bd0d15f3a2e8c751d78d61acd18f869ddec3b2d5 Mon Sep 17 00:00:00 2001 From: Eyck-Alexander Jentzsch Date: Sun, 23 Jul 2023 08:10:57 +0200 Subject: [PATCH 08/14] updates template for faster instruction decoding --- gen_input/templates/interp/CORENAME.cpp.gtl | 91 +++++++++++++++------ src/vm/interp/vm_tgc_c.cpp | 2 +- 2 files changed, 66 insertions(+), 27 deletions(-) diff --git a/gen_input/templates/interp/CORENAME.cpp.gtl b/gen_input/templates/interp/CORENAME.cpp.gtl index acf7afd..7a7707e 100644 --- a/gen_input/templates/interp/CORENAME.cpp.gtl +++ b/gen_input/templates/interp/CORENAME.cpp.gtl @@ -159,30 +159,81 @@ private: /**************************************************************************** * start opcode definitions ****************************************************************************/ - struct InstructionDesriptor { + struct instruction_descriptor { size_t length; uint32_t value; uint32_t mask; typename arch::traits::opcode_e op; }; + struct decoding_tree_node{ + std::vector instrs; + std::vector children; + uint32_t submask = std::numeric_limits::max(); + uint32_t value; + decoding_tree_node(uint32_t value) : value(value){} + }; - const std::array instr_descr = {{ + decoding_tree_node* root {nullptr}; + const std::array instr_descr = {{ /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %> {${instr.length}, ${instr.encoding}, ${instr.mask}, arch::traits::opcode_e::${instr.instruction.name}},<%}%> }}; - //static constexpr typename traits::addr_t upper_bits = ~traits::PGMASK; iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ auto phys_pc = this->core.v2p(pc); - //if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary - // if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err; - // if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction - // if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) return iss::Err; - //} else { if (this->core.read(phys_pc, 4, data) != iss::Ok) return iss::Err; - //} return iss::Ok; } + void populate_decoding_tree(decoding_tree_node* root){ + //create submask + for(auto instr: root->instrs){ + root->submask &= instr.mask; + } + //put each instr according to submask&encoding into children + for(auto instr: root->instrs){ + bool foundMatch = false; + for(auto child: root->children){ + //use value as identifying trait + if(child->value == (instr.value&root->submask)){ + child->instrs.push_back(instr); + foundMatch = true; + } + } + if(!foundMatch){ + decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask); + child->instrs.push_back(instr); + root->children.push_back(child); + } + } + root->instrs.clear(); + //call populate_decoding_tree for all children + if(root->children.size() >1) + for(auto child: root->children){ + populate_decoding_tree(child); + } + else{ + //sort instrs by value of the mask, this works bc we want to have the least restrictive one last + std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) { + return instr1.mask > instr2.mask; + }); + } + } + typename arch::traits::opcode_e decodeInstr(decoding_tree_node* node, code_word_t word){ + if(!node->children.size()){ + if(node->instrs.size() == 1) return node->instrs[0].op; + for(auto instr : node->instrs){ + if((instr.mask&word) == instr.value) return instr.op; + } + } + else{ + for(auto child : node->children){ + if (child->value == (node->submask&word)){ + return decodeInstr(child, word); + } + } + } + return arch::traits::opcode_e::MAX_OPCODE; + } }; template void debug_fn(CODE_WORD insn) { @@ -210,15 +261,11 @@ template vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) : vm_base(core, core_id, cluster_id) { unsigned id=0; - for (auto instr : instr_descr) { - auto quadrant = instr.value & 0x3; - qlut[quadrant].push_back(instruction_pattern{instr.value, instr.mask, instr.op}); - } - for(auto& lut: qlut){ - std::sort(std::begin(lut), std::end(lut), [](instruction_pattern const& a, instruction_pattern const& b){ - return bit_count(a.mask) > bit_count(b.mask); - }); + root = new decoding_tree_node(std::numeric_limits::max()); + for(auto instr:instr_descr){ + root->instrs.push_back(instr); } + populate_decoding_tree(root); } inline bool is_count_limit_enabled(finish_cond_e cond){ @@ -229,14 +276,6 @@ inline bool is_jump_to_self_enabled(finish_cond_e cond){ return (cond & finish_cond_e::JUMP_TO_SELF) == finish_cond_e::JUMP_TO_SELF; } -template -typename arch::traits::opcode_e vm_impl::decode_inst_id(code_word_t instr){ - for(auto& e: qlut[instr&0x3]){ - if(!((instr&e.mask) ^ e.value )) return e.id; - } - return arch::traits::opcode_e::MAX_OPCODE; -} - template typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){ auto pc=start; @@ -258,7 +297,7 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co } else { if (is_jump_to_self_enabled(cond) && (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' - auto inst_id = decode_inst_id(instr); + auto inst_id = decodeInstr(root, instr); // pre execution stuff this->core.reg.last_branch = 0; if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast(inst_id)); diff --git a/src/vm/interp/vm_tgc_c.cpp b/src/vm/interp/vm_tgc_c.cpp index 2525a37..d5817ed 100644 --- a/src/vm/interp/vm_tgc_c.cpp +++ b/src/vm/interp/vm_tgc_c.cpp @@ -166,7 +166,7 @@ private: uint32_t value; decoding_tree_node(uint32_t value) : value(value){} }; - + decoding_tree_node* root {nullptr}; const std::array instr_descr = {{ /* entries are: size, valid value, valid mask, function ptr */ From 6e52af168bb7984c28e4ed0208aa38720875dde7 Mon Sep 17 00:00:00 2001 From: Eyck-Alexander Jentzsch Date: Sat, 29 Jul 2023 11:42:46 +0200 Subject: [PATCH 09/14] adds faster decoding to tcc and cleans up others --- gen_input/templates/interp/CORENAME.cpp.gtl | 7 +- gen_input/templates/tcc/CORENAME.cpp.gtl | 158 ++++++++-------- src/vm/interp/vm_tgc_c.cpp | 7 +- src/vm/tcc/vm_tgc_c.cpp | 195 ++++++++++---------- 4 files changed, 180 insertions(+), 187 deletions(-) diff --git a/gen_input/templates/interp/CORENAME.cpp.gtl b/gen_input/templates/interp/CORENAME.cpp.gtl index 7a7707e..9585627 100644 --- a/gen_input/templates/interp/CORENAME.cpp.gtl +++ b/gen_input/templates/interp/CORENAME.cpp.gtl @@ -218,7 +218,7 @@ private: }); } } - typename arch::traits::opcode_e decodeInstr(decoding_tree_node* node, code_word_t word){ + typename arch::traits::opcode_e decode_instr(decoding_tree_node* node, code_word_t word){ if(!node->children.size()){ if(node->instrs.size() == 1) return node->instrs[0].op; for(auto instr : node->instrs){ @@ -228,7 +228,7 @@ private: else{ for(auto child : node->children){ if (child->value == (node->submask&word)){ - return decodeInstr(child, word); + return decode_instr(child, word); } } } @@ -260,7 +260,6 @@ constexpr size_t bit_count(uint32_t u) { template vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) : vm_base(core, core_id, cluster_id) { - unsigned id=0; root = new decoding_tree_node(std::numeric_limits::max()); for(auto instr:instr_descr){ root->instrs.push_back(instr); @@ -297,7 +296,7 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co } else { if (is_jump_to_self_enabled(cond) && (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' - auto inst_id = decodeInstr(root, instr); + auto inst_id = decode_instr(root, instr); // pre execution stuff this->core.reg.last_branch = 0; if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast(inst_id)); diff --git a/gen_input/templates/tcc/CORENAME.cpp.gtl b/gen_input/templates/tcc/CORENAME.cpp.gtl index b7cec56..809ae00 100644 --- a/gen_input/templates/tcc/CORENAME.cpp.gtl +++ b/gen_input/templates/tcc/CORENAME.cpp.gtl @@ -121,57 +121,7 @@ protected: } } - // some compile time constants - // enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 }; - enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 }; - enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 }; - enum { LUT_SIZE = 1 << util::bit_count(static_cast(EXTR_MASK32)), LUT_SIZE_C = 1 << util::bit_count(static_cast(EXTR_MASK16)) }; - - std::array lut; - - std::array lut_00, lut_01, lut_10; - std::array lut_11; - - std::array qlut; - - std::array lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}}; - - void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[], - compile_func f) { - if (pos < 0) { - lut[idx] = f; - } else { - auto bitmask = 1UL << pos; - if ((mask & bitmask) == 0) { - expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f); - } else { - if ((valid & bitmask) == 0) { - expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f); - expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f); - } else { - auto new_val = idx << 1; - if ((value & bitmask) != 0) new_val++; - expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f); - } - } - } - } - - inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); } - - uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) { - if (pos >= 0) { - auto bitmask = 1UL << pos; - if ((mask & bitmask) == 0) { - lut_val = extract_fields(pos - 1, val, mask, lut_val); - } else { - auto new_val = lut_val << 1; - if ((val & bitmask) != 0) new_val++; - lut_val = extract_fields(pos - 1, val, mask, new_val); - } - } - return lut_val; - } + template::type> inline S sext(U from) { auto mask = (1ULL< instrs; + std::vector children; + uint32_t submask = std::numeric_limits::max(); + uint32_t value; + decoding_tree_node(uint32_t value) : value(value){} + }; - const std::array instr_descr = {{ + decoding_tree_node* root {nullptr}; + + const std::array instr_descr = {{ /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %> /* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */ {${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%> @@ -228,11 +187,64 @@ private: vm_impl::gen_trap_check(tu); return BRANCH; } + + //decoding functionality + + void populate_decoding_tree(decoding_tree_node* root){ + //create submask + for(auto instr: root->instrs){ + root->submask &= instr.mask; + } + //put each instr according to submask&encoding into children + for(auto instr: root->instrs){ + bool foundMatch = false; + for(auto child: root->children){ + //use value as identifying trait + if(child->value == (instr.value&root->submask)){ + child->instrs.push_back(instr); + foundMatch = true; + } + } + if(!foundMatch){ + decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask); + child->instrs.push_back(instr); + root->children.push_back(child); + } + } + root->instrs.clear(); + //call populate_decoding_tree for all children + if(root->children.size() >1) + for(auto child: root->children){ + populate_decoding_tree(child); + } + else{ + //sort instrs by value of the mask, this works bc we want to have the least restrictive one last + std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) { + return instr1.mask > instr2.mask; + }); + } + } + compile_func decode_instr(decoding_tree_node* node, code_word_t word){ + if(!node->children.size()){ + if(node->instrs.size() == 1) return node->instrs[0].op; + for(auto instr : node->instrs){ + if((instr.mask&word) == instr.value) return instr.op; + } + } + else{ + for(auto child : node->children){ + if (child->value == (node->submask&word)){ + return decode_instr(child, word); + } + } + } + return nullptr; + } }; -template void debug_fn(CODE_WORD insn) { - volatile CODE_WORD x = insn; - insn = 2 * x; +template void debug_fn(CODE_WORD instr) { + volatile CODE_WORD x = instr; + instr = 2 * x; } template vm_impl::vm_impl() { this(new ARCH()); } @@ -240,14 +252,11 @@ template vm_impl::vm_impl() { this(new ARCH()); } template vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) : vm_base(core, core_id, cluster_id) { - qlut[0] = lut_00.data(); - qlut[1] = lut_01.data(); - qlut[2] = lut_10.data(); - qlut[3] = lut_11.data(); - for (auto instr : instr_descr) { - auto quantrant = instr.value & 0x3; - expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op); + root = new decoding_tree_node(std::numeric_limits::max()); + for(auto instr:instr_descr){ + root->instrs.push_back(instr); } + populate_decoding_tree(root); } template @@ -255,30 +264,19 @@ std::tuple vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) { // we fetch at max 4 byte, alignment is 2 enum {TRAP_ID=1<<16}; - code_word_t insn = 0; - // const typename traits::addr_t upper_bits = ~traits::PGMASK; + code_word_t instr = 0; phys_addr_t paddr(pc); - auto *const data = (uint8_t *)&insn; paddr = this->core.v2p(pc); -// if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary -// auto res = this->core.read(paddr, 2, data); -// if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); -// if ((insn & 0x3) == 0x3) { // this is a 32bit instruction -// res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); -// } -// } else { - auto res = this->core.read(paddr, 4, data); - if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); -// } - if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' + auto res = this->core.read(paddr, 4, reinterpret_cast(&instr)); + if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); + if (instr == 0x0000006f || (instr&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' // curr pc on stack ++inst_cnt; - auto lut_val = extract_fields(insn); - auto f = qlut[insn & 0x3][lut_val]; + auto f = decode_instr(root, instr); if (f == nullptr) { f = &this_class::illegal_intruction; } - return (this->*f)(pc, insn, tu); + return (this->*f)(pc, instr, tu); } template void vm_impl::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) { diff --git a/src/vm/interp/vm_tgc_c.cpp b/src/vm/interp/vm_tgc_c.cpp index d5817ed..55c75d5 100644 --- a/src/vm/interp/vm_tgc_c.cpp +++ b/src/vm/interp/vm_tgc_c.cpp @@ -298,7 +298,7 @@ private: }); } } - typename arch::traits::opcode_e decodeInstr(decoding_tree_node* node, code_word_t word){ + typename arch::traits::opcode_e decode_instr(decoding_tree_node* node, code_word_t word){ if(!node->children.size()){ if(node->instrs.size() == 1) return node->instrs[0].op; for(auto instr : node->instrs){ @@ -308,7 +308,7 @@ private: else{ for(auto child : node->children){ if (child->value == (node->submask&word)){ - return decodeInstr(child, word); + return decode_instr(child, word); } } } @@ -340,7 +340,6 @@ constexpr size_t bit_count(uint32_t u) { template vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) : vm_base(core, core_id, cluster_id) { - unsigned id=0; root = new decoding_tree_node(std::numeric_limits::max()); for(auto instr:instr_descr){ root->instrs.push_back(instr); @@ -377,7 +376,7 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co } else { if (is_jump_to_self_enabled(cond) && (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' - auto inst_id = decodeInstr(root, instr); + auto inst_id = decode_instr(root, instr); // pre execution stuff this->core.reg.last_branch = 0; if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast(inst_id)); diff --git a/src/vm/tcc/vm_tgc_c.cpp b/src/vm/tcc/vm_tgc_c.cpp index 495d97e..fde3ec3 100644 --- a/src/vm/tcc/vm_tgc_c.cpp +++ b/src/vm/tcc/vm_tgc_c.cpp @@ -121,57 +121,7 @@ protected: } } - // some compile time constants - // enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 }; - enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 }; - enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 }; - enum { LUT_SIZE = 1 << util::bit_count(static_cast(EXTR_MASK32)), LUT_SIZE_C = 1 << util::bit_count(static_cast(EXTR_MASK16)) }; - - std::array lut; - - std::array lut_00, lut_01, lut_10; - std::array lut_11; - - std::array qlut; - - std::array lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}}; - - void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[], - compile_func f) { - if (pos < 0) { - lut[idx] = f; - } else { - auto bitmask = 1UL << pos; - if ((mask & bitmask) == 0) { - expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f); - } else { - if ((valid & bitmask) == 0) { - expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f); - expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f); - } else { - auto new_val = idx << 1; - if ((value & bitmask) != 0) new_val++; - expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f); - } - } - } - } - - inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); } - - uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) { - if (pos >= 0) { - auto bitmask = 1UL << pos; - if ((mask & bitmask) == 0) { - lut_val = extract_fields(pos - 1, val, mask, lut_val); - } else { - auto new_val = lut_val << 1; - if ((val & bitmask) != 0) new_val++; - lut_val = extract_fields(pos - 1, val, mask, new_val); - } - } - return lut_val; - } + template::type> inline S sext(U from) { auto mask = (1ULL< instrs; + std::vector children; + uint32_t submask = std::numeric_limits::max(); + uint32_t value; + decoding_tree_node(uint32_t value) : value(value){} + }; - const std::array instr_descr = {{ + decoding_tree_node* root {nullptr}; + + const std::array instr_descr = {{ /* entries are: size, valid value, valid mask, function ptr */ /* instruction LUI, encoding '0b00000000000000000000000000110111' */ {32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, &this_class::__lui}, @@ -494,14 +453,14 @@ private: this->gen_raise_trap(tu, 0, 2); } else{ - auto new_pc = tu.assignment(tu.ext((tu.bitwise_and((tu.add(tu.load(rs1+ traits::X0, 0),tu.constant((int16_t)sext<12>(imm),16))),tu.constant(~ 0x1,8))),32,true),32); + auto new_pc = tu.assignment(tu.ext((tu.bitwise_and((tu.add(tu.load(rs1+ traits::X0, 0),tu.constant((int16_t)sext<12>(imm),16))),tu.constant(~0x1,8))),32,true),32); tu.open_if(tu.srem(new_pc,tu.constant(static_cast(traits:: INSTR_ALIGNMENT),32))); this->gen_raise_trap(tu, 0, 0); tu.open_else(); if(rd!= 0) { tu.store(rd + traits::X0,tu.ext((tu.add(tu.ext(cur_pc_val,32,false),tu.constant( 4,8))),32,true)); } - auto PC_val_v = tu.assignment("PC_val", tu.bitwise_and(new_pc,tu.constant(~ 0x1,8)),32); + auto PC_val_v = tu.assignment("PC_val", tu.bitwise_and(new_pc,tu.constant(~0x1,8)),32); tu.store(traits::NEXT_PC, PC_val_v); tu.store(traits::LAST_BRANCH, tu.constant(2U, 2)); tu.close_scope(); @@ -1963,7 +1922,7 @@ private: else{ auto xrd = tu.assignment(tu.read_mem(traits::CSR, csr, 32),32); if(zimm!= 0) { - tu.write_mem(traits::CSR, csr, tu.bitwise_and(xrd,tu.constant(~ ((uint32_t)zimm),32))); + tu.write_mem(traits::CSR, csr, tu.bitwise_and(xrd,tu.constant(~((uint32_t)zimm),32))); } if(rd!= 0) { tu.store(rd + traits::X0,xrd); @@ -2024,7 +1983,7 @@ private: this->gen_raise_trap(tu, 0, 2); } else{ - auto res = tu.assignment(tu.mul(tu.ext(tu.load(rs1+ traits::X0, 0),32,false),tu.ext(tu.load(rs2+ traits::X0, 0),32,false)),64); + auto res = tu.assignment(tu.ext((tu.mul(tu.ext(tu.ext(tu.load(rs1+ traits::X0, 0),32,true),64,false),tu.ext(tu.ext(tu.load(rs2+ traits::X0, 0),32,true),64,false))),64,false),64); if(rd!=0) { tu.store(rd + traits::X0,tu.ext(res,32,true)); } @@ -2058,7 +2017,7 @@ private: this->gen_raise_trap(tu, 0, 2); } else{ - auto res = tu.assignment(tu.mul(tu.ext(tu.load(rs1+ traits::X0, 0),32,false),tu.ext(tu.load(rs2+ traits::X0, 0),32,false)),64); + auto res = tu.assignment(tu.ext((tu.mul(tu.ext(tu.ext(tu.load(rs1+ traits::X0, 0),32,true),64,false),tu.ext(tu.ext(tu.load(rs2+ traits::X0, 0),32,true),64,false))),64,false),64); if(rd!=0) { tu.store(rd + traits::X0,tu.ext((tu.lshr(res,tu.constant(static_cast(traits:: XLEN),32))),32,true)); } @@ -2092,7 +2051,7 @@ private: this->gen_raise_trap(tu, 0, 2); } else{ - auto res = tu.assignment(tu.mul(tu.ext(tu.load(rs1+ traits::X0, 0),32,false),tu.load(rs2+ traits::X0, 0)),64); + auto res = tu.assignment(tu.ext((tu.mul(tu.ext(tu.ext(tu.load(rs1+ traits::X0, 0),32,true),64,false),tu.ext(tu.load(rs2+ traits::X0, 0),64,true))),64,false),64); if(rd!=0) { tu.store(rd + traits::X0,tu.ext((tu.lshr(res,tu.constant(static_cast(traits:: XLEN),32))),32,true)); } @@ -2126,7 +2085,7 @@ private: this->gen_raise_trap(tu, 0, 2); } else{ - auto res = tu.assignment(tu.mul(tu.load(rs1+ traits::X0, 0),tu.load(rs2+ traits::X0, 0)),64); + auto res = tu.assignment(tu.ext((tu.mul(tu.ext(tu.load(rs1+ traits::X0, 0),64,true),tu.ext(tu.load(rs2+ traits::X0, 0),64,true))),64,true),64); if(rd!=0) { tu.store(rd + traits::X0,tu.ext((tu.lshr(res,tu.constant(static_cast(traits:: XLEN),32))),32,true)); } @@ -2164,13 +2123,13 @@ private: auto divisor = tu.assignment(tu.ext(tu.load(rs2+ traits::X0, 0),32,false),32); if(rd!= 0){ tu.open_if(tu.icmp(ICmpInst::ICMP_NE,divisor,tu.constant( 0,8))); auto MMIN = tu.assignment(tu.constant(((uint32_t)1)<<(static_cast(traits:: XLEN)-1),32),32); - tu.open_if(tu.logical_and(tu.icmp(ICmpInst::ICMP_EQ,tu.load(rs1+ traits::X0, 0),MMIN),tu.icmp(ICmpInst::ICMP_EQ,divisor,tu.constant(- 1,8)))); + tu.open_if(tu.logical_and(tu.icmp(ICmpInst::ICMP_EQ,tu.load(rs1+ traits::X0, 0),MMIN),tu.icmp(ICmpInst::ICMP_EQ,divisor,tu.constant(-1,8)))); tu.store(rd + traits::X0,MMIN); tu.open_else(); tu.store(rd + traits::X0,tu.ext((tu.sdiv(dividend,divisor)),32,true)); tu.close_scope(); tu.open_else(); - tu.store(rd + traits::X0,tu.constant((uint32_t)- 1,32)); + tu.store(rd + traits::X0,tu.constant((uint32_t)-1,32)); tu.close_scope(); } } @@ -2209,7 +2168,7 @@ private: } tu.open_else(); if(rd!=0) { - tu.store(rd + traits::X0,tu.constant((uint32_t)- 1,32)); + tu.store(rd + traits::X0,tu.constant((uint32_t)-1,32)); } tu.close_scope(); } @@ -2244,7 +2203,7 @@ private: else{ tu.open_if(tu.icmp(ICmpInst::ICMP_NE,tu.load(rs2+ traits::X0, 0),tu.constant( 0,8))); auto MMIN = tu.assignment(tu.constant( 1<<(static_cast(traits:: XLEN)-1),8),32); - tu.open_if(tu.logical_and(tu.icmp(ICmpInst::ICMP_EQ,tu.load(rs1+ traits::X0, 0),MMIN),tu.icmp(ICmpInst::ICMP_EQ,tu.ext(tu.load(rs2+ traits::X0, 0),32,false),tu.constant(- 1,8)))); + tu.open_if(tu.logical_and(tu.icmp(ICmpInst::ICMP_EQ,tu.load(rs1+ traits::X0, 0),MMIN),tu.icmp(ICmpInst::ICMP_EQ,tu.ext(tu.load(rs2+ traits::X0, 0),32,false),tu.constant(-1,8)))); if(rd!=0) { tu.store(rd + traits::X0,tu.constant( 0,8)); } @@ -2353,8 +2312,8 @@ private: pc=pc+ 2; gen_set_pc(tu, pc, traits::NEXT_PC); tu.open_scope(); - auto load_address = tu.assignment(tu.ext((tu.add(tu.load(rs1+ 8+ traits::X0, 0),tu.constant(uimm,8))),32,true),32); - tu.store(rd+ 8 + traits::X0,tu.ext(tu.ext(tu.read_mem(traits::MEM, load_address, 32),32,false),32,true)); + auto offs = tu.assignment(tu.ext((tu.add(tu.load(rs1+ 8+ traits::X0, 0),tu.constant(uimm,8))),32,true),32); + tu.store(rd+ 8 + traits::X0,tu.ext(tu.ext(tu.read_mem(traits::MEM, offs, 32),32,false),32,true)); auto returnValue = std::make_tuple(CONT); tu.close_scope(); vm_base::gen_sync(tu, POST_SYNC,58); @@ -2380,8 +2339,8 @@ private: pc=pc+ 2; gen_set_pc(tu, pc, traits::NEXT_PC); tu.open_scope(); - auto load_address = tu.assignment(tu.ext((tu.add(tu.load(rs1+ 8+ traits::X0, 0),tu.constant(uimm,8))),32,true),32); - tu.write_mem(traits::MEM, load_address, tu.ext(tu.load(rs2+ 8+ traits::X0, 0),32,true)); + auto offs = tu.assignment(tu.ext((tu.add(tu.load(rs1+ 8+ traits::X0, 0),tu.constant(uimm,8))),32,true),32); + tu.write_mem(traits::MEM, offs, tu.ext(tu.load(rs2+ 8+ traits::X0, 0),32,true)); auto returnValue = std::make_tuple(CONT); tu.close_scope(); vm_base::gen_sync(tu, POST_SYNC,59); @@ -2898,8 +2857,7 @@ private: } else{ auto offs = tu.assignment(tu.ext((tu.add(tu.load(2+ traits::X0, 0),tu.constant(uimm,8))),32,true),32); - auto res = tu.assignment(tu.ext(tu.read_mem(traits::MEM, offs, 32),32,false),32); - tu.store(rd + traits::X0,tu.ext(res,32,true)); + tu.store(rd + traits::X0,tu.ext(tu.ext(tu.read_mem(traits::MEM, offs, 32),32,false),32,true)); } auto returnValue = std::make_tuple(CONT); tu.close_scope(); @@ -2957,7 +2915,7 @@ private: gen_set_pc(tu, pc, traits::NEXT_PC); tu.open_scope(); if(rs1&&rs1(traits:: RFS)) { - auto PC_val_v = tu.assignment("PC_val", tu.bitwise_and(tu.load(rs1%static_cast(traits:: RFS)+ traits::X0, 0),tu.constant(~ 0x1,8)),32); + auto PC_val_v = tu.assignment("PC_val", tu.bitwise_and(tu.load(rs1%static_cast(traits:: RFS)+ traits::X0, 0),tu.constant(~0x1,8)),32); tu.store(traits::NEXT_PC, PC_val_v); tu.store(traits::LAST_BRANCH, tu.constant(2U, 2)); } @@ -3045,7 +3003,7 @@ private: else{ auto new_pc = tu.assignment(tu.load(rs1+ traits::X0, 0),32); tu.store(1 + traits::X0,tu.ext((tu.add(tu.ext(cur_pc_val,32,false),tu.constant( 2,8))),32,true)); - auto PC_val_v = tu.assignment("PC_val", tu.bitwise_and(new_pc,tu.constant(~ 0x1,8)),32); + auto PC_val_v = tu.assignment("PC_val", tu.bitwise_and(new_pc,tu.constant(~0x1,8)),32); tu.store(traits::NEXT_PC, PC_val_v); tu.store(traits::LAST_BRANCH, tu.constant(2U, 2)); } @@ -3138,11 +3096,64 @@ private: vm_impl::gen_trap_check(tu); return BRANCH; } + + //decoding functionality + + void populate_decoding_tree(decoding_tree_node* root){ + //create submask + for(auto instr: root->instrs){ + root->submask &= instr.mask; + } + //put each instr according to submask&encoding into children + for(auto instr: root->instrs){ + bool foundMatch = false; + for(auto child: root->children){ + //use value as identifying trait + if(child->value == (instr.value&root->submask)){ + child->instrs.push_back(instr); + foundMatch = true; + } + } + if(!foundMatch){ + decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask); + child->instrs.push_back(instr); + root->children.push_back(child); + } + } + root->instrs.clear(); + //call populate_decoding_tree for all children + if(root->children.size() >1) + for(auto child: root->children){ + populate_decoding_tree(child); + } + else{ + //sort instrs by value of the mask, this works bc we want to have the least restrictive one last + std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) { + return instr1.mask > instr2.mask; + }); + } + } + compile_func decode_instr(decoding_tree_node* node, code_word_t word){ + if(!node->children.size()){ + if(node->instrs.size() == 1) return node->instrs[0].op; + for(auto instr : node->instrs){ + if((instr.mask&word) == instr.value) return instr.op; + } + } + else{ + for(auto child : node->children){ + if (child->value == (node->submask&word)){ + return decode_instr(child, word); + } + } + } + return nullptr; + } }; -template void debug_fn(CODE_WORD insn) { - volatile CODE_WORD x = insn; - insn = 2 * x; +template void debug_fn(CODE_WORD instr) { + volatile CODE_WORD x = instr; + instr = 2 * x; } template vm_impl::vm_impl() { this(new ARCH()); } @@ -3150,14 +3161,11 @@ template vm_impl::vm_impl() { this(new ARCH()); } template vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) : vm_base(core, core_id, cluster_id) { - qlut[0] = lut_00.data(); - qlut[1] = lut_01.data(); - qlut[2] = lut_10.data(); - qlut[3] = lut_11.data(); - for (auto instr : instr_descr) { - auto quantrant = instr.value & 0x3; - expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op); + root = new decoding_tree_node(std::numeric_limits::max()); + for(auto instr:instr_descr){ + root->instrs.push_back(instr); } + populate_decoding_tree(root); } template @@ -3165,30 +3173,19 @@ std::tuple vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) { // we fetch at max 4 byte, alignment is 2 enum {TRAP_ID=1<<16}; - code_word_t insn = 0; - // const typename traits::addr_t upper_bits = ~traits::PGMASK; + code_word_t instr = 0; phys_addr_t paddr(pc); - auto *const data = (uint8_t *)&insn; paddr = this->core.v2p(pc); -// if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary -// auto res = this->core.read(paddr, 2, data); -// if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); -// if ((insn & 0x3) == 0x3) { // this is a 32bit instruction -// res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); -// } -// } else { - auto res = this->core.read(paddr, 4, data); - if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); -// } - if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' + auto res = this->core.read(paddr, 4, reinterpret_cast(&instr)); + if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); + if (instr == 0x0000006f || (instr&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' // curr pc on stack ++inst_cnt; - auto lut_val = extract_fields(insn); - auto f = qlut[insn & 0x3][lut_val]; + auto f = decode_instr(root, instr); if (f == nullptr) { f = &this_class::illegal_intruction; } - return (this->*f)(pc, insn, tu); + return (this->*f)(pc, instr, tu); } template void vm_impl::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) { From f38cc7d8b9c84daeb95b2304e9e1947f581c2a70 Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Sat, 29 Jul 2023 17:55:37 +0200 Subject: [PATCH 10/14] updates LLVM build --- CMakeLists.txt | 12 +- ...m-vm_CORENAME.cpp.gtl => CORENAME.cpp.gtl} | 62 +++-- .../templates/llvm/CORENAME_cyles.txt.gtl | 9 - gen_input/templates/llvm/incl-CORENAME.h.gtl | 223 ------------------ gen_input/templates/llvm/src-CORENAME.cpp.gtl | 107 --------- src/vm/interp/vm_tgc_c.cpp | 1 + src/vm/llvm/vm_tgc_c.cpp | 59 +++-- src/vm/tcc/vm_tgc_c.cpp | 1 + 8 files changed, 96 insertions(+), 378 deletions(-) rename gen_input/templates/llvm/{vm-vm_CORENAME.cpp.gtl => CORENAME.cpp.gtl} (82%) delete mode 100644 gen_input/templates/llvm/CORENAME_cyles.txt.gtl delete mode 100644 gen_input/templates/llvm/incl-CORENAME.h.gtl delete mode 100644 gen_input/templates/llvm/src-CORENAME.cpp.gtl diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ad2123..64cd15b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,9 @@ set(LIB_SOURCES if(WITH_TCC) list(APPEND LIB_SOURCES src/vm/tcc/vm_tgc_c.cpp) endif() +if(WITH_LLVM) + list(APPEND LIB_SOURCES src/vm/llvm/vm_tgc_c.cpp src/vm/llvm/fp_impl.cpp) +endif() # library files FILE(GLOB GEN_ISS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp) @@ -70,7 +73,7 @@ endif() add_library(${PROJECT_NAME} ${LIB_SOURCES}) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - target_compile_options(${PROJECT_NAME} PRIVATE -Wno-shift-count-overflow) + target_compile_options(${PROJECT_NAME} PRIVATE -Wno-shift-count-overflow) elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") target_compile_options(${PROJECT_NAME} PRIVATE /wd4293) endif() @@ -101,6 +104,13 @@ if(TARGET RapidJSON::RapidJSON) elseif(TARGET RapidJSON) target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON) endif() +if(WITH_LLVM) + target_compile_definitions(${PROJECT_NAME} PUBLIC ${LLVM_DEFINITIONS}) + target_include_directories(${PROJECT_NAME} PUBLIC ${LLVM_INCLUDE_DIRS}) + if(BUILD_SHARED_LIBS) + target_link_libraries( ${PROJECT_NAME} PUBLIC ${LLVM_LIBRARIES}) + endif() +endif() set_target_properties(${PROJECT_NAME} PROPERTIES diff --git a/gen_input/templates/llvm/vm-vm_CORENAME.cpp.gtl b/gen_input/templates/llvm/CORENAME.cpp.gtl similarity index 82% rename from gen_input/templates/llvm/vm-vm_CORENAME.cpp.gtl rename to gen_input/templates/llvm/CORENAME.cpp.gtl index d0a8067..5eb61cf 100644 --- a/gen_input/templates/llvm/vm-vm_CORENAME.cpp.gtl +++ b/gen_input/templates/llvm/CORENAME.cpp.gtl @@ -30,10 +30,9 @@ * *******************************************************************************/ +#include #include #include -#include -#include #include #include #include @@ -111,7 +110,7 @@ protected: void gen_trap_check(BasicBlock *bb); inline Value *gen_reg_load(unsigned i, unsigned level = 0) { - return this->builder.CreateLoad(get_reg_ptr(i), false); + return this->builder.CreateLoad(this->get_typeptr(i), get_reg_ptr(i), false); } inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) { @@ -124,7 +123,7 @@ protected: // enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 }; enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 }; enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 }; - enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) }; + enum { LUT_SIZE = 1 << util::bit_count(static_cast(EXTR_MASK32)), LUT_SIZE_C = 1 << util::bit_count(static_cast(EXTR_MASK16)) }; using this_class = vm_impl; using compile_func = std::tuple (this_class::*)(virt_addr_t &pc, @@ -204,10 +203,10 @@ private: ****************************************************************************/ std::tuple illegal_intruction(virt_addr_t &pc, code_word_t instr, BasicBlock *bb) { this->gen_sync(iss::PRE_SYNC, instr_descr.size()); - this->builder.CreateStore(this->builder.CreateLoad(get_reg_ptr(traits::NEXT_PC), true), + this->builder.CreateStore(this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC), get_reg_ptr(traits::NEXT_PC), true), get_reg_ptr(traits::PC), true); this->builder.CreateStore( - this->builder.CreateAdd(this->builder.CreateLoad(get_reg_ptr(traits::ICOUNT), true), + this->builder.CreateAdd(this->builder.CreateLoad(this->get_typeptr(traits::ICOUNT), get_reg_ptr(traits::ICOUNT), true), this->gen_const(64U, 1)), get_reg_ptr(traits::ICOUNT), true); pc = pc + ((instr & 3) == 3 ? 4 : 2); @@ -244,20 +243,21 @@ vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, // we fetch at max 4 byte, alignment is 2 enum {TRAP_ID=1<<16}; code_word_t insn = 0; - const typename traits::addr_t upper_bits = ~traits::PGMASK; + // const typename traits::addr_t upper_bits = ~traits::PGMASK; phys_addr_t paddr(pc); auto *const data = (uint8_t *)&insn; paddr = this->core.v2p(pc); - if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary - auto res = this->core.read(paddr, 2, data); - if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); - if ((insn & 0x3) == 0x3) { // this is a 32bit instruction - res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); - } - } else { + //TODO: re-add page handling +// if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary +// auto res = this->core.read(paddr, 2, data); +// if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); +// if ((insn & 0x3) == 0x3) { // this is a 32bit instruction +// res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); +// } +// } else { auto res = this->core.read(paddr, 4, data); if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); - } +// } if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' // curr pc on stack ++inst_cnt; @@ -271,7 +271,7 @@ vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, template void vm_impl::gen_leave_behavior(BasicBlock *leave_blk) { this->builder.SetInsertPoint(leave_blk); - this->builder.CreateRet(this->builder.CreateLoad(get_reg_ptr(arch::traits::NEXT_PC), false)); + this->builder.CreateRet(this->builder.CreateLoad(this->get_typeptr(arch::traits::NEXT_PC), get_reg_ptr(arch::traits::NEXT_PC), false)); } template void vm_impl::gen_raise_trap(uint16_t trap_id, uint16_t cause) { @@ -295,18 +295,18 @@ template void vm_impl::gen_wait(unsigned type) { template void vm_impl::gen_trap_behavior(BasicBlock *trap_blk) { this->builder.SetInsertPoint(trap_blk); - auto *trap_state_val = this->builder.CreateLoad(get_reg_ptr(traits::TRAP_STATE), true); + auto *trap_state_val = this->builder.CreateLoad(this->get_typeptr(arch::traits::TRAP_STATE), get_reg_ptr(traits::TRAP_STATE), true); this->builder.CreateStore(this->gen_const(32U, std::numeric_limits::max()), get_reg_ptr(traits::LAST_BRANCH), false); std::vector args{this->core_ptr, this->adj_to64(trap_state_val), - this->adj_to64(this->builder.CreateLoad(get_reg_ptr(traits::PC), false))}; + this->adj_to64(this->builder.CreateLoad(this->get_typeptr(arch::traits::PC), get_reg_ptr(traits::PC), false))}; this->builder.CreateCall(this->mod->getFunction("enter_trap"), args); - auto *trap_addr_val = this->builder.CreateLoad(get_reg_ptr(traits::NEXT_PC), false); + auto *trap_addr_val = this->builder.CreateLoad(this->get_typeptr(arch::traits::NEXT_PC), get_reg_ptr(traits::NEXT_PC), false); this->builder.CreateRet(trap_addr_val); } template inline void vm_impl::gen_trap_check(BasicBlock *bb) { - auto *v = this->builder.CreateLoad(get_reg_ptr(arch::traits::TRAP_STATE), true); + auto *v = this->builder.CreateLoad(this->get_typeptr(arch::traits::TRAP_STATE), get_reg_ptr(arch::traits::TRAP_STATE), true); this->gen_cond_branch(this->builder.CreateICmp( ICmpInst::ICMP_EQ, v, ConstantInt::get(getContext(), APInt(v->getType()->getIntegerBitWidth(), 0))), @@ -323,3 +323,25 @@ std::unique_ptr create(arch::${coreD } } // namespace llvm } // namespace iss + +#include +#include +#include +namespace iss { +namespace { +volatile std::array dummy = { + core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|llvm", [](unsigned port, void*) -> std::tuple{ + auto* cpu = new iss::arch::riscv_hart_m_p(); + auto* vm = new llvm::${coreDef.name.toLowerCase()}::vm_impl(*cpu, false); + if (port != 0) debugger::server::run_server(vm, port); + return {cpu_ptr{cpu}, vm_ptr{vm}}; + }), + core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|llvm", [](unsigned port, void*) -> std::tuple{ + auto* cpu = new iss::arch::riscv_hart_mu_p(); + auto* vm = new llvm::${coreDef.name.toLowerCase()}::vm_impl(*cpu, false); + if (port != 0) debugger::server::run_server(vm, port); + return {cpu_ptr{cpu}, vm_ptr{vm}}; + }) +}; +} +} diff --git a/gen_input/templates/llvm/CORENAME_cyles.txt.gtl b/gen_input/templates/llvm/CORENAME_cyles.txt.gtl deleted file mode 100644 index 3a1ad8e..0000000 --- a/gen_input/templates/llvm/CORENAME_cyles.txt.gtl +++ /dev/null @@ -1,9 +0,0 @@ -{ - "${coreDef.name}" : [<%instructions.eachWithIndex{instr,index -> %>${index==0?"":","} - { - "name" : "${instr.name}", - "size" : ${instr.length}, - "delay" : ${generator.hasAttribute(instr.instruction, com.minres.coredsl.coreDsl.InstrAttribute.COND)?[1,1]:1} - }<%}%> - ] -} \ No newline at end of file diff --git a/gen_input/templates/llvm/incl-CORENAME.h.gtl b/gen_input/templates/llvm/incl-CORENAME.h.gtl deleted file mode 100644 index 0a5b99f..0000000 --- a/gen_input/templates/llvm/incl-CORENAME.h.gtl +++ /dev/null @@ -1,223 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2017, 2018 MINRES Technologies GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - *******************************************************************************/ - -<% -import com.minres.coredsl.coreDsl.Register -import com.minres.coredsl.coreDsl.RegisterFile -import com.minres.coredsl.coreDsl.RegisterAlias -def getTypeSize(size){ - if(size > 32) 64 else if(size > 16) 32 else if(size > 8) 16 else 8 -} -def getOriginalName(reg){ - if( reg.original instanceof RegisterFile) { - if( reg.index != null ) { - return reg.original.name+generator.generateHostCode(reg.index) - } else { - return reg.original.name - } - } else if(reg.original instanceof Register){ - return reg.original.name - } -} -def getRegisterNames(){ - def regNames = [] - allRegs.each { reg -> - if( reg instanceof RegisterFile) { - (reg.range.right..reg.range.left).each{ - regNames+=reg.name.toLowerCase()+it - } - } else if(reg instanceof Register){ - regNames+=reg.name.toLowerCase() - } - } - return regNames -} -def getRegisterAliasNames(){ - def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]} - return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg -> - if( reg instanceof RegisterFile) { - return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() } - } else if(reg instanceof Register){ - regMap[reg.name]?:reg.name.toLowerCase() - } - }.flatten() -} -%> -#ifndef _${coreDef.name.toUpperCase()}_H_ -#define _${coreDef.name.toUpperCase()}_H_ - -#include -#include -#include -#include - -namespace iss { -namespace arch { - -struct ${coreDef.name.toLowerCase()}; - -template <> struct traits<${coreDef.name.toLowerCase()}> { - - constexpr static char const* const core_type = "${coreDef.name}"; - - static constexpr std::array reg_names{ - {"${getRegisterNames().join("\", \"")}"}}; - - static constexpr std::array reg_aliases{ - {"${getRegisterAliasNames().join("\", \"")}"}}; - - enum constants {${coreDef.constants.collect{c -> c.name+"="+c.value}.join(', ')}}; - - constexpr static unsigned FP_REGS_SIZE = ${coreDef.constants.find {it.name=='FLEN'}?.value?:0}; - - enum reg_e {<% - allRegs.each { reg -> - if( reg instanceof RegisterFile) { - (reg.range.right..reg.range.left).each{%> - ${reg.name}${it},<% - } - } else if(reg instanceof Register){ %> - ${reg.name},<% - } - }%> - NUM_REGS, - NEXT_${pc.name}=NUM_REGS, - TRAP_STATE, - PENDING_TRAP, - MACHINE_STATE, - LAST_BRANCH, - ICOUNT<% - allRegs.each { reg -> - if(reg instanceof RegisterAlias){ def aliasname=getOriginalName(reg)%>, - ${reg.name} = ${aliasname}<% - } - }%> - }; - - using reg_t = uint${regDataWidth}_t; - - using addr_t = uint${addrDataWidth}_t; - - using code_word_t = uint${addrDataWidth}_t; //TODO: check removal - - using virt_addr_t = iss::typed_addr_t; - - using phys_addr_t = iss::typed_addr_t; - - static constexpr std::array reg_bit_widths{ - {${regSizes.join(",")}}}; - - static constexpr std::array reg_byte_offsets{ - {${regOffsets.join(",")}}}; - - static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1); - - enum sreg_flag_e { FLAGS }; - - enum mem_type_e { ${allSpaces.collect{s -> s.name}.join(', ')} }; -}; - -struct ${coreDef.name.toLowerCase()}: public arch_if { - - using virt_addr_t = typename traits<${coreDef.name.toLowerCase()}>::virt_addr_t; - using phys_addr_t = typename traits<${coreDef.name.toLowerCase()}>::phys_addr_t; - using reg_t = typename traits<${coreDef.name.toLowerCase()}>::reg_t; - using addr_t = typename traits<${coreDef.name.toLowerCase()}>::addr_t; - - ${coreDef.name.toLowerCase()}(); - ~${coreDef.name.toLowerCase()}(); - - void reset(uint64_t address=0) override; - - uint8_t* get_regs_base_ptr() override; - /// deprecated - void get_reg(short idx, std::vector& value) override {} - void set_reg(short idx, const std::vector& value) override {} - /// deprecated - bool get_flag(int flag) override {return false;} - void set_flag(int, bool value) override {}; - /// deprecated - void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {}; - - inline uint64_t get_icount() { return reg.icount; } - - inline bool should_stop() { return interrupt_sim; } - - inline uint64_t stop_code() { return interrupt_sim; } - - inline phys_addr_t v2p(const iss::addr_t& addr){ - if (addr.space != traits<${coreDef.name.toLowerCase()}>::MEM || addr.type == iss::address_type::PHYSICAL || - addr_mode[static_cast(addr.access)&0x3]==address_type::PHYSICAL) { - return phys_addr_t(addr.access, addr.space, addr.val&traits<${coreDef.name.toLowerCase()}>::addr_mask); - } else - return virt2phys(addr); - } - - virtual phys_addr_t virt2phys(const iss::addr_t& addr); - - virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } - - inline uint32_t get_last_branch() { return reg.last_branch; } - -protected: - struct ${coreDef.name}_regs {<% - allRegs.each { reg -> - if( reg instanceof RegisterFile) { - (reg.range.right..reg.range.left).each{%> - uint${generator.getSize(reg)}_t ${reg.name}${it} = 0;<% - } - } else if(reg instanceof Register){ %> - uint${generator.getSize(reg)}_t ${reg.name} = 0;<% - } - }%> - uint${generator.getSize(pc)}_t NEXT_${pc.name} = 0; - uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0; - uint64_t icount = 0; - } reg; - - std::array addr_mode; - - uint64_t interrupt_sim=0; -<% -def fcsr = allRegs.find {it.name=='FCSR'} -if(fcsr != null) {%> - uint${generator.getSize(fcsr)}_t get_fcsr(){return reg.FCSR;} - void set_fcsr(uint${generator.getSize(fcsr)}_t val){reg.FCSR = val;} -<%} else { %> - uint32_t get_fcsr(){return 0;} - void set_fcsr(uint32_t val){} -<%}%> -}; - -} -} -#endif /* _${coreDef.name.toUpperCase()}_H_ */ diff --git a/gen_input/templates/llvm/src-CORENAME.cpp.gtl b/gen_input/templates/llvm/src-CORENAME.cpp.gtl deleted file mode 100644 index 8ed478f..0000000 --- a/gen_input/templates/llvm/src-CORENAME.cpp.gtl +++ /dev/null @@ -1,107 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2017, 2018 MINRES Technologies GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - *******************************************************************************/ - <% -import com.minres.coredsl.coreDsl.Register -import com.minres.coredsl.coreDsl.RegisterFile -import com.minres.coredsl.coreDsl.RegisterAlias -def getOriginalName(reg){ - if( reg.original instanceof RegisterFile) { - if( reg.index != null ) { - return reg.original.name+generator.generateHostCode(reg.index) - } else { - return reg.original.name - } - } else if(reg.original instanceof Register){ - return reg.original.name - } -} -def getRegisterNames(){ - def regNames = [] - allRegs.each { reg -> - if( reg instanceof RegisterFile) { - (reg.range.right..reg.range.left).each{ - regNames+=reg.name.toLowerCase()+it - } - } else if(reg instanceof Register){ - regNames+=reg.name.toLowerCase() - } - } - return regNames -} -def getRegisterAliasNames(){ - def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]} - return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg -> - if( reg instanceof RegisterFile) { - return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() } - } else if(reg instanceof Register){ - regMap[reg.name]?:reg.name.toLowerCase() - } - }.flatten() -} -%> -#include "util/ities.h" -#include -#include -#include -#include -#include - -using namespace iss::arch; - -constexpr std::array iss::arch::traits::reg_names; -constexpr std::array iss::arch::traits::reg_aliases; -constexpr std::array iss::arch::traits::reg_bit_widths; -constexpr std::array iss::arch::traits::reg_byte_offsets; - -${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() { - reg.icount = 0; -} - -${coreDef.name.toLowerCase()}::~${coreDef.name.toLowerCase()}() = default; - -void ${coreDef.name.toLowerCase()}::reset(uint64_t address) { - for(size_t i=0; i::NUM_REGS; ++i) set_reg(i, std::vector(sizeof(traits<${coreDef.name.toLowerCase()}>::reg_t),0)); - reg.PC=address; - reg.NEXT_PC=reg.PC; - reg.trap_state=0; - reg.machine_state=0x3; - reg.icount=0; -} - -uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() { - return reinterpret_cast(®); -} - -${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &pc) { - return phys_addr_t(pc); // change logical address to physical address -} - diff --git a/src/vm/interp/vm_tgc_c.cpp b/src/vm/interp/vm_tgc_c.cpp index 3b409df..2d48193 100644 --- a/src/vm/interp/vm_tgc_c.cpp +++ b/src/vm/interp/vm_tgc_c.cpp @@ -253,6 +253,7 @@ private: //static constexpr typename traits::addr_t upper_bits = ~traits::PGMASK; iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ auto phys_pc = this->core.v2p(pc); + //TODO: re-add page handling //if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary // if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err; // if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction diff --git a/src/vm/llvm/vm_tgc_c.cpp b/src/vm/llvm/vm_tgc_c.cpp index e712445..f289f0c 100644 --- a/src/vm/llvm/vm_tgc_c.cpp +++ b/src/vm/llvm/vm_tgc_c.cpp @@ -111,7 +111,7 @@ protected: void gen_trap_check(BasicBlock *bb); inline Value *gen_reg_load(unsigned i, unsigned level = 0) { - return this->builder.CreateLoad(get_reg_ptr(i), false); + return this->builder.CreateLoad(this->get_typeptr(i), get_reg_ptr(i), false); } inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) { @@ -124,7 +124,7 @@ protected: // enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 }; enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 }; enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 }; - enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) }; + enum { LUT_SIZE = 1 << util::bit_count(static_cast(EXTR_MASK32)), LUT_SIZE_C = 1 << util::bit_count(static_cast(EXTR_MASK16)) }; using this_class = vm_impl; using compile_func = std::tuple (this_class::*)(virt_addr_t &pc, @@ -4042,10 +4042,10 @@ private: ****************************************************************************/ std::tuple illegal_intruction(virt_addr_t &pc, code_word_t instr, BasicBlock *bb) { this->gen_sync(iss::PRE_SYNC, instr_descr.size()); - this->builder.CreateStore(this->builder.CreateLoad(get_reg_ptr(traits::NEXT_PC), true), + this->builder.CreateStore(this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC), get_reg_ptr(traits::NEXT_PC), true), get_reg_ptr(traits::PC), true); this->builder.CreateStore( - this->builder.CreateAdd(this->builder.CreateLoad(get_reg_ptr(traits::ICOUNT), true), + this->builder.CreateAdd(this->builder.CreateLoad(this->get_typeptr(traits::ICOUNT), get_reg_ptr(traits::ICOUNT), true), this->gen_const(64U, 1)), get_reg_ptr(traits::ICOUNT), true); pc = pc + ((instr & 3) == 3 ? 4 : 2); @@ -4082,20 +4082,21 @@ vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, // we fetch at max 4 byte, alignment is 2 enum {TRAP_ID=1<<16}; code_word_t insn = 0; - const typename traits::addr_t upper_bits = ~traits::PGMASK; + // const typename traits::addr_t upper_bits = ~traits::PGMASK; phys_addr_t paddr(pc); auto *const data = (uint8_t *)&insn; paddr = this->core.v2p(pc); - if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary - auto res = this->core.read(paddr, 2, data); - if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); - if ((insn & 0x3) == 0x3) { // this is a 32bit instruction - res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); - } - } else { + //TODO: re-add page handling +// if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary +// auto res = this->core.read(paddr, 2, data); +// if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); +// if ((insn & 0x3) == 0x3) { // this is a 32bit instruction +// res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); +// } +// } else { auto res = this->core.read(paddr, 4, data); if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); - } +// } if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' // curr pc on stack ++inst_cnt; @@ -4109,7 +4110,7 @@ vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, template void vm_impl::gen_leave_behavior(BasicBlock *leave_blk) { this->builder.SetInsertPoint(leave_blk); - this->builder.CreateRet(this->builder.CreateLoad(get_reg_ptr(arch::traits::NEXT_PC), false)); + this->builder.CreateRet(this->builder.CreateLoad(this->get_typeptr(arch::traits::NEXT_PC), get_reg_ptr(arch::traits::NEXT_PC), false)); } template void vm_impl::gen_raise_trap(uint16_t trap_id, uint16_t cause) { @@ -4133,18 +4134,18 @@ template void vm_impl::gen_wait(unsigned type) { template void vm_impl::gen_trap_behavior(BasicBlock *trap_blk) { this->builder.SetInsertPoint(trap_blk); - auto *trap_state_val = this->builder.CreateLoad(get_reg_ptr(traits::TRAP_STATE), true); + auto *trap_state_val = this->builder.CreateLoad(this->get_typeptr(arch::traits::TRAP_STATE), get_reg_ptr(traits::TRAP_STATE), true); this->builder.CreateStore(this->gen_const(32U, std::numeric_limits::max()), get_reg_ptr(traits::LAST_BRANCH), false); std::vector args{this->core_ptr, this->adj_to64(trap_state_val), - this->adj_to64(this->builder.CreateLoad(get_reg_ptr(traits::PC), false))}; + this->adj_to64(this->builder.CreateLoad(this->get_typeptr(arch::traits::PC), get_reg_ptr(traits::PC), false))}; this->builder.CreateCall(this->mod->getFunction("enter_trap"), args); - auto *trap_addr_val = this->builder.CreateLoad(get_reg_ptr(traits::NEXT_PC), false); + auto *trap_addr_val = this->builder.CreateLoad(this->get_typeptr(arch::traits::NEXT_PC), get_reg_ptr(traits::NEXT_PC), false); this->builder.CreateRet(trap_addr_val); } template inline void vm_impl::gen_trap_check(BasicBlock *bb) { - auto *v = this->builder.CreateLoad(get_reg_ptr(arch::traits::TRAP_STATE), true); + auto *v = this->builder.CreateLoad(this->get_typeptr(arch::traits::TRAP_STATE), get_reg_ptr(arch::traits::TRAP_STATE), true); this->gen_cond_branch(this->builder.CreateICmp( ICmpInst::ICMP_EQ, v, ConstantInt::get(getContext(), APInt(v->getType()->getIntegerBitWidth(), 0))), @@ -4161,3 +4162,25 @@ std::unique_ptr create(arch::tgc_c *core, unsigned short por } } // namespace llvm } // namespace iss + +#include +#include +#include +namespace iss { +namespace { +volatile std::array dummy = { + core_factory::instance().register_creator("tgc_c|m_p|llvm", [](unsigned port, void*) -> std::tuple{ + auto* cpu = new iss::arch::riscv_hart_m_p(); + auto* vm = new llvm::tgc_c::vm_impl(*cpu, false); + if (port != 0) debugger::server::run_server(vm, port); + return {cpu_ptr{cpu}, vm_ptr{vm}}; + }), + core_factory::instance().register_creator("tgc_c|mu_p|llvm", [](unsigned port, void*) -> std::tuple{ + auto* cpu = new iss::arch::riscv_hart_mu_p(); + auto* vm = new llvm::tgc_c::vm_impl(*cpu, false); + if (port != 0) debugger::server::run_server(vm, port); + return {cpu_ptr{cpu}, vm_ptr{vm}}; + }) +}; +} +} diff --git a/src/vm/tcc/vm_tgc_c.cpp b/src/vm/tcc/vm_tgc_c.cpp index fee3a87..43c22bb 100644 --- a/src/vm/tcc/vm_tgc_c.cpp +++ b/src/vm/tcc/vm_tgc_c.cpp @@ -3168,6 +3168,7 @@ vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, phys_addr_t paddr(pc); auto *const data = (uint8_t *)&insn; paddr = this->core.v2p(pc); + //TODO: re-add page handling // if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary // auto res = this->core.read(paddr, 2, data); // if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); From 24de2bbdf5fa0b3514a715078a00995a91eb33ae Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Sun, 30 Jul 2023 13:55:57 +0200 Subject: [PATCH 11/14] purge build system --- CMakeLists.txt | 116 +++++++++++++++++++-------------------- src/iss/plugin/pctrace.h | 1 - 2 files changed, 56 insertions(+), 61 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 750c35e..b21636c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,41 +9,27 @@ include(GNUInstallDirs) include(flink) find_package(elfio QUIET) -find_package(Boost COMPONENTS coroutine) find_package(jsoncpp) - -if(TARGET tcc::tcc) - set(WITH_TCC ON) -endif() - -if(WITH_LLVM) - if(DEFINED ENV{LLVM_HOME}) - find_path (LLVM_DIR LLVM-Config.cmake $ENV{LLVM_HOME}/lib/cmake/llvm) - endif() - find_package(LLVM QUIET CONFIG) - if(LLVM_FOUND) - message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") - message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") - llvm_map_components_to_libnames(llvm_libs support core mcjit x86codegen x86asmparser) - else() - find_package(LLVM REQUIRED LLVMSupport LLVMCore LLVMMCJIT LLVMX86CodeGen LLVMX86AsmParser) - endif() -endif() +find_package(Boost COMPONENTS coroutine REQUIRED) add_subdirectory(softfloat) set(LIB_SOURCES - src/iss/plugin/instruction_count.cpp src/iss/arch/tgc_c.cpp src/vm/tcc/vm_tgc_c.cpp src/vm/interp/vm_tgc_c.cpp src/vm/fp_functions.cpp ) if(WITH_TCC) - list(APPEND LIB_SOURCES src/vm/tcc/vm_tgc_c.cpp) + list(APPEND LIB_SOURCES + src/vm/tcc/vm_tgc_c.cpp + ) endif() if(WITH_LLVM) - list(APPEND LIB_SOURCES src/vm/llvm/vm_tgc_c.cpp src/vm/llvm/fp_impl.cpp) + list(APPEND LIB_SOURCES + src/vm/llvm/vm_tgc_c.cpp + src/vm/llvm/fp_impl.cpp + ) endif() # library files @@ -55,7 +41,7 @@ foreach(FILEPATH ${GEN_ISS_SOURCES}) string(TOUPPER ${CORE} CORE) list(APPEND LIB_DEFINES CORE_${CORE}) endforeach() -message("Core defines are ${LIB_DEFINES}") +message(STATUS "Core defines are ${LIB_DEFINES}") if(WITH_LLVM) FILE(GLOB LLVM_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/llvm/vm_*.cpp) @@ -67,10 +53,17 @@ if(WITH_TCC) list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES}) endif() -if(TARGET RapidJSON OR TARGET RapidJSON::RapidJSON) - list(APPEND LIB_SOURCES src/iss/plugin/cycle_estimate.cpp src/iss/plugin/pctrace.cpp) +if(TARGET RapidJSON) + list(APPEND LIB_SOURCES + src/iss/plugin/cycle_estimate.cpp + src/iss/plugin/pctrace.cpp + ) +endif() +if(TARGET jsoncpp::jsoncpp) + list(APPEND LIB_SOURCES + src/iss/plugin/instruction_count.cpp + ) endif() - # Define the library add_library(${PROJECT_NAME} SHARED ${LIB_SOURCES}) @@ -81,37 +74,25 @@ elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") endif() target_include_directories(${PROJECT_NAME} PUBLIC src) target_include_directories(${PROJECT_NAME} PUBLIC src-gen) -target_link_libraries(${PROJECT_NAME} PUBLIC softfloat scc-util Boost::coroutine) + +target_force_link_libraries(${PROJECT_NAME} PRIVATE dbt-rise-core) +# only re-export the include paths +get_target_property(DBT_CORE_INCL dbt-rise-core INTERFACE_INCLUDE_DIRECTORIES) +target_include_directories(${PROJECT_NAME} INTERFACE ${DBT_CORE_INCL}) +get_target_property(DBT_CORE_DEFS dbt-rise-core INTERFACE_COMPILE_DEFINITIONS) +target_compile_definitions(${PROJECT_NAME} INTERFACE ${DBT_CORE_DEFS}) + +target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio softfloat scc-util Boost::coroutine) if(TARGET jsoncpp::jsoncpp) target_link_libraries(${PROJECT_NAME} PUBLIC jsoncpp::jsoncpp) -else() - target_link_libraries(${PROJECT_NAME} PUBLIC jsoncpp) -endif() - -target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-core) - -if(TARGET elfio::elfio) - target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio) -else() - message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing") endif() if(TARGET lz4::lz4) target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_LZ4) target_link_libraries(${PROJECT_NAME} PUBLIC lz4::lz4) endif() -if(TARGET RapidJSON::RapidJSON) - target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON::RapidJSON) -elseif(TARGET RapidJSON) +if(TARGET RapidJSON) target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON) endif() -if(WITH_LLVM) - target_compile_definitions(${PROJECT_NAME} PUBLIC ${LLVM_DEFINITIONS}) - target_include_directories(${PROJECT_NAME} PUBLIC ${LLVM_INCLUDE_DIRS}) - if(BUILD_SHARED_LIBS) - target_link_libraries( ${PROJECT_NAME} PUBLIC ${LLVM_LIBRARIES}) - endif() -endif() - set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION} @@ -156,15 +137,16 @@ foreach(F IN LISTS TGC_SOURCES) endif() endforeach() -if(WITH_LLVM) - target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM) - target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs}) -endif() -if(WITH_TCC) - target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_TCC) -endif() -# Links the target exe against the libraries -target_force_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc) +#if(WITH_LLVM) +# target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM) +# #target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs}) +#endif() +#if(WITH_TCC) +# target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_TCC) +#endif() + +target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc fmt::fmt) + if(TARGET Boost::program_options) target_link_libraries(${PROJECT_NAME} PUBLIC Boost::program_options) else() @@ -184,6 +166,20 @@ install(TARGETS tgc-sim PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} # headers for mac (note the different component -> different package) INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers ) + +if(BUILD_TESTING) + # ... CMake code to create tests ... + add_test(NAME tgc-sim-interp + COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend interp) + if(WITH_TCC) + add_test(NAME tgc-sim-tcc + COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend tcc) + endif() + if(WITH_LLVM) + add_test(NAME tgc-sim-llvm + COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend llvm) + endif() +endif() ############################################################################### # ############################################################################### @@ -206,9 +202,9 @@ if(TARGET scc-sysc) endif() endforeach() target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc-sysc) - if(WITH_LLVM) - target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs}) - endif() +# if(WITH_LLVM) +# target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs}) +# endif() set(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/sysc/core_complex.h) set_target_properties(${PROJECT_NAME} PROPERTIES diff --git a/src/iss/plugin/pctrace.h b/src/iss/plugin/pctrace.h index 092719d..0e89110 100644 --- a/src/iss/plugin/pctrace.h +++ b/src/iss/plugin/pctrace.h @@ -37,7 +37,6 @@ #include #include "iss/instrumentation_if.h" -#include #include #include From e151416f5878ccc2bfca00e7e7c86084c46e40bd Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Mon, 31 Jul 2023 12:55:09 +0200 Subject: [PATCH 12/14] fixes systemc factory registration --- gen_input/templates/CORENAME_sysc.cpp.gtl | 14 ++++++++------ src/sysc/register_tgc_c.cpp | 14 ++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/gen_input/templates/CORENAME_sysc.cpp.gtl b/gen_input/templates/CORENAME_sysc.cpp.gtl index e56e7db..3ef2df9 100644 --- a/gen_input/templates/CORENAME_sysc.cpp.gtl +++ b/gen_input/templates/CORENAME_sysc.cpp.gtl @@ -36,6 +36,7 @@ #include #include "sc_core_adapter.h" #include "core_complex.h" +#include namespace iss { namespace interp { @@ -55,16 +56,17 @@ volatile std::array ${coreDef.name.toLowerCase()}_init = { } #if defined(WITH_TCC) namespace tcc { +using namespace sysc; volatile std::array ${coreDef.name.toLowerCase()}_init = { - core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned gdb_port, void* data) -> std::tuple{ - auto cc = reinterpret_cast(data); + iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t { + auto* cc = reinterpret_cast(data); auto* cpu = new sc_core_adapter>(cc); - return {cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; + return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; }), - core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned gdb_port, void* data) -> std::tuple{ - auto cc = reinterpret_cast(data); + iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t { + auto* cc = reinterpret_cast(data); auto* cpu = new sc_core_adapter>(cc); - return {cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; + return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; }) }; } diff --git a/src/sysc/register_tgc_c.cpp b/src/sysc/register_tgc_c.cpp index 31a99a5..4fd8eac 100644 --- a/src/sysc/register_tgc_c.cpp +++ b/src/sysc/register_tgc_c.cpp @@ -36,6 +36,7 @@ #include #include "sc_core_adapter.h" #include "core_complex.h" +#include namespace iss { namespace interp { @@ -55,16 +56,17 @@ volatile std::array tgc_init = { } #if defined(WITH_TCC) namespace tcc { +using namespace sysc; volatile std::array tgc_init = { - core_factory::instance().register_creator("tgc_c|m_p|tcc", [](unsigned gdb_port, void* data) -> std::tuple{ - auto cc = reinterpret_cast(data); + iss_factory::instance().register_creator("tgc_c|m_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t { + auto* cc = reinterpret_cast(data); auto* cpu = new sc_core_adapter>(cc); - return {cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; + return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; }), - core_factory::instance().register_creator("tgc_c|mu_p|tcc", [](unsigned gdb_port, void* data) -> std::tuple{ - auto cc = reinterpret_cast(data); + iss_factory::instance().register_creator("tgc_c|mu_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t { + auto* cc = reinterpret_cast(data); auto* cpu = new sc_core_adapter>(cc); - return {cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; + return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; }) }; } From 20e920338c43c7e8960c158877904b6ab9abb1a3 Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Fri, 4 Aug 2023 13:08:10 +0200 Subject: [PATCH 13/14] removes v2p function --- gen_input/templates/CORENAME.cpp.gtl | 4 ++-- gen_input/templates/CORENAME.h.gtl | 8 -------- src/iss/arch/riscv_hart_m_p.h | 17 ++++++++--------- src/iss/arch/riscv_hart_msu_vp.h | 11 ++++------- src/iss/arch/riscv_hart_mu_p.h | 19 +++++++++---------- src/iss/arch/tgc_c.cpp | 4 ++-- src/iss/arch/tgc_c.h | 9 --------- src/vm/interp/vm_tgc_c.cpp | 25 ++++++++++++++++--------- src/vm/llvm/vm_tgc_c.cpp | 3 ++- src/vm/tcc/vm_tgc_c.cpp | 3 ++- 10 files changed, 45 insertions(+), 58 deletions(-) diff --git a/gen_input/templates/CORENAME.cpp.gtl b/gen_input/templates/CORENAME.cpp.gtl index b7468c7..ebdff65 100644 --- a/gen_input/templates/CORENAME.cpp.gtl +++ b/gen_input/templates/CORENAME.cpp.gtl @@ -70,7 +70,7 @@ uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() { return reinterpret_cast(®); } -${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &pc) { - return phys_addr_t(pc); // change logical address to physical address +${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &addr) { + return phys_addr_t(addr.access, addr.space, addr.val&traits<${coreDef.name.toLowerCase()}>::addr_mask); } diff --git a/gen_input/templates/CORENAME.h.gtl b/gen_input/templates/CORENAME.h.gtl index 2debd97..96ba762 100644 --- a/gen_input/templates/CORENAME.h.gtl +++ b/gen_input/templates/CORENAME.h.gtl @@ -137,14 +137,6 @@ struct ${coreDef.name.toLowerCase()}: public arch_if { inline uint64_t stop_code() { return interrupt_sim; } - inline phys_addr_t v2p(const iss::addr_t& addr){ - if (addr.space != traits<${coreDef.name.toLowerCase()}>::MEM || addr.type == iss::address_type::PHYSICAL || - addr_mode[static_cast(addr.access)&0x3]==address_type::PHYSICAL) { - return phys_addr_t(addr.access, addr.space, addr.val&traits<${coreDef.name.toLowerCase()}>::addr_mask); - } else - return virt2phys(addr); - } - virtual phys_addr_t virt2phys(const iss::addr_t& addr); virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } diff --git a/src/iss/arch/riscv_hart_m_p.h b/src/iss/arch/riscv_hart_m_p.h index 5df25e2..632bdd2 100644 --- a/src/iss/arch/riscv_hart_m_p.h +++ b/src/iss/arch/riscv_hart_m_p.h @@ -666,7 +666,7 @@ iss::status riscv_hart_m_p::read(const address_type type, const acce fault_data=addr; return iss::Err; } - auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr}); + phys_addr_t phys_addr{access, space, addr}; auto res = iss::Err; if(access != access_type::FETCH && memfn_range.size()){ auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple const& a){ @@ -759,7 +759,7 @@ iss::status riscv_hart_m_p::write(const address_type type, const acc fault_data=addr; return iss::Err; } - auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr}); + phys_addr_t phys_addr{access, space, addr}; auto res = iss::Err; if(access != access_type::FETCH && memfn_range.size()){ auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple const& a){ @@ -784,9 +784,8 @@ iss::status riscv_hart_m_p::write(const address_type type, const acc return iss::Err; } - phys_addr_t paddr = BASE::v2p(iss::addr_t{access, type, space, addr}); - if ((paddr.val + length) > mem.size()) return iss::Err; - switch (paddr.val) { + if ((addr + length) > mem.size()) return iss::Err; + switch (addr) { case 0x10013000: // UART0 base, TXFIFO reg case 0x10023000: // UART1 base, TXFIFO reg uart_buf << (char)data[0]; @@ -798,16 +797,16 @@ iss::status riscv_hart_m_p::write(const address_type type, const acc } return iss::Ok; case 0x10008000: { // HFROSC base, hfrosccfg reg - auto &p = mem(paddr.val / mem.page_size); - auto offs = paddr.val & mem.page_addr_mask; + auto &p = mem(addr / mem.page_size); + auto offs = addr & mem.page_addr_mask; std::copy(data, data + length, p.data() + offs); auto &x = *(p.data() + offs + 3); if (x & 0x40) x |= 0x80; // hfroscrdy = 1 if hfroscen==1 return iss::Ok; } case 0x10008008: { // HFROSC base, pllcfg reg - auto &p = mem(paddr.val / mem.page_size); - auto offs = paddr.val & mem.page_addr_mask; + auto &p = mem(addr / mem.page_size); + auto offs = addr & mem.page_addr_mask; std::copy(data, data + length, p.data() + offs); auto &x = *(p.data() + offs + 3); x |= 0x80; // set pll lock upon writing diff --git a/src/iss/arch/riscv_hart_msu_vp.h b/src/iss/arch/riscv_hart_msu_vp.h index b107aac..23a805b 100644 --- a/src/iss/arch/riscv_hart_msu_vp.h +++ b/src/iss/arch/riscv_hart_msu_vp.h @@ -430,6 +430,7 @@ template riscv_hart_msu_vp::riscv_hart_msu_vp() : state() , instr_if(*this) { + this->_has_mmu = true; // reset values csr[misa] = traits::MISA_VAL; csr[mvendorid] = 0x669; @@ -632,9 +633,7 @@ iss::status riscv_hart_msu_vp::read(const address_type type, const access_ return res; } } - auto res = type==iss::address_type::PHYSICAL? - read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data): - read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data); + auto res = read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data); if (unlikely(res != iss::Ok)){ this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault fault_data=addr; @@ -719,6 +718,7 @@ iss::status riscv_hart_msu_vp::write(const address_type type, const access this->reg.trap_state = (1 << 31); // issue trap 0 return iss::Err; } + phys_addr_t paddr = BASE::v2p(iss::addr_t{access, type, space, addr}); try { if (unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK))) { // we may cross a page boundary vm_info vm = hart_state_type::decode_vm_info(this->reg.PRIV, state.satp); @@ -731,9 +731,7 @@ iss::status riscv_hart_msu_vp::write(const address_type type, const access return res; } } - auto res = type==iss::address_type::PHYSICAL? - write_mem(phys_addr_t{access, space, addr}, length, data): - write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data); + auto res = write_mem(paddr, length, data); if (unlikely(res != iss::Ok)) { this->reg.trap_state = (1UL << 31) | (7UL << 16); // issue trap 7 (Store/AMO access fault) fault_data=addr; @@ -745,7 +743,6 @@ iss::status riscv_hart_msu_vp::write(const address_type type, const access return iss::Err; } - phys_addr_t paddr = BASE::v2p(iss::addr_t{access, type, space, addr}); if ((paddr.val + length) > mem.size()) return iss::Err; switch (paddr.val) { case 0x10013000: // UART0 base, TXFIFO reg diff --git a/src/iss/arch/riscv_hart_mu_p.h b/src/iss/arch/riscv_hart_mu_p.h index 6ac7d9b..da30b21 100644 --- a/src/iss/arch/riscv_hart_mu_p.h +++ b/src/iss/arch/riscv_hart_mu_p.h @@ -834,7 +834,7 @@ iss::status riscv_hart_mu_p::read(const address_type type, const acc fault_data=addr; return iss::Err; } - auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr}); + phys_addr_t phys_addr{access, space, addr}; auto res = iss::Err; if(!is_fetch(access) && memfn_range.size()){ auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple const& a){ @@ -935,7 +935,7 @@ iss::status riscv_hart_mu_p::write(const address_type type, const ac fault_data=addr; return iss::Err; } - auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr}); + phys_addr_t phys_addr{access, space, addr}; auto res = iss::Err; if(!is_fetch(access) && memfn_range.size()){ auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple const& a){ @@ -960,30 +960,29 @@ iss::status riscv_hart_mu_p::write(const address_type type, const ac return iss::Err; } - phys_addr_t paddr = BASE::v2p(iss::addr_t{access, type, space, addr}); - if ((paddr.val + length) > mem.size()) return iss::Err; - switch (paddr.val) { + if ((addr + length) > mem.size()) return iss::Err; + switch (addr) { case 0x10013000: // UART0 base, TXFIFO reg case 0x10023000: // UART1 base, TXFIFO reg uart_buf << (char)data[0]; if (((char)data[0]) == '\n' || data[0] == 0) { - // LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send + // LOG(INFO)<<"UART"<<((addr>>16)&0x3)<<" send // '"<(®); } -tgc_c::phys_addr_t tgc_c::virt2phys(const iss::addr_t &pc) { - return phys_addr_t(pc); // change logical address to physical address +tgc_c::phys_addr_t tgc_c::virt2phys(const iss::addr_t &addr) { + return phys_addr_t(addr.access, addr.space, addr.val&traits::addr_mask); } diff --git a/src/iss/arch/tgc_c.h b/src/iss/arch/tgc_c.h index 2f33ca5..af3b3ba 100644 --- a/src/iss/arch/tgc_c.h +++ b/src/iss/arch/tgc_c.h @@ -195,14 +195,6 @@ struct tgc_c: public arch_if { inline uint64_t stop_code() { return interrupt_sim; } - inline phys_addr_t v2p(const iss::addr_t& addr){ - if (addr.space != traits::MEM || addr.type == iss::address_type::PHYSICAL || - addr_mode[static_cast(addr.access)&0x3]==address_type::PHYSICAL) { - return phys_addr_t(addr.access, addr.space, addr.val&traits::addr_mask); - } else - return virt2phys(addr); - } - virtual phys_addr_t virt2phys(const iss::addr_t& addr); virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } @@ -262,7 +254,6 @@ struct tgc_c: public arch_if { uint32_t get_fcsr(){return 0;} void set_fcsr(uint32_t val){} - }; } diff --git a/src/vm/interp/vm_tgc_c.cpp b/src/vm/interp/vm_tgc_c.cpp index e070215..8ad108e 100644 --- a/src/vm/interp/vm_tgc_c.cpp +++ b/src/vm/interp/vm_tgc_c.cpp @@ -259,15 +259,22 @@ private: }}; iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ - auto phys_pc = this->core.v2p(pc); - //TODO: re-add page handling - //if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary - // if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err; - // if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction - // if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) return iss::Err; - //} else { - if (this->core.read(phys_pc, 4, data) != iss::Ok) return iss::Err; - //} + if(this->core.has_mmu()) { + auto phys_pc = this->core.virt2phys(pc); +// if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary +// if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err; +// if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction +// if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) +// return iss::Err; +// } else { + if (this->core.read(phys_pc, 4, data) != iss::Ok) + return iss::Err; +// } + } else { + if (this->core.read(phys_addr_t(pc.access, pc.space, pc.val), 4, data) != iss::Ok) + return iss::Err; + + } return iss::Ok; } void populate_decoding_tree(decoding_tree_node* root){ diff --git a/src/vm/llvm/vm_tgc_c.cpp b/src/vm/llvm/vm_tgc_c.cpp index f289f0c..d256089 100644 --- a/src/vm/llvm/vm_tgc_c.cpp +++ b/src/vm/llvm/vm_tgc_c.cpp @@ -4085,7 +4085,8 @@ vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, // const typename traits::addr_t upper_bits = ~traits::PGMASK; phys_addr_t paddr(pc); auto *const data = (uint8_t *)&insn; - paddr = this->core.v2p(pc); + if(this->core.has_mmu()) + paddr = this->core.virt2phys(pc); //TODO: re-add page handling // if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary // auto res = this->core.read(paddr, 2, data); diff --git a/src/vm/tcc/vm_tgc_c.cpp b/src/vm/tcc/vm_tgc_c.cpp index eeca8ec..1be78b8 100644 --- a/src/vm/tcc/vm_tgc_c.cpp +++ b/src/vm/tcc/vm_tgc_c.cpp @@ -3174,7 +3174,8 @@ vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, enum {TRAP_ID=1<<16}; code_word_t instr = 0; phys_addr_t paddr(pc); - paddr = this->core.v2p(pc); + if(this->core.has_mmu()) + paddr = this->core.virt2phys(pc); //TODO: re-add page handling // if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary // auto res = this->core.read(paddr, 2, data); From 18e08cfc50c91ac68bd9cfb3aa5cfe92b1f0777c Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Tue, 8 Aug 2023 06:23:38 +0200 Subject: [PATCH 14/14] fixes missing template updates --- gen_input/templates/interp/CORENAME.cpp.gtl | 23 +++++++++++++++++---- gen_input/templates/tcc/CORENAME.cpp.gtl | 20 +++++++++++++----- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/gen_input/templates/interp/CORENAME.cpp.gtl b/gen_input/templates/interp/CORENAME.cpp.gtl index 333a9eb..7645bdc 100644 --- a/gen_input/templates/interp/CORENAME.cpp.gtl +++ b/gen_input/templates/interp/CORENAME.cpp.gtl @@ -179,10 +179,25 @@ private: }}; iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ - auto phys_pc = this->core.v2p(pc); - if (this->core.read(phys_pc, 4, data) != iss::Ok) return iss::Err; + if(this->core.has_mmu()) { + auto phys_pc = this->core.virt2phys(pc); +// if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary +// if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err; +// if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction +// if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) +// return iss::Err; +// } else { + if (this->core.read(phys_pc, 4, data) != iss::Ok) + return iss::Err; +// } + } else { + if (this->core.read(phys_addr_t(pc.access, pc.space, pc.val), 4, data) != iss::Ok) + return iss::Err; + + } return iss::Ok; } + void populate_decoding_tree(decoding_tree_node* root){ //create submask for(auto instr: root->instrs){ @@ -359,13 +374,13 @@ std::unique_ptr create(arch::${coreD namespace iss { namespace { volatile std::array dummy = { - core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned port, void*) -> std::tuple{ + core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned port, void*) -> std::tuple{ auto* cpu = new iss::arch::riscv_hart_m_p(); auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl(*cpu, false); if (port != 0) debugger::server::run_server(vm, port); return {cpu_ptr{cpu}, vm_ptr{vm}}; }), - core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned port, void*) -> std::tuple{ + core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned port, void*) -> std::tuple{ auto* cpu = new iss::arch::riscv_hart_mu_p(); auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl(*cpu, false); if (port != 0) debugger::server::run_server(vm, port); diff --git a/gen_input/templates/tcc/CORENAME.cpp.gtl b/gen_input/templates/tcc/CORENAME.cpp.gtl index 832422a..fb912cd 100644 --- a/gen_input/templates/tcc/CORENAME.cpp.gtl +++ b/gen_input/templates/tcc/CORENAME.cpp.gtl @@ -265,9 +265,19 @@ vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, enum {TRAP_ID=1<<16}; code_word_t instr = 0; phys_addr_t paddr(pc); - paddr = this->core.v2p(pc); - auto res = this->core.read(paddr, 4, reinterpret_cast(&instr)); - if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); + if(this->core.has_mmu()) + paddr = this->core.virt2phys(pc); + //TODO: re-add page handling +// if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary +// auto res = this->core.read(paddr, 2, data); +// if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); +// if ((insn & 0x3) == 0x3) { // this is a 32bit instruction +// res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); +// } +// } else { + auto res = this->core.read(paddr, 4, reinterpret_cast(&instr)); + if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); +// } if (instr == 0x0000006f || (instr&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' // curr pc on stack ++inst_cnt; @@ -316,13 +326,13 @@ std::unique_ptr create(arch::${coreD namespace iss { namespace { volatile std::array dummy = { - core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned port, void*) -> std::tuple{ + core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned port, void*) -> std::tuple{ auto* cpu = new iss::arch::riscv_hart_m_p(); auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl(*cpu, false); if (port != 0) debugger::server::run_server(vm, port); return {cpu_ptr{cpu}, vm_ptr{vm}}; }), - core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned port, void*) -> std::tuple{ + core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned port, void*) -> std::tuple{ auto* cpu = new iss::arch::riscv_hart_mu_p(); auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl(*cpu, false); if (port != 0) debugger::server::run_server(vm, port);