diff options
-rw-r--r-- | riscv/csrs.cc | 73 | ||||
-rw-r--r-- | riscv/csrs.h | 15 | ||||
-rw-r--r-- | riscv/decode.h | 6 | ||||
-rw-r--r-- | riscv/insns/hfence_gvma.h | 2 | ||||
-rw-r--r-- | riscv/insns/mret.h | 2 | ||||
-rw-r--r-- | riscv/insns/sfence_vma.h | 2 | ||||
-rw-r--r-- | riscv/insns/sret.h | 2 | ||||
-rw-r--r-- | riscv/insns/wfi.h | 2 | ||||
-rw-r--r-- | riscv/mmu.cc | 8 | ||||
-rw-r--r-- | riscv/processor.cc | 87 | ||||
-rw-r--r-- | riscv/processor.h | 2 |
11 files changed, 108 insertions, 93 deletions
diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 1a294d4..1840143 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -349,14 +349,14 @@ void vsstatus_csr_t::backdoor_write(const reg_t val) noexcept { // implement class sstatus_proxy_csr_t sstatus_proxy_csr_t::sstatus_proxy_csr_t(processor_t* const proc, const reg_t addr): logged_csr_t(proc, addr), - mstatus(&(proc->get_state()->mstatus)) { + mstatus(proc->get_state()->mstatus) { } reg_t sstatus_proxy_csr_t::read() const noexcept { reg_t mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UBE | SSTATUS_SPP | SSTATUS_FS | (proc->supports_extension('V') ? SSTATUS_VS : 0) | SSTATUS_XS | SSTATUS_SUM | SSTATUS_MXR | SSTATUS_UXL; - reg_t sstatus = *mstatus & mask; + reg_t sstatus = mstatus->read() & mask; if ((sstatus & SSTATUS_FS) == SSTATUS_FS || (sstatus & SSTATUS_XS) == SSTATUS_XS || (sstatus & SSTATUS_VS) == SSTATUS_VS) @@ -368,8 +368,71 @@ bool sstatus_proxy_csr_t::unlogged_write(const reg_t val) noexcept { reg_t mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS | SSTATUS_SUM | SSTATUS_MXR | (proc->supports_extension('V') ? SSTATUS_VS : 0); - reg_t new_mstatus = (*mstatus & ~mask) | (val & mask); + reg_t new_mstatus = (mstatus->read() & ~mask) | (val & mask); - proc->set_csr(CSR_MSTATUS, new_mstatus); - return false; // avoid double logging: already logged by proc->set_csr() + mstatus->write(new_mstatus); + return false; // avoid double logging: already logged by mstatus->write() +} + + +// implement class mstatus_csr_t +mstatus_csr_t::mstatus_csr_t(processor_t* const proc, const reg_t addr): + basic_csr_t(proc, addr, +#ifdef RISCV_ENABLE_DUAL_ENDIAN + proc->get_mmu()->is_target_big_endian() ? MSTATUS_UBE | MSTATUS_SBE | MSTATUS_MBE : +#endif + 0 // initial value for mstatus + ) { +} + + +bool mstatus_csr_t::unlogged_write(const reg_t val) noexcept { + return backdoor_write(val); +} + +bool mstatus_csr_t::backdoor_write(const reg_t val) noexcept { + bool has_page = proc->supports_extension('S') && proc->supports_impl(IMPL_MMU); + if ((val ^ read()) & + (MSTATUS_MPP | MSTATUS_MPRV + | (has_page ? (MSTATUS_MXR | MSTATUS_SUM) : 0) + | MSTATUS_MXR)) + proc->get_mmu()->flush_tlb(); + + bool has_fs = proc->supports_extension('S') || proc->supports_extension('F') + || proc->supports_extension('V'); + bool has_vs = proc->supports_extension('V'); + bool has_mpv = proc->supports_extension('S') && proc->supports_extension('H'); + bool has_gva = has_mpv; + + reg_t mask = MSTATUS_MIE | MSTATUS_MPIE | MSTATUS_MPRV | MSTATUS_MPP + | (proc->supports_extension('S') ? (MSTATUS_SIE | MSTATUS_SPIE) : 0) + | MSTATUS_TW | MSTATUS_TSR + | (has_page ? (MSTATUS_MXR | MSTATUS_SUM | MSTATUS_TVM) : 0) + | (has_fs ? MSTATUS_FS : 0) + | (has_vs ? MSTATUS_VS : 0) + | (proc->any_custom_extensions() ? MSTATUS_XS : 0) + | (has_gva ? MSTATUS_GVA : 0) + | (has_mpv ? MSTATUS_MPV : 0); + + reg_t requested_mpp = proc->legalize_privilege(get_field(val, MSTATUS_MPP)); + reg_t new_mstatus = set_field(val, MSTATUS_MPP, requested_mpp); + if (proc->supports_extension('S')) + mask |= MSTATUS_SPP; + + new_mstatus = (read() & ~mask) | (new_mstatus & mask); + + bool dirty = (new_mstatus & MSTATUS_FS) == MSTATUS_FS; + dirty |= (new_mstatus & MSTATUS_XS) == MSTATUS_XS; + dirty |= (new_mstatus & MSTATUS_VS) == MSTATUS_VS; + if (proc->get_max_xlen() == 32) + new_mstatus = set_field(new_mstatus, MSTATUS32_SD, dirty); + else + new_mstatus = set_field(new_mstatus, MSTATUS64_SD, dirty); + + if (proc->supports_extension('U')) + new_mstatus = set_field(new_mstatus, MSTATUS_UXL, xlen_to_uxl(proc->get_max_xlen())); + if (proc->supports_extension('S')) + new_mstatus = set_field(new_mstatus, MSTATUS_SXL, xlen_to_uxl(proc->get_max_xlen())); + + return basic_csr_t::unlogged_write(new_mstatus); } diff --git a/riscv/csrs.h b/riscv/csrs.h index 7078595..0afdd0c 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -205,7 +205,7 @@ typedef std::shared_ptr<vsstatus_csr_t> vsstatus_csr_t_p; // 2. [done] One by one, switch references to state.mstatus to use // state.sstatus. When complete, all references to sstatus that // need to be virtualized will be through this object. -// 3. Convert mstatus into a csr_t subclass. +// 3. [done] Convert mstatus into a csr_t subclass. // 4. Refactor common code into base class. // 5. Convert sstatus to a virtualized_csr_t, with a // nonvirtual_sstatus of type sstatus_proxy_csr_t, and @@ -221,8 +221,19 @@ class sstatus_proxy_csr_t: public logged_csr_t { protected: virtual bool unlogged_write(const reg_t val) noexcept override; private: - reg_t* const mstatus; + csr_t_p mstatus; }; +class mstatus_csr_t: public basic_csr_t { + public: + mstatus_csr_t(processor_t* const proc, const reg_t addr); + bool backdoor_write(const reg_t val) noexcept; + protected: + virtual bool unlogged_write(const reg_t val) noexcept override; +}; + +typedef std::shared_ptr<mstatus_csr_t> mstatus_csr_t_p; + + #endif diff --git a/riscv/decode.h b/riscv/decode.h index 0fdc4f5..a269ad1 100644 --- a/riscv/decode.h +++ b/riscv/decode.h @@ -249,9 +249,9 @@ private: #define require_extension(s) require(p->supports_extension(s)) #define require_either_extension(A,B) require(p->supports_extension(A) || p->supports_extension(B)); #define require_impl(s) require(p->supports_impl(s)) -#define require_fp require(((STATE.mstatus & MSTATUS_FS) != 0) && ((STATE.v == 0) || ((STATE.vsstatus->read() & SSTATUS_FS) != 0))) -#define require_accelerator require(((STATE.mstatus & MSTATUS_XS) != 0) && ((STATE.v == 0) || ((STATE.vsstatus->read() & SSTATUS_XS) != 0))) -#define require_vector_vs require(((STATE.mstatus & MSTATUS_VS) != 0) && ((STATE.v == 0) || ((STATE.vsstatus->read() & SSTATUS_VS) != 0))) +#define require_fp require(((STATE.mstatus->read() & MSTATUS_FS) != 0) && ((STATE.v == 0) || ((STATE.vsstatus->read() & SSTATUS_FS) != 0))) +#define require_accelerator require(((STATE.mstatus->read() & MSTATUS_XS) != 0) && ((STATE.v == 0) || ((STATE.vsstatus->read() & SSTATUS_XS) != 0))) +#define require_vector_vs require(((STATE.mstatus->read() & MSTATUS_VS) != 0) && ((STATE.v == 0) || ((STATE.vsstatus->read() & SSTATUS_VS) != 0))) #define require_vector(alu) \ do { \ require_vector_vs; \ diff --git a/riscv/insns/hfence_gvma.h b/riscv/insns/hfence_gvma.h index f1996d9..b3ddf1e 100644 --- a/riscv/insns/hfence_gvma.h +++ b/riscv/insns/hfence_gvma.h @@ -1,4 +1,4 @@ require_extension('H'); require_novirt(); -require_privilege(get_field(STATE.mstatus, MSTATUS_TVM) ? PRV_M : PRV_S); +require_privilege(get_field(STATE.mstatus->read(), MSTATUS_TVM) ? PRV_M : PRV_S); MMU.flush_tlb(); diff --git a/riscv/insns/mret.h b/riscv/insns/mret.h index 57e9cef..44a6aa9 100644 --- a/riscv/insns/mret.h +++ b/riscv/insns/mret.h @@ -1,6 +1,6 @@ require_privilege(PRV_M); set_pc_and_serialize(p->get_state()->mepc->read()); -reg_t s = STATE.mstatus; +reg_t s = STATE.mstatus->read(); reg_t prev_prv = get_field(s, MSTATUS_MPP); reg_t prev_virt = get_field(s, MSTATUS_MPV); if (prev_prv != PRV_M) diff --git a/riscv/insns/sfence_vma.h b/riscv/insns/sfence_vma.h index 2896024..a14865f 100644 --- a/riscv/insns/sfence_vma.h +++ b/riscv/insns/sfence_vma.h @@ -4,6 +4,6 @@ if (STATE.v) { if (STATE.prv == PRV_U || get_field(STATE.hstatus, HSTATUS_VTVM)) require_novirt(); } else { - require_privilege(get_field(STATE.mstatus, MSTATUS_TVM) ? PRV_M : PRV_S); + require_privilege(get_field(STATE.mstatus->read(), MSTATUS_TVM) ? PRV_M : PRV_S); } MMU.flush_tlb(); diff --git a/riscv/insns/sret.h b/riscv/insns/sret.h index bbe3d5c..8436cda 100644 --- a/riscv/insns/sret.h +++ b/riscv/insns/sret.h @@ -3,7 +3,7 @@ if (STATE.v) { if (STATE.prv == PRV_U || get_field(STATE.hstatus, HSTATUS_VTSR)) require_novirt(); } else { - require_privilege(get_field(STATE.mstatus, MSTATUS_TSR) ? PRV_M : PRV_S); + require_privilege(get_field(STATE.mstatus->read(), MSTATUS_TSR) ? PRV_M : PRV_S); } reg_t next_pc = p->get_state()->sepc->read(); set_pc_and_serialize(next_pc); diff --git a/riscv/insns/wfi.h b/riscv/insns/wfi.h index 59ed35b..efe62fd 100644 --- a/riscv/insns/wfi.h +++ b/riscv/insns/wfi.h @@ -1,6 +1,6 @@ if (STATE.v && STATE.prv == PRV_U) { require_novirt(); -} else if (get_field(STATE.mstatus, MSTATUS_TW)) { +} else if (get_field(STATE.mstatus->read(), MSTATUS_TW)) { require_privilege(PRV_M); } else if (STATE.v) { // VS-mode if (get_field(STATE.hstatus, HSTATUS_VTW)) diff --git a/riscv/mmu.cc b/riscv/mmu.cc index c214884..a9c056c 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -57,9 +57,9 @@ reg_t mmu_t::translate(reg_t addr, reg_t len, access_type type, uint32_t xlate_f bool hlvx = xlate_flags & RISCV_XLATE_VIRT_HLVX; reg_t mode = proc->state.prv; if (type != FETCH) { - if (!proc->state.debug_mode && get_field(proc->state.mstatus, MSTATUS_MPRV)) { - mode = get_field(proc->state.mstatus, MSTATUS_MPP); - if (get_field(proc->state.mstatus, MSTATUS_MPV) && mode != PRV_M) + if (!proc->state.debug_mode && get_field(proc->state.mstatus->read(), MSTATUS_MPRV)) { + mode = get_field(proc->state.mstatus->read(), MSTATUS_MPP); + if (get_field(proc->state.mstatus->read(), MSTATUS_MPV) && mode != PRV_M) virt = true; } if (xlate_flags & RISCV_XLATE_VIRT) { @@ -190,7 +190,7 @@ tlb_entry_t mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, char* host_addr, access_ tlb_entry_t entry = {host_addr - vaddr, paddr - vaddr}; - if (proc && get_field(proc->state.mstatus, MSTATUS_MPRV)) + if (proc && get_field(proc->state.mstatus->read(), MSTATUS_MPRV)) return entry; if ((tlb_load_tag[idx] & ~TLB_CHECK_TRIGGERS) != expected_tag) diff --git a/riscv/processor.cc b/riscv/processor.cc index 58d044b..7cf7d88 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -330,13 +330,13 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) FPR.reset(); // This assumes xlen is always max_xlen, which is true today (see - // set_csr() for CSR_MSTATUS): + // mstatus_csr_t::backdoor_write()): auto xlen = proc->get_max_xlen(); prv = PRV_M; v = false; misa = max_isa; - mstatus = 0; + csrmap[CSR_MSTATUS] = mstatus = std::make_shared<mstatus_csr_t>(proc, CSR_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); csrmap[CSR_MSCRATCH] = std::make_shared<basic_csr_t>(proc, CSR_MSCRATCH, 0); @@ -501,18 +501,15 @@ void processor_t::enable_log_commits() void processor_t::reset() { + xlen = max_xlen; state.reset(this, max_isa); -#ifdef RISCV_ENABLE_DUAL_ENDIAN - if (mmu->is_target_big_endian()) - state.mstatus |= MSTATUS_UBE | MSTATUS_SBE | MSTATUS_MBE; -#endif state.mideleg = supports_extension('H') ? MIDELEG_FORCED_MASK : 0; state.dcsr.halt = halt_on_reset; halt_on_reset = false; - set_csr(CSR_MSTATUS, state.mstatus); - state.vsstatus->write(state.mstatus & SSTATUS_VS_MASK); // set UXL + state.mstatus->write(state.mstatus->read()); // set fixed fields + state.vsstatus->write(state.mstatus->read() & SSTATUS_VS_MASK); // set UXL set_csr(CSR_HSTATUS, state.hstatus); // set VSXL VU.reset(); @@ -606,7 +603,7 @@ void processor_t::take_interrupt(reg_t pending_interrupts) } // M-ints have higher priority over HS-ints and VS-ints - mie = get_field(state.mstatus, MSTATUS_MIE); + mie = get_field(state.mstatus->read(), MSTATUS_MIE); m_enabled = state.prv < PRV_M || (state.prv == PRV_M && mie); enabled_interrupts = pending_interrupts & ~state.mideleg & -m_enabled; if (enabled_interrupts == 0) { @@ -703,8 +700,8 @@ void processor_t::set_virt(bool virt) mask = SSTATUS_VS_MASK; mask |= (supports_extension('V') ? SSTATUS_VS : 0); mask |= (xlen == 64 ? SSTATUS64_SD : SSTATUS32_SD); - tmp = state.mstatus & mask; - state.mstatus = (state.mstatus & ~mask) | (state.vsstatus->read() & mask); + tmp = state.mstatus->read() & mask; + state.mstatus->backdoor_write((state.mstatus->read() & ~mask) | (state.vsstatus->read() & mask)); state.vsstatus->backdoor_write(tmp); state.v = virt; } @@ -822,13 +819,13 @@ void processor_t::take_trap(trap_t& t, reg_t epc) state.mtval2 = t.get_tval2(); state.mtinst = t.get_tinst(); - reg_t s = state.mstatus; + reg_t s = state.mstatus->read(); s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_MIE)); s = set_field(s, MSTATUS_MPP, state.prv); s = set_field(s, MSTATUS_MIE, 0); s = set_field(s, MSTATUS_MPV, curr_virt); s = set_field(s, MSTATUS_GVA, t.has_gva()); - set_csr(CSR_MSTATUS, s); + state.mstatus->write(s); set_privilege(PRV_M); } } @@ -957,53 +954,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_MSTATUS: { - bool has_page = supports_extension('S') && supports_impl(IMPL_MMU); - if ((val ^ state.mstatus) & - (MSTATUS_MPP | MSTATUS_MPRV - | (has_page ? (MSTATUS_MXR | MSTATUS_SUM) : 0) - | MSTATUS_MXR)) - mmu->flush_tlb(); - - bool has_fs = supports_extension('S') || supports_extension('F') - || supports_extension('V'); - bool has_vs = supports_extension('V'); - bool has_mpv = supports_extension('S') && supports_extension('H'); - bool has_gva = has_mpv; - - reg_t mask = MSTATUS_MIE | MSTATUS_MPIE | MSTATUS_MPRV - | (supports_extension('S') ? (MSTATUS_SIE | MSTATUS_SPIE) : 0) - | MSTATUS_TW | MSTATUS_TSR - | (has_page ? (MSTATUS_MXR | MSTATUS_SUM | MSTATUS_TVM) : 0) - | (has_fs ? MSTATUS_FS : 0) - | (has_vs ? MSTATUS_VS : 0) - | (any_custom_extensions() ? MSTATUS_XS : 0) - | (has_gva ? MSTATUS_GVA : 0) - | (has_mpv ? MSTATUS_MPV : 0); - - reg_t requested_mpp = legalize_privilege(get_field(val, MSTATUS_MPP)); - state.mstatus = set_field(state.mstatus, MSTATUS_MPP, requested_mpp); - if (supports_extension('S')) - mask |= MSTATUS_SPP; - - state.mstatus = (state.mstatus & ~mask) | (val & mask); - - bool dirty = (state.mstatus & MSTATUS_FS) == MSTATUS_FS; - dirty |= (state.mstatus & MSTATUS_XS) == MSTATUS_XS; - dirty |= (state.mstatus & MSTATUS_VS) == MSTATUS_VS; - if (max_xlen == 32) - state.mstatus = set_field(state.mstatus, MSTATUS32_SD, dirty); - else - state.mstatus = set_field(state.mstatus, MSTATUS64_SD, dirty); - - if (supports_extension('U')) - state.mstatus = set_field(state.mstatus, MSTATUS_UXL, xlen_to_uxl(max_xlen)); - if (supports_extension('S')) - state.mstatus = set_field(state.mstatus, MSTATUS_SXL, xlen_to_uxl(max_xlen)); - // U-XLEN == S-XLEN == M-XLEN - xlen = max_xlen; - 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: @@ -1122,7 +1072,7 @@ void processor_t::set_csr(int which, reg_t val) if (!new_h && prev_h) { state.mideleg &= ~MIDELEG_FORCED_MASK; state.medeleg &= ~hypervisor_exceptions; - state.mstatus &= ~(MSTATUS_GVA | MSTATUS_MPV); + 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 set_csr(CSR_HSTATUS, 0); @@ -1298,35 +1248,28 @@ void processor_t::set_csr(int which, reg_t val) switch (which) { case CSR_FFLAGS: - LOG_CSR(CSR_MSTATUS); LOG_CSR(CSR_FFLAGS); break; case CSR_FRM: - LOG_CSR(CSR_MSTATUS); LOG_CSR(CSR_FRM); break; case CSR_FCSR: - LOG_CSR(CSR_MSTATUS); LOG_CSR(CSR_FFLAGS); LOG_CSR(CSR_FRM); LOG_CSR(CSR_FCSR); break; case CSR_VCSR: - LOG_CSR(CSR_MSTATUS); LOG_CSR(CSR_VXSAT); LOG_CSR(CSR_VXRM); break; case CSR_VSTART: - LOG_CSR(CSR_MSTATUS); LOG_CSR(CSR_VSTART); break; case CSR_VXSAT: - LOG_CSR(CSR_MSTATUS); LOG_CSR(CSR_VXSAT); break; case CSR_VXRM: - LOG_CSR(CSR_MSTATUS); LOG_CSR(CSR_VXRM); break; @@ -1339,7 +1282,6 @@ void processor_t::set_csr(int which, reg_t val) LOG_CSR(CSR_SIE); break; - case CSR_MSTATUS: case CSR_MIP: case CSR_MIE: case CSR_MIDELEG: @@ -1513,15 +1455,14 @@ reg_t processor_t::get_csr(int which, insn_t insn, bool write, bool peek) goto throw_virtual; ret(state.vsatp); } else { - if (get_field(state.mstatus, MSTATUS_TVM)) + if (get_field(state.mstatus->read(), MSTATUS_TVM)) require_privilege(PRV_M); ret(state.satp); } } - case CSR_MSTATUS: ret(state.mstatus); case CSR_MSTATUSH: if (xlen == 32) - ret((state.mstatus >> 32) & (MSTATUSH_SBE | MSTATUSH_MBE)); + ret((state.mstatus->read() >> 32) & (MSTATUSH_SBE | MSTATUSH_MBE)); break; case CSR_MIP: ret(state.mip); case CSR_MIE: ret(state.mie); @@ -1557,7 +1498,7 @@ reg_t processor_t::get_csr(int which, insn_t insn, bool write, bool peek) case CSR_HVIP: ret(state.mip & MIP_VS_MASK); case CSR_HTINST: ret(state.htinst); case CSR_HGATP: { - if (!state.v && get_field(state.mstatus, MSTATUS_TVM)) + if (!state.v && get_field(state.mstatus->read(), MSTATUS_TVM)) require_privilege(PRV_M); ret(state.hgatp); } diff --git a/riscv/processor.h b/riscv/processor.h index f872416..c61bb94 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -169,7 +169,7 @@ struct state_t reg_t prv; // TODO: Can this be an enum instead? bool v; reg_t misa; - reg_t mstatus; + mstatus_csr_t_p mstatus; csr_t_p mepc; csr_t_p mtval; csr_t_p mtvec; |