25#include "mlir/IR/Builders.h"
26#include "mlir/IR/ImplicitLocOpBuilder.h"
27#include "mlir/IR/Threading.h"
28#include "mlir/Pass/Pass.h"
29#include "mlir/Transforms/DialectConversion.h"
31#define DEBUG_TYPE "lower-seq-to-sv"
39#define GEN_PASS_DEF_LOWERSEQTOSV
40#include "circt/Conversion/Passes.h.inc"
42struct SeqToSVPass :
public impl::LowerSeqToSVBase<SeqToSVPass> {
46 using LowerSeqToSVBase<
SeqToSVPass>::lowerToAlwaysFF;
47 using LowerSeqToSVBase<
SeqToSVPass>::disableRegRandomization;
48 using LowerSeqToSVBase<
SeqToSVPass>::emitSeparateAlwaysBlocks;
49 using LowerSeqToSVBase<
SeqToSVPass>::emitPresetAsInlineInit;
50 using LowerSeqToSVBase<
SeqToSVPass>::LowerSeqToSVBase;
51 using LowerSeqToSVBase<
SeqToSVPass>::numSubaccessRestored;
56struct ModuleLoweringState {
58 : immutableValueLowering(module), module(module) {}
60 struct ImmutableValueLowering {
64 LogicalResult lower();
65 LogicalResult lower(seq::InitialOp initialOp);
68 lookupImmutableValue(mlir::TypedValue<seq::ImmutableType> immut)
const {
69 return mapping.lookup(immut);
72 sv::InitialOp getSVInitial()
const {
return svInitialOp; }
75 sv::InitialOp svInitialOp = {};
81 } immutableValueLowering;
84 bool needsRegFragment =
false;
90LogicalResult ModuleLoweringState::ImmutableValueLowering::lower() {
95 auto initialOp = *result;
99 return lower(initialOp);
103ModuleLoweringState::ImmutableValueLowering::lower(seq::InitialOp initialOp) {
104 OpBuilder builder = OpBuilder::atBlockBegin(module.getBodyBlock());
106 svInitialOp = sv::InitialOp::create(builder, initialOp->getLoc());
108 assert(initialOp.getNumOperands() == 0 &&
109 "initial op should have no operands");
111 auto loc = initialOp.getLoc();
112 llvm::SmallVector<Value> results;
114 auto yieldOp = cast<seq::YieldOp>(initialOp.getBodyBlock()->getTerminator());
116 for (
auto [result, operand] :
117 llvm::zip(initialOp.getResults(), yieldOp->getOperands())) {
119 mlir::UnrealizedConversionCastOp::create(
120 builder, loc, ArrayRef<Type>{result.getType()}, ArrayRef<Value>{})
122 result.replaceAllUsesWith(placeholder);
124 {cast<mlir::TypedValue<seq ::ImmutableType>>(placeholder), operand});
127 svInitialOp.getBodyBlock()->getOperations().splice(
128 svInitialOp.end(), initialOp.getBodyBlock()->getOperations());
130 assert(initialOp->use_empty());
138template <
typename OpTy>
142 TypeConverter &typeConverter, MLIRContext *
context,
bool lowerToAlwaysFF,
145 lowerToAlwaysFF(lowerToAlwaysFF),
146 moduleLoweringStates(moduleLoweringStates) {}
151 matchAndRewrite(OpTy
reg, OpAdaptor adaptor,
152 ConversionPatternRewriter &rewriter)
const final {
153 Location loc =
reg.getLoc();
156 ConversionPattern::getTypeConverter()->convertType(
reg.getType());
157 auto svReg = sv::RegOp::create(rewriter, loc, regTy,
reg.getNameAttr(),
158 reg.getInnerSymAttr());
160 svReg->setDialectAttrs(
reg->getDialectAttrs());
166 auto assignValue = [&] {
167 createAssign(rewriter,
reg.getLoc(), svReg,
reg);
169 auto assignReset = [&] {
170 sv::PAssignOp::create(rewriter, loc, svReg, adaptor.getResetValue());
176 bool mayLowerToAlwaysFF = lowerToAlwaysFF && !
reg.getInitialValue();
178 if (adaptor.getReset() && adaptor.getResetValue()) {
179 if (mayLowerToAlwaysFF) {
180 sv::AlwaysFFOp::create(rewriter, loc, sv::EventControl::AtPosEdge,
181 adaptor.getClk(), sv::ResetType::SyncReset,
182 sv::EventControl::AtPosEdge, adaptor.getReset(),
183 assignValue, assignReset);
185 sv::AlwaysOp::create(
186 rewriter, loc, sv::EventControl::AtPosEdge, adaptor.getClk(), [&] {
187 sv::IfOp::create(rewriter, loc, adaptor.getReset(), assignReset,
192 if (mayLowerToAlwaysFF) {
193 sv::AlwaysFFOp::create(rewriter, loc, sv::EventControl::AtPosEdge,
194 adaptor.getClk(), assignValue);
196 sv::AlwaysOp::create(rewriter, loc, sv::EventControl::AtPosEdge,
197 adaptor.getClk(), assignValue);
202 if (
auto init =
reg.getInitialValue()) {
203 auto module = reg->template getParentOfType<hw::HWModuleOp>();
204 const auto &initial =
205 moduleLoweringStates.find(module.getModuleNameAttr())
206 ->second.immutableValueLowering;
208 Value initialValue = initial.lookupImmutableValue(init);
210 if (
auto op = initialValue.getDefiningOp();
211 op && op->hasTrait<mlir::OpTrait::ConstantLike>()) {
212 auto clonedConstant = rewriter.clone(*op);
213 rewriter.moveOpBefore(clonedConstant, svReg);
214 svReg.getInitMutable().assign(clonedConstant->getResult(0));
216 OpBuilder::InsertionGuard guard(rewriter);
217 auto in = initial.getSVInitial();
218 rewriter.setInsertionPointToEnd(in.getBodyBlock());
219 sv::BPAssignOp::create(rewriter,
reg->getLoc(), svReg, initialValue);
223 rewriter.replaceOp(
reg, regVal);
228 void createAssign(ConversionPatternRewriter &rewriter, Location loc,
232 bool lowerToAlwaysFF;
238void CompRegLower<CompRegOp>::createAssign(ConversionPatternRewriter &rewriter,
240 OpAdaptor
reg)
const {
241 sv::PAssignOp::create(rewriter, loc, svReg,
reg.getInput());
245void CompRegLower<CompRegClockEnabledOp>::createAssign(
246 ConversionPatternRewriter &rewriter, Location loc,
sv::RegOp svReg,
247 OpAdaptor
reg)
const {
248 sv::IfOp::create(rewriter, loc,
reg.getClockEnable(), [&]() {
249 sv::PAssignOp::create(rewriter, loc, svReg, reg.getInput());
256 FromImmutableLowering(
257 TypeConverter &typeConverter, MLIRContext *
context,
260 moduleLoweringStates(moduleLoweringStates) {}
265 matchAndRewrite(FromImmutableOp fromImmutableOp, OpAdaptor adaptor,
266 ConversionPatternRewriter &rewriter)
const final {
267 Location loc = fromImmutableOp.getLoc();
269 auto regTy = ConversionPattern::getTypeConverter()->convertType(
270 fromImmutableOp.getType());
271 auto svReg = sv::RegOp::create(rewriter, loc, regTy);
276 auto module = fromImmutableOp->template getParentOfType<hw::HWModuleOp>();
277 const auto &initial = moduleLoweringStates.find(module.getModuleNameAttr())
278 ->second.immutableValueLowering;
281 initial.lookupImmutableValue(fromImmutableOp.getInput());
283 OpBuilder::InsertionGuard guard(rewriter);
284 auto in = initial.getSVInitial();
285 rewriter.setInsertionPointToEnd(in.getBodyBlock());
286 sv::BPAssignOp::create(rewriter, fromImmutableOp->getLoc(), svReg,
289 rewriter.replaceOp(fromImmutableOp, regVal);
303 matchAndRewrite(ClockGateOp clockGate, OpAdaptor adaptor,
304 ConversionPatternRewriter &rewriter)
const final {
305 auto loc = clockGate.getLoc();
306 Value
clk = adaptor.getInput();
309 Value enable = adaptor.getEnable();
310 if (
auto te = adaptor.getTestEnable())
311 enable = comb::OrOp::create(rewriter, loc, enable, te);
315 sv::RegOp::create(rewriter, loc, rewriter.getI1Type(),
316 rewriter.getStringAttr(
"cg_en_latch"));
319 sv::AlwaysOp::create(
320 rewriter, loc, llvm::SmallVector<sv::EventControl>{},
321 llvm::SmallVector<Value>{}, [&]() {
323 rewriter, loc, comb::createOrFoldNot(rewriter, loc, clk), [&]() {
324 sv::PAssignOp::create(rewriter, loc, enableLatch, enable);
342 matchAndRewrite(ClockInverterOp op, OpAdaptor adaptor,
343 ConversionPatternRewriter &rewriter)
const final {
344 auto loc = op.getLoc();
345 Value
clk = adaptor.getInput();
347 StringAttr name = op->getAttrOfType<StringAttr>(
"sv.namehint");
349 auto newOp = rewriter.replaceOpWithNewOp<
comb::XorOp>(op,
clk, one);
351 rewriter.modifyOpInPlace(newOp,
352 [&] { newOp->setAttr(
"sv.namehint", name); });
365 matchAndRewrite(ClockMuxOp clockMux, OpAdaptor adaptor,
366 ConversionPatternRewriter &rewriter)
const final {
367 rewriter.replaceOpWithNewOp<
comb::MuxOp>(clockMux, adaptor.getCond(),
368 adaptor.getTrueClock(),
369 adaptor.getFalseClock(),
true);
375struct SeqToSVTypeConverter :
public TypeConverter {
376 SeqToSVTypeConverter() {
377 addConversion([&](Type type) {
return type; });
378 addConversion([&](seq::ImmutableType type) {
return type.getInnerType(); });
379 addConversion([&](seq::ClockType type) {
380 return IntegerType::get(type.getContext(), 1);
382 addConversion([&](hw::StructType structTy) {
383 bool changed =
false;
385 SmallVector<hw::StructType::FieldInfo> newFields;
386 for (
auto field : structTy.getElements()) {
387 auto &newField = newFields.emplace_back();
388 newField.name = field.name;
390 if (field.type != newField.type)
397 return hw::StructType::get(structTy.getContext(), newFields);
399 addConversion([&](hw::ArrayType arrayTy) {
400 auto elementTy = arrayTy.getElementType();
402 if (elementTy != newElementTy)
403 return hw::ArrayType::get(newElementTy, arrayTy.getNumElements());
407 addTargetMaterialization([&](mlir::OpBuilder &builder,
408 mlir::Type resultType, mlir::ValueRange inputs,
409 mlir::Location loc) -> mlir::Value {
410 if (inputs.size() != 1)
412 return mlir::UnrealizedConversionCastOp::create(builder, loc, resultType,
417 addSourceMaterialization([&](mlir::OpBuilder &builder,
418 mlir::Type resultType, mlir::ValueRange inputs,
419 mlir::Location loc) -> mlir::Value {
420 if (inputs.size() != 1)
422 return mlir::UnrealizedConversionCastOp::create(builder, loc, resultType,
436 matchAndRewrite(T op,
typename T::Adaptor adaptor,
437 ConversionPatternRewriter &rewriter)
const final {
439 if (Operation *inputOp = adaptor.getInput().getDefiningOp())
440 if (!isa<mlir::UnrealizedConversionCastOp>(inputOp))
442 rewriter.modifyOpInPlace(
443 inputOp, [&] { inputOp->setAttr(
"sv.namehint", name); });
445 rewriter.replaceOp(op, adaptor.getInput());
458 matchAndRewrite(ConstClockOp clockConst, OpAdaptor adaptor,
459 ConversionPatternRewriter &rewriter)
const final {
461 clockConst, APInt(1, clockConst.getValue() == ClockConst::High));
466class AggregateConstantPattern
473 matchAndRewrite(hw::AggregateConstantOp aggregateConstant, OpAdaptor adaptor,
474 ConversionPatternRewriter &rewriter)
const final {
475 auto newType = typeConverter->convertType(aggregateConstant.getType());
476 auto newAttr = aggregateConstant.getFieldsAttr().replace(
477 [](seq::ClockConstAttr clockConst) {
478 return mlir::IntegerAttr::get(
479 mlir::IntegerType::get(clockConst.getContext(), 1),
480 APInt(1, clockConst.getValue() == ClockConst::High));
482 rewriter.replaceOpWithNewOp<hw::AggregateConstantOp>(
483 aggregateConstant, newType, cast<ArrayAttr>(newAttr));
496 matchAndRewrite(ClockDividerOp clockDiv, OpAdaptor adaptor,
497 ConversionPatternRewriter &rewriter)
const final {
498 Location loc = clockDiv.getLoc();
501 if (clockDiv.getPow2()) {
505 Value output = clockDiv.getInput();
507 SmallVector<Value> regs;
508 for (
unsigned i = 0; i < clockDiv.getPow2(); ++i) {
509 Value
reg = sv::RegOp::create(
510 rewriter, loc, rewriter.getI1Type(),
511 rewriter.getStringAttr(
"clock_out_" + std::to_string(i)));
514 sv::AlwaysOp::create(
515 rewriter, loc, sv::EventControl::AtPosEdge, output, [&] {
517 Value inverted = comb::XorOp::create(rewriter, loc, outputVal, one);
518 sv::BPAssignOp::create(rewriter, loc,
reg, inverted);
526 sv::InitialOp::create(rewriter, loc, [&] {
527 for (Value
reg : regs) {
528 sv::BPAssignOp::create(rewriter, loc,
reg, zero);
533 rewriter.replaceOp(clockDiv, output);
542 if (hw::type_isa<ClockType>(ty))
545 if (
auto arrayTy = hw::type_dyn_cast<hw::ArrayType>(ty))
548 if (
auto structTy = hw::type_dyn_cast<hw::StructType>(ty)) {
549 for (
auto field : structTy.getElements())
560 if (
auto module = dyn_cast<hw::HWModuleLike>(op)) {
561 for (
auto port :
module.getHWModuleType().getPorts())
562 if (!isLegalType(port.type))
567 if (
auto hwAggregateConstantOp = dyn_cast<hw::AggregateConstantOp>(op)) {
568 bool foundClockAttr =
false;
569 hwAggregateConstantOp.getFieldsAttr().walk(
570 [&](seq::ClockConstAttr attr) { foundClockAttr =
true; });
575 bool allOperandsLowered = llvm::all_of(
576 op->getOperands(), [](
auto op) { return isLegalType(op.getType()); });
577 bool allResultsLowered = llvm::all_of(op->getResults(), [](
auto result) {
578 return isLegalType(result.getType());
580 return allOperandsLowered && allResultsLowered;
584 auto circuit = getOperation();
585 MLIRContext *
context = &getContext();
587 auto modules = llvm::to_vector(circuit.getOps<
HWModuleOp>());
594 SmallVector<HWModuleGeneratedOp> generatedModules;
595 for (
auto &[config, memOps] : uniqueMems) {
598 generatedModules.push_back(genOp);
601 for (
auto memOp : memOps) {
602 auto parent = memOp->getParentOfType<
HWModuleOp>();
603 memsByModule[parent].emplace_back(&config, genOp, memOp);
614 std::atomic<bool> needsRegRandomization =
false;
615 std::atomic<bool> needsMemRandomization =
false;
618 for (
auto module : circuit.getOps<
HWModuleOp>())
619 moduleLoweringStates.try_emplace(module.getModuleNameAttr(),
620 ModuleLoweringState(module));
622 auto result = mlir::failableParallelForEach(
623 &getContext(), moduleLoweringStates, [&](
auto &moduleAndState) {
624 auto &state = moduleAndState.second;
625 auto module = state.module;
626 SeqToSVTypeConverter typeConverter;
628 typeConverter, module, pathTable, disableRegRandomization,
629 emitSeparateAlwaysBlocks, emitPresetAsInlineInit);
632 if (!disableRegRandomization) {
633 state.fragment.needsRegFragment =
true;
635 needsRegRandomization =
true;
639 if (
auto *it = memsByModule.find(module); it != memsByModule.end()) {
643 needsMemRandomization =
true;
644 needsRegRandomization =
true;
646 return state.immutableValueLowering.lower();
650 return signalPassFailure();
652 auto randomInitFragmentName =
653 FlatSymbolRefAttr::get(
context,
"RANDOM_INIT_FRAGMENT");
654 auto randomInitRegFragmentName =
655 FlatSymbolRefAttr::get(
context,
"RANDOM_INIT_REG_FRAGMENT");
656 auto randomInitMemFragmentName =
657 FlatSymbolRefAttr::get(
context,
"RANDOM_INIT_MEM_FRAGMENT");
659 for (
auto &[_, state] : moduleLoweringStates) {
660 const auto &info = state.fragment;
662 if (!info.needsRegFragment) {
666 SmallVector<Attribute> fragmentAttrs;
667 auto module = state.module;
670 fragmentAttrs = llvm::to_vector(others);
672 if (info.needsRegFragment) {
673 fragmentAttrs.push_back(randomInitRegFragmentName);
674 fragmentAttrs.push_back(randomInitFragmentName);
677 module->setAttr(emit::getFragmentsAttrName(),
678 ArrayAttr::get(context, fragmentAttrs));
682 SmallVector<Attribute> genModFragments;
683 if (!disableRegRandomization)
684 genModFragments.push_back(randomInitRegFragmentName);
685 if (!disableMemRandomization)
686 genModFragments.push_back(randomInitMemFragmentName);
687 if (!genModFragments.empty()) {
688 genModFragments.push_back(randomInitFragmentName);
689 auto fragmentAttr = ArrayAttr::get(
context, genModFragments);
690 for (
auto genOp : generatedModules)
695 SeqToSVTypeConverter typeConverter;
696 ConversionTarget target(*
context);
697 target.addIllegalDialect<SeqDialect>();
698 target.markUnknownOpDynamicallyLegal(
isLegalOp);
701 patterns.add<CompRegLower<CompRegOp>>(typeConverter,
context, lowerToAlwaysFF,
702 moduleLoweringStates);
703 patterns.add<CompRegLower<CompRegClockEnabledOp>>(
704 typeConverter,
context, lowerToAlwaysFF, moduleLoweringStates);
706 moduleLoweringStates);
707 patterns.add<ClockCastLowering<seq::FromClockOp>>(typeConverter,
context);
708 patterns.add<ClockCastLowering<seq::ToClockOp>>(typeConverter,
context);
717 if (failed(applyPartialConversion(circuit, target, std::move(
patterns))))
720 auto loc = UnknownLoc::get(
context);
721 auto b = ImplicitLocOpBuilder::atBlockBegin(loc, circuit.getBody());
722 if (needsRegRandomization || needsMemRandomization) {
723 sv::MacroDeclOp::create(b,
"ENABLE_INITIAL_REG_");
724 sv::MacroDeclOp::create(b,
"ENABLE_INITIAL_MEM_");
725 if (needsRegRandomization) {
726 sv::MacroDeclOp::create(b,
"FIRRTL_BEFORE_INITIAL");
727 sv::MacroDeclOp::create(b,
"FIRRTL_AFTER_INITIAL");
729 if (needsMemRandomization)
730 sv::MacroDeclOp::create(b,
"RANDOMIZE_MEM_INIT");
731 sv::MacroDeclOp::create(b,
"RANDOMIZE_REG_INIT");
732 sv::MacroDeclOp::create(b,
"RANDOMIZE");
733 sv::MacroDeclOp::create(b,
"RANDOMIZE_DELAY");
734 sv::MacroDeclOp::create(b,
"RANDOM");
735 sv::MacroDeclOp::create(b,
"INIT_RANDOM");
736 sv::MacroDeclOp::create(b,
"INIT_RANDOM_PROLOG_");
739 bool hasRegRandomization = needsRegRandomization && !disableRegRandomization;
740 bool hasMemRandomization = needsMemRandomization && !disableMemRandomization;
741 if (!hasRegRandomization && !hasMemRandomization)
746 for (Operation &op : *circuit.getBody()) {
747 if (!isa<sv::VerbatimOp, sv::IfDefOp>(&op)) {
748 b.setInsertionPoint(&op);
756 for (
auto sym : circuit.getOps<sv::MacroDeclOp>())
757 symbols.insert(sym.getName());
758 if (!symbols.count(
"SYNTHESIS"))
759 sv::MacroDeclOp::create(b,
"SYNTHESIS");
760 if (!symbols.count(
"VERILATOR"))
761 sv::MacroDeclOp::create(b,
"VERILATOR");
766 auto emitGuardedDefine = [&](StringRef guard, StringRef defName,
767 StringRef defineTrue =
"",
768 StringRef defineFalse = StringRef()) {
769 if (!defineFalse.data()) {
770 assert(defineTrue.data() &&
"didn't define anything");
772 b, guard, [&]() { sv::MacroDefOp::create(b, defName, defineTrue); });
777 if (defineTrue.data())
778 sv::MacroDefOp::create(b, defName, defineTrue);
780 [&]() { sv::MacroDefOp::create(b, defName, defineFalse); });
785 auto emitGuard = [&](
const char *guard, llvm::function_ref<void(
void)> body) {
787 b, guard, []() {}, body);
790 emit::FragmentOp::create(b, randomInitFragmentName.getAttr(), [&] {
791 sv::VerbatimOp::create(b,
792 "// Standard header to adapt well known macros for "
793 "register randomization.");
795 sv::VerbatimOp::create(
796 b,
"\n// RANDOM may be set to an expression that produces a 32-bit "
797 "random unsigned value.");
798 emitGuardedDefine(
"RANDOM",
"RANDOM", StringRef(),
"$random");
800 sv::VerbatimOp::create(
801 b,
"\n// Users can define INIT_RANDOM as general code that gets "
803 "into the\n// initializer block for modules with registers.");
804 emitGuardedDefine(
"INIT_RANDOM",
"INIT_RANDOM", StringRef(),
"");
806 sv::VerbatimOp::create(
807 b,
"\n// If using random initialization, you can also define "
808 "RANDOMIZE_DELAY to\n// customize the delay used, otherwise 0.002 "
810 emitGuardedDefine(
"RANDOMIZE_DELAY",
"RANDOMIZE_DELAY", StringRef(),
813 sv::VerbatimOp::create(
814 b,
"\n// Define INIT_RANDOM_PROLOG_ for use in our modules below.");
815 emitGuard(
"INIT_RANDOM_PROLOG_", [&]() {
819 emitGuardedDefine(
"VERILATOR",
"INIT_RANDOM_PROLOG_",
821 "`INIT_RANDOM #`RANDOMIZE_DELAY begin end");
823 [&]() { sv::MacroDefOp::create(b,
"INIT_RANDOM_PROLOG_",
""); });
827 if (hasMemRandomization) {
828 emit::FragmentOp::create(b, randomInitMemFragmentName.getAttr(), [&] {
829 sv::VerbatimOp::create(b,
"\n// Include rmemory initializers in init "
830 "blocks unless synthesis is set");
831 emitGuard(
"RANDOMIZE", [&]() {
832 emitGuardedDefine(
"RANDOMIZE_MEM_INIT",
"RANDOMIZE");
834 emitGuard(
"SYNTHESIS", [&] {
835 emitGuardedDefine(
"ENABLE_INITIAL_MEM_",
"ENABLE_INITIAL_MEM_",
838 sv::VerbatimOp::create(b,
"");
842 if (hasRegRandomization) {
843 emit::FragmentOp::create(b, randomInitRegFragmentName.getAttr(), [&] {
844 sv::VerbatimOp::create(b,
"\n// Include register initializers in init "
845 "blocks unless synthesis is set");
846 emitGuard(
"RANDOMIZE", [&]() {
847 emitGuardedDefine(
"RANDOMIZE_REG_INIT",
"RANDOMIZE");
849 emitGuard(
"SYNTHESIS", [&] {
850 emitGuardedDefine(
"ENABLE_INITIAL_REG_",
"ENABLE_INITIAL_REG_",
853 sv::VerbatimOp::create(b,
"");
860 return std::make_unique<SeqToSVPass>(options);
assert(baseType &&"element must be base type")
static bool isLegalOp(Operation *op)
Returns true if the given op is considered as legal - i.e.
static std::unique_ptr< Context > context
static FIRRTLBaseType convertType(FIRRTLBaseType type)
Returns null type if no conversion is needed.
static bool isLegalType(Type ty)
static bool isLegalOp(Operation *op)
FIR memory lowering helper.
UniqueConfigs collectMemories(ArrayRef< hw::HWModuleOp > modules)
Groups memories by their kind from the whole design.
void lowerMemoriesInModule(hw::HWModuleOp module, ArrayRef< MemoryConfig > mems)
Lowers a group of memories from the same module.
hw::HWModuleGeneratedOp createMemoryModule(FirMemConfig &mem, ArrayRef< seq::FirMemOp > memOps)
Creates the generated module for a given configuration.
Lower FirRegOp to sv.reg and sv.always.
bool needsRegRandomization() const
static PathTable createPaths(mlir::ModuleOp top)
When a register is buried under an ifdef op, the initialization code at the footer of the HW module w...
unsigned numSubaccessRestored
StringRef getFragmentsAttrName()
Return the name of the fragments array attribute.
FailureOr< seq::InitialOp > mergeInitialOps(Block *block)
mlir::ArrayAttr getSVAttributes(mlir::Operation *op)
Return all the SV attributes of an operation, or null if there are none.
void setSVAttributes(mlir::Operation *op, mlir::ArrayAttr attrs)
Set the SV attributes of an operation.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< mlir::Pass > createLowerSeqToSVPass(const LowerSeqToSVOptions &options={})
StringRef chooseName(StringRef a, StringRef b)
Choose a good name for an item from two options.
reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
void runOnOperation() override
Generic pattern which replaces an operation by one of the same operation name, but with converted att...