Browse Source

Add Smcntrpmf functionality

If Smcntrpmf is enabled, mcycle / minstret increment only if counting
for the privilege level isn't inhibited in mcyclecfg / minstretcfg.
pull/1381/head
Atul Khare 3 years ago
parent
commit
c927773dd1
  1. 2
      disasm/isa_parser.cc
  2. 43
      riscv/csrs.cc
  3. 22
      riscv/csrs.h
  4. 1
      riscv/isa_parser.h
  5. 23
      riscv/processor.cc

2
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) {

43
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,8 +1010,12 @@ reg_t wide_counter_csr_t::read() const noexcept {
}
void wide_counter_csr_t::bump(const reg_t howmuch) noexcept {
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 {
this->val = val;
@ -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.
// 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);
}

22
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

1
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;

23
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();

Loading…
Cancel
Save