15#include "mlir/IR/ImplicitLocOpBuilder.h"
16#include "mlir/Pass/Pass.h"
17#include "llvm/Support/Debug.h"
20#define DEBUG_TYPE "arc-strip-sv"
24#define GEN_PASS_DEF_STRIPSV
25#include "circt/Dialect/Arc/ArcPasses.h.inc"
33struct StripSVPass :
public arc::impl::StripSVBase<StripSVPass> {
35 void runOnOperation()
override;
36 SmallVector<Operation *> opsToDelete;
37 SmallPtrSet<StringAttr, 4> clockGateModuleNames;
41void StripSVPass::runOnOperation() {
42 auto mlirModule = getOperation();
44 clockGateModuleNames.clear();
46 auto expectedClockGateInputs =
47 ArrayAttr::get(&getContext(), {StringAttr::get(&getContext(),
"in"),
48 StringAttr::get(&getContext(),
"test_en"),
49 StringAttr::get(&getContext(),
"en")});
50 auto expectedClockGateOutputs =
51 ArrayAttr::get(&getContext(), {StringAttr::get(&getContext(),
"out")});
52 auto i1Type = IntegerType::get(&getContext(), 1);
54 for (
auto extModOp : mlirModule.getOps<
hw::HWModuleExternOp>()) {
55 if (extModOp.getVerilogModuleName() ==
"EICG_wrapper") {
56 if (!llvm::equal(extModOp.getInputNames(), expectedClockGateInputs) ||
57 !llvm::equal(extModOp.getOutputNames(), expectedClockGateOutputs)) {
58 extModOp.emitError(
"clock gate module `")
59 << extModOp.getModuleName() <<
"` has incompatible port names "
60 << extModOp.getInputNames() <<
" -> " << extModOp.getOutputNames();
61 return signalPassFailure();
63 if (!llvm::equal(extModOp.getInputTypes(),
64 ArrayRef<Type>{i1Type, i1Type, i1Type}) ||
65 !llvm::equal(extModOp.getOutputTypes(), ArrayRef<Type>{i1Type})) {
66 extModOp.emitError(
"clock gate module `")
67 << extModOp.getModuleName() <<
"` has incompatible port types "
68 << extModOp.getInputTypes() <<
" -> " << extModOp.getOutputTypes();
69 return signalPassFailure();
71 clockGateModuleNames.insert(extModOp.getModuleNameAttr());
72 opsToDelete.push_back(extModOp);
76 LLVM_DEBUG(llvm::dbgs() <<
"Found " << clockGateModuleNames.size()
80 mlirModule.walk([](Operation *op) {
81 auto isSVAttr = [](NamedAttribute attr) {
82 return attr.getName().getValue().starts_with(
"sv.");
84 if (llvm::any_of(op->getAttrs(), isSVAttr)) {
85 SmallVector<NamedAttribute> newAttrs;
86 newAttrs.reserve(op->getAttrs().size());
87 for (
auto attr : op->getAttrs())
89 newAttrs.push_back(attr);
90 op->setAttrs(newAttrs);
95 for (
auto verb : mlirModule.getOps<
sv::VerbatimOp>())
96 opsToDelete.push_back(verb);
97 for (
auto verb : mlirModule.getOps<
sv::IfDefOp>())
98 opsToDelete.push_back(verb);
99 for (
auto verb : mlirModule.getOps<
sv::MacroDeclOp>())
100 opsToDelete.push_back(verb);
102 mlirModule.walk([&](sv::MacroRefExprOp macroRef) {
103 StringRef macroName = macroRef.getMacroName();
104 bool isConditionMacro = macroName ==
"STOP_COND_" ||
105 macroName ==
"PRINTF_COND_" ||
106 macroName ==
"ASSERT_VERBOSE_COND_";
108 if (macroRef.getType().isInteger(1) && isConditionMacro) {
109 OpBuilder builder(macroRef);
110 auto trueConst = hw::ConstantOp::create(builder, macroRef.getLoc(),
111 builder.getI1Type(), 1);
113 macroRef.replaceAllUsesWith(trueConst->getResult(0));
114 opsToDelete.push_back(macroRef);
118 for (
auto module : mlirModule.getOps<
hw::HWModuleOp>()) {
121 if (isa<sv::IfDefOp, sv::CoverOp, sv::CoverConcurrentOp>(&op)) {
122 opsToDelete.push_back(&op);
125 if (isa<sv::VerbatimOp, sv::AlwaysOp>(&op)) {
126 opsToDelete.push_back(&op);
131 if (
auto assign = dyn_cast<sv::AssignOp>(&op)) {
132 auto wire = assign.getDest().getDefiningOp<
sv::WireOp>();
134 assign.emitOpError(
"expected wire lhs");
135 return signalPassFailure();
137 for (Operation *user : wire->getUsers()) {
140 auto readInout = dyn_cast<sv::ReadInOutOp>(user);
142 user->emitOpError(
"has user that is not `sv.read_inout`");
143 return signalPassFailure();
145 readInout.replaceAllUsesWith(assign.getSrc());
146 opsToDelete.push_back(readInout);
148 opsToDelete.push_back(assign);
149 opsToDelete.push_back(wire);
154 if (
auto reg = dyn_cast<seq::FirRegOp>(&op)) {
155 OpBuilder builder(reg);
157 if (
reg.getIsAsync() && !asyncResetsAsSync) {
158 reg.emitOpError(
"only synchronous resets are currently supported");
159 return signalPassFailure();
164 if (
reg.getPreset() && !
reg.getPreset()->isZero()) {
165 assert(hw::type_isa<IntegerType>(
reg.getType()) &&
166 "cannot lower non integer preset");
168 builder,
reg.getLoc(),
169 IntegerAttr::get(
reg.getType(), *
reg.getPreset()));
173 builder,
reg.getLoc(),
reg.getType(),
reg.getNext(),
reg.getClk(),
174 reg.getNameAttr(),
reg.getReset(),
reg.getResetValue(),
175 presetValue,
reg.getInnerSymAttr());
176 reg.replaceAllUsesWith(compReg);
177 opsToDelete.push_back(reg);
183 if (
auto instOp = dyn_cast<hw::InstanceOp>(&op)) {
184 auto modName = instOp.getModuleNameAttr().getAttr();
185 ImplicitLocOpBuilder builder(instOp.getLoc(), instOp);
186 if (clockGateModuleNames.contains(modName)) {
187 auto gated = seq::ClockGateOp::create(
188 builder, instOp.getOperand(0), instOp.getOperand(1),
189 instOp.getOperand(2), hw::InnerSymAttr{});
190 instOp.replaceAllUsesWith(gated);
191 opsToDelete.push_back(instOp);
197 if (
auto hbr = dyn_cast<verif::HasBeenResetOp>(&op)) {
198 OpBuilder builder(hbr);
200 if (hbr.getAsync() && !asyncResetsAsSync) {
201 hbr.emitOpError(
"has async reset, but only sync resets supported");
202 return signalPassFailure();
206 seq::ToClockOp::create(builder, hbr.getLoc(), hbr.getClock());
208 builder, hbr.getLoc(), builder.getBoolAttr(
false));
212 StringAttr{}, hbr.getReset(), one,
213 initial, hw::InnerSymAttr{});
214 reg.getInputMutable().assign(reg);
216 comb::createOrFoldNot(builder, hbr.getLoc(), hbr.getReset());
218 comb::AndOp::create(builder, hbr.getLoc(), reg, notReset,
true);
219 hbr.getResult().replaceAllUsesWith(masked);
220 opsToDelete.push_back(hbr);
225 for (
auto *op : opsToDelete)
assert(baseType &&"element must be base type")
static Block * getBodyBlock(FModuleLike mod)
create(cls, result_type, reset=None, reset_value=None, name=None, sym_name=None, **kwargs)
mlir::TypedValue< seq::ImmutableType > createConstantInitialValue(OpBuilder builder, Location loc, mlir::IntegerAttr attr)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)