On-chip RAM is an array of words with an address, write-enable, and (usually) a registered read. FPGA BRAM is synchronous: you present an address, and data appears one clock later.
flowchart LR addr[addr] --> ram[sync_ram] we[we] --> ram wdata[wdata] --> ram clk[clk] --> ram ram --> rdata[rdata_q]
Synchronous write / registered read
logic [7:0] mem [0:15];
logic [7:0] rdata;
always_ff @(posedge clk) begin
if (we) mem[addr] <= wdata;
rdata <= mem[addr];
end
That read-after-write behavior (write-first vs read-old) is technology-dependent — pick one and test it.
Wrong vs right
Wrong — treat RAM like a combo ROM in the same cycle you change addr:
assign rdata = mem[addr]; // async read; may not map to BRAM
Right — accept the 1-cycle latency and register the consumer:
always_ff @(posedge clk) rdata <= mem[addr];
Init and test
$readmemb/$readmemhin the TB (or a loadable ROM path) to preload.- Check read-after-write and the wrap of the address space.
- Do not reset every RAM bit unless the spec says so — reset the control, init the array.