Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • RTL Foundations36
  • Combinational Design25
  • Sequential Design27
  • FSM & Control27
  • Timing & Clocking39
  • Reset & CDC34
  • Memory & Buses57
    • SRAM and ROM
      • Inference Starts from Coding Style
      • Single-Port Synchronous RAM Template
      • Read-First vs Write-First
      • Dual-Port RAM Patterns
      • True Dual-Port RAM and Collisions
      • ROM Inference
    • Register Files
    • Valid/Ready Handshake
    • AXI-Lite
    • AXI-Stream
    • Bus Integration
    • Synchronous FIFO
    • Register-Map and CSR RTL
    • Memory Reliability
    • Peripheral RTL Integration
    • Full AXI4: RTL Roadmap
  • Advanced RTL28
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹SRAM and ROM
  1. Topics
  2. RTL Design
  3. Memory & Buses
  4. SRAM and ROM
  5. Single-Port Synchronous RAM Template

Part 7 · Memory & Buses · Intermediate

Single-Port Synchronous RAM Template

The standard single-port RAM, tested with 20,000 random operations against a reference, including the one-cycle read latency.

On this page

    Why this matters

    A synchronous RAM answers one cycle after the address, and in this version a same-address write still shows the old word. Control logic that forgets that cycle reads the previous request's data.

    After this lesson you can: build a single-port synchronous RAM with a registered read, and predict dout for each cycle around a same-address write.

    The template

    One array, one clock, one address. The write is synchronous and the read is registered.

    The full listing sits under Testbench below.

    Part

    Why

    logic [DW-1:0] mem [2**AW]

    The storage array, no reset

    if (we) mem[addr] <= din;

    Synchronous write with enable

    dout <= mem[addr];

    Synchronous read; the result is registered, one cycle later

    Same addr for read and write

    One shared address/access port; a write also observes the old word

    Read latency

    • Data appears one cycle after the address. Control logic around the RAM must account for that cycle (a valid bit travels with the request).

    • In this version a write with the same address also reads: the output shows the old word (read-first). The next lesson compares the alternatives.

    • Throughput is one shared-address access per cycle. A write also produces a read-first observation at that address; there is no independent second read address.

    Each slot is one clock cycle. Dout is the RAM output after the opening edge, and consumer is a flop sampling dout, so every dout word reaches consumer exactly one edge later.

    • Slot 0 offers the write with we high while dout still shows the previous request.

    • Slot 1 keeps dout at the old word 0x22 even though the write has landed: read-first.

    • Slot 2 shows the new word 0x11 on dout while consumer captures 0x22.

    • Slot 3 onward shows consumer holding 0x11: one cycle of RAM latency plus one consumer edge.

    Instant (address 7 initially 0x22)

    Request

    Output / consumer observation

    Before rising edge E

    addr=7, we=1, din=0x11 stable

    dout still belongs to the previous request

    At E, before NBA updates

    RAM samples the request

    A clocked consumer samples the previous dout

    After E's NBA updates

    mem[7] becomes 0x11

    dout becomes old mem[7] = 0x22

    Before / at E+1

    addr=7, we=0

    Consumer captures 0x22; after NBA dout becomes 0x11

    At E+2

    Next request may already be present

    Consumer captures 0x11 from the read at E+1

    Tip

    Wrap the RAM in a small module that exposes req/we/addr/wdata and rvalid/rdata, with the valid bit delayed by the RAM's latency. Then the rest of the design never sees the latency as an assumption.

    Common mistakes

    Common pitfall

    A clocked consumer at the request-sampling edge sees the previous dout. The new result appears after that edge's nonblocking updates and can be captured by the consumer at the next edge. Align request-valid metadata to that observation point.

    Interview

    State the observation instants: address stable before E, RAM output updated after E, clocked consumer captures that result at E+1.

    Check yourself What does dout show in the cycle after a write to address 7 if address 7 is also being read?

    The old contents of address 7 (read-first behaviour). The new data is visible only in a subsequent read.

    Testbench

    The testbench runs a directed read-first and consumer-latency trace, then 20,000 random reference comparisons.

    ram_sp.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    module ram_sp #(parameter int AW = 6, parameter int DW = 8) (
      input  logic          clk, we,
      input  logic [AW-1:0] addr,
      input  logic [DW-1:0] din,
      output logic [DW-1:0] dout
    );
      logic [DW-1:0] mem [2**AW];                    // the array: no reset, so it can map to a block RAM
    
      always_ff @(posedge clk) begin
        if (we) mem[addr] <= din;                    // synchronous write
        dout <= mem[addr];                           // synchronous read: this is what makes it a block RAM
      end
    endmodule
    

    Remember

    • Data appears one cycle after the address, so a valid bit must travel with the request.

    • A write to the address being read shows the old word on dout (read-first); the new word appears on a later read.

    • A clocked consumer sees the result one edge after dout updates.

    Rule of thumb: wrap the RAM so the rest of the design never assumes its latency.

    How this was checked

    Source checker, run with Icarus Verilog 13.0 (2026-10-16): prints PASS. It runs a directed read-first and consumer-latency trace and 20,000 random reference comparisons. Target mapping is not checked.

    Keep going

    • Practice: Single-port RAM with write-first behaviour

    • Code lab: SRAM model 16x8

    • Interview: run a mock interview on this topic

    Related topics

    • Read-first versus write-first

    Previous

    190 / 350

    Next: Read-First vs Write-First

    Up next

    Up nextRead-First vs Write-First

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Dual-Port RAM Patterns
    • True Dual-Port RAM and Collisions
    • ROM Inference
    clkweaddr7din11dout2211consumer2211
    A write of 0x11 to address 7 while it holds 0x22: the output keeps the old word for one cycle, and a clocked consumer sees each word one edge later