[rtl] Fix the minstret counter#2446
Open
SamuelRiedel wants to merge 2 commits into
Open
Conversation
The `wb_count_q` signal can become stale. It tracks whether the current or previous retired instruction increments the `instret` count. If there is a bubble before an `minstret` read, the counter will be updated, but `wb_count_q` and therefore `perf_instr_ret_wb_spec_o` will incorrectly suggest speculatively incrementing the counter further. This led to the `instret` counter being one instruction ahead every time we read it after a stall cycle. We fix this by validating `wb_count_q` and only incrementing speculatively if we actually have to. That is, when we are executing instructions back-to-back and the counter hasn't updated yet.
According to the Specification Section 6.1 CSR Instructions: Some CSRs, such as the instructions-retired counter, instret, may be modified as side effects of instruction execution. In these cases, if a CSR access instruction reads a CSR, it reads the value prior to the execution of the instruction. If a CSR access instruction writes such a CSR, the explicit write is done instead of the update from the side effect. In particular, a value written to instret by one instruction will be the value read by the following instruction.
Contributor
marnovandermaas
left a comment
There was a problem hiding this comment.
I think this implementation makes sense. If you would like to do the DV in the other pull request as well. Does it make sense to implement both minstret and mcounteren in the same pull request?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR resolves two different RTL issues that lead to inaccurate
instretcounts.Fix
minstretupdate after explicit write:Previously, a write to
minstretwould set the value in the ID stage and then increment it in the WB stage again. This doesn't match the RISC-V Specification Section 6.1:Fix speculative
minstretincrement:Prevents over-counting by validating the
wb_count_qsignal. This ensures the counter is only speculatively incremented during back-to-back instruction execution, fixing a bug where stale signals caused the counter to jump ahead after a stall cycle.The following figures explain the behavior. We are looking at the relevant signals for two back to back CSR reads of
minstretafter some stall cycles (empty WB stage). The counter is initially on0x3cretired instructions. The CSRs are read in cycle 2 & 3.Previous behavior
Both CSR reads return the same value (
0x3d). Wheneverinstr_ret_specis set, we read theminstret_nextvalue (the counter's increment) because we assume that there is an instruction retiring in the WB stage ahead of us. Otherwise, we read theminstret_rawsignal (the current counter value).instr_ret_specwas previously directly connected towb_count_qand therefore, we would always read the incremented value, because this just stores whether the current/last instruction in the WB stage counted towards theinstretcount. The counter increment is triggered byinstr_ret, which happens in cycle 3 for the first CSR read and the counter stores the increment in cycle 4. Note that if we read the counter again in cycle 5, the counter already reads0x3feven though there is no instruction in the WB stage retiring and we only retired0x3einstructions by then.Fixed behavior
We now validate
instr_ret_specwithwb_valid_q. This invalidates it in the first cycles, when the WB stage is empty, and readingminstretreturns the actual counter value0x3cin cycle 2. In cycle 3, the previous read is retiring, but the counter did not have time to update and will do so in the next cycle. Nowinstr_ret_specis set and we read the speculative/incremented counter value0x3din our second read. Similarly, in cycle 4 we would read the incremented value because the second read is retiring. In cycle 5 we would again see the counters unmodified value since it had a change to update after the last instruction retired.Verification
The current CSR tests seem to exclude the cosim and focus on making sure that the access behavior/rights is correct but not the counter value. Since we noticed this bug when adding verification for the
mcounterenCSR where we access and compare theminstretwith the cosim enabled, I extended that test to verify both testcases. This test was able to catch both of those errors together with the cosim. In the future, a fully randomzied test would be ideal.I suggest we use #2403 for the verification for now instead of waiting with those fixes until we have a full blown DV environment for the
minstret.