Skip to content

[firtool] Memories are compiled with randomization logic, but not macros #8164

@seldridge

Description

@seldridge

The memory randomization logic for FIRRTL memories is being included. However, the required Verilog macros are not being included. This can create situations where memories are not initialized.

Consider the following FIRRTL:

FIRRTL version 4.2.0
circuit Foo:
  public module Foo:
    input clock: Clock
    input r: {addr: UInt<3>, en: UInt<1>, flip data: UInt<32>}
    input w: {addr: UInt<3>, en: UInt<1>, data: UInt<32>, mask: UInt<1>}

    mem memory:
      data-type => UInt<32>
      depth => 16
      reader => r
      writer => w
      read-latency => 1
      write-latency => 1
      read-under-write => undefined

    connect memory.r.addr, r.addr
    connect memory.r.en, r.en
    connect memory.r.clk, clock
    connect r.data, memory.r.data

    connect memory.w.addr, w.addr
    connect memory.w.en, w.en
    connect memory.w.clk, clock
    connect memory.w.data, w.data
    connect memory.w.mask, w.mask

When compiled, this produces (with split-verilog to make it more obvious) the following memory:

// Generated by CIRCT firtool-1.101.0-44-g0cea50e9e
// VCS coverage exclude_file
module memory_16x32(
  input  [3:0]  R0_addr,
  input         R0_en,
                R0_clk,
  output [31:0] R0_data,
  input  [3:0]  W0_addr,
  input         W0_en,
                W0_clk,
  input  [31:0] W0_data
);

  reg [31:0] Memory[0:15];
  reg        _R0_en_d0;
  reg [3:0]  _R0_addr_d0;
  always @(posedge R0_clk) begin
    _R0_en_d0 <= R0_en;
    _R0_addr_d0 <= R0_addr;
  end // always @(posedge)
  always @(posedge W0_clk) begin
    if (W0_en & 1'h1)
      Memory[W0_addr] <= W0_data;
  end // always @(posedge)
  `ifdef ENABLE_INITIAL_MEM_
    `ifdef RANDOMIZE_REG_INIT
      reg [31:0] _RANDOM;
    `endif // RANDOMIZE_REG_INIT
    reg [31:0] _RANDOM_MEM;
    initial begin
      `INIT_RANDOM_PROLOG_
      `ifdef RANDOMIZE_MEM_INIT
        for (logic [4:0] i = 5'h0; i < 5'h10; i += 5'h1) begin
          _RANDOM_MEM = `RANDOM;
          Memory[i[3:0]] = _RANDOM_MEM;
        end
      `endif // RANDOMIZE_MEM_INIT
      `ifdef RANDOMIZE_REG_INIT
        _RANDOM = {`RANDOM};
        _R0_en_d0 = _RANDOM[0];
        _R0_addr_d0 = _RANDOM[4:1];
      `endif // RANDOMIZE_REG_INIT
    end // initial
  `endif // ENABLE_INITIAL_MEM_
  assign R0_data = _R0_en_d0 ? Memory[_R0_addr_d0] : 32'bx;
endmodule

This includes randomization logic, but it will never run unless other macros are defined. To highlight this, see all the macros generated for module Foo:

// Generated by CIRCT firtool-1.101.0-44-g0cea50e9e

// Include rmemory initializers in init blocks unless synthesis is set
`ifndef RANDOMIZE
  `ifdef RANDOMIZE_MEM_INIT
    `define RANDOMIZE
  `endif // RANDOMIZE_MEM_INIT
`endif // not def RANDOMIZE
`ifndef SYNTHESIS
  `ifndef ENABLE_INITIAL_MEM_
    `define ENABLE_INITIAL_MEM_
  `endif // not def ENABLE_INITIAL_MEM_
`endif // not def SYNTHESIS

// Standard header to adapt well known macros for register randomization.

// RANDOM may be set to an expression that produces a 32-bit random unsigned value.
`ifndef RANDOM
  `define RANDOM $random
`endif // not def RANDOM

// Users can define INIT_RANDOM as general code that gets injected into the
// initializer block for modules with registers.
`ifndef INIT_RANDOM
  `define INIT_RANDOM
`endif // not def INIT_RANDOM

// If using random initialization, you can also define RANDOMIZE_DELAY to
// customize the delay used, otherwise 0.002 is used.
`ifndef RANDOMIZE_DELAY
  `define RANDOMIZE_DELAY 0.002
`endif // not def RANDOMIZE_DELAY

// Define INIT_RANDOM_PROLOG_ for use in our modules below.
`ifndef INIT_RANDOM_PROLOG_
  `ifdef RANDOMIZE
    `ifdef VERILATOR
      `define INIT_RANDOM_PROLOG_ `INIT_RANDOM
    `else  // VERILATOR
      `define INIT_RANDOM_PROLOG_ `INIT_RANDOM #`RANDOMIZE_DELAY begin end
    `endif // VERILATOR
  `else  // RANDOMIZE
    `define INIT_RANDOM_PROLOG_
  `endif // RANDOMIZE
`endif // not def INIT_RANDOM_PROLOG_
module Foo(
  input         clock,
  input  [2:0]  r_addr,
  input         r_en,
  output [31:0] r_data,
  input  [2:0]  w_addr,
  input         w_en,
  input  [31:0] w_data,
  input         w_mask
);

  memory_16x32 memory_ext (
    .R0_addr ({1'h0, r_addr}),
    .R0_en   (r_en),
    .R0_clk  (clock),
    .R0_data (r_data),
    .W0_addr ({1'h0, w_addr}),
    .W0_en   (w_en & w_mask),
    .W0_clk  (clock),
    .W0_data (w_data)
  );
endmodule

Fix this by generating the macros for the memory.

Metadata

Metadata

Assignees

Labels

FIRRTLInvolving the `firrtl` dialectSeqInvolving the `seq` dialectbugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions