Showing a debug halt let a register write slip through
A closed bug report on a RISC-V core: a control register write went through while debug halted the core. We reproduced it and proved the maintainers' fix holds.
1The issue
CSRs are the control and status registers that hold the core's settings. The report said the core updated the mscratch register when a debug request interrupted a CSR instruction. When debug stops the core, that instruction is cancelled and run again after debug ends. So the register could be written twice, or written when the write was meant to be cancelled.
The points on the issue
2What we did
- 1Read the design and found the cause: the CSR write was not blocked by the halt signal debug uses to stop the last pipeline stage.
- 2Wrote two rules on the CSR write port and ran them with formal verification, which checks every reachable state, on the design before the fix. The second rule failed at step 8.
- 3Ran both rules on the current design. They hold for every reachable state, and a bounded check 30 steps deep also passes. The halted CSR instruction is still reached, so the proof is meaningful. Only the write is blocked.
- 4Read the fix by the core's maintainers only after the proof. It adds the same halt condition our failing rule checks.
3Result
The bug is reproduced on the design before the fix, and both rules hold on the current design. The failing case shows the bug does not depend on which register is written.
The core's maintainers wrote the fix, and we checked it only against our own checks, not the wider test suite.
Have a bug like this one?
Describe the problem in a few lines. An engineer replies, and we agree the scope together.
Discuss a verification problem