From 1c91fd56ba54bf62c67fea94b80726008895a57a Mon Sep 17 00:00:00 2001 From: Atul Khare Date: Mon, 24 Jul 2023 17:56:38 -0700 Subject: [PATCH 1/3] Regenerate encoding.h --- riscv/encoding.h | 57 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/riscv/encoding.h b/riscv/encoding.h index 9666774076..f1defd41b2 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) From 62178539f8377805705fd6d857338c04b52ef60f Mon Sep 17 00:00:00 2001 From: Atul Khare Date: Wed, 14 Jun 2023 16:12:56 -0700 Subject: [PATCH 2/3] Add prv_changed / v_changed fields to state This tracks whether the privilege / virtual mode was changed by the execution of the current instruction. --- riscv/execute.cc | 2 ++ riscv/processor.cc | 4 ++++ riscv/processor.h | 2 ++ 3 files changed, 8 insertions(+) diff --git a/riscv/execute.cc b/riscv/execute.cc index 591090bd96..4f5860ba19 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/processor.cc b/riscv/processor.cc index ff64f5a24a..3126433a34 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(proc, CSR_MISA, max_isa); mstatus = std::make_shared(proc, CSR_MSTATUS); @@ -766,6 +768,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 1b00808977..a2e428651e 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -84,6 +84,8 @@ struct state_t std::unordered_map 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; From c927773dd1584d870dd60a1cf86c0a8f0d138dd4 Mon Sep 17 00:00:00 2001 From: Atul Khare Date: Wed, 14 Jun 2023 16:49:40 -0700 Subject: [PATCH 3/3] Add Smcntrpmf functionality If Smcntrpmf is enabled, mcycle / minstret increment only if counting for the privilege level isn't inhibited in mcyclecfg / minstretcfg. --- disasm/isa_parser.cc | 2 ++ riscv/csrs.cc | 47 ++++++++++++++++++++++++++++++++++++++++---- riscv/csrs.h | 22 ++++++++++++++++++++- riscv/isa_parser.h | 1 + riscv/processor.cc | 23 ++++++++++++++++++++-- 5 files changed, 88 insertions(+), 7 deletions(-) diff --git a/disasm/isa_parser.cc b/disasm/isa_parser.cc index f4d9da44eb..d5dc439a77 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 9849ea2fbc..e3b5ad4902 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 cf48673ced..5ca7e15738 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -15,6 +15,8 @@ // For access_type: #include "memtracer.h" #include +// For std::optional +#include 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_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_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 prev_val; +}; #endif diff --git a/riscv/isa_parser.h b/riscv/isa_parser.h index bba5a91c56..f955e1613c 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 3126433a34..0704d8ccf8 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(proc, CSR_MSCRATCH, 0); csrmap[CSR_MTVEC] = mtvec = std::make_shared(proc, CSR_MTVEC); csrmap[CSR_MCAUSE] = mcause = std::make_shared(proc, CSR_MCAUSE); - minstret = std::make_shared(proc, CSR_MINSTRET); - mcycle = std::make_shared(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(proc, CSR_MINSTRETCFG, mask, 0); + auto mcyclecfg = std::make_shared(proc, CSR_MCYCLECFG, mask, 0); + + minstret = std::make_shared(proc, CSR_MINSTRET, minstretcfg); + mcycle = std::make_shared(proc, CSR_MCYCLE, mcyclecfg); time = std::make_shared(proc, CSR_TIME); if (proc->extension_enabled_const(EXT_ZICNTR)) { csrmap[CSR_INSTRET] = std::make_shared(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(proc, CSR_MCYCLECFG, mcyclecfg); + csrmap[CSR_MCYCLECFGH] = std::make_shared(proc, CSR_MCYCLECFGH, mcyclecfg); + csrmap[CSR_MINSTRETCFG] = std::make_shared(proc, CSR_MINSTRETCFG, minstretcfg); + csrmap[CSR_MINSTRETCFGH] = std::make_shared(proc, CSR_MINSTRETCFGH, minstretcfg); + } else { + csrmap[CSR_MCYCLECFG] = mcyclecfg; + csrmap[CSR_MINSTRETCFG] = minstretcfg; + } + } + serialized = false; log_reg_write.clear();