[circt-verilog] Add register-to-memory pass to pipeline (#8773)

Add the new RegOfVecToMem pass to the circt-verilog pipeline. This will
detect memories described as `always` blocks and map them from the
current `seq.firreg` representation to the correpsonding `seq.firmem`.
This allows later parts of the pipeline to reason about memories more
easily and transform them if needed.
This commit is contained in:
Fabian Schuiki 2025-07-23 15:24:37 -07:00 committed by GitHub
parent 5c3780f58b
commit dbbc952d89
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 49 additions and 0 deletions

View File

@ -0,0 +1,34 @@
// RUN: circt-verilog %s | FileCheck %s --check-prefixes=CHECK,MEMON
// RUN: circt-verilog --detect-memories=1 %s | FileCheck %s --check-prefixes=CHECK,MEMON
// RUN: circt-verilog --detect-memories=0 %s | FileCheck %s --check-prefixes=CHECK,MEMOFF
// REQUIRES: slang
// Internal issue in Slang v3 about jump depending on uninitialised value.
// UNSUPPORTED: valgrind
// CHECK-LABEL: hw.module @Memory(
module Memory(
input bit clock,
input bit [3:0] waddr,
input bit [41:0] wdata,
input bit wenable,
input bit [3:0] raddr,
output bit [41:0] rdata
);
// CHECK-DAG: [[CLK:%.+]] = seq.to_clock %clock
// MEMON-DAG: [[MEM:%.+]] = seq.firmem 0, 1, undefined, undefined : <16 x 42, mask 1>
// MEMON-DAG: [[RDATA:%.+]] = seq.firmem.read_port [[MEM]][%raddr]
// MEMON-DAG: seq.firmem.write_port %mem[%waddr] = %wdata, clock [[CLK]] enable %wenable
// MEMOFF-DAG: [[REG:%.+]] = seq.firreg [[NEXT:%.+]] clock [[CLK]] : !hw.array<16xi42>
// MEMOFF-DAG: [[TMP:%.+]] = hw.array_inject [[REG]][%waddr], %wdata
// MEMOFF-DAG: [[NEXT]] = comb.mux bin %wenable, [[TMP]], [[REG]]
// MEMOFF-DAG: [[RDATA:%.+]] = hw.array_get [[REG]][%raddr]
// CHECK: hw.output [[RDATA]]
bit [41:0] storage [15:0];
always_ff @(posedge clock)
if (wenable)
storage[waddr] <= wdata;
assign rdata = storage[raddr];
endmodule

View File

@ -9,6 +9,7 @@ set(libs
CIRCTMooreToCore
CIRCTMooreTransforms
CIRCTSeq
CIRCTSeqTransforms
CIRCTSim
CIRCTSupport
CIRCTTransforms

View File

@ -23,6 +23,7 @@
#include "circt/Dialect/Moore/MooreDialect.h"
#include "circt/Dialect/Moore/MoorePasses.h"
#include "circt/Dialect/Seq/SeqDialect.h"
#include "circt/Dialect/Seq/SeqPasses.h"
#include "circt/Dialect/Sim/SimDialect.h"
#include "circt/Dialect/Verif/VerifDialect.h"
#include "circt/Support/Passes.h"
@ -129,6 +130,11 @@ struct CLOptions {
cl::desc("Interpret `always @(*)` as `always_comb`"), cl::init(true),
cl::cat(cat)};
cl::opt<bool> detectMemories{
"detect-memories",
cl::desc("Detect memories and lower them to `seq.firmem`"),
cl::init(true), cl::cat(cat)};
//===--------------------------------------------------------------------===//
// Include paths
//===--------------------------------------------------------------------===//
@ -354,6 +360,14 @@ static void populateLLHDLowering(PassManager &pm) {
modulePM.addPass(llhd::createSig2Reg());
modulePM.addPass(mlir::createCSEPass());
modulePM.addPass(mlir::createCanonicalizerPass());
// Map `seq.firreg` with array type and `hw.array_inject` self-feedback to
// `seq.firmem` ops.
if (opts.detectMemories) {
modulePM.addPass(seq::createRegOfVecToMem());
modulePM.addPass(mlir::createCSEPass());
modulePM.addPass(mlir::createCanonicalizerPass());
}
}
/// Populate the given pass manager with transformations as configured by the