aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAtul Khare <atulkhare@rivosinc.com>2023-06-14 16:49:40 -0700
committerAtul Khare <atulkhare@rivosinc.com>2023-07-26 09:10:31 -0700
commitc927773dd1584d870dd60a1cf86c0a8f0d138dd4 (patch)
treeb5398b210a0437b256f9cf69b80ef7280fe2c302
parent62178539f8377805705fd6d857338c04b52ef60f (diff)
downloadriscv-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.cc2
-rw-r--r--riscv/csrs.cc47
-rw-r--r--riscv/csrs.h22
-rw-r--r--riscv/isa_parser.h1
-rw-r--r--riscv/processor.cc23
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();