diff options
author | i2h2 <110197402+i2h2@users.noreply.github.com> | 2022-08-03 16:01:57 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-03 15:01:57 -0700 |
commit | 5672c4a41ad7a9af011d385962c175a5a6012fd9 (patch) | |
tree | 2b2268331e4bb8011f3578492d846568113ca990 | |
parent | 14cb6b2a6244e3a1511c4c169676a6e2bd6785ed (diff) | |
download | spike-5672c4a41ad7a9af011d385962c175a5a6012fd9.zip spike-5672c4a41ad7a9af011d385962c175a5a6012fd9.tar.gz spike-5672c4a41ad7a9af011d385962c175a5a6012fd9.tar.bz2 |
Add Sstc support. (#1057)
-rw-r--r-- | riscv/csrs.cc | 37 | ||||
-rw-r--r-- | riscv/csrs.h | 17 | ||||
-rw-r--r-- | riscv/isa_parser.cc | 2 | ||||
-rw-r--r-- | riscv/isa_parser.h | 1 | ||||
-rw-r--r-- | riscv/processor.cc | 23 | ||||
-rw-r--r-- | riscv/processor.h | 4 |
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 |