ยง 4.4.4. Memory Access¶
RV32ISingleCycleMemoryStage formats direct load/store pins and load results. In the core it is named MEMORY. It contains no storage, request registers, clock, or reset state.
These are stage-local pins. The complete core's combinational DATA_PORT converts them to universal REQ/RSP pins for the external zero-wait FF endpoint; it adds no buffering or cycle. The endpoint's controller and native device are outside this stage.
| Component | Description | Structural | Behavioral |
|---|---|---|---|
RV32ISingleCycleMemoryStage |
Combinational address/lane formatting, alignment check, and commit-gated store enable | Yes | Yes |
4.4.4.1. RV32ISingleCycleMemoryStage¶
IO pins¶
| Pin | Direction | Width | Description |
|---|---|---|---|
ISSUE, COMMIT |
Input | 1 each | Active memory intent; final permission to commit |
MEM_WRITE, SIGN_EXTEND |
Input | 1 each | Store direction; signed byte/halfword load |
ADDR, WRITE_DATA |
Input | 32 each | Effective byte address; unshifted source |
SIZE |
Input | 2 | 0 byte, 1 halfword, 2 word, 3 invalid |
DMEM_READ_DATA |
Input | 32 | Native word before load-lane selection |
DMEM_FAULT |
Input | 1 | Native access fault |
READ_DATA |
Output | 32 | Narrowed and sign/zero-extended load value |
DONE, FAULT, MISALIGNED |
Output | 1 each | Constant one; native fault; bad alignment or invalid size |
DMEM_WORD_ADDR |
Output | 32 | ADDR/4 native word index |
DMEM_WRITE_DATA |
Output | 32 | Source shifted to selected little-endian lanes |
DMEM_WRITE_MASK |
Output | 4 | Enabled byte lanes |
DMEM_READ_EN, DMEM_WE |
Output | 1 each | Active access/read check; authorized store enable |
Behavior¶
ADDR[1:0] selects the little-endian byte lane. RV32IMemoryLanes shifts store data, forms the byte mask, and extracts/sign-extends loads. Invalid SIZE=3 gives mask/result zero. Misaligned halfwords/words are reported; there are no split accesses.
DMEM_READ_EN follows ISSUE for both reads and stores. DMEM_WE is ISSUE && MEM_WRITE && COMMIT && !MISALIGNED. In the complete core, ISSUE excludes earlier fetch/decode faults and terminal state, and COMMIT is tied high: the endpoint validates the request and never writes on a fault. Its response must not feed COMMIT, because that would change a rejected write's REQ_OP to read and create a feedback loop. Standalone native-device callers may use COMMIT as an independent store authorization, provided the device rejects invalid writes.
The native memory owns the write clock and captures DMEM_WORD_ADDR/WRITE_DATA/WRITE_MASK on the same rising edge as PC and the register file. Changing this stage's input immediately changes its output after settling: there is no payload capture or response buffer. No store needs its new contents read back to finish.
DONE is constant one because this port has no handshake; it does not detect settling. FAULT follows DMEM_FAULT without ISSUE qualification. The core uses it only for an active memory instruction.
Memory compatibility¶
The connected core requires MemoryEndpoint<ff,32>: either the fused behavioral form or an FF controller with native FF storage. MemoryContainer<ff,32> supplies scalable storage behind that controller; FFMemory<32> supplies a small expanded circuit. Native devices are not wired directly to the core's universal pins. See the complete-core memory table.
This stage cannot wait for a delayed response: DONE stays one and there is no pending-request state. The current SRAM, DRAM, ROM, and NOR-flash endpoints therefore require a wait-capable core, not just a controller attached to this stage. Construction guards reject them for the single-cycle system; bypassing those guards can produce incorrect execution rather than additional wait cycles.
C++ example¶
This binary reference reuses only the combinational lane and alignment examples from 4.3.5.
#include <cstdint>
namespace single_cycle_example {
struct MemoryInputs {
bool ISSUE, COMMIT, MEM_WRITE, SIGN_EXTEND;
uint32_t ADDR, WRITE_DATA;
unsigned SIZE;
uint32_t DMEM_READ_DATA;
bool DMEM_FAULT;
};
struct MemoryOutputs {
uint32_t READ_DATA;
bool DONE, FAULT, MISALIGNED;
uint32_t DMEM_WORD_ADDR, DMEM_WRITE_DATA;
unsigned DMEM_WRITE_MASK;
bool DMEM_READ_EN, DMEM_WE;
};
class Memory {
public:
MemoryOutputs observe(const MemoryInputs& i) const {
const auto l=memory_access_example::lanes(i.ADDR,i.WRITE_DATA,i.DMEM_READ_DATA,i.SIZE,i.SIGN_EXTEND);
const bool bad=i.SIZE==3||memory_access_example::misaligned(i.ADDR,i.SIZE);
return {l.READ_DATA,true,i.DMEM_FAULT,bad,i.ADDR>>2,l.WORD_WRITE_DATA,l.WRITE_MASK,
i.ISSUE,i.ISSUE&&i.MEM_WRITE&&i.COMMIT&&!bad};
}
MemoryOutputs evaluate(const MemoryInputs& i) { return observe(i); }
};
}
Unknown inputs and timing¶
The behavioral model preserves each selected load bit and its sign extension, including unknown bits. Unknown neighboring bytes do not invalidate a known byte load. Address, size, and store-data integer conversions are binary abstractions; nonbinary controls/store operands are outside equivalence. Fault bits are forwarded. The catalog-selected stage uses gate-derived output delays; eligible paths can use a delay twin for current values. Neither fidelity adds a clock to this path. Allow the entire load-to-writeback path to settle.
Implementation¶
Structural implementation¶
LANES performs byte-lane formatting without constructing an unused guarded word-address output. ALIGNMENT plus SIZE_BITS/INVALID_SIZE rejects bad accesses; MEMORY_PORT forms the word index directly. WRITE_INTENT, ALIGNED, WRITE_ALLOWED, and COMMIT_STORE gate stores, so a bad address cannot write a rounded-down word. Constants drive DONE. There is no REQUEST child.
Behavioral implementation¶
BehavioralStage's Memory branch evaluates the same combinational logic without MemoryRequestState or owned contents. Both implementations are registered as rv32i.single-cycle.memory.
Examples¶
Eleven accesses cover signed/unsigned loads, every store width, invalid size, misalignment, and native faults. Each checks direct outputs, commit permission, changed store data without any edge, and disabled access.
All 44 recorded rows of RV32ISingleCycleMemoryStageTest, 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: canonical-default-preview / structural (7ecc45acd04324df). Changing fidelity or the circuit can change these times.
| Checkpointzero-based number ยท timeline label | Timesimulator units | ADDRInput ยท 32 bit |
COMMITInput ยท 1 bit |
DMEM_FAULTInput ยท 1 bit |
DMEM_READ_DATAInput ยท 32 bit |
ISSUEInput ยท 1 bit |
MEM_WRITEInput ยท 1 bit |
SIGN_EXTENDInput ยท 1 bit |
SIZEInput ยท 2 bit |
WRITE_DATAInput ยท 32 bit |
DMEM_READ_ENExpected output ยท 1 bit |
DMEM_WEExpected output ยท 1 bit |
DMEM_WORD_ADDRExpected output ยท 32 bit |
DMEM_WRITE_DATAExpected output ยท 32 bit |
DMEM_WRITE_MASKExpected output ยท 4 bit |
DONEExpected output ยท 1 bit |
FAULTExpected output ยท 1 bit |
MISALIGNEDExpected output ยท 1 bit |
READ_DATAExpected output ยท 32 bit |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
#0direct-access-0 | 10 | 0x00000101 |
0 |
0 |
0x00008000 |
1 |
0 |
1 |
0x0 |
0xDEADBEEF |
not checked | 0 |
0x00000040 |
0xADBEEF00 |
0x2 |
1 |
0 |
0 |
0xFFFFFF80 |
#1authorize-0 | 13 | 0x00000101 |
1 |
0 |
0x00008000 |
1 |
0 |
1 |
0x0 |
0xDEADBEEF |
not checked | 0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#2payload-is-not-buffered-0 | 19 | 0x00000101 |
1 |
0 |
0x00008000 |
1 |
0 |
1 |
0x0 |
0x00000000 |
not checked | not checked | not checked | 0x00000000 |
not checked | not checked | not checked | not checked | not checked |
#3disabled-0 | 21 | 0x00000101 |
1 |
0 |
0x00008000 |
0 |
0 |
1 |
0x0 |
0x00000000 |
0 |
0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#4direct-access-1 | 29 | 0x00000103 |
0 |
0 |
0x80000000 |
1 |
0 |
0 |
0x0 |
0xDEADBEEF |
not checked | 0 |
0x00000040 |
0xEF000000 |
0x8 |
1 |
0 |
0 |
0x00000080 |
#5authorize-1 | 32 | 0x00000103 |
1 |
0 |
0x80000000 |
1 |
0 |
0 |
0x0 |
0xDEADBEEF |
not checked | 0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#6payload-is-not-buffered-1 | 38 | 0x00000103 |
1 |
0 |
0x80000000 |
1 |
0 |
0 |
0x0 |
0x00000000 |
not checked | not checked | not checked | 0x00000000 |
not checked | not checked | not checked | not checked | not checked |
#7disabled-1 | 40 | 0x00000103 |
1 |
0 |
0x80000000 |
0 |
0 |
0 |
0x0 |
0x00000000 |
0 |
0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#8direct-access-2 | 52 | 0x00000102 |
0 |
0 |
0x80010000 |
1 |
0 |
1 |
0x1 |
0xDEADBEEF |
not checked | 0 |
0x00000040 |
0xBEEF0000 |
0xC |
1 |
0 |
0 |
0xFFFF8001 |
#9authorize-2 | 55 | 0x00000102 |
1 |
0 |
0x80010000 |
1 |
0 |
1 |
0x1 |
0xDEADBEEF |
not checked | 0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#10payload-is-not-buffered-2 | 61 | 0x00000102 |
1 |
0 |
0x80010000 |
1 |
0 |
1 |
0x1 |
0x00000000 |
not checked | not checked | not checked | 0x00000000 |
not checked | not checked | not checked | not checked | not checked |
#11disabled-2 | 63 | 0x00000102 |
1 |
0 |
0x80010000 |
0 |
0 |
1 |
0x1 |
0x00000000 |
0 |
0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#12direct-access-3 | 73 | 0x00000100 |
0 |
0 |
0x0000FFFE |
1 |
0 |
0 |
0x1 |
0xDEADBEEF |
not checked | 0 |
0x00000040 |
0xDEADBEEF |
0x3 |
1 |
0 |
0 |
0x0000FFFE |
#13authorize-3 | 76 | 0x00000100 |
1 |
0 |
0x0000FFFE |
1 |
0 |
0 |
0x1 |
0xDEADBEEF |
not checked | 0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#14payload-is-not-buffered-3 | 82 | 0x00000100 |
1 |
0 |
0x0000FFFE |
1 |
0 |
0 |
0x1 |
0x00000000 |
not checked | not checked | not checked | 0x00000000 |
not checked | not checked | not checked | not checked | not checked |
#15disabled-3 | 84 | 0x00000100 |
1 |
0 |
0x0000FFFE |
0 |
0 |
0 |
0x1 |
0x00000000 |
0 |
0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#16direct-access-4 | 93 | 0x00000100 |
0 |
0 |
0x12345678 |
1 |
0 |
0 |
0x2 |
0xDEADBEEF |
not checked | 0 |
0x00000040 |
0xDEADBEEF |
0xF |
1 |
0 |
0 |
0x12345678 |
#17authorize-4 | 96 | 0x00000100 |
1 |
0 |
0x12345678 |
1 |
0 |
0 |
0x2 |
0xDEADBEEF |
not checked | 0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#18payload-is-not-buffered-4 | 102 | 0x00000100 |
1 |
0 |
0x12345678 |
1 |
0 |
0 |
0x2 |
0x00000000 |
not checked | not checked | not checked | 0x00000000 |
not checked | not checked | not checked | not checked | not checked |
#19disabled-4 | 104 | 0x00000100 |
1 |
0 |
0x12345678 |
0 |
0 |
0 |
0x2 |
0x00000000 |
0 |
0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#20direct-access-5 | 114 | 0x00000102 |
0 |
0 |
0x00000000 |
1 |
1 |
0 |
0x0 |
0xDEADBEEF |
not checked | 0 |
0x00000040 |
0xBEEF0000 |
0x4 |
1 |
0 |
0 |
0x00000000 |
#21authorize-5 | 117 | 0x00000102 |
1 |
0 |
0x00000000 |
1 |
1 |
0 |
0x0 |
0xDEADBEEF |
not checked | 1 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#22payload-is-not-buffered-5 | 123 | 0x00000102 |
1 |
0 |
0x00000000 |
1 |
1 |
0 |
0x0 |
0x00000000 |
not checked | not checked | not checked | 0x00000000 |
not checked | not checked | not checked | not checked | not checked |
#23disabled-5 | 126 | 0x00000102 |
1 |
0 |
0x00000000 |
0 |
1 |
0 |
0x0 |
0x00000000 |
0 |
0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#24direct-access-6 | 132 | 0x00000102 |
0 |
0 |
0x00000000 |
1 |
1 |
0 |
0x1 |
0xDEADBEEF |
not checked | 0 |
0x00000040 |
0xBEEF0000 |
0xC |
1 |
0 |
0 |
0x00000000 |
#25authorize-6 | 135 | 0x00000102 |
1 |
0 |
0x00000000 |
1 |
1 |
0 |
0x1 |
0xDEADBEEF |
not checked | 1 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#26payload-is-not-buffered-6 | 141 | 0x00000102 |
1 |
0 |
0x00000000 |
1 |
1 |
0 |
0x1 |
0x00000000 |
not checked | not checked | not checked | 0x00000000 |
not checked | not checked | not checked | not checked | not checked |
#27disabled-6 | 144 | 0x00000102 |
1 |
0 |
0x00000000 |
0 |
1 |
0 |
0x1 |
0x00000000 |
0 |
0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#28direct-access-7 | 152 | 0x00000100 |
0 |
0 |
0x00000000 |
1 |
1 |
0 |
0x2 |
0xDEADBEEF |
not checked | 0 |
0x00000040 |
0xDEADBEEF |
0xF |
1 |
0 |
0 |
0x00000000 |
#29authorize-7 | 155 | 0x00000100 |
1 |
0 |
0x00000000 |
1 |
1 |
0 |
0x2 |
0xDEADBEEF |
not checked | 1 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#30payload-is-not-buffered-7 | 161 | 0x00000100 |
1 |
0 |
0x00000000 |
1 |
1 |
0 |
0x2 |
0x00000000 |
not checked | not checked | not checked | 0x00000000 |
not checked | not checked | not checked | not checked | not checked |
#31disabled-7 | 164 | 0x00000100 |
1 |
0 |
0x00000000 |
0 |
1 |
0 |
0x2 |
0x00000000 |
0 |
0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#32direct-access-8 | 172 | 0x00000102 |
0 |
1 |
0x00000000 |
1 |
1 |
0 |
0x2 |
0xDEADBEEF |
not checked | 0 |
0x00000040 |
0xBEEF0000 |
0xF |
1 |
1 |
1 |
0x00000000 |
#33authorize-8 | 173 | 0x00000102 |
0 |
1 |
0x00000000 |
1 |
1 |
0 |
0x2 |
0xDEADBEEF |
not checked | 0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#34payload-is-not-buffered-8 | 179 | 0x00000102 |
0 |
1 |
0x00000000 |
1 |
1 |
0 |
0x2 |
0x00000000 |
not checked | not checked | not checked | 0x00000000 |
not checked | not checked | not checked | not checked | not checked |
#35disabled-8 | 182 | 0x00000102 |
0 |
1 |
0x00000000 |
0 |
1 |
0 |
0x2 |
0x00000000 |
0 |
0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#36direct-access-9 | 188 | 0x00000100 |
0 |
1 |
0x00000000 |
1 |
0 |
0 |
0x3 |
0xDEADBEEF |
not checked | 0 |
0x00000040 |
0xDEADBEEF |
0x0 |
1 |
1 |
1 |
0x00000000 |
#37authorize-9 | 189 | 0x00000100 |
0 |
1 |
0x00000000 |
1 |
0 |
0 |
0x3 |
0xDEADBEEF |
not checked | 0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#38payload-is-not-buffered-9 | 195 | 0x00000100 |
0 |
1 |
0x00000000 |
1 |
0 |
0 |
0x3 |
0x00000000 |
not checked | not checked | not checked | 0x00000000 |
not checked | not checked | not checked | not checked | not checked |
#39disabled-9 | 197 | 0x00000100 |
0 |
1 |
0x00000000 |
0 |
0 |
0 |
0x3 |
0x00000000 |
0 |
0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#40direct-access-10 | 203 | 0x00000100 |
0 |
1 |
0x00000000 |
1 |
0 |
0 |
0x2 |
0xDEADBEEF |
not checked | 0 |
0x00000040 |
0xDEADBEEF |
0xF |
1 |
1 |
0 |
0x00000000 |
#41authorize-10 | 204 | 0x00000100 |
0 |
1 |
0x00000000 |
1 |
0 |
0 |
0x2 |
0xDEADBEEF |
not checked | 0 |
not checked | not checked | not checked | not checked | not checked | not checked | not checked |
#42payload-is-not-buffered-10 | 210 | 0x00000100 |
0 |
1 |
0x00000000 |
1 |
0 |
0 |
0x2 |
0x00000000 |
not checked | not checked | not checked | 0x00000000 |
not checked | not checked | not checked | not checked | not checked |
#43disabled-10 | 212 | 0x00000100 |
0 |
1 |
0x00000000 |
0 |
0 |
0 |
0x2 |
0x00000000 |
0 |
0 |
not checked | not checked | not checked | 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.
Embedded simulation¶
Tests¶
RV32ISingleCycleMemoryStageTest compares both implementations. RV32ISingleCycleStageIntegrationTest checks old-source loads/stores with at most one cycle per instruction. RV32ISingleCycleDocumentationTest.py executes the exact C++ example. Sources: RV32ISingleCycleStages.cpp, RV32ISingleCycleStagesBehavioral.cpp, and RV32ISingleCycleStageTests.cpp.