diff options
author | Andrew Waterman <andrew@sifive.com> | 2023-07-26 12:45:44 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-26 12:45:44 -0700 |
commit | c59e80e980e46b1425016d6a31d7f21c8d9ebfa2 (patch) | |
tree | b5398b210a0437b256f9cf69b80ef7280fe2c302 | |
parent | 60c08b1ea5e3d96a97c235db87d472a7cfb2611b (diff) | |
parent | c927773dd1584d870dd60a1cf86c0a8f0d138dd4 (diff) | |
download | riscv-isa-sim-c59e80e980e46b1425016d6a31d7f21c8d9ebfa2.zip riscv-isa-sim-c59e80e980e46b1425016d6a31d7f21c8d9ebfa2.tar.gz riscv-isa-sim-c59e80e980e46b1425016d6a31d7f21c8d9ebfa2.tar.bz2 |
Merge pull request #1381 from rivosinc/smcntrpmf_feature
Add Smcntrpmf support
-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/encoding.h | 57 | ||||
-rw-r--r-- | riscv/execute.cc | 2 | ||||
-rw-r--r-- | riscv/isa_parser.h | 1 | ||||
-rw-r--r-- | riscv/processor.cc | 27 | ||||
-rw-r--r-- | riscv/processor.h | 2 |
8 files changed, 136 insertions, 24 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/encoding.h b/riscv/encoding.h index 9666774..f1defd4 100644 --- a/riscv/encoding.h +++ b/riscv/encoding.h @@ -4,7 +4,7 @@ /* * This file is auto-generated by running 'make' in - * https://github.com/riscv/riscv-opcodes (be53d24) + * https://github.com/riscv/riscv-opcodes (6790b30) */ #ifndef RISCV_CSR_ENCODING_H @@ -172,6 +172,7 @@ #define MSTATEEN0_FCSR 0x00000002 #define MSTATEEN0_JVT 0x00000004 #define MSTATEEN0_HCONTEXT 0x0200000000000000 +#define MSTATEEN0_CD 0x0100000000000000 #define MSTATEEN0_HENVCFG 0x4000000000000000 #define MSTATEEN_HSTATEEN 0x8000000000000000 @@ -205,6 +206,18 @@ #define HENVCFGH_PBMTE 0x40000000 #define HENVCFGH_STCE 0x80000000 +#define SISELECT_SMCDELEG_START 0x40 +#define SISELECT_SMCDELEG_UNUSED 0x41 +#define SISELECT_SMCDELEG_INSTRET 0x42 +#define SISELECT_SMCDELEG_INSTRETCFG 0x42 +/* + * ?iselect values for hpmcounters4..31 and hpmevent4..31 + * can easily computed, and were elided for brevity. + */ +#define SISELECT_SMCDELEG_HPMCOUNTER_3 0x43 +#define SISELECT_SMCDELEG_HPMEVENT_3 0x43 +#define SISELECT_SMCDELEG_END 0x5f + #define HSTATEEN0_CS 0x00000001 #define HSTATEEN0_FCSR 0x00000002 #define HSTATEEN0_JVT 0x00000004 @@ -2477,10 +2490,10 @@ #define MASK_VMADD_VV 0xfc00707f #define MATCH_VMADD_VX 0xa4006057 #define MASK_VMADD_VX 0xfc00707f -#define MATCH_VMAND_MM 0x64002057 -#define MASK_VMAND_MM 0xfc00707f -#define MATCH_VMANDN_MM 0x60002057 -#define MASK_VMANDN_MM 0xfc00707f +#define MATCH_VMAND_MM 0x66002057 +#define MASK_VMAND_MM 0xfe00707f +#define MATCH_VMANDN_MM 0x62002057 +#define MASK_VMANDN_MM 0xfe00707f #define MATCH_VMAX_VV 0x1c000057 #define MASK_VMAX_VV 0xfc00707f #define MATCH_VMAX_VX 0x1c004057 @@ -2523,14 +2536,14 @@ #define MASK_VMINU_VV 0xfc00707f #define MATCH_VMINU_VX 0x10004057 #define MASK_VMINU_VX 0xfc00707f -#define MATCH_VMNAND_MM 0x74002057 -#define MASK_VMNAND_MM 0xfc00707f -#define MATCH_VMNOR_MM 0x78002057 -#define MASK_VMNOR_MM 0xfc00707f -#define MATCH_VMOR_MM 0x68002057 -#define MASK_VMOR_MM 0xfc00707f -#define MATCH_VMORN_MM 0x70002057 -#define MASK_VMORN_MM 0xfc00707f +#define MATCH_VMNAND_MM 0x76002057 +#define MASK_VMNAND_MM 0xfe00707f +#define MATCH_VMNOR_MM 0x7a002057 +#define MASK_VMNOR_MM 0xfe00707f +#define MATCH_VMOR_MM 0x6a002057 +#define MASK_VMOR_MM 0xfe00707f +#define MATCH_VMORN_MM 0x72002057 +#define MASK_VMORN_MM 0xfe00707f #define MATCH_VMSBC_VV 0x4e000057 #define MASK_VMSBC_VV 0xfe00707f #define MATCH_VMSBC_VVM 0x4c000057 @@ -2619,10 +2632,10 @@ #define MASK_VMV_V_X 0xfff0707f #define MATCH_VMV_X_S 0x42002057 #define MASK_VMV_X_S 0xfe0ff07f -#define MATCH_VMXNOR_MM 0x7c002057 -#define MASK_VMXNOR_MM 0xfc00707f -#define MATCH_VMXOR_MM 0x6c002057 -#define MASK_VMXOR_MM 0xfc00707f +#define MATCH_VMXNOR_MM 0x7e002057 +#define MASK_VMXNOR_MM 0xfe00707f +#define MATCH_VMXOR_MM 0x6e002057 +#define MASK_VMXOR_MM 0xfe00707f #define MATCH_VNCLIP_WI 0xbc003057 #define MASK_VNCLIP_WI 0xfc00707f #define MATCH_VNCLIP_WV 0xbc000057 @@ -3051,6 +3064,7 @@ #define CSR_SSTATEEN1 0x10d #define CSR_SSTATEEN2 0x10e #define CSR_SSTATEEN3 0x10f +#define CSR_SCOUNTINHIBIT 0x120 #define CSR_SSCRATCH 0x140 #define CSR_SEPC 0x141 #define CSR_SCAUSE 0x142 @@ -3280,6 +3294,8 @@ #define CSR_MHPMCOUNTER29 0xb1d #define CSR_MHPMCOUNTER30 0xb1e #define CSR_MHPMCOUNTER31 0xb1f +#define CSR_MCYCLECFG 0x321 +#define CSR_MINSTRETCFG 0x322 #define CSR_MHPMEVENT3 0x323 #define CSR_MHPMEVENT4 0x324 #define CSR_MHPMEVENT5 0x325 @@ -3375,6 +3391,8 @@ #define CSR_MSTATEEN2H 0x31e #define CSR_MSTATEEN3H 0x31f #define CSR_MIPH 0x354 +#define CSR_MCYCLECFGH 0x721 +#define CSR_MINSTRETCFGH 0x722 #define CSR_MHPMEVENT3H 0x723 #define CSR_MHPMEVENT4H 0x724 #define CSR_MHPMEVENT5H 0x725 @@ -4933,6 +4951,7 @@ DECLARE_CSR(sstateen0, CSR_SSTATEEN0) DECLARE_CSR(sstateen1, CSR_SSTATEEN1) DECLARE_CSR(sstateen2, CSR_SSTATEEN2) DECLARE_CSR(sstateen3, CSR_SSTATEEN3) +DECLARE_CSR(scountinhibit, CSR_SCOUNTINHIBIT) DECLARE_CSR(sscratch, CSR_SSCRATCH) DECLARE_CSR(sepc, CSR_SEPC) DECLARE_CSR(scause, CSR_SCAUSE) @@ -5162,6 +5181,8 @@ DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28) DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29) DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30) DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31) +DECLARE_CSR(mcyclecfg, CSR_MCYCLECFG) +DECLARE_CSR(minstretcfg, CSR_MINSTRETCFG) DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3) DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4) DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5) @@ -5257,6 +5278,8 @@ DECLARE_CSR(mstateen1h, CSR_MSTATEEN1H) DECLARE_CSR(mstateen2h, CSR_MSTATEEN2H) DECLARE_CSR(mstateen3h, CSR_MSTATEEN3H) DECLARE_CSR(miph, CSR_MIPH) +DECLARE_CSR(mcyclecfgh, CSR_MCYCLECFGH) +DECLARE_CSR(minstretcfgh, CSR_MINSTRETCFGH) DECLARE_CSR(mhpmevent3h, CSR_MHPMEVENT3H) DECLARE_CSR(mhpmevent4h, CSR_MHPMEVENT4H) DECLARE_CSR(mhpmevent5h, CSR_MHPMEVENT5H) diff --git a/riscv/execute.cc b/riscv/execute.cc index 591090b..4f5860b 100644 --- a/riscv/execute.cc +++ b/riscv/execute.cc @@ -226,6 +226,8 @@ void processor_t::step(size_t n) size_t instret = 0; reg_t pc = state.pc; mmu_t* _mmu = mmu; + state.prv_changed = false; + state.v_changed = false; #define advance_pc() \ if (unlikely(invalid_pc(pc))) { \ 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 ff64f5a..0704d8c 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -203,6 +203,8 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) prv = prev_prv = PRV_M; v = prev_v = false; + prv_changed = false; + v_changed = false; csrmap[CSR_MISA] = misa = std::make_shared<misa_csr_t>(proc, CSR_MISA, max_isa); mstatus = std::make_shared<mstatus_csr_t>(proc, CSR_MSTATUS); @@ -217,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); @@ -564,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(); @@ -766,6 +787,8 @@ void processor_t::set_privilege(reg_t prv, bool virt) state.prev_v = state.v; state.prv = legalize_privilege(prv); state.v = virt && state.prv != PRV_M; + state.prv_changed = state.prv != state.prev_prv; + state.v_changed = state.v != state.prev_v; } const char* processor_t::get_privilege_string() diff --git a/riscv/processor.h b/riscv/processor.h index 1b00808..a2e4286 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -84,6 +84,8 @@ struct state_t std::unordered_map<reg_t, csr_t_p> csrmap; reg_t prv; // TODO: Can this be an enum instead? reg_t prev_prv; + bool prv_changed; + bool v_changed; bool v; bool prev_v; misa_csr_t_p misa; |