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
  • Advanced RTL28
    • Parameterization and Generate Hub
    • Top-Level Integration Hub
    • Synthesis Intent Hub
      • Inference-focused coding style
      • Inferring flip-flops and RAM
      • Latch avoidance and case semantics
      • Reading a synthesis report
    • Style and Static Checks Hub
    • Assertions in RTL Hub
    • Formal Verification Basics Hub
    • Reusable SystemVerilog for RTL
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹Synthesis Intent Hub
  1. Topics
  2. RTL Design
  3. Advanced RTL
  4. Synthesis Intent Hub
  5. Inferring flip-flops and RAM

Part 8 · Advanced · Advanced

Inferring flip-flops and RAM

An enabled flop and a synchronous RAM, with the same-address collision defined.

On this page

    Why this matters

    An array with an asynchronous read or an array reset can turn into thousands of flip-flops where a RAM was expected. The report shows it only after synthesis, so know the template first.

    After this lesson you can: write a flip-flop with enable and a synchronous RAM with a stated collision policy, and explain why q trails d by one cycle.

    A flip-flop with enable

    Storage infers from a clocked process. Reset comes first, then the enable guard, so reset wins regardless of enable.

    dff_en.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // yosys: ok
    module dff_en (
      input logic clk, rst_n, en,
      input logic [7:0] d,
      output logic [7:0] q
    );
      always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) q <= '0;
        else if (en) q <= d;
      end
    endmodule

    The middle row, en, decides whether d reaches q. Inputs change just after a rising edge, so the values drawn in one slot are captured at the edge that starts the next slot: q trails d by one cycle.

    • Slot 1: rst_n is 0, so q is 0 (in reset).

    • Slot 2: rst_n is 1, en is 1 and d is a5. q is still 0; nothing has been captured yet.

    • Slot 3: the edge captured a5, so q is a5. Now en is 0 and d is 3c.

    • Slot 4: en was 0 at the edge, so q holds a5. en goes back to 1.

    • Slot 5: the edge captured 3c, so q is 3c. d changes to f0.

    • Slot 6: the edge captured f0, so q is f0.

    • Slot 7: rst_n falls, so q is 0 at once (the asynchronous reset does not wait for an edge).

    A synchronous RAM

    This array has clocked writes and registered reads with read-first RTL semantics. It is compatible with some synchronous RAM templates, subject to target dimensions, ports and collision support. Mapping reports must confirm the actual resource. This version reads the old word when one address is written and read together.

    ram_sp_sync.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // yosys: ok
    module ram_sp_sync #(parameter int AW = 4, parameter int DW = 8) (
      input logic clk, wr_en,
      input logic [AW-1:0] addr,
      input logic [DW-1:0] wdata,
      output logic [DW-1:0] rdata
    );
      logic [DW-1:0] mem [2**AW];                  // no reset on the array, so it can map to a block RAM
      always_ff @(posedge clk) begin
        if (wr_en) mem[addr] <= wdata;             // synchronous write
        rdata <= mem[addr];                        // synchronous read: old word on a same-address collision
      end
    endmodule

    Waveform modeling assumption: its separate source zero-fills memory initially, hence 00 on the first writes to addresses 3 and 5. The lesson RAM above has no initialization: an unwritten old word is unknown in four-state simulation, not guaranteed zero in hardware. The bench below preloads addresses before checking their data and collision behavior.

    The bottom row, rdata, trails the address by one cycle: the access drawn in one slot completes at the edge that starts the next slot.

    • Slot 1: write 22 to address 3. rdata is 00 from the read of address 3 one cycle earlier.

    • Slot 2: read address 3. rdata is 00: the slot 1 write and read hit address 3 together, so the read returned the old word.

    • Slot 3: write 11 to address 3. rdata is 22 from the slot 2 read.

    • Slot 4: read address 3. rdata is still 22: the slot 3 write collided and returned the old word (read-first).

    • Slot 5: write 77 to address 5. rdata is 11 from the slot 4 read.

    • Slot 6: read address 5. rdata is 00, the old word under the slot 5 write.

    • Slot 7: rdata is 77 from the slot 6 read.

    The collision policy is explicit: a same-cycle write plus read returns the old word. The new word is visible in a read issued in a later cycle.

    Common mistakes

    Common pitfall

    A combinational read (assign rdata = mem[addr]) is incompatible with many synchronous FPGA block RAMs, but can infer asynchronous-read LUT RAM on supported targets. Select the required latency and resource first, follow its documented template, then inspect mapping reports. Any area or timing cost requires a measured comparison on that target.

    Interview

    Likely question: “Describe the cycles of a synchronous RAM read.”

    • Address presented before the edge, data registered at the edge.

    • Data available in the next cycle, one access per cycle.

    • Collision on one address returns the old word in read-first mode.

    Check yourself Enable is low and d changes. What does q do?

    Nothing. It holds its value until enable is high at a clock edge.

    Check yourself A write and a read hit address 3 in the same cycle. What does the read return in the template above, and when is the new data visible?

    The old word. The new data is visible in a read issued in a later cycle, as slots 3 to 5 of the waveform show: the slot 3 write returns 22 in slot 4, and the slot 4 read returns 11 in slot 5.

    Testbench

    The flop and the RAM plus a testbench that checks reset, enable and the collision.

    dff_en.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    module dff_en (
      input logic clk, rst_n, en,
      input logic [7:0] d,
      output logic [7:0] q
    );
      always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) q <= '0;
        else if (en) q <= d;
      end
    endmodule
    
    module ram_sp_sync #(parameter int AW = 4, parameter int DW = 8) (
      input logic clk, wr_en,
      input logic [AW-1:0] addr,
      input logic [DW-1:0] wdata,
      output logic [DW-1:0] rdata
    );
      logic [DW-1:0] mem [2**AW];
      always_ff @(posedge clk) begin
        if (wr_en) mem[addr] <= wdata;
        rdata <= mem[addr];
      end
    endmodule
    

    Remember

    • A clocked process infers storage; reset comes first, then the enable guard.

    • Many block RAMs need synchronous reads, no array reset and supported port counts.

    • State the collision policy: a same-cycle write and read returns the old word, and the new word shows in a later read.

    Rule of thumb: choose the latency and resource first, then write the template that maps to it.

    How this was checked

    Testbench run with Icarus Verilog 13.0 (2026-10-16): prints PASS. It checks reset, enable and the collision case. The RAM waveform uses a separate source that zero-fills memory; the lesson RAM has no initialisation, so an unwritten word is unknown in simulation and not guaranteed zero in hardware.

    Keep going

    • Practice: Parameterised single-port synchronous RAM

    • Code lab: SRAM model 16x8

    • Interview: run a mock interview on this topic

    Related topics

    • Latch avoidance and case semantics

    • Single-port synchronous RAM template

    Previous

    253 / 350

    Next: Latch avoidance and case semantics

    Up next

    Up nextLatch avoidance and case semantics

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Reading a synthesis report
    clkrst_nend0a53cf0q0a53cf00
    An enabled flop through reset, capture, hold and re-reset
    clkwr_enaddr35rdata02211077
    A same-address write and read returning the old word