From 7c8ae9ba4d6f2e8b5b35918d4a0ec2f0f965ca43 Mon Sep 17 00:00:00 2001 From: Scott Johnson Date: Sun, 7 Mar 2021 23:27:43 -0800 Subject: [PATCH] Convert mip to csr_t family This changes the commitlog of `csrw sip` so that it only logs a change to `mip`, instead of both `mip` and `sip`. This is arguably preferable, since there is no real `sip` register -- it is only a view into `mip`. It also adds proper tracing of the modification to `mip` when doing `csrw` to `hip`, `hvip`, and `vsip`, which were all missing previously. --- riscv/clint.cc | 10 +++++----- riscv/csrs.cc | 37 +++++++++++++++++++++++++++++++++- riscv/csrs.h | 19 ++++++++++++++++++ riscv/processor.cc | 49 +++++++++++++++------------------------------- riscv/processor.h | 4 ++-- 5 files changed, 78 insertions(+), 41 deletions(-) diff --git a/riscv/clint.cc b/riscv/clint.cc index aee995bf..72d1bbeb 100644 --- a/riscv/clint.cc +++ b/riscv/clint.cc @@ -33,7 +33,7 @@ bool clint_t::load(reg_t addr, size_t len, uint8_t* bytes) if (addr >= MSIP_BASE && addr + len <= MSIP_BASE + procs.size()*sizeof(msip_t)) { std::vector msip(procs.size()); for (size_t i = 0; i < procs.size(); ++i) - msip[i] = !!(procs[i]->state.mip & MIP_MSIP); + 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); @@ -54,9 +54,9 @@ bool clint_t::store(reg_t addr, size_t len, const uint8_t* bytes) 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 &= ~MIP_MSIP; + procs[i]->state.mip->backdoor_write_with_mask(MIP_MSIP, 0); if (!!(msip[i] & 1)) - procs[i]->state.mip |= MIP_MSIP; + procs[i]->state.mip->backdoor_write_with_mask(MIP_MSIP, MIP_MSIP); } } else if (addr >= MTIMECMP_BASE && addr + len <= MTIMECMP_BASE + procs.size()*sizeof(mtimecmp_t)) { memcpy((uint8_t*)&mtimecmp[0] + addr - MTIMECMP_BASE, bytes, len); @@ -82,8 +82,8 @@ void clint_t::increment(reg_t inc) mtime += inc; } for (size_t i = 0; i < procs.size(); i++) { - procs[i]->state.mip &= ~MIP_MTIP; + procs[i]->state.mip->backdoor_write_with_mask(MIP_MTIP, 0); if (mtime >= mtimecmp[i]) - procs[i]->state.mip |= MIP_MTIP; + procs[i]->state.mip->backdoor_write_with_mask(MIP_MTIP, MIP_MTIP); } } diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 4935f82f..584b330e 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -486,7 +486,7 @@ bool misa_csr_t::unlogged_write(const reg_t val) noexcept { state->medeleg &= ~hypervisor_exceptions; state->mstatus->write(state->mstatus->read() & ~(MSTATUS_GVA | MSTATUS_MPV)); state->mie &= ~MIP_HS_MASK; // also takes care of hie, sie - state->mip &= ~MIP_HS_MASK; // also takes care of hip, sip, hvip + state->mip->write_with_mask(MIP_HS_MASK, 0); // also takes care of hip, sip, hvip proc->set_csr(CSR_HSTATUS, 0); } @@ -502,3 +502,38 @@ bool misa_csr_t::extension_enabled_const(unsigned char ext) const noexcept { assert(!(1 & (write_mask >> (ext - 'A')))); return extension_enabled(ext); } + + +// implement class mip_csr_t +mip_csr_t::mip_csr_t(processor_t* const proc, const reg_t addr): + logged_csr_t(proc, addr), + val(0) { +} + +reg_t mip_csr_t::read() const noexcept { + return val; +} + +void mip_csr_t::write_with_mask(const reg_t mask, const reg_t val) noexcept { + backdoor_write_with_mask(mask, val); + log_write(); +} + +void mip_csr_t::backdoor_write_with_mask(const reg_t mask, const reg_t val) noexcept { + this->val = (this->val & ~mask) | (val & mask); +} + +bool mip_csr_t::unlogged_write(const reg_t val) noexcept { + const reg_t supervisor_ints = proc->extension_enabled('S') ? MIP_SSIP | MIP_STIP | MIP_SEIP : 0; + const reg_t vssip_int = proc->extension_enabled('H') ? MIP_VSSIP : 0; + const reg_t hypervisor_ints = proc->extension_enabled('H') ? MIP_HS_MASK : 0; + // We must mask off sgeip, vstip, and vseip. All three of these + // bits are aliases for the same bits in hip. The hip spec says: + // * sgeip is read-only -- write hgeip instead + // * vseip is read-only -- write hvip instead + // * vstip is read-only -- write hvip instead + const reg_t mask = (supervisor_ints | hypervisor_ints) & + (MIP_SEIP | MIP_SSIP | MIP_STIP | vssip_int); + this->val = (this->val & ~mask) | (val & mask); + return true; +} diff --git a/riscv/csrs.h b/riscv/csrs.h index 032d0576..1bd035cd 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -270,4 +270,23 @@ class misa_csr_t: public basic_csr_t { typedef std::shared_ptr misa_csr_t_p; + +class mip_csr_t: public logged_csr_t { + public: + mip_csr_t(processor_t* const proc, const reg_t addr); + virtual reg_t read() const noexcept override; + + void write_with_mask(const reg_t mask, const reg_t val) noexcept; + + // Does not log. Used by external things (clint) that wiggle bits in mip. + void backdoor_write_with_mask(const reg_t mask, const reg_t val) noexcept; + protected: + virtual bool unlogged_write(const reg_t val) noexcept override; + private: + reg_t val; +}; + +typedef std::shared_ptr mip_csr_t_p; + + #endif diff --git a/riscv/processor.cc b/riscv/processor.cc index 1324bd84..065300bb 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -346,7 +346,7 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) csrmap[CSR_MCAUSE] = mcause = std::make_shared(proc, CSR_MCAUSE); minstret = 0; mie = 0; - mip = 0; + csrmap[CSR_MIP] = mip = std::make_shared(proc, CSR_MIP); medeleg = 0; mideleg = 0; mcounteren = 0; @@ -947,17 +947,6 @@ void processor_t::set_csr(int which, reg_t val) VU.vxsat = (val & VCSR_VXSAT) >> VCSR_VXSAT_SHIFT; VU.vxrm = (val & VCSR_VXRM) >> VCSR_VXRM_SHIFT; break; - case CSR_MIP: { - // We must mask off sgeip, vstip, and vseip. All three of these - // bits are aliases for the same bits in hip. The hip spec says: - // * sgeip is read-only -- write hgeip instead - // * vseip is read-only -- write hvip instead - // * vstip is read-only -- write hvip instead - reg_t mask = (supervisor_ints | hypervisor_ints) & - (MIP_SEIP | MIP_SSIP | MIP_STIP | vssip_int); - state.mip = (state.mip & ~mask) | (val & mask); - break; - } case CSR_MIE: state.mie = (state.mie & ~all_ints) | (val & all_ints); break; @@ -1008,8 +997,8 @@ void processor_t::set_csr(int which, reg_t val) } else { mask = state.mideleg & MIP_SSIP; } - state.mip = (state.mip & ~mask) | (val & mask); - break; + state.mip->write_with_mask(mask, val); + return; } case CSR_SIE: { reg_t mask; @@ -1083,13 +1072,13 @@ void processor_t::set_csr(int which, reg_t val) break; case CSR_HIP: { reg_t mask = MIP_VSSIP; - state.mip = (state.mip & ~mask) | (val & mask); - break; + state.mip->write_with_mask(mask, val); + return; } case CSR_HVIP: { reg_t mask = MIP_VS_MASK; - state.mip = (state.mip & ~mask) | (val & mask); - break; + state.mip->write_with_mask(mask, val); + return; } case CSR_HTINST: state.htinst = val; @@ -1120,8 +1109,8 @@ void processor_t::set_csr(int which, reg_t val) } case CSR_VSIP: { reg_t mask = state.hideleg & MIP_VSSIP; - state.mip = (state.mip & ~mask) | ((val << 1) & mask); - break; + state.mip->write_with_mask(mask, val << 1); + return; } case CSR_VSATP: if (!supports_impl(IMPL_MMU)) @@ -1230,16 +1219,11 @@ void processor_t::set_csr(int which, reg_t val) LOG_CSR(CSR_VXRM); break; - case CSR_SIP: - LOG_CSR(CSR_MIP); - LOG_CSR(CSR_SIP); - break; case CSR_SIE: LOG_CSR(CSR_MIE); LOG_CSR(CSR_SIE); break; - case CSR_MIP: case CSR_MIE: case CSR_MIDELEG: case CSR_MEDELEG: @@ -1393,9 +1377,9 @@ reg_t processor_t::get_csr(int which, insn_t insn, bool write, bool peek) case CSR_MCOUNTINHIBIT: ret(0); case CSR_SIP: { if (state.v) { - ret((state.mip & state.hideleg & MIP_VS_MASK) >> 1); + ret((state.mip->read() & state.hideleg & MIP_VS_MASK) >> 1); } else { - ret(state.mip & state.mideleg & ~MIP_HS_MASK); + ret(state.mip->read() & state.mideleg & ~MIP_HS_MASK); } } case CSR_SIE: { @@ -1420,7 +1404,6 @@ reg_t processor_t::get_csr(int which, insn_t insn, bool write, bool peek) if (xlen == 32) ret((state.mstatus->read() >> 32) & (MSTATUSH_SBE | MSTATUSH_MBE)); break; - case CSR_MIP: ret(state.mip); case CSR_MIE: ret(state.mie); case CSR_MTVAL2: if (extension_enabled('H')) @@ -1449,8 +1432,8 @@ reg_t processor_t::get_csr(int which, insn_t insn, bool write, bool peek) case CSR_HCOUNTEREN: ret(state.hcounteren); case CSR_HGEIE: ret(0); case CSR_HTVAL: ret(state.htval); - case CSR_HIP: ret(state.mip & MIP_HS_MASK); - case CSR_HVIP: ret(state.mip & MIP_VS_MASK); + case CSR_HIP: ret(state.mip->read() & MIP_HS_MASK); + case CSR_HVIP: ret(state.mip->read() & MIP_VS_MASK); case CSR_HTINST: ret(state.htinst); case CSR_HGATP: { if (!state.v && get_field(state.mstatus->read(), MSTATUS_TVM)) @@ -1459,7 +1442,7 @@ reg_t processor_t::get_csr(int which, insn_t insn, bool write, bool peek) } case CSR_HGEIP: ret(0); case CSR_VSIE: ret((state.mie & state.hideleg & MIP_VS_MASK) >> 1); - case CSR_VSIP: ret((state.mip & state.hideleg & MIP_VS_MASK) >> 1); + case CSR_VSIP: ret((state.mip->read() & state.hideleg & MIP_VS_MASK) >> 1); case CSR_VSATP: ret(state.vsatp); case CSR_TSELECT: ret(state.tselect); case CSR_TDATA1: @@ -1691,7 +1674,7 @@ bool processor_t::load(reg_t addr, size_t len, uint8_t* bytes) case 0: if (len <= 4) { memset(bytes, 0, len); - bytes[0] = get_field(state.mip, MIP_MSIP); + bytes[0] = get_field(state.mip->read(), MIP_MSIP); return true; } break; @@ -1706,7 +1689,7 @@ bool processor_t::store(reg_t addr, size_t len, const uint8_t* bytes) { case 0: if (len <= 4) { - state.mip = set_field(state.mip, MIP_MSIP, bytes[0]); + state.mip->write_with_mask(MIP_MSIP, bytes[0] << IRQ_M_SOFT); return true; } break; diff --git a/riscv/processor.h b/riscv/processor.h index 2a5d3e1a..de594ea2 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -176,7 +176,7 @@ struct state_t csr_t_p mcause; reg_t minstret; reg_t mie; - reg_t mip; + mip_csr_t_p mip; reg_t medeleg; reg_t mideleg; uint32_t mcounteren; @@ -485,7 +485,7 @@ private: static const size_t OPCODE_CACHE_SIZE = 8191; insn_desc_t opcode_cache[OPCODE_CACHE_SIZE]; - void take_pending_interrupt() { take_interrupt(state.mip & state.mie); } + void take_pending_interrupt() { take_interrupt(state.mip->read() & state.mie); } void take_interrupt(reg_t mask); // take first enabled interrupt in mask void take_trap(trap_t& t, reg_t epc); // take an exception void disasm(insn_t insn); // disassemble and print an instruction