aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Johnson <scott.johnson@arilinc.com>2022-07-13 09:33:36 -0700
committerScott Johnson <scott.johnson@arilinc.com>2022-07-13 18:57:55 -0700
commit85ab2228ddb802c33a967349d69b2d948846bd01 (patch)
treef10f767ca76db9903d0a9fb1169d9c833cd1804c
parent8f36f1a5f8a47282743706e7777a277b9f17ba6f (diff)
downloadspike-85ab2228ddb802c33a967349d69b2d948846bd01.zip
spike-85ab2228ddb802c33a967349d69b2d948846bd01.tar.gz
spike-85ab2228ddb802c33a967349d69b2d948846bd01.tar.bz2
Add proxy for accessing the low 32 bits of a 64-bit CSR
Use this for mstatus on RV32 so that `csrw mstatus` does not modify the bits in `mstatush`. Fixes #1044.
-rw-r--r--riscv/csrs.cc18
-rw-r--r--riscv/csrs.h15
-rw-r--r--riscv/processor.cc5
3 files changed, 37 insertions, 1 deletions
diff --git a/riscv/csrs.cc b/riscv/csrs.cc
index 3a929ff..dac3eef 100644
--- a/riscv/csrs.cc
+++ b/riscv/csrs.cc
@@ -493,6 +493,24 @@ bool mstatus_csr_t::unlogged_write(const reg_t val) noexcept {
return true;
}
+// implement class rv32_low_csr_t
+rv32_low_csr_t::rv32_low_csr_t(processor_t* const proc, const reg_t addr, csr_t_p orig):
+ csr_t(proc, addr),
+ orig(orig) {
+}
+
+reg_t rv32_low_csr_t::read() const noexcept {
+ return orig->read() & 0xffffffffU;
+}
+
+void rv32_low_csr_t::verify_permissions(insn_t insn, bool write) const {
+ orig->verify_permissions(insn, write);
+}
+
+bool rv32_low_csr_t::unlogged_write(const reg_t val) noexcept {
+ return orig->unlogged_write((orig->written_value() >> 32 << 32) | (val & 0xffffffffU));
+}
+
// implement class rv32_high_csr_t
rv32_high_csr_t::rv32_high_csr_t(processor_t* const proc, const reg_t addr, csr_t_p orig):
csr_t(proc, addr),
diff --git a/riscv/csrs.h b/riscv/csrs.h
index 3998d79..500bde7 100644
--- a/riscv/csrs.h
+++ b/riscv/csrs.h
@@ -54,7 +54,9 @@ class csr_t {
const unsigned csr_priv;
const bool csr_read_only;
+ // For access to written_value() and unlogged_write():
friend class rv32_high_csr_t;
+ friend class rv32_low_csr_t;
};
typedef std::shared_ptr<csr_t> csr_t_p;
@@ -249,6 +251,19 @@ class mstatus_csr_t final: public base_status_csr_t {
typedef std::shared_ptr<mstatus_csr_t> mstatus_csr_t_p;
+// For RV32 CSRs that are split into two, e.g. mstatus/mstatush
+// CSRW should only modify the lower half
+class rv32_low_csr_t: public csr_t {
+ public:
+ rv32_low_csr_t(processor_t* const proc, const reg_t addr, csr_t_p orig);
+ virtual reg_t read() const noexcept override;
+ virtual void verify_permissions(insn_t insn, bool write) const override;
+ protected:
+ virtual bool unlogged_write(const reg_t val) noexcept override;
+ private:
+ csr_t_p orig;
+};
+
class rv32_high_csr_t: public csr_t {
public:
rv32_high_csr_t(processor_t* const proc, const reg_t addr, csr_t_p orig);
diff --git a/riscv/processor.cc b/riscv/processor.cc
index c0f4964..28129ba 100644
--- a/riscv/processor.cc
+++ b/riscv/processor.cc
@@ -189,10 +189,13 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
prv = PRV_M;
v = false;
csrmap[CSR_MISA] = misa = std::make_shared<misa_csr_t>(proc, CSR_MISA, max_isa);
- csrmap[CSR_MSTATUS] = mstatus = std::make_shared<mstatus_csr_t>(proc, CSR_MSTATUS);
+ mstatus = std::make_shared<mstatus_csr_t>(proc, CSR_MSTATUS);
if (xlen == 32) {
+ csrmap[CSR_MSTATUS] = std::make_shared<rv32_low_csr_t>(proc, CSR_MSTATUS, mstatus);
csrmap[CSR_MSTATUSH] = std::make_shared<rv32_high_csr_t>(proc, CSR_MSTATUSH, mstatus);
+ } else {
+ csrmap[CSR_MSTATUS] = mstatus;
}
csrmap[CSR_MEPC] = mepc = std::make_shared<epc_csr_t>(proc, CSR_MEPC);
csrmap[CSR_MTVAL] = mtval = std::make_shared<basic_csr_t>(proc, CSR_MTVAL, 0);