diff options
author | Scott Johnson <scott.johnson@arilinc.com> | 2022-07-13 09:33:36 -0700 |
---|---|---|
committer | Scott Johnson <scott.johnson@arilinc.com> | 2022-07-13 18:57:55 -0700 |
commit | 85ab2228ddb802c33a967349d69b2d948846bd01 (patch) | |
tree | f10f767ca76db9903d0a9fb1169d9c833cd1804c | |
parent | 8f36f1a5f8a47282743706e7777a277b9f17ba6f (diff) | |
download | spike-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.cc | 18 | ||||
-rw-r--r-- | riscv/csrs.h | 15 | ||||
-rw-r--r-- | riscv/processor.cc | 5 |
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); |