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

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
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. Inference Starts from Coding Style
On this page

    Part 7 of 9, lesson 1 of 57Part 7 of 9/Memory & Buses/Lesson 1 of 57Intermediate

    Inference Starts from Coding Style

    Three codings of a 64-word RAM and what Yosys builds from each one.

    A RAM coded the wrong way synthesises into thousands of flip-flops and a wide mux instead of a block RAM. In the 64-word example, resetting the array adds 64 extra reset writes that no conventional block RAM can perform.

    After this lesson you can: write a RAM that infers a block RAM, and name what breaks inference: an asynchronous read, an array reset or heavy address logic.

    What the tool sees

    Three codings of the same 64-word RAM. Only the first has the synchronous-read, no-array-reset structure expected by a conventional synchronous block RAM. Actual mapping depends on the target resources and synthesis flow.

    ram_good.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // Good: a plain synchronous single-port RAM
    module ram_good #(parameter int AW = 6, 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];
      always_ff @(posedge clk) begin
        if (we) mem[addr] <= din;
        dout <= mem[addr];
      end
    endmodule
    // Bad: asynchronous (combinational) read
    module ram_async_read #(parameter int AW = 6, 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];
      always_ff @(posedge clk) if (we) mem[addr] <= din;
      assign dout = mem[addr];
    endmodule
    // Bad: reset applied to every word of the array
    module ram_reset #(parameter int AW = 6, DW = 8) (input logic clk, rst_n, 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];
      always_ff @(posedge clk) begin
        if (!rst_n) for (int i = 0; i < 2**AW; i++) mem[i] <= '0;
        else begin
          if (we) mem[addr] <= din;
          dout <= mem[addr];
        end
      end
    endmodule

    After reading the source with read_verilog -sv and selecting the module, use proc; memory -nomap; stat; dump to inspect generic memory cells and their port parameters. The -nomap option skips memory_map; a plain memory run includes that pass and lowers any remaining generic memories into word-wide registers and address decoding. A generic memory cell is intermediate inference evidence, not proof of a mapped block RAM. The table describes structural expectations, not measured cell counts:

    Coding

    Read port

    Write behavior

    Generic-memory inspection

    Mapping eligibility

    ram_good

    Clocked (RD_CLK_ENABLE = 1)

    One synchronous write

    Memory with clocked read and write ports

    Eligible for synchronous block RAM; verify target mapping

    ram_async_read

    Not clocked (RD_CLK_ENABLE = 0)

    One synchronous write

    Memory with asynchronous read port

    Not eligible for a synchronous-read block RAM: LUT RAM or flip-flops

    ram_reset

    Output register present but not merged into the read port (RD_CLK_ENABLE = 0 plus a separate $dff); the array reset is the real blocker

    64 reset writes plus one normal write before port optimization

    Array-wide reset writes; port and mux counts depend on optimization

    Conventional block RAM cannot clear every stored word in one cycle

    The ram_reset case is instructive. Its output is functionally registered like ram_good, but dout holds during reset, so Yosys keeps that register as a separate $dff instead of merging it into the read port. The bigger problem is the write side: before port optimization, the loop produces 64 extra reset writes. Optimization may merge ports, but it cannot remove the requirement to clear every stored word in one cycle, which a conventional block RAM cannot implement. For ram_reset, the generic fallback is registers plus a mux tree.

    To establish actual block-RAM mapping, run the target-specific synthesis flow and inspect the mapped RAM primitives, dimensions, and read/write behavior. Do not treat a generic memory count or RD_CLK_ENABLE alone as proof that a device RAM resource was selected.

    Check yourself Does one generic memory cell after memory -nomap prove the design uses block RAM?

    No. It proves memory structure remains at that intermediate stage. Target-specific mapping must select a RAM primitive, and the mapped report must confirm the intended resource and behavior. Plain memory instead maps remaining generic memories to registers and decoding logic.

    Memory contents are almost never reset; for clean contents, write zeros with a short state machine after reset.

    Rules for inference

    1. Use a plain array logic [DW-1:0] mem [DEPTH] and index it.

    2. Write synchronously, in a clocked always_ff, with a write enable.

    3. Read synchronously: assign the read data to a register on the clock edge. This matches the block RAM's registered output.

    4. Don't reset the array. Reset the control logic around it.

    5. One write per port per cycle. Multiple writes to the array from different branches become extra ports.

    6. Keep the address and enable logic simple; wide muxes in front of the array may defeat the mapping.

    7. Read the synthesis report: check the tool reports a RAM of the expected size and type, not thousands of flops.

    Make the check automatic: a script that greps the synthesis log for flip-flop counts above a threshold in the memory module catches an accidental loss of inference at the next synthesis run, not at the end of the project.

    Common mistakes

    Initialisation matters too: initial blocks that fill the array are fine for FPGAs (loaded from the bitstream) and for ROM-like data, but ASIC SRAMs have no initial contents. Don't depend on initial values in an ASIC memory.

    Check yourself Which coding change turns ram_async_read into a block-RAM-compatible RAM?

    Register the read: always_ff @(posedge clk) dout <= mem[addr];, as in ram_good. The read data then appears one cycle after the address.

    • Write synchronously with an enable, read into a register, and never reset the array.

    • Reset the control logic around the memory. To clear contents, run a short state machine after reset.

    • A generic memory cell in the Yosys output is not proof of a mapped block RAM. Check the target-specific report.

    Rule of thumb: read the synthesis report and look for a RAM of the expected size, not thousands of flops.

    • Practice: Asynchronous read memory design in SystemVerilog

    • Code lab: SRAM model 16x8

    • Interview: run a mock interview on this topic

    Related topics

    • Single-port RAM template

    Previous

    189 / 350

    Next: Single-Port Synchronous RAM Template

    Up next

    Up nextSingle-Port Synchronous RAM Template

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Read-First vs Write-First
    • Dual-Port RAM Patterns
    • True Dual-Port RAM and Collisions