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. True Dual-Port RAM and Collisions

Part 7 · Memory & Buses · Intermediate

True Dual-Port RAM and Collisions

Write-write collisions in true dual-port RAMs and a wrapper where port A wins and a flag is raised.

On this page

    Why this matters

    Two ports writing the same address in one cycle leave a hardware RAM with either value, a mix of bits or a corrupted word, and the result differs between devices. Interviewers ask what you do about it.

    After this lesson you can: list the ways to handle a write-write collision and say what each costs in the write-enable path.

    The write-write collision

    Two ports writing the same address in the same cycle is a collision. A hardware RAM gives an undefined result: either value, a mix of bits, or a corrupted word.

    The behaviour differs between devices, so a design that causes collisions is not portable. Prevent them at the system level, or make them defined in a wrapper.

    Handling collisions

    Option

    Cost

    When

    Design them out: arbitration or address partitioning so ports never touch the same word

    None in the RAM

    Preferred

    Priority (see the wrapper below) with a flag

    A comparator and a mux on the write enable of the lower-priority port

    When collisions are rare but must be defined

    Merge (byte enables) so non-overlapping bytes both succeed

    Per-byte enables and comparators

    Bus masters writing different bytes of the same word

    Assertion only: collisions are a bug

    Simulation-only check

    Systems where a collision means a design error

    A priority mux makes the RAM slower: the write-enable path now includes an address comparator. If the RAM runs at the limit of its clock, the collision logic can be the critical path.

    Move the comparison into the control logic one cycle earlier if necessary.

    Common pitfall

    Collision-safe wrappers only work with one clock for both ports. Between two unrelated clocks the two writes cannot be compared in the same instant, so collisions must be prevented by protocol (a handshake or a pointer-based design such as the async FIFO).

    Interview

    A common question: “What happens if both ports of a dual-port RAM write the same address?” Undefined in hardware; say how you would prevent it (arbitration, address partitioning) or define it (priority plus a flag).

    Same-port read-during-write mode and opposite-port collision behaviour are separate contracts. A common clock alone does not make the opposite port's read valid: AMD block RAM returns old data in the supported READ_FIRST configuration, but the opposite read can be invalid when the writing port uses WRITE_FIRST or NO_CHANGE. The wrapper below specifies old-data reads on both ports; mapping it to a macro requires that exact common-clock cross-port guarantee, or explicit forwarding/collision exclusion.

    Check yourself Why does this wrapper flag only write-write collisions?

    Its RTL defines old-data reads for same-address read/write collisions on either port, while the flag reports two competing writes and port A wins. That old-data contract must be checked against the target macro; common-clock WRITE_FIRST or NO_CHANGE does not generally guarantee valid opposite-port read data.

    Port A wins, cycle by cycle

    The wrapper below makes the collision defined. Here it runs a short directed sequence in which every access goes to address 5, which starts at 0x00.

    Each slot is one clock cycle. A request offered in a slot lands at the edge that ends it, so mem5 (the word at address 5) and doutb change one slot later.

    • Slot 0: port A writes 0x11 and port B writes 0x22 to the same word. collision is high, and in slot 1 the word holds 0x11: port A won.

    • Slot 2: only port B writes, 0x33. It succeeds, and mem5 is 0x33 in slot 3.

    • Slot 3: port A writes 0x44 while port B reads. doutb in slot 4 is the old word 0x33, and the new word 0x44 reaches it in slot 5.

    Testbench

    A common-clock wrapper where port A wins competing writes and both read outputs return old data. The testbench checks the winner and both directions of cross-port read/write collision. These RTL checks do not establish a physical macro's collision mode; review its configuration and implementation report separately.

    ram_tdp_safe.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // True dual-port RAM that makes the write-write collision DEFINED: port A wins, and a flag is raised.
    module ram_tdp_safe #(parameter int AW = 4, parameter int DW = 8) (
      input  logic          clk,                                      // one clock for both ports (typical for a collision-safe design)
      input  logic          wea, web,
      input  logic [AW-1:0] addra, addrb,
      input  logic [DW-1:0] dina, dinb,
      output logic [DW-1:0] douta, doutb,
      output logic          collision                                 // both ports write the same address in the same cycle
    );
      logic [DW-1:0] mem [2**AW];
      assign collision = wea && web && (addra == addrb);
    
      // Requires a target with common-clock old-data reads on BOTH ports during a collision.
      always_ff @(posedge clk) begin
        if (wea) mem[addra] <= dina;
        if (web && !(wea && addra == addrb)) mem[addrb] <= dinb;       // on a collision port A wins
        douta <= mem[addra];
        doutb <= mem[addrb];
      end
    endmodule
    

    Step

    Port A

    Port B

    Result

    1

    write 0xAA to address 2

    write 0xBB to address 9

    Both writes succeed

    2

    write 0x11 to address 5

    write 0x22 to address 5

    Collision flagged, port A wins: address 5 holds 0x11

    3

    idle

    write 0x33 to address 5

    Port B writes normally: address 5 holds 0x33

    Remember

    • A same-cycle write to one address is undefined in hardware and not portable.

    • Prevent it by arbitration or address partitioning, or define it in a wrapper with a priority port and a collision flag.

    • A collision-safe wrapper needs one clock for both ports, and the address comparator can become the critical path.

    Rule of thumb: never leave a collision undefined: prevent it, or define the winner and raise a flag.

    How this was checked

    The testbench checks the RTL wrapper's winner and both directions of cross-port read and write collision. These RTL checks do not establish a physical macro's collision mode; review its configuration and implementation report separately.

    Keep going

    • Practice: Dual-port RAM with read-after-write handling

    • Code lab: True dual-port RAM sketch

    • Interview: run a mock interview on this topic

    Related topics

    • ROM inference

    Previous

    193 / 350

    Next: ROM Inference

    Up next

    Up nextROM Inference

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Inference Starts from Coding Style
    • Single-Port Synchronous RAM Template
    • Read-First vs Write-First
    clkweawebcollisionmem50113344doutb0113344
    ram_tdp_safe with every access to address 5: both ports write in slot 0 and port A's 0x11 is stored, then port B reads old data while port A writes in slot 3