diff options
-rw-r--r-- | riscv/csrs.cc | 35 | ||||
-rw-r--r-- | riscv/csrs.h | 18 | ||||
-rw-r--r-- | riscv/processor.cc | 23 | ||||
-rw-r--r-- | riscv/processor.h | 1 |
4 files changed, 62 insertions, 15 deletions
diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 83906cc..6f8f260 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -455,6 +455,10 @@ sstatus_proxy_csr_t::sstatus_proxy_csr_t(processor_t* const proc, const reg_t ad bool sstatus_proxy_csr_t::unlogged_write(const reg_t val) noexcept { const reg_t new_mstatus = (mstatus->read() & ~sstatus_write_mask) | (val & sstatus_write_mask); + // On RV32 this will only log the low 32 bits, so make sure we're + // not modifying anything in the upper 32 bits. + assert((sstatus_write_mask & 0xffffffffU) == sstatus_write_mask); + mstatus->write(new_mstatus); return false; // avoid double logging: already logged by mstatus->write() } @@ -493,15 +497,32 @@ 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, const reg_t mask, csr_t_p orig): +rv32_high_csr_t::rv32_high_csr_t(processor_t* const proc, const reg_t addr, csr_t_p orig): csr_t(proc, addr), - orig(orig), - mask(mask) { + orig(orig) { } reg_t rv32_high_csr_t::read() const noexcept { - return (orig->read() >> 32) & mask; + return (orig->read() >> 32) & 0xffffffffU; } void rv32_high_csr_t::verify_permissions(insn_t insn, bool write) const { @@ -509,7 +530,7 @@ void rv32_high_csr_t::verify_permissions(insn_t insn, bool write) const { } bool rv32_high_csr_t::unlogged_write(const reg_t val) noexcept { - return orig->unlogged_write((orig->written_value() & ~(mask << 32)) | ((val & mask) << 32)); + return orig->unlogged_write((orig->written_value() << 32 >> 32) | ((val & 0xffffffffU) << 32)); } // implement class sstatus_csr_t @@ -595,7 +616,9 @@ bool misa_csr_t::unlogged_write(const reg_t val) noexcept { | (1 << CAUSE_STORE_GUEST_PAGE_FAULT) ; state->medeleg->write(state->medeleg->read() & ~hypervisor_exceptions); - state->mstatus->write(state->mstatus->read() & ~(MSTATUS_GVA | MSTATUS_MPV)); + const reg_t new_mstatus = state->mstatus->read() & ~(MSTATUS_GVA | MSTATUS_MPV); + state->mstatus->write(new_mstatus); + if (state->mstatush) state->mstatush->write(new_mstatus >> 32); // log mstatush change state->mie->write_with_mask(MIP_HS_MASK, 0); // also takes care of hie, sie state->mip->write_with_mask(MIP_HS_MASK, 0); // also takes care of hip, sip, hvip state->hstatus->write(0); diff --git a/riscv/csrs.h b/riscv/csrs.h index bde31da..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,16 +251,28 @@ 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, const reg_t mask, csr_t_p orig); + rv32_high_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; - const reg_t mask; }; class sstatus_proxy_csr_t final: public base_status_csr_t { diff --git a/riscv/processor.cc b/riscv/processor.cc index 5973baf..8f77b47 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -189,11 +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) { - const reg_t mstatush_mask = MSTATUSH_MPV | MSTATUSH_GVA | MSTATUSH_SBE | MSTATUSH_MBE; - csrmap[CSR_MSTATUSH] = std::make_shared<rv32_high_csr_t>(proc, CSR_MSTATUSH, mstatush_mask, mstatus); + csrmap[CSR_MSTATUS] = std::make_shared<rv32_low_csr_t>(proc, CSR_MSTATUS, mstatus); + csrmap[CSR_MSTATUSH] = 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); @@ -403,15 +405,21 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) const reg_t mstateen0_mask = hstateen0_mask; for (int i = 0; i < 4; i++) { const reg_t mstateen_mask = i == 0 ? mstateen0_mask : MSTATEEN_HSTATEEN; - csrmap[CSR_MSTATEEN0 + i] = mstateen[i] = std::make_shared<masked_csr_t>(proc, CSR_MSTATEEN0 + i, mstateen_mask, 0); + mstateen[i] = std::make_shared<masked_csr_t>(proc, CSR_MSTATEEN0 + i, mstateen_mask, 0); if (xlen == 32) { - csrmap[CSR_MSTATEEN0H + i] = std::make_shared<rv32_high_csr_t>(proc, CSR_MSTATEEN0H + i, -1, mstateen[i]); + csrmap[CSR_MSTATEEN0 + i] = std::make_shared<rv32_low_csr_t>(proc, CSR_MSTATEEN0 + i, mstateen[i]); + csrmap[CSR_MSTATEEN0H + i] = std::make_shared<rv32_high_csr_t>(proc, CSR_MSTATEEN0H + i, mstateen[i]); + } else { + csrmap[CSR_MSTATEEN0 + i] = mstateen[i]; } const reg_t hstateen_mask = i == 0 ? hstateen0_mask : HSTATEEN_SSTATEEN; - csrmap[CSR_HSTATEEN0 + i] = hstateen[i] = std::make_shared<hstateen_csr_t>(proc, CSR_HSTATEEN0 + i, hstateen_mask, 0, i); + hstateen[i] = std::make_shared<hstateen_csr_t>(proc, CSR_HSTATEEN0 + i, hstateen_mask, 0, i); if (xlen == 32) { - csrmap[CSR_HSTATEEN0H + i] = std::make_shared<rv32_high_csr_t>(proc, CSR_HSTATEEN0H + i, -1, hstateen[i]); + csrmap[CSR_HSTATEEN0 + i] = std::make_shared<rv32_low_csr_t>(proc, CSR_HSTATEEN0 + i, hstateen[i]); + csrmap[CSR_HSTATEEN0H + i] = std::make_shared<rv32_high_csr_t>(proc, CSR_HSTATEEN0H + i, hstateen[i]); + } else { + csrmap[CSR_HSTATEEN0 + i] = hstateen[i]; } const reg_t sstateen_mask = i == 0 ? sstateen0_mask : 0; @@ -816,6 +824,7 @@ void processor_t::take_trap(trap_t& t, reg_t epc) s = set_field(s, MSTATUS_MPV, curr_virt); s = set_field(s, MSTATUS_GVA, t.has_gva()); state.mstatus->write(s); + if (state.mstatush) state.mstatush->write(s >> 32); // log mstatush change set_privilege(PRV_M); } } diff --git a/riscv/processor.h b/riscv/processor.h index 727c404..347ae16 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -133,6 +133,7 @@ struct state_t bool v; misa_csr_t_p misa; mstatus_csr_t_p mstatus; + csr_t_p mstatush; csr_t_p mepc; csr_t_p mtval; csr_t_p mtvec; |