From 0a42c9d2ea543dce6d51d2af1f52a18079de65d6 Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Wed, 4 Oct 2017 23:15:04 +0200 Subject: [PATCH] Added plic functionality --- CMakeLists.txt | 4 +- riscv.sc/incl/sysc/SiFive/platform.h | 2 + riscv.sc/incl/sysc/SiFive/plic.h | 18 ++++- riscv.sc/src/sysc/platform.cpp | 6 +- riscv.sc/src/sysc/plic.cpp | 117 ++++++++++++++++++++++++++- 5 files changed, 138 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3331712..71d4723 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ set(GIT_SUBMODULE_BRANCH_sc-components ${GIT_BRANCH}) set(GIT_SUBMODULE_BRANCH_dbt-core ${GIT_BRANCH}) include(GNUInstallDirs) -include(cmake/Submodules.cmake) +include(Submodules) #enable_testing() @@ -33,7 +33,7 @@ find_package(Threads) find_package(Tcmalloc) set(PROJECT_3PARTY_DIRS external sr_report sr_signal) -include(sc-components/cmake/clang-format.cmake) +include(clang-format) add_subdirectory(external) add_subdirectory(dbt-core) diff --git a/riscv.sc/incl/sysc/SiFive/platform.h b/riscv.sc/incl/sysc/SiFive/platform.h index e74f018..0a75e15 100644 --- a/riscv.sc/incl/sysc/SiFive/platform.h +++ b/riscv.sc/incl/sysc/SiFive/platform.h @@ -59,6 +59,8 @@ public: scc::memory<128_kB, 32> i_mem_ram; sc_core::sc_signal s_clk; sc_core::sc_signal s_rst, s_mtime_int, s_msie_int; + sc_core::sc_vector> s_global_int; + sc_core::sc_signal s_core_int; platform(sc_core::sc_module_name nm); diff --git a/riscv.sc/incl/sysc/SiFive/plic.h b/riscv.sc/incl/sysc/SiFive/plic.h index 0c50814..93d3b87 100644 --- a/riscv.sc/incl/sysc/SiFive/plic.h +++ b/riscv.sc/incl/sysc/SiFive/plic.h @@ -17,7 +17,8 @@ #ifndef _PLIC_H_ #define _PLIC_H_ -#include "scc/tlm_target.h" +#include +#include namespace sysc { @@ -28,14 +29,27 @@ public: SC_HAS_PROCESS(plic); sc_core::sc_in clk_i; sc_core::sc_in rst_i; + sc_core::sc_vector> global_interrupts_i; + sc_core::sc_out core_interrupt_o; + sc_core::sc_event raise_int_ev; + sc_core::sc_event clear_int_ev; plic(sc_core::sc_module_name nm); - virtual ~plic() override; + ~plic() override; protected: void clock_cb(); void reset_cb(); + void init_callbacks(); + + void global_int_port_cb(); + void handle_pending_int(); + void reset_pending_int(uint32_t irq); + + void raise_core_interrupt(); + void clear_core_interrupt(); sc_core::sc_time clk; std::unique_ptr regs; + std::function, uint32_t)> m_claim_complete_write_cb; }; } /* namespace sysc */ diff --git a/riscv.sc/src/sysc/platform.cpp b/riscv.sc/src/sysc/platform.cpp index 5471f63..c971570 100644 --- a/riscv.sc/src/sysc/platform.cpp +++ b/riscv.sc/src/sysc/platform.cpp @@ -39,7 +39,9 @@ platform::platform(sc_core::sc_module_name nm) , NAMED(i_mem_qspi) , NAMED(i_mem_ram) , NAMED(s_clk) -, NAMED(s_rst) { +, NAMED(s_rst) +, NAMED(s_global_int, 256) +, NAMED(s_core_int) { i_core_complex.initiator(i_router.target[0]); size_t i = 0; for (const auto &e : e300_plat_map) { @@ -75,6 +77,8 @@ platform::platform(sc_core::sc_module_name nm) i_clint.mtime_int_o(s_mtime_int); i_clint.msip_int_o(s_msie_int); + i_plic.global_interrupts_i(s_global_int); + i_plic.core_interrupt_o(s_core_int); SC_THREAD(gen_reset); } diff --git a/riscv.sc/src/sysc/plic.cpp b/riscv.sc/src/sysc/plic.cpp index dfe4c06..91373f3 100644 --- a/riscv.sc/src/sysc/plic.cpp +++ b/riscv.sc/src/sysc/plic.cpp @@ -14,10 +14,11 @@ // the License. //////////////////////////////////////////////////////////////////////////////// -#include "sysc/SiFive/plic.h" +#include -#include "scc/utilities.h" -#include "sysc/SiFive/gen/plic_regs.h" +#include +#include +#include namespace sysc { @@ -26,8 +27,24 @@ plic::plic(sc_core::sc_module_name nm) , tlm_target<>(clk) , NAMED(clk_i) , NAMED(rst_i) -, NAMEDD(plic_regs, regs) { +, NAMED(global_interrupts_i, 256) +, NAMED(core_interrupt_o) +, NAMEDD(plic_regs, regs) + +{ regs->registerResources(*this); + // register callbacks + init_callbacks(); + regs->claim_complete.set_write_cb(m_claim_complete_write_cb); + + // port callbacks + SC_METHOD(global_int_port_cb); + for (uint8_t i = 0; i < 255; i++) { + sensitive << global_interrupts_i[i].pos(); + } + dont_initialize(); + + // register event callbacks SC_METHOD(clock_cb); sensitive << clk_i; SC_METHOD(reset_cb); @@ -37,6 +54,16 @@ plic::plic(sc_core::sc_module_name nm) plic::~plic() {} +void plic::init_callbacks() { + m_claim_complete_write_cb = [=](scc::sc_register reg, uint32_t v) -> bool { + reg.put(v); + reset_pending_int(v); + // std::cout << "Value of register: 0x" << std::hex << reg << std::endl; + // todo: reset related interrupt and find next high-prio interrupt + return true; + }; +} + void plic::clock_cb() { this->clk = clk_i.read(); } void plic::reset_cb() { @@ -46,4 +73,86 @@ void plic::reset_cb() { regs->reset_stop(); } +// Functional handling of interrupts: +// - global_int_port_cb() +// - set pending register bits +// - called by: incoming global_int +// - handle_pending_int() +// - update claim register content +// - generate core-interrupt pulse +// - called by: +// - incoming global_int +// - complete-register write access +// - reset_pending_int(int-id) +// - reset pending bit +// - call next handle_pending_int() +// - called by: +// - complete-reg write register content + +void plic::global_int_port_cb() { + + // set related pending bit if enable is set for incoming global_interrupt + + // todo: extend up to 255 bits (limited to 32 right now) + for (uint32_t i = 1; i < 32; i++) { + uint32_t enable_bits = regs->r_enabled; + bool enable = enable_bits & (0x1 << i); // read enable bit + + if (enable && global_interrupts_i[i].read() == 1) { + regs->r_pending = regs->r_pending | (0x1 << i); + LOG(DEBUG) << "pending interrupt identified: " << i; + } + } + + handle_pending_int(); +} + +void plic::handle_pending_int() { + // identify high-prio pending interrupt and raise a core-interrupt + uint32_t claim_int = 0; // claim interrupt + uint32_t claim_prio = 0; // related priority (highest prio interrupt wins the race) + bool raise_int = 0; + uint32_t thold = regs->r_threshold.threshold; // threshold value + + // todo: extend up to 255 bits (limited to 32 right now) + for (uint32_t i = 1; i < 32; i++) { + uint32_t pending_bits = regs->r_pending; + bool pending = (pending_bits & (0x1 << i)) ? true : false; + uint32_t prio = regs->r_priority[i - 1].priority; // read priority value + + if (pending && thold < prio) { + regs->r_pending = regs->r_pending | (0x1 << i); + // below condition ensures implicitly that lowest id is selected in case of multiple identical + // priority-interrupts + if (prio > claim_prio) { + claim_prio = prio; + claim_int = i; + raise_int = 1; + LOG(DEBUG) << "pending interrupt activated: " << i; + } + } + } + + if (raise_int) { + regs->r_claim_complete = claim_int; + core_interrupt_o.write(1); + // todo: evluate clock period + } else { + regs->r_claim_complete = 0; + LOG(DEBUG) << "no further pending interrupt."; + } +} + +void plic::reset_pending_int(uint32_t irq) { + // todo: evaluate enable register (see spec) + // todo: make sure that pending is set, otherwise don't reset irq ... read spec. + LOG(INFO) << "reset pending interrupt: " << irq; + // reset related pending bit + regs->r_pending &= ~(0x1 << irq); + core_interrupt_o.write(0); + + // evaluate next pending interrupt + handle_pending_int(); +} + } /* namespace sysc */