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>::LowerSeqToSVBase;
50 using LowerSeqToSVBase<
SeqToSVPass>::numSubaccessRestored;
42struct SeqToSVPass :
public impl::LowerSeqToSVBase<SeqToSVPass> {
…};
55struct ModuleLoweringState {
57 : immutableValueLowering(module), module(module) {}
59 struct ImmutableValueLowering {
63 LogicalResult lower();
64 LogicalResult lower(seq::InitialOp initialOp);
67 lookupImmutableValue(mlir::TypedValue<seq::ImmutableType> immut)
const {
68 return mapping.lookup(immut);
71 sv::InitialOp getSVInitial()
const {
return svInitialOp; }
74 sv::InitialOp svInitialOp = {};
77 MapVector<mlir::TypedValue<seq::ImmutableType>, Value> mapping;
80 } immutableValueLowering;
83 bool needsRegFragment =
false;
89LogicalResult ModuleLoweringState::ImmutableValueLowering::lower() {
94 auto initialOp = *result;
98 return lower(initialOp);
102ModuleLoweringState::ImmutableValueLowering::lower(seq::InitialOp initialOp) {
103 OpBuilder builder = OpBuilder::atBlockBegin(module.getBodyBlock());
105 svInitialOp = builder.create<sv::InitialOp>(initialOp->getLoc());
107 assert(initialOp.getNumOperands() == 0 &&
108 "initial op should have no operands");
110 auto loc = initialOp.getLoc();
111 llvm::SmallVector<Value> results;
113 auto yieldOp = cast<seq::YieldOp>(initialOp.getBodyBlock()->getTerminator());
115 for (
auto [result, operand] :
116 llvm::zip(initialOp.getResults(), yieldOp->getOperands())) {
119 .create<mlir::UnrealizedConversionCastOp>(
120 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,
143 const MapVector<StringAttr, ModuleLoweringState> &moduleLoweringStates)
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 = rewriter.create<
sv::RegOp>(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 rewriter.create<sv::PAssignOp>(loc, svReg, adaptor.getResetValue());
176 bool mayLowerToAlwaysFF = lowerToAlwaysFF && !
reg.getInitialValue();
178 if (adaptor.getReset() && adaptor.getResetValue()) {
179 if (mayLowerToAlwaysFF) {
180 rewriter.create<sv::AlwaysFFOp>(
181 loc, sv::EventControl::AtPosEdge, adaptor.getClk(),
182 sv::ResetType::SyncReset, sv::EventControl::AtPosEdge,
183 adaptor.getReset(), assignValue, assignReset);
185 rewriter.create<sv::AlwaysOp>(
186 loc, sv::EventControl::AtPosEdge, adaptor.getClk(), [&] {
187 rewriter.create<sv::IfOp>(loc, adaptor.getReset(), assignReset,
192 if (mayLowerToAlwaysFF) {
193 rewriter.create<sv::AlwaysFFOp>(loc, sv::EventControl::AtPosEdge,
194 adaptor.getClk(), assignValue);
196 rewriter.create<sv::AlwaysOp>(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 rewriter.create<sv::BPAssignOp>(
reg->getLoc(), svReg, initialValue);
223 rewriter.replaceOp(
reg, regVal);
228 void createAssign(ConversionPatternRewriter &rewriter, Location loc,
232 bool lowerToAlwaysFF;
233 const MapVector<StringAttr, ModuleLoweringState> &moduleLoweringStates;
238void CompRegLower<CompRegOp>::createAssign(ConversionPatternRewriter &rewriter,
240 OpAdaptor
reg)
const {
241 rewriter.create<sv::PAssignOp>(loc, svReg,
reg.getInput());
245void CompRegLower<CompRegClockEnabledOp>::createAssign(
246 ConversionPatternRewriter &rewriter, Location loc,
sv::RegOp svReg,
247 OpAdaptor
reg)
const {
248 rewriter.create<sv::IfOp>(loc,
reg.getClockEnable(), [&]() {
249 rewriter.create<sv::PAssignOp>(loc, svReg,
reg.getInput());
256 FromImmutableLowering(
257 TypeConverter &typeConverter, MLIRContext *context,
258 const MapVector<StringAttr, ModuleLoweringState> &moduleLoweringStates)
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 = rewriter.create<
sv::RegOp>(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 rewriter.
create<sv::BPAssignOp>(fromImmutableOp->getLoc(), svReg,
289 rewriter.replaceOp(fromImmutableOp, regVal);
294 const MapVector<StringAttr, ModuleLoweringState> &moduleLoweringStates;
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 = rewriter.create<
comb::OrOp>(loc, enable, te);
314 Value enableLatch = rewriter.create<
sv::RegOp>(
315 loc, rewriter.getI1Type(), rewriter.getStringAttr(
"cg_en_latch"));
318 rewriter.create<sv::AlwaysOp>(
319 loc, llvm::SmallVector<sv::EventControl>{}, llvm::SmallVector<Value>{},
321 rewriter.create<sv::IfOp>(
322 loc, comb::createOrFoldNot(loc, clk, rewriter), [&]() {
323 rewriter.create<sv::PAssignOp>(loc, enableLatch, enable);
341 matchAndRewrite(ClockInverterOp op, OpAdaptor adaptor,
342 ConversionPatternRewriter &rewriter)
const final {
343 auto loc = op.getLoc();
344 Value
clk = adaptor.getInput();
346 StringAttr name = op->getAttrOfType<StringAttr>(
"sv.namehint");
348 auto newOp = rewriter.replaceOpWithNewOp<
comb::XorOp>(op,
clk, one);
350 rewriter.modifyOpInPlace(newOp,
351 [&] { newOp->setAttr(
"sv.namehint", name); });
364 matchAndRewrite(ClockMuxOp clockMux, OpAdaptor adaptor,
365 ConversionPatternRewriter &rewriter)
const final {
366 rewriter.replaceOpWithNewOp<
comb::MuxOp>(clockMux, adaptor.getCond(),
367 adaptor.getTrueClock(),
368 adaptor.getFalseClock(),
true);
374struct SeqToSVTypeConverter :
public TypeConverter {
375 SeqToSVTypeConverter() {
376 addConversion([&](Type type) {
return type; });
377 addConversion([&](seq::ImmutableType type) {
return type.getInnerType(); });
378 addConversion([&](seq::ClockType type) {
379 return IntegerType::get(type.getContext(), 1);
381 addConversion([&](hw::StructType structTy) {
382 bool changed =
false;
384 SmallVector<hw::StructType::FieldInfo> newFields;
385 for (
auto field : structTy.getElements()) {
386 auto &newField = newFields.emplace_back();
387 newField.name = field.name;
389 if (field.type != newField.type)
396 return hw::StructType::get(structTy.getContext(), newFields);
398 addConversion([&](hw::ArrayType arrayTy) {
399 auto elementTy = arrayTy.getElementType();
401 if (elementTy != newElementTy)
402 return hw::ArrayType::get(newElementTy, arrayTy.getNumElements());
406 addTargetMaterialization([&](mlir::OpBuilder &builder,
407 mlir::Type resultType, mlir::ValueRange inputs,
408 mlir::Location loc) -> mlir::Value {
409 if (inputs.size() != 1)
412 .create<mlir::UnrealizedConversionCastOp>(loc, resultType, inputs[0])
416 addSourceMaterialization([&](mlir::OpBuilder &builder,
417 mlir::Type resultType, mlir::ValueRange inputs,
418 mlir::Location loc) -> mlir::Value {
419 if (inputs.size() != 1)
422 .create<mlir::UnrealizedConversionCastOp>(loc, resultType, inputs[0])
435 matchAndRewrite(T op,
typename T::Adaptor adaptor,
436 ConversionPatternRewriter &rewriter)
const final {
438 if (Operation *inputOp = adaptor.getInput().getDefiningOp())
439 if (!isa<mlir::UnrealizedConversionCastOp>(inputOp))
441 rewriter.modifyOpInPlace(
442 inputOp, [&] { inputOp->setAttr(
"sv.namehint", name); });
444 rewriter.replaceOp(op, adaptor.getInput());
457 matchAndRewrite(ConstClockOp clockConst, OpAdaptor adaptor,
458 ConversionPatternRewriter &rewriter)
const final {
460 clockConst, APInt(1, clockConst.getValue() == ClockConst::High));
465class AggregateConstantPattern
472 matchAndRewrite(hw::AggregateConstantOp aggregateConstant, OpAdaptor adaptor,
473 ConversionPatternRewriter &rewriter)
const final {
474 auto newType = typeConverter->convertType(aggregateConstant.getType());
475 auto newAttr = aggregateConstant.getFieldsAttr().replace(
476 [](seq::ClockConstAttr clockConst) {
477 return mlir::IntegerAttr::get(
478 mlir::IntegerType::get(clockConst.getContext(), 1),
479 APInt(1, clockConst.getValue() == ClockConst::High));
481 rewriter.replaceOpWithNewOp<hw::AggregateConstantOp>(
482 aggregateConstant, newType, cast<ArrayAttr>(newAttr));
495 matchAndRewrite(ClockDividerOp clockDiv, OpAdaptor adaptor,
496 ConversionPatternRewriter &rewriter)
const final {
497 Location loc = clockDiv.getLoc();
500 if (clockDiv.getPow2()) {
504 Value output = clockDiv.getInput();
506 SmallVector<Value> regs;
507 for (
unsigned i = 0; i < clockDiv.getPow2(); ++i) {
509 loc, rewriter.getI1Type(),
510 rewriter.getStringAttr(
"clock_out_" + std::to_string(i)));
513 rewriter.create<sv::AlwaysOp>(
514 loc, sv::EventControl::AtPosEdge, output, [&] {
517 rewriter.create<sv::BPAssignOp>(loc,
reg, inverted);
525 rewriter.
create<sv::InitialOp>(loc, [&] {
526 for (Value
reg : regs) {
527 rewriter.
create<sv::BPAssignOp>(loc,
reg, zero);
532 rewriter.replaceOp(clockDiv, output);
541 if (hw::type_isa<ClockType>(ty))
544 if (
auto arrayTy = hw::type_dyn_cast<hw::ArrayType>(ty))
547 if (
auto structTy = hw::type_dyn_cast<hw::StructType>(ty)) {
548 for (
auto field : structTy.getElements())
559 if (
auto module = dyn_cast<hw::HWModuleLike>(op)) {
560 for (
auto port :
module.getHWModuleType().getPorts())
561 if (!isLegalType(port.type))
566 if (
auto hwAggregateConstantOp = dyn_cast<hw::AggregateConstantOp>(op)) {
567 bool foundClockAttr =
false;
568 hwAggregateConstantOp.getFieldsAttr().walk(
569 [&](seq::ClockConstAttr attr) { foundClockAttr =
true; });
574 bool allOperandsLowered = llvm::all_of(
575 op->getOperands(), [](
auto op) { return isLegalType(op.getType()); });
576 bool allResultsLowered = llvm::all_of(op->getResults(), [](
auto result) {
577 return isLegalType(result.getType());
579 return allOperandsLowered && allResultsLowered;
583 auto circuit = getOperation();
584 MLIRContext *context = &getContext();
586 auto modules = llvm::to_vector(circuit.getOps<
HWModuleOp>());
592 MapVector<HWModuleOp, SmallVector<FirMemLowering::MemoryConfig>> memsByModule;
593 SmallVector<HWModuleGeneratedOp> generatedModules;
594 for (
auto &[config, memOps] : uniqueMems) {
597 generatedModules.push_back(genOp);
600 for (
auto memOp : memOps) {
601 auto parent = memOp->getParentOfType<
HWModuleOp>();
602 memsByModule[parent].emplace_back(&config, genOp, memOp);
613 std::atomic<bool> needsRegRandomization =
false;
614 std::atomic<bool> needsMemRandomization =
false;
616 MapVector<StringAttr, ModuleLoweringState> moduleLoweringStates;
617 for (
auto module : circuit.getOps<
HWModuleOp>())
618 moduleLoweringStates.try_emplace(module.getModuleNameAttr(),
619 ModuleLoweringState(module));
621 auto result = mlir::failableParallelForEach(
622 &getContext(), moduleLoweringStates, [&](
auto &moduleAndState) {
623 auto &state = moduleAndState.second;
624 auto module = state.module;
625 SeqToSVTypeConverter typeConverter;
627 disableRegRandomization,
628 emitSeparateAlwaysBlocks);
631 if (!disableRegRandomization) {
632 state.fragment.needsRegFragment =
true;
634 needsRegRandomization =
true;
638 if (
auto *it = memsByModule.find(module); it != memsByModule.end()) {
642 needsMemRandomization =
true;
643 needsRegRandomization =
true;
645 return state.immutableValueLowering.lower();
649 return signalPassFailure();
651 auto randomInitFragmentName =
652 FlatSymbolRefAttr::get(context,
"RANDOM_INIT_FRAGMENT");
653 auto randomInitRegFragmentName =
654 FlatSymbolRefAttr::get(context,
"RANDOM_INIT_REG_FRAGMENT");
655 auto randomInitMemFragmentName =
656 FlatSymbolRefAttr::get(context,
"RANDOM_INIT_MEM_FRAGMENT");
658 for (
auto &[_, state] : moduleLoweringStates) {
659 const auto &info = state.fragment;
661 if (!info.needsRegFragment) {
665 SmallVector<Attribute> fragmentAttrs;
666 auto module = state.module;
669 fragmentAttrs = llvm::to_vector(others);
671 if (info.needsRegFragment) {
672 fragmentAttrs.push_back(randomInitRegFragmentName);
673 fragmentAttrs.push_back(randomInitFragmentName);
676 module->setAttr(emit::getFragmentsAttrName(),
677 ArrayAttr::get(context, fragmentAttrs));
681 SmallVector<Attribute> genModFragments;
682 if (!disableRegRandomization)
683 genModFragments.push_back(randomInitRegFragmentName);
684 if (!disableMemRandomization)
685 genModFragments.push_back(randomInitMemFragmentName);
686 if (!genModFragments.empty()) {
687 genModFragments.push_back(randomInitFragmentName);
688 auto fragmentAttr = ArrayAttr::get(context, genModFragments);
689 for (
auto genOp : generatedModules)
694 SeqToSVTypeConverter typeConverter;
695 ConversionTarget target(*context);
696 target.addIllegalDialect<SeqDialect>();
697 target.markUnknownOpDynamicallyLegal(
isLegalOp);
699 RewritePatternSet
patterns(context);
700 patterns.add<CompRegLower<CompRegOp>>(typeConverter, context, lowerToAlwaysFF,
701 moduleLoweringStates);
702 patterns.add<CompRegLower<CompRegClockEnabledOp>>(
703 typeConverter, context, lowerToAlwaysFF, moduleLoweringStates);
704 patterns.add<FromImmutableLowering>(typeConverter, context,
705 moduleLoweringStates);
706 patterns.add<ClockCastLowering<seq::FromClockOp>>(typeConverter, context);
707 patterns.add<ClockCastLowering<seq::ToClockOp>>(typeConverter, context);
708 patterns.add<ClockGateLowering>(typeConverter, context);
709 patterns.add<ClockInverterLowering>(typeConverter, context);
710 patterns.add<ClockMuxLowering>(typeConverter, context);
711 patterns.add<ClockDividerLowering>(typeConverter, context);
712 patterns.add<ClockConstLowering>(typeConverter, context);
714 patterns.add<AggregateConstantPattern>(typeConverter, context);
716 if (failed(applyPartialConversion(circuit, target, std::move(
patterns))))
719 auto loc = UnknownLoc::get(context);
720 auto b = ImplicitLocOpBuilder::atBlockBegin(loc, circuit.getBody());
721 if (needsRegRandomization || needsMemRandomization) {
722 b.create<sv::MacroDeclOp>(
"ENABLE_INITIAL_REG_");
723 b.create<sv::MacroDeclOp>(
"ENABLE_INITIAL_MEM_");
724 if (needsRegRandomization) {
725 b.create<sv::MacroDeclOp>(
"FIRRTL_BEFORE_INITIAL");
726 b.create<sv::MacroDeclOp>(
"FIRRTL_AFTER_INITIAL");
728 if (needsMemRandomization)
729 b.create<sv::MacroDeclOp>(
"RANDOMIZE_MEM_INIT");
730 b.create<sv::MacroDeclOp>(
"RANDOMIZE_REG_INIT");
731 b.create<sv::MacroDeclOp>(
"RANDOMIZE");
732 b.create<sv::MacroDeclOp>(
"RANDOMIZE_DELAY");
733 b.create<sv::MacroDeclOp>(
"RANDOM");
734 b.create<sv::MacroDeclOp>(
"INIT_RANDOM");
735 b.create<sv::MacroDeclOp>(
"INIT_RANDOM_PROLOG_");
738 bool hasRegRandomization = needsRegRandomization && !disableRegRandomization;
739 bool hasMemRandomization = needsMemRandomization && !disableMemRandomization;
740 if (!hasRegRandomization && !hasMemRandomization)
745 for (Operation &op : *circuit.getBody()) {
746 if (!isa<sv::VerbatimOp, sv::IfDefOp>(&op)) {
747 b.setInsertionPoint(&op);
755 for (
auto sym : circuit.getOps<sv::MacroDeclOp>())
756 symbols.insert(sym.getName());
757 if (!symbols.count(
"SYNTHESIS"))
758 b.create<sv::MacroDeclOp>(
"SYNTHESIS");
759 if (!symbols.count(
"VERILATOR"))
760 b.create<sv::MacroDeclOp>(
"VERILATOR");
765 auto emitGuardedDefine = [&](StringRef guard, StringRef defName,
766 StringRef defineTrue =
"",
767 StringRef defineFalse = StringRef()) {
768 if (!defineFalse.data()) {
769 assert(defineTrue.data() &&
"didn't define anything");
771 guard, [&]() { b.create<sv::MacroDefOp>(defName, defineTrue); });
776 if (defineTrue.data())
777 b.create<sv::MacroDefOp>(defName, defineTrue);
779 [&]() { b.create<sv::MacroDefOp>(defName, defineFalse); });
784 auto emitGuard = [&](
const char *guard, llvm::function_ref<void(
void)> body) {
786 guard, []() {}, body);
789 b.create<emit::FragmentOp>(randomInitFragmentName.getAttr(), [&] {
790 b.create<sv::VerbatimOp>(
791 "// Standard header to adapt well known macros for "
792 "register randomization.");
794 b.create<sv::VerbatimOp>(
795 "\n// RANDOM may be set to an expression that produces a 32-bit "
796 "random unsigned value.");
797 emitGuardedDefine(
"RANDOM",
"RANDOM", StringRef(),
"$random");
799 b.create<sv::VerbatimOp>(
800 "\n// Users can define INIT_RANDOM as general code that gets "
802 "into the\n// initializer block for modules with registers.");
803 emitGuardedDefine(
"INIT_RANDOM",
"INIT_RANDOM", StringRef(),
"");
805 b.create<sv::VerbatimOp>(
806 "\n// If using random initialization, you can also define "
807 "RANDOMIZE_DELAY to\n// customize the delay used, otherwise 0.002 "
809 emitGuardedDefine(
"RANDOMIZE_DELAY",
"RANDOMIZE_DELAY", StringRef(),
812 b.create<sv::VerbatimOp>(
813 "\n// Define INIT_RANDOM_PROLOG_ for use in our modules below.");
814 emitGuard(
"INIT_RANDOM_PROLOG_", [&]() {
818 emitGuardedDefine(
"VERILATOR",
"INIT_RANDOM_PROLOG_",
820 "`INIT_RANDOM #`RANDOMIZE_DELAY begin end");
822 [&]() { b.create<sv::MacroDefOp>(
"INIT_RANDOM_PROLOG_",
""); });
826 if (hasMemRandomization) {
827 b.create<emit::FragmentOp>(randomInitMemFragmentName.getAttr(), [&] {
828 b.create<sv::VerbatimOp>(
"\n// Include rmemory initializers in init "
829 "blocks unless synthesis is set");
830 emitGuard(
"RANDOMIZE", [&]() {
831 emitGuardedDefine(
"RANDOMIZE_MEM_INIT",
"RANDOMIZE");
833 emitGuard(
"SYNTHESIS", [&] {
834 emitGuardedDefine(
"ENABLE_INITIAL_MEM_",
"ENABLE_INITIAL_MEM_",
837 b.create<sv::VerbatimOp>(
"");
841 if (hasRegRandomization) {
842 b.create<emit::FragmentOp>(randomInitRegFragmentName.getAttr(), [&] {
843 b.create<sv::VerbatimOp>(
"\n// Include register initializers in init "
844 "blocks unless synthesis is set");
845 emitGuard(
"RANDOMIZE", [&]() {
846 emitGuardedDefine(
"RANDOMIZE_REG_INIT",
"RANDOMIZE");
848 emitGuard(
"SYNTHESIS", [&] {
849 emitGuardedDefine(
"ENABLE_INITIAL_REG_",
"ENABLE_INITIAL_REG_",
852 b.create<sv::VerbatimOp>(
"");
859 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 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...