Skip to content

🐛 [vlsu/sequencer] Indexed-mem & OoO-retire fixes (#434,#456,#457)#471

Open
saurav-fermions wants to merge 4 commits into
pulp-platform:mainfrom
Fermions-ASI:pr/vlsu-sequencer-fixes
Open

🐛 [vlsu/sequencer] Indexed-mem & OoO-retire fixes (#434,#456,#457)#471
saurav-fermions wants to merge 4 commits into
pulp-platform:mainfrom
Fermions-ASI:pr/vlsu-sequencer-fixes

Conversation

@saurav-fermions

@saurav-fermions saurav-fermions commented Jun 20, 2026

Copy link
Copy Markdown

Three correctness fixes in the address generator / VLSU and the main sequencer,
each atomic and accompanied by a Spike-vs-Ara differential reproducer. Includes
the headline out-of-order-retire hazard fix (#434).

Verification

Reproducers vlxe_misalign_cause, vlxe_masked_misalign (e16/e32/e64), and
rar_retire_hazard are checked against the Spike golden model and pass at
2/4/8/16 lanes. For #434 the unfixed model was built to confirm the reproducer
fails (bad=168/256) and the fixed model matches Spike (bad=0); the fix is
measured cycle-for-cycle performance-neutral on imatmul.

Checklist

  • Automated tests pass — Spike-vs-Ara differential reproducers (added here)
  • Changelog updated
  • Code style guideline is observed

Fixes #434
Fixes #456
Fixes #457


Developed with SAIGE, Fermions' autonomous RTL/EDA debugging agent; root-caused, tested, and signed off by the submitter (@saurav-fermions).

An indexed memory element whose effective address is misaligned to its
EEW must raise a load/store address-misaligned exception (RVV spec) and
report the faulting effective address in [ms]tval. The addrgen instead
reported `riscv::ILLEGAL_INSTR` with tval=0, so software saw the wrong
mcause and lost the faulting address.

Set the exception cause to LD_ADDR_MISALIGNED / ST_ADDR_MISALIGNED based
on the access direction and forward the faulting virtual address
(idx_final_vaddr_q) as tval. The cause/tval already propagate to CVA6 via
ara_resp.exception. The load/store still has to be drained, so widen the
addrgen_illegal_load_o/store_o kill condition to also fire on the
misaligned cause (it is really a "kill faulted op" signal for the VLDU/
VSTU drain, not specific to illegal instructions).

Verified against Spike with a trap probe: unmasked vluxei32.v with a
base+1 index now traps with mcause=4 (LD_ADDR_MISALIGNED) and
mtval=faulting address (Ara previously reported mcause=2, mtval=0).

Refs pulp-platform#457
A masked indexed load/store must not raise a misalignment exception for an
element that is masked off: per the RVV spec, masked-off elements generate
neither exceptions nor architectural accesses. Ara trapped because the
address generator checked is_addr_error() per indexed element without any
visibility into the per-element mask.

Route the mask (peek-only; the load/store units still own the handshake) into
the addrgen. For a misaligned indexed element whose mask bit is 0, suppress
the exception, align the address down to the element width, and emit a normal
beat. The VLDU/VSTU already zero the byte strobes of masked-off elements, so
the element is dropped exactly like any other masked-off element and the
element accounting stays in sync.

The mask is resolved in the addrgen only when the whole vector fits within a
single mask chunk (vl <= elements-per-chunk); otherwise the conservative
trapping behaviour is kept, so there is no regression on multi-chunk vectors.

Verified against the Spike golden model (vlxe_masked_misalign, e16/e32/e64):
masked-off misaligned element no longer traps and keeps its old value, while
an active misaligned element still traps with LD_ADDR_MISALIGNED (cause=4).

Refs pulp-platform#456
…O retire

Ara issues in order but retires out of order. The main sequencer's read table
recorded only the *last* instruction reading each vector register, so a writer
built a WAR hazard against just that last reader. A slow earlier reader could
then be overtaken: once the last (fast) reader retired, the writer was allowed
to overwrite the register while the slow reader had not finished reading it,
so the slow reader observed the new value.

Example (the writer to v2 only waited for the fast vadd, not the slow vdivu):

    vdivu.vv v6, v4, v2   ; slow, reads v2
    vadd.vv  v8, v2, v2   ; fast, reads v2 -> overwrote the read-table entry
    vadd.vv  v2, v12, v12 ; writes v2 -> WAR only vs the fast vadd (bug)

Replace the "last reader id" per register with a per-register bitmask of every
in-flight reader (one bit per instruction id). The WAR build then ORs the whole
reader mask into the writer's hazards, so the writer waits for all pending
readers to retire. This is the maintainer's preferred fix (issue pulp-platform#434): it only
affects writers (no reader-reader serialization), so it does not slow down
read-heavy code such as matmul. The mask decays with vinsn_running, like the
previous valid bit. Writes still track only the last writer (serialized by WAW).

Verified against the Spike golden model with the rar_retire_hazard reproducer
(256-element e32/m2 divide + clobber): unfixed Ara returned 168/256 wrong
elements (sum=1040), the fixed model matches Spike (sum=2048, bad=0).
Regressions: dotproduct (reductions) and fmatmul both still pass.

Refs pulp-platform#434
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant