aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authori2h2 <110197402+i2h2@users.noreply.github.com>2022-08-03 16:01:57 -0600
committerGitHub <noreply@github.com>2022-08-03 15:01:57 -0700
commit5672c4a41ad7a9af011d385962c175a5a6012fd9 (patch)
tree2b2268331e4bb8011f3578492d846568113ca990
parent14cb6b2a6244e3a1511c4c169676a6e2bd6785ed (diff)
downloadriscv-isa-sim-5672c4a41ad7a9af011d385962c175a5a6012fd9.zip
riscv-isa-sim-5672c4a41ad7a9af011d385962c175a5a6012fd9.tar.gz
riscv-isa-sim-5672c4a41ad7a9af011d385962c175a5a6012fd9.tar.bz2
Add Sstc support. (#1057)
-rw-r--r--riscv/csrs.cc37
-rw-r--r--riscv/csrs.h17
-rw-r--r--riscv/isa_parser.cc2
-rw-r--r--riscv/isa_parser.h1
-rw-r--r--riscv/processor.cc23
-rw-r--r--riscv/processor.h4
6 files changed, 79 insertions, 5 deletions
diff --git a/riscv/csrs.cc b/riscv/csrs.cc
index d02212b..50cbfb3 100644
--- a/riscv/csrs.cc
+++ b/riscv/csrs.cc
@@ -679,7 +679,8 @@ void mip_csr_t::backdoor_write_with_mask(const reg_t mask, const reg_t val) noex
}
reg_t mip_csr_t::write_mask() const noexcept {
- const reg_t supervisor_ints = proc->extension_enabled('S') ? MIP_SSIP | MIP_STIP | MIP_SEIP : 0;
+ // MIP_STIP is writable unless SSTC exists and STCE is set in MENVCFG
+ const reg_t supervisor_ints = proc->extension_enabled('S') ? MIP_SSIP | ((state->menvcfg->read() & MENVCFG_STCE) ? 0 : 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
@@ -979,6 +980,11 @@ reg_t time_counter_csr_t::read() const noexcept {
void time_counter_csr_t::sync(const reg_t val) noexcept {
shadow_val = val;
+ if (proc->extension_enabled(EXT_SSTC)) {
+ const reg_t mip_val = (shadow_val >= state->stimecmp->read() ? MIP_STIP : 0) |
+ (shadow_val + state->htimedelta->read() >= state->vstimecmp->read() ? MIP_VSTIP : 0);
+ state->mip->backdoor_write_with_mask(MIP_STIP | MIP_VSTIP, mip_val);
+ }
}
proxy_csr_t::proxy_csr_t(processor_t* const proc, const reg_t addr, csr_t_p delegate):
@@ -1400,3 +1406,32 @@ void henvcfg_csr_t::verify_permissions(insn_t insn, bool write) const {
throw trap_illegal_instruction(insn.bits());
}
}
+
+stimecmp_csr_t::stimecmp_csr_t(processor_t* const proc, const reg_t addr, const reg_t imask):
+ basic_csr_t(proc, addr, 0), intr_mask(imask) {
+}
+
+bool stimecmp_csr_t::unlogged_write(const reg_t val) noexcept {
+ state->mip->backdoor_write_with_mask(intr_mask, state->time->read() >= val ? intr_mask : 0);
+ return basic_csr_t::unlogged_write(val);
+}
+
+virtualized_stimecmp_csr_t::virtualized_stimecmp_csr_t(processor_t* const proc, csr_t_p orig, csr_t_p virt):
+ virtualized_csr_t(proc, orig, virt) {
+}
+
+void virtualized_stimecmp_csr_t::verify_permissions(insn_t insn, bool write) const {
+ virtualized_csr_t::verify_permissions(insn, write);
+
+ // check for read permission to time as enabled by xcounteren
+ state->time_proxy->verify_permissions(insn, false);
+
+ if (!(state->menvcfg->read() & MENVCFG_STCE)) {
+ // access to (v)stimecmp with MENVCFG.STCE = 0
+ if (state->prv < PRV_M)
+ throw trap_illegal_instruction(insn.bits());
+ } else if (state->v && !(state->henvcfg->read() & HENVCFG_STCE)) {
+ // access to vstimecmp with MENVCFG.STCE = 1 and HENVCFG.STCE = 0 when V = 1
+ throw trap_virtual_instruction(insn.bits());
+ }
+}
diff --git a/riscv/csrs.h b/riscv/csrs.h
index c979942..acd889c 100644
--- a/riscv/csrs.h
+++ b/riscv/csrs.h
@@ -449,12 +449,13 @@ class masked_csr_t: public basic_csr_t {
};
// henvcfg.pbmte is read_only 0 when menvcfg.pbmte = 0
+// henvcfg.stce is read_only 0 when menvcfg.stce = 0
class henvcfg_csr_t final: public masked_csr_t {
public:
henvcfg_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init, csr_t_p menvcfg);
reg_t read() const noexcept override {
- return (menvcfg->read() | ~MENVCFG_PBMTE) & masked_csr_t::read();
+ return (menvcfg->read() | ~(MENVCFG_PBMTE | MENVCFG_STCE)) & masked_csr_t::read();
}
virtual void verify_permissions(insn_t insn, bool write) const override;
@@ -729,4 +730,18 @@ class senvcfg_csr_t final: public masked_csr_t {
virtual void verify_permissions(insn_t insn, bool write) const override;
};
+class stimecmp_csr_t: public basic_csr_t {
+ public:
+ stimecmp_csr_t(processor_t* const proc, const reg_t addr, const reg_t imask);
+ protected:
+ virtual bool unlogged_write(const reg_t val) noexcept override;
+ private:
+ reg_t intr_mask;
+};
+
+class virtualized_stimecmp_csr_t: public virtualized_csr_t {
+ public:
+ virtualized_stimecmp_csr_t(processor_t* const proc, csr_t_p orig, csr_t_p virt);
+ virtual void verify_permissions(insn_t insn, bool write) const override;
+};
#endif
diff --git a/riscv/isa_parser.cc b/riscv/isa_parser.cc
index 81b770c..6ac146b 100644
--- a/riscv/isa_parser.cc
+++ b/riscv/isa_parser.cc
@@ -181,6 +181,8 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
} else if (ext_str == "zicbop") {
} else if (ext_str == "zicntr") {
} else if (ext_str == "zihpm") {
+ } else if (ext_str == "sstc") {
+ extension_table[EXT_SSTC] = true;
} else if (ext_str[0] == 'x') {
max_isa |= 1L << ('x' - 'a');
extension_table[toupper('x')] = true;
diff --git a/riscv/isa_parser.h b/riscv/isa_parser.h
index 6065dbc..c57436e 100644
--- a/riscv/isa_parser.h
+++ b/riscv/isa_parser.h
@@ -52,6 +52,7 @@ typedef enum {
EXT_XZBM,
EXT_XZBR,
EXT_XZBT,
+ EXT_SSTC,
} isa_extension_t;
typedef enum {
diff --git a/riscv/processor.cc b/riscv/processor.cc
index 6d0d349..0389707 100644
--- a/riscv/processor.cc
+++ b/riscv/processor.cc
@@ -208,7 +208,7 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
if (proc->extension_enabled_const(EXT_ZICNTR)) {
csrmap[CSR_INSTRET] = std::make_shared<counter_proxy_csr_t>(proc, CSR_INSTRET, minstret);
csrmap[CSR_CYCLE] = std::make_shared<counter_proxy_csr_t>(proc, CSR_CYCLE, mcycle);
- csrmap[CSR_TIME] = std::make_shared<counter_proxy_csr_t>(proc, CSR_TIME, time);
+ csrmap[CSR_TIME] = time_proxy = std::make_shared<counter_proxy_csr_t>(proc, CSR_TIME, time);
}
if (xlen == 32) {
csr_t_p minstreth, mcycleh;
@@ -405,7 +405,8 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
if (proc->extension_enabled_const('U')) {
const reg_t menvcfg_mask = (proc->extension_enabled(EXT_ZICBOM) ? MENVCFG_CBCFE | MENVCFG_CBIE : 0) |
(proc->extension_enabled(EXT_ZICBOZ) ? MENVCFG_CBZE : 0) |
- (proc->extension_enabled(EXT_SVPBMT) ? MENVCFG_PBMTE : 0);
+ (proc->extension_enabled(EXT_SVPBMT) ? MENVCFG_PBMTE : 0) |
+ (proc->extension_enabled(EXT_SSTC) ? MENVCFG_STCE : 0);
const reg_t menvcfg_init = (proc->extension_enabled(EXT_SVPBMT) ? MENVCFG_PBMTE : 0);
menvcfg = std::make_shared<masked_csr_t>(proc, CSR_MENVCFG, menvcfg_mask, menvcfg_init);
if (xlen == 32) {
@@ -419,7 +420,8 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
csrmap[CSR_SENVCFG] = senvcfg = std::make_shared<senvcfg_csr_t>(proc, CSR_SENVCFG, senvcfg_mask, 0);
const reg_t henvcfg_mask = (proc->extension_enabled(EXT_ZICBOM) ? HENVCFG_CBCFE | HENVCFG_CBIE : 0) |
(proc->extension_enabled(EXT_ZICBOZ) ? HENVCFG_CBZE : 0) |
- (proc->extension_enabled(EXT_SVPBMT) ? HENVCFG_PBMTE : 0);
+ (proc->extension_enabled(EXT_SVPBMT) ? HENVCFG_PBMTE : 0) |
+ (proc->extension_enabled(EXT_SSTC) ? HENVCFG_STCE : 0);
const reg_t henvcfg_init = (proc->extension_enabled(EXT_SVPBMT) ? HENVCFG_PBMTE : 0);
henvcfg = std::make_shared<henvcfg_csr_t>(proc, CSR_HENVCFG, henvcfg_mask, henvcfg_init, menvcfg);
if (xlen == 32) {
@@ -457,6 +459,21 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
}
}
+ if (proc->extension_enabled_const(EXT_SSTC)) {
+ stimecmp = std::make_shared<stimecmp_csr_t>(proc, CSR_STIMECMP, MIP_STIP);
+ vstimecmp = std::make_shared<stimecmp_csr_t>(proc, CSR_VSTIMECMP, MIP_VSTIP);
+ auto virtualized_stimecmp = std::make_shared<virtualized_stimecmp_csr_t>(proc, stimecmp, vstimecmp);
+ if (xlen == 32) {
+ csrmap[CSR_STIMECMP] = std::make_shared<rv32_low_csr_t>(proc, CSR_STIMECMP, virtualized_stimecmp);
+ csrmap[CSR_STIMECMPH] = std::make_shared<rv32_high_csr_t>(proc, CSR_STIMECMPH, virtualized_stimecmp);
+ csrmap[CSR_VSTIMECMP] = std::make_shared<rv32_low_csr_t>(proc, CSR_VSTIMECMP, vstimecmp);
+ csrmap[CSR_VSTIMECMPH] = std::make_shared<rv32_high_csr_t>(proc, CSR_VSTIMECMPH, vstimecmp);
+ } else {
+ csrmap[CSR_STIMECMP] = virtualized_stimecmp;
+ csrmap[CSR_VSTIMECMP] = vstimecmp;
+ }
+ }
+
serialized = false;
#ifdef RISCV_ENABLE_COMMITLOG
diff --git a/riscv/processor.h b/riscv/processor.h
index b415402..88ddf70 100644
--- a/riscv/processor.h
+++ b/riscv/processor.h
@@ -193,6 +193,10 @@ struct state_t
csr_t_p htimedelta;
time_counter_csr_t_p time;
+ csr_t_p time_proxy;
+
+ csr_t_p stimecmp;
+ csr_t_p vstimecmp;
bool serialized; // whether timer CSRs are in a well-defined state