diff options
author | Andrew Waterman <andrew@sifive.com> | 2022-11-21 15:39:50 -0800 |
---|---|---|
committer | Andrew Waterman <andrew@sifive.com> | 2022-11-23 16:38:55 -0800 |
commit | 86595060b1dfd28384ff8cd21d0023808ba957a4 (patch) | |
tree | afa842d1d9ee7a87b688f432a5f42b721bd94a53 /riscv/plic.cc | |
parent | 0ce940f81b357f8ed5363bc5ac35beb842c9bc30 (diff) | |
download | riscv-isa-sim-86595060b1dfd28384ff8cd21d0023808ba957a4.zip riscv-isa-sim-86595060b1dfd28384ff8cd21d0023808ba957a4.tar.gz riscv-isa-sim-86595060b1dfd28384ff8cd21d0023808ba957a4.tar.bz2 |
Make reserved PLIC behavior more realistic
Most implementations can't raise precise exceptions as a function of
sub-page addressing, so don't attempt to do so here. Also, support
double-word-sized writes. Although PLICs aren't required to support
this behavior, they are allowed to. Some existing implementations
support this behavior, and some existing software relies upon it
(unfortunately).
Diffstat (limited to 'riscv/plic.cc')
-rw-r--r-- | riscv/plic.cc | 54 |
1 files changed, 32 insertions, 22 deletions
diff --git a/riscv/plic.cc b/riscv/plic.cc index 0cdcebb..9f19bef 100644 --- a/riscv/plic.cc +++ b/riscv/plic.cc @@ -150,11 +150,11 @@ bool plic_t::priority_read(reg_t offset, uint32_t *val) { uint32_t id = (offset >> 2); - if (id == 0 || id >= num_ids) { - return false; - } + if (id > 0 && id < num_ids) + *val = priority[id]; + else + *val = 0; - *val = priority[id]; return true; } @@ -162,12 +162,11 @@ bool plic_t::priority_write(reg_t offset, uint32_t val) { uint32_t id = (offset >> 2); - if (id == 0 || id >= num_ids) { - return false; + if (id > 0 && id < num_ids) { + val &= ((1 << PLIC_PRIO_BITS) - 1); + priority[id] = val; } - val &= ((1 << PLIC_PRIO_BITS) - 1); - priority[id] = val; return true; } @@ -176,11 +175,11 @@ bool plic_t::context_enable_read(const plic_context_t *c, { uint32_t id_word = offset >> 2; - if (num_ids_word < id_word) { - return false; - } + if (id_word < num_ids_word) + *val = c->enable[id_word]; + else + *val = 0; - *val = c->enable[id_word]; return true; } @@ -189,9 +188,8 @@ bool plic_t::context_enable_write(plic_context_t *c, { uint32_t id_word = offset >> 2; - if (num_ids_word < id_word) { - return false; - } + if (id_word >= num_ids_word) + return true; uint32_t old_val = c->enable[id_word]; uint32_t new_val = id_word == 0 ? val & ~(uint32_t)1 : val; @@ -232,7 +230,7 @@ bool plic_t::context_read(plic_context_t *c, *val = context_claim(c); return true; default: - return false; + return true; }; } @@ -317,9 +315,15 @@ bool plic_t::load(reg_t addr, size_t len, uint8_t* bytes) bool ret = false; uint32_t val = 0; - /* Only 32bit loads supported */ - if (len != 4) { - return false; + switch (len) { + case 4: + break; + case 8: + // Implement double-word loads as a pair of word loads + return load(addr, 4, bytes) && load(addr + 4, 4, bytes + 4); + default: + // Subword loads are not supported + return false; } if (PRIORITY_BASE <= addr && addr < ENABLE_BASE) { @@ -350,9 +354,15 @@ bool plic_t::store(reg_t addr, size_t len, const uint8_t* bytes) bool ret = false; uint32_t val; - /* Only 32bit stores supported */ - if (len != 4) { - return false; + switch (len) { + case 4: + break; + case 8: + // Implement double-word stores as a pair of word stores + return store(addr, 4, bytes) && store(addr + 4, 4, bytes + 4); + default: + // Subword stores are not supported + return false; } memcpy((uint8_t *)&val, bytes, len); |