Synchronous Memories

Modeling RAM/ROM with clock.

Darshan N
Updated: 19 March 2026
11 min read

Memory modeling in Verilog is essential for designing processors, cache controllers, FIFOs, and embedded systems. Synchronous memories use a clock to register read and write operations, unlike asynchronous memories where outputs respond immediately to address changes. Understanding how to correctly model synchronous RAM and ROM in Verilog ensures that synthesis tools map the design onto on-chip memory blocks efficiently.

Synchronous MemoryRAM / ROMaddr [A-1:0]data_in [W-1:0]we (write enable)clkdata_out [W-1:0]Write PortRead PortFigure: Synchronous memory interface — address, data, write enable, clock
Figure 1: Synchronous memory interface with read and write ports controlled by clock

Core Concept: Clocked Memory Access

In a synchronous memory, all read and write operations are triggered by the rising (or falling) edge of a clock signal. This is in contrast to asynchronous memory where the output changes immediately when the address changes. In synchronous design, the write enable (we) signal is sampled on the clock edge. If we is high, the data on data_in is written to the location specified by addr. If we is low, the memory retains its contents.

For a read operation, there are two common behaviors depending on the design: read-first (output shows old data at the addressed location before the write happens on the same cycle) and write-first (output shows the new data being written). These are also called read-before-write and write-before-read modes. FPGA block RAMs support both modes and the Verilog coding style determines which is inferred.

For synchronous read, the data output register is updated on the clock edge: always @(posedge clk) data_out <= mem[addr];. This adds one clock cycle of read latency, meaning data is available one cycle after the address is presented. This is standard for FPGA BRAM inference and is essential for meeting timing at high clock frequencies.

Modeling Synchronous RAM in Verilog

A synchronous RAM is declared using a two-dimensional register array: reg [W-1:0] mem [0:DEPTH-1]; where W is the data width in bits and DEPTH is the number of addressable locations. The write port is inside a clocked always block, conditioned on we. The read port can be synchronous (clocked output register) or asynchronous (combinational assignment).

For synthesis tools to correctly infer a block RAM (BRAM) on an FPGA, both the read and write ports should be synchronous. If the read port is asynchronous, many tools will infer distributed RAM (using lookup tables) instead of block RAM, which is far less area-efficient for large memories. This is a critical difference that affects both area and timing in FPGA implementation.

Modeling Synchronous ROM in Verilog

A ROM has no write port. It is initialized at synthesis time using an initial block or a $readmemh / $readmemb system task. The initial block assigns constant values to all memory locations. Since ROM content never changes at runtime, synthesis tools recognize the read-only pattern and map it to appropriate on-chip resources. A typical synchronous ROM output uses a clocked always block: always @(posedge clk) data_out <= mem[addr];.

The $readmemh system task reads hexadecimal values from a file and initializes the memory array. This is useful for loading lookup tables, coefficient memories, or microcode ROMs. The corresponding task for binary is $readmemb. These tasks are supported in both simulation and synthesis on most FPGA tools, making them the preferred initialization method for large ROMs.

Mathematical Expression

For a memory with address width A bits and data width W bits: the total number of addressable locations is DEPTH = 2^A, and the total memory capacity in bits is: Capacity = 2^A x W bits. For example, a memory with 10-bit address and 8-bit data has 1024 locations and a capacity of 8192 bits (1 KB). The read latency in synchronous mode is exactly 1 clock cycle when a registered output stage is used.

Practical Understanding

FPGA block RAMs are dual-port synchronous memories with configurable read/write mode. Properly coded Verilog RAM inference allows the synthesis tool to use these hardware primitives directly, avoiding the overhead of implementing memory with thousands of flip-flops. ROMs are commonly used for sine lookup tables in DDS synthesizers, CRC tables, character font bitmaps, and instruction ROMs in small processors.

Example
Given:
Synchronous single-port RAM: 8-bit data width, 6-bit address (64 locations)
Operation: Write 0xAB to address 10, then read address 10 one cycle later

Why this formula applies:
Synchronous write: on posedge clk, if we=1, mem[addr] <= data_in
Synchronous read: on posedge clk, data_out <= mem[addr]
Read latency = 1 clock cycle

Formula:
Capacity = 2^A x W = 2^6 x 8 = 512 bits = 64 bytes
Read latency = 1 cycle

Substitution:
Cycle 1: addr=10, we=1, data_in=0xAB -> mem[10] written = 0xAB
Cycle 2: addr=10, we=0 -> data_out registered = mem[10] = 0xAB

Calculation:
Cycle 1 posedge: write executes, mem[10]=0xAB
Cycle 2 posedge: read executes, data_out=0xAB (available after cycle 2 clock edge)

Final Answer:
data_out = 0xAB, available 1 clock cycle after read address presented
Exam Tip: In synchronous RAM, the read latency is 1 clock cycle when a registered output is used. GATE and VLSI questions often ask to distinguish read-first vs write-first mode — the key is whether data_out reflects old or new data when a simultaneous read-write to the same address occurs.

Read/Write Timing Mechanism

Synchronous RAM Read/Write Timingclkaddraddr=10addr=10 (read)wewe=1 (write)we=0data_in0xABdata_outinvalid0xAB validwrite occursread latchesoutput validFigure: Synchronous RAM timing: write on cycle 1, read output valid after cycle 2 clock edge
Figure 2: Synchronous RAM read and write timing — 1-cycle read latency with registered output
  • Synchronous RAM write: on posedge clk, if we=1, mem[addr] <= data_in.
  • Synchronous read: data_out <= mem[addr] on posedge clk; 1 cycle read latency.
  • ROM: read-only, initialized via initial block or $readmemh; no write port.
  • Capacity = 2^A x W bits for address width A and data width W.
  • Registered output is necessary for FPGA BRAM inference; asynchronous read infers distributed RAM.

Quick Revision

  • Memory declaration: reg [W-1:0] mem [0:DEPTH-1] where DEPTH = 2^A.
  • Synchronous write: always @(posedge clk) if(we) mem[addr] <= data_in.
  • Synchronous read: always @(posedge clk) data_out <= mem[addr]; — 1 cycle latency.
  • ROM: initial block assigns constants; $readmemh loads from hex file.
  • Capacity = 2^A x W bits.
  • Read-first vs write-first: determines data_out value on simultaneous read-write to same address.
  • Exam trap: asynchronous read (combinational) does NOT infer BRAM on FPGA — always use registered read for block RAM.

Synchronous Memory Quiz

Test understanding of synchronous RAM and ROM modeling.

Question 1 of 3

Q1.What syntax correctly declares a memory array of 256 bytes in Verilog?