Added plic functionality
This commit is contained in:
parent
768df67646
commit
0a42c9d2ea
|
@ -15,7 +15,7 @@ set(GIT_SUBMODULE_BRANCH_sc-components ${GIT_BRANCH})
|
||||||
set(GIT_SUBMODULE_BRANCH_dbt-core ${GIT_BRANCH})
|
set(GIT_SUBMODULE_BRANCH_dbt-core ${GIT_BRANCH})
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
include(cmake/Submodules.cmake)
|
include(Submodules)
|
||||||
|
|
||||||
#enable_testing()
|
#enable_testing()
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ find_package(Threads)
|
||||||
find_package(Tcmalloc)
|
find_package(Tcmalloc)
|
||||||
|
|
||||||
set(PROJECT_3PARTY_DIRS external sr_report sr_signal)
|
set(PROJECT_3PARTY_DIRS external sr_report sr_signal)
|
||||||
include(sc-components/cmake/clang-format.cmake)
|
include(clang-format)
|
||||||
|
|
||||||
add_subdirectory(external)
|
add_subdirectory(external)
|
||||||
add_subdirectory(dbt-core)
|
add_subdirectory(dbt-core)
|
||||||
|
|
|
@ -59,6 +59,8 @@ public:
|
||||||
scc::memory<128_kB, 32> i_mem_ram;
|
scc::memory<128_kB, 32> i_mem_ram;
|
||||||
sc_core::sc_signal<sc_core::sc_time> s_clk;
|
sc_core::sc_signal<sc_core::sc_time> s_clk;
|
||||||
sc_core::sc_signal<bool> s_rst, s_mtime_int, s_msie_int;
|
sc_core::sc_signal<bool> s_rst, s_mtime_int, s_msie_int;
|
||||||
|
sc_core::sc_vector<sc_core::sc_signal<bool>> s_global_int;
|
||||||
|
sc_core::sc_signal<bool> s_core_int;
|
||||||
|
|
||||||
platform(sc_core::sc_module_name nm);
|
platform(sc_core::sc_module_name nm);
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
#ifndef _PLIC_H_
|
#ifndef _PLIC_H_
|
||||||
#define _PLIC_H_
|
#define _PLIC_H_
|
||||||
|
|
||||||
#include "scc/tlm_target.h"
|
#include <scc/register.h>
|
||||||
|
#include <scc/tlm_target.h>
|
||||||
|
|
||||||
namespace sysc {
|
namespace sysc {
|
||||||
|
|
||||||
|
@ -28,14 +29,27 @@ public:
|
||||||
SC_HAS_PROCESS(plic);
|
SC_HAS_PROCESS(plic);
|
||||||
sc_core::sc_in<sc_core::sc_time> clk_i;
|
sc_core::sc_in<sc_core::sc_time> clk_i;
|
||||||
sc_core::sc_in<bool> rst_i;
|
sc_core::sc_in<bool> rst_i;
|
||||||
|
sc_core::sc_vector<sc_core::sc_in<bool>> global_interrupts_i;
|
||||||
|
sc_core::sc_out<bool> core_interrupt_o;
|
||||||
|
sc_core::sc_event raise_int_ev;
|
||||||
|
sc_core::sc_event clear_int_ev;
|
||||||
plic(sc_core::sc_module_name nm);
|
plic(sc_core::sc_module_name nm);
|
||||||
virtual ~plic() override;
|
~plic() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void clock_cb();
|
void clock_cb();
|
||||||
void reset_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;
|
sc_core::sc_time clk;
|
||||||
std::unique_ptr<plic_regs> regs;
|
std::unique_ptr<plic_regs> regs;
|
||||||
|
std::function<bool(scc::sc_register<uint32_t>, uint32_t)> m_claim_complete_write_cb;
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace sysc */
|
} /* namespace sysc */
|
||||||
|
|
|
@ -39,7 +39,9 @@ platform::platform(sc_core::sc_module_name nm)
|
||||||
, NAMED(i_mem_qspi)
|
, NAMED(i_mem_qspi)
|
||||||
, NAMED(i_mem_ram)
|
, NAMED(i_mem_ram)
|
||||||
, NAMED(s_clk)
|
, 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]);
|
i_core_complex.initiator(i_router.target[0]);
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (const auto &e : e300_plat_map) {
|
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.mtime_int_o(s_mtime_int);
|
||||||
i_clint.msip_int_o(s_msie_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);
|
SC_THREAD(gen_reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,11 @@
|
||||||
// the License.
|
// the License.
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "sysc/SiFive/plic.h"
|
#include <sysc/SiFive/plic.h>
|
||||||
|
|
||||||
#include "scc/utilities.h"
|
#include <scc/utilities.h>
|
||||||
#include "sysc/SiFive/gen/plic_regs.h"
|
#include <scc/report.h>
|
||||||
|
#include <sysc/SiFive/gen/plic_regs.h>
|
||||||
|
|
||||||
namespace sysc {
|
namespace sysc {
|
||||||
|
|
||||||
|
@ -26,8 +27,24 @@ plic::plic(sc_core::sc_module_name nm)
|
||||||
, tlm_target<>(clk)
|
, tlm_target<>(clk)
|
||||||
, NAMED(clk_i)
|
, NAMED(clk_i)
|
||||||
, NAMED(rst_i)
|
, NAMED(rst_i)
|
||||||
, NAMEDD(plic_regs, regs) {
|
, NAMED(global_interrupts_i, 256)
|
||||||
|
, NAMED(core_interrupt_o)
|
||||||
|
, NAMEDD(plic_regs, regs)
|
||||||
|
|
||||||
|
{
|
||||||
regs->registerResources(*this);
|
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);
|
SC_METHOD(clock_cb);
|
||||||
sensitive << clk_i;
|
sensitive << clk_i;
|
||||||
SC_METHOD(reset_cb);
|
SC_METHOD(reset_cb);
|
||||||
|
@ -37,6 +54,16 @@ plic::plic(sc_core::sc_module_name nm)
|
||||||
|
|
||||||
plic::~plic() {}
|
plic::~plic() {}
|
||||||
|
|
||||||
|
void plic::init_callbacks() {
|
||||||
|
m_claim_complete_write_cb = [=](scc::sc_register<uint32_t> 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::clock_cb() { this->clk = clk_i.read(); }
|
||||||
|
|
||||||
void plic::reset_cb() {
|
void plic::reset_cb() {
|
||||||
|
@ -46,4 +73,86 @@ void plic::reset_cb() {
|
||||||
regs->reset_stop();
|
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 */
|
} /* namespace sysc */
|
||||||
|
|
Loading…
Reference in New Issue