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 = 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);
607 std::atomic<bool> needsRegRandomization =
false;
608 std::atomic<bool> needsMemRandomization =
false;
610 MapVector<StringAttr, ModuleLoweringState> moduleLoweringStates;
611 for (
auto module : circuit.getOps<
HWModuleOp>())
612 moduleLoweringStates.try_emplace(module.getModuleNameAttr(),
613 ModuleLoweringState(module));
615 auto result = mlir::failableParallelForEach(
616 &getContext(), moduleLoweringStates, [&](
auto &moduleAndState) {
617 auto &state = moduleAndState.second;
618 auto module = state.module;
619 SeqToSVTypeConverter typeConverter;
621 disableRegRandomization,
622 emitSeparateAlwaysBlocks);
625 if (!disableRegRandomization) {
626 state.fragment.needsRegFragment =
true;
628 needsRegRandomization =
true;
632 if (
auto *it = memsByModule.find(module); it != memsByModule.end()) {
636 needsMemRandomization =
true;
637 needsRegRandomization =
true;
639 return state.immutableValueLowering.lower();
643 return signalPassFailure();
645 auto randomInitFragmentName =
646 FlatSymbolRefAttr::get(context,
"RANDOM_INIT_FRAGMENT");
647 auto randomInitRegFragmentName =
648 FlatSymbolRefAttr::get(context,
"RANDOM_INIT_REG_FRAGMENT");
649 auto randomInitMemFragmentName =
650 FlatSymbolRefAttr::get(context,
"RANDOM_INIT_MEM_FRAGMENT");
652 for (
auto &[_, state] : moduleLoweringStates) {
653 const auto &info = state.fragment;
655 if (!info.needsRegFragment) {
659 SmallVector<Attribute> fragmentAttrs;
660 auto module = state.module;
663 fragmentAttrs = llvm::to_vector(others);
665 if (info.needsRegFragment) {
666 fragmentAttrs.push_back(randomInitRegFragmentName);
667 fragmentAttrs.push_back(randomInitFragmentName);
670 module->setAttr(emit::getFragmentsAttrName(),
671 ArrayAttr::get(context, fragmentAttrs));
675 SmallVector<Attribute> genModFragments;
676 if (!disableRegRandomization)
677 genModFragments.push_back(randomInitRegFragmentName);
678 if (!disableMemRandomization)
679 genModFragments.push_back(randomInitMemFragmentName);
680 if (!genModFragments.empty()) {
681 genModFragments.push_back(randomInitFragmentName);
682 auto fragmentAttr = ArrayAttr::get(context, genModFragments);
683 for (
auto genOp : generatedModules)
688 SeqToSVTypeConverter typeConverter;
689 ConversionTarget target(*context);
690 target.addIllegalDialect<SeqDialect>();
691 target.markUnknownOpDynamicallyLegal(
isLegalOp);
693 RewritePatternSet
patterns(context);
694 patterns.add<CompRegLower<CompRegOp>>(typeConverter, context, lowerToAlwaysFF,
695 moduleLoweringStates);
696 patterns.add<CompRegLower<CompRegClockEnabledOp>>(
697 typeConverter, context, lowerToAlwaysFF, moduleLoweringStates);
698 patterns.add<FromImmutableLowering>(typeConverter, context,
699 moduleLoweringStates);
700 patterns.add<ClockCastLowering<seq::FromClockOp>>(typeConverter, context);
701 patterns.add<ClockCastLowering<seq::ToClockOp>>(typeConverter, context);
702 patterns.add<ClockGateLowering>(typeConverter, context);
703 patterns.add<ClockInverterLowering>(typeConverter, context);
704 patterns.add<ClockMuxLowering>(typeConverter, context);
705 patterns.add<ClockDividerLowering>(typeConverter, context);
706 patterns.add<ClockConstLowering>(typeConverter, context);
708 patterns.add<AggregateConstantPattern>(typeConverter, context);
710 if (failed(applyPartialConversion(circuit, target, std::move(
patterns))))
713 auto loc = UnknownLoc::get(context);
714 auto b = ImplicitLocOpBuilder::atBlockBegin(loc, circuit.getBody());
715 if (needsRegRandomization || needsMemRandomization) {
716 b.create<sv::MacroDeclOp>(
"ENABLE_INITIAL_REG_");
717 b.create<sv::MacroDeclOp>(
"ENABLE_INITIAL_MEM_");
718 if (needsRegRandomization) {
719 b.create<sv::MacroDeclOp>(
"FIRRTL_BEFORE_INITIAL");
720 b.create<sv::MacroDeclOp>(
"FIRRTL_AFTER_INITIAL");
722 if (needsMemRandomization)
723 b.create<sv::MacroDeclOp>(
"RANDOMIZE_MEM_INIT");
724 b.create<sv::MacroDeclOp>(
"RANDOMIZE_REG_INIT");
725 b.create<sv::MacroDeclOp>(
"RANDOMIZE");
726 b.create<sv::MacroDeclOp>(
"RANDOMIZE_DELAY");
727 b.create<sv::MacroDeclOp>(
"RANDOM");
728 b.create<sv::MacroDeclOp>(
"INIT_RANDOM");
729 b.create<sv::MacroDeclOp>(
"INIT_RANDOM_PROLOG_");
732 bool hasRegRandomization = needsRegRandomization && !disableRegRandomization;
733 bool hasMemRandomization = needsMemRandomization && !disableMemRandomization;
734 if (!hasRegRandomization && !hasMemRandomization)
739 for (Operation &op : *circuit.getBody()) {
740 if (!isa<sv::VerbatimOp, sv::IfDefOp>(&op)) {
741 b.setInsertionPoint(&op);
749 for (
auto sym : circuit.getOps<sv::MacroDeclOp>())
750 symbols.insert(sym.getName());
751 if (!symbols.count(
"SYNTHESIS"))
752 b.create<sv::MacroDeclOp>(
"SYNTHESIS");
753 if (!symbols.count(
"VERILATOR"))
754 b.create<sv::MacroDeclOp>(
"VERILATOR");
759 auto emitGuardedDefine = [&](StringRef guard, StringRef defName,
760 StringRef defineTrue =
"",
761 StringRef defineFalse = StringRef()) {
762 if (!defineFalse.data()) {
763 assert(defineTrue.data() &&
"didn't define anything");
765 guard, [&]() { b.create<sv::MacroDefOp>(defName, defineTrue); });
770 if (defineTrue.data())
771 b.create<sv::MacroDefOp>(defName, defineTrue);
773 [&]() { b.create<sv::MacroDefOp>(defName, defineFalse); });
778 auto emitGuard = [&](
const char *guard, llvm::function_ref<void(
void)> body) {
780 guard, []() {}, body);
783 b.create<emit::FragmentOp>(randomInitFragmentName.getAttr(), [&] {
784 b.create<sv::VerbatimOp>(
785 "// Standard header to adapt well known macros for "
786 "register randomization.");
788 b.create<sv::VerbatimOp>(
789 "\n// RANDOM may be set to an expression that produces a 32-bit "
790 "random unsigned value.");
791 emitGuardedDefine(
"RANDOM",
"RANDOM", StringRef(),
"$random");
793 b.create<sv::VerbatimOp>(
794 "\n// Users can define INIT_RANDOM as general code that gets "
796 "into the\n// initializer block for modules with registers.");
797 emitGuardedDefine(
"INIT_RANDOM",
"INIT_RANDOM", StringRef(),
"");
799 b.create<sv::VerbatimOp>(
800 "\n// If using random initialization, you can also define "
801 "RANDOMIZE_DELAY to\n// customize the delay used, otherwise 0.002 "
803 emitGuardedDefine(
"RANDOMIZE_DELAY",
"RANDOMIZE_DELAY", StringRef(),
806 b.create<sv::VerbatimOp>(
807 "\n// Define INIT_RANDOM_PROLOG_ for use in our modules below.");
808 emitGuard(
"INIT_RANDOM_PROLOG_", [&]() {
812 emitGuardedDefine(
"VERILATOR",
"INIT_RANDOM_PROLOG_",
814 "`INIT_RANDOM #`RANDOMIZE_DELAY begin end");
816 [&]() { b.create<sv::MacroDefOp>(
"INIT_RANDOM_PROLOG_",
""); });
820 if (hasMemRandomization) {
821 b.create<emit::FragmentOp>(randomInitMemFragmentName.getAttr(), [&] {
822 b.create<sv::VerbatimOp>(
"\n// Include rmemory initializers in init "
823 "blocks unless synthesis is set");
824 emitGuard(
"RANDOMIZE", [&]() {
825 emitGuardedDefine(
"RANDOMIZE_MEM_INIT",
"RANDOMIZE");
827 emitGuard(
"SYNTHESIS", [&] {
828 emitGuardedDefine(
"ENABLE_INITIAL_MEM_",
"ENABLE_INITIAL_MEM_",
831 b.create<sv::VerbatimOp>(
"");
835 if (hasRegRandomization) {
836 b.create<emit::FragmentOp>(randomInitRegFragmentName.getAttr(), [&] {
837 b.create<sv::VerbatimOp>(
"\n// Include register initializers in init "
838 "blocks unless synthesis is set");
839 emitGuard(
"RANDOMIZE", [&]() {
840 emitGuardedDefine(
"RANDOMIZE_REG_INIT",
"RANDOMIZE");
842 emitGuard(
"SYNTHESIS", [&] {
843 emitGuardedDefine(
"ENABLE_INITIAL_REG_",
"ENABLE_INITIAL_REG_",
846 b.create<sv::VerbatimOp>(
"");
853 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
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...