Skip to content

[hw] Pop a scalar FP result from FPU0 only - #125

Open
emiliengnr wants to merge 1 commit into
pulp-platform:mainfrom
emiliengnr:fix/fpu-scalar-out-ready
Open

[hw] Pop a scalar FP result from FPU0 only#125
emiliengnr wants to merge 1 commit into
pulp-platform:mainfrom
emiliengnr:fix/fpu-scalar-out-ready

Conversation

@emiliengnr

Copy link
Copy Markdown
Contributor

Hello, here is a pull request for a bug I found.

Problem

A scalar FP instruction followed by a vector FP instruction wedges the VFU, and before it wedges it
drops one VRF word of the vector result.

Scalar instructions go to fpnew lane 0 only (spatz_vfu.sv:1576):

assign int_fpu_in_valid = spatz_req_valid && operands_ready && (!spatz_req.op_arith.is_scalar || fpu == 0) && is_fpu_insn;

The output handshake has no matching term (spatz_vfu.sv:1630), out_ready_i is the shared
result_ready. It is computed from lane 0's tag, and for a scalar result pending_results covers
the low ELEN/8 bytes, so the gate closes on lane 0 alone and every lane pops. Lanes 1 to N-1 hold
the first word of the vector instruction that followed, and that word is lost. Lane 0 then trails by
one result. When the vector op reaches its last word only lane 0 holds it, the all-lane gate
&(result_valid | ~pending_results) can no longer close, and the write-back, the drain and the
response emit all stop. fpnew holds busy_o high on the unpopped result, so the FSM cannot leave
VFU_RunningFPU and the core hangs on the next dependent instruction.

A lane probe on a default build (n_fpu=4, ELEN=64), scalar VFADD at vl=1 then vector
VFMINMAX at vsew=EW_64 vl=8, otid the tag id at each lane output, LSB lane first:

rvalid=ffffffff rdy=1 gate=1 tag[id=0 wb=1 last=1] otid=0,2,2,2   scalar pop, lanes 1-3 lose vector word 0
rvalid=ffffffff rdy=1 gate=1 tag[id=2 wb=0 last=0] otid=2,2,2,2   mixed word write-back
rvalid=000000ff rdy=0 gate=0 tag[id=2 wb=0 last=1] otid=2,0,0,0   wedge, lane 0 alone holds the last word

Fix

Give the output handshake the lane term the input already has:

// Only the FPU0 retires scalar instructions
logic int_fpu_out_ready;
assign int_fpu_out_ready = result_ready && (!result_tag.wb || fpu == 0);

wired to .out_ready_i. Lane 0 drains its scalar result on its own and presents the vector word one
cycle later, then all lanes pop it together. Vector instructions are unaffected, their
result_tag.wb is 0.

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.

1 participant