diff options
author | Atul Khare <atulkhare@rivosinc.com> | 2023-06-14 16:49:40 -0700 |
---|---|---|
committer | Atul Khare <atulkhare@rivosinc.com> | 2023-07-26 09:10:31 -0700 |
commit | c927773dd1584d870dd60a1cf86c0a8f0d138dd4 (patch) | |
tree | b5398b210a0437b256f9cf69b80ef7280fe2c302 | |
parent | 62178539f8377805705fd6d857338c04b52ef60f (diff) | |
download | riscv-isa-sim-c927773dd1584d870dd60a1cf86c0a8f0d138dd4.zip riscv-isa-sim-c927773dd1584d870dd60a1cf86c0a8f0d138dd4.tar.gz riscv-isa-sim-c927773dd1584d870dd60a1cf86c0a8f0d138dd4.tar.bz2 |
Add Smcntrpmf functionality
If Smcntrpmf is enabled, mcycle / minstret increment only if counting
for the privilege level isn't inhibited in mcyclecfg / minstretcfg.
-rw-r--r-- | disasm/isa_parser.cc | 2 | ||||
-rw-r--r-- | riscv/csrs.cc | 47 | ||||
-rw-r--r-- | riscv/csrs.h | 22 | ||||
-rw-r--r-- | riscv/isa_parser.h | 1 | ||||
-rw-r--r-- | riscv/processor.cc | 23 |
5 files changed, 88 insertions, 7 deletions
diff --git a/disasm/isa_parser.cc b/disasm/isa_parser.cc index f4d9da4..d5dc439 100644 --- a/disasm/isa_parser.cc +++ b/disasm/isa_parser.cc @@ -290,6 +290,8 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) extension_table[EXT_SMCSRIND] = true; } else if (ext_str == "sscsrind") { extension_table[EXT_SSCSRIND] = true; + } else if (ext_str == "smcntrpmf") { + extension_table[EXT_SMCNTRPMF] = true; } else if (ext_str[0] == 'x') { extension_table['X'] = true; if (ext_str.size() == 1) { diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 9849ea2..e3b5ad4 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -999,9 +999,10 @@ bool virtualized_satp_csr_t::unlogged_write(const reg_t val) noexcept { } // implement class wide_counter_csr_t -wide_counter_csr_t::wide_counter_csr_t(processor_t* const proc, const reg_t addr): +wide_counter_csr_t::wide_counter_csr_t(processor_t* const proc, const reg_t addr, smcntrpmf_csr_t_p config_csr): csr_t(proc, addr), - val(0) { + val(0), + config_csr(config_csr) { } reg_t wide_counter_csr_t::read() const noexcept { @@ -1009,7 +1010,11 @@ reg_t wide_counter_csr_t::read() const noexcept { } void wide_counter_csr_t::bump(const reg_t howmuch) noexcept { - val += howmuch; // to keep log reasonable size, don't log every bump + if (is_counting_enabled()) { + val += howmuch; // to keep log reasonable size, don't log every bump + } + // Clear cached value + config_csr->reset_prev(); } bool wide_counter_csr_t::unlogged_write(const reg_t val) noexcept { @@ -1018,7 +1023,10 @@ bool wide_counter_csr_t::unlogged_write(const reg_t val) noexcept { // takes precedence over the increment to instret. However, Spike // unconditionally increments instret after executing an instruction. // Correct for this artifact by decrementing instret here. - this->val--; + // Ensure that Smctrpmf hasn't disabled counting. + if (is_counting_enabled()) { + this->val--; + } return true; } @@ -1027,6 +1035,20 @@ reg_t wide_counter_csr_t::written_value() const noexcept { return this->val + 1; } +// Returns true if counting is not inhibited by Smcntrpmf. +// Note that minstretcfg / mcyclecfg / mhpmevent* share the same inhibit bits. +bool wide_counter_csr_t::is_counting_enabled() const noexcept { + auto prv = state->prv_changed ? state->prev_prv : state->prv; + auto v = state->v_changed ? state->v : state->prev_v; + auto mask = MHPMEVENT_MINH; + if (prv == PRV_S) { + mask = v ? MHPMEVENT_VSINH : MHPMEVENT_SINH; + } else if (prv == PRV_U) { + mask = v ? MHPMEVENT_VUINH : MHPMEVENT_UINH; + } + return (config_csr->read_prev() & mask) == 0; +} + // implement class time_counter_csr_t time_counter_csr_t::time_counter_csr_t(processor_t* const proc, const reg_t addr): csr_t(proc, addr), @@ -1649,3 +1671,20 @@ csr_t_p sscsrind_reg_csr_t::get_reg() const noexcept { void sscsrind_reg_csr_t::add_ireg_proxy(const reg_t iselect_value, csr_t_p csr) { ireg_proxy[iselect_value] = csr; } + +smcntrpmf_csr_t::smcntrpmf_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init) : masked_csr_t(proc, addr, mask, init) { +} + +reg_t smcntrpmf_csr_t::read_prev() const noexcept { + reg_t val = prev_val.value_or(read()); + return val; +} + +void smcntrpmf_csr_t::reset_prev() noexcept { + prev_val.reset(); +} + +bool smcntrpmf_csr_t::unlogged_write(const reg_t val) noexcept { + prev_val = read(); + return masked_csr_t::unlogged_write(val); +} diff --git a/riscv/csrs.h b/riscv/csrs.h index cf48673..5ca7e15 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -15,6 +15,8 @@ // For access_type: #include "memtracer.h" #include <cassert> +// For std::optional +#include <optional> class processor_t; struct state_t; @@ -516,12 +518,16 @@ class virtualized_satp_csr_t: public virtualized_csr_t { satp_csr_t_p orig_satp; }; +// Forward declaration +class smcntrpmf_csr_t; +typedef std::shared_ptr<smcntrpmf_csr_t> smcntrpmf_csr_t_p; + // For minstret and mcycle, which are always 64 bits, but in RV32 are // split into high and low halves. The first class always holds the // full 64-bit value. class wide_counter_csr_t: public csr_t { public: - wide_counter_csr_t(processor_t* const proc, const reg_t addr); + wide_counter_csr_t(processor_t* const proc, const reg_t addr, smcntrpmf_csr_t_p config_csr); // Always returns full 64-bit value virtual reg_t read() const noexcept override; void bump(const reg_t howmuch) noexcept; @@ -529,7 +535,9 @@ class wide_counter_csr_t: public csr_t { virtual bool unlogged_write(const reg_t val) noexcept override; virtual reg_t written_value() const noexcept override; private: + bool is_counting_enabled() const noexcept; reg_t val; + smcntrpmf_csr_t_p config_csr; }; typedef std::shared_ptr<wide_counter_csr_t> wide_counter_csr_t_p; @@ -822,4 +830,16 @@ class sscsrind_reg_csr_t : public csr_t { csr_t_p get_reg() const noexcept; }; +// smcntrpmf_csr_t caches the previous state of the CSR in case a CSRW instruction +// modifies the state that should not be immediately visible to bump() +class smcntrpmf_csr_t : public masked_csr_t { + public: + smcntrpmf_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init); + reg_t read_prev() const noexcept; + void reset_prev() noexcept; + protected: + virtual bool unlogged_write(const reg_t val) noexcept override; + private: + std::optional<reg_t> prev_val; +}; #endif diff --git a/riscv/isa_parser.h b/riscv/isa_parser.h index bba5a91..f955e16 100644 --- a/riscv/isa_parser.h +++ b/riscv/isa_parser.h @@ -79,6 +79,7 @@ typedef enum { EXT_INTERNAL_ZFH_MOVE, EXT_SMCSRIND, EXT_SSCSRIND, + EXT_SMCNTRPMF, NUM_ISA_EXTENSIONS } isa_extension_t; diff --git a/riscv/processor.cc b/riscv/processor.cc index 3126433..0704d8c 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -219,8 +219,15 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) csrmap[CSR_MSCRATCH] = std::make_shared<basic_csr_t>(proc, CSR_MSCRATCH, 0); csrmap[CSR_MTVEC] = mtvec = std::make_shared<tvec_csr_t>(proc, CSR_MTVEC); csrmap[CSR_MCAUSE] = mcause = std::make_shared<cause_csr_t>(proc, CSR_MCAUSE); - minstret = std::make_shared<wide_counter_csr_t>(proc, CSR_MINSTRET); - mcycle = std::make_shared<wide_counter_csr_t>(proc, CSR_MCYCLE); + + auto smcntrpmf_enabled = proc->extension_enabled_const(EXT_SMCNTRPMF); + const reg_t mask = smcntrpmf_enabled ? MHPMEVENT_MINH | MHPMEVENT_SINH | + MHPMEVENT_UINH | MHPMEVENT_VSINH | MHPMEVENT_VUINH : 0; + auto minstretcfg = std::make_shared<smcntrpmf_csr_t>(proc, CSR_MINSTRETCFG, mask, 0); + auto mcyclecfg = std::make_shared<smcntrpmf_csr_t>(proc, CSR_MCYCLECFG, mask, 0); + + minstret = std::make_shared<wide_counter_csr_t>(proc, CSR_MINSTRET, minstretcfg); + mcycle = std::make_shared<wide_counter_csr_t>(proc, CSR_MCYCLE, mcyclecfg); time = std::make_shared<time_counter_csr_t>(proc, CSR_TIME); if (proc->extension_enabled_const(EXT_ZICNTR)) { csrmap[CSR_INSTRET] = std::make_shared<counter_proxy_csr_t>(proc, CSR_INSTRET, minstret); @@ -566,6 +573,18 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) } } + if (smcntrpmf_enabled) { + if (xlen == 32) { + csrmap[CSR_MCYCLECFG] = std::make_shared<rv32_low_csr_t>(proc, CSR_MCYCLECFG, mcyclecfg); + csrmap[CSR_MCYCLECFGH] = std::make_shared<rv32_high_csr_t>(proc, CSR_MCYCLECFGH, mcyclecfg); + csrmap[CSR_MINSTRETCFG] = std::make_shared<rv32_low_csr_t>(proc, CSR_MINSTRETCFG, minstretcfg); + csrmap[CSR_MINSTRETCFGH] = std::make_shared<rv32_high_csr_t>(proc, CSR_MINSTRETCFGH, minstretcfg); + } else { + csrmap[CSR_MCYCLECFG] = mcyclecfg; + csrmap[CSR_MINSTRETCFG] = minstretcfg; + } + } + serialized = false; log_reg_write.clear(); |