Add options for controlling emission of randomization code. (#4240)

Add `--disable-{mem,reg,all}-randomization` to firtool.

Fixes #4202.
This commit is contained in:
Will Dietz 2022-11-04 14:46:51 -05:00 committed by GitHub
parent b12d21b682
commit 937457399f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 265 additions and 179 deletions

View File

@ -23,10 +23,10 @@ class Pass;
namespace circt {
std::unique_ptr<mlir::Pass>
createLowerFIRRTLToHWPass(bool enableAnnotationWarning = false,
bool emitChiselAssertsAsSVA = false,
bool stripMuxPragmas = false);
std::unique_ptr<mlir::Pass> createLowerFIRRTLToHWPass(
bool enableAnnotationWarning = false, bool emitChiselAssertsAsSVA = false,
bool stripMuxPragmas = false, bool disableMemRandomization = false,
bool disableRegRandomization = false);
} // namespace circt

View File

@ -288,6 +288,10 @@ def LowerFIRRTLToHW : Pass<"lower-firrtl-to-hw", "mlir::ModuleOp"> {
let dependentDialects = ["comb::CombDialect", "hw::HWDialect",
"seq::SeqDialect", "sv::SVDialect"];
let options = [
Option<"disableMemRandomization", "disable-mem-randomization", "bool", "false",
"Disable emission of memory randomization code">,
Option<"disableRegRandomization", "disable-reg-randomization", "bool", "false",
"Disable emission of register randomization code">,
Option<"enableAnnotationWarning", "warn-on-unprocessed-annotations",
"bool", "false",
"Emit warnings on unprocessed annotations during lower-to-hw pass">,

View File

@ -25,10 +25,10 @@ std::unique_ptr<mlir::Pass> createHWStubExternalModulesPass();
std::unique_ptr<mlir::Pass> createHWLegalizeModulesPass();
std::unique_ptr<mlir::Pass> createSVTraceIVerilogPass();
std::unique_ptr<mlir::Pass> createHWGeneratorCalloutPass();
std::unique_ptr<mlir::Pass>
createHWMemSimImplPass(bool replSeqMem = false,
bool ignoreReadEnableMem = false,
bool stripMuxPragmas = false);
std::unique_ptr<mlir::Pass> createHWMemSimImplPass(
bool replSeqMem = false, bool ignoreReadEnableMem = false,
bool stripMuxPragmas = false, bool disableMemRandomization = false,
bool disableRegRandomization = false);
std::unique_ptr<mlir::Pass>
createSVExtractTestCodePass(bool disableInstanceExtraction = false,
bool disableModuleInlining = false);

View File

@ -94,6 +94,10 @@ def HWMemSimImpl : Pass<"hw-memory-sim", "ModuleOp"> {
let dependentDialects = ["circt::sv::SVDialect"];
let options = [
Option<"disableMemRandomization", "disable-mem-randomization", "bool", "false",
"Disable emission of memory randomization code">,
Option<"disableRegRandomization", "disable-reg-randomization", "bool", "false",
"Disable emission of register randomization code">,
Option<"replSeqMem", "repl-seq-mem", "bool",
"false", "Prepare seq mems for macro replacement">,
Option<"ignoreReadEnableMem", "ignore-read-enable-mem", "bool",

View File

@ -20,7 +20,8 @@ namespace circt {
namespace seq {
std::unique_ptr<mlir::Pass> createSeqLowerToSVPass();
std::unique_ptr<mlir::Pass> createSeqFIRRTLLowerToSVPass();
std::unique_ptr<mlir::Pass>
createSeqFIRRTLLowerToSVPass(bool disableRegRandomization = false);
std::unique_ptr<mlir::Pass> createLowerSeqHLMemPass();
/// Generate the code for registering passes.

View File

@ -25,6 +25,10 @@ def LowerSeqFIRRTLToSV: Pass<"lower-seq-firrtl-to-sv", "hw::HWModuleOp"> {
let summary = "Lower sequential firrtl ops to SV.";
let constructor = "circt::seq::createSeqFIRRTLLowerToSVPass()";
let dependentDialects = ["circt::sv::SVDialect"];
let options = [
Option<"disableRegRandomization", "disable-reg-randomization", "bool", "false",
"Disable emission of register randomization code">
];
}
def LowerSeqHLMem: Pass<"lower-seq-hlmem", "hw::HWModuleOp"> {

View File

@ -449,6 +449,8 @@ namespace {
struct FIRRTLModuleLowering : public LowerFIRRTLToHWBase<FIRRTLModuleLowering> {
void runOnOperation() override;
void setDisableMemRandomization() { disableMemRandomization = true; }
void setDisableRegRandomization() { disableRegRandomization = true; }
void setEnableAnnotationWarning() { enableAnnotationWarning = true; }
void setEmitChiselAssertAsSVA() { emitChiselAssertsAsSVA = true; }
void setStripMuxPragmas() { stripMuxPragmas = true; }
@ -480,10 +482,10 @@ private:
} // end anonymous namespace
/// This is the pass constructor.
std::unique_ptr<mlir::Pass>
circt::createLowerFIRRTLToHWPass(bool enableAnnotationWarning,
bool emitChiselAssertsAsSVA,
bool stripMuxPragmas) {
std::unique_ptr<mlir::Pass> circt::createLowerFIRRTLToHWPass(
bool enableAnnotationWarning, bool emitChiselAssertsAsSVA,
bool stripMuxPragmas, bool disableMemRandomization,
bool disableRegRandomization) {
auto pass = std::make_unique<FIRRTLModuleLowering>();
if (enableAnnotationWarning)
pass->setEnableAnnotationWarning();
@ -491,6 +493,10 @@ circt::createLowerFIRRTLToHWPass(bool enableAnnotationWarning,
pass->setEmitChiselAssertAsSVA();
if (stripMuxPragmas)
pass->setStripMuxPragmas();
if (disableMemRandomization)
pass->setDisableMemRandomization();
if (disableRegRandomization)
pass->setDisableRegRandomization();
return pass;
}
@ -827,10 +833,15 @@ void FIRRTLModuleLowering::lowerFileHeader(CircuitOp op,
}
};
bool needsRandomizeRegInit =
state.used_RANDOMIZE_REG_INIT && !disableRegRandomization;
bool needsRandomizeMemInit =
state.used_RANDOMIZE_MEM_INIT && !disableMemRandomization;
// If none of the macros are needed, then don't emit any header at all, not
// even the header comment.
if (!state.used_RANDOMIZE_GARBAGE_ASSIGN && !state.used_RANDOMIZE_REG_INIT &&
!state.used_RANDOMIZE_MEM_INIT && !state.used_PRINTF_COND &&
if (!state.used_RANDOMIZE_GARBAGE_ASSIGN && !needsRandomizeRegInit &&
!needsRandomizeMemInit && !state.used_PRINTF_COND &&
!state.used_ASSERT_VERBOSE_COND && !state.used_STOP_COND)
return;
@ -841,11 +852,11 @@ void FIRRTLModuleLowering::lowerFileHeader(CircuitOp op,
emitGuardedDefine("RANDOMIZE_GARBAGE_ASSIGN", "RANDOMIZE");
needRandom = true;
}
if (state.used_RANDOMIZE_REG_INIT) {
if (needsRandomizeRegInit) {
emitGuardedDefine("RANDOMIZE_REG_INIT", "RANDOMIZE");
needRandom = true;
}
if (state.used_RANDOMIZE_MEM_INIT) {
if (needsRandomizeMemInit) {
emitGuardedDefine("RANDOMIZE_MEM_INIT", "RANDOMIZE");
needRandom = true;
}

View File

@ -48,6 +48,8 @@ namespace {
class HWMemSimImpl {
bool ignoreReadEnableMem;
bool stripMuxPragmas;
bool disableMemRandomization;
bool disableRegRandomization;
SmallVector<sv::RegOp> registers;
@ -57,9 +59,12 @@ class HWMemSimImpl {
sv::AlwaysOp lastPipelineAlwaysOp;
public:
HWMemSimImpl(bool ignoreReadEnableMem, bool stripMuxPragmas)
HWMemSimImpl(bool ignoreReadEnableMem, bool stripMuxPragmas,
bool disableMemRandomization, bool disableRegRandomization)
: ignoreReadEnableMem(ignoreReadEnableMem),
stripMuxPragmas(stripMuxPragmas) {}
stripMuxPragmas(stripMuxPragmas),
disableMemRandomization(disableMemRandomization),
disableRegRandomization(disableRegRandomization) {}
void generateMemory(HWModuleOp op, FirMemory mem);
};
@ -70,6 +75,8 @@ struct HWMemSimImplPass : public sv::HWMemSimImplBase<HWMemSimImplPass> {
using sv::HWMemSimImplBase<HWMemSimImplPass>::ignoreReadEnableMem;
using sv::HWMemSimImplBase<HWMemSimImplPass>::replSeqMem;
using sv::HWMemSimImplBase<HWMemSimImplPass>::stripMuxPragmas;
using sv::HWMemSimImplBase<HWMemSimImplPass>::disableMemRandomization;
using sv::HWMemSimImplBase<HWMemSimImplPass>::disableRegRandomization;
};
} // end anonymous namespace
@ -415,8 +422,14 @@ void HWMemSimImpl::generateMemory(HWModuleOp op, FirMemory mem) {
}
}
auto *outputOp = op.getBodyBlock()->getTerminator();
outputOp->setOperands(outputs);
// Add logic to initialize the memory and any internal registers to random
// values.
if (disableMemRandomization && disableRegRandomization)
return;
constexpr unsigned randomWidth = 32;
sv::RegOp randomMemReg;
b.create<sv::IfDefOp>("SYNTHESIS", std::function<void()>(), [&]() {
@ -424,131 +437,138 @@ void HWMemSimImpl::generateMemory(HWModuleOp op, FirMemory mem) {
StringRef initvar;
// Declare variables for use by memory randomization logic.
b.create<sv::IfDefOp>("RANDOMIZE_MEM_INIT", [&]() {
initvar = moduleNamespace.newName("initvar");
b.create<sv::VerbatimOp>("integer " + Twine(initvar) + ";\n");
randomMemReg = b.create<sv::RegOp>(
b.getIntegerType(llvm::divideCeil(mem.dataWidth, randomWidth) *
randomWidth),
b.getStringAttr("_RANDOM_MEM"),
b.getStringAttr(moduleNamespace.newName("_RANDOM_MEM")));
});
if (!disableMemRandomization) {
b.create<sv::IfDefOp>("RANDOMIZE_MEM_INIT", [&]() {
initvar = moduleNamespace.newName("initvar");
b.create<sv::VerbatimOp>("integer " + Twine(initvar) + ";\n");
randomMemReg = b.create<sv::RegOp>(
b.getIntegerType(llvm::divideCeil(mem.dataWidth, randomWidth) *
randomWidth),
b.getStringAttr("_RANDOM_MEM"),
b.getStringAttr(moduleNamespace.newName("_RANDOM_MEM")));
});
}
// Declare variables for use by register randomization logic.
SmallVector<sv::RegOp> randRegs;
b.create<sv::IfDefOp>("RANDOMIZE_REG_INIT", [&]() {
signed totalWidth = 0;
for (sv::RegOp &reg : registers)
totalWidth += reg.getElementType().getIntOrFloatBitWidth();
while (totalWidth > 0) {
auto name = b.getStringAttr(moduleNamespace.newName(Twine("_RANDOM")));
randRegs.push_back(
b.create<sv::RegOp>(b.getIntegerType(randomWidth), name, name));
totalWidth -= randomWidth;
}
});
if (!disableRegRandomization) {
b.create<sv::IfDefOp>("RANDOMIZE_REG_INIT", [&]() {
signed totalWidth = 0;
for (sv::RegOp &reg : registers)
totalWidth += reg.getElementType().getIntOrFloatBitWidth();
while (totalWidth > 0) {
auto name =
b.getStringAttr(moduleNamespace.newName(Twine("_RANDOM")));
randRegs.push_back(
b.create<sv::RegOp>(b.getIntegerType(randomWidth), name, name));
totalWidth -= randomWidth;
}
});
}
b.create<sv::InitialOp>([&]() {
b.create<sv::VerbatimOp>("`INIT_RANDOM_PROLOG_");
// Memory randomization logic. The entire memory is randomized.
b.create<sv::IfDefProceduralOp>("RANDOMIZE_MEM_INIT", [&]() {
std::string verbatimForLoop;
llvm::raw_string_ostream s(verbatimForLoop);
s << "for (" << initvar << " = 0; " << initvar << " < " << mem.depth
<< "; " << initvar << " = " << initvar << " + 1) begin\n"
<< " {{0}} = ";
auto repetitionCount = llvm::divideCeil(mem.dataWidth, randomWidth);
if (repetitionCount > 1)
s << "{";
for (size_t i = 0; i != repetitionCount; ++i) {
if (i > 0)
s << ", ";
s << "{`RANDOM}";
}
if (repetitionCount > 1)
s << "}";
s << ";\n";
s << " Memory[" << initvar << "] = "
<< "{{0}}[" << mem.dataWidth - 1 << ":" << 0 << "];\n"
<< "end";
b.create<sv::VerbatimOp>(
verbatimForLoop, ValueRange{},
b.getArrayAttr({hw::InnerRefAttr::get(
op.getNameAttr(), randomMemReg.getInnerSymAttr())}));
});
if (!disableMemRandomization) {
b.create<sv::IfDefProceduralOp>("RANDOMIZE_MEM_INIT", [&]() {
std::string verbatimForLoop;
llvm::raw_string_ostream s(verbatimForLoop);
s << "for (" << initvar << " = 0; " << initvar << " < " << mem.depth
<< "; " << initvar << " = " << initvar << " + 1) begin\n"
<< " {{0}} = ";
auto repetitionCount = llvm::divideCeil(mem.dataWidth, randomWidth);
if (repetitionCount > 1)
s << "{";
for (size_t i = 0; i != repetitionCount; ++i) {
if (i > 0)
s << ", ";
s << "{`RANDOM}";
}
if (repetitionCount > 1)
s << "}";
s << ";\n";
s << " Memory[" << initvar << "] = "
<< "{{0}}[" << mem.dataWidth - 1 << ":" << 0 << "];\n"
<< "end";
b.create<sv::VerbatimOp>(
verbatimForLoop, ValueRange{},
b.getArrayAttr({hw::InnerRefAttr::get(
op.getNameAttr(), randomMemReg.getInnerSymAttr())}));
});
}
// Register randomization logic. Randomize every register to a random
// making efficient use of available randomization registers.
//
// TODO: This shares a lot of common logic with LowerToHW. Combine these
// two in a common randomization utility.
b.create<sv::IfDefProceduralOp>("RANDOMIZE_REG_INIT", [&]() {
unsigned bits = randomWidth;
for (sv::RegOp &reg : randRegs)
b.create<sv::VerbatimOp>(
b.getStringAttr("{{0}} = {`RANDOM};"), ValueRange{},
b.getArrayAttr(hw::InnerRefAttr::get(op.getNameAttr(),
reg.getInnerSymAttr())));
auto randRegIdx = 0;
for (sv::RegOp &reg : registers) {
SmallVector<std::pair<Attribute, std::pair<size_t, size_t>>> values;
auto width = reg.getElementType().getIntOrFloatBitWidth();
auto widthRemaining = width;
while (widthRemaining > 0) {
if (bits == randomWidth) {
randReg = randRegs[randRegIdx++];
bits = 0;
// TODO: This shares a lot of common logic with LowerToHW. Combine
// these two in a common randomization utility.
if (!disableRegRandomization) {
b.create<sv::IfDefProceduralOp>("RANDOMIZE_REG_INIT", [&]() {
unsigned bits = randomWidth;
for (sv::RegOp &reg : randRegs)
b.create<sv::VerbatimOp>(
b.getStringAttr("{{0}} = {`RANDOM};"), ValueRange{},
b.getArrayAttr(hw::InnerRefAttr::get(op.getNameAttr(),
reg.getInnerSymAttr())));
auto randRegIdx = 0;
for (sv::RegOp &reg : registers) {
SmallVector<std::pair<Attribute, std::pair<size_t, size_t>>> values;
auto width = reg.getElementType().getIntOrFloatBitWidth();
auto widthRemaining = width;
while (widthRemaining > 0) {
if (bits == randomWidth) {
randReg = randRegs[randRegIdx++];
bits = 0;
}
auto innerRef = hw::InnerRefAttr::get(op.getNameAttr(),
randReg.getInnerSymAttr());
if (widthRemaining <= randomWidth - bits) {
values.push_back({innerRef, {bits + widthRemaining - 1, bits}});
bits += widthRemaining;
widthRemaining = 0;
continue;
}
values.push_back({innerRef, {randomWidth - 1, bits}});
widthRemaining -= (randomWidth - bits);
bits = randomWidth;
}
auto innerRef = hw::InnerRefAttr::get(op.getNameAttr(),
randReg.getInnerSymAttr());
if (widthRemaining <= randomWidth - bits) {
values.push_back({innerRef, {bits + widthRemaining - 1, bits}});
bits += widthRemaining;
widthRemaining = 0;
continue;
SmallString<32> rhs("{{0}} = ");
unsigned idx = 1;
assert(reg.getInnerSymAttr());
SmallVector<Attribute, 4> symbols({hw::InnerRefAttr::get(
op.getNameAttr(), reg.getInnerSymAttr())});
if (values.size() > 1)
rhs.append("{");
for (auto &v : values) {
if (idx > 1)
rhs.append(", ");
auto [sym, range] = v;
symbols.push_back(sym);
rhs.append(("{{" + Twine(idx++) + "}}").str());
// Do not emit a part select as the whole value is used.
if (range.first == randomWidth - 1 && range.second == 0)
continue;
// Emit a single bit part select, e.g., "[3]"
if (range.first == range.second) {
rhs.append(("[" + Twine(range.first) + "]").str());
continue;
}
// Emit a part select, e.g., "[4:2]"
rhs.append(
("[" + Twine(range.first) + ":" + Twine(range.second) + "]")
.str());
}
values.push_back({innerRef, {randomWidth - 1, bits}});
widthRemaining -= (randomWidth - bits);
bits = randomWidth;
if (values.size() > 1)
rhs.append("}");
rhs.append(";");
b.create<sv::VerbatimOp>(rhs, ValueRange{},
b.getArrayAttr(symbols));
}
SmallString<32> rhs("{{0}} = ");
unsigned idx = 1;
assert(reg.getInnerSymAttr());
SmallVector<Attribute, 4> symbols(
{hw::InnerRefAttr::get(op.getNameAttr(), reg.getInnerSymAttr())});
if (values.size() > 1)
rhs.append("{");
for (auto &v : values) {
if (idx > 1)
rhs.append(", ");
auto [sym, range] = v;
symbols.push_back(sym);
rhs.append(("{{" + Twine(idx++) + "}}").str());
// Do not emit a part select as the whole value is used.
if (range.first == randomWidth - 1 && range.second == 0)
continue;
// Emit a single bit part select, e.g., "[3]"
if (range.first == range.second) {
rhs.append(("[" + Twine(range.first) + "]").str());
continue;
}
// Emit a part select, e.g., "[4:2]"
rhs.append(
("[" + Twine(range.first) + ":" + Twine(range.second) + "]")
.str());
}
if (values.size() > 1)
rhs.append("}");
rhs.append(";");
b.create<sv::VerbatimOp>(rhs, ValueRange{}, b.getArrayAttr(symbols));
}
});
});
}
});
});
auto outputOp = op.getBodyBlock()->getTerminator();
outputOp->setOperands(outputs);
}
void HWMemSimImplPass::runOnOperation() {
@ -588,7 +608,8 @@ void HWMemSimImplPass::runOnOperation() {
newModule.setCommentAttr(
builder.getStringAttr("VCS coverage exclude_file"));
HWMemSimImpl(ignoreReadEnableMem, stripMuxPragmas)
HWMemSimImpl(ignoreReadEnableMem, stripMuxPragmas,
disableMemRandomization, disableRegRandomization)
.generateMemory(newModule, mem);
}
@ -601,12 +622,14 @@ void HWMemSimImplPass::runOnOperation() {
markAllAnalysesPreserved();
}
std::unique_ptr<Pass>
circt::sv::createHWMemSimImplPass(bool replSeqMem, bool ignoreReadEnableMem,
bool stripMuxPragmas) {
std::unique_ptr<Pass> circt::sv::createHWMemSimImplPass(
bool replSeqMem, bool ignoreReadEnableMem, bool stripMuxPragmas,
bool disableMemRandomization, bool disableRegRandomization) {
auto pass = std::make_unique<HWMemSimImplPass>();
pass->replSeqMem = replSeqMem;
pass->ignoreReadEnableMem = ignoreReadEnableMem;
pass->stripMuxPragmas = stripMuxPragmas;
pass->disableMemRandomization = disableMemRandomization;
pass->disableRegRandomization = disableRegRandomization;
return pass;
}

View File

@ -36,6 +36,7 @@ struct SeqToSVPass : public LowerSeqToSVBase<SeqToSVPass> {
};
struct SeqFIRRTLToSVPass : public LowerSeqFIRRTLToSVBase<SeqFIRRTLToSVPass> {
void runOnOperation() override;
using LowerSeqFIRRTLToSVBase<SeqFIRRTLToSVPass>::disableRegRandomization;
};
} // anonymous namespace
@ -89,7 +90,8 @@ namespace {
/// Lower FirRegOp to `sv.reg` and `sv.always`.
class FirRegLower {
public:
FirRegLower(hw::HWModuleOp module) : module(module){};
FirRegLower(hw::HWModuleOp module, bool disableRegRandomization = false)
: module(module), disableRegRandomization(disableRegRandomization){};
void lower();
@ -142,6 +144,8 @@ private:
llvm::SmallDenseMap<std::pair<Value, unsigned>, Value> arrayIndexCache;
hw::HWModuleOp module;
bool disableRegRandomization;
};
} // namespace
@ -201,7 +205,7 @@ void FirRegLower::lower() {
// `INIT_RANDOM_PROLOG_
// ... initBuilder ..
// `endif
if (toInit.empty())
if (toInit.empty() || disableRegRandomization)
return;
auto loc = module.getLoc();
@ -502,13 +506,17 @@ void SeqToSVPass::runOnOperation() {
void SeqFIRRTLToSVPass::runOnOperation() {
hw::HWModuleOp module = getOperation();
FirRegLower(module).lower();
FirRegLower(module, disableRegRandomization).lower();
}
std::unique_ptr<Pass> circt::seq::createSeqLowerToSVPass() {
return std::make_unique<SeqToSVPass>();
}
std::unique_ptr<Pass> circt::seq::createSeqFIRRTLLowerToSVPass() {
return std::make_unique<SeqFIRRTLToSVPass>();
std::unique_ptr<Pass>
circt::seq::createSeqFIRRTLLowerToSVPass(bool disableRegRandomization) {
auto pass = std::make_unique<SeqFIRRTLToSVPass>();
if (disableRegRandomization)
pass->disableRegRandomization = disableRegRandomization;
return pass;
}

View File

@ -1,5 +1,9 @@
// RUN: circt-opt -lower-firrtl-to-hw -verify-diagnostics %s | FileCheck %s
// RUN: circt-opt -pass-pipeline="lower-firrtl-to-hw{disable-mem-randomization}" -verify-diagnostics %s | FileCheck %s --check-prefix DISABLE_RANDOM --implicit-check-not RANDOMIZE_MEM
// RUN: circt-opt -pass-pipeline="lower-firrtl-to-hw{disable-reg-randomization}" -verify-diagnostics %s | FileCheck %s --check-prefix DISABLE_RANDOM --implicit-check-not RANDOMIZE_REG
// RUN: circt-opt -pass-pipeline="lower-firrtl-to-hw{disable-mem-randomization disable-reg-randomization}" -verify-diagnostics %s | FileCheck %s --check-prefix DISABLE_RANDOM --implicit-check-not RANDOMIZE_MEM --implicit-check-not RANDOMIZE_REG
// DISABLE_RANDOM-LABEL: module @Simple
firrtl.circuit "Simple" attributes {annotations = [{class =
"sifive.enterprise.firrtl.ExtractAssumptionsAnnotation", directory = "dir1", filename = "./dir1/filename1" }, {class =
"sifive.enterprise.firrtl.ExtractCoverageAnnotation", directory = "dir2", filename = "./dir2/filename2" }, {class =

View File

@ -1,10 +1,12 @@
// RUN: circt-opt -hw-memory-sim %s | FileCheck %s
// RUN: circt-opt -hw-memory-sim{strip-mux-pragmas} %s | FileCheck %s --check-prefix=STRIP
// STRIP-NOT: sv.attributes
// RUN: circt-opt -hw-memory-sim %s | FileCheck %s --check-prefixes=CHECK,COMMON
// RUN: circt-opt -pass-pipeline="hw-memory-sim{strip-mux-pragmas}" %s | FileCheck %s --check-prefix COMMON --implicit-check-not sv.attributes
// RUN: circt-opt -pass-pipeline="hw-memory-sim{disable-mem-randomization}" %s | FileCheck %s --check-prefix COMMON --implicit-check-not RANDOMIZE_MEM
// RUN: circt-opt -pass-pipeline="hw-memory-sim{disable-reg-randomization}" %s | FileCheck %s --check-prefix COMMON --implicit-check-not RANDOMIZE_REG
// RUN: circt-opt -pass-pipeline="hw-memory-sim{disable-mem-randomization disable-reg-randomization}" %s | FileCheck %s --check-prefix COMMON --implicit-check-not RANDOMIZE_REG --implicit-check-not RANDOMIZE_MEM
hw.generator.schema @FIRRTLMem, "FIRRTL_Memory", ["depth", "numReadPorts", "numWritePorts", "numReadWritePorts", "readLatency", "writeLatency", "width", "readUnderWrite", "writeUnderWrite", "writeClockIDs"]
//CHECK-LABEL: @complex
// COMMON-LABEL: @complex
hw.module @complex(%clock: i1, %reset: i1, %r0en: i1, %mode: i1, %data0: i16) -> (data1: i16, data2: i16) {
%true = hw.constant true
%c0_i4 = hw.constant 0 : i4
@ -32,7 +34,7 @@ hw.module @complexMultiBit(%clock: i1, %reset: i1, %r0en: i1, %mode: i1, %data0:
hw.output %tmp41.ro_data_0, %tmp41.rw_rdata_0 : i16, i16
}
//CHECK-LABEL: @simple
// COMMON-LABEL: @simple
hw.module @simple(%clock: i1, %reset: i1, %r0en: i1, %mode: i1, %data0: i16) -> (data1: i16, data2: i16) {
%true = hw.constant true
%c0_i4 = hw.constant 0 : i4
@ -48,7 +50,7 @@ hw.module @simple(%clock: i1, %reset: i1, %r0en: i1, %mode: i1, %data0: i16) ->
hw.output %tmp41.ro_data_0, %tmp41.rw_rdata_0 : i16, i16
}
//CHECK-LABEL: @WriteOrderedSameClock
// COMMON-LABEL: @WriteOrderedSameClock
hw.module @WriteOrderedSameClock(%clock: i1, %w0_addr: i4, %w0_en: i1, %w0_data: i8, %w0_mask: i1, %w1_addr: i4, %w1_en: i1, %w1_data: i8, %w1_mask: i1) {
hw.instance "memory"
@FIRRTLMemOneAlways(wo_addr_0: %w0_addr: i4, wo_en_0: %w0_en: i1,
@ -58,7 +60,7 @@ hw.module @WriteOrderedSameClock(%clock: i1, %w0_addr: i4, %w0_en: i1, %w0_data:
hw.output
}
//CHECK-LABEL: @WriteOrderedDifferentClock
// COMMON-LABEL: @WriteOrderedDifferentClock
hw.module @WriteOrderedDifferentClock(%clock: i1, %clock2: i1, %w0_addr: i4, %w0_en: i1, %w0_data: i8, %w0_mask: i1, %w1_addr: i4, %w1_en: i1, %w1_data: i8, %w1_mask: i1) {
hw.instance "memory"
@FIRRTLMemTwoAlways(wo_addr_0: %w0_addr: i4, wo_en_0: %w0_en: i1,
@ -70,7 +72,7 @@ hw.module @WriteOrderedDifferentClock(%clock: i1, %clock2: i1, %w0_addr: i4, %w0
hw.module.generated @FIRRTLMem_1_1_1_16_10_0_1_0_0, @FIRRTLMem(%ro_addr_0: i4, %ro_en_0: i1, %ro_clock_0: i1,%rw_addr_0: i4, %rw_en_0: i1, %rw_clock_0: i1, %rw_wmode_0: i1, %rw_wdata_0: i16, %wo_addr_0: i4, %wo_en_0: i1, %wo_clock_0: i1, %wo_data_0: i16) -> (ro_data_0: i16, rw_rdata_0: i16) attributes {depth = 10 : i64, numReadPorts = 1 : ui32, numReadWritePorts = 1 : ui32, numWritePorts = 1 : ui32, readLatency = 0 : ui32, readUnderWrite = 0 : ui32, width = 16 : ui32, writeClockIDs = [], writeLatency = 1 : ui32, writeUnderWrite = 0 : i32}
//CHECK-LABEL: @FIRRTLMem_1_1_1_16_10_0_1_0_0
//COMMON-LABEL: @FIRRTLMem_1_1_1_16_10_0_1_0_0
//CHECK-SAME: attributes {comment = "VCS coverage exclude_file"}
//CHECK: %Memory = sv.reg : !hw.inout<uarray<10xi16>>
//CHECK-NEXT: %[[rslot:.+]] = sv.array_index_inout %Memory[%ro_addr_0]
@ -137,7 +139,7 @@ hw.module.generated @FIRRTLMem_1_1_1_16_10_0_1_0_0, @FIRRTLMem(%ro_addr_0: i4, %
hw.module.generated @FIRRTLMem_1_1_1_16_10_2_4_0_0, @FIRRTLMem(%ro_addr_0: i4, %ro_en_0: i1, %ro_clock_0: i1,%rw_addr_0: i4, %rw_en_0: i1, %rw_clock_0: i1, %rw_wmode_0: i1, %rw_wdata_0: i16, %wo_addr_0: i4, %wo_en_0: i1, %wo_clock_0: i1, %wo_data_0: i16) -> (ro_data_0: i16, rw_rdata_0: i16) attributes {depth = 10 : i64, numReadPorts = 1 : ui32, numReadWritePorts = 1 : ui32, numWritePorts = 1 : ui32, readLatency = 2 : ui32, readUnderWrite = 0 : ui32, width = 16 : ui32, writeClockIDs = [], writeLatency = 4 : ui32, writeUnderWrite = 0 : i32}
//CHECK-LABEL: @FIRRTLMem_1_1_1_16_10_2_4_0_0
//COMMON-LABEL: @FIRRTLMem_1_1_1_16_10_2_4_0_0
//COM: This produces a lot of output, we check one field's pipeline
//CHECK: %Memory = sv.reg : !hw.inout<uarray<10xi16>>
//CHECK-NEXT: [[EN_0:%.+]] = sv.reg {{.+}} : !hw.inout<i1>
@ -157,18 +159,18 @@ hw.module.generated @FIRRTLMem_1_1_1_16_10_2_4_0_0, @FIRRTLMem(%ro_addr_0: i4, %
//CHECK-NEXT: {{%.+}} = sv.array_index_inout %Memory[[[ADDR_1R]]] : !hw.inout<uarray<10xi16>>, i4
hw.module.generated @FIRRTLMem_1_1_1_16_1_0_1_0_0, @FIRRTLMem(%ro_addr_0: i4, %ro_en_0: i1, %ro_clock_0: i1,%rw_addr_0: i4, %rw_en_0: i1, %rw_clock_0: i1, %rw_wmode_0: i1, %rw_wdata_0: i16, %wo_addr_0: i4, %wo_en_0: i1, %wo_clock_0: i1, %wo_data_0: i16) -> (ro_data_0: i16, rw_rdata_0: i16) attributes {depth = 1 : i64, numReadPorts = 1 : ui32, numReadWritePorts = 1 : ui32, numWritePorts = 1 : ui32, readLatency = 0 : ui32, readUnderWrite = 0 : ui32, width = 16 : ui32, writeClockIDs = [], writeLatency = 1 : ui32, writeUnderWrite = 0 : i32}
// CHECK-LABEL: @FIRRTLMem_1_1_1_16_1_0_1_0_0
// COMMON-LABEL: @FIRRTLMem_1_1_1_16_1_0_1_0_0
// CHECK-NOT: sv.attributes
hw.module.generated @FIRRTLMemOneAlways, @FIRRTLMem( %wo_addr_0: i4, %wo_en_0: i1, %wo_clock_0: i1,%wo_data_0: i8, %wo_addr_1: i4, %wo_en_1: i1, %wo_clock_1: i1, %wo_data_1: i8) attributes {depth = 16 : i64, numReadPorts = 0 : ui32, numReadWritePorts = 0 : ui32, numWritePorts = 2 : ui32, readLatency = 1 : ui32, readUnderWrite = 0 : ui32, width = 8 : ui32, writeClockIDs = [0 : i32, 0 : i32], writeLatency = 1 : ui32, writeUnderWrite = 1 : i32}
//CHECK-LABEL: @FIRRTLMemOneAlways
//COMMON-LABEL: @FIRRTLMemOneAlways
//CHECK-COUNT-1: sv.always
//CHECK-NOT: sv.always
hw.module.generated @FIRRTLMemTwoAlways, @FIRRTLMem( %wo_addr_0: i4, %wo_en_0: i1, %wo_clock_0: i1,%wo_data_0: i8, %wo_addr_1: i4, %wo_en_1: i1, %wo_clock_1: i1, %wo_data_1: i8) attributes {depth = 16 : i64, numReadPorts = 0 : ui32, numReadWritePorts = 0 : ui32, numWritePorts = 2 : ui32, readLatency = 1 : ui32, readUnderWrite = 0 : ui32, width = 8 : ui32, writeClockIDs = [0 : i32, 1 : i32], writeLatency = 1 : ui32, writeUnderWrite = 1 : i32}
//CHECK-LABEL: @FIRRTLMemTwoAlways
//COMMON-LABEL: @FIRRTLMemTwoAlways
//CHECK-COUNT-2: sv.always
//CHECK-NOT: sv.always
@ -178,7 +180,7 @@ hw.module.generated @FIRRTLMemTwoAlways, @FIRRTLMem( %wo_addr_0: i4, %wo_en_0: i
%memory.R0_data = hw.instance "memory" @FIRRTLMem_1_1_0_32_16_1_1_0_1_a(R0_addr: %rAddr: i4, R0_en: %rEn: i1, R0_clk: %clock: i1, W0_addr: %wAddr: i4, W0_en: %wEn: i1, W0_clk: %clock: i1, W0_data: %wData: i32, W0_mask: %wMask: i4) -> (R0_data: i32)
hw.output %memory.R0_data : i32
}
// CHECK-LABEL: hw.module @FIRRTLMem_1_1_0_32_16_1_1_0_1_a
// COMMON-LABEL: hw.module @FIRRTLMem_1_1_0_32_16_1_1_0_1_a
// CHECK-SAME: (%R0_addr: i4, %R0_en: i1, %R0_clk: i1, %W0_addr: i4, %W0_en: i1, %W0_clk: i1, %W0_data: i32, %W0_mask: i4) -> (R0_data: i32)
// CHECK-NEXT: %[[Memory:.+]] = sv.reg : !hw.inout<uarray<16xi32>>
// CHECK: %[[v4:.+]] = sv.array_index_inout %[[Memory]][%[[v3:.+]]] :
@ -210,7 +212,7 @@ hw.module.generated @FIRRTLMemTwoAlways, @FIRRTLMem( %wo_addr_0: i4, %wo_en_0: i
R0_clk: %clock: i1, W0_addr: %wAddr: i4, W0_en: %wEn: i1, W0_clk: %clock: i1, W0_data: %wData: i32, W0_mask: %wMask: i2) -> (R0_data: i32)
hw.output %memory.R0_data : i32
}
// CHECK-LABEL:hw.module @FIRRTLMem_1_1_0_32_16_1_1_0_1_b
// COMMON-LABEL:hw.module @FIRRTLMem_1_1_0_32_16_1_1_0_1_b
// CHECK-SAME: (%R0_addr: i4, %R0_en: i1, %R0_clk: i1, %W0_addr: i4, %W0_en: i1, %W0_clk: i1, %W0_data: i32, %W0_mask: i2) -> (R0_data: i32)
// CHECK: %[[Memory0:.+]] = sv.reg : !hw.inout<uarray<16xi32>>
// CHECK: %[[v8:.+]] = sv.array_index_inout %[[Memory0]][%[[v7:.+]]] : !hw.inout<uarray<16xi32>>, i4
@ -247,7 +249,7 @@ i4, %rw_en_0: i1, %rw_clock_0: i1, %rw_wmode_0: i1, %rw_wdata_0: i16, %rw_wmas
%wo_clock_0: i1, %wo_data_0: i16, %wo_mask_0: i2) -> (ro_data_0: i16, rw_rdata_0: i16) attributes {depth = 10 : i64,
numReadPorts = 1 : ui32, numReadWritePorts = 1 : ui32,maskGran = 8 :ui32, numWritePorts = 1 : ui32, readLatency = 2 : ui32, readUnderWrite = 0 : ui32, width = 16 : ui32, writeClockIDs = [], writeLatency = 4 : ui32, writeUnderWrite = 0 : i32}
// CHECK-LABEL: hw.module @FIRRTLMem_1_1_1_16_10_2_4_0_0_multi
// COMMON-LABEL: hw.module @FIRRTLMem_1_1_1_16_10_2_4_0_0_multi
// CHECK-SAME: %ro_addr_0: i4, %ro_en_0: i1, %ro_clock_0: i1, %rw_addr_0: i4,
// CHECK-SAME: %rw_en_0: i1, %rw_clock_0: i1, %rw_wmode_0: i1, %rw_wdata_0: i16,
// CHECK-SAME: %rw_wmask_0: i2, %wo_addr_0: i4, %wo_en_0: i1, %wo_clock_0: i1,
@ -289,16 +291,16 @@ numReadPorts = 1 : ui32, numReadWritePorts = 1 : ui32,maskGran = 8 :ui32, numWri
// Ensure state is cleaned up between the expansion of modules.
// See https://github.com/llvm/circt/pull/2769
// CHECK-LABEL: hw.module @PR2769
// COMMON-LABEL: hw.module @PR2769
// CHECK-NOT: _GEN
hw.module.generated @PR2769, @FIRRTLMem(%ro_addr_0: i4, %ro_en_0: i1, %ro_clock_0: i1,%rw_addr_0: i4, %rw_en_0: i1, %rw_clock_0: i1, %rw_wmode_0: i1, %rw_wdata_0: i16, %wo_addr_0: i4, %wo_en_0: i1, %wo_clock_0: i1, %wo_data_0: i16) -> (ro_data_0: i16, rw_rdata_0: i16) attributes {depth = 10 : i64, numReadPorts = 1 : ui32, numReadWritePorts = 1 : ui32, numWritePorts = 1 : ui32, readLatency = 0 : ui32, readUnderWrite = 0 : ui32, width = 16 : ui32, writeClockIDs = [], writeLatency = 1 : ui32, writeUnderWrite = 0 : i32}
// CHECK-LABEL: hw.module @RandomizeWeirdWidths
// COMMON-LABEL: hw.module @RandomizeWeirdWidths
// CHECK: sv.ifdef.procedural "RANDOMIZE_MEM_INIT"
// CHECK-NEXT{LITERAL}: sv.verbatim "for (initvar = 0; initvar < 10; initvar = initvar + 1) begin\0A {{0}} = {{`RANDOM}, {`RANDOM}, {`RANDOM}, {`RANDOM}, {`RANDOM}};\0A Memory[initvar] = {{0}}[144:0];\0Aend"
hw.module.generated @RandomizeWeirdWidths, @FIRRTLMem(%ro_addr_0: i4, %ro_en_0: i1, %ro_clock_0: i1,%rw_addr_0: i4, %rw_en_0: i1, %rw_clock_0: i1, %rw_wmode_0: i1, %rw_wdata_0: i145, %wo_addr_0: i4, %wo_en_0: i1, %wo_clock_0: i1, %wo_data_0: i145) -> (ro_data_0: i145, rw_rdata_0: i145) attributes {depth = 10 : i64, numReadPorts = 1 : ui32, numReadWritePorts = 1 : ui32, numWritePorts = 1 : ui32, readLatency = 2 : ui32, readUnderWrite = 0 : ui32, width = 145 : ui32, writeClockIDs = [], writeLatency = 4 : ui32, writeUnderWrite = 0 : i32}
// CHECK-LABEL: hw.module @ReadWriteWithHighReadLatency
// COMMON-LABEL: hw.module @ReadWriteWithHighReadLatency
hw.module.generated @ReadWriteWithHighReadLatency, @FIRRTLMem(%rw_addr: i4, %rw_en: i1, %rw_clock: i1, %rw_wmode: i1, %rw_wdata: i16) -> (rw_rdata: i16) attributes {depth = 16 : i64, numReadPorts = 0 : ui32, numReadWritePorts = 1 : ui32, numWritePorts = 0 : ui32, readLatency = 4 : ui32, readUnderWrite = 0 : ui32, width = 16 : ui32, writeClockIDs = [], writeLatency = 3 : ui32, writeUnderWrite = 0 : i32}
// CHECK: [[MEM:%.+]] = sv.reg : !hw.inout<uarray
@ -347,7 +349,7 @@ hw.module.generated @ReadWriteWithHighReadLatency, @FIRRTLMem(%rw_addr: i4, %rw_
// CHECK: [[WCOND:%.+]] comb.and [[EN_1R]], [[TMP]]
// CHECK: [[WPTR:%.+]] = sv.array_index_inout [[MEM]][[[ADDR_1R]]]
// CHECK-LABEL: hw.module @ReadWriteWithHighWriteLatency
// COMMON-LABEL: hw.module @ReadWriteWithHighWriteLatency
hw.module.generated @ReadWriteWithHighWriteLatency, @FIRRTLMem(%rw_addr: i4, %rw_en: i1, %rw_clock: i1, %rw_wmode: i1, %rw_wdata: i16) -> (rw_rdata: i16) attributes {depth = 16 : i64, numReadPorts = 0 : ui32, numReadWritePorts = 1 : ui32, numWritePorts = 0 : ui32, readLatency = 2 : ui32, readUnderWrite = 0 : ui32, width = 16 : ui32, writeClockIDs = [], writeLatency = 5 : ui32, writeUnderWrite = 0 : i32}
// CHECK: [[MEM:%.+]] = sv.reg : !hw.inout<uarray

View File

@ -1,6 +1,7 @@
// RUN: circt-opt %s -verify-diagnostics --lower-seq-firrtl-to-sv | FileCheck %s
// RUN: circt-opt %s -verify-diagnostics --lower-seq-firrtl-to-sv | FileCheck %s --check-prefixes=CHECK,COMMON
// RUN: circt-opt %s -verify-diagnostics --pass-pipeline="hw.module(lower-seq-firrtl-to-sv{disable-reg-randomization})" | FileCheck %s --check-prefix COMMON --implicit-check-not RANDOMIZE_REG
// CHECK-LABEL: hw.module @lowering
// COMMON-LABEL: hw.module @lowering
hw.module @lowering(%clk: i1, %rst: i1, %in: i32) -> (a: i32, b: i32, c: i32, d: i32, e: i32, f: i32) {
%cst0 = hw.constant 0 : i32
@ -128,7 +129,7 @@ hw.module @lowering(%clk: i1, %rst: i1, %in: i32) -> (a: i32, b: i32, c: i32, d:
hw.output %rA, %rB, %rC, %rD, %rE, %rF : i32, i32, i32, i32, i32, i32
}
// CHECK-LABEL: hw.module private @UninitReg1(%clock: i1, %reset: i1, %cond: i1, %value: i2) {
// COMMON-LABEL: hw.module private @UninitReg1(%clock: i1, %reset: i1, %cond: i1, %value: i2) {
hw.module private @UninitReg1(%clock: i1, %reset: i1, %cond: i1, %value: i2) {
// CHECK: %c0_i2 = hw.constant 0 : i2
%c0_i2 = hw.constant 0 : i2
@ -179,7 +180,7 @@ hw.module private @UninitReg1(%clock: i1, %reset: i1, %cond: i1, %value: i2) {
// CHECK: hw.output
hw.output
}
// CHECK-LABEL: hw.module private @UninitReg1_nonbin(%clock: i1, %reset: i1, %cond: i1, %value: i2) {
// COMMON-LABEL: hw.module private @UninitReg1_nonbin(%clock: i1, %reset: i1, %cond: i1, %value: i2) {
hw.module private @UninitReg1_nonbin(%clock: i1, %reset: i1, %cond: i1, %value: i2) {
// CHECK: %c0_i2 = hw.constant 0 : i2
%c0_i2 = hw.constant 0 : i2
@ -212,7 +213,7 @@ hw.module private @UninitReg1_nonbin(%clock: i1, %reset: i1, %cond: i1, %value:
// io_q <= reg
// reg <= mux(io_en, io_d, reg)
// CHECK-LABEL: hw.module private @InitReg1(
// COMMON-LABEL: hw.module private @InitReg1(
hw.module private @InitReg1(%clock: i1, %reset: i1, %io_d: i32, %io_en: i1) -> (io_q: i32) {
%false = hw.constant false
%c1_i32 = hw.constant 1 : i32
@ -298,7 +299,7 @@ hw.module private @InitReg1(%clock: i1, %reset: i1, %io_d: i32, %io_en: i1) -> (
hw.output %reg : i32
}
// CHECK-LABEL: hw.module private @UninitReg42(%clock: i1, %reset: i1, %cond: i1, %value: i42) {
// COMMON-LABEL: hw.module private @UninitReg42(%clock: i1, %reset: i1, %cond: i1, %value: i42) {
hw.module private @UninitReg42(%clock: i1, %reset: i1, %cond: i1, %value: i42) {
%c0_i42 = hw.constant 0 : i42
%count = seq.firreg %1 clock %clock sym @count : i42
@ -339,7 +340,7 @@ hw.module private @UninitReg42(%clock: i1, %reset: i1, %cond: i1, %value: i42) {
hw.output
}
// CHECK-LABEL: hw.module private @regInitRandomReuse
// COMMON-LABEL: hw.module private @regInitRandomReuse
hw.module private @regInitRandomReuse(%clock: i1, %a: i1) -> (o1: i2, o2: i4, o3: i32, o4: i100) {
%c0_i99 = hw.constant 0 : i99
%c0_i31 = hw.constant 0 : i31
@ -386,7 +387,7 @@ hw.module private @regInitRandomReuse(%clock: i1, %a: i1) -> (o1: i2, o2: i4, o3
hw.output %r1, %r2, %r3, %r4 : i2, i4, i32, i100
}
// CHECK-LABEL: hw.module private @init1DVector
// COMMON-LABEL: hw.module private @init1DVector
hw.module private @init1DVector(%clock: i1, %a: !hw.array<2xi1>) -> (b: !hw.array<2xi1>) {
%r = seq.firreg %a clock %clock sym @__r__ : !hw.array<2xi1>
@ -421,7 +422,7 @@ hw.module private @init1DVector(%clock: i1, %a: !hw.array<2xi1>) -> (b: !hw.arra
hw.output %r : !hw.array<2xi1>
}
// CHECK-LABEL: hw.module private @init2DVector
// COMMON-LABEL: hw.module private @init2DVector
hw.module private @init2DVector(%clock: i1, %a: !hw.array<1xarray<1xi1>>) -> (b: !hw.array<1xarray<1xi1>>) {
%r = seq.firreg %a clock %clock sym @__r__ : !hw.array<1xarray<1xi1>>
@ -453,7 +454,7 @@ hw.module private @init2DVector(%clock: i1, %a: !hw.array<1xarray<1xi1>>) -> (b:
// CHECK: hw.output %0 : !hw.array<1xarray<1xi1>>
}
// CHECK-LABEL: hw.module private @initStruct
// COMMON-LABEL: hw.module private @initStruct
hw.module private @initStruct(%clock: i1) {
%r = seq.firreg %r clock %clock sym @__r__ : !hw.struct<a: i1>
@ -482,7 +483,7 @@ hw.module private @initStruct(%clock: i1) {
hw.output
}
// CHECK-LABEL: issue1594
// COMMON-LABEL: issue1594
// Make sure LowerToHW's merging of always blocks kicks in for this example.
hw.module @issue1594(%clock: i1, %reset: i1, %a: i1) -> (b: i1) {
%true = hw.constant true
@ -499,7 +500,7 @@ hw.module @issue1594(%clock: i1, %reset: i1, %a: i1) -> (b: i1) {
}
// Check that deeply nested if statement creation doesn't cause any issue.
// CHECK-LABEL: @DeeplyNestedIfs
// COMMON-LABEL: @DeeplyNestedIfs
// CHECK-COUNT-17: sv.if
hw.module @DeeplyNestedIfs(%a_0: i1, %a_1: i1, %a_2: i1, %c_0_0: i1, %c_0_1: i1, %c_1_0: i1, %c_1_1: i1, %c_2_0: i1, %c_2_1: i1, %clock: i1) -> (out_0: i1, out_1: i1) {
%r_0 = seq.firreg %25 clock %clock {firrtl.random_init_start = 0 : ui64} : i1
@ -559,7 +560,7 @@ hw.module @DeeplyNestedIfs(%a_0: i1, %a_1: i1, %a_2: i1, %c_0_0: i1, %c_0_1: i1,
hw.output %r_0, %r_1 : i1, i1
}
// CHECK-LABEL: @ArrayElements
// COMMON-LABEL: @ArrayElements
hw.module @ArrayElements(%a: !hw.array<2xi1>, %clock: i1, %cond: i1) -> (b: !hw.array<2xi1>) {
%false = hw.constant false
%true = hw.constant true

View File

@ -1,6 +1,9 @@
; RUN: firtool %s --format=fir --ir-sv | FileCheck %s
; RUN: firtool %s --format=fir --ir-sv -strip-mux-pragmas | FileCheck %s --check-prefix=STRIP
; STRIP-NOT: sv.attributes
; RUN: firtool %s --format=fir --ir-sv | FileCheck %s --check-prefixes=CHECK,COMMON
; RUN: firtool %s --format=fir --ir-sv -strip-mux-pragmas | FileCheck %s --check-prefix COMMON --implicit-check-not sv.attributes
; RUN: firtool %s --format=fir --ir-sv -disable-mem-randomization | FileCheck %s --check-prefix COMMON --implicit-check-not RANDOMIZE_MEM
; RUN: firtool %s --format=fir --ir-sv -disable-reg-randomization | FileCheck %s --check-prefix COMMON --implicit-check-not RANDOMIZE_REG
; RUN: firtool %s --format=fir --ir-sv -disable-mem-randomization --disable-reg-randomization | FileCheck %s --check-prefix COMMON --implicit-check-not RANDOMIZE_MEM --implicit-check-not RANDOMIZE_REG
; RUN: firtool %s --format=fir --ir-sv -disable-all-randomization | FileCheck %s --check-prefix COMMON --implicit-check-not RANDOMIZE_MEM --implicit-check-not RANDOMIZE_REG
circuit Qux: %[[{
"class": "sifive.enterprise.firrtl.MarkDUTAnnotation",
@ -65,7 +68,7 @@ circuit Qux: %[[{
; This test is quite fragile, both as written, and in that it depends on
; multiple passes. It should be replaced with a narrower test.
;CHECK-LABEL: hw.module @Qux
;COMMON-LABEL: hw.module @Qux
;CHECK: %[[memory_0:.+]] = sv.reg
;CHECK: %[[memory_1:.+]] = sv.reg
;CHECK: %[[memory_2:.+]] = sv.reg

View File

@ -322,6 +322,22 @@ static cl::opt<bool> etcDisableModuleInlining(
cl::desc("Disable inlining modules that only feed test code"),
cl::init(false), cl::cat(mainCategory));
enum class RandomKind { None, Mem, Reg, All };
static cl::opt<RandomKind> disableRandom(
cl::desc("Disable random initialization code (may break semantics!)"),
cl::values(clEnumValN(RandomKind::Mem, "disable-mem-randomization",
"Disable emission of memory randomization code"),
clEnumValN(RandomKind::Reg, "disable-reg-randomization",
"Disable emission of register randomization code"),
clEnumValN(RandomKind::All, "disable-all-randomization",
"Disable emission of all randomization code")),
cl::init(RandomKind::None), cl::cat(mainCategory));
static bool isRandomEnabled(RandomKind kind) {
return disableRandom != RandomKind::All && disableRandom != kind;
}
enum OutputFormatKind {
OutputParseOnly,
OutputIRFir,
@ -645,8 +661,9 @@ processBuffer(MLIRContext &context, TimingScope &ts, llvm::SourceMgr &sourceMgr,
// implementation assumes it can run at a time where every register is
// currently in the final module it will be emitted in, all registers have
// been created, and no registers have yet been removed.
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
firrtl::createRandomizeRegisterInitPass());
if (isRandomEnabled(RandomKind::Reg))
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
firrtl::createRandomizeRegisterInitPass());
if (!disableCheckCombCycles) {
// TODO: Currently CheckCombCyles pass doesn't support aggregates so skip
@ -749,9 +766,10 @@ processBuffer(MLIRContext &context, TimingScope &ts, llvm::SourceMgr &sourceMgr,
// RefType ports and ops.
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerXMRPass());
pm.addPass(createLowerFIRRTLToHWPass(enableAnnotationWarning.getValue(),
emitChiselAssertsAsSVA.getValue(),
stripMuxPragmas.getValue()));
pm.addPass(createLowerFIRRTLToHWPass(
enableAnnotationWarning.getValue(), emitChiselAssertsAsSVA.getValue(),
stripMuxPragmas.getValue(), !isRandomEnabled(RandomKind::Mem),
!isRandomEnabled(RandomKind::Reg)));
if (outputFormat == OutputIRHW) {
if (!disableOptimization) {
@ -768,9 +786,12 @@ processBuffer(MLIRContext &context, TimingScope &ts, llvm::SourceMgr &sourceMgr,
modulePM.addPass(createCSEPass());
}
pm.nest<hw::HWModuleOp>().addPass(seq::createSeqFIRRTLLowerToSVPass());
pm.nest<hw::HWModuleOp>().addPass(
seq::createSeqFIRRTLLowerToSVPass(!isRandomEnabled(RandomKind::Reg)));
pm.addPass(sv::createHWMemSimImplPass(replSeqMem, ignoreReadEnableMem,
stripMuxPragmas));
stripMuxPragmas,
!isRandomEnabled(RandomKind::Mem),
!isRandomEnabled(RandomKind::Reg)));
if (extractTestCode)
pm.addPass(sv::createSVExtractTestCodePass(etcDisableInstanceExtraction,