diff options
author | Andrew Waterman <andrew@sifive.com> | 2023-03-02 06:03:10 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-02 06:03:10 -0800 |
commit | 1742648305d50c193c53f3356732261e9b83af20 (patch) | |
tree | 440124e6d35607886225fa5371513fb78787ff37 | |
parent | d1ae27b7f843b35bd32778c54b4973d7aeffad52 (diff) | |
parent | 74064f806737925c2efeb9e617c1d9c57d26172e (diff) | |
download | riscv-isa-sim-1742648305d50c193c53f3356732261e9b83af20.zip riscv-isa-sim-1742648305d50c193c53f3356732261e9b83af20.tar.gz riscv-isa-sim-1742648305d50c193c53f3356732261e9b83af20.tar.bz2 |
Merge pull request #1265 from riscv-software-src/plic-fixes
PLIC and CLINT fixes for heterogeneous harts/discontiguous hart IDs
-rw-r--r-- | riscv/clint.cc | 77 | ||||
-rw-r--r-- | riscv/devices.h | 39 | ||||
-rw-r--r-- | riscv/plic.cc | 37 | ||||
-rw-r--r-- | riscv/sim.cc | 4 |
4 files changed, 94 insertions, 63 deletions
diff --git a/riscv/clint.cc b/riscv/clint.cc index 3d41668..778c085 100644 --- a/riscv/clint.cc +++ b/riscv/clint.cc @@ -1,9 +1,10 @@ #include <sys/time.h> #include "devices.h" #include "processor.h" +#include "sim.h" -clint_t::clint_t(std::vector<processor_t*>& procs, uint64_t freq_hz, bool real_time) - : procs(procs), freq_hz(freq_hz), real_time(real_time), mtime(0), mtimecmp(procs.size()) +clint_t::clint_t(sim_t* sim, uint64_t freq_hz, bool real_time) + : sim(sim), freq_hz(freq_hz), real_time(real_time), mtime(0) { struct timeval base; @@ -29,16 +30,27 @@ clint_t::clint_t(std::vector<processor_t*>& procs, uint64_t freq_hz, bool real_t bool clint_t::load(reg_t addr, size_t len, uint8_t* bytes) { + if (len > 8) + return false; + increment(0); - if (addr >= MSIP_BASE && addr + len <= MSIP_BASE + procs.size()*sizeof(msip_t)) { - std::vector<msip_t> msip(procs.size()); - for (size_t i = 0; i < procs.size(); ++i) - msip[i] = !!(procs[i]->state.mip->read() & MIP_MSIP); - memcpy(bytes, (uint8_t*)&msip[0] + addr - MSIP_BASE, len); - } else if (addr >= MTIMECMP_BASE && addr + len <= MTIMECMP_BASE + procs.size()*sizeof(mtimecmp_t)) { - memcpy(bytes, (uint8_t*)&mtimecmp[0] + addr - MTIMECMP_BASE, len); - } else if (addr >= MTIME_BASE && addr + len <= MTIME_BASE + sizeof(mtime_t)) { - memcpy(bytes, (uint8_t*)&mtime + addr - MTIME_BASE, len); + + if (addr >= MSIP_BASE && addr < MTIMECMP_BASE) { + if (len == 8) { + // Implement double-word loads as a pair of word loads + return load(addr, 4, bytes) && load(addr + 4, 4, bytes + 4); + } + + const auto hart_id = (addr - MSIP_BASE) / sizeof(msip_t); + const msip_t res = sim->get_harts().count(hart_id) && (sim->get_harts().at(hart_id)->state.mip->read() & MIP_MSIP); + read_little_endian_reg(res, addr, len, bytes); + return true; + } else if (addr >= MTIMECMP_BASE && addr < MTIME_BASE) { + const auto hart_id = (addr - MTIMECMP_BASE) / sizeof(mtimecmp_t); + const mtime_t res = sim->get_harts().count(hart_id) ? mtimecmp[hart_id] : 0; + read_little_endian_reg(res, addr, len, bytes); + } else if (addr >= MTIME_BASE && addr < MTIME_BASE + sizeof(mtime_t)) { + read_little_endian_reg(mtime, addr, len, bytes); } else if (addr + len <= CLINT_SIZE) { memset(bytes, 0, len); } else { @@ -49,21 +61,27 @@ bool clint_t::load(reg_t addr, size_t len, uint8_t* bytes) bool clint_t::store(reg_t addr, size_t len, const uint8_t* bytes) { - if (addr >= MSIP_BASE && addr + len <= MSIP_BASE + procs.size()*sizeof(msip_t)) { - std::vector<msip_t> msip(procs.size()); - std::vector<msip_t> mask(procs.size(), 0); - memcpy((uint8_t*)&msip[0] + addr - MSIP_BASE, bytes, len); - memset((uint8_t*)&mask[0] + addr - MSIP_BASE, 0xff, len); - for (size_t i = 0; i < procs.size(); ++i) { - if (!(mask[i] & 0xFF)) continue; - procs[i]->state.mip->backdoor_write_with_mask(MIP_MSIP, 0); - if (!!(msip[i] & 1)) - procs[i]->state.mip->backdoor_write_with_mask(MIP_MSIP, MIP_MSIP); + if (len > 8) + return false; + + if (addr >= MSIP_BASE && addr < MTIMECMP_BASE) { + if (len == 8) { + // Implement double-word stores as a pair of word stores + return store(addr, 4, bytes) && store(addr + 4, 4, bytes + 4); } - } else if (addr >= MTIMECMP_BASE && addr + len <= MTIMECMP_BASE + procs.size()*sizeof(mtimecmp_t)) { - memcpy((uint8_t*)&mtimecmp[0] + addr - MTIMECMP_BASE, bytes, len); - } else if (addr >= MTIME_BASE && addr + len <= MTIME_BASE + sizeof(mtime_t)) { - memcpy((uint8_t*)&mtime + addr - MTIME_BASE, bytes, len); + + msip_t msip = 0; + write_little_endian_reg(&msip, addr, len, bytes); + + const auto hart_id = (addr - MSIP_BASE) / sizeof(msip_t); + if (sim->get_harts().count(hart_id)) + sim->get_harts().at(hart_id)->state.mip->backdoor_write_with_mask(MIP_MSIP, msip & 1 ? MIP_MSIP : 0); + } else if (addr >= MTIMECMP_BASE && addr < MTIME_BASE) { + const auto hart_id = (addr - MTIMECMP_BASE) / sizeof(mtimecmp_t); + if (sim->get_harts().count(hart_id)) + write_little_endian_reg(&mtimecmp[hart_id], addr, len, bytes); + } else if (addr >= MTIME_BASE && addr < MTIME_BASE + sizeof(mtime_t)) { + write_little_endian_reg(&mtime, addr, len, bytes); } else if (addr + len <= CLINT_SIZE) { // Do nothing } else { @@ -85,10 +103,9 @@ void clint_t::increment(reg_t inc) } else { mtime += inc; } - for (size_t i = 0; i < procs.size(); i++) { - procs[i]->state.time->sync(mtime); - procs[i]->state.mip->backdoor_write_with_mask(MIP_MTIP, 0); - if (mtime >= mtimecmp[i]) - procs[i]->state.mip->backdoor_write_with_mask(MIP_MTIP, MIP_MTIP); + + for (const auto& [hart_id, hart] : sim->get_harts()) { + hart->state.time->sync(mtime); + hart->state.mip->backdoor_write_with_mask(MIP_MTIP, mtime >= mtimecmp[hart_id] ? MIP_MTIP : 0); } } diff --git a/riscv/devices.h b/riscv/devices.h index 040fe3e..2a9c005 100644 --- a/riscv/devices.h +++ b/riscv/devices.h @@ -10,8 +10,10 @@ #include <queue> #include <vector> #include <utility> +#include <cassert> class processor_t; +class sim_t; class bus_t : public abstract_device_t { public: @@ -56,7 +58,7 @@ class mem_t : public abstract_device_t { class clint_t : public abstract_device_t { public: - clint_t(std::vector<processor_t*>&, uint64_t freq_hz, bool real_time); + clint_t(sim_t*, uint64_t freq_hz, bool real_time); bool load(reg_t addr, size_t len, uint8_t* bytes); bool store(reg_t addr, size_t len, const uint8_t* bytes); size_t size() { return CLINT_SIZE; } @@ -67,19 +69,23 @@ class clint_t : public abstract_device_t { typedef uint64_t mtime_t; typedef uint64_t mtimecmp_t; typedef uint32_t msip_t; - std::vector<processor_t*>& procs; + sim_t* sim; uint64_t freq_hz; bool real_time; uint64_t real_time_ref_secs; uint64_t real_time_ref_usecs; mtime_t mtime; - std::vector<mtimecmp_t> mtimecmp; + std::map<size_t, mtimecmp_t> mtimecmp; }; #define PLIC_MAX_DEVICES 1024 struct plic_context_t { - uint32_t num; + plic_context_t(processor_t* proc, bool mmode) + : proc(proc), mmode(mmode), priority_threshold(0), enable{}, pending{}, + pending_priority{}, claimed{} + {} + processor_t *proc; bool mmode; @@ -92,13 +98,12 @@ struct plic_context_t { class plic_t : public abstract_device_t, public abstract_interrupt_controller_t { public: - plic_t(std::vector<processor_t*>&, bool smode, uint32_t ndev); + plic_t(sim_t*, uint32_t ndev); bool load(reg_t addr, size_t len, uint8_t* bytes); bool store(reg_t addr, size_t len, const uint8_t* bytes); void set_interrupt_level(uint32_t id, int lvl); size_t size() { return PLIC_SIZE; } private: - std::vector<processor_t*>& procs; std::vector<plic_context_t> contexts; uint32_t num_ids; uint32_t num_ids_word; @@ -166,4 +171,26 @@ class mmio_plugin_device_t : public abstract_device_t { void* user_data; }; +template<typename T> +void write_little_endian_reg(T* word, reg_t addr, size_t len, const uint8_t* bytes) +{ + assert(len <= sizeof(T)); + + for (size_t i = 0; i < len; i++) { + const int shift = 8 * ((addr + i) % sizeof(T)); + *word = (*word & ~(T(0xFF) << shift)) | (T(bytes[i]) << shift); + } +} + +template<typename T> +void read_little_endian_reg(T word, reg_t addr, size_t len, uint8_t* bytes) +{ + assert(len <= sizeof(T)); + + for (size_t i = 0; i < len; i++) { + const int shift = 8 * ((addr + i) % sizeof(T)); + bytes[i] = word >> shift; + } +} + #endif diff --git a/riscv/plic.cc b/riscv/plic.cc index d0f1268..515451a 100644 --- a/riscv/plic.cc +++ b/riscv/plic.cc @@ -1,6 +1,7 @@ #include <sys/time.h> #include "devices.h" #include "processor.h" +#include "sim.h" #define PLIC_MAX_CONTEXTS 15872 @@ -66,29 +67,17 @@ #define REG_SIZE 0x1000000 -plic_t::plic_t(std::vector<processor_t*>& procs, bool smode, uint32_t ndev) - : procs(procs), contexts(procs.size() * (smode ? 2 : 1)), - num_ids(ndev + 1), num_ids_word(((ndev + 1) + (32 - 1)) / 32), - max_prio((1UL << PLIC_PRIO_BITS) - 1) +plic_t::plic_t(sim_t* sim, uint32_t ndev) + : num_ids(ndev + 1), num_ids_word(((ndev + 1) + (32 - 1)) / 32), + max_prio((1UL << PLIC_PRIO_BITS) - 1), priority{}, level{} { - size_t contexts_per_hart = smode ? 2 : 1; + // PLIC contexts are contiguous in memory even if harts are discontiguous. + for (const auto& [hart_id, hart] : sim->get_harts()) { + contexts.push_back(plic_context_t(hart, true)); - memset(priority, 0, sizeof(priority)); - memset(level, 0, sizeof(level)); - - for (size_t i = 0; i < contexts.size(); i++) { - plic_context_t* c = &contexts[i]; - c->num = i; - c->proc = procs[i / contexts_per_hart]; - if (smode) { - c->mmode = (i % contexts_per_hart == 0); - } else { - c->mmode = true; + if (hart->extension_enabled_const('S')) { + contexts.push_back(plic_context_t(hart, false)); } - memset(&c->enable, 0, sizeof(c->enable)); - memset(&c->pending, 0, sizeof(c->pending)); - memset(&c->pending_priority, 0, sizeof(c->pending_priority)); - memset(&c->claimed, 0, sizeof(c->claimed)); } } @@ -340,9 +329,7 @@ bool plic_t::load(reg_t addr, size_t len, uint8_t* bytes) } } - if (ret) { - memcpy(bytes, (uint8_t *)&val, len); - } + read_little_endian_reg(val, addr, len, bytes); return ret; } @@ -350,7 +337,7 @@ bool plic_t::load(reg_t addr, size_t len, uint8_t* bytes) bool plic_t::store(reg_t addr, size_t len, const uint8_t* bytes) { bool ret = false; - uint32_t val; + uint32_t val = 0; switch (len) { case 4: @@ -363,7 +350,7 @@ bool plic_t::store(reg_t addr, size_t len, const uint8_t* bytes) return false; } - memcpy((uint8_t *)&val, bytes, len); + write_little_endian_reg(&val, addr, len, bytes); if (PRIORITY_BASE <= addr && addr < ENABLE_BASE) { ret = priority_write(addr, val); diff --git a/riscv/sim.cc b/riscv/sim.cc index c623de1..a31e057 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -119,7 +119,7 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, // setting the dtb_file argument has one. reg_t clint_base; if (fdt_parse_clint(fdt, &clint_base, "riscv,clint0") == 0) { - clint.reset(new clint_t(procs, CPU_HZ / INSNS_PER_RTC_TICK, cfg->real_time_clint())); + clint.reset(new clint_t(this, CPU_HZ / INSNS_PER_RTC_TICK, cfg->real_time_clint())); bus.add_device(clint_base, clint.get()); } @@ -130,7 +130,7 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, reg_t plic_base; uint32_t plic_ndev; if (fdt_parse_plic(fdt, &plic_base, &plic_ndev, "riscv,plic0") == 0) { - plic.reset(new plic_t(procs, true, plic_ndev)); + plic.reset(new plic_t(this, plic_ndev)); bus.add_device(plic_base, plic.get()); intctrl = plic.get(); } |