Skip to content

ยง 4.5.6. Writeback and Retirement

Writeback is combinational, just like single-cycle Writeback. The preceding MEM/WB register holds the instruction's results; the register file in Decode captures the selected value. There is no result register or completed-PC register inside Writeback.

Stopping state belongs to a separate execution-status block, shared by the baseline and advanced pipelines.

Component Description Structural Behavioral
RV32IWritebackStage Combinational result selection and retirement permission Yes Yes
RV32IPipelineExecutionStatus Six persistent halt/trap status bits outside the datapath Yes Yes

Writeback

IO pins

Pin Direction Width Description
COMMIT_ENABLE Input 1 Permission from pipeline control
IN_VALID Input 1 MEM/WB validity
IN_ALU_RESULT, IN_MEMORY_DATA, IN_PC_PLUS_4, IN_CONTROL, IN_REGISTER_ADDRESSES, IN_FETCH_STATUS, IN_EXECUTION_STATUS, IN_MEMORY_STATUS Input 32 each Result, destination/control and fault fields from MEM/WB
WB_VALID, WB_REG_WRITE Output 1 each Incoming validity and decoded write intent, independent of commit permission
REGISTER_WRITE, WB_RD, WB_VALUE Output 1, 5, 32 Qualified register-file write port
TERMINAL, RETIRE_TERMINAL, COMMIT_VALID Output 1 each Pending valid halt/trap, permitted terminal retirement, permitted retirement
HALT_EVENT, TRAP_EVENT, TRAP_CAUSE Output 1, 1, 4 Qualified stop events and combinational cause; not stored status

Behavior

WRITEBACK_SEL chooses zero (0), ALU_RESULT (1), MEMORY_DATA (2), or PC_PLUS_4 (3). WB_RD comes from the retiring packet. These outputs settle whenever the inputs change: no clock is needed.

COMMIT_VALID is COMMIT_ENABLE && IN_VALID. REGISTER_WRITE additionally requires decoded write intent and no terminal condition. These are permissions sampled by receiving registers at the next rising edge, not one-tick completion pulses. The register file enforces x0's hardwired-zero rule.

Fault priority is: PC misalignment โ†’ instruction access fault โ†’ illegal instruction โ†’ decoded trap โ†’ load misalignment/access fault โ†’ store misalignment/access fault โ†’ selected-target misalignment. Halt is considered only when there is no trap. Machine-model trap codes are used, not privileged RISC-V CSRs.

TERMINAL identifies a valid stopping packet even when COMMIT_ENABLE=0. HALT_EVENT and TRAP_EVENT require commit permission, and RETIRE_TERMINAL is their OR. TRAP_CAUSE is unqualified: it describes the current fault/control fields even when IN_VALID or COMMIT_ENABLE is low. It is captured only with TRAP_EVENT. A bubble suppresses events; changing the fault fields changes the cause after settling. Nothing sticks here.

There is no CLK, RST, or IN_NEXT_PC input. The enclosing controller suppresses COMMIT_ENABLE during reset, pause and after stopping. Stores have already taken place at the MEM edge; Writeback does not repeat them.

C++ example

This pure function describes all binary outputs. Packet and its packed control fields are shared with the other examples.

inline unsigned trap_cause(const Packet& p) {
    const auto c=unpackControl(p.control);
    if(p.fetch_status&1) return 3;
    if(p.fetch_status&2) return 4;
    if(!c.legal) return 1;
    if(c.trap) return c.trap_cause==rv32i::RV32ITrapCause::EnvironmentCall?2:1;
    if(c.mem_read&&(p.memory_status&1)) return 5;
    if(c.mem_read&&(p.memory_status&2)) return 6;
    if(c.mem_write&&(p.memory_status&1)) return 7;
    if(c.mem_write&&(p.memory_status&2)) return 8;
    return p.execution_status&1?3:0;
}
struct WritebackOutputs {
    bool valid,reg_write,register_write,terminal,retire_terminal,commit_valid;
    unsigned rd; uint32_t value;
    bool halt_event,trap_event;
    unsigned cause;
};
inline WritebackOutputs writeback(const Packet& p,bool commit_enable) {
    const auto c=unpackControl(p.control);
    const auto trap=trap_cause(p);
    const bool terminal=p.valid&&(trap||c.halt),commit=commit_enable&&p.valid;
    const auto sel=bits(p.control,9,3);
    const uint32_t value=sel==1?p.alu_result:sel==2?p.memory_data:sel==3?p.pc_plus_4:0;
    return {p.valid,c.reg_write,commit&&!terminal&&c.reg_write,terminal,commit&&terminal,
        commit,rd(p.addresses),value,commit&&!trap&&c.halt,commit&&bool(trap),trap};
}

Implementation

Structural implementation

WRITEBACK_MUX selects the result. RETIREMENT is an RV32IPipelineRetirementUnit that qualifies completion, register writes and stop events. Rewire blocks unpack fields and pass validity through; gates report pending terminal conditions. There are zero stored bits in this stage.

Behavioral implementation

RV32IWritebackStageBehavioral evaluates the same selection, fault priority and permissions without retaining state. Both implementations share rv32i.pipeline.stage.writeback.

Examples

The scenario changes inputs without clock edges: ALU/load/link selection, disabled commits, bubbles, halt and every trap cause. Each terminal case is followed by another packet or bubble to verify that events do not stick.

All 28 recorded rows of RV32IWritebackStageTest, 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 (af48e84b52b36344). Changing fidelity or the circuit can change these times.

Checkpointzero-based number ยท timeline label Timesimulator units COMMIT_ENABLEInput ยท 1 bit IN_ALU_RESULTInput ยท 32 bit IN_CONTROLInput ยท 32 bit IN_EXECUTION_STATUSInput ยท 32 bit IN_FETCH_STATUSInput ยท 32 bit IN_MEMORY_DATAInput ยท 32 bit IN_MEMORY_STATUSInput ยท 32 bit IN_PC_PLUS_4Input ยท 32 bit IN_REGISTER_ADDRESSESInput ยท 32 bit IN_VALIDInput ยท 1 bit COMMIT_VALIDExpected output ยท 1 bit HALT_EVENTExpected output ยท 1 bit REGISTER_WRITEExpected output ยท 1 bit RETIRE_TERMINALExpected output ยท 1 bit TERMINALExpected output ยท 1 bit TRAP_CAUSEExpected output ยท 4 bit TRAP_EVENTExpected output ยท 1 bit WB_RDExpected output ยท 5 bit WB_REG_WRITEExpected output ยท 1 bit WB_VALIDExpected output ยท 1 bit WB_VALUEExpected output ยท 32 bit
#0bubble21 1 0x00000005 0x20001283 0x00000000 0x00000000 0x81234567 0x00000000 0x0000000C 0x000004A0 0 0 0 0 not checked not checked 0x0 0 0x01 not checked 0 0x00000005
#1addi-without-clock26 1 0x00000005 0x20001283 0x00000000 0x00000000 0x81234567 0x00000000 0x0000000C 0x000004A0 1 1 not checked 1 0 0 not checked not checked not checked 1 1 not checked
#2disabled-result-still-combinational32 0 0x00000063 0x20001283 0x00000000 0x00000000 0x81234567 0x00000000 0x0000000C 0x000004A0 1 0 not checked 0 not checked not checked not checked not checked not checked not checked not checked 0x00000063
#3load39 1 0x00000063 0x20001487 0x00000000 0x00000000 0x81234567 0x00000000 0x0000000C 0x00000800 1 1 not checked 1 not checked not checked not checked not checked 0x02 not checked not checked 0x81234567
#4jump-link46 1 0x00000063 0x28011603 0x00000000 0x00000000 0x81234567 0x00000000 0x0000000C 0x00000D00 1 1 not checked 1 not checked not checked not checked not checked 0x03 not checked not checked 0x0000000C
#5store52 1 0x00000063 0x20001189 0x00000000 0x00000000 0x81234567 0x00000000 0x0000000C 0x00000060 1 1 not checked 0 not checked not checked not checked not checked 0x00 not checked not checked 0x00000000
#6alu-again58 1 0x00000063 0x20001283 0x00000000 0x00000000 0x81234567 0x00000000 0x0000000C 0x000004A0 1 1 not checked 1 not checked not checked not checked not checked 0x01 not checked not checked 0x00000063
#7halt-without-permission64 0 0x00000063 0x53001021 0x00000000 0x00000000 0x81234567 0x00000000 0x0000000C 0x000004A0 1 not checked 0 not checked 0 1 not checked not checked not checked not checked not checked not checked
#8halt-event69 1 0x00000063 0x53001021 0x00000000 0x00000000 0x81234567 0x00000000 0x0000000C 0x000004A0 1 not checked 1 0 1 not checked not checked 0 not checked not checked not checked not checked
#9halt-does-not-stick75 1 0x00000063 0x20001283 0x00000000 0x00000000 0x81234567 0x00000000 0x0000000C 0x000004A0 1 not checked 0 1 not checked 0 not checked not checked not checked not checked not checked not checked
#10pc-before-fetch-and-halt92 1 0x00000063 0x53001021 0x00000001 0x00000003 0x81234567 0x00000000 0x0000000C 0x000004A0 1 1 0 0 1 not checked 0x3 1 not checked not checked not checked not checked
#11pc-before-fetch-and-halt-bubble-clears96 1 0x00000063 0x53001021 0x00000001 0x00000003 0x81234567 0x00000000 0x0000000C 0x000004A0 0 0 not checked not checked 0 0 0x3 0 not checked not checked not checked not checked
#12fetch-before-illegal107 1 0x00000063 0x53041040 0x00000000 0x00000002 0x81234567 0x00000000 0x0000000C 0x000004A0 1 1 0 0 1 not checked 0x4 1 not checked not checked not checked not checked
#13fetch-before-illegal-bubble-clears111 1 0x00000063 0x53041040 0x00000000 0x00000002 0x81234567 0x00000000 0x0000000C 0x000004A0 0 0 not checked not checked 0 0 0x4 0 not checked not checked not checked not checked
#14illegal-before-target122 1 0x00000063 0x53041040 0x00000001 0x00000000 0x81234567 0x00000000 0x0000000C 0x000004A0 1 1 0 0 1 not checked 0x1 1 not checked not checked not checked not checked
#15illegal-before-target-bubble-clears126 1 0x00000063 0x53041040 0x00000001 0x00000000 0x81234567 0x00000000 0x0000000C 0x000004A0 0 0 not checked not checked 0 0 0x1 0 not checked not checked not checked not checked
#16ecall139 1 0x00000063 0x53081041 0x00000000 0x00000000 0x81234567 0x00000000 0x0000000C 0x000004A0 1 1 0 0 1 not checked 0x2 1 not checked not checked not checked not checked
#17ecall-bubble-clears143 1 0x00000063 0x53081041 0x00000000 0x00000000 0x81234567 0x00000000 0x0000000C 0x000004A0 0 0 not checked not checked 0 0 0x2 0 not checked not checked not checked not checked
#18load-alignment-before-access158 1 0x00000063 0x20001487 0x00000001 0x00000000 0x81234567 0x00000003 0x0000000C 0x000004A0 1 1 0 0 1 not checked 0x5 1 not checked not checked not checked not checked
#19load-alignment-before-access-bubble-clears162 1 0x00000063 0x20001487 0x00000001 0x00000000 0x81234567 0x00000003 0x0000000C 0x000004A0 0 0 not checked not checked 0 0 0x5 0 not checked not checked not checked not checked
#20load-access-before-target178 1 0x00000063 0x20001487 0x00000001 0x00000000 0x81234567 0x00000002 0x0000000C 0x000004A0 1 1 0 0 1 not checked 0x6 1 not checked not checked not checked not checked
#21load-access-before-target-bubble-clears182 1 0x00000063 0x20001487 0x00000001 0x00000000 0x81234567 0x00000002 0x0000000C 0x000004A0 0 0 not checked not checked 0 0 0x6 0 not checked not checked not checked not checked
#22store-alignment-before-access200 1 0x00000063 0x20001189 0x00000001 0x00000000 0x81234567 0x00000003 0x0000000C 0x000004A0 1 1 0 0 1 not checked 0x7 1 not checked not checked not checked not checked
#23store-alignment-before-access-bubble-clears204 1 0x00000063 0x20001189 0x00000001 0x00000000 0x81234567 0x00000003 0x0000000C 0x000004A0 0 0 not checked not checked 0 0 0x7 0 not checked not checked not checked not checked
#24store-access-before-target220 1 0x00000063 0x20001189 0x00000001 0x00000000 0x81234567 0x00000002 0x0000000C 0x000004A0 1 1 0 0 1 not checked 0x8 1 not checked not checked not checked not checked
#25store-access-before-target-bubble-clears224 1 0x00000063 0x20001189 0x00000001 0x00000000 0x81234567 0x00000002 0x0000000C 0x000004A0 0 0 not checked not checked 0 0 0x8 0 not checked not checked not checked not checked
#26target-misaligned243 1 0x00000063 0x28011603 0x00000001 0x00000000 0x81234567 0x00000000 0x0000000C 0x000004A0 1 1 0 0 1 not checked 0x3 1 not checked not checked not checked not checked
#27target-misaligned-bubble-clears247 1 0x00000063 0x28011603 0x00000001 0x00000000 0x81234567 0x00000000 0x0000000C 0x000004A0 0 0 not checked not checked 0 0 0x3 0 not checked not checked 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.

Open Writeback stage

Tests

RV32IWritebackStageTest checks both implementations. The documentation test checks its complete pin contract and verifies that its hierarchy contains no registers or flip-flops. RV32IBaselineExamplesTest replays the same rows through the C++ example.

Execution status

IO pins

Pin Direction Width Description
CLK, RST Input 1 each Rising-edge capture; asynchronous active-high reset
HALT_EVENT, TRAP_EVENT Input 1 each Writeback's permitted stopping events
EVENT_TRAP_CAUSE Input 4 Writeback's combinational cause
HALTED, TRAPPED, TRAP_CAUSE Output 1, 1, 4 Persistent stopping status

Behavior

Reset clears all six bits, regardless of the clock or event inputs. Otherwise, a rising edge sets HALTED when HALT_EVENT=1, and sets TRAPPED and captures EVENT_TRAP_CAUSE when TRAP_EVENT=1. Each flag holds until reset; cause holds until another trap event or reset. Falling edges and changes to cause alone do not update state.

The two event inputs are independent; asserting both sets both flags. Writeback itself never generates both together because a trap takes priority over a halt. The complete core feeds HALTED/TRAPPED back to control, preventing further retirement once either is set. Four cause bits are simulator reporting state, not a privileged exception mechanism.

C++ example

struct ExecutionStatus {
    bool halted=false,trapped=false,previous_clock=false;
    unsigned cause=0;
    void evaluate(bool clk,bool reset,bool halt_event,bool trap_event,unsigned event_cause) {
        if(reset) {halted=trapped=false;cause=0;}
        else if(!previous_clock&&clk) {
            if(halt_event) halted=true;
            if(trap_event) {trapped=true;cause=event_cause&15;}
        }
        previous_clock=clk;
    }
};

Implementation

Structural implementation

HALTED_STATE and TRAPPED_STATE are individual FlipFlopCells. TRAP_CAUSE_WORD is a four-bit Register<4> sharing the trap-capture enable, clock, and reset. The block appears as EXECUTION_STATUS beside pipeline control, not between MEM/WB and the register file.

Behavioral implementation

RV32IPipelineExecutionStatusBehavioral retains the same six status bits and detects rising edges, with asynchronous reset taking priority. Family: rv32i.pipeline.execution-status.

Examples

The scenario checks edge-only capture, sticky flags, reset, every four-bit cause value and ignored cause changes when no trap event is accepted.

All 88 recorded rows of RV32IPipelineExecutionStatusTest, 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 (d5d272a9070b8ef3). Changing fidelity or the circuit can change these times.

Checkpointzero-based number ยท timeline label Timesimulator units CLKInput ยท 1 bit EVENT_TRAP_CAUSEInput ยท 4 bit HALT_EVENTInput ยท 1 bit RSTInput ยท 1 bit TRAP_EVENTInput ยท 1 bit HALTEDExpected output ยท 1 bit TRAPPEDExpected output ยท 1 bit TRAP_CAUSEExpected output ยท 4 bit
#0reset4 0 0x0 0 1 0 0 0 0x0
#1halt-needs-edge5 0 0x0 1 0 0 0 not checked not checked
#2halt-edge10 1 0x0 1 0 0 1 not checked not checked
#3halt-sticky11 0 0x0 0 0 0 1 0 not checked
#4reset-016 0 0x0 0 1 1 0 0 0x0
#5no-edge-017 0 0x0 0 0 1 not checked 0 0x0
#6trap-edge-022 1 0x0 0 0 1 not checked 1 0x0
#7cause-held-023 1 0xF 0 0 0 not checked 1 0x0
#8idle-edge-029 1 0xF 0 0 0 not checked 1 0x0
#9reset-134 0 0x1 0 1 1 0 0 0x0
#10no-edge-135 0 0x1 0 0 1 not checked 0 0x0
#11trap-edge-140 1 0x1 0 0 1 not checked 1 0x1
#12cause-held-141 1 0xE 0 0 0 not checked 1 0x1
#13idle-edge-147 1 0xE 0 0 0 not checked 1 0x1
#14reset-252 0 0x2 0 1 1 0 0 0x0
#15no-edge-253 0 0x2 0 0 1 not checked 0 0x0
#16trap-edge-258 1 0x2 0 0 1 not checked 1 0x2
#17cause-held-259 1 0xD 0 0 0 not checked 1 0x2
#18idle-edge-265 1 0xD 0 0 0 not checked 1 0x2
#19reset-370 0 0x3 0 1 1 0 0 0x0
#20no-edge-371 0 0x3 0 0 1 not checked 0 0x0
#21trap-edge-376 1 0x3 0 0 1 not checked 1 0x3
#22cause-held-377 1 0xC 0 0 0 not checked 1 0x3
#23idle-edge-383 1 0xC 0 0 0 not checked 1 0x3
#24reset-488 0 0x4 0 1 1 0 0 0x0
#25no-edge-489 0 0x4 0 0 1 not checked 0 0x0
#26trap-edge-494 1 0x4 0 0 1 not checked 1 0x4
#27cause-held-495 1 0xB 0 0 0 not checked 1 0x4
#28idle-edge-4101 1 0xB 0 0 0 not checked 1 0x4
#29reset-5106 0 0x5 0 1 1 0 0 0x0
#30no-edge-5107 0 0x5 0 0 1 not checked 0 0x0
#31trap-edge-5112 1 0x5 0 0 1 not checked 1 0x5
#32cause-held-5113 1 0xA 0 0 0 not checked 1 0x5
#33idle-edge-5119 1 0xA 0 0 0 not checked 1 0x5
#34reset-6124 0 0x6 0 1 1 0 0 0x0
#35no-edge-6125 0 0x6 0 0 1 not checked 0 0x0
#36trap-edge-6130 1 0x6 0 0 1 not checked 1 0x6
#37cause-held-6131 1 0x9 0 0 0 not checked 1 0x6
#38idle-edge-6137 1 0x9 0 0 0 not checked 1 0x6
#39reset-7142 0 0x7 0 1 1 0 0 0x0
#40no-edge-7143 0 0x7 0 0 1 not checked 0 0x0
#41trap-edge-7148 1 0x7 0 0 1 not checked 1 0x7
#42cause-held-7149 1 0x8 0 0 0 not checked 1 0x7
#43idle-edge-7155 1 0x8 0 0 0 not checked 1 0x7
#44reset-8160 0 0x8 0 1 1 0 0 0x0
#45no-edge-8161 0 0x8 0 0 1 not checked 0 0x0
#46trap-edge-8166 1 0x8 0 0 1 not checked 1 0x8
#47cause-held-8167 1 0x7 0 0 0 not checked 1 0x8
#48idle-edge-8173 1 0x7 0 0 0 not checked 1 0x8
#49reset-9178 0 0x9 0 1 1 0 0 0x0
#50no-edge-9179 0 0x9 0 0 1 not checked 0 0x0
#51trap-edge-9184 1 0x9 0 0 1 not checked 1 0x9
#52cause-held-9185 1 0x6 0 0 0 not checked 1 0x9
#53idle-edge-9191 1 0x6 0 0 0 not checked 1 0x9
#54reset-10196 0 0xA 0 1 1 0 0 0x0
#55no-edge-10197 0 0xA 0 0 1 not checked 0 0x0
#56trap-edge-10202 1 0xA 0 0 1 not checked 1 0xA
#57cause-held-10203 1 0x5 0 0 0 not checked 1 0xA
#58idle-edge-10209 1 0x5 0 0 0 not checked 1 0xA
#59reset-11214 0 0xB 0 1 1 0 0 0x0
#60no-edge-11215 0 0xB 0 0 1 not checked 0 0x0
#61trap-edge-11220 1 0xB 0 0 1 not checked 1 0xB
#62cause-held-11221 1 0x4 0 0 0 not checked 1 0xB
#63idle-edge-11227 1 0x4 0 0 0 not checked 1 0xB
#64reset-12232 0 0xC 0 1 1 0 0 0x0
#65no-edge-12233 0 0xC 0 0 1 not checked 0 0x0
#66trap-edge-12238 1 0xC 0 0 1 not checked 1 0xC
#67cause-held-12239 1 0x3 0 0 0 not checked 1 0xC
#68idle-edge-12245 1 0x3 0 0 0 not checked 1 0xC
#69reset-13250 0 0xD 0 1 1 0 0 0x0
#70no-edge-13251 0 0xD 0 0 1 not checked 0 0x0
#71trap-edge-13256 1 0xD 0 0 1 not checked 1 0xD
#72cause-held-13257 1 0x2 0 0 0 not checked 1 0xD
#73idle-edge-13263 1 0x2 0 0 0 not checked 1 0xD
#74reset-14268 0 0xE 0 1 1 0 0 0x0
#75no-edge-14269 0 0xE 0 0 1 not checked 0 0x0
#76trap-edge-14274 1 0xE 0 0 1 not checked 1 0xE
#77cause-held-14275 1 0x1 0 0 0 not checked 1 0xE
#78idle-edge-14281 1 0x1 0 0 0 not checked 1 0xE
#79reset-15286 0 0xF 0 1 1 0 0 0x0
#80no-edge-15287 0 0xF 0 0 1 not checked 0 0x0
#81trap-edge-15292 1 0xF 0 0 1 not checked 1 0xF
#82cause-held-15293 1 0x0 0 0 0 not checked 1 0xF
#83idle-edge-15299 1 0x0 0 0 0 not checked 1 0xF
#84async-reset-high-clock304 1 0x0 1 1 1 0 0 0x0
#85independent-events-together310 1 0x9 1 0 1 1 1 0x9
#86cause-change-with-high-clock311 1 0x6 1 0 1 not checked not checked 0x9
#87new-event-replaces-cause317 1 0x6 1 0 1 1 1 0x6

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.

Open execution status

Tests

RV32IPipelineExecutionStatusTest compares structural and behavioral implementations; RV32IBaselineExamplesTest checks the example. Complete-core program tests check stopping and precise traps in context. Source for both components: RV32IWritebackStage.cpp (structural) and RV32IPipelineStagesBehavioral.cpp (behavioral).

Completed-PC observation

The hardware retains the fetch PC and PCs carried by pipeline packets. It needs no extra completed-PC register. RV32IRetirementView exposes the settled MEM/WB packet before its retirement edge; the host-side RV32IPipelineObserver follows that packet's computed next PC, retaining the current PC for halt/trap. It does not execute the instruction or calculate its result with the oracle.

RV32IPipelineStateView::snapshotPipelineState(observed_pc) combines that host-supplied PC with the actual register-file and execution-status state. The program testbench displays this observation on its own PC output; the pipeline core has no PC output for it, and it never feeds back into the circuit. Retirement counters and saved traces likewise belong to the harness.