Read First Single Port RAM
FPGA block RAMs and ASIC memory compilers often provide a read-first mode, also known as read-before-write. When a read and a write occur simultaneously to the exact same memory address on the same clock cycle, the memory outputs the existing data before overwriting it with the new data. Matching this exact behavior in RTL ensures that simulation matches the synthesized hardware, preventing subtle functional bugs in pipelines that rely on memory forwarding.
The module computes a parameterized single-port synchronous RAM. On every positive clock edge, the memory evaluates the enable signal. If the enable is high, the memory accesses the provided address. If the write enable is also high, the input data is stored into the memory array at that address. The read data output must always reflect the data present at the address immediately before any write operation on that same clock cycle takes effect. If the enable signal is low, the memory array remains unchanged and the output holds its previous value.
- Clock edge:
posedge - Reset: No explicit reset for the memory array.
- Output value on initialization: The memory array and the output register must be initialized to 0.
- Priority rules: Enable dictates all activity. If enable is 0, write enable is ignored.
Cycle 1: en=1, we=1, addr=0, din=8'hAA • writes 0xAA, dout updates to 8'h00 (old data) Cycle 2: en=1, we=0, addr=0, din=8'h00 • reads addr 0, dout updates to 8'hAA Cycle 3: en=1, we=1, addr=0, din=8'hBB • writes 0xBB, dout updates to 8'hAA (old data) Cycle 4: en=0, we=1, addr=1, din=8'hCC • no operation, dout holds 8'hAA Cycle 5: en=1, we=0, addr=1, din=8'h00 • reads addr 1, dout updates to 8'h00
{ "signal": [
{ "name": "clk", "wave": "p....." },
{ "name": "en", "wave": "011101" },
{ "name": "we", "wave": "010110" },
{ "name": "addr", "wave": "x=====", "data": ["0", "0", "0", "1", "1"] },
{ "name": "din", "wave": "x=====", "data": ["AA", "00", "BB", "CC", "00"] },
{ "name": "dout", "wave": "======", "data": ["00", "00", "AA", "AA", "AA", "00"] }
], "head": { "text": "Cycle-by-cycle read-first behavior" } }| Signal | Direction | Width | Description | |--------|-----------|-------|-------------| | clk | input | 1 | Positive-edge triggered clock | | en | input | 1 | Memory enable; memory only updates when en is 1 | | we | input | 1 | Write enable; active high, evaluated only if en is 1 | | addr | input | ADDR_WIDTH | Memory address to read or write | | din | input | DATA_WIDTH | Data to be written into memory | | dout | output | DATA_WIDTH | Read data output; registered on clk |
Constraints
- The module must accept
DATA_WIDTH(default 8) andADDR_WIDTH(default 4) as parameters. - The memory array must be sized to exactly
2**ADDR_WIDTHelements. - Output
doutmust be updated synchronously onposedge clk. - Read-first behavior must be strictly enforced:
doutmust receive the old data ataddrduring a write. - If
enis 0, both read and write operations are ignored anddoutstrictly holds its previous value. - Initial value of all memory locations and
doutmust be 0.
Topics
Solve this problem
Write the module in Verilog, SystemVerilog or VHDL. Your submission is compiled and simulated against a real testbench — you get the waveform back, not a stored answer.
This problem is part of Codiode Pro. The statement above is free to read.
The circuit builder and code editor need a desktop screen. On a phone, read the problem here and open it on a laptop to solve.