Data Memory
Imagine a warehouse where your CPU stores and retrieves data—that’s what data memory is in our single-cycle core. While instruction memory is a read-only stencil, data memory behaves like a library with both check-out (read) and return (write) operations. Let’s unpack src/data_mem.v and see how it works.
Core Parameters
parameter DATA_WIDTH = 32; // bits per word (data size)
parameter ADDR_WIDTH = 11; // bits for addressing (how many words?)
DATA_WIDTH = 32: Each memory slot holds a 32-bit value—like a 32-page data packet.
ADDR_WIDTH = 11: With 11 bits, you can address 2¹¹ = 2048 words (warehouse shelves).
Trade-off: 8 KB of storage (2 048 × 4 bytes) gives enough room for variables, arrays, and the stack without exhausting FPGA RAM.
Declaring the Warehouse
reg [DATA_WIDTH-1:0] mem [(1<<ADDR_WIDTH)-1:0];This line sets up a 2D array: 2 048 entries, each 32 bits wide.
Analogy: A warehouse with 2 048 bins (addresses 0 to 2047), each bin holding a data crate of 32 bits.
Synchronous Read and Write
always @(posedge clk) begin
if (we) begin
mem[addr] <= write_data; // store new data
end
read_data <= mem[addr]; // retrieve data
endWrite Enable (we): When
weis high at the clock’s rising edge, new data is returned to the warehouse at slotaddr.Read Data: Also at the same clock edge, the content at
addris checked out and presented onread_data.Same-cycle read: Both operations happen on the same rising edge—read returns the old data if
weis high, or the new data, depending on synthesis rules.
Reflect: How might asynchronous reads differ? What are the pros and cons of reading immediately vs. on the clock?
Connecting to the Datapath
Load (read)
data_mem dmem( .clk(clk), .we(1'b0), // disable write on load .addr(alu_result[ADDR_WIDTH-1:0]), .write_data(32'b0), .read_data(load_data) );The ALU computes an address (
alu_result). We slice it down toADDR_WIDTHbits to index into data memory.On a load instruction,
weis low, soread_datareturns the stored value.
Store (write)
data_mem dmem( .clk(clk), .we(mem_write), // control logic asserts this on store ops .addr(alu_result[ADDR_WIDTH-1:0]), .write_data(reg_data), .read_data() // unused );- For a store instruction,
weis high. The data from the register file goes into memory at the computed address.
- For a store instruction,
Control Logic
Decodes the instruction (
opcode,funct3) to generatemem_readandmem_writesignals.Ensures we don’t accidentally write when we only meant to read, and vice versa.
Why It Matters
Data memory is the backbone for all load/store operations. Whether you’re loading an array element or storing a computed result, this module must be reliable and fast. In advanced designs, you’ll layer caches or even dual-ported memories, but here we start with a clean, single-ported design.