§ 4.6.5. Memory Wait Handling¶
The advanced core accepts the same universal memory interface as the other cores, but it also handles delayed acceptance and delayed responses. The default remains separate zero-wait FF instruction and data endpoints; no cache is introduced here.
| Component | Description | Structural | Behavioral |
|---|---|---|---|
RV32IMemoryRequest |
CPU-side ownership of one outstanding request and its response | Yes | Yes; the advanced core builds its two requesters structurally |
RV32IMemoryLanes |
Load extension, byte-lane placement and masks | Yes | Yes; the cores build theirs structurally |
RV32IPipelineCoordinator |
Combine completion, hazards, recovery and precise stopping | Yes | Yes |
Responsibilities¶
An endpoint/controller knows how to operate its memory device. A CPU requester remembers which instruction owns the operation and whether the CPU has consumed its response. These are different responsibilities. The native device stores bytes; the pipeline does not duplicate that storage.
The full requester pin contract and binary C++ state machine remain in 4.3.5. Memory Access. The advanced core instantiates FETCH_REQUEST and DATA_REQUEST, one per port. A zero-wait request and response can complete on the same edge through the bypass. Once captured, a request's payload stays stable until accepted; acceptance is not the same event as completion. Each accepted store occurs exactly once.
The core's FETCH child is RV32IFetchStage. In this assembly, external_next_pc=1 makes REDIRECT_PC the PC register's next value from prediction; PC_REDIRECT remains on the shared stage interface but does not select a local PC+4 path. FETCH_VALID qualifies the outgoing IF/ID packet while FETCH_PC and IMEM_ADDR expose the stored byte PC. The MEMORY child is RV32IMemoryStage: it consumes the EX/MEM packet and DMEM_READ_DATA/DMEM_FAULT, emits the MEM/WB packet and stage-local memory fields, and exposes LOAD_REQUEST, STORE_REQUEST, faults, and forwarding signals to the coordinator and later stages. Neither child holds a pending memory transaction; the requesters own that state.
Pipeline behavior¶
| Condition | Fetch / IF/ID | ID/EX, EX/MEM, MEM/WB | Register write / training |
|---|---|---|---|
| No wait or hazard | Accept one instruction | Advance normally | Qualified WB write; eligible branch trains |
| Instruction response absent | PC holds; IF/ID becomes invalid after its old instruction moves | Older instructions continue | Older work may retire |
| Data response absent for a MEM operation | Hold | Hold all packets | No repeated WB commit or predictor training |
| Load-use hazard | Hold consumer | Bubble ID/EX; advance older packets | Normal older work continues |
| Prediction correction | Correct PC; invalidate younger packet | Bubble ID/EX; resolved instruction advances | Train resolved branch once |
| Older data fault | Discard younger work | Kill EX result; carry fault to WB | Younger branch does not train |
| Terminal instruction retires | Stop accepting work | Clear remaining valid slots | Record halt/trap in separate status component |
VALID=0 suppresses side effects even if payload bits remain. Stores are authorized only for the oldest eligible MEM operation. On a redirect, an already issued instruction request cannot simply disappear: its requester drains an obsolete response and starts the current fetch when permitted. Returning later to the same address does not revive an abandoned request.
Coordinator IO pins¶
All pins below are one bit. The coordinator is combinational; CLK/RST belong to the stateful core components. During reset the core gates its effective ENABLE.
| Pins | Direction | Description |
|---|---|---|
ENABLE, HALTED, TRAPPED |
Input | Whether normal execution is permitted |
IMEM_READY, DMEM_READY |
Input | Requester DONE: complete response for this instruction, not raw REQ_READY |
LOAD_USE_HAZARD |
Input | Immediate load dependency |
TERMINAL_PENDING, EX_PRETERMINAL, MEMORY_TERMINAL, WB_TERMINAL |
Input | Terminal work at different points; stop younger fetches |
EX_REDIRECT |
Input | Saved/actual next-PC mismatch from recovery |
MEMORY_FAULT, RETIRE_TERMINAL |
Input | Older data fault; terminal WB is retiring |
MEM_LOAD, MEM_STORE |
Input | Qualified MEM operation intents |
ACTIVE, IMEM_READ_ENABLE, DMEM_READ_ENABLE, DMEM_WRITE_ENABLE |
Output | Execution and request permissions |
FETCH_RESPONSE_TAKE |
Output | Consume an admitted instruction response, or drain one after a flush, halt or trap |
DATA_REQUEST_ISSUE |
Output | Present a data request when either data-read or data-write permission is asserted |
FETCH_VALID, FETCH_PC_WRITE, FETCH_PC_REDIRECT |
Output | Accept fetched instruction, advance/correct PC |
IF_ID_WRITE, ID_EX_WRITE, EX_MEM_WRITE, MEM_WB_WRITE |
Output | Capture or hold each packet register |
IF_ID_FLUSH, ID_EX_FLUSH, EX_MEM_FLUSH, MEM_WB_FLUSH |
Output | Write a bubble when the corresponding WRITE is enabled |
COMMIT_ENABLE |
Output | Permit combinational Writeback's edge-qualified commit |
PIPELINE_STALL, LOAD_USE_STALL, MEMORY_STALL, DATA_PORT_STALL, PIPELINE_FLUSH |
Output | Combinational observations; no counter storage |
MEM_LOAD and MEM_STORE cannot both be true for a legal core packet. The component still defines that input combination: serialize the conflict, let WB clear and suppress a simultaneous read. DATA_PORT_STALL is therefore normally zero in this core.
Response consumption and data issue are CPU policy, computed inside the coordinator:
FETCH_RESPONSE_TAKE = FETCH_VALID OR ((HALTED OR TRAPPED) OR IF_ID_FLUSH)
DATA_REQUEST_ISSUE = DMEM_READ_ENABLE OR DMEM_WRITE_ENABLE
Pausing alone does not discard a fetched response. Halt/trap still permits draining while paused, without admitting the response into IF/ID. These outputs grant permission; the requester still checks whether it owns a matching response and retains its handshake state.
The advanced core connects the instruction requester to ACTIVE, not IMEM_READ_ENABLE. This permits a speculative fetch while a terminal instruction is pending, removing the late EX/MEM terminal-to-instruction-data-to-prediction path. FETCH_VALID still prevents admitting such an instruction. IMEM must be side-effect-free instruction storage, not a read-sensitive MMIO peripheral. The existing request holder preserves stalled payloads and discards stale responses after a PC change; registered halt/trap also drains a pending response without accepting it into IF/ID. No additional response buffer is introduced. IMEM_READ_ENABLE remains the coordinator's conservative non-speculative permission for standalone users.
C++ example¶
The output fields follow the IO table. This includes every coordinator output, including its defensive simultaneous-load/store behavior.
struct ControlInputs {
bool enable,halted,trapped,imem_ready,dmem_ready,load_use,terminal_pending;
bool ex_preterminal,memory_terminal,wb_terminal,ex_redirect,memory_fault;
bool mem_load,mem_store,retire_terminal;
};
struct ControlOutputs {
bool active,imem_read,dmem_read,dmem_write,fetch_valid,pc_write,pc_redirect;
bool if_id_write,if_id_flush,id_ex_write,id_ex_flush,ex_mem_write,ex_mem_flush;
bool mem_wb_write,mem_wb_flush,commit,stall,load_use_stall,memory_stall,port_stall,flush;
bool fetch_response_take,data_request_issue;
};
inline ControlOutputs control(ControlInputs i) {
const bool active=i.enable&&!i.halted&&!i.trapped;
const bool wait=active&&(i.mem_load||i.mem_store)&&!i.wb_terminal&&!i.dmem_ready;
const bool conflict=active&&i.mem_load&&i.mem_store&&!i.wb_terminal&&i.dmem_ready;
const bool terminal=i.terminal_pending||i.ex_preterminal||i.memory_terminal||i.wb_terminal;
const bool retire=active&&!wait&&i.retire_terminal;
const bool step=active&&!wait&&!conflict&&!retire;
const bool kill=i.ex_preterminal||i.ex_redirect||i.memory_fault;
const bool fetch=step&&!kill&&!i.load_use&&i.imem_ready&&!terminal;
const bool redirect=step&&i.ex_redirect;
const bool read=active&&i.mem_load&&!i.mem_store&&!i.wb_terminal;
const bool write=active&&i.mem_store&&!i.wb_terminal;
const bool if_flush=retire||(step&&kill);
return {active,active&&!terminal,read,write,fetch,fetch||redirect,redirect,
retire||(step&&!i.load_use),retire||(step&&kill),retire||step,retire||(step&&(kill||i.load_use)),
retire||step,retire||(step&&i.memory_fault),retire||conflict||step,retire||conflict,
active&&!wait,wait||conflict||i.load_use,step&&i.load_use,wait,conflict,step&&kill,
fetch||((i.halted||i.trapped)||if_flush),read||write};
}
Implementation¶
Structural implementation¶
The coordinator is a grouped gate network producing enables, flushes, fetch-response consumption and data-request issue; it owns no instruction registers. Its FETCH_STOPPED → FETCH_DISCARD → FETCH_CONSUME OR chain implements the consumption rule, and DATA_ISSUE combines the two data permissions. The requesters independently retain only their outstanding transaction state. Memory-stage data calculations, fault qualification and forwarding-value selection remain combinational.
Behavioral implementation¶
The coordinator evaluates the same equations. The behavioral core uses the same one-outstanding requester model and packet hold/advance rules; changing fidelity does not replace a delayed endpoint with an instant one.
Suitable memories¶
| Memory endpoint | Advanced pipeline | Single-cycle / baseline |
|---|---|---|
MemoryEndpoint<ff,32> |
Supported; default, zero-wait | Supported; required current timing model |
MemoryEndpoint<sram,32>, MemoryEndpoint<dram,32> |
Supported with stalls | Not supported as drop-in delayed memories |
MemoryEndpoint<rom,32> |
Suitable for instruction/read-only data; writes fault | Not supported with its delayed controller |
MemoryEndpoint<nor-flash,32> |
Protocol-compatible reads; normal stores fail because flash programming is a different operation | Not supported |
Each endpoint may expose controller plus structural device, controller plus scalable native MemoryContainer, or a fused behavioral endpoint with the same transaction contract. The core sees the endpoint, not a bare container. Technology timing and supported commands remain the controller's contract in 3.3. A huge behavioral device changes capacity and simulation cost, not the bus pins or CPU wait logic.
Examples and tests¶
All 11 recorded rows of RV32IPipelineCoordinatorTest, 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 (b3b43b9f6bcb1478). Changing fidelity or the circuit can change these times.
| Checkpointzero-based number · timeline label | Timesimulator units | DMEM_READYInput · 1 bit |
ENABLEInput · 1 bit |
EX_PRETERMINALInput · 1 bit |
EX_REDIRECTInput · 1 bit |
HALTEDInput · 1 bit |
IMEM_READYInput · 1 bit |
LOAD_USE_HAZARDInput · 1 bit |
MEMORY_FAULTInput · 1 bit |
MEMORY_TERMINALInput · 1 bit |
MEM_LOADInput · 1 bit |
MEM_STOREInput · 1 bit |
RETIRE_TERMINALInput · 1 bit |
TERMINAL_PENDINGInput · 1 bit |
TRAPPEDInput · 1 bit |
WB_TERMINALInput · 1 bit |
ACTIVEExpected output · 1 bit |
COMMIT_ENABLEExpected output · 1 bit |
DATA_PORT_STALLExpected output · 1 bit |
DATA_REQUEST_ISSUEExpected output · 1 bit |
DMEM_READ_ENABLEExpected output · 1 bit |
DMEM_WRITE_ENABLEExpected output · 1 bit |
EX_MEM_FLUSHExpected output · 1 bit |
EX_MEM_WRITEExpected output · 1 bit |
FETCH_PC_REDIRECTExpected output · 1 bit |
FETCH_PC_WRITEExpected output · 1 bit |
FETCH_RESPONSE_TAKEExpected output · 1 bit |
FETCH_VALIDExpected output · 1 bit |
ID_EX_FLUSHExpected output · 1 bit |
ID_EX_WRITEExpected output · 1 bit |
IF_ID_FLUSHExpected output · 1 bit |
IF_ID_WRITEExpected output · 1 bit |
IMEM_READ_ENABLEExpected output · 1 bit |
LOAD_USE_STALLExpected output · 1 bit |
MEMORY_STALLExpected output · 1 bit |
MEM_WB_FLUSHExpected output · 1 bit |
MEM_WB_WRITEExpected output · 1 bit |
PIPELINE_FLUSHExpected output · 1 bit |
PIPELINE_STALLExpected output · 1 bit |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
#0disabled | 8 | 1 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
#1halted-drains-fetch-response | 18 | 1 |
1 |
0 |
0 |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
#2trapped-drains-fetch-response | 22 | 1 |
1 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
#3paused-halted-still-drains-fetch-response | 25 | 1 |
0 |
0 |
0 |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
#4normal-fetch-and-advance | 35 | 1 |
1 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
1 |
1 |
0 |
1 |
0 |
1 |
1 |
0 |
0 |
0 |
1 |
0 |
0 |
#5load-use-bubble | 41 | 1 |
1 |
0 |
0 |
0 |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
1 |
1 |
0 |
0 |
1 |
1 |
0 |
0 |
1 |
0 |
1 |
#6redirect-flushes-younger-stages | 49 | 1 |
1 |
0 |
1 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
1 |
0 |
1 |
1 |
1 |
1 |
1 |
0 |
0 |
0 |
1 |
1 |
0 |
#7older-memory-fault-kills-ex-stage | 52 | 1 |
1 |
0 |
0 |
0 |
1 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
0 |
0 |
0 |
0 |
1 |
1 |
0 |
0 |
1 |
0 |
1 |
1 |
1 |
1 |
1 |
0 |
0 |
0 |
1 |
1 |
0 |
#8memory-wait-holds-pipeline | 64 | 0 |
1 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
0 |
0 |
0 |
1 |
#9invalid-dual-memory-request-stalls | 75 | 1 |
1 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
1 |
1 |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
1 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
1 |
1 |
0 |
1 |
#10terminal-retirement-clears-pipeline | 81 | 1 |
1 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
0 |
0 |
1 |
1 |
0 |
0 |
0 |
0 |
1 |
1 |
0 |
0 |
1 |
0 |
1 |
1 |
1 |
1 |
0 |
0 |
0 |
1 |
1 |
0 |
0 |
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.
RV32IPipelineCoordinatorTest compares the gate and behavioral equations. RV32IMemoryMigrationTest checks request acceptance/backpressure, response holding, redirected/obsolete requests, pause/reset, masked stores and delayed ROM/SRAM programs, including every predictor policy. RV32IAdvancedExamplesTest validates the displayed coordinator code against all registered rows.