Skip to content

Keep a finished divide in Execute when a flush arrives during StallM - #1925

Open
davidharrishmc wants to merge 5 commits into
openhwfoundation:mainfrom
davidharrishmc:dh/div-flush-stall
Open

davidharrishmc wants to merge 5 commits into
openhwfoundation:mainfrom
davidharrishmc:dh/div-flush-stall

Conversation

@davidharrishmc

@davidharrishmc davidharrishmc commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Merge together with #1941, which contains this PR's commits. The stall injector added here also exposes a bug #1941 fixes: during an injected stall, trap CSRs (mepc/mcause, sepc/scause/stval) can be written for a trap that is never taken. With this PR alone, lockstep can report such a mismatch at a test's final ecall when the injected stall lands there. Merging #1941 merges both; if this PR is merged first, merge #1941 immediately after.

A divide that the BTB predicts as a jump raises FlushE in its DONE cycle. If StallM held it in Execute, the divider FSMs went IDLE and the divide restarted with stale forwarded operands: 100/7 gave 0, and an fdiv could flip sign. The FSMs now reset only when the Execute pipeline register clears (FlushE & ~StallM, which equals FlushE & ~StallE because a flush clears the divider's own Execute stall), which also makes a coverage exclusion obsolete.

This is reachable only through ExternalStall (the RVVI packetizer in the FPGA builds). The PR therefore adds an opt-in testbench stall injector, triggered by the custom-use HINT slti x0, x0, imm, and two tests:

  • divflushstall on rv64gc, which divides on the FPU (fdivsqrtfsm.sv)
  • divflushstall32 on rv32gc, which uses the integer divider (div.sv)

rv64gc never exercises div.sv, and cvw had no RV32 coverage tests, so this adds tests/coverage32/, built by make coverage and run on rv32gc in regression-wally's nightly lockstep run; divflushstall32 reports a mismatch through tohost. It is a separate directory because the nightly lockstep run executes every ELF under tests/coverage/ on rv64gc. Part of #1921.

🤖 Generated with Claude Code

A divide mispredicted as a jump raises FlushE in its DONE cycle; when StallM
held it in Execute the divider FSM went IDLE and restarted with stale
operands.  Reset the FSMs only when Execute advances; add an opt-in
testbench ExternalStall injector and the divflushstall test.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: David Harris <David_Harris@hmc.edu>
davidharrishmc and others added 2 commits October 6, 2026 06:42
…v.sv on rv32gc

Use FlushE & ~StallE, matching flopenrc, which clears only when enabled.
rv64gc divides on the FPU, so add divflushstall32 for rv32gc to exercise
div.sv.  RV32 self-checking tests live in tests/coverage32 (built by
'make coverage', run by the self-checked coverage32gc suite) so the
nightly lockstep run over tests/coverage on rv64gc does not pick them up.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: David Harris <David_Harris@hmc.edu>
StallE equals StallM whenever FlushE is asserted: FlushECause masks the divider's own StallECause, and
LatestUnstalledE implies ~StallE.  FlushE & ~StallM is therefore the same condition, and it needs no new
StallE port through fpu, fdivsqrt, mdu, the core and testbench_fp.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: David Harris <David_Harris@hmc.edu>
davidharrishmc added a commit to davidharrishmc/cvw that referenced this pull request Oct 6, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: David Harris <David_Harris@hmc.edu>
Comment thread testbench/testbench.sv Outdated
{StallLength, StallDelay} <= InstrM[31:20];
else if (StallDelay != 0) StallDelay <= StallDelay - 1;
else if (StallLength != 0) StallLength <= StallLength - 1;
assign RVVIStall = (StallDelay == 0) & (StallLength != 0);

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.

Since we are repurposing the RVVIStall, would it make sense to rename this ExternalStall? It won't break my hardware RVVI because it uses it's own tb and top level.

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.

Good idea, done in b01c3bd. The testbench net is now ExternalStall, since it comes from either the RVVI wrapper or the stall injector. The wrapper's port keeps the name RVVIStall. #1930 has the same change merged in.

The net now has two drivers, the RVVI wrapper and the stall injector, so name
it after the core port it drives. rvvitbwrapper keeps its RVVIStall port.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: David Harris <David_Harris@hmc.edu>
davidharrishmc added a commit to davidharrishmc/cvw that referenced this pull request Oct 6, 2026
Brings in the ExternalStall rename of the testbench net.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: David Harris <David_Harris@hmc.edu>
@davidharrishmc
davidharrishmc marked this pull request as draft October 6, 2026 22:26
@davidharrishmc
davidharrishmc marked this pull request as ready for review October 6, 2026 22:27
…iv-flush-stall

Port the PR to main's ELF-based test flow:
- testbench/tests.vh is gone, so drop the coverage32gc list and its
  testbench.sv case; keep the ExternalStall injector and the
  RVVIStall -> ExternalStall wiring on main's testbench.
- tests/coverage/divflushstall.S runs from tests/coverage like the other
  coverage tests and reports through tohost via WALLY-selfcheck.h.
- tests/coverage32 is built by the root Makefile's coverage target (which
  regression-wally's buildTests uses), and regression-wally --nightly runs
  it on rv32gc in lockstep next to the rv32gc ACT tests, as it runs
  tests/coverage on rv64gc.
- divflushstall32.S reports failure to tohost ((2 << 1) | 1) instead of
  always storing 1, so a mismatch fails the run under main's convention.
- coverage-exclusions-rv64gc.do keeps main's /core scopes and drops the
  fdivsqrtfsm StallM exclusions that divflushstall now covers.

Signed-off-by: David Harris <David_Harris@hmc.edu>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
davidharrishmc added a commit to davidharrishmc/cvw that referenced this pull request Oct 10, 2026
…nhwfoundation#1895) into dh/wfi-wait

dh/div-flush-stall carries upstream/main through 20f2af7 (riscof retired,
openhwfoundation#1895), so this also brings dh/wfi-wait up to date with main.  Resolution:
- testbench/tests.vh is gone; the new wfi/trap tests run from
  tests/coverage like the other coverage tests and report through tohost
  via main's WALLY-selfcheck.h.
- lockstepwaivers keeps main's entries and adds wfiTW.elf,
  wfitimeoutint.elf and wfitimeoutnext.elf (matched by ELF file name);
  tests/coverage32 runs on rv32gc in nightly lockstep as in openhwfoundation#1925.
- csrc.sv keeps the taken-trap HPM events (TrapM & ~StallW) with main's
  division-cycles comment and exclusion in place of coverage off/on.
- coverage-exclusions-rv64gc.do takes main's version (/core scopes; the
  D$ SetValidEN/ClearValidEN exclusions whose comment this branch edited
  are gone on main) and drops the stale fdivsqrtfsm StallM exclusions
  that c7cbd78 had brought back although the exclusion tag is gone.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: David Harris <David_Harris@hmc.edu>
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.

2 participants