Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Import memory files inline for Verilog generation #1805

Merged
merged 1 commit into from
Mar 11, 2021

Conversation

carlosedp
Copy link
Contributor

@carlosedp carlosedp commented Mar 9, 2021

This annotation adds memory import with inline generation for the
emmiter.
Supports both readmemh and readmemb statements based on argument.

This PR depends on FIRRTL version with merged PR chipsalliance/firrtl#2107.

Example code:

package utils

import chisel3._
import chisel3.util.experimental.loadMemoryFromFileInline

class DualPortRAM(words: Int = 1, width: Int = 32, memoryFile: String = "")
    extends Module {
  val addrWidth = chiselTypeOf((words * 1024).U)
  val io = IO(new Bundle {
    // Port 1
    val addr1 = Input(addrWidth)
    val addr2 = Input(addrWidth)
    val dataIn1 = Input(UInt(width.W))
    val we1 = Input(Bool())
    val dataOut1 = Output(UInt(width.W))
    val dataOut2 = Output(UInt(width.W))
  })
  val mem = SyncReadMem(words, UInt(width.W))
  loadMemoryFromFileInline(mem, memoryFile)

  // Port 1
  io.dataOut1 := mem.read(io.addr1)
  when(io.we1) {
    mem.write(io.addr1, io.dataIn1)
  }
  // Port 2
  io.dataOut2 := mem.read(io.addr2)
}

object DualPortRAMObj extends App {
  (new chisel3.stage.ChiselStage).emitVerilog(
    new DualPortRAM(16, width = 64, memoryFile = "sample.hex"),
    Array("-X", "verilog") ++ args
  )
}

Generated Verilog:

module DualPortRAM(
  input         clock,
  input         reset,
  input  [14:0] io_addr1,
  input  [14:0] io_addr2,
  input  [63:0] io_dataIn1,
  input         io_we1,
  output [63:0] io_dataOut1,
  output [63:0] io_dataOut2
);
`ifdef RANDOMIZE_REG_INIT
  reg [31:0] _RAND_0;
  reg [31:0] _RAND_1;
`endif // RANDOMIZE_REG_INIT
  reg [63:0] mem [0:15]; // @[DualportRAM.scala 26:24]
  wire [63:0] mem_MPORT_data; // @[DualportRAM.scala 26:24]
  wire [3:0] mem_MPORT_addr; // @[DualportRAM.scala 26:24]
  wire [63:0] mem_MPORT_2_data; // @[DualportRAM.scala 26:24]
  wire [3:0] mem_MPORT_2_addr; // @[DualportRAM.scala 26:24]
  wire [63:0] mem_MPORT_1_data; // @[DualportRAM.scala 26:24]
  wire [3:0] mem_MPORT_1_addr; // @[DualportRAM.scala 26:24]
  wire  mem_MPORT_1_mask; // @[DualportRAM.scala 26:24]
  wire  mem_MPORT_1_en; // @[DualportRAM.scala 26:24]
  reg [3:0] mem_MPORT_addr_pipe_0;
  reg [3:0] mem_MPORT_2_addr_pipe_0;
  assign mem_MPORT_addr = mem_MPORT_addr_pipe_0;
  assign mem_MPORT_data = mem[mem_MPORT_addr]; // @[DualportRAM.scala 26:24]
  assign mem_MPORT_2_addr = mem_MPORT_2_addr_pipe_0;
  assign mem_MPORT_2_data = mem[mem_MPORT_2_addr]; // @[DualportRAM.scala 26:24]
  assign mem_MPORT_1_data = io_dataIn1;
  assign mem_MPORT_1_addr = io_addr1[3:0];
  assign mem_MPORT_1_mask = 1'h1;
  assign mem_MPORT_1_en = io_we1;
  assign io_dataOut1 = mem_MPORT_data; // @[DualportRAM.scala 33:15]
  assign io_dataOut2 = mem_MPORT_2_data; // @[DualportRAM.scala 38:15]
  always @(posedge clock) begin
    if (mem_MPORT_1_en & mem_MPORT_1_mask) begin
      mem[mem_MPORT_1_addr] <= mem_MPORT_1_data; // @[DualportRAM.scala 26:24]
    end
    mem_MPORT_addr_pipe_0 <= io_addr1[3:0];
    mem_MPORT_2_addr_pipe_0 <= io_addr2[3:0];
  end
// Register and memory initialization
`ifdef RANDOMIZE_GARBAGE_ASSIGN
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_INVALID_ASSIGN
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_REG_INIT
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_MEM_INIT
`define RANDOMIZE
`endif
`ifndef RANDOM
`define RANDOM $random
`endif
  integer initvar;
`ifndef SYNTHESIS
`ifdef FIRRTL_BEFORE_INITIAL
`FIRRTL_BEFORE_INITIAL
`endif
initial begin
  `ifdef RANDOMIZE
    `ifdef INIT_RANDOM
      `INIT_RANDOM
    `endif
    `ifndef VERILATOR
      `ifdef RANDOMIZE_DELAY
        #`RANDOMIZE_DELAY begin end
      `else
        #0.002 begin end
      `endif
    `endif
`ifdef RANDOMIZE_REG_INIT
  _RAND_0 = {1{`RANDOM}};
  mem_MPORT_addr_pipe_0 = _RAND_0[3:0];
  _RAND_1 = {1{`RANDOM}};
  mem_MPORT_2_addr_pipe_0 = _RAND_1[3:0];
`endif // RANDOMIZE_REG_INIT
  `endif // RANDOMIZE

initial begin
  $readmemh("sample.hex", mem);
end
end // initial
`ifdef FIRRTL_AFTER_INITIAL
`FIRRTL_AFTER_INITIAL
`endif
`endif // SYNTHESIS
endmodule

Contributor Checklist

  • Did you add Scaladoc to every public function/method?
  • Did you add at least one test demonstrating the PR?
  • Did you delete any extraneous printlns/debugging code?
  • Did you specify the type of improvement?
  • Did you add appropriate documentation in docs/src?
  • Did you state the API impact?
  • Did you specify the code generation impact?
  • Did you request a desired merge strategy?
  • Did you add text to be included in the Release Notes for this change?

Type of Improvement

  • new feature/API

API Impact

This change adds a new annotation method supporting load memory files inline in generated Verilog code. No impacts to existing methods or API.

Backend Code Generation Impact

The change adds inline memory read statements to generated Verilog backend.

Desired Merge Strategy

  • Squash: The PR will be squashed and merged

Release Notes

(addition) Added loadMemoryFromFileInline annotation in chisel3.util.experimental to allow loading hex and bin memory files inline in Verilog emitter backend(#1805)

Reviewer Checklist (only modified by reviewer)

  • Did you add the appropriate labels?
  • Did you mark the proper milestone (3.2.x, 3.3.x, 3.4.0, 3.5.0) ?
  • Did you review?
  • Did you check whether all relevant Contributor checkboxes have been checked?
  • Did you mark as Please Merge?

@CLAassistant
Copy link

CLAassistant commented Mar 9, 2021

CLA assistant check
All committers have signed the CLA.

@jackkoenig
Copy link
Contributor

I believe this CI failure is unrelated. I intend to look into it today.

@jackkoenig
Copy link
Contributor

CI failure is fixed in chipsalliance/firrtl#2112, so once that's merged we can rerun CI

Copy link
Contributor

@jackkoenig jackkoenig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great. I have a couple of minor suggestions and a meta point for @mwachs5 about that Wiki link.

This annotation adds memory import with inline generation for the
emmiter.
Supports both readmemh and readmemb statements based on argument.
Copy link
Contributor

@jackkoenig jackkoenig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Nice work!

@jackkoenig jackkoenig added this to the 3.4.x milestone Mar 11, 2021
@jackkoenig jackkoenig added Feature New feature, will be included in release notes Please Merge Accepted PRs that are ready to be merged. Useful when waiting on CI. labels Mar 11, 2021
@ekiwi ekiwi self-requested a review March 11, 2021 21:25
Copy link
Contributor

@ekiwi ekiwi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚢

@mergify mergify bot merged commit 9ea57e0 into chipsalliance:master Mar 11, 2021
mergify bot pushed a commit that referenced this pull request Mar 11, 2021
This annotation adds memory import with inline generation for the
emmiter.
Supports both readmemh and readmemb statements based on argument.

(cherry picked from commit 9ea57e0)
@mergify mergify bot added the Backported This PR has been backported label Mar 11, 2021
mergify bot added a commit that referenced this pull request Mar 11, 2021
This annotation adds memory import with inline generation for the
emmiter.
Supports both readmemh and readmemb statements based on argument.

(cherry picked from commit 9ea57e0)

Co-authored-by: Carlos Eduardo <carlosedp@gmail.com>
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
Backported This PR has been backported Feature New feature, will be included in release notes Please Merge Accepted PRs that are ready to be merged. Useful when waiting on CI.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants