aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Waterman <andrew@sifive.com>2023-05-25 15:59:48 -0700
committerGitHub <noreply@github.com>2023-05-25 15:59:48 -0700
commit1bcbd715dcca5ac3724ed46bc7ed2018e5137661 (patch)
tree7e324eb00527f04dcf7c74e0b93f97bd6011063c
parentfa79c20a4eea06650c96986360a06403732d88a7 (diff)
parent2c6b94e853cc1ee0c51a46859cf92451c0c19491 (diff)
downloadriscv-isa-sim-1bcbd715dcca5ac3724ed46bc7ed2018e5137661.zip
riscv-isa-sim-1bcbd715dcca5ac3724ed46bc7ed2018e5137661.tar.gz
riscv-isa-sim-1bcbd715dcca5ac3724ed46bc7ed2018e5137661.tar.bz2
Merge pull request #1366 from riscv-software-src/fix-1365
Implement dcsr.v and make DRET use it
-rw-r--r--riscv/csrs.cc32
-rw-r--r--riscv/csrs.h3
-rw-r--r--riscv/insns/dret.h2
-rw-r--r--riscv/insns/mnret.h3
-rw-r--r--riscv/insns/mret.h3
-rw-r--r--riscv/insns/sret.h6
-rw-r--r--riscv/processor.cc59
-rw-r--r--riscv/processor.h10
8 files changed, 55 insertions, 63 deletions
diff --git a/riscv/csrs.cc b/riscv/csrs.cc
index 396f42f..95b5e22 100644
--- a/riscv/csrs.cc
+++ b/riscv/csrs.cc
@@ -13,6 +13,8 @@
#include "trap.h"
// For require():
#include "insn_macros.h"
+// For CSR_DCSR_V:
+#include "debug_defines.h"
// STATE macro used by require_privilege() macro:
#undef STATE
@@ -1234,6 +1236,7 @@ dcsr_csr_t::dcsr_csr_t(processor_t* const proc, const reg_t addr):
ebreaks(false),
ebreaku(false),
halt(false),
+ v(false),
cause(0) {
}
@@ -1244,18 +1247,19 @@ void dcsr_csr_t::verify_permissions(insn_t insn, bool write) const {
}
reg_t dcsr_csr_t::read() const noexcept {
- uint32_t v = 0;
- v = set_field(v, DCSR_XDEBUGVER, 1);
- v = set_field(v, DCSR_EBREAKM, ebreakm);
- v = set_field(v, DCSR_EBREAKH, ebreakh);
- v = set_field(v, DCSR_EBREAKS, ebreaks);
- v = set_field(v, DCSR_EBREAKU, ebreaku);
- v = set_field(v, DCSR_STOPCYCLE, 0);
- v = set_field(v, DCSR_STOPTIME, 0);
- v = set_field(v, DCSR_CAUSE, cause);
- v = set_field(v, DCSR_STEP, step);
- v = set_field(v, DCSR_PRV, prv);
- return v;
+ reg_t result = 0;
+ result = set_field(result, DCSR_XDEBUGVER, 1);
+ result = set_field(result, DCSR_EBREAKM, ebreakm);
+ result = set_field(result, DCSR_EBREAKH, ebreakh);
+ result = set_field(result, DCSR_EBREAKS, ebreaks);
+ result = set_field(result, DCSR_EBREAKU, ebreaku);
+ result = set_field(result, DCSR_STOPCYCLE, 0);
+ result = set_field(result, DCSR_STOPTIME, 0);
+ result = set_field(result, DCSR_CAUSE, cause);
+ result = set_field(result, DCSR_STEP, step);
+ result = set_field(result, DCSR_PRV, prv);
+ result = set_field(result, CSR_DCSR_V, v);
+ return result;
}
bool dcsr_csr_t::unlogged_write(const reg_t val) noexcept {
@@ -1267,12 +1271,14 @@ bool dcsr_csr_t::unlogged_write(const reg_t val) noexcept {
ebreaks = get_field(val, DCSR_EBREAKS);
ebreaku = get_field(val, DCSR_EBREAKU);
halt = get_field(val, DCSR_HALT);
+ v = proc->extension_enabled('H') ? get_field(val, CSR_DCSR_V) : false;
return true;
}
-void dcsr_csr_t::write_cause_and_prv(uint8_t cause, reg_t prv) noexcept {
+void dcsr_csr_t::write_cause_and_prv(uint8_t cause, reg_t prv, bool v) noexcept {
this->cause = cause;
this->prv = prv;
+ this->v = v;
log_write();
}
diff --git a/riscv/csrs.h b/riscv/csrs.h
index 65be799..19aefca 100644
--- a/riscv/csrs.h
+++ b/riscv/csrs.h
@@ -656,7 +656,7 @@ class dcsr_csr_t: public csr_t {
dcsr_csr_t(processor_t* const proc, const reg_t addr);
virtual void verify_permissions(insn_t insn, bool write) const override;
virtual reg_t read() const noexcept override;
- void write_cause_and_prv(uint8_t cause, reg_t prv) noexcept;
+ void write_cause_and_prv(uint8_t cause, reg_t prv, bool v) noexcept;
protected:
virtual bool unlogged_write(const reg_t val) noexcept override;
public:
@@ -667,6 +667,7 @@ class dcsr_csr_t: public csr_t {
bool ebreaks;
bool ebreaku;
bool halt;
+ bool v;
uint8_t cause;
};
diff --git a/riscv/insns/dret.h b/riscv/insns/dret.h
index 56ce25b..2abcc7d 100644
--- a/riscv/insns/dret.h
+++ b/riscv/insns/dret.h
@@ -1,6 +1,6 @@
require(STATE.debug_mode);
set_pc_and_serialize(STATE.dpc->read());
-p->set_privilege(STATE.dcsr->prv);
+p->set_privilege(STATE.dcsr->prv, STATE.dcsr->v);
if (STATE.prv < PRV_M)
STATE.mstatus->write(STATE.mstatus->read() & ~MSTATUS_MPRV);
diff --git a/riscv/insns/mnret.h b/riscv/insns/mnret.h
index bc69510..30f1081 100644
--- a/riscv/insns/mnret.h
+++ b/riscv/insns/mnret.h
@@ -11,5 +11,4 @@ if (prev_prv != PRV_M) {
}
s = set_field(s, MNSTATUS_NMIE, 1);
STATE.mnstatus->write(s);
-p->set_privilege(prev_prv);
-p->set_virt(prev_virt);
+p->set_privilege(prev_prv, prev_virt);
diff --git a/riscv/insns/mret.h b/riscv/insns/mret.h
index 5198b8f..f5f86a2 100644
--- a/riscv/insns/mret.h
+++ b/riscv/insns/mret.h
@@ -10,5 +10,4 @@ s = set_field(s, MSTATUS_MPIE, 1);
s = set_field(s, MSTATUS_MPP, p->extension_enabled('U') ? PRV_U : PRV_M);
s = set_field(s, MSTATUS_MPV, 0);
p->put_csr(CSR_MSTATUS, s);
-p->set_privilege(prev_prv);
-p->set_virt(prev_virt);
+p->set_privilege(prev_prv, prev_virt);
diff --git a/riscv/insns/sret.h b/riscv/insns/sret.h
index 5102c15..4c7305d 100644
--- a/riscv/insns/sret.h
+++ b/riscv/insns/sret.h
@@ -14,14 +14,14 @@ s = set_field(s, MSTATUS_SIE, get_field(s, MSTATUS_SPIE));
s = set_field(s, MSTATUS_SPIE, 1);
s = set_field(s, MSTATUS_SPP, PRV_U);
STATE.sstatus->write(s);
-p->set_privilege(prev_prv);
+bool prev_virt = STATE.v;
if (!STATE.v) {
if (p->extension_enabled('H')) {
- reg_t prev_virt = get_field(prev_hstatus, HSTATUS_SPV);
- p->set_virt(prev_virt);
+ prev_virt = get_field(prev_hstatus, HSTATUS_SPV);
reg_t new_hstatus = set_field(prev_hstatus, HSTATUS_SPV, 0);
STATE.hstatus->write(new_hstatus);
}
STATE.mstatus->write(set_field(STATE.mstatus->read(), MSTATUS_MPRV, 0));
}
+p->set_privilege(prev_prv, prev_virt);
diff --git a/riscv/processor.cc b/riscv/processor.cc
index 23284b8..ef985a1 100644
--- a/riscv/processor.cc
+++ b/riscv/processor.cc
@@ -327,10 +327,10 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
mcounteren = std::make_shared<masked_csr_t>(proc, CSR_MCOUNTEREN, counteren_mask, 0);
if (proc->extension_enabled_const('U')) csrmap[CSR_MCOUNTEREN] = mcounteren;
csrmap[CSR_SCOUNTEREN] = scounteren = std::make_shared<masked_csr_t>(proc, CSR_SCOUNTEREN, counteren_mask, 0);
- auto nonvirtual_sepc = std::make_shared<epc_csr_t>(proc, CSR_SEPC);
+ nonvirtual_sepc = std::make_shared<epc_csr_t>(proc, CSR_SEPC);
csrmap[CSR_VSEPC] = vsepc = std::make_shared<epc_csr_t>(proc, CSR_VSEPC);
csrmap[CSR_SEPC] = sepc = std::make_shared<virtualized_csr_t>(proc, nonvirtual_sepc, vsepc);
- auto nonvirtual_stval = std::make_shared<basic_csr_t>(proc, CSR_STVAL, 0);
+ nonvirtual_stval = std::make_shared<basic_csr_t>(proc, CSR_STVAL, 0);
csrmap[CSR_VSTVAL] = vstval = std::make_shared<basic_csr_t>(proc, CSR_VSTVAL, 0);
csrmap[CSR_STVAL] = stval = std::make_shared<virtualized_csr_t>(proc, nonvirtual_stval, vstval);
auto sscratch = std::make_shared<basic_csr_t>(proc, CSR_SSCRATCH, 0);
@@ -338,13 +338,13 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
// Note: if max_isa does not include H, we don't really need this virtualized_csr_t at all (though it doesn't hurt):
csrmap[CSR_SSCRATCH] = std::make_shared<virtualized_csr_t>(proc, sscratch, vsscratch);
csrmap[CSR_VSSCRATCH] = vsscratch;
- auto nonvirtual_stvec = std::make_shared<tvec_csr_t>(proc, CSR_STVEC);
+ nonvirtual_stvec = std::make_shared<tvec_csr_t>(proc, CSR_STVEC);
csrmap[CSR_VSTVEC] = vstvec = std::make_shared<tvec_csr_t>(proc, CSR_VSTVEC);
csrmap[CSR_STVEC] = stvec = std::make_shared<virtualized_csr_t>(proc, nonvirtual_stvec, vstvec);
auto nonvirtual_satp = std::make_shared<satp_csr_t>(proc, CSR_SATP);
csrmap[CSR_VSATP] = vsatp = std::make_shared<base_atp_csr_t>(proc, CSR_VSATP);
csrmap[CSR_SATP] = satp = std::make_shared<virtualized_satp_csr_t>(proc, nonvirtual_satp, vsatp);
- auto nonvirtual_scause = std::make_shared<cause_csr_t>(proc, CSR_SCAUSE);
+ nonvirtual_scause = std::make_shared<cause_csr_t>(proc, CSR_SCAUSE);
csrmap[CSR_VSCAUSE] = vscause = std::make_shared<cause_csr_t>(proc, CSR_VSCAUSE);
csrmap[CSR_SCAUSE] = scause = std::make_shared<virtualized_csr_t>(proc, nonvirtual_scause, vscause);
csrmap[CSR_MTVAL2] = mtval2 = std::make_shared<hypervisor_csr_t>(proc, CSR_MTVAL2);
@@ -382,7 +382,7 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
csrmap[CSR_HTVAL] = htval = std::make_shared<basic_csr_t>(proc, CSR_HTVAL, 0);
csrmap[CSR_HTINST] = htinst = std::make_shared<basic_csr_t>(proc, CSR_HTINST, 0);
csrmap[CSR_HGATP] = hgatp = std::make_shared<hgatp_csr_t>(proc, CSR_HGATP);
- auto nonvirtual_sstatus = std::make_shared<sstatus_proxy_csr_t>(proc, CSR_SSTATUS, mstatus);
+ nonvirtual_sstatus = std::make_shared<sstatus_proxy_csr_t>(proc, CSR_SSTATUS, mstatus);
csrmap[CSR_VSSTATUS] = vsstatus = std::make_shared<vsstatus_csr_t>(proc, CSR_VSSTATUS);
csrmap[CSR_SSTATUS] = sstatus = std::make_shared<sstatus_csr_t>(proc, nonvirtual_sstatus, vsstatus);
@@ -714,11 +714,13 @@ reg_t processor_t::legalize_privilege(reg_t prv)
return prv;
}
-void processor_t::set_privilege(reg_t prv)
+void processor_t::set_privilege(reg_t prv, bool virt)
{
mmu->flush_tlb();
state.prev_prv = state.prv;
+ state.prev_v = state.v;
state.prv = legalize_privilege(prv);
+ state.v = virt && state.prv != PRV_M;
}
const char* processor_t::get_privilege_string()
@@ -741,30 +743,11 @@ const char* processor_t::get_privilege_string()
abort();
}
-void processor_t::set_virt(bool virt)
-{
- reg_t tmp, mask;
-
- if (state.prv == PRV_M)
- return;
-
- /*
- * Ideally, we should flush TLB here but we don't need it because
- * set_virt() is always used in conjucter with set_privilege() and
- * set_privilege() will flush TLB unconditionally.
- *
- * The virtualized sstatus register also relies on this TLB flush,
- * since changing V might change sstatus.MXR and sstatus.SUM.
- */
- state.prev_v = state.v;
- state.v = virt;
-}
-
void processor_t::enter_debug_mode(uint8_t cause)
{
state.debug_mode = true;
- state.dcsr->write_cause_and_prv(cause, state.prv);
- set_privilege(PRV_M);
+ state.dcsr->write_cause_and_prv(cause, state.prv, state.v);
+ set_privilege(PRV_M, false);
state.dpc->write(state.pc);
state.pc = DEBUG_ROM_ENTRY;
in_wfi = false;
@@ -831,23 +814,22 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
s = set_field(s, MSTATUS_SPP, state.prv);
s = set_field(s, MSTATUS_SIE, 0);
state.sstatus->write(s);
- set_privilege(PRV_S);
+ set_privilege(PRV_S, true);
} else if (state.prv <= PRV_S && bit < max_xlen && ((hsdeleg >> bit) & 1)) {
// Handle the trap in HS-mode
- set_virt(false);
- reg_t vector = (state.stvec->read() & 1) && interrupt ? 4 * bit : 0;
- state.pc = (state.stvec->read() & ~(reg_t)1) + vector;
- state.scause->write(t.cause());
- state.sepc->write(epc);
- state.stval->write(t.get_tval());
+ reg_t vector = (state.nonvirtual_stvec->read() & 1) && interrupt ? 4 * bit : 0;
+ state.pc = (state.nonvirtual_stvec->read() & ~(reg_t)1) + vector;
+ state.nonvirtual_scause->write(t.cause());
+ state.nonvirtual_sepc->write(epc);
+ state.nonvirtual_stval->write(t.get_tval());
state.htval->write(t.get_tval2());
state.htinst->write(t.get_tinst());
- reg_t s = state.sstatus->read();
+ reg_t s = state.nonvirtual_sstatus->read();
s = set_field(s, MSTATUS_SPIE, get_field(s, MSTATUS_SIE));
s = set_field(s, MSTATUS_SPP, state.prv);
s = set_field(s, MSTATUS_SIE, 0);
- state.sstatus->write(s);
+ state.nonvirtual_sstatus->write(s);
if (extension_enabled('H')) {
s = state.hstatus->read();
if (curr_virt)
@@ -856,10 +838,9 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
s = set_field(s, HSTATUS_GVA, t.has_gva());
state.hstatus->write(s);
}
- set_privilege(PRV_S);
+ set_privilege(PRV_S, false);
} else {
// Handle the trap in M-mode
- set_virt(false);
const reg_t vector = (state.mtvec->read() & 1) && interrupt ? 4 * bit : 0;
const reg_t trap_handler_address = (state.mtvec->read() & ~(reg_t)1) + vector;
// RNMI exception vector is implementation-defined. Since we don't model
@@ -881,7 +862,7 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
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);
+ set_privilege(PRV_M, false);
}
}
diff --git a/riscv/processor.h b/riscv/processor.h
index 34354c2..1b00808 100644
--- a/riscv/processor.h
+++ b/riscv/processor.h
@@ -110,6 +110,13 @@ struct state_t
virtualized_csr_t_p satp;
csr_t_p scause;
+ // When taking a trap into HS-mode, we must access the nonvirtualized HS-mode CSRs directly:
+ csr_t_p nonvirtual_stvec;
+ csr_t_p nonvirtual_scause;
+ csr_t_p nonvirtual_sepc;
+ csr_t_p nonvirtual_stval;
+ sstatus_proxy_csr_t_p nonvirtual_sstatus;
+
csr_t_p mtval2;
csr_t_p mtinst;
csr_t_p hstatus;
@@ -262,8 +269,7 @@ public:
throw trap_instruction_address_misaligned(state.v, pc, 0, 0);
}
reg_t legalize_privilege(reg_t);
- void set_privilege(reg_t);
- void set_virt(bool);
+ void set_privilege(reg_t, bool);
const char* get_privilege_string();
void update_histogram(reg_t pc);
const disassembler_t* get_disassembler() { return disassembler; }