aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--riscv/csrs.cc73
-rw-r--r--riscv/csrs.h15
-rw-r--r--riscv/decode.h6
-rw-r--r--riscv/insns/hfence_gvma.h2
-rw-r--r--riscv/insns/mret.h2
-rw-r--r--riscv/insns/sfence_vma.h2
-rw-r--r--riscv/insns/sret.h2
-rw-r--r--riscv/insns/wfi.h2
-rw-r--r--riscv/mmu.cc8
-rw-r--r--riscv/processor.cc87
-rw-r--r--riscv/processor.h2
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;