From b4e44df0832871032a9aa0ce224bb3466340f137 Mon Sep 17 00:00:00 2001 From: Samuel Riedel Date: Fri, 24 Apr 2026 14:37:48 +0200 Subject: [PATCH 1/9] [rtl] Add register for `mcounteren` --- rtl/ibex_cs_registers.sv | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/rtl/ibex_cs_registers.sv b/rtl/ibex_cs_registers.sv index 11c181b8c..564c801eb 100644 --- a/rtl/ibex_cs_registers.sv +++ b/rtl/ibex_cs_registers.sv @@ -258,6 +258,11 @@ module ibex_cs_registers import ibex_pkg::*; #( logic [MHPMCounterNum+3-1:0] mcountinhibit_d, mcountinhibit_q; logic mcountinhibit_we; + // mcounteren: machine counter enable (controls U-mode counter access) + logic [31:0] mcounteren; + logic [MHPMCounterNum+3-1:0] mcounteren_d, mcounteren_q; + logic mcounteren_we; + // mhpmcounter flops are elaborated below providing only the precise number that is required based // on MHPMCounterNum/MHPMCounterWidth. This signal connects to the Q output of these flops // where they exist and is otherwise 0. @@ -374,9 +379,7 @@ module ibex_cs_registers import ibex_pkg::*; #( end // mcounteren: machine counter enable - CSR_MCOUNTEREN: begin - csr_rdata_int = '0; - end + CSR_MCOUNTEREN: csr_rdata_int = mcounteren; CSR_MSCRATCH: csr_rdata_int = mscratch_q; @@ -598,6 +601,7 @@ module ibex_cs_registers import ibex_pkg::*; #( mstack_cause_d = mcause_q; mcountinhibit_we = 1'b0; + mcounteren_we = 1'b0; mhpmcounter_we = '0; mhpmcounterh_we = '0; @@ -675,6 +679,7 @@ module ibex_cs_registers import ibex_pkg::*; #( CSR_DSCRATCH1: dscratch1_en = 1'b1; // machine counter/timers + CSR_MCOUNTEREN: mcounteren_we = 1'b1; CSR_MCOUNTINHIBIT: mcountinhibit_we = 1'b1; CSR_MCYCLE, @@ -1277,6 +1282,15 @@ module ibex_cs_registers import ibex_pkg::*; #( end end + always_comb begin : mcounteren_update + if (mcounteren_we == 1'b1) begin + // bit 1 must always be 0 (no time CSR implemented) + mcounteren_d = {csr_wdata_int[MHPMCounterNum+2:2], 1'b0, csr_wdata_int[0]}; + end else begin + mcounteren_d = mcounteren_q; + end + end + // event selection (hardwired) & control always_comb begin : gen_mhpmcounter_incr @@ -1434,6 +1448,25 @@ module ibex_cs_registers import ibex_pkg::*; #( end end + if (MHPMCounterNum < 29) begin : g_mcounteren_reduced + assign mcounteren = {{29 - MHPMCounterNum{1'b0}}, mcounteren_q}; + end else begin : g_mcounteren_full + assign mcounteren = mcounteren_q; + end + + ibex_csr #( + .Width (MHPMCounterNum+3), + .ShadowCopy(1'b0), + .ResetValue('0) + ) u_mcounteren_csr ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .wr_data_i (mcounteren_d), + .wr_en_i (mcounteren_we), + .rd_data_o (mcounteren_q), + .rd_error_o() + ); + ///////////////////////////// // Debug trigger registers // ///////////////////////////// From fbe97abceeaac0e20e1faeea4c956c38e26b9f3a Mon Sep 17 00:00:00 2001 From: Samuel Riedel Date: Fri, 24 Apr 2026 16:49:16 +0200 Subject: [PATCH 2/9] [rtl] Add unpriviledged counter/timers --- rtl/ibex_cs_registers.sv | 29 ++++++++++++++++++ rtl/ibex_pkg.sv | 63 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/rtl/ibex_cs_registers.sv b/rtl/ibex_cs_registers.sv index 564c801eb..b279b607e 100644 --- a/rtl/ibex_cs_registers.sv +++ b/rtl/ibex_cs_registers.sv @@ -507,6 +507,35 @@ module ibex_cs_registers import ibex_pkg::*; #( csr_rdata_int = mhpmcounter[mhpmcounter_idx][63:32]; end + // Unprivileged Counter/Timers (readable from U-mode subject to mcounteren) + CSR_CYCLE, + CSR_INSTRET, + CSR_HPMCOUNTER3, + CSR_HPMCOUNTER4, CSR_HPMCOUNTER5, CSR_HPMCOUNTER6, CSR_HPMCOUNTER7, + CSR_HPMCOUNTER8, CSR_HPMCOUNTER9, CSR_HPMCOUNTER10, CSR_HPMCOUNTER11, + CSR_HPMCOUNTER12, CSR_HPMCOUNTER13, CSR_HPMCOUNTER14, CSR_HPMCOUNTER15, + CSR_HPMCOUNTER16, CSR_HPMCOUNTER17, CSR_HPMCOUNTER18, CSR_HPMCOUNTER19, + CSR_HPMCOUNTER20, CSR_HPMCOUNTER21, CSR_HPMCOUNTER22, CSR_HPMCOUNTER23, + CSR_HPMCOUNTER24, CSR_HPMCOUNTER25, CSR_HPMCOUNTER26, CSR_HPMCOUNTER27, + CSR_HPMCOUNTER28, CSR_HPMCOUNTER29, CSR_HPMCOUNTER30, CSR_HPMCOUNTER31: begin + csr_rdata_int = mhpmcounter[mhpmcounter_idx][31:0]; + illegal_csr = (priv_lvl_q == PRIV_LVL_U) && !mcounteren[mhpmcounter_idx]; + end + + CSR_CYCLEH, + CSR_INSTRETH, + CSR_HPMCOUNTER3H, + CSR_HPMCOUNTER4H, CSR_HPMCOUNTER5H, CSR_HPMCOUNTER6H, CSR_HPMCOUNTER7H, + CSR_HPMCOUNTER8H, CSR_HPMCOUNTER9H, CSR_HPMCOUNTER10H, CSR_HPMCOUNTER11H, + CSR_HPMCOUNTER12H, CSR_HPMCOUNTER13H, CSR_HPMCOUNTER14H, CSR_HPMCOUNTER15H, + CSR_HPMCOUNTER16H, CSR_HPMCOUNTER17H, CSR_HPMCOUNTER18H, CSR_HPMCOUNTER19H, + CSR_HPMCOUNTER20H, CSR_HPMCOUNTER21H, CSR_HPMCOUNTER22H, CSR_HPMCOUNTER23H, + CSR_HPMCOUNTER24H, CSR_HPMCOUNTER25H, CSR_HPMCOUNTER26H, CSR_HPMCOUNTER27H, + CSR_HPMCOUNTER28H, CSR_HPMCOUNTER29H, CSR_HPMCOUNTER30H, CSR_HPMCOUNTER31H: begin + csr_rdata_int = mhpmcounter[mhpmcounter_idx][63:32]; + illegal_csr = (priv_lvl_q == PRIV_LVL_U) && !mcounteren[mhpmcounter_idx]; + end + // Debug triggers CSR_TSELECT: begin csr_rdata_int = tselect_rdata; diff --git a/rtl/ibex_pkg.sv b/rtl/ibex_pkg.sv index fbe63b91c..45b406444 100644 --- a/rtl/ibex_pkg.sv +++ b/rtl/ibex_pkg.sv @@ -608,6 +608,69 @@ package ibex_pkg; CSR_MHPMCOUNTER29H = 12'hB9D, CSR_MHPMCOUNTER30H = 12'hB9E, CSR_MHPMCOUNTER31H = 12'hB9F, + // Unprivileged Counter/Timers (readable from U-mode subject to mcounteren) + CSR_CYCLE = 12'hC00, + CSR_INSTRET = 12'hC02, + CSR_HPMCOUNTER3 = 12'hC03, + CSR_HPMCOUNTER4 = 12'hC04, + CSR_HPMCOUNTER5 = 12'hC05, + CSR_HPMCOUNTER6 = 12'hC06, + CSR_HPMCOUNTER7 = 12'hC07, + CSR_HPMCOUNTER8 = 12'hC08, + CSR_HPMCOUNTER9 = 12'hC09, + CSR_HPMCOUNTER10 = 12'hC0A, + CSR_HPMCOUNTER11 = 12'hC0B, + CSR_HPMCOUNTER12 = 12'hC0C, + CSR_HPMCOUNTER13 = 12'hC0D, + CSR_HPMCOUNTER14 = 12'hC0E, + CSR_HPMCOUNTER15 = 12'hC0F, + CSR_HPMCOUNTER16 = 12'hC10, + CSR_HPMCOUNTER17 = 12'hC11, + CSR_HPMCOUNTER18 = 12'hC12, + CSR_HPMCOUNTER19 = 12'hC13, + CSR_HPMCOUNTER20 = 12'hC14, + CSR_HPMCOUNTER21 = 12'hC15, + CSR_HPMCOUNTER22 = 12'hC16, + CSR_HPMCOUNTER23 = 12'hC17, + CSR_HPMCOUNTER24 = 12'hC18, + CSR_HPMCOUNTER25 = 12'hC19, + CSR_HPMCOUNTER26 = 12'hC1A, + CSR_HPMCOUNTER27 = 12'hC1B, + CSR_HPMCOUNTER28 = 12'hC1C, + CSR_HPMCOUNTER29 = 12'hC1D, + CSR_HPMCOUNTER30 = 12'hC1E, + CSR_HPMCOUNTER31 = 12'hC1F, + CSR_CYCLEH = 12'hC80, + CSR_INSTRETH = 12'hC82, + CSR_HPMCOUNTER3H = 12'hC83, + CSR_HPMCOUNTER4H = 12'hC84, + CSR_HPMCOUNTER5H = 12'hC85, + CSR_HPMCOUNTER6H = 12'hC86, + CSR_HPMCOUNTER7H = 12'hC87, + CSR_HPMCOUNTER8H = 12'hC88, + CSR_HPMCOUNTER9H = 12'hC89, + CSR_HPMCOUNTER10H = 12'hC8A, + CSR_HPMCOUNTER11H = 12'hC8B, + CSR_HPMCOUNTER12H = 12'hC8C, + CSR_HPMCOUNTER13H = 12'hC8D, + CSR_HPMCOUNTER14H = 12'hC8E, + CSR_HPMCOUNTER15H = 12'hC8F, + CSR_HPMCOUNTER16H = 12'hC90, + CSR_HPMCOUNTER17H = 12'hC91, + CSR_HPMCOUNTER18H = 12'hC92, + CSR_HPMCOUNTER19H = 12'hC93, + CSR_HPMCOUNTER20H = 12'hC94, + CSR_HPMCOUNTER21H = 12'hC95, + CSR_HPMCOUNTER22H = 12'hC96, + CSR_HPMCOUNTER23H = 12'hC97, + CSR_HPMCOUNTER24H = 12'hC98, + CSR_HPMCOUNTER25H = 12'hC99, + CSR_HPMCOUNTER26H = 12'hC9A, + CSR_HPMCOUNTER27H = 12'hC9B, + CSR_HPMCOUNTER28H = 12'hC9C, + CSR_HPMCOUNTER29H = 12'hC9D, + CSR_HPMCOUNTER30H = 12'hC9E, + CSR_HPMCOUNTER31H = 12'hC9F, CSR_CPUCTRLSTS = 12'h7C0, CSR_SECURESEED = 12'h7C1 } csr_num_e; From 6f5e1ad1f2027c0fcc40f08a1b0733e2b7cf23a0 Mon Sep 17 00:00:00 2001 From: Samuel Riedel Date: Mon, 27 Apr 2026 16:21:32 +0200 Subject: [PATCH 3/9] [rtl] Add input to lock mcounteren --- dv/formal/check/top.sv | 1 + .../rtl/ibex_riscv_compliance.sv | 1 + dv/uvm/core_ibex/tb/core_ibex_tb_top.sv | 1 + .../simple_system/rtl/ibex_simple_system.sv | 1 + rtl/ibex_core.sv | 2 + rtl/ibex_cs_registers.sv | 3 +- rtl/ibex_lockstep.sv | 40 ++++++++++--------- rtl/ibex_top.sv | 13 ++++++ rtl/ibex_top_tracing.sv | 2 + 9 files changed, 45 insertions(+), 19 deletions(-) diff --git a/dv/formal/check/top.sv b/dv/formal/check/top.sv index adea4b633..dc5e6c8b6 100644 --- a/dv/formal/check/top.sv +++ b/dv/formal/check/top.sv @@ -103,6 +103,7 @@ module top import ibex_pkg::*; #( // CPU Control Signals input ibex_mubi_t fetch_enable_i, + input ibex_mubi_t mcounteren_writable_i, output logic core_sleep_o, output logic alert_minor_o, output logic alert_major_internal_o, diff --git a/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv b/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv index ea53592d2..48ab742dc 100644 --- a/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv +++ b/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv @@ -216,6 +216,7 @@ module ibex_riscv_compliance ( .double_fault_seen_o ( ), .fetch_enable_i (ibex_pkg::IbexMuBiOn ), + .mcounteren_writable_i (ibex_pkg::IbexMuBiOn ), .alert_minor_o ( ), .alert_major_internal_o ( ), .alert_major_bus_o ( ), diff --git a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv index a2658d123..cb1ec5c57 100644 --- a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv +++ b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv @@ -169,6 +169,7 @@ module core_ibex_tb_top; .double_fault_seen_o (dut_if.double_fault_seen ), .fetch_enable_i (dut_if.fetch_enable ), + .mcounteren_writable_i (ibex_pkg::IbexMuBiOn ), .alert_minor_o (dut_if.alert_minor ), .alert_major_internal_o (dut_if.alert_major_internal), .alert_major_bus_o (dut_if.alert_major_bus ), diff --git a/examples/simple_system/rtl/ibex_simple_system.sv b/examples/simple_system/rtl/ibex_simple_system.sv index 1f5e08602..58ef1296e 100644 --- a/examples/simple_system/rtl/ibex_simple_system.sv +++ b/examples/simple_system/rtl/ibex_simple_system.sv @@ -273,6 +273,7 @@ module ibex_simple_system ( .double_fault_seen_o (), .fetch_enable_i (ibex_pkg::IbexMuBiOn), + .mcounteren_writable_i (ibex_pkg::IbexMuBiOn), .alert_minor_o (), .alert_major_internal_o (), .alert_major_bus_o (), diff --git a/rtl/ibex_core.sv b/rtl/ibex_core.sv index 79eef6976..85c623abc 100644 --- a/rtl/ibex_core.sv +++ b/rtl/ibex_core.sv @@ -168,6 +168,7 @@ module ibex_core import ibex_pkg::*; #( // CPU Control Signals // SEC_CM: FETCH.CTRL.LC_GATED input ibex_mubi_t fetch_enable_i, + input ibex_mubi_t mcounteren_writable_i, output logic alert_minor_o, output logic alert_major_internal_o, output logic alert_major_bus_o, @@ -1135,6 +1136,7 @@ module ibex_core import ibex_pkg::*; #( .icache_enable_o (icache_enable), .csr_shadow_err_o (csr_shadow_err), .ic_scr_key_valid_i (ic_scr_key_valid_i), + .mcounteren_writable_i(mcounteren_writable_i), .csr_save_if_i (csr_save_if), .csr_save_id_i (csr_save_id), diff --git a/rtl/ibex_cs_registers.sv b/rtl/ibex_cs_registers.sv index b279b607e..961909360 100644 --- a/rtl/ibex_cs_registers.sv +++ b/rtl/ibex_cs_registers.sv @@ -98,6 +98,7 @@ module ibex_cs_registers import ibex_pkg::*; #( output logic icache_enable_o, output logic csr_shadow_err_o, input logic ic_scr_key_valid_i, + input ibex_mubi_t mcounteren_writable_i, // Exception save/restore input logic csr_save_if_i, @@ -708,7 +709,7 @@ module ibex_cs_registers import ibex_pkg::*; #( CSR_DSCRATCH1: dscratch1_en = 1'b1; // machine counter/timers - CSR_MCOUNTEREN: mcounteren_we = 1'b1; + CSR_MCOUNTEREN: mcounteren_we = mcounteren_writable_i == IbexMuBiOn; CSR_MCOUNTINHIBIT: mcountinhibit_we = 1'b1; CSR_MCYCLE, diff --git a/rtl/ibex_lockstep.sv b/rtl/ibex_lockstep.sv index f83f3061f..b0fb5ed7b 100644 --- a/rtl/ibex_lockstep.sv +++ b/rtl/ibex_lockstep.sv @@ -104,6 +104,7 @@ module ibex_lockstep import ibex_pkg::*; #( input logic double_fault_seen_i, input ibex_mubi_t fetch_enable_i, + input ibex_mubi_t mcounteren_writable_i, output logic alert_minor_o, output logic alert_major_internal_o, output logic alert_major_bus_o, @@ -247,6 +248,7 @@ module ibex_lockstep import ibex_pkg::*; #( logic irq_nm; logic debug_req; ibex_mubi_t fetch_enable; + ibex_mubi_t mcounteren_writable; logic ic_scr_key_valid; } delayed_inputs_t; @@ -310,24 +312,25 @@ module ibex_lockstep import ibex_pkg::*; #( end // Assign the inputs to the delay structure - assign shadow_inputs_in.instr_gnt = instr_gnt_i; - assign shadow_inputs_in.instr_rvalid = instr_rvalid_i; - assign shadow_inputs_in.instr_rdata = instr_rdata_i; - assign shadow_inputs_in.instr_err = instr_err_i; - assign shadow_inputs_in.data_gnt = data_gnt_i; - assign shadow_inputs_in.data_rvalid = data_rvalid_i; - assign shadow_inputs_in.data_rdata = data_rdata_i; - assign shadow_inputs_in.data_err = data_err_i; - assign shadow_inputs_in.rf_rdata_a = rf_rdata_a_i; - assign shadow_inputs_in.rf_rdata_b = rf_rdata_b_i; - assign shadow_inputs_in.irq_software = irq_software_i; - assign shadow_inputs_in.irq_timer = irq_timer_i; - assign shadow_inputs_in.irq_external = irq_external_i; - assign shadow_inputs_in.irq_fast = irq_fast_i; - assign shadow_inputs_in.irq_nm = irq_nm_i; - assign shadow_inputs_in.debug_req = debug_req_i; - assign shadow_inputs_in.fetch_enable = fetch_enable_i; - assign shadow_inputs_in.ic_scr_key_valid = ic_scr_key_valid_i; + assign shadow_inputs_in.instr_gnt = instr_gnt_i; + assign shadow_inputs_in.instr_rvalid = instr_rvalid_i; + assign shadow_inputs_in.instr_rdata = instr_rdata_i; + assign shadow_inputs_in.instr_err = instr_err_i; + assign shadow_inputs_in.data_gnt = data_gnt_i; + assign shadow_inputs_in.data_rvalid = data_rvalid_i; + assign shadow_inputs_in.data_rdata = data_rdata_i; + assign shadow_inputs_in.data_err = data_err_i; + assign shadow_inputs_in.rf_rdata_a = rf_rdata_a_i; + assign shadow_inputs_in.rf_rdata_b = rf_rdata_b_i; + assign shadow_inputs_in.irq_software = irq_software_i; + assign shadow_inputs_in.irq_timer = irq_timer_i; + assign shadow_inputs_in.irq_external = irq_external_i; + assign shadow_inputs_in.irq_fast = irq_fast_i; + assign shadow_inputs_in.irq_nm = irq_nm_i; + assign shadow_inputs_in.debug_req = debug_req_i; + assign shadow_inputs_in.fetch_enable = fetch_enable_i; + assign shadow_inputs_in.mcounteren_writable = mcounteren_writable_i; + assign shadow_inputs_in.ic_scr_key_valid = ic_scr_key_valid_i; /////////////////// // Output delays // @@ -554,6 +557,7 @@ module ibex_lockstep import ibex_pkg::*; #( `endif .fetch_enable_i (shadow_inputs_q[0].fetch_enable), + .mcounteren_writable_i (shadow_inputs_q[0].mcounteren_writable), .alert_minor_o (shadow_alert_minor), .alert_major_internal_o (shadow_alert_major_internal), .alert_major_bus_o (shadow_alert_major_bus), diff --git a/rtl/ibex_top.sv b/rtl/ibex_top.sv index 1a0712c4f..0f6419a89 100644 --- a/rtl/ibex_top.sv +++ b/rtl/ibex_top.sv @@ -160,6 +160,7 @@ module ibex_top import ibex_pkg::*; #( // CPU Control Signals input ibex_mubi_t fetch_enable_i, + input ibex_mubi_t mcounteren_writable_i, output logic alert_minor_o, output logic alert_major_internal_o, output logic alert_major_bus_o, @@ -244,6 +245,7 @@ module ibex_top import ibex_pkg::*; #( logic scramble_req_d, scramble_req_q; ibex_mubi_t fetch_enable_buf; + ibex_mubi_t mcounteren_writable_buf; ///////////////////// // Main clock gate // @@ -296,6 +298,11 @@ module ibex_top import ibex_pkg::*; #( .out_o(fetch_enable_buf) ); + prim_buf #(.Width($bits(ibex_mubi_t))) u_mcounteren_writable_buf ( + .in_i (mcounteren_writable_i), + .out_o(mcounteren_writable_buf) + ); + // ibex_core takes integrity and data bits together. Combine the separate integrity and data // inputs here. assign data_rdata_core[31:0] = data_rdata_i; @@ -449,6 +456,7 @@ module ibex_top import ibex_pkg::*; #( `endif .fetch_enable_i (fetch_enable_buf), + .mcounteren_writable_i (mcounteren_writable_buf), .alert_minor_o (core_alert_minor), .alert_major_internal_o(core_alert_major_internal), .alert_major_bus_o (core_alert_major_bus), @@ -829,6 +837,7 @@ module ibex_top import ibex_pkg::*; #( crash_dump_o, double_fault_seen_o, fetch_enable_i, + mcounteren_writable_i, core_busy_d }); @@ -879,6 +888,7 @@ module ibex_top import ibex_pkg::*; #( crash_dump_t crash_dump_local; logic double_fault_seen_local; ibex_mubi_t fetch_enable_local; + ibex_mubi_t mcounteren_writable_local; ibex_mubi_t core_busy_local; @@ -922,6 +932,7 @@ module ibex_top import ibex_pkg::*; #( crash_dump_o, double_fault_seen_o, fetch_enable_i, + mcounteren_writable_i, core_busy_d }; @@ -965,6 +976,7 @@ module ibex_top import ibex_pkg::*; #( crash_dump_local, double_fault_seen_local, fetch_enable_local, + mcounteren_writable_local, core_busy_local } = buf_out; @@ -1083,6 +1095,7 @@ module ibex_top import ibex_pkg::*; #( .double_fault_seen_i (double_fault_seen_local), .fetch_enable_i (fetch_enable_local), + .mcounteren_writable_i (mcounteren_writable_local), .alert_minor_o (lockstep_alert_minor_local), .alert_major_internal_o (lockstep_alert_major_internal_local), .alert_major_bus_o (lockstep_alert_major_bus_local), diff --git a/rtl/ibex_top_tracing.sv b/rtl/ibex_top_tracing.sv index a5f37d1d6..3823dd219 100644 --- a/rtl/ibex_top_tracing.sv +++ b/rtl/ibex_top_tracing.sv @@ -96,6 +96,7 @@ module ibex_top_tracing import ibex_pkg::*; #( // CPU Control Signals input ibex_mubi_t fetch_enable_i, + input ibex_mubi_t mcounteren_writable_i, output logic alert_minor_o, output logic alert_major_internal_o, output logic alert_major_bus_o, @@ -313,6 +314,7 @@ module ibex_top_tracing import ibex_pkg::*; #( .rvfi_ext_expanded_insn_last, .fetch_enable_i, + .mcounteren_writable_i, .alert_minor_o, .alert_major_internal_o, .alert_major_bus_o, From c8fbf38899fd889fd161f825d33ba6d58bfdea4f Mon Sep 17 00:00:00 2001 From: Samuel Riedel Date: Mon, 27 Apr 2026 16:22:20 +0200 Subject: [PATCH 4/9] [dv] Implement Ibex-specific mcounteren behavior in cosim --- dv/cosim/spike_cosim.cc | 18 +++++++++++++++++- dv/cosim/spike_cosim.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/dv/cosim/spike_cosim.cc b/dv/cosim/spike_cosim.cc index daa400709..32537875e 100644 --- a/dv/cosim/spike_cosim.cc +++ b/dv/cosim/spike_cosim.cc @@ -39,7 +39,10 @@ SpikeCosim::SpikeCosim(const std::string &isa_string, uint32_t start_pc, uint32_t pmp_num_regions, uint32_t pmp_granularity, uint32_t mhpm_counter_num, uint32_t dm_start_addr, uint32_t dm_end_addr) - : nmi_mode(false), pending_iside_error(false), insn_cnt(0) { + : nmi_mode(false), + pending_iside_error(false), + insn_cnt(0), + mhpm_counter_num(mhpm_counter_num) { FILE *log_file = nullptr; if (trace_log_path.length() != 0) { log = std::make_unique(trace_log_path.c_str()); @@ -832,6 +835,19 @@ void SpikeCosim::fixup_csr(int csr_num, uint32_t csr_val) { processor->set_csr(csr_num, new_val); #else processor->put_csr(csr_num, new_val); +#endif + break; + } + case CSR_MCOUNTEREN: { + // Bits 3..3+mhpm_counter_num-1 correspond to implemented HPM counters + reg_t hpm_mask = ((1 << mhpm_counter_num) - 1) << 3; + // Bit 0 and 2 are for mcycle and minstret which are always implemented + // Bit 1 is for time which is not implemented, hence the mask 0x5 + reg_t new_val = csr_val & (0x5 | hpm_mask); +#ifdef OLD_SPIKE + processor->set_csr(csr_num, new_val); +#else + processor->put_csr(csr_num, new_val); #endif break; } diff --git a/dv/cosim/spike_cosim.h b/dv/cosim/spike_cosim.h index 68fd2204f..2849206e0 100644 --- a/dv/cosim/spike_cosim.h +++ b/dv/cosim/spike_cosim.h @@ -98,6 +98,7 @@ class SpikeCosim : public simif_t, public Cosim { void misaligned_pmp_fixup(); unsigned int insn_cnt; + uint32_t mhpm_counter_num; public: SpikeCosim(const std::string &isa_string, uint32_t start_pc, From ea2ad1d2d6b6d60366e33e9e44612a24ba55e86b Mon Sep 17 00:00:00 2001 From: Samuel Riedel Date: Wed, 29 Apr 2026 15:10:34 +0200 Subject: [PATCH 5/9] [dv] Add `mcounteren` directed test --- .../directed_tests/directed_testlist.yaml | 626 +++++++++--------- .../core_ibex/directed_tests/gen_testlist.py | 8 + .../mcounteren_test/mcounteren_test.S | 224 +++++++ 3 files changed, 549 insertions(+), 309 deletions(-) create mode 100644 dv/uvm/core_ibex/directed_tests/mcounteren_test/mcounteren_test.S diff --git a/dv/uvm/core_ibex/directed_tests/directed_testlist.yaml b/dv/uvm/core_ibex/directed_tests/directed_testlist.yaml index 2517f54a7..ec1adf8b1 100644 --- a/dv/uvm/core_ibex/directed_tests/directed_testlist.yaml +++ b/dv/uvm/core_ibex/directed_tests/directed_testlist.yaml @@ -60,6 +60,14 @@ test_srcs: empty/empty.S config: riscv-tests +- test: mcounteren_test + desc: > + Tests the mcounteren CSR: reset value, hardwired-zero bit 1 (time), + and U-mode counter access gating. + iterations: 1 + test_srcs: mcounteren_test/mcounteren_test.S + config: riscv-tests + - test: pmp_mseccfg_test_rlb1_l0_0_u0 desc: > mseccfg test @@ -388,167 +396,6 @@ # Test-suite: riscv-tests -- test: breakpoint - desc: > - riscv test - breakpoint - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/breakpoint.S - config: riscv-tests - -- test: csr - desc: > - riscv test - csr - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/csr.S - config: riscv-tests - -- test: illegal - desc: > - riscv test - illegal - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/illegal.S - config: riscv-tests - -- test: lh-misaligned - desc: > - riscv test - lh-misaligned - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/lh-misaligned.S - config: riscv-tests - -- test: lw-misaligned - desc: > - riscv test - lw-misaligned - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/lw-misaligned.S - config: riscv-tests - -- test: ma_addr - desc: > - riscv test - ma_addr - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/ma_addr.S - config: riscv-tests - -- test: ma_fetch - desc: > - riscv test - ma_fetch - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/ma_fetch.S - config: riscv-tests - -- test: mcsr - desc: > - riscv test - mcsr - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/mcsr.S - config: riscv-tests - -- test: sbreak - desc: > - riscv test - sbreak - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/sbreak.S - config: riscv-tests - -- test: scall - desc: > - riscv test - scall - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/scall.S - config: riscv-tests - -- test: shamt - desc: > - riscv test - shamt - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/shamt.S - config: riscv-tests - -- test: sh-misaligned - desc: > - riscv test - sh-misaligned - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/sh-misaligned.S - config: riscv-tests - -- test: sw-misaligned - desc: > - riscv test - sw-misaligned - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/sw-misaligned.S - config: riscv-tests - -- test: zicntr - desc: > - riscv test - zicntr - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/zicntr.S - config: riscv-tests - -- test: rvc - desc: > - riscv test - rvc - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32uc/rvc.S - config: riscv-tests - -- test: div - desc: > - riscv test - div - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32um/div.S - config: riscv-tests - -- test: divu - desc: > - riscv test - divu - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32um/divu.S - config: riscv-tests - -- test: mulh - desc: > - riscv test - mulh - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32um/mulh.S - config: riscv-tests - -- test: mulhsu - desc: > - riscv test - mulhsu - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32um/mulhsu.S - config: riscv-tests - -- test: mulhu - desc: > - riscv test - mulhu - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32um/mulhu.S - config: riscv-tests - -- test: mul - desc: > - riscv test - mul - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32um/mul.S - config: riscv-tests - -- test: rem - desc: > - riscv test - rem - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32um/rem.S - config: riscv-tests - -- test: remu - desc: > - riscv test - remu - iterations: 1 - test_srcs: ../../../../vendor/riscv-tests/isa/rv32um/remu.S - config: riscv-tests - - test: addi desc: > riscv test - addi @@ -822,258 +669,230 @@ test_srcs: ../../../../vendor/riscv-tests/isa/rv32ui/xor.S config: riscv-tests -# Test-suite: riscv-arch-tests - -- test: div-01 +- test: breakpoint desc: > - riscv test - div-01 + riscv test - breakpoint iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/div-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/breakpoint.S + config: riscv-tests -- test: divu-01 +- test: csr desc: > - riscv test - divu-01 + riscv test - csr iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/divu-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/csr.S + config: riscv-tests -- test: mul-01 +- test: illegal desc: > - riscv test - mul-01 + riscv test - illegal iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/mul-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/illegal.S + config: riscv-tests -- test: mulh-01 +- test: lh-misaligned desc: > - riscv test - mulh-01 + riscv test - lh-misaligned iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/mulh-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/lh-misaligned.S + config: riscv-tests -- test: mulhsu-01 +- test: lw-misaligned desc: > - riscv test - mulhsu-01 + riscv test - lw-misaligned iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/mulhsu-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/lw-misaligned.S + config: riscv-tests -- test: mulhu-01 +- test: ma_addr desc: > - riscv test - mulhu-01 + riscv test - ma_addr iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/mulhu-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/ma_addr.S + config: riscv-tests -- test: rem-01 +- test: ma_fetch desc: > - riscv test - rem-01 + riscv test - ma_fetch iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/rem-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/ma_fetch.S + config: riscv-tests -- test: remu-01 +- test: mcsr desc: > - riscv test - remu-01 + riscv test - mcsr iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/remu-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/mcsr.S + config: riscv-tests -- test: cadd-01 +- test: sbreak desc: > - riscv test - cadd-01 + riscv test - sbreak iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cadd-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/sbreak.S + config: riscv-tests -- test: caddi-01 +- test: scall desc: > - riscv test - caddi-01 + riscv test - scall iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/caddi-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/scall.S + config: riscv-tests -- test: caddi16sp-01 +- test: shamt desc: > - riscv test - caddi16sp-01 + riscv test - shamt iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/caddi16sp-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/shamt.S + config: riscv-tests -- test: caddi4spn-01 - desc: > - riscv test - caddi4spn-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/caddi4spn-01.S - config: riscv-arch-tests - -- test: cand-01 - desc: > - riscv test - cand-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cand-01.S - config: riscv-arch-tests - -- test: candi-01 - desc: > - riscv test - candi-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/candi-01.S - config: riscv-arch-tests - -- test: cbeqz-01 +- test: sh-misaligned desc: > - riscv test - cbeqz-01 + riscv test - sh-misaligned iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cbeqz-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/sh-misaligned.S + config: riscv-tests -- test: cbnez-01 +- test: sw-misaligned desc: > - riscv test - cbnez-01 + riscv test - sw-misaligned iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cbnez-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/sw-misaligned.S + config: riscv-tests -- test: cebreak-01 +- test: zicntr desc: > - riscv test - cebreak-01 + riscv test - zicntr iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cebreak-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32mi/zicntr.S + config: riscv-tests -- test: cj-01 +- test: rvc desc: > - riscv test - cj-01 + riscv test - rvc iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cj-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32uc/rvc.S + config: riscv-tests -- test: cjal-01 +- test: div desc: > - riscv test - cjal-01 + riscv test - div iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cjal-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32um/div.S + config: riscv-tests -- test: cjalr-01 +- test: divu desc: > - riscv test - cjalr-01 + riscv test - divu iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cjalr-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32um/divu.S + config: riscv-tests -- test: cjr-01 +- test: mulh desc: > - riscv test - cjr-01 + riscv test - mulh iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cjr-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32um/mulh.S + config: riscv-tests -- test: cli-01 +- test: mulhsu desc: > - riscv test - cli-01 + riscv test - mulhsu iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cli-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32um/mulhsu.S + config: riscv-tests -- test: clui-01 +- test: mulhu desc: > - riscv test - clui-01 + riscv test - mulhu iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/clui-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32um/mulhu.S + config: riscv-tests -- test: clw-01 +- test: mul desc: > - riscv test - clw-01 + riscv test - mul iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/clw-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32um/mul.S + config: riscv-tests -- test: clwsp-01 +- test: rem desc: > - riscv test - clwsp-01 + riscv test - rem iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/clwsp-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32um/rem.S + config: riscv-tests -- test: cmv-01 +- test: remu desc: > - riscv test - cmv-01 + riscv test - remu iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cmv-01.S - config: riscv-arch-tests + test_srcs: ../../../../vendor/riscv-tests/isa/rv32um/remu.S + config: riscv-tests -- test: cnop-01 - desc: > - riscv test - cnop-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cnop-01.S - config: riscv-arch-tests +# Test-suite: riscv-arch-tests -- test: cor-01 +- test: Fencei desc: > - riscv test - cor-01 + riscv test - Fencei iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cor-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/Zifencei/src/Fencei.S config: riscv-arch-tests -- test: cslli-01 +- test: div-01 desc: > - riscv test - cslli-01 + riscv test - div-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cslli-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/div-01.S config: riscv-arch-tests -- test: csrai-01 +- test: divu-01 desc: > - riscv test - csrai-01 + riscv test - divu-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/csrai-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/divu-01.S config: riscv-arch-tests -- test: csrli-01 +- test: mul-01 desc: > - riscv test - csrli-01 + riscv test - mul-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/csrli-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/mul-01.S config: riscv-arch-tests -- test: csub-01 +- test: mulh-01 desc: > - riscv test - csub-01 + riscv test - mulh-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/csub-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/mulh-01.S config: riscv-arch-tests -- test: csw-01 +- test: mulhsu-01 desc: > - riscv test - csw-01 + riscv test - mulhsu-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/csw-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/mulhsu-01.S config: riscv-arch-tests -- test: cswsp-01 +- test: mulhu-01 desc: > - riscv test - cswsp-01 + riscv test - mulhu-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cswsp-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/mulhu-01.S config: riscv-arch-tests -- test: cxor-01 +- test: rem-01 desc: > - riscv test - cxor-01 + riscv test - rem-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cxor-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/rem-01.S config: riscv-arch-tests -- test: Fencei +- test: remu-01 desc: > - riscv test - Fencei + riscv test - remu-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/Zifencei/src/Fencei.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/remu-01.S config: riscv-arch-tests - test: add-01 @@ -1573,6 +1392,195 @@ test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/zext-h_32-01.S config: riscv-arch-tests +- test: cadd-01 + desc: > + riscv test - cadd-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cadd-01.S + config: riscv-arch-tests + +- test: caddi-01 + desc: > + riscv test - caddi-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/caddi-01.S + config: riscv-arch-tests + +- test: caddi16sp-01 + desc: > + riscv test - caddi16sp-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/caddi16sp-01.S + config: riscv-arch-tests + +- test: caddi4spn-01 + desc: > + riscv test - caddi4spn-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/caddi4spn-01.S + config: riscv-arch-tests + +- test: cand-01 + desc: > + riscv test - cand-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cand-01.S + config: riscv-arch-tests + +- test: candi-01 + desc: > + riscv test - candi-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/candi-01.S + config: riscv-arch-tests + +- test: cbeqz-01 + desc: > + riscv test - cbeqz-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cbeqz-01.S + config: riscv-arch-tests + +- test: cbnez-01 + desc: > + riscv test - cbnez-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cbnez-01.S + config: riscv-arch-tests + +- test: cebreak-01 + desc: > + riscv test - cebreak-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cebreak-01.S + config: riscv-arch-tests + +- test: cj-01 + desc: > + riscv test - cj-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cj-01.S + config: riscv-arch-tests + +- test: cjal-01 + desc: > + riscv test - cjal-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cjal-01.S + config: riscv-arch-tests + +- test: cjalr-01 + desc: > + riscv test - cjalr-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cjalr-01.S + config: riscv-arch-tests + +- test: cjr-01 + desc: > + riscv test - cjr-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cjr-01.S + config: riscv-arch-tests + +- test: cli-01 + desc: > + riscv test - cli-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cli-01.S + config: riscv-arch-tests + +- test: clui-01 + desc: > + riscv test - clui-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/clui-01.S + config: riscv-arch-tests + +- test: clw-01 + desc: > + riscv test - clw-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/clw-01.S + config: riscv-arch-tests + +- test: clwsp-01 + desc: > + riscv test - clwsp-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/clwsp-01.S + config: riscv-arch-tests + +- test: cmv-01 + desc: > + riscv test - cmv-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cmv-01.S + config: riscv-arch-tests + +- test: cnop-01 + desc: > + riscv test - cnop-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cnop-01.S + config: riscv-arch-tests + +- test: cor-01 + desc: > + riscv test - cor-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cor-01.S + config: riscv-arch-tests + +- test: cslli-01 + desc: > + riscv test - cslli-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cslli-01.S + config: riscv-arch-tests + +- test: csrai-01 + desc: > + riscv test - csrai-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/csrai-01.S + config: riscv-arch-tests + +- test: csrli-01 + desc: > + riscv test - csrli-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/csrli-01.S + config: riscv-arch-tests + +- test: csub-01 + desc: > + riscv test - csub-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/csub-01.S + config: riscv-arch-tests + +- test: csw-01 + desc: > + riscv test - csw-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/csw-01.S + config: riscv-arch-tests + +- test: cswsp-01 + desc: > + riscv test - cswsp-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cswsp-01.S + config: riscv-arch-tests + +- test: cxor-01 + desc: > + riscv test - cxor-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/C/src/cxor-01.S + config: riscv-arch-tests + # Test-suite: epmp-tests - test: test_pmp_csr_1_lock00_rlb0_mmwp0_mml0_pmp_01 diff --git a/dv/uvm/core_ibex/directed_tests/gen_testlist.py b/dv/uvm/core_ibex/directed_tests/gen_testlist.py index c92260814..f7a2ae7da 100644 --- a/dv/uvm/core_ibex/directed_tests/gen_testlist.py +++ b/dv/uvm/core_ibex/directed_tests/gen_testlist.py @@ -80,6 +80,14 @@ def add_configs_and_handwritten_directed_tests(): test_srcs: empty/empty.S config: riscv-tests +- test: mcounteren_test + desc: > + Tests the mcounteren CSR: reset value, hardwired-zero bit 1 (time), + and U-mode counter access gating. + iterations: 1 + test_srcs: mcounteren_test/mcounteren_test.S + config: riscv-tests + - test: pmp_mseccfg_test_rlb1_l0_0_u0 desc: > mseccfg test diff --git a/dv/uvm/core_ibex/directed_tests/mcounteren_test/mcounteren_test.S b/dv/uvm/core_ibex/directed_tests/mcounteren_test/mcounteren_test.S new file mode 100644 index 000000000..388576f83 --- /dev/null +++ b/dv/uvm/core_ibex/directed_tests/mcounteren_test/mcounteren_test.S @@ -0,0 +1,224 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +# This test verifies mcounteren CSR functionality by sweeping multiple bit +# patterns to ensure User-mode access to all 64 performance counters is +# correctly gated. It confirms that allowed registers read successfully, +# while disabled registers securely trigger illegal instruction exceptions. + +#include "custom_macros.h" +#include "riscv_test.h" +#include "test_macros.h" + +# Register Allocation: +# s1: Expected instruction execution state(1 = should succeed, 0 = should trap) +# s2: Readback snapshot of valid mcounteren bits +# s3: Subroutine return address backup tracking register(ra) +# s4: Label pointing to the next macro boundary +# s5: Subroutine continuation target pointer used upon full block completion + +.macro RUN_CSR_TEST idx, csr_addr + # Check if this counter is configured to be accessible + # Get position at which to check mcounteren bit for this counter + li t0, \csr_addr + andi t0, t0, 0x1F + # Create mask from position + li t1, 1 + sll t1, t1, t0 + and t1, s2, t1 + # s1 = 1 if counter is enabled and should succeed cleanly + snez s1, t1 + + # Set next test label for the handler + la s4, next_test_\idx + + # Read counter.This should trap if s1 == 0 and succeed if s1 == 1 + csrr t0, \csr_addr + # If the counter was supposed to trap but didn't, fail immediately + beqz s1, fail + # Continue to next test +next_test_\idx: +.endm + +.macro RUN_ALL_CSR_TESTS + # Lower 32 Bits of Performance Counters + RUN_CSR_TEST 0, 0xC00 # cycle + RUN_CSR_TEST 1, 0xC01 # time + RUN_CSR_TEST 2, 0xC02 # instret + RUN_CSR_TEST 3, 0xC03 # hpmcounter3 + RUN_CSR_TEST 4, 0xC04 + RUN_CSR_TEST 5, 0xC05 + RUN_CSR_TEST 6, 0xC06 + RUN_CSR_TEST 7, 0xC07 + RUN_CSR_TEST 8, 0xC08 + RUN_CSR_TEST 9, 0xC09 + RUN_CSR_TEST 10, 0xC0A + RUN_CSR_TEST 11, 0xC0B + RUN_CSR_TEST 12, 0xC0C + RUN_CSR_TEST 13, 0xC0D + RUN_CSR_TEST 14, 0xC0E + RUN_CSR_TEST 15, 0xC0F + RUN_CSR_TEST 16, 0xC10 + RUN_CSR_TEST 17, 0xC11 + RUN_CSR_TEST 18, 0xC12 + RUN_CSR_TEST 19, 0xC13 + RUN_CSR_TEST 20, 0xC14 + RUN_CSR_TEST 21, 0xC15 + RUN_CSR_TEST 22, 0xC16 + RUN_CSR_TEST 23, 0xC17 + RUN_CSR_TEST 24, 0xC18 + RUN_CSR_TEST 25, 0xC19 + RUN_CSR_TEST 26, 0xC1A + RUN_CSR_TEST 27, 0xC1B + RUN_CSR_TEST 28, 0xC1C + RUN_CSR_TEST 29, 0xC1D + RUN_CSR_TEST 30, 0xC1E + RUN_CSR_TEST 31, 0xC1F # hpmcounter31 + # Upper 32 Bits of Performance Counters + RUN_CSR_TEST 32, 0xC80 # cycleh + RUN_CSR_TEST 33, 0xC81 # timeh + RUN_CSR_TEST 34, 0xC82 # instreth + RUN_CSR_TEST 35, 0xC83 # hpmcounter3h + RUN_CSR_TEST 36, 0xC84 + RUN_CSR_TEST 37, 0xC85 + RUN_CSR_TEST 38, 0xC86 + RUN_CSR_TEST 39, 0xC87 + RUN_CSR_TEST 40, 0xC88 + RUN_CSR_TEST 41, 0xC89 + RUN_CSR_TEST 42, 0xC8A + RUN_CSR_TEST 43, 0xC8B + RUN_CSR_TEST 44, 0xC8C + RUN_CSR_TEST 45, 0xC8D + RUN_CSR_TEST 46, 0xC8E + RUN_CSR_TEST 47, 0xC8F + RUN_CSR_TEST 48, 0xC90 + RUN_CSR_TEST 49, 0xC91 + RUN_CSR_TEST 50, 0xC92 + RUN_CSR_TEST 51, 0xC93 + RUN_CSR_TEST 52, 0xC94 + RUN_CSR_TEST 53, 0xC95 + RUN_CSR_TEST 54, 0xC96 + RUN_CSR_TEST 55, 0xC97 + RUN_CSR_TEST 56, 0xC98 + RUN_CSR_TEST 57, 0xC99 + RUN_CSR_TEST 58, 0xC9A + RUN_CSR_TEST 59, 0xC9B + RUN_CSR_TEST 60, 0xC9C + RUN_CSR_TEST 61, 0xC9D + RUN_CSR_TEST 62, 0xC9E + RUN_CSR_TEST 63, 0xC9F # hpmcounter31h +.endm + +# ----------------------------------------------------------------------- +# Main Verification Blocks +# ----------------------------------------------------------------------- + +RVTEST_RV32M +RVTEST_CODE_BEGIN + + la t0, mtvec_handler + csrw mtvec, t0 + + # Verify default power - on reset state + csrr t0, mcounteren + bnez t0, fail + + # Verify that we can write to mcounteren and read back the expected value + li t0, 0x1 + csrw mcounteren, t0 + csrr t1, mcounteren + bne t1, t0, fail + + # Verify time enable bit is hardwired to zero while other bits are sticky + li t0, 0x7 + csrw mcounteren, t0 + csrr t1, mcounteren + xori t1, t1, 0x5 + bnez t1, fail + + # Sweep with all implemented counters enabled + li t0, 0xFFFFFFFF + csrw mcounteren, t0 + csrr s2, mcounteren + jal ra, run_all_csr_tests + + # Sweep with all counters disabled + csrwi mcounteren, 0 + csrr s2, mcounteren + jal ra, run_all_csr_tests + + # Sweep using alternating bits + li t0, 0x55555555 + csrw mcounteren, t0 + csrr s2, mcounteren + jal ra, run_all_csr_tests + + # Sweep using arbitrary custom mask + li t0, 0xCD609E2D + csrw mcounteren, t0 + csrr s2, mcounteren + jal ra, run_all_csr_tests + + # If execution hits this line, all pattern sweeps successfully completed + csrwi mcounteren, 0 + j pass + + TEST_PASSFAIL + +# ----------------------------------------------------------------------- +# Evaluation Subroutine +# ----------------------------------------------------------------------- +run_all_csr_tests: + mv s3, ra + la s5, post_all_tests + # Drop to U-mode once per pattern to execute the continuous instruction stream + SWITCH_TO_U_MODE_LABEL(u_mode_sweep_entry) + +.balign 4 +u_mode_sweep_entry: + RUN_ALL_CSR_TESTS + + # Reaching this line implies all 32 checks passed cleanly + ecall + +post_all_tests: + mv ra, s3 + ret + +# ----------------------------------------------------------------------- +# Exception Trap Handler +# ----------------------------------------------------------------------- +.balign 256 +mtvec_handler: + csrr t0, mcause + + # mcause 8 = Environment Call from U-mode (stream finished successfully) + li t1, 8 + beq t0, t1, handle_ecall + + # mcause 2 = Illegal Instruction + li t1, 2 + # Drop out to failure trap on all unexpected exceptions + bne t0, t1, fail + + # If the register was supposed to be accessible (s1 == 1) but faulted, fail + bnez s1, fail + + # Valid hardware restriction exception. Safely continue to next macro block + csrw mepc, s4 + mret + +handle_ecall: + # All unrolled checks passed. Safely return back to M-mode context runner + csrw mepc, s5 + li t0, 0x1800 + csrs mstatus, t0 + mret + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + TEST_DATA +RVTEST_DATA_END From e3f146879853cdacf59df932625180257aa67255 Mon Sep 17 00:00:00 2001 From: Samuel Riedel Date: Mon, 11 May 2026 09:58:16 +0200 Subject: [PATCH 6/9] [dv] Correctly set `minstret` in cosim --- dv/cosim/cosim.h | 11 ++++++++++ dv/cosim/cosim_dpi.cc | 7 +++++++ dv/cosim/cosim_dpi.h | 1 + dv/cosim/cosim_dpi.svh | 1 + dv/cosim/spike_cosim.cc | 21 +++++++++++++++++++ dv/cosim/spike_cosim.h | 1 + .../ibex_cosim_agent/ibex_cosim_scoreboard.sv | 1 + .../ibex_cosim_agent/ibex_rvfi_monitor.sv | 1 + .../ibex_cosim_agent/ibex_rvfi_seq_item.sv | 2 ++ dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv | 2 ++ dv/uvm/core_ibex/tb/core_ibex_tb_top.sv | 1 + rtl/ibex_core.sv | 6 ++++++ rtl/ibex_lockstep.sv | 1 + rtl/ibex_top.sv | 2 ++ rtl/ibex_top_tracing.sv | 4 ++++ 15 files changed, 62 insertions(+) diff --git a/dv/cosim/cosim.h b/dv/cosim/cosim.h index 4a5c63c75..305af005d 100644 --- a/dv/cosim/cosim.h +++ b/dv/cosim/cosim.h @@ -128,6 +128,17 @@ class Cosim { // A full 64-bit value is provided setting both the mcycle and mcycleh CSRs. virtual void set_mcycle(uint64_t mcycle) = 0; + // Set the value of minstret. + // + // The co-simulation model doesn't alter the value of minstret itself (other + // than instructions that do a direct CSR write). minstret should be set to + // the correct value before any `step` call that may execute an instruction + // that observes the value of minstret. + // + // A full 64-bit value is provided setting both the minstret and minstreth + // CSRs. + virtual void set_minstret(uint64_t minstret) = 0; + // Set the value of a CSR. This is used when it is needed to have direct // communication between DUT and Spike (e.g. Performance counters). virtual void set_csr(const int csr_num, const uint32_t new_val) = 0; diff --git a/dv/cosim/cosim_dpi.cc b/dv/cosim/cosim_dpi.cc index 30a3da74d..fac12f79b 100644 --- a/dv/cosim/cosim_dpi.cc +++ b/dv/cosim/cosim_dpi.cc @@ -52,6 +52,13 @@ void riscv_cosim_set_mcycle(Cosim *cosim, svBitVecVal *mcycle) { cosim->set_mcycle(mcycle_full); } +void riscv_cosim_set_minstret(Cosim *cosim, svBitVecVal *minstret) { + assert(cosim); + + uint64_t minstret_full = minstret[0] | (uint64_t)minstret[1] << 32; + cosim->set_minstret(minstret_full); +} + void riscv_cosim_set_csr(Cosim *cosim, const int csr_id, const svBitVecVal *csr_val) { assert(cosim); diff --git a/dv/cosim/cosim_dpi.h b/dv/cosim/cosim_dpi.h index bbadbc5e3..f6df9ce27 100644 --- a/dv/cosim/cosim_dpi.h +++ b/dv/cosim/cosim_dpi.h @@ -23,6 +23,7 @@ void riscv_cosim_set_nmi(Cosim *cosim, svBit nmi); void riscv_cosim_set_nmi_int(Cosim *cosim, svBit nmi_int); void riscv_cosim_set_debug_req(Cosim *cosim, svBit debug_req); void riscv_cosim_set_mcycle(Cosim *cosim, svBitVecVal *mcycle); +void riscv_cosim_set_minstret(Cosim *cosim, svBitVecVal *minstret); void riscv_cosim_set_csr(Cosim *cosim, const int csr_id, const svBitVecVal *csr_val); void riscv_cosim_set_ic_scr_key_valid(Cosim *cosim, svBit valid); diff --git a/dv/cosim/cosim_dpi.svh b/dv/cosim/cosim_dpi.svh index 35ecd3b8c..4e8cea072 100644 --- a/dv/cosim/cosim_dpi.svh +++ b/dv/cosim/cosim_dpi.svh @@ -18,6 +18,7 @@ import "DPI-C" function void riscv_cosim_set_nmi(chandle cosim_handle, bit nmi); import "DPI-C" function void riscv_cosim_set_nmi_int(chandle cosim_handle, bit nmi_int); import "DPI-C" function void riscv_cosim_set_debug_req(chandle cosim_handle, bit debug_req); import "DPI-C" function void riscv_cosim_set_mcycle(chandle cosim_handle, bit [63:0] mcycle); +import "DPI-C" function void riscv_cosim_set_minstret(chandle cosim_handle, bit [63:0] minstret); import "DPI-C" function void riscv_cosim_set_csr(chandle cosim_handle, int csr_id, bit [31:0] csr_val); import "DPI-C" function void riscv_cosim_set_ic_scr_key_valid(chandle cosim_handle, bit valid); diff --git a/dv/cosim/spike_cosim.cc b/dv/cosim/spike_cosim.cc index 32537875e..a5d5caa24 100644 --- a/dv/cosim/spike_cosim.cc +++ b/dv/cosim/spike_cosim.cc @@ -750,6 +750,27 @@ void SpikeCosim::set_mcycle(uint64_t mcycle) { // to write all 64 bits at once at least. } +void SpikeCosim::set_minstret(uint64_t minstret) { + uint32_t upper_minstret = minstret >> 32; + uint32_t lower_minstret = minstret & 0xffffffff; + + // Spike decrements the MINSTRET CSR when you write to it. This is the same + // issue as with MCYCLE. See `set_mcycle` for more details. + + // Write the lower half first, incremented twice due to the double decrement + processor->get_state()->csrmap[CSR_MINSTRET]->write(lower_minstret + 2); + + if ((processor->get_state()->csrmap[CSR_MINSTRET]->read() & 0xffffffff) == + 0) { + // If the lower half is 0 at this point then the upper half will get + // decremented, so increment it first. + upper_minstret++; + } + + // Set the upper half + processor->get_state()->csrmap[CSR_MINSTRETH]->write(upper_minstret); +} + void SpikeCosim::set_csr(const int csr_num, const uint32_t new_val) { // Note that this is tested with ibex-cosim-v0.3 version of Spike. 'set_csr' // method might have a hardwired zero for mhpmcounterX registers. diff --git a/dv/cosim/spike_cosim.h b/dv/cosim/spike_cosim.h index 2849206e0..9fd603ee5 100644 --- a/dv/cosim/spike_cosim.h +++ b/dv/cosim/spike_cosim.h @@ -132,6 +132,7 @@ class SpikeCosim : public simif_t, public Cosim { void set_nmi_int(bool nmi_int) override; void set_debug_req(bool debug_req) override; void set_mcycle(uint64_t mcycle) override; + void set_minstret(uint64_t minstret) override; void set_csr(const int csr_num, const uint32_t new_val) override; void set_ic_scr_key_valid(bool valid) override; void notify_dside_access(const DSideAccessInfo &access_info) override; diff --git a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_cosim_scoreboard.sv b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_cosim_scoreboard.sv index f55e1936f..04f056150 100644 --- a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_cosim_scoreboard.sv +++ b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_cosim_scoreboard.sv @@ -151,6 +151,7 @@ class ibex_cosim_scoreboard extends uvm_scoreboard; riscv_cosim_set_nmi_int(cosim_handle, rvfi_instr.nmi_int); riscv_cosim_set_mip(cosim_handle, rvfi_instr.pre_mip, rvfi_instr.post_mip); riscv_cosim_set_mcycle(cosim_handle, rvfi_instr.mcycle); + riscv_cosim_set_minstret(cosim_handle, rvfi_instr.minstret); // Set performance counters through a pseudo-backdoor write for (int i=0; i < 10; i++) begin diff --git a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_monitor.sv b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_monitor.sv index 0bf50116e..d68b5222c 100644 --- a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_monitor.sv +++ b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_monitor.sv @@ -44,6 +44,7 @@ class ibex_rvfi_monitor extends uvm_monitor; trans_collected.debug_req = vif.monitor_cb.ext_debug_req; trans_collected.rf_wr_suppress = vif.monitor_cb.ext_rf_wr_suppress; trans_collected.mcycle = vif.monitor_cb.ext_mcycle; + trans_collected.minstret = vif.monitor_cb.ext_minstret; trans_collected.ic_scr_key_valid = vif.monitor_cb.ext_ic_scr_key_valid; for (int i=0; i < 10; i++) begin diff --git a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_seq_item.sv b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_seq_item.sv index dceba31c4..c8a6ee5fd 100644 --- a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_seq_item.sv +++ b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_seq_item.sv @@ -16,6 +16,7 @@ class ibex_rvfi_seq_item extends uvm_sequence_item; bit debug_req; bit rf_wr_suppress; bit [63:0] mcycle; + bit [63:0] minstret; bit [31:0] mhpmcounters [10]; bit [31:0] mhpmcountersh [10]; @@ -34,6 +35,7 @@ class ibex_rvfi_seq_item extends uvm_sequence_item; `uvm_field_int (debug_req, UVM_DEFAULT) `uvm_field_int (rf_wr_suppress, UVM_DEFAULT) `uvm_field_int (mcycle, UVM_DEFAULT) + `uvm_field_int (minstret, UVM_DEFAULT) `uvm_field_sarray_int (mhpmcounters, UVM_DEFAULT) `uvm_field_sarray_int (mhpmcountersh, UVM_DEFAULT) `uvm_field_int (ic_scr_key_valid, UVM_DEFAULT) diff --git a/dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv b/dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv index 0199b87f7..a3034dbf8 100644 --- a/dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv +++ b/dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv @@ -33,6 +33,7 @@ interface core_ibex_rvfi_if(input logic clk); logic [31:0] ext_debug_req; logic [31:0] ext_rf_wr_suppress; logic [63:0] ext_mcycle; + logic [63:0] ext_minstret; logic ext_irq_valid; logic [31:0] ext_mhpmcounters [10]; @@ -70,6 +71,7 @@ interface core_ibex_rvfi_if(input logic clk); input ext_debug_req; input ext_rf_wr_suppress; input ext_mcycle; + input ext_minstret; input ext_mhpmcounters; input ext_mhpmcountersh; input ext_ic_scr_key_valid; diff --git a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv index cb1ec5c57..b2f2c675d 100644 --- a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv +++ b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv @@ -249,6 +249,7 @@ module core_ibex_tb_top; assign rvfi_if.ext_debug_req = dut.rvfi_ext_debug_req; assign rvfi_if.ext_rf_wr_suppress = dut.rvfi_ext_rf_wr_suppress; assign rvfi_if.ext_mcycle = dut.rvfi_ext_mcycle; + assign rvfi_if.ext_minstret = dut.rvfi_ext_minstret; assign rvfi_if.ext_mhpmcounters = dut.rvfi_ext_mhpmcounters; assign rvfi_if.ext_mhpmcountersh = dut.rvfi_ext_mhpmcountersh; assign rvfi_if.ext_ic_scr_key_valid = dut.rvfi_ext_ic_scr_key_valid; diff --git a/rtl/ibex_core.sv b/rtl/ibex_core.sv index 85c623abc..0f0556c86 100644 --- a/rtl/ibex_core.sv +++ b/rtl/ibex_core.sv @@ -156,6 +156,7 @@ module ibex_core import ibex_pkg::*; #( output logic rvfi_ext_debug_mode, output logic rvfi_ext_rf_wr_suppress, output logic [63:0] rvfi_ext_mcycle, + output logic [63:0] rvfi_ext_minstret, output logic [31:0] rvfi_ext_mhpmcounters [10], output logic [31:0] rvfi_ext_mhpmcountersh [10], output logic rvfi_ext_ic_scr_key_valid, @@ -1316,6 +1317,7 @@ module ibex_core import ibex_pkg::*; #( logic rvfi_ext_stage_debug_req [RVFI_STAGES+1]; logic rvfi_ext_stage_debug_mode [RVFI_STAGES]; logic [63:0] rvfi_ext_stage_mcycle [RVFI_STAGES]; + logic [63:0] rvfi_ext_stage_minstret [RVFI_STAGES]; logic [31:0] rvfi_ext_stage_mhpmcounters [RVFI_STAGES][10]; logic [31:0] rvfi_ext_stage_mhpmcountersh [RVFI_STAGES][10]; logic rvfi_ext_stage_ic_scr_key_valid [RVFI_STAGES]; @@ -1384,6 +1386,7 @@ module ibex_core import ibex_pkg::*; #( assign rvfi_ext_debug_req = rvfi_ext_stage_debug_req [RVFI_STAGES]; assign rvfi_ext_debug_mode = rvfi_ext_stage_debug_mode [RVFI_STAGES-1]; assign rvfi_ext_mcycle = rvfi_ext_stage_mcycle [RVFI_STAGES-1]; + assign rvfi_ext_minstret = rvfi_ext_stage_minstret [RVFI_STAGES-1]; assign rvfi_ext_mhpmcounters = rvfi_ext_stage_mhpmcounters [RVFI_STAGES-1]; assign rvfi_ext_mhpmcountersh = rvfi_ext_stage_mhpmcountersh [RVFI_STAGES-1]; assign rvfi_ext_ic_scr_key_valid = rvfi_ext_stage_ic_scr_key_valid [RVFI_STAGES-1]; @@ -1607,6 +1610,7 @@ module ibex_core import ibex_pkg::*; #( rvfi_ext_stage_debug_req[i+1] <= '0; rvfi_ext_stage_debug_mode[i] <= '0; rvfi_ext_stage_mcycle[i] <= '0; + rvfi_ext_stage_minstret[i] <= '0; rvfi_ext_stage_ic_scr_key_valid[i] <= '0; rvfi_ext_stage_expanded_insn_valid[i] <= '0; rvfi_ext_stage_expanded_insn[i] <= '0; @@ -1661,6 +1665,7 @@ module ibex_core import ibex_pkg::*; #( rvfi_stage_mem_addr[i] <= rvfi_mem_addr_d; rvfi_ext_stage_debug_mode[i] <= debug_mode; rvfi_ext_stage_mcycle[i] <= cs_registers_i.mcycle_counter_i.counter_val_o; + rvfi_ext_stage_minstret[i] <= cs_registers_i.mhpmcounter[2]; rvfi_ext_stage_ic_scr_key_valid[i] <= cs_registers_i.cpuctrlsts_ic_scr_key_valid_q; rvfi_ext_stage_expanded_insn_valid[i] <= rvfi_expanded_insn_valid; rvfi_ext_stage_expanded_insn[i] <= rvfi_expanded_insn; @@ -1731,6 +1736,7 @@ module ibex_core import ibex_pkg::*; #( rvfi_ext_stage_debug_mode[i] <= rvfi_ext_stage_debug_mode[i-1]; rvfi_ext_stage_mcycle[i] <= rvfi_ext_stage_mcycle[i-1]; + rvfi_ext_stage_minstret[i] <= rvfi_ext_stage_minstret[i-1]; rvfi_ext_stage_ic_scr_key_valid[i] <= rvfi_ext_stage_ic_scr_key_valid[i-1]; rvfi_ext_stage_mhpmcounters[i] <= rvfi_ext_stage_mhpmcounters[i-1]; rvfi_ext_stage_mhpmcountersh[i] <= rvfi_ext_stage_mhpmcountersh[i-1]; diff --git a/rtl/ibex_lockstep.sv b/rtl/ibex_lockstep.sv index b0fb5ed7b..8f1b69c08 100644 --- a/rtl/ibex_lockstep.sv +++ b/rtl/ibex_lockstep.sv @@ -547,6 +547,7 @@ module ibex_lockstep import ibex_pkg::*; #( .rvfi_ext_debug_mode (), .rvfi_ext_rf_wr_suppress (), .rvfi_ext_mcycle (), + .rvfi_ext_minstret (), .rvfi_ext_mhpmcounters (), .rvfi_ext_mhpmcountersh (), .rvfi_ext_ic_scr_key_valid (), diff --git a/rtl/ibex_top.sv b/rtl/ibex_top.sv index 0f6419a89..99c72eb83 100644 --- a/rtl/ibex_top.sv +++ b/rtl/ibex_top.sv @@ -149,6 +149,7 @@ module ibex_top import ibex_pkg::*; #( output logic rvfi_ext_debug_mode, output logic rvfi_ext_rf_wr_suppress, output logic [63:0] rvfi_ext_mcycle, + output logic [63:0] rvfi_ext_minstret, output logic [31:0] rvfi_ext_mhpmcounters [10], output logic [31:0] rvfi_ext_mhpmcountersh [10], output logic rvfi_ext_ic_scr_key_valid, @@ -446,6 +447,7 @@ module ibex_top import ibex_pkg::*; #( .rvfi_ext_debug_mode, .rvfi_ext_rf_wr_suppress, .rvfi_ext_mcycle, + .rvfi_ext_minstret, .rvfi_ext_mhpmcounters, .rvfi_ext_mhpmcountersh, .rvfi_ext_ic_scr_key_valid, diff --git a/rtl/ibex_top_tracing.sv b/rtl/ibex_top_tracing.sv index 3823dd219..5e37cf80c 100644 --- a/rtl/ibex_top_tracing.sv +++ b/rtl/ibex_top_tracing.sv @@ -154,6 +154,7 @@ module ibex_top_tracing import ibex_pkg::*; #( logic rvfi_ext_debug_mode; logic rvfi_ext_rf_wr_suppress; logic [63:0] rvfi_ext_mcycle; + logic [63:0] rvfi_ext_minstret; logic [31:0] rvfi_ext_mhpmcounters [10]; logic [31:0] rvfi_ext_mhpmcountersh [10]; @@ -175,6 +176,7 @@ module ibex_top_tracing import ibex_pkg::*; #( logic unused_rvfi_ext_debug_mode; logic unused_rvfi_ext_rf_wr_suppress; logic [63:0] unused_rvfi_ext_mcycle; + logic [63:0] unused_rvfi_ext_minstret; logic unused_rvfi_ext_ic_scr_key_valid; logic unused_rvfi_ext_irq_valid; logic unused_rvfi_ext_expanded_insn_last; @@ -189,6 +191,7 @@ module ibex_top_tracing import ibex_pkg::*; #( assign unused_rvfi_ext_debug_mode = rvfi_ext_debug_mode; assign unused_rvfi_ext_rf_wr_suppress = rvfi_ext_rf_wr_suppress; assign unused_rvfi_ext_mcycle = rvfi_ext_mcycle; + assign unused_rvfi_ext_minstret = rvfi_ext_minstret; assign unused_perf_regs = rvfi_ext_mhpmcounters; assign unused_perf_regsh = rvfi_ext_mhpmcountersh; assign unused_rvfi_ext_ic_scr_key_valid = rvfi_ext_ic_scr_key_valid; @@ -305,6 +308,7 @@ module ibex_top_tracing import ibex_pkg::*; #( .rvfi_ext_debug_mode, .rvfi_ext_rf_wr_suppress, .rvfi_ext_mcycle, + .rvfi_ext_minstret, .rvfi_ext_mhpmcounters, .rvfi_ext_mhpmcountersh, .rvfi_ext_ic_scr_key_valid, From 2ea303de11841ef0cadceb381894d0436e069d92 Mon Sep 17 00:00:00 2001 From: Samuel Riedel Date: Tue, 12 May 2026 17:41:35 +0200 Subject: [PATCH 7/9] [dv] Add directed test for mcounteren lock signal --- .../directed_tests/directed_testlist.yaml | 439 +++++++++--------- .../core_ibex/directed_tests/gen_testlist.py | 9 + .../mcounteren_test/mcounteren_lock_test.S | 62 +++ .../core_ibex/env/core_ibex_dut_probe_if.sv | 5 +- dv/uvm/core_ibex/tb/core_ibex_tb_top.sv | 2 +- dv/uvm/core_ibex/tests/core_ibex_test_lib.sv | 41 ++ 6 files changed, 341 insertions(+), 217 deletions(-) create mode 100644 dv/uvm/core_ibex/directed_tests/mcounteren_test/mcounteren_lock_test.S diff --git a/dv/uvm/core_ibex/directed_tests/directed_testlist.yaml b/dv/uvm/core_ibex/directed_tests/directed_testlist.yaml index ec1adf8b1..8f41460b3 100644 --- a/dv/uvm/core_ibex/directed_tests/directed_testlist.yaml +++ b/dv/uvm/core_ibex/directed_tests/directed_testlist.yaml @@ -68,6 +68,15 @@ test_srcs: mcounteren_test/mcounteren_test.S config: riscv-tests +- test: mcounteren_lock_test + desc: > + Tests that mcounteren retains its value after mcounteren_writable_i is + de-asserted mid-simulation (write-lock). + iterations: 1 + rtl_test: core_ibex_mcounteren_lock_test + test_srcs: mcounteren_test/mcounteren_lock_test.S + config: riscv-tests + - test: pmp_mseccfg_test_rlb1_l0_0_u0 desc: > mseccfg test @@ -832,67 +841,228 @@ # Test-suite: riscv-arch-tests -- test: Fencei +- test: andn-01 desc: > - riscv test - Fencei + riscv test - andn-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/Zifencei/src/Fencei.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/andn-01.S config: riscv-arch-tests -- test: div-01 +- test: bclr-01 desc: > - riscv test - div-01 + riscv test - bclr-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/div-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/bclr-01.S config: riscv-arch-tests -- test: divu-01 +- test: bclri-01 desc: > - riscv test - divu-01 + riscv test - bclri-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/divu-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/bclri-01.S config: riscv-arch-tests -- test: mul-01 +- test: bext-01 desc: > - riscv test - mul-01 + riscv test - bext-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/mul-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/bext-01.S config: riscv-arch-tests -- test: mulh-01 +- test: bexti-01 desc: > - riscv test - mulh-01 + riscv test - bexti-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/mulh-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/bexti-01.S config: riscv-arch-tests -- test: mulhsu-01 +- test: binv-01 desc: > - riscv test - mulhsu-01 + riscv test - binv-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/mulhsu-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/binv-01.S config: riscv-arch-tests -- test: mulhu-01 +- test: binvi-01 desc: > - riscv test - mulhu-01 + riscv test - binvi-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/mulhu-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/binvi-01.S config: riscv-arch-tests -- test: rem-01 +- test: bset-01 desc: > - riscv test - rem-01 + riscv test - bset-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/rem-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/bset-01.S config: riscv-arch-tests -- test: remu-01 +- test: bseti-01 desc: > - riscv test - remu-01 + riscv test - bseti-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/remu-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/bseti-01.S + config: riscv-arch-tests + +- test: clmul-01 + desc: > + riscv test - clmul-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/clmul-01.S + config: riscv-arch-tests + +- test: clmulh-01 + desc: > + riscv test - clmulh-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/clmulh-01.S + config: riscv-arch-tests + +- test: clmulr-01 + desc: > + riscv test - clmulr-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/clmulr-01.S + config: riscv-arch-tests + +- test: clz-01 + desc: > + riscv test - clz-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/clz-01.S + config: riscv-arch-tests + +- test: cpop-01 + desc: > + riscv test - cpop-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/cpop-01.S + config: riscv-arch-tests + +- test: ctz-01 + desc: > + riscv test - ctz-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/ctz-01.S + config: riscv-arch-tests + +- test: max-01 + desc: > + riscv test - max-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/max-01.S + config: riscv-arch-tests + +- test: maxu-01 + desc: > + riscv test - maxu-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/maxu-01.S + config: riscv-arch-tests + +- test: min-01 + desc: > + riscv test - min-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/min-01.S + config: riscv-arch-tests + +- test: minu-01 + desc: > + riscv test - minu-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/minu-01.S + config: riscv-arch-tests + +- test: orcb_32-01 + desc: > + riscv test - orcb_32-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/orcb_32-01.S + config: riscv-arch-tests + +- test: orn-01 + desc: > + riscv test - orn-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/orn-01.S + config: riscv-arch-tests + +- test: rev8_32-01 + desc: > + riscv test - rev8_32-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/rev8_32-01.S + config: riscv-arch-tests + +- test: rol-01 + desc: > + riscv test - rol-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/rol-01.S + config: riscv-arch-tests + +- test: ror-01 + desc: > + riscv test - ror-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/ror-01.S + config: riscv-arch-tests + +- test: rori-01 + desc: > + riscv test - rori-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/rori-01.S + config: riscv-arch-tests + +- test: sext-b-01 + desc: > + riscv test - sext-b-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/sext-b-01.S + config: riscv-arch-tests + +- test: sext-h-01 + desc: > + riscv test - sext-h-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/sext-h-01.S + config: riscv-arch-tests + +- test: sh1add-01 + desc: > + riscv test - sh1add-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/sh1add-01.S + config: riscv-arch-tests + +- test: sh2add-01 + desc: > + riscv test - sh2add-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/sh2add-01.S + config: riscv-arch-tests + +- test: sh3add-01 + desc: > + riscv test - sh3add-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/sh3add-01.S + config: riscv-arch-tests + +- test: xnor-01 + desc: > + riscv test - xnor-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/xnor-01.S + config: riscv-arch-tests + +- test: zext-h_32-01 + desc: > + riscv test - zext-h_32-01 + iterations: 1 + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/zext-h_32-01.S config: riscv-arch-tests - test: add-01 @@ -1168,228 +1338,67 @@ test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/I/src/xori-01.S config: riscv-arch-tests -- test: andn-01 - desc: > - riscv test - andn-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/andn-01.S - config: riscv-arch-tests - -- test: bclr-01 - desc: > - riscv test - bclr-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/bclr-01.S - config: riscv-arch-tests - -- test: bclri-01 - desc: > - riscv test - bclri-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/bclri-01.S - config: riscv-arch-tests - -- test: bext-01 - desc: > - riscv test - bext-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/bext-01.S - config: riscv-arch-tests - -- test: bexti-01 - desc: > - riscv test - bexti-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/bexti-01.S - config: riscv-arch-tests - -- test: binv-01 - desc: > - riscv test - binv-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/binv-01.S - config: riscv-arch-tests - -- test: binvi-01 - desc: > - riscv test - binvi-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/binvi-01.S - config: riscv-arch-tests - -- test: bset-01 - desc: > - riscv test - bset-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/bset-01.S - config: riscv-arch-tests - -- test: bseti-01 - desc: > - riscv test - bseti-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/bseti-01.S - config: riscv-arch-tests - -- test: clmul-01 - desc: > - riscv test - clmul-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/clmul-01.S - config: riscv-arch-tests - -- test: clmulh-01 - desc: > - riscv test - clmulh-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/clmulh-01.S - config: riscv-arch-tests - -- test: clmulr-01 - desc: > - riscv test - clmulr-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/clmulr-01.S - config: riscv-arch-tests - -- test: clz-01 - desc: > - riscv test - clz-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/clz-01.S - config: riscv-arch-tests - -- test: cpop-01 - desc: > - riscv test - cpop-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/cpop-01.S - config: riscv-arch-tests - -- test: ctz-01 - desc: > - riscv test - ctz-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/ctz-01.S - config: riscv-arch-tests - -- test: max-01 - desc: > - riscv test - max-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/max-01.S - config: riscv-arch-tests - -- test: maxu-01 - desc: > - riscv test - maxu-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/maxu-01.S - config: riscv-arch-tests - -- test: min-01 - desc: > - riscv test - min-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/min-01.S - config: riscv-arch-tests - -- test: minu-01 - desc: > - riscv test - minu-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/minu-01.S - config: riscv-arch-tests - -- test: orcb_32-01 - desc: > - riscv test - orcb_32-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/orcb_32-01.S - config: riscv-arch-tests - -- test: orn-01 - desc: > - riscv test - orn-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/orn-01.S - config: riscv-arch-tests - -- test: rev8_32-01 - desc: > - riscv test - rev8_32-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/rev8_32-01.S - config: riscv-arch-tests - -- test: rol-01 - desc: > - riscv test - rol-01 - iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/rol-01.S - config: riscv-arch-tests - -- test: ror-01 +- test: div-01 desc: > - riscv test - ror-01 + riscv test - div-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/ror-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/div-01.S config: riscv-arch-tests -- test: rori-01 +- test: divu-01 desc: > - riscv test - rori-01 + riscv test - divu-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/rori-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/divu-01.S config: riscv-arch-tests -- test: sext-b-01 +- test: mul-01 desc: > - riscv test - sext-b-01 + riscv test - mul-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/sext-b-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/mul-01.S config: riscv-arch-tests -- test: sext-h-01 +- test: mulh-01 desc: > - riscv test - sext-h-01 + riscv test - mulh-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/sext-h-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/mulh-01.S config: riscv-arch-tests -- test: sh1add-01 +- test: mulhsu-01 desc: > - riscv test - sh1add-01 + riscv test - mulhsu-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/sh1add-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/mulhsu-01.S config: riscv-arch-tests -- test: sh2add-01 +- test: mulhu-01 desc: > - riscv test - sh2add-01 + riscv test - mulhu-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/sh2add-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/mulhu-01.S config: riscv-arch-tests -- test: sh3add-01 +- test: rem-01 desc: > - riscv test - sh3add-01 + riscv test - rem-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/sh3add-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/rem-01.S config: riscv-arch-tests -- test: xnor-01 +- test: remu-01 desc: > - riscv test - xnor-01 + riscv test - remu-01 iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/xnor-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/M/src/remu-01.S config: riscv-arch-tests -- test: zext-h_32-01 +- test: Fencei desc: > - riscv test - zext-h_32-01 + riscv test - Fencei iterations: 1 - test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/B/src/zext-h_32-01.S + test_srcs: ../../../../vendor/riscv-arch-tests/riscv-test-suite/rv32i_m/Zifencei/src/Fencei.S config: riscv-arch-tests - test: cadd-01 diff --git a/dv/uvm/core_ibex/directed_tests/gen_testlist.py b/dv/uvm/core_ibex/directed_tests/gen_testlist.py index f7a2ae7da..acb57867a 100644 --- a/dv/uvm/core_ibex/directed_tests/gen_testlist.py +++ b/dv/uvm/core_ibex/directed_tests/gen_testlist.py @@ -88,6 +88,15 @@ def add_configs_and_handwritten_directed_tests(): test_srcs: mcounteren_test/mcounteren_test.S config: riscv-tests +- test: mcounteren_lock_test + desc: > + Tests that mcounteren retains its value after mcounteren_writable_i is + de-asserted mid-simulation (write-lock). + iterations: 1 + rtl_test: core_ibex_mcounteren_lock_test + test_srcs: mcounteren_test/mcounteren_lock_test.S + config: riscv-tests + - test: pmp_mseccfg_test_rlb1_l0_0_u0 desc: > mseccfg test diff --git a/dv/uvm/core_ibex/directed_tests/mcounteren_test/mcounteren_lock_test.S b/dv/uvm/core_ibex/directed_tests/mcounteren_test/mcounteren_lock_test.S new file mode 100644 index 000000000..30f7fc251 --- /dev/null +++ b/dv/uvm/core_ibex/directed_tests/mcounteren_test/mcounteren_lock_test.S @@ -0,0 +1,62 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +# This test verifies the mcounteren write-lock mechanism by dynamically setting +# the mcounteren_writable_i hardware input. It validates that register updates +# are silently ignored while locked and succeed when unlocked, using immediate +# software readbacks to confirm the state. Inter-process signaling with the UVM +# testbench is achieved by monitoring writes to mcycle (lock command) and +# mcycleh (unlock command). + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32M +RVTEST_CODE_BEGIN + + # Initial Write (Unlocked) + li s0, 0x5 + csrw mcounteren, s0 + csrr t1, mcounteren + li t2, 0x5 + # If readback != 0x5, fail immediately + bne t1, t2, fail + + # Tell UVM to lock by writing to mcycle, which is monitored by the UVM + # testbench to set `mcounteren_writable` + csrw mcycle, x0 + + # Small delay loop to let the hardware pin force propagate + .rept 5 + nop + .endr + + # Try to overwrite mcounteren with 0x0 while locked + li s1, 0x0 + csrw mcounteren, s1 + csrr t1, mcounteren + bne t1, s0, fail + + # Tell UVM to unlock by writing to mcycleh + csrw mcycleh, x0 + + .rept 5 + nop + .endr + + # Try to overwrite it with 0x0 again. This time while unlocked + li s3, 0x0 + csrw mcounteren, s3 + csrr t1, mcounteren + bne t1, s3, fail + + # Success Exit + j pass + TEST_PASSFAIL + +RVTEST_CODE_END + +RVTEST_DATA_BEGIN + TEST_DATA +RVTEST_DATA_END diff --git a/dv/uvm/core_ibex/env/core_ibex_dut_probe_if.sv b/dv/uvm/core_ibex/env/core_ibex_dut_probe_if.sv index 2de5d8fff..a1e0bc8b1 100644 --- a/dv/uvm/core_ibex/env/core_ibex_dut_probe_if.sv +++ b/dv/uvm/core_ibex/env/core_ibex_dut_probe_if.sv @@ -18,6 +18,7 @@ interface core_ibex_dut_probe_if(input logic clk); logic dret; logic mret; ibex_pkg::ibex_mubi_t fetch_enable; + ibex_pkg::ibex_mubi_t mcounteren_writable; logic core_sleep; logic alert_minor; logic alert_major_internal; @@ -59,6 +60,7 @@ interface core_ibex_dut_probe_if(input logic clk); clocking dut_cb @(posedge clk); output fetch_enable; output debug_req; + output mcounteren_writable; input reset; input illegal_instr; input ecall; @@ -91,7 +93,8 @@ interface core_ibex_dut_probe_if(input logic clk); endclocking initial begin - debug_req = 1'b0; + debug_req = 1'b0; + mcounteren_writable = ibex_pkg::IbexMuBiOn; end `DV_CREATE_SIGNAL_PROBE_FUNCTION(signal_probe_rf_ren_a, rf_ren_a) diff --git a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv index b2f2c675d..9bc8754a1 100644 --- a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv +++ b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv @@ -169,7 +169,7 @@ module core_ibex_tb_top; .double_fault_seen_o (dut_if.double_fault_seen ), .fetch_enable_i (dut_if.fetch_enable ), - .mcounteren_writable_i (ibex_pkg::IbexMuBiOn ), + .mcounteren_writable_i (dut_if.mcounteren_writable ), .alert_minor_o (dut_if.alert_minor ), .alert_major_internal_o (dut_if.alert_major_internal), .alert_major_bus_o (dut_if.alert_major_bus ), diff --git a/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv b/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv index 5794dde7c..0186201c6 100644 --- a/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv +++ b/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv @@ -2025,3 +2025,44 @@ class core_ibex_assorted_traps_interrupts_debug_test extends core_ibex_directed_ endtask endclass + +class core_ibex_mcounteren_lock_test extends core_ibex_base_test; + `uvm_component_utils(core_ibex_mcounteren_lock_test) + `uvm_component_new + + virtual function void build_phase(uvm_phase phase); + super.build_phase(phase); + // Relaxes co-simulation tracking so mismatches during lock don't abort + cosim_cfg.relax_cosim_check = 1'b1; + endfunction + + virtual task send_stimulus(); + // Fork the binary execution in the background + fork + vseq.start(env.vseqr); + join_none + + // Wait for a write to MCYCLE to indicate locking the mcounteren CSRs + wait_for_live_csr_write(CSR_MCYCLE); + dut_vif.dut_cb.mcounteren_writable <= ibex_pkg::IbexMuBiOff; + `uvm_info(`gfn, "Write to MCYCLE: locking mcounteren!", UVM_LOW) + + // Wait for a write to MCYCLEH to indicate unlocking the mcounteren CSRs + wait_for_live_csr_write(CSR_MCYCLEH); + dut_vif.dut_cb.mcounteren_writable <= ibex_pkg::IbexMuBiOn; + `uvm_info(`gfn, "Write to MCYCLEH: unlocking mcounteren!", UVM_LOW) + endtask + + // Snoop the CSR interface to catch writes to the specified CSR addresses + task wait_for_live_csr_write(bit [11:0] addr); + forever begin + @(csr_vif.csr_cb); + if (csr_vif.csr_cb.csr_access === 1'b1 && + csr_vif.csr_cb.csr_addr === addr && + csr_vif.csr_cb.csr_op != CSR_OP_READ) begin + break; + end + end + endtask + +endclass From 8d4fc8ff7eccc75cae7469bb6c91fd78d082630f Mon Sep 17 00:00:00 2001 From: Samuel Riedel Date: Wed, 13 May 2026 11:41:39 +0200 Subject: [PATCH 8/9] [doc] Document the newly added performance counters --- doc/01_overview/compliance.rst | 4 ++++ doc/03_reference/performance_counters.rst | 20 ++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/doc/01_overview/compliance.rst b/doc/01_overview/compliance.rst index f9436be88..83a1c7aab 100644 --- a/doc/01_overview/compliance.rst +++ b/doc/01_overview/compliance.rst @@ -43,6 +43,10 @@ In addition, the following instruction set extensions are available. - 2.0 - always enabled + * - **"Zicntr" and "Zihpm": Extensions for Counters and Performance Monitoring** + - 2.0 + - always enabled + * - **Zifencei**: Instruction-Fetch Fence - 2.0 - always enabled diff --git a/doc/03_reference/performance_counters.rst b/doc/03_reference/performance_counters.rst index 35c347cd6..9225c8a64 100644 --- a/doc/03_reference/performance_counters.rst +++ b/doc/03_reference/performance_counters.rst @@ -3,10 +3,13 @@ Performance Counters ==================== -Ibex implements performance counters according to the RISC-V Privileged Specification, version 1.11 (see Hardware Performance Monitor, Section 3.1.11). +Ibex implements performance counters according to the RISC-V Privileged Specification, version 1.11 (see Hardware Performance Monitor, Section 3.1.11) and supports the **Zihpm** (Hardware Performance Counters) extension. The performance counters are placed inside the Control and Status Registers (CSRs) and can be accessed with the ``CSRRW(I)`` and ``CSRRS/C(I)`` instructions. -Ibex implements the clock cycle counter ``mcycle(h)``, the retired instruction counter ``minstret(h)``, as well as the 29 event counters ``mhpmcounter3(h)`` - ``mhpmcounter31(h)`` and the corresponding event selector CSRs ``mhpmevent3`` - ``mhpmevent31``, and the ``mcountinhibit`` CSR to individually enable/disable the counters. +Ibex implements the machine-mode clock cycle counter ``mcycle(h)``, the retired instruction counter ``minstret(h)``, as well as the 29 event counters ``mhpmcounter3(h)`` - ``mhpmcounter31(h)`` and the corresponding event selector CSRs ``mhpmevent3`` - ``mhpmevent31``, and the ``mcountinhibit`` CSR to individually enable/disable the counters. + +Additionally, Ibex implements the Zicntr and Zihpm extensions which provide User-mode (U-mode) aliases for these performance counters: ``cycle(h)``, ``instret(h)``, and ``hpmcounter3(h)`` - ``hpmcounter31(h)``. These aliases provide read-only access to the exact same underlying hardware counters configured in M-mode. + ``mcycle(h)`` and ``minstret(h)`` are always available and 64 bit wide. The ``mhpmcounter`` performance counters are optional (unavailable by default) and parametrizable in width. @@ -60,6 +63,19 @@ In particular, to enable/disable ``mcycle(h)``, bit 0 must be written. For ``min The lower 32 bits of all counters can be accessed through the base register, whereas the upper 32 bits are accessed through the ``h``-register. Reads to all these registers are non-destructive. +User-Mode Counter Access (mcounteren) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Access to the U-mode counter aliases (``cycle(h)``, ``instret(h)``, and ``hpmcounterX(h)``) is controlled via the Machine Counter-Enable CSR (``mcounteren``). This register can gate access to the counters from less privileged modes to prevent benchmarking the core if desired. + +* **Bit 0** controls access to ``cycle(h)``. +* **Bit 2** controls access to ``instret(h)``. +* **Bit X** controls access to ``hpmcounterX(h)``. + +When a bit in ``mcounteren`` is clear (0), any attempt to read the corresponding counter alias from U-mode will trigger an illegal instruction exception. + +To secure this mechanism, the ``mcounteren`` register can be locked against software modifications using a MUBI input signal called ``mcounteren_writeable``. When this signal disables writes, any attempt by software to modify the contents of ``mcounteren`` is ignored. + Parametrization at synthesis time --------------------------------- From fe789273413593e25df6ff29c75927da92f298ac Mon Sep 17 00:00:00 2001 From: Samuel Riedel Date: Wed, 13 May 2026 11:48:46 +0200 Subject: [PATCH 9/9] WIP [formal] Exclude u-mode counters from formal verification --- dv/formal/check/top.sv | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dv/formal/check/top.sv b/dv/formal/check/top.sv index dc5e6c8b6..53f6a06ab 100644 --- a/dv/formal/check/top.sv +++ b/dv/formal/check/top.sv @@ -163,7 +163,9 @@ NotDebug: assume property (!ibex_top_i.u_ibex_core.debug_mode & !debug_req_i); ConstantBoot: assume property (boot_addr_i == $past(boot_addr_i)); // 3. Always fetch enable FetchEnable: assume property (fetch_enable_i == IbexMuBiOn); -// 4. Never try to sleep if we couldn't ever wake up +// 4. Always have mcounteren writable +McounterenWritable: assume property (mcounteren_writable_i == IbexMuBiOn); +// 5. Never try to sleep if we couldn't ever wake up WFIStart: assume property (`IDC.ctrl_fsm_cs == SLEEP |-> ( `CSR.mie_q.irq_software | `CSR.mie_q.irq_timer | @@ -201,6 +203,7 @@ WFIStart: assume property (`IDC.ctrl_fsm_cs == SLEEP |-> ( logic [31:0] `X(mscratch); \ logic [31:0] `X(mepc); \ logic [63:0] `X(mcycle); \ + logic [63:0] `X(cycle); \ logic [31:0] `X(mshwmb); \ logic [31:0] `X(mshwm); \ logic [31:0] `X(mcounteren); \ @@ -442,13 +445,17 @@ logic ex_is_checkable_csr; assign ex_is_checkable_csr = ~( ((CSR_MHPMCOUNTER3H <= `CSR_ADDR) && (`CSR_ADDR <= CSR_MHPMCOUNTER31H)) | ((CSR_MHPMCOUNTER3 <= `CSR_ADDR) && (`CSR_ADDR <= CSR_MHPMCOUNTER31)) | + ((CSR_HPMCOUNTER3H <= `CSR_ADDR) && (`CSR_ADDR <= CSR_HPMCOUNTER31H)) | + ((CSR_HPMCOUNTER3 <= `CSR_ADDR) && (`CSR_ADDR <= CSR_HPMCOUNTER31)) | ((CSR_MHPMEVENT3 <= `CSR_ADDR) && (`CSR_ADDR <= CSR_MHPMEVENT31)) | (`CSR_ADDR == CSR_CPUCTRLSTS) | (`CSR_ADDR == CSR_SECURESEED) | (`CSR_ADDR == CSR_MIE) | (`CSR_ADDR == CSR_MCYCLE) | (`CSR_ADDR == CSR_MCYCLEH) | + (`CSR_ADDR == CSR_CYCLE) | (`CSR_ADDR == CSR_CYCLEH) | // TODO: (`CSR_ADDR == CSR_MINSTRET) | (`CSR_ADDR == CSR_MINSTRETH) | + (`CSR_ADDR == CSR_INSTRET) | (`CSR_ADDR == CSR_INSTRETH) | (`CSR_ADDR == CSR_MCOUNTINHIBIT) );