aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Waterman <andrew@sifive.com>2023-03-02 06:03:10 -0800
committerGitHub <noreply@github.com>2023-03-02 06:03:10 -0800
commit1742648305d50c193c53f3356732261e9b83af20 (patch)
tree440124e6d35607886225fa5371513fb78787ff37
parentd1ae27b7f843b35bd32778c54b4973d7aeffad52 (diff)
parent74064f806737925c2efeb9e617c1d9c57d26172e (diff)
downloadriscv-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.cc77
-rw-r--r--riscv/devices.h39
-rw-r--r--riscv/plic.cc37
-rw-r--r--riscv/sim.cc4
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();
}