aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Waterman <andrew@sifive.com>2023-02-04 19:40:02 -0800
committerAndrew Waterman <andrew@sifive.com>2023-02-05 15:52:14 -0800
commite85f86695092f1377a515c94de5c706bcff1f2bd (patch)
tree92a5bdf324fa79a01b2688b409a612585346ff7e
parentddabbe516e2f82ac1d94ce5351402b73fbf55850 (diff)
downloadspike-e85f86695092f1377a515c94de5c706bcff1f2bd.zip
spike-e85f86695092f1377a515c94de5c706bcff1f2bd.tar.gz
spike-e85f86695092f1377a515c94de5c706bcff1f2bd.tar.bz2
Fix CLINT on big-endian machines
This will also make it easier to support discontiguous hart IDs.
-rw-r--r--riscv/clint.cc78
1 files changed, 55 insertions, 23 deletions
diff --git a/riscv/clint.cc b/riscv/clint.cc
index 3d41668..056aa00 100644
--- a/riscv/clint.cc
+++ b/riscv/clint.cc
@@ -27,18 +27,47 @@ clint_t::clint_t(std::vector<processor_t*>& procs, uint64_t freq_hz, bool real_t
#define MTIMECMP_BASE 0x4000
#define MTIME_BASE 0xbff8
+template<typename T>
+void partial_write(T* word, reg_t addr, size_t len, const uint8_t* bytes)
+{
+ 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 partial_read(T word, reg_t addr, size_t len, uint8_t* bytes)
+{
+ for (size_t i = 0; i < len; i++) {
+ const int shift = 8 * ((addr + i) % sizeof(T));
+ bytes[i] = word >> shift;
+ }
+}
+
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);
+
+ const auto msip_hart_id = (addr - MSIP_BASE) / sizeof(msip_t);
+ const auto mtimecmp_hart_id = (addr - MTIMECMP_BASE) / sizeof(mtimecmp_t);
+
+ if (addr >= MSIP_BASE && msip_hart_id < procs.size()) {
+ if (len == 8) {
+ // Implement double-word loads as a pair of word loads
+ return load(addr, 4, bytes) && load(addr + 4, 4, bytes + 4);
+ }
+
+ msip_t res = !!(procs[msip_hart_id]->state.mip->read() & MIP_MSIP);
+ partial_read(res, addr, len, bytes);
+ return true;
+ } else if (addr >= MTIMECMP_BASE && mtimecmp_hart_id < procs.size()) {
+ partial_read(mtimecmp[mtimecmp_hart_id], addr, len, bytes);
+ } else if (addr >= MTIME_BASE && addr < MTIME_BASE + sizeof(mtime_t)) {
+ partial_read(mtime, addr, len, bytes);
} else if (addr + len <= CLINT_SIZE) {
memset(bytes, 0, len);
} else {
@@ -49,21 +78,24 @@ 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;
+
+ const auto msip_hart_id = (addr - MSIP_BASE) / sizeof(msip_t);
+ const auto mtimecmp_hart_id = (addr - MTIMECMP_BASE) / sizeof(mtimecmp_t);
+
+ if (addr >= MSIP_BASE && msip_hart_id < procs.size()) {
+ 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);
+
+ if (addr % sizeof(msip_t) == 0)
+ procs[msip_hart_id]->state.mip->backdoor_write_with_mask(MIP_MSIP, bytes[0] & 1 ? MIP_MSIP : 0);
+ } else if (addr >= MTIMECMP_BASE && mtimecmp_hart_id < procs.size()) {
+ partial_write(&mtimecmp[mtimecmp_hart_id], addr, len, bytes);
+ } else if (addr >= MTIME_BASE && addr < MTIME_BASE + sizeof(mtime_t)) {
+ partial_write(&mtime, addr, len, bytes);
} else if (addr + len <= CLINT_SIZE) {
// Do nothing
} else {