Level 64: The Short Path
The task
Goal: build the Fwd32 block (comparing rs numbers against rdM/rdW, EX/MEM priority over MEM/WB, x0 and lw-from-EX/MEM exceptions), extend IdEx32 with the rs1/rs2 numbers (+10 bits), and add EX operand muxes gated by fwd_en. The level-62 pipeline handled RAW dependencies with honest latency: an instruction read registers in ID while results were written in WB — the value arrived three cycles later, and a close dependency read garbage. You close the hazard with a short path — forwarding: the ALU result from EX/MEM and the write value from MEM/WB feed the next instruction's ALU inputs directly, bypassing the regfile. The manual run on the pipeline engine shows the difference: the golden pays no cycle for RAW, while "hardware with fwd_en=0" reads garbage. Acceptance is exact-step against the engine plus the fwd_en=0 negative.
The level-62 pipeline resolves RAW dependencies with honest latency: an instruction reads registers in ID and writes its result in WB — the value only arrives at distance 4. A close dependency reads garbage. You close the hazard with a short path — forwarding: the ALU result from EX/MEM and the write value from MEM/WB feed the next instruction's ALU inputs directly, bypassing the regfile.
This is a hardware level: editable files are pipetop.v, fwd.v, idex.v; the level-62 pipeline registers and all level-58 core blocks are read-only. Tasks:
- Extend IdEx32 to 165 bits. To the level-62 layout add the numbers
rs1N[9:5]andrs2N[4:0]— not the values, the numbers from Decoder32: the forwarding block will compare them. - Build Fwd32 (fwd.v). Compare the operand numbers against
rdM(EX/MEM) andrdW(MEM/WB):fwdX=01whenregWriteM & rdM!=0 & !memReadM,fwdX=10whenregWriteW & rdW!=0. Priority — EX/MEM over MEM/WB: the fresher value wins. Exceptions: x0 is never forwarded, lw from EX/MEM is not forwarded (the data is not there yet — level 65 fixes that). - Add the EX operand muxes. Per bit, three shoulders: the payload /
alu_yfrom EX/MEM /wdatafrom MEM/WB; every shoulder bit is gated byfwd_en. Use the forwarded values everywhere: Alu32, the eight I-modules, the alusrc mux, store_val. - Close distance 3. Distances 1–2 are covered by forwarding, 4+ by the regfile; distance 3 needs write-first: if
rdWbmatches the register being read andregWriteWholds, readwdataWbinstead of the regfile q (also underfwd_en). - Run against the golden. The manual run goes on the pipeline engine: the RAW program flows without bubbles (15 instructions, 19 cycles), and with
fwd_en=0the registers fill with garbage.
Solution for self-checking
Build it yourself first. The solution below is a checkpoint.
What you should get: exact-step against the pipeline golden passes: the RAW program runs without bubbles — 15 retirements, 19 cycles, nstall = 0, nflush = 0; the fwd_en = 0 negative keeps err = 0, but the registers must differ from the golden.
Step 1 — acceptance programs. A RAW program (distances 1–3, lw→use at distance 2), linear logic, and the fwd_en=0 negative (it must keep err=0 and change the registers — otherwise the unit is not in the datapath).
Step 2 — the Fwd32 comparators. Each one is 5 bits of xor+not and an and-tree. The EX/MEM shoulder: m1 = regWriteM & rdMnz & ~memReadM & eqM; the MEM/WB shoulder: m2 = regWriteW & rdWnz & eqW; the outputs: fwdX[0]=m1, fwdX[1]=m2 & ~m1 (the priority).
Step 3 — the muxes and the bypass. fwa0 = fwdA[0] & fwd_en, fwa1 = fwdA[1] & fwd_en, the zero shoulder ~(fwa0|fwa1); rs1F[b] = rs1E[b]&sel00 | aluYM[b]&fwa0 | wdataWb[b]&fwa1 (same for rs2F). Write-first: wf = eq(rdWb, rs) & weRfWb & fwd_en → the payload pack takes wdataWb instead of the regfile value.
Step 4 — the checkpoint numbers. The RAW program: 15 retires, 19 cycles (15 + 4 fill), no bubbles: nstall=0, nflush=0. Logic: 12/16. The fwd_en=0 negative: the program still halts normally on .end, but the registers must differ from the golden.
Check yourself
Why is lw from EX/MEM not forwarded?
At the EX/MEM stage only the address is ready — the data itself leaves memory at the end of MEM, so there is nothing to forward. The neighbour reading an lw result too early is saved by the level-65 bubble, not by Fwd32: the memReadM exception explicitly blocks the EX/MEM arm.