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;
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 = sv::InitialOp::create(builder, 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())) {
118 mlir::UnrealizedConversionCastOp::create(
119 builder, loc, ArrayRef<Type>{result.getType()}, ArrayRef<Value>{})
121 result.replaceAllUsesWith(placeholder);
123 {cast<mlir::TypedValue<seq ::ImmutableType>>(placeholder), operand});
126 svInitialOp.getBodyBlock()->getOperations().splice(
127 svInitialOp.end(), initialOp.getBodyBlock()->getOperations());
129 assert(initialOp->use_empty());
137template <
typename OpTy>
141 TypeConverter &typeConverter, MLIRContext *context,
bool lowerToAlwaysFF,
142 const MapVector<StringAttr, ModuleLoweringState> &moduleLoweringStates)
144 lowerToAlwaysFF(lowerToAlwaysFF),
145 moduleLoweringStates(moduleLoweringStates) {}
150 matchAndRewrite(OpTy
reg, OpAdaptor adaptor,
151 ConversionPatternRewriter &rewriter)
const final {
152 Location loc =
reg.getLoc();
155 ConversionPattern::getTypeConverter()->convertType(
reg.getType());
156 auto svReg = sv::RegOp::create(rewriter, loc, regTy,
reg.getNameAttr(),
157 reg.getInnerSymAttr());
159 svReg->setDialectAttrs(
reg->getDialectAttrs());
165 auto assignValue = [&] {
166 createAssign(rewriter,
reg.getLoc(), svReg,
reg);
168 auto assignReset = [&] {
169 sv::PAssignOp::create(rewriter, loc, svReg, adaptor.getResetValue());
175 bool mayLowerToAlwaysFF = lowerToAlwaysFF && !
reg.getInitialValue();
177 if (adaptor.getReset() && adaptor.getResetValue()) {
178 if (mayLowerToAlwaysFF) {
179 sv::AlwaysFFOp::create(rewriter, loc, sv::EventControl::AtPosEdge,
180 adaptor.getClk(), sv::ResetType::SyncReset,
181 sv::EventControl::AtPosEdge, adaptor.getReset(),
182 assignValue, assignReset);
184 sv::AlwaysOp::create(
185 rewriter, loc, sv::EventControl::AtPosEdge, adaptor.getClk(), [&] {
186 sv::IfOp::create(rewriter, loc, adaptor.getReset(), assignReset,
191 if (mayLowerToAlwaysFF) {
192 sv::AlwaysFFOp::create(rewriter, loc, sv::EventControl::AtPosEdge,
193 adaptor.getClk(), assignValue);
195 sv::AlwaysOp::create(rewriter, loc, sv::EventControl::AtPosEdge,
196 adaptor.getClk(), assignValue);
201 if (
auto init =
reg.getInitialValue()) {
202 auto module = reg->template getParentOfType<hw::HWModuleOp>();
203 const auto &initial =
204 moduleLoweringStates.find(module.getModuleNameAttr())
205 ->second.immutableValueLowering;
207 Value initialValue = initial.lookupImmutableValue(init);
209 if (
auto op = initialValue.getDefiningOp();
210 op && op->hasTrait<mlir::OpTrait::ConstantLike>()) {
211 auto clonedConstant = rewriter.clone(*op);
212 rewriter.moveOpBefore(clonedConstant, svReg);
213 svReg.getInitMutable().assign(clonedConstant->getResult(0));
215 OpBuilder::InsertionGuard guard(rewriter);
216 auto in = initial.getSVInitial();
217 rewriter.setInsertionPointToEnd(in.getBodyBlock());
218 sv::BPAssignOp::create(rewriter,
reg->getLoc(), svReg, initialValue);
222 rewriter.replaceOp(
reg, regVal);
227 void createAssign(ConversionPatternRewriter &rewriter, Location loc,
231 bool lowerToAlwaysFF;
232 const MapVector<StringAttr, ModuleLoweringState> &moduleLoweringStates;
237void CompRegLower<CompRegOp>::createAssign(ConversionPatternRewriter &rewriter,
239 OpAdaptor
reg)
const {
240 sv::PAssignOp::create(rewriter, loc, svReg,
reg.getInput());
244void CompRegLower<CompRegClockEnabledOp>::createAssign(
245 ConversionPatternRewriter &rewriter, Location loc,
sv::RegOp svReg,
246 OpAdaptor
reg)
const {
247 sv::IfOp::create(rewriter, loc,
reg.getClockEnable(), [&]() {
248 sv::PAssignOp::create(rewriter, loc, svReg, reg.getInput());
255 FromImmutableLowering(
256 TypeConverter &typeConverter, MLIRContext *context,
257 const MapVector<StringAttr, ModuleLoweringState> &moduleLoweringStates)
259 moduleLoweringStates(moduleLoweringStates) {}
264 matchAndRewrite(FromImmutableOp fromImmutableOp, OpAdaptor adaptor,
265 ConversionPatternRewriter &rewriter)
const final {
266 Location loc = fromImmutableOp.getLoc();
268 auto regTy = ConversionPattern::getTypeConverter()->convertType(
269 fromImmutableOp.getType());
270 auto svReg = sv::RegOp::create(rewriter, loc, regTy);
275 auto module = fromImmutableOp->template getParentOfType<hw::HWModuleOp>();
276 const auto &initial = moduleLoweringStates.find(module.getModuleNameAttr())
277 ->second.immutableValueLowering;
280 initial.lookupImmutableValue(fromImmutableOp.getInput());
282 OpBuilder::InsertionGuard guard(rewriter);
283 auto in = initial.getSVInitial();
284 rewriter.setInsertionPointToEnd(in.getBodyBlock());
285 sv::BPAssignOp::create(rewriter, fromImmutableOp->getLoc(), svReg,
288 rewriter.replaceOp(fromImmutableOp, regVal);
293 const MapVector<StringAttr, ModuleLoweringState> &moduleLoweringStates;
302 matchAndRewrite(ClockGateOp clockGate, OpAdaptor adaptor,
303 ConversionPatternRewriter &rewriter)
const final {
304 auto loc = clockGate.getLoc();
305 Value
clk = adaptor.getInput();
308 Value enable = adaptor.getEnable();
309 if (
auto te = adaptor.getTestEnable())
310 enable = comb::OrOp::create(rewriter, loc, enable, te);
314 sv::RegOp::create(rewriter, loc, rewriter.getI1Type(),
315 rewriter.getStringAttr(
"cg_en_latch"));
318 sv::AlwaysOp::create(
319 rewriter, loc, llvm::SmallVector<sv::EventControl>{},
320 llvm::SmallVector<Value>{}, [&]() {
322 rewriter, loc, comb::createOrFoldNot(loc, clk, rewriter), [&]() {
323 sv::PAssignOp::create(rewriter, 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)
411 return mlir::UnrealizedConversionCastOp::create(builder, loc, resultType,
416 addSourceMaterialization([&](mlir::OpBuilder &builder,
417 mlir::Type resultType, mlir::ValueRange inputs,
418 mlir::Location loc) -> mlir::Value {
419 if (inputs.size() != 1)
421 return mlir::UnrealizedConversionCastOp::create(builder, loc, resultType,
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) {
508 Value
reg = sv::RegOp::create(
509 rewriter, loc, rewriter.getI1Type(),
510 rewriter.getStringAttr(
"clock_out_" + std::to_string(i)));
513 sv::AlwaysOp::create(
514 rewriter, loc, sv::EventControl::AtPosEdge, output, [&] {
516 Value inverted = comb::XorOp::create(rewriter, loc, outputVal, one);
517 sv::BPAssignOp::create(rewriter, loc,
reg, inverted);
525 sv::InitialOp::create(rewriter, loc, [&] {
526 for (Value
reg : regs) {
527 sv::BPAssignOp::create(rewriter, 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 sv::MacroDeclOp::create(b,
"ENABLE_INITIAL_REG_");
723 sv::MacroDeclOp::create(b,
"ENABLE_INITIAL_MEM_");
724 if (needsRegRandomization) {
725 sv::MacroDeclOp::create(b,
"FIRRTL_BEFORE_INITIAL");
726 sv::MacroDeclOp::create(b,
"FIRRTL_AFTER_INITIAL");
728 if (needsMemRandomization)
729 sv::MacroDeclOp::create(b,
"RANDOMIZE_MEM_INIT");
730 sv::MacroDeclOp::create(b,
"RANDOMIZE_REG_INIT");
731 sv::MacroDeclOp::create(b,
"RANDOMIZE");
732 sv::MacroDeclOp::create(b,
"RANDOMIZE_DELAY");
733 sv::MacroDeclOp::create(b,
"RANDOM");
734 sv::MacroDeclOp::create(b,
"INIT_RANDOM");
735 sv::MacroDeclOp::create(b,
"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 sv::MacroDeclOp::create(b,
"SYNTHESIS");
759 if (!symbols.count(
"VERILATOR"))
760 sv::MacroDeclOp::create(b,
"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 b, guard, [&]() { sv::MacroDefOp::create(b, defName, defineTrue); });
776 if (defineTrue.data())
777 sv::MacroDefOp::create(b, defName, defineTrue);
779 [&]() { sv::MacroDefOp::create(b, defName, defineFalse); });
784 auto emitGuard = [&](
const char *guard, llvm::function_ref<void(
void)> body) {
786 b, guard, []() {}, body);
789 emit::FragmentOp::create(b, randomInitFragmentName.getAttr(), [&] {
790 sv::VerbatimOp::create(b,
791 "// Standard header to adapt well known macros for "
792 "register randomization.");
794 sv::VerbatimOp::create(
795 b,
"\n// RANDOM may be set to an expression that produces a 32-bit "
796 "random unsigned value.");
797 emitGuardedDefine(
"RANDOM",
"RANDOM", StringRef(),
"$random");
799 sv::VerbatimOp::create(
800 b,
"\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 sv::VerbatimOp::create(
806 b,
"\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 sv::VerbatimOp::create(
813 b,
"\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 [&]() { sv::MacroDefOp::create(b,
"INIT_RANDOM_PROLOG_",
""); });
826 if (hasMemRandomization) {
827 emit::FragmentOp::create(b, randomInitMemFragmentName.getAttr(), [&] {
828 sv::VerbatimOp::create(b,
"\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 sv::VerbatimOp::create(b,
"");
841 if (hasRegRandomization) {
842 emit::FragmentOp::create(b, randomInitRegFragmentName.getAttr(), [&] {
843 sv::VerbatimOp::create(b,
"\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 sv::VerbatimOp::create(b,
"");
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...