Skip to content

🐛 [dispatcher] RVV correctness fixes (#436, #452, #453, #460)#467

Open
saurav-fermions wants to merge 6 commits into
pulp-platform:mainfrom
Fermions-ASI:pr/dispatcher-fixes
Open

🐛 [dispatcher] RVV correctness fixes (#436, #452, #453, #460)#467
saurav-fermions wants to merge 6 commits into
pulp-platform:mainfrom
Fermions-ASI:pr/dispatcher-fixes

Conversation

@saurav-fermions

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

Copy link
Copy Markdown

Four dispatcher correctness fixes, each atomic and accompanied by a Spike-vs-Ara
differential reproducer (added under apps/, only main.c tracked).

Verification

Each fix has a reproducer checked against the Spike golden model (vmv_x_s_hazard,
vlseg_eew, vzext_vf8, vmerge_v0_illegal); all pass on the Verilated Ara model
at 2/4/8/16 lanes.

Checklist

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

Fixes #436
Fixes #452
Fixes #453
Fixes #460


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

vmv.x.s, vcpop.m and vfirst.m are decoded in the OPMVV path, where
use_vs1 defaults to 1'b1. For these instructions the rs1 field encodes
the sub-opcode rather than a vector register, so leaving use_vs1
asserted makes the main sequencer raise a spurious hazard against
whatever register number happens to occupy the rs1 field.

Clear use_vs1 in the VWXUNARY0 block, mirroring the sibling 6'b010100
(VMSBF/VMSOF/VMSIF) block that already does this.

Refs pulp-platform#436
Add a self-checking app that exercises the VWXUNARY0 spurious-vs1 hazard
(pulp-platform#436). vmv.x.s decodes with rs1 = 0, which a buggy dispatcher reads as a
false dependency on v0; the app writes v0 immediately before each
vmv.x.s reading an unrelated source, in a tight chain.

The dominant failure mode is serialization/deadlock rather than data
corruption: a hang is caught by the testbench cycle-timeout, while the
scalar read-back guards against result corruption. Build with
`make bin/vmv_x_s_hazard`; run on Spike (`make spike-run-vmv_x_s_hazard`)
or the Verilated model (`make simv app=vmv_x_s_hazard`).

Refs pulp-platform#436
The per-vreg EEW tracker (eew_d) only tagged EMUL consecutive registers
from the base vd. Segment loads/stores write (nf+1) groups of EMUL
registers, so vd+1..vd+nf kept the reset-default EW8; a later read at
the real EEW saw a mismatch and triggered an on-read reshuffle that
byte-packed the data across lanes.

Detect segment memory ops (VLE/VLSE/VLXE/VSE/VSSE/VSXE with nf != 0) and
tag (nf+1)*EMUL consecutive destination registers.

Verified with a Spike-vs-Ara differential (vlseg_eew, vlseg4e16 at
e16/m1, 4 lanes, VLEN=4096): after the fix Ara matches Spike on all four
fields {1,2,3,4},{11,12,13,14},{21,22,23,24},{31,32,33,34}.

Refs pulp-platform#453
VXUNARY0 VF8 set `eew_vs2 = eew_q[vs2]`, i.e. the source register's
last-written element width. When that tracked eew was wider than the
1/8-width view (e.g. the source was last written at e16), the ZExt8/SExt8
opqueue conversion - which only handles EW8 - falls through and the
operand is forwarded unconverted, producing a wrong result.

vf8 is only legal at SEW=e64, so the source elements are always EW8.
Force `eew_vs2 = EW8`, mirroring how VF4/VF2 already use the computed
narrower width rather than the tracked eew.

Verified against Spike: `vzext.vf8` of e16 0xa04f now yields
v14[0]=0x4f, v14[1]=0xa0 (Ara previously returned 0xa04f, 0).

Refs pulp-platform#452
A masked vector instruction's destination group must not overlap the mask
source v0 (RVV spec), unless it writes a mask or scalar result. vmerge and
vfmerge are always masked by v0 and write a full vector, so vd=v0 is
illegal. Ara executed it instead of trapping.

Raise illegal-instruction when the merge form (vm=0) targets vd=v0, across
the OPIVV/OPIVX/OPIVI integer encodings and the OPFVF float encoding. The
vmv.v.*/vfmv.v.f forms (vm=1) share the funct6 but are unmasked and remain
legal with vd=v0.

Verified against Spike with a trap probe: vmerge.vim v0, v20, -2, v0 now
traps with mcause=2 (illegal instruction), while the preceding legal
vmv.v.x v0 setup does not trap.

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