26 #include "mlir/Analysis/TopologicalSortUtils.h"
27 #include "mlir/IR/Builders.h"
28 #include "mlir/IR/DialectImplementation.h"
29 #include "mlir/IR/ImplicitLocOpBuilder.h"
30 #include "mlir/IR/Threading.h"
31 #include "mlir/Pass/Pass.h"
32 #include "mlir/Transforms/DialectConversion.h"
33 #include "llvm/ADT/IntervalMap.h"
34 #include "llvm/ADT/TypeSwitch.h"
35 #include "llvm/Support/Mutex.h"
37 #define DEBUG_TYPE "lower-seq-to-sv"
39 using namespace circt;
42 using llvm::MapVector;
45 #define GEN_PASS_DEF_LOWERSEQTOSV
46 #include "circt/Conversion/Passes.h.inc"
48 struct SeqToSVPass :
public impl::LowerSeqToSVBase<SeqToSVPass> {
50 void runOnOperation()
override;
52 using LowerSeqToSVBase<SeqToSVPass>::lowerToAlwaysFF;
53 using LowerSeqToSVBase<SeqToSVPass>::disableRegRandomization;
54 using LowerSeqToSVBase<SeqToSVPass>::emitSeparateAlwaysBlocks;
55 using LowerSeqToSVBase<SeqToSVPass>::LowerSeqToSVBase;
56 using LowerSeqToSVBase<SeqToSVPass>::numSubaccessRestored;
61 struct ModuleLoweringState {
63 : immutableValueLowering(module), module(module) {}
65 struct ImmutableValueLowering {
69 LogicalResult lower();
70 LogicalResult lower(seq::InitialOp initialOp);
73 lookupImmutableValue(mlir::TypedValue<seq::ImmutableType> immut)
const {
74 return mapping.lookup(immut);
77 sv::InitialOp getSVInitial()
const {
return svInitialOp; }
80 sv::InitialOp svInitialOp = {};
83 MapVector<mlir::TypedValue<seq::ImmutableType>, Value> mapping;
86 } immutableValueLowering;
89 bool needsRegFragment =
false;
90 bool needsMemFragment =
false;
96 LogicalResult ModuleLoweringState::ImmutableValueLowering::lower() {
101 auto initialOp = *result;
105 return lower(initialOp);
109 ModuleLoweringState::ImmutableValueLowering::lower(seq::InitialOp initialOp) {
110 OpBuilder builder = OpBuilder::atBlockBegin(module.getBodyBlock());
112 svInitialOp = builder.create<sv::InitialOp>(initialOp->getLoc());
114 assert(initialOp.getNumOperands() == 0 &&
115 "initial op should have no operands");
117 auto loc = initialOp.getLoc();
118 llvm::SmallVector<Value> results;
120 auto yieldOp = cast<seq::YieldOp>(initialOp.getBodyBlock()->getTerminator());
122 for (
auto [result, operand] :
123 llvm::zip(initialOp.getResults(), yieldOp->getOperands())) {
126 .create<mlir::UnrealizedConversionCastOp>(
127 loc, ArrayRef<Type>{result.getType()}, ArrayRef<Value>{})
129 result.replaceAllUsesWith(placeholder);
131 {cast<mlir::TypedValue<seq ::ImmutableType>>(placeholder), operand});
134 svInitialOp.getBodyBlock()->getOperations().splice(
135 svInitialOp.end(), initialOp.getBodyBlock()->getOperations());
137 assert(initialOp->use_empty());
145 template <
typename OpTy>
149 TypeConverter &typeConverter, MLIRContext *context,
bool lowerToAlwaysFF,
150 const MapVector<StringAttr, ModuleLoweringState> &moduleLoweringStates)
152 lowerToAlwaysFF(lowerToAlwaysFF),
153 moduleLoweringStates(moduleLoweringStates) {}
158 matchAndRewrite(OpTy
reg, OpAdaptor adaptor,
159 ConversionPatternRewriter &rewriter)
const final {
160 Location loc =
reg.getLoc();
163 ConversionPattern::getTypeConverter()->convertType(
reg.getType());
164 auto svReg = rewriter.create<
sv::RegOp>(loc, regTy,
reg.getNameAttr(),
165 reg.getInnerSymAttr());
167 svReg->setDialectAttrs(
reg->getDialectAttrs());
173 auto assignValue = [&] {
174 createAssign(rewriter,
reg.getLoc(), svReg,
reg);
176 auto assignReset = [&] {
177 rewriter.create<sv::PAssignOp>(loc, svReg, adaptor.getResetValue());
183 bool mayLowerToAlwaysFF = lowerToAlwaysFF && !
reg.getInitialValue();
185 if (adaptor.getReset() && adaptor.getResetValue()) {
186 if (mayLowerToAlwaysFF) {
187 rewriter.create<sv::AlwaysFFOp>(
188 loc, sv::EventControl::AtPosEdge, adaptor.getClk(),
189 sv::ResetType::SyncReset, sv::EventControl::AtPosEdge,
190 adaptor.getReset(), assignValue, assignReset);
192 rewriter.create<sv::AlwaysOp>(
193 loc, sv::EventControl::AtPosEdge, adaptor.getClk(), [&] {
194 rewriter.create<sv::IfOp>(loc, adaptor.getReset(), assignReset,
199 if (mayLowerToAlwaysFF) {
200 rewriter.create<sv::AlwaysFFOp>(loc, sv::EventControl::AtPosEdge,
201 adaptor.getClk(), assignValue);
203 rewriter.create<sv::AlwaysOp>(loc, sv::EventControl::AtPosEdge,
204 adaptor.getClk(), assignValue);
209 if (
auto init =
reg.getInitialValue()) {
210 auto module =
reg->template getParentOfType<hw::HWModuleOp>();
211 const auto &initial =
212 moduleLoweringStates.find(module.getModuleNameAttr())
213 ->second.immutableValueLowering;
215 Value initialValue = initial.lookupImmutableValue(init);
217 if (
auto op = initialValue.getDefiningOp();
218 op && op->hasTrait<mlir::OpTrait::ConstantLike>()) {
219 auto clonedConstant = rewriter.clone(*op);
220 rewriter.moveOpBefore(clonedConstant, svReg);
221 svReg.getInitMutable().assign(clonedConstant->getResult(0));
223 OpBuilder::InsertionGuard guard(rewriter);
224 auto in = initial.getSVInitial();
225 rewriter.setInsertionPointToEnd(in.getBodyBlock());
226 rewriter.create<sv::BPAssignOp>(
reg->getLoc(), svReg, initialValue);
230 rewriter.replaceOp(
reg, regVal);
235 void createAssign(ConversionPatternRewriter &rewriter, Location loc,
239 bool lowerToAlwaysFF;
240 const MapVector<StringAttr, ModuleLoweringState> &moduleLoweringStates;
245 void CompRegLower<CompRegOp>::createAssign(ConversionPatternRewriter &rewriter,
247 OpAdaptor
reg)
const {
248 rewriter.create<sv::PAssignOp>(loc, svReg,
reg.getInput());
252 void CompRegLower<CompRegClockEnabledOp>::createAssign(
253 ConversionPatternRewriter &rewriter, Location loc,
sv::RegOp svReg,
254 OpAdaptor
reg)
const {
255 rewriter.create<sv::IfOp>(loc,
reg.getClockEnable(), [&]() {
256 rewriter.create<sv::PAssignOp>(loc, svReg,
reg.getInput());
263 FromImmutableLowering(
264 TypeConverter &typeConverter, MLIRContext *context,
265 const MapVector<StringAttr, ModuleLoweringState> &moduleLoweringStates)
267 moduleLoweringStates(moduleLoweringStates) {}
272 matchAndRewrite(FromImmutableOp fromImmutableOp, OpAdaptor adaptor,
273 ConversionPatternRewriter &rewriter)
const final {
274 Location loc = fromImmutableOp.getLoc();
276 auto regTy = ConversionPattern::getTypeConverter()->convertType(
277 fromImmutableOp.getType());
278 auto svReg = rewriter.create<
sv::RegOp>(loc, regTy);
283 auto module = fromImmutableOp->template getParentOfType<hw::HWModuleOp>();
284 const auto &initial = moduleLoweringStates.find(module.getModuleNameAttr())
285 ->second.immutableValueLowering;
288 initial.lookupImmutableValue(fromImmutableOp.getInput());
290 OpBuilder::InsertionGuard guard(rewriter);
291 auto in = initial.getSVInitial();
292 rewriter.setInsertionPointToEnd(in.getBodyBlock());
293 rewriter.create<sv::BPAssignOp>(fromImmutableOp->getLoc(), svReg,
296 rewriter.replaceOp(fromImmutableOp, regVal);
301 const MapVector<StringAttr, ModuleLoweringState> &moduleLoweringStates;
310 matchAndRewrite(ClockGateOp clockGate, OpAdaptor adaptor,
311 ConversionPatternRewriter &rewriter)
const final {
312 auto loc = clockGate.getLoc();
313 Value
clk = adaptor.getInput();
316 Value enable = adaptor.getEnable();
317 if (
auto te = adaptor.getTestEnable())
318 enable = rewriter.create<
comb::OrOp>(loc, enable, te);
321 Value enableLatch = rewriter.create<
sv::RegOp>(
322 loc, rewriter.getI1Type(), rewriter.getStringAttr(
"cg_en_latch"));
325 rewriter.create<sv::AlwaysOp>(
326 loc, llvm::SmallVector<sv::EventControl>{}, llvm::SmallVector<Value>{},
328 rewriter.create<sv::IfOp>(
330 rewriter.create<sv::PAssignOp>(loc, enableLatch, enable);
348 matchAndRewrite(ClockInverterOp op, OpAdaptor adaptor,
349 ConversionPatternRewriter &rewriter)
const final {
350 auto loc = op.getLoc();
351 Value
clk = adaptor.getInput();
353 StringAttr name = op->getAttrOfType<StringAttr>(
"sv.namehint");
355 auto newOp = rewriter.replaceOpWithNewOp<
comb::XorOp>(op,
clk, one);
357 rewriter.modifyOpInPlace(newOp,
358 [&] { newOp->setAttr(
"sv.namehint", name); });
371 matchAndRewrite(ClockMuxOp clockMux, OpAdaptor adaptor,
372 ConversionPatternRewriter &rewriter)
const final {
373 rewriter.replaceOpWithNewOp<
comb::MuxOp>(clockMux, adaptor.getCond(),
374 adaptor.getTrueClock(),
375 adaptor.getFalseClock(),
true);
381 struct SeqToSVTypeConverter :
public TypeConverter {
382 SeqToSVTypeConverter() {
383 addConversion([&](Type type) {
return type; });
384 addConversion([&](seq::ImmutableType type) {
return type.getInnerType(); });
385 addConversion([&](seq::ClockType type) {
388 addConversion([&](hw::StructType structTy) {
389 bool changed =
false;
391 SmallVector<hw::StructType::FieldInfo> newFields;
392 for (
auto field : structTy.getElements()) {
393 auto &newField = newFields.emplace_back();
394 newField.name = field.name;
395 newField.type = convertType(field.type);
396 if (field.type != newField.type)
405 addConversion([&](hw::ArrayType arrayTy) {
406 auto elementTy = arrayTy.getElementType();
408 if (elementTy != newElementTy)
413 addTargetMaterialization([&](mlir::OpBuilder &builder,
414 mlir::Type resultType, mlir::ValueRange inputs,
415 mlir::Location loc) -> mlir::Value {
416 if (inputs.size() != 1)
419 .create<mlir::UnrealizedConversionCastOp>(loc, resultType, inputs[0])
423 addSourceMaterialization([&](mlir::OpBuilder &builder,
424 mlir::Type resultType, mlir::ValueRange inputs,
425 mlir::Location loc) -> mlir::Value {
426 if (inputs.size() != 1)
429 .create<mlir::UnrealizedConversionCastOp>(loc, resultType, inputs[0])
436 template <
typename T>
442 matchAndRewrite(T op,
typename T::Adaptor adaptor,
443 ConversionPatternRewriter &rewriter)
const final {
445 if (Operation *inputOp = adaptor.getInput().getDefiningOp())
446 if (!isa<mlir::UnrealizedConversionCastOp>(inputOp))
448 rewriter.modifyOpInPlace(
449 inputOp, [&] { inputOp->setAttr(
"sv.namehint", name); });
451 rewriter.replaceOp(op, adaptor.getInput());
464 matchAndRewrite(ConstClockOp clockConst, OpAdaptor adaptor,
465 ConversionPatternRewriter &rewriter)
const final {
467 clockConst, APInt(1, clockConst.getValue() == ClockConst::High));
472 class AggregateConstantPattern
479 matchAndRewrite(hw::AggregateConstantOp aggregateConstant, OpAdaptor adaptor,
480 ConversionPatternRewriter &rewriter)
const final {
481 auto newType = typeConverter->convertType(aggregateConstant.getType());
482 auto newAttr = aggregateConstant.getFieldsAttr().replace(
483 [](seq::ClockConstAttr clockConst) {
486 APInt(1, clockConst.getValue() == ClockConst::High));
488 rewriter.replaceOpWithNewOp<hw::AggregateConstantOp>(
489 aggregateConstant, newType, cast<ArrayAttr>(newAttr));
502 matchAndRewrite(ClockDividerOp clockDiv, OpAdaptor adaptor,
503 ConversionPatternRewriter &rewriter)
const final {
504 Location loc = clockDiv.getLoc();
507 if (clockDiv.getPow2()) {
511 Value output = clockDiv.getInput();
513 SmallVector<Value> regs;
514 for (
unsigned i = 0; i < clockDiv.getPow2(); ++i) {
516 loc, rewriter.getI1Type(),
517 rewriter.getStringAttr(
"clock_out_" + std::to_string(i)));
520 rewriter.create<sv::AlwaysOp>(
521 loc, sv::EventControl::AtPosEdge, output, [&] {
524 rewriter.create<sv::BPAssignOp>(loc,
reg, inverted);
532 rewriter.
create<sv::InitialOp>(loc, [&] {
533 for (Value
reg : regs) {
534 rewriter.
create<sv::BPAssignOp>(loc,
reg, zero);
539 rewriter.replaceOp(clockDiv, output);
548 if (hw::type_isa<ClockType>(ty))
551 if (
auto arrayTy = hw::type_dyn_cast<hw::ArrayType>(ty))
554 if (
auto structTy = hw::type_dyn_cast<hw::StructType>(ty)) {
555 for (
auto field : structTy.getElements())
566 if (
auto module = dyn_cast<hw::HWModuleLike>(op)) {
567 for (
auto port : module.getHWModuleType().getPorts())
573 if (
auto hwAggregateConstantOp = dyn_cast<hw::AggregateConstantOp>(op)) {
574 bool foundClockAttr =
false;
575 hwAggregateConstantOp.getFieldsAttr().walk(
576 [&](seq::ClockConstAttr attr) { foundClockAttr =
true; });
581 bool allOperandsLowered = llvm::all_of(
582 op->getOperands(), [](
auto op) { return isLegalType(op.getType()); });
583 bool allResultsLowered = llvm::all_of(op->getResults(), [](
auto result) {
584 return isLegalType(result.getType());
586 return allOperandsLowered && allResultsLowered;
590 auto circuit = getOperation();
591 MLIRContext *context = &getContext();
593 auto modules = llvm::to_vector(circuit.getOps<
HWModuleOp>());
599 MapVector<HWModuleOp, SmallVector<FirMemLowering::MemoryConfig>> memsByModule;
600 for (
auto &[config, memOps] : uniqueMems) {
605 for (
auto memOp : memOps) {
606 auto parent = memOp->getParentOfType<
HWModuleOp>();
607 memsByModule[parent].emplace_back(&config, genOp, memOp);
612 std::atomic<bool> needsRegRandomization =
false;
613 std::atomic<bool> needsMemRandomization =
false;
615 MapVector<StringAttr, ModuleLoweringState> moduleLoweringStates;
616 for (
auto module : circuit.getOps<
HWModuleOp>())
617 moduleLoweringStates.try_emplace(module.getModuleNameAttr(),
618 ModuleLoweringState(module));
620 auto result = mlir::failableParallelForEach(
621 &getContext(), moduleLoweringStates, [&](
auto &moduleAndState) {
622 auto &state = moduleAndState.second;
623 auto module = state.module;
624 SeqToSVTypeConverter typeConverter;
626 disableRegRandomization,
627 emitSeparateAlwaysBlocks);
630 if (!disableRegRandomization) {
631 state.fragment.needsRegFragment =
true;
633 needsRegRandomization =
true;
637 if (
auto *it = memsByModule.find(module); it != memsByModule.end()) {
639 if (!disableMemRandomization) {
640 state.fragment.needsMemFragment =
true;
642 needsMemRandomization =
true;
644 return state.immutableValueLowering.lower();
648 return signalPassFailure();
650 auto randomInitFragmentName =
652 auto randomInitRegFragmentName =
654 auto randomInitMemFragmentName =
657 for (
auto &[_, state] : moduleLoweringStates) {
658 const auto &info = state.fragment;
659 if (!info.needsRegFragment && !info.needsMemFragment) {
664 SmallVector<Attribute> fragmentAttrs;
665 auto module = state.module;
668 fragmentAttrs = llvm::to_vector(others);
670 if (info.needsRegFragment)
671 fragmentAttrs.push_back(randomInitRegFragmentName);
672 if (info.needsMemFragment)
673 fragmentAttrs.push_back(randomInitMemFragmentName);
674 fragmentAttrs.push_back(randomInitFragmentName);
681 SeqToSVTypeConverter typeConverter;
682 ConversionTarget target(*context);
683 target.addIllegalDialect<SeqDialect>();
684 target.markUnknownOpDynamicallyLegal(
isLegalOp);
686 RewritePatternSet
patterns(context);
687 patterns.add<CompRegLower<CompRegOp>>(typeConverter, context, lowerToAlwaysFF,
688 moduleLoweringStates);
689 patterns.add<CompRegLower<CompRegClockEnabledOp>>(
690 typeConverter, context, lowerToAlwaysFF, moduleLoweringStates);
691 patterns.add<FromImmutableLowering>(typeConverter, context,
692 moduleLoweringStates);
693 patterns.add<ClockCastLowering<seq::FromClockOp>>(typeConverter, context);
694 patterns.add<ClockCastLowering<seq::ToClockOp>>(typeConverter, context);
695 patterns.add<ClockGateLowering>(typeConverter, context);
696 patterns.add<ClockInverterLowering>(typeConverter, context);
697 patterns.add<ClockMuxLowering>(typeConverter, context);
698 patterns.add<ClockDividerLowering>(typeConverter, context);
699 patterns.add<ClockConstLowering>(typeConverter, context);
701 patterns.add<AggregateConstantPattern>(typeConverter, context);
703 if (failed(applyPartialConversion(circuit, target, std::move(
patterns))))
707 auto b = ImplicitLocOpBuilder::atBlockBegin(loc, circuit.getBody());
708 if (needsRegRandomization || needsMemRandomization) {
709 b.create<sv::MacroDeclOp>(
"ENABLE_INITIAL_REG_");
710 b.create<sv::MacroDeclOp>(
"ENABLE_INITIAL_MEM_");
711 if (needsRegRandomization) {
712 b.create<sv::MacroDeclOp>(
"FIRRTL_BEFORE_INITIAL");
713 b.create<sv::MacroDeclOp>(
"FIRRTL_AFTER_INITIAL");
715 if (needsMemRandomization)
716 b.create<sv::MacroDeclOp>(
"RANDOMIZE_MEM_INIT");
717 b.create<sv::MacroDeclOp>(
"RANDOMIZE_REG_INIT");
718 b.create<sv::MacroDeclOp>(
"RANDOMIZE");
719 b.create<sv::MacroDeclOp>(
"RANDOMIZE_DELAY");
720 b.create<sv::MacroDeclOp>(
"RANDOM");
721 b.create<sv::MacroDeclOp>(
"INIT_RANDOM");
722 b.create<sv::MacroDeclOp>(
"INIT_RANDOM_PROLOG_");
725 bool hasRegRandomization = needsRegRandomization && !disableRegRandomization;
726 bool hasMemRandomization = needsMemRandomization && !disableMemRandomization;
727 if (!hasRegRandomization && !hasMemRandomization)
732 for (Operation &op : *circuit.getBody()) {
733 if (!isa<sv::VerbatimOp, sv::IfDefOp>(&op)) {
734 b.setInsertionPoint(&op);
742 for (
auto sym : circuit.getOps<sv::MacroDeclOp>())
743 symbols.insert(sym.getName());
744 if (!symbols.count(
"SYNTHESIS"))
745 b.create<sv::MacroDeclOp>(
"SYNTHESIS");
746 if (!symbols.count(
"VERILATOR"))
747 b.create<sv::MacroDeclOp>(
"VERILATOR");
752 auto emitGuardedDefine = [&](StringRef guard, StringRef defName,
753 StringRef defineTrue =
"",
754 StringRef defineFalse = StringRef()) {
755 if (!defineFalse.data()) {
756 assert(defineTrue.data() &&
"didn't define anything");
758 guard, [&]() { b.create<sv::MacroDefOp>(defName, defineTrue); });
763 if (defineTrue.data())
764 b.create<sv::MacroDefOp>(defName, defineTrue);
766 [&]() { b.create<sv::MacroDefOp>(defName, defineFalse); });
771 auto emitGuard = [&](
const char *guard, llvm::function_ref<void(
void)> body) {
773 guard, []() {}, body);
776 b.create<emit::FragmentOp>(randomInitFragmentName.getAttr(), [&] {
777 b.create<sv::VerbatimOp>(
778 "// Standard header to adapt well known macros for "
779 "register randomization.");
781 b.create<sv::VerbatimOp>(
782 "\n// RANDOM may be set to an expression that produces a 32-bit "
783 "random unsigned value.");
784 emitGuardedDefine(
"RANDOM",
"RANDOM", StringRef(),
"$random");
786 b.create<sv::VerbatimOp>(
787 "\n// Users can define INIT_RANDOM as general code that gets "
789 "into the\n// initializer block for modules with registers.");
790 emitGuardedDefine(
"INIT_RANDOM",
"INIT_RANDOM", StringRef(),
"");
792 b.create<sv::VerbatimOp>(
793 "\n// If using random initialization, you can also define "
794 "RANDOMIZE_DELAY to\n// customize the delay used, otherwise 0.002 "
796 emitGuardedDefine(
"RANDOMIZE_DELAY",
"RANDOMIZE_DELAY", StringRef(),
799 b.create<sv::VerbatimOp>(
800 "\n// Define INIT_RANDOM_PROLOG_ for use in our modules below.");
801 emitGuard(
"INIT_RANDOM_PROLOG_", [&]() {
805 emitGuardedDefine(
"VERILATOR",
"INIT_RANDOM_PROLOG_",
807 "`INIT_RANDOM #`RANDOMIZE_DELAY begin end");
809 [&]() { b.create<sv::MacroDefOp>(
"INIT_RANDOM_PROLOG_",
""); });
813 if (hasMemRandomization) {
814 b.create<emit::FragmentOp>(randomInitMemFragmentName.getAttr(), [&] {
815 b.create<sv::VerbatimOp>(
"\n// Include rmemory initializers in init "
816 "blocks unless synthesis is set");
817 emitGuard(
"RANDOMIZE", [&]() {
818 emitGuardedDefine(
"RANDOMIZE_MEM_INIT",
"RANDOMIZE");
820 emitGuard(
"SYNTHESIS", [&] {
821 emitGuardedDefine(
"ENABLE_INITIAL_MEM_",
"ENABLE_INITIAL_MEM_",
824 b.create<sv::VerbatimOp>(
"");
828 if (hasRegRandomization) {
829 b.create<emit::FragmentOp>(randomInitRegFragmentName.getAttr(), [&] {
830 b.create<sv::VerbatimOp>(
"\n// Include register initializers in init "
831 "blocks unless synthesis is set");
832 emitGuard(
"RANDOMIZE", [&]() {
833 emitGuardedDefine(
"RANDOMIZE_REG_INIT",
"RANDOMIZE");
835 emitGuard(
"SYNTHESIS", [&] {
836 emitGuardedDefine(
"ENABLE_INITIAL_REG_",
"ENABLE_INITIAL_REG_",
839 b.create<sv::VerbatimOp>(
"");
844 std::unique_ptr<Pass>
846 return std::make_unique<SeqToSVPass>(options);
assert(baseType &&"element must be base type")
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
def create(data_type, value)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Value createOrFoldNot(Location loc, Value value, OpBuilder &builder, bool twoState=false)
Create a `‘Not’' gate on a value.
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.
def 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...