§ 4.6.1. Operand Forwarding¶
Forwarding supplies an older instruction's result before its register-file write becomes visible to a younger instruction. It does not read back the younger instruction's own writes.
| Component | Description | Structural | Behavioral |
|---|---|---|---|
RV32IForwardingUnit |
Two register comparisons with newest-producer priority | Yes | Yes |
RV32IDecodeStage |
Decode/register read with WB bypass and load-use detection | Yes | Yes |
RV32IExecuteStage |
Forwarded operands around the shared execution datapath | Yes | Yes |
RV32IWritebackBypass |
Internal Decode selector for a matching, valid WB destination | Yes | Via enclosing stage |
RV32IForwardedOperands |
Internal selector and two operand muxes | Yes | Via enclosing stage |
RV32IExecutePacketStatus |
Internal terminal/redirect qualification gates | Yes | Via enclosing stage |
Forwarding-unit IO pins¶
| Pin | Direction | Width | Description |
|---|---|---|---|
ID_EX_RS1, ID_EX_RS2 |
Input | 5 each | Execute's source register numbers |
EX_MEM_RD, MEM_WB_RD |
Input | 5 each | Producer destinations |
EX_MEM_VALID, MEM_WB_VALID |
Input | 1 each | Producer slot contains an instruction |
EX_MEM_REG_WRITE, MEM_WB_REG_WRITE |
Input | 1 each | Producer writes a register |
EX_MEM_RESULT_READY |
Input | 1 | EX/MEM has a usable ALU/link result, not a pending load |
FORWARD_A, FORWARD_B |
Output | 2 each | 0: captured operand; 1: EX/MEM; 2: MEM/WB; 3 unused |
Behavior¶
For each source, a matching valid EX/MEM writer wins over MEM/WB. If that newer producer is not ready, select the captured operand—not an older WB value for the same register. The load-use interlock prevents the consumer from using that unavailable value in normal execution. Destination x0 never forwards.
The same selected RS2 feeds both ALU input selection and store data. Forwarded operands also feed branch comparisons and JALR target calculation. Decode uses a dedicated WB bypass: two source-register comparisons and two 2:1 data muxes. WB's value can therefore reach an instruction entering ID/EX on the very edge that commits WB.
C++ example¶
Producer.ready matters only for EX/MEM. Packet, the binary ALU, target selection and status checks come from 4.5.4. Captured x0 operands are zero by the register-file contract.
struct Producer { bool valid,write,ready; unsigned rd; uint32_t value; };
inline unsigned forward_select(unsigned source,Producer ex,Producer wb) {
source&=31;
if(ex.valid&&ex.write&&(ex.rd&31)&&((ex.rd&31)==source)) return ex.ready?1:0;
if(wb.valid&&wb.write&&(wb.rd&31)&&((wb.rd&31)==source)) return 2;
return 0;
}
inline uint32_t forwarded(unsigned source,uint32_t captured,Producer ex,Producer wb) {
switch(forward_select(source,ex,wb)) {
case 1:return ex.value; case 2:return wb.value; default:return captured;
}
}
inline baseline_example::StageResult execute(Packet p,Producer ex,Producer wb) {
using namespace rv32i::pipeline_encoding;
p.rs1_value=forwarded(rs1(p.addresses),p.rs1_value,ex,wb);
p.rs2_value=forwarded(rs2(p.addresses),p.rs2_value,ex,wb);
return baseline_example::execute(p); // The same ALU/target/status contract as 4.5.4.
}
Stage-interface changes¶
The common packet inputs/outputs retain the baseline Decode and Execute field meanings. TERMINAL on the advanced Execute interface is named PRETERMINAL; the baseline's CONTROL_FLOW output is replaced by the more specific signals below.
| Stage | Additional or changed pins | Width | Meaning |
|---|---|---|---|
| Decode input | WB_VALID, WB_REG_WRITE, WB_REGISTER_WRITE |
1 each | WB packet/write intent for bypass; qualified edge write for the register file |
| Decode input | EX_VALID, EX_CONTROL, EX_REGISTER_ADDRESSES |
1, 32, 32 | Current Execute producer for load-use detection |
| Decode output | LOAD_USE_HAZARD, TERMINAL |
1 each | Interlock and valid early-terminal instruction |
| Execute input | EX_MEM_VALID, EX_MEM_REG_WRITE, EX_MEM_RESULT_READY, MEM_WB_VALID, MEM_WB_REG_WRITE |
1 each | Forwarding qualifications |
| Execute input | EX_MEM_RD, MEM_WB_RD |
5 each | Producer destinations |
| Execute input | EX_MEM_VALUE, MEM_WB_VALUE |
32 each | Forwardable values |
| Execute output | IS_BRANCH, BRANCH_TAKEN |
1 each | Conditional-branch kind and actual condition; validity is qualified by recovery |
| Execute output | REDIRECT, PRETERMINAL |
1 each | Valid selected control transfer; valid early-terminal instruction |
| Execute output | REDIRECT_PC |
32 | Actual next PC, including fallthrough |
| Execute output | CONTROL_TARGET, CONTROL_TAKEN |
32, 1 | Candidate branch/jump destination and its selection, before the next-PC mux; paired with OUT_PC_PLUS_4 for parallel recovery comparisons |
Decode retains CLK, RST, WB_RD<5> and WB_VALUE<32>. Its register-file write input is WB_REGISTER_WRITE, not the baseline's REGISTER_WRITE. Execute remains combinational. The core uses prediction mismatch, not Execute's compatibility REDIRECT output, to decide whether to flush.
Implementation¶
Structural implementation¶
Execute's main groups are FORWARDED_OPERANDS, DATAPATH, NEXT_PC, and PACKET_STATUS. DATAPATH is the same selectable single-cycle execution component used by the baseline: one ALU32 for arithmetic, address calculation, comparison, and JAL/JALR targets. The separate PC+immediate adder is needed alongside a conditional-branch comparison; PC+4 uses an incrementer. There is no duplicate RS1+immediate target adder.
The forwarding selector uses five-bit equality networks, nonzero checks and priority gates. Decode's WB_BYPASS child is RV32IWritebackBypass: it compares RS1 and RS2 with WB_RD (five bits each) and asserts its one-bit SELECT_A/SELECT_B outputs only when WB_VALID, WB_REG_WRITE, a nonzero destination, and the corresponding match hold. The two 32-bit muxes then select WB_VALUE. Muxes select values without storing them. Packet/status rewiring stays separate from the datapath.
Behavioral implementation¶
The selector computes the same priority equations; the stage evaluates forwarded operands through the equivalent ALU and next-PC rules. The two internal grouping components have no separately registered behavioral variant: selecting the enclosing stage's behavior replaces their assembly.
Examples¶
The selector rows cover both sources, competing producers, x0, invalid producers, and a younger unready producer hiding WB. Execute rows also show forwarded branch operands and shared-ALU JAL/JALR targets.
All 7 recorded rows of RV32IForwardingUnitTest, in checkpoint order. Outputs are test expectations verified against the simulation. Time is the absolute settled checkpoint time in simulator units, not milliseconds or CPU cycles.
Default scenario profile: rv32i-component-preview-preview / structural (a5a83c6c721cd53c). Changing fidelity or the circuit can change these times.
| Checkpointzero-based number · timeline label | Timesimulator units | EX_MEM_RDInput · 5 bit |
EX_MEM_REG_WRITEInput · 1 bit |
EX_MEM_RESULT_READYInput · 1 bit |
EX_MEM_VALIDInput · 1 bit |
ID_EX_RS1Input · 5 bit |
ID_EX_RS2Input · 5 bit |
MEM_WB_RDInput · 5 bit |
MEM_WB_REG_WRITEInput · 1 bit |
MEM_WB_VALIDInput · 1 bit |
FORWARD_AExpected output · 2 bit |
FORWARD_BExpected output · 2 bit |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
#0no-producer | 7 | 0x00 |
0 |
0 |
0 |
0x01 |
0x02 |
0x00 |
0 |
0 |
0x0 |
0x0 |
#1ex-forwards-both | 17 | 0x05 |
1 |
1 |
1 |
0x05 |
0x05 |
0x00 |
0 |
0 |
0x1 |
0x1 |
#2mem-forwards-both | 26 | 0x00 |
0 |
0 |
0 |
0x07 |
0x07 |
0x07 |
1 |
1 |
0x2 |
0x2 |
#3newest-producer-wins | 36 | 0x08 |
1 |
1 |
1 |
0x08 |
0x08 |
0x08 |
1 |
1 |
0x1 |
0x1 |
#4unready-newest-blocks-stale-value | 40 | 0x09 |
1 |
0 |
1 |
0x09 |
0x09 |
0x09 |
1 |
1 |
0x0 |
0x0 |
#5independent-operands | 50 | 0x0A |
1 |
1 |
1 |
0x0A |
0x0B |
0x0B |
1 |
1 |
0x1 |
0x2 |
#6x0-never-forwards | 59 | 0x00 |
1 |
1 |
1 |
0x00 |
0x00 |
0x00 |
1 |
1 |
0x0 |
0x0 |
Scroll within the table for all rows and pins. Buses use hexadecimal; values containing X/Z use MSB-first binary. Inputs show the declared values in effect at each checkpoint, including retained inputs. Sequential tests also replay preparation changes between checkpoints, such as lowering the clock. Use the matching checkpoint label in the simulation below.
All 7 recorded rows of RV32IExecuteStageTest, in checkpoint order. Outputs are test expectations verified against the simulation. Time is the absolute settled checkpoint time in simulator units, not milliseconds or CPU cycles.
Default scenario profile: rv32i-component-preview-preview / structural (1766858467d25ef7). Changing fidelity or the circuit can change these times.
| Checkpointzero-based number · timeline label | Timesimulator units | EX_MEM_RDInput · 5 bit |
EX_MEM_REG_WRITEInput · 1 bit |
EX_MEM_RESULT_READYInput · 1 bit |
EX_MEM_VALIDInput · 1 bit |
EX_MEM_VALUEInput · 32 bit |
IN_CONTROLInput · 32 bit |
IN_FETCH_STATUSInput · 32 bit |
IN_IMMEDIATEInput · 32 bit |
IN_INSTRUCTIONInput · 32 bit |
IN_PCInput · 32 bit |
IN_REGISTER_ADDRESSESInput · 32 bit |
IN_RS1_VALUEInput · 32 bit |
IN_RS2_VALUEInput · 32 bit |
IN_VALIDInput · 1 bit |
MEM_WB_RDInput · 5 bit |
MEM_WB_REG_WRITEInput · 1 bit |
MEM_WB_VALIDInput · 1 bit |
MEM_WB_VALUEInput · 32 bit |
BRANCH_TAKENExpected output · 1 bit |
CONTROL_TAKENExpected output · 1 bit |
CONTROL_TARGETExpected output · 32 bit |
IS_BRANCHExpected output · 1 bit |
OUT_ALU_RESULTExpected output · 32 bit |
OUT_CONTROLExpected output · 32 bit |
OUT_EXECUTION_STATUSExpected output · 32 bit |
OUT_FETCH_STATUSExpected output · 32 bit |
OUT_INSTRUCTIONExpected output · 32 bit |
OUT_NEXT_PCExpected output · 32 bit |
OUT_PCExpected output · 32 bit |
OUT_PC_PLUS_4Expected output · 32 bit |
OUT_REGISTER_ADDRESSESExpected output · 32 bit |
OUT_STORE_DATAExpected output · 32 bit |
OUT_VALIDExpected output · 1 bit |
PRETERMINALExpected output · 1 bit |
REDIRECTExpected output · 1 bit |
REDIRECT_PCExpected output · 32 bit |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
#0addi | 36 | 0x00 |
0 |
0 |
0 |
0x00000000 |
0x20001283 |
0x00000000 |
0x00000005 |
0x00508193 |
0x00000100 |
0x00000CA1 |
0x00000007 |
0x00000000 |
1 |
0x00 |
0 |
0 |
0x00000000 |
0 |
not checked | not checked | 0 |
0x0000000C |
not checked | 0x00000000 |
not checked | not checked | 0x00000104 |
0x00000100 |
0x00000104 |
not checked | 0x00000000 |
1 |
0 |
0 |
not checked |
#1ex-forwarding | 78 | 0x01 |
1 |
1 |
1 |
0x00000014 |
0x20001283 |
0x00000000 |
0x00000005 |
0x00508193 |
0x00000100 |
0x00000CA1 |
0x00000007 |
0x00000000 |
1 |
0x00 |
0 |
0 |
0x00000000 |
not checked | not checked | not checked | not checked | 0x00000019 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#2taken-branch | 121 | 0x00 |
0 |
0 |
0 |
0x00000000 |
0x00403181 |
0x00000000 |
0x00000008 |
0x00208463 |
0x00000200 |
0x00002041 |
0x00000004 |
0x00000004 |
1 |
0x00 |
0 |
0 |
0x00000000 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked | 0x00000208 |
not checked | not checked | not checked | not checked | not checked | 0 |
1 |
0x00000208 |
#3wb-branch-forwarding | 173 | 0x00 |
0 |
0 |
0 |
0x00000000 |
0x00403181 |
0x00000000 |
0x00000008 |
0x00208463 |
0x00000200 |
0x00002041 |
0x00000004 |
0x00000009 |
1 |
0x01 |
1 |
1 |
0x00000009 |
1 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#4younger-unready-blocks-old-wb | 217 | 0x01 |
1 |
0 |
1 |
0x00000000 |
0x00403181 |
0x00000000 |
0x00000008 |
0x00208463 |
0x00000200 |
0x00002041 |
0x00000004 |
0x00000009 |
1 |
0x01 |
1 |
1 |
0x00000009 |
0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked | 0x00000204 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#5jal-shares-alu | 248 | 0x00 |
0 |
0 |
0 |
0x00000000 |
0x28011603 |
0x00000000 |
0x00000008 |
0x008000EF |
0x00000100 |
0x00000500 |
0x00000000 |
0x00000000 |
1 |
0x00 |
0 |
0 |
0x00000000 |
not checked | not checked | not checked | 0 |
0x00000108 |
not checked | not checked | not checked | not checked | 0x00000108 |
not checked | 0x00000104 |
not checked | not checked | not checked | not checked | not checked | not checked |
#6jalr-shares-alu-and-clears-bit-zero | 276 | 0x00 |
0 |
0 |
0 |
0x00000000 |
0x20021683 |
0x00000000 |
0x00000001 |
0x001080E7 |
0x00000100 |
0x00000421 |
0x00000208 |
0x00000000 |
1 |
0x00 |
0 |
0 |
0x00000000 |
not checked | not checked | not checked | not checked | 0x00000209 |
not checked | not checked | not checked | not checked | 0x00000208 |
not checked | not checked | not checked | not checked | not checked | 0 |
not checked | not checked |
Scroll within the table for all rows and pins. Buses use hexadecimal; values containing X/Z use MSB-first binary. Inputs show the declared values in effect at each checkpoint, including retained inputs. Sequential tests also replay preparation changes between checkpoints, such as lowering the clock. Use the matching checkpoint label in the simulation below.
Tests¶
RV32IForwardingUnitTest, RV32IDecodeStageTest, and RV32IExecuteStageTest compare both fidelities. Program lockstep additionally checks arithmetic chains, loads, stores, branches and JALR against the architectural oracle. RV32IAdvancedExamplesTest compiles and checks the displayed selector example.