Skip to content

Add mcounteren register#2403

Open
SamuelRiedel wants to merge 12 commits into
lowRISC:masterfrom
SamuelRiedel:mcounteren
Open

Add mcounteren register#2403
SamuelRiedel wants to merge 12 commits into
lowRISC:masterfrom
SamuelRiedel:mcounteren

Conversation

@SamuelRiedel
Copy link
Copy Markdown
Contributor

@SamuelRiedel SamuelRiedel commented May 11, 2026

This PR adds the mcounteren register, which has so far been tied to zero and implements the U-mode performance counter aliases. The mcounteren register can be locked with an external MUBI signal (mcounteren_writable_i).

DV:
This PR adds two directed tests:

  • mcounteren_test goes through multiple configurations of the mcounteren register and validates that u-mode can only access the ones enabled.
  • mcounteren_lock_test verifies that the mcounteren CSR cannot be modified without the mcounteren_writable_i signal being set.

To Dos:

  • For the directed tests and the cosim to pass, we have to update riscv-isa-sim to also support those performance counters: Enable ZIHPM unpriviledged performance counters riscv-isa-sim#29
  • Currently, u-mode counter reads will lead to illegal instruction exceptions. However, we are not gating the value at the CSR module's interface for simplicity. The signal will not leave the core, but we should double-check that this is no security issue.
  • The dv/uvm/core_ibex/directed_tests/directed_testlist.yaml changes a lot everytime I regenerate it after even small modifications. This polluted the diff quite a bit. Is this expected?

resolves #1973
fixes #2312

Copy link
Copy Markdown
Contributor

@gautschimi gautschimi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look all good to me! Just a few minor comments. (I did not look at the two WIP commits about formal)

Comment thread rtl/ibex_cs_registers.sv
Comment thread rtl/ibex_top.sv
Comment thread dv/uvm/core_ibex/directed_tests/mcounteren_test/mcounteren_test.S
Comment thread dv/uvm/core_ibex/directed_tests/directed_testlist.yaml
@SamuelRiedel
Copy link
Copy Markdown
Contributor Author

I disabled the check of the mcounteren CSR in the formal verification for now. Another reason for the failure of the formal verification was that we ran out of memory on the runner that has twice as many cores but half as much memory available. I'll address this in a separate PR and rebase once merged.

Copy link
Copy Markdown
Contributor

@gautschimi gautschimi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

I mostly looked at RTL, but the changes in python, C, yaml, etc. look also good to me!

The set created a random order of the tests. So small modifications or
additions to the testlist polluted the diff. Fixing the order in a list
makes the output deterministic.

I swapped the order of the tests to match the current output order of
the testlist to avoid a diff.
Copy link
Copy Markdown
Contributor

@marnovandermaas marnovandermaas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're adding an extension do we need to do an update of ISA strings that are passed to compilers?

Comment thread rtl/ibex_cs_registers.sv

// mcounteren: machine counter enable (controls U-mode counter access)
logic [31:0] mcounteren;
logic [MHPMCounterNum+3-1:0] mcounteren_d, mcounteren_q;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It probably makes sense to have at least a local parameter with the 3 offset since this is shared with the mcountinhibit above.

Comment thread rtl/ibex_pkg.sv
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I double checked this mapping and I think they are right.

Comment thread dv/formal/check/top.sv

// CPU Control Signals
input ibex_mubi_t fetch_enable_i,
input ibex_mubi_t mcounteren_writable_i,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the point of making this an input as opposed to a parameter? Is there a use-case to be able to switch this dynamically during runtime?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. This allows locking the mcounteren in a certain configuration. For example, the boot code could enable only the instret counter to be accessible to the user mode and then lock it to prevent the software from switching it later and use other counters to profile the core. This option, gives us the most flexibility and security.

Comment thread ci/vars.env
# end up as float otherwise).
VERILATOR_VERSION=v4.210
IBEX_COSIM_VERSION=6d5b660
IBEX_COSIM_VERSION=aadf648
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bump adds ZIHPM extension to Spike but it also pulls in the Zc* extensions. Is there any risk in that inclusion?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. But that will be fine, because we anyway already have the Zc* extension in the RTL. Only the DV is not fully merged yet, but already having Spike support those extensions will not hurt.

Copy link
Copy Markdown
Contributor

@marnovandermaas marnovandermaas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realised there are some more commits so here are some more comments. Very good work on this and please disregard my previous mention that the docs needed updating.


if 'riscv-arch-tests' in test_suite_list or test_suite == 'all':
arch_tests = {'rv32i_m/B/src', 'rv32i_m/C/src', 'rv32i_m/I/src', 'rv32i_m/M/src', 'rv32i_m/Zifencei/src'}
arch_tests = ['rv32i_m/M/src', 'rv32i_m/C/src', 'rv32i_m/Zifencei/src', 'rv32i_m/I/src', 'rv32i_m/B/src']
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit extra space here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding this test, very useful!

Comment thread dv/cosim/cosim.h

// Set the value of minstret.
//
// The co-simulation model doesn't alter the value of minstret itself (other
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How come this is true? Spike should have all the information it needs to calculate minstret right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. And it does, the Spike counter is just lagging one instruction behind Ibex. It should match though, so I'll investigate a bit more...

li s1, 0x0
csrw mcounteren, s1
csrr t1, mcounteren
bne t1, s0, fail
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be s1?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because in this instance, the register should be locked. So the csrw mcounteren, s1 must have no effect. So the read should return the previous write value.

li s1, 0x0
csrw mcounteren, s1
csrr t1, mcounteren
bne t1, s0, fail
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also shouldn't this one fail if it is equal?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, they are both the same lines you commented. So here we either fail if:

  • The current value is not equal to the previous value (s0=0x5) from before we locked it and tried to change it to s1=0
  • The current value is equal to s1=0, because this means that the write was successful despite the locking.

I decided to do the first to also catch behaviour where the overwrite had some sort of effect, like changing just a few bits to zero.


endclass

class core_ibex_mcounteren_lock_test extends core_ibex_base_test;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding this test, this is great!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug,TestFW] Zicntr in CoSim not compliant with the standard [rtl] Implement cycle/instret/time/hmpcountern CSRs

3 participants