mirror of https://github.com/llvm/circt.git
Add options for controlling emission of randomization code. (#4240)
Add `--disable-{mem,reg,all}-randomization` to firtool. Fixes #4202.
This commit is contained in:
parent
b12d21b682
commit
937457399f
|
@ -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
|
||||
|
||||
|
|
|
@ -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">,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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"> {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 ® : 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 ® : 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 ® : 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 ® : 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 ® : 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 ® : 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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue