16 #include "mlir/IR/ImplicitLocOpBuilder.h"
17 #include "mlir/Pass/Pass.h"
18 #include "llvm/Support/Debug.h"
21 #define DEBUG_TYPE "arc-strip-sv"
25 #define GEN_PASS_DEF_STRIPSV
26 #include "circt/Dialect/Arc/ArcPasses.h.inc"
30 using namespace circt;
34 struct StripSVPass :
public arc::impl::StripSVBase<StripSVPass> {
35 void runOnOperation()
override;
36 SmallVector<Operation *> opsToDelete;
37 SmallPtrSet<StringAttr, 4> clockGateModuleNames;
41 void StripSVPass::runOnOperation() {
42 auto mlirModule = getOperation();
44 clockGateModuleNames.clear();
46 auto expectedClockGateInputs =
50 auto expectedClockGateOutputs =
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 for (
auto &op : llvm::make_early_inc_range(*mlirModule.getBody()))
81 if (isa<emit::EmitDialect, om::OMDialect>(op.getDialect()))
85 mlirModule.walk([](Operation *op) {
86 auto isSVAttr = [](NamedAttribute attr) {
87 return attr.getName().getValue().starts_with(
"sv.");
89 if (llvm::any_of(op->getAttrs(), isSVAttr)) {
90 SmallVector<NamedAttribute> newAttrs;
91 newAttrs.reserve(op->getAttrs().size());
92 for (
auto attr : op->getAttrs())
94 newAttrs.push_back(attr);
95 op->setAttrs(newAttrs);
100 for (
auto verb : mlirModule.getOps<sv::VerbatimOp>())
101 opsToDelete.push_back(verb);
103 opsToDelete.push_back(verb);
104 for (
auto verb : mlirModule.getOps<sv::MacroDeclOp>())
105 opsToDelete.push_back(verb);
108 for (Operation &op : *module.getBodyBlock()) {
110 if (isa<sv::IfDefOp, sv::CoverOp, sv::CoverConcurrentOp>(&op)) {
111 opsToDelete.push_back(&op);
114 if (isa<sv::VerbatimOp, sv::AlwaysOp>(&op)) {
115 opsToDelete.push_back(&op);
120 if (
auto assign = dyn_cast<sv::AssignOp>(&op)) {
121 auto wire = assign.getDest().getDefiningOp<
sv::WireOp>();
123 assign.emitOpError(
"expected wire lhs");
124 return signalPassFailure();
126 for (Operation *user : wire->getUsers()) {
129 auto readInout = dyn_cast<sv::ReadInOutOp>(user);
131 user->emitOpError(
"has user that is not `sv.read_inout`");
132 return signalPassFailure();
134 readInout.replaceAllUsesWith(assign.getSrc());
135 opsToDelete.push_back(readInout);
137 opsToDelete.push_back(assign);
138 opsToDelete.push_back(wire);
143 if (
auto reg = dyn_cast<seq::FirRegOp>(&op)) {
144 OpBuilder builder(
reg);
149 reg.getResetValue(),
reg.getNext(),
152 next =
reg.getNext();
156 if (
reg.getPreset() && !
reg.getPreset()->isZero()) {
157 assert(hw::type_isa<IntegerType>(
reg.getType()) &&
158 "cannot lower non integer preset");
160 builder,
reg.getLoc(),
165 reg.getLoc(), next.getType(), next,
reg.getClk(),
reg.getNameAttr(),
166 Value{}, Value{}, presetValue,
167 reg.getInnerSymAttr());
168 reg.replaceAllUsesWith(compReg);
169 opsToDelete.push_back(
reg);
175 if (
auto instOp = dyn_cast<hw::InstanceOp>(&op)) {
176 auto modName = instOp.getModuleNameAttr().getAttr();
177 ImplicitLocOpBuilder builder(instOp.getLoc(), instOp);
178 if (clockGateModuleNames.contains(modName)) {
179 auto gated = builder.create<seq::ClockGateOp>(
180 instOp.getOperand(0), instOp.getOperand(1), instOp.getOperand(2),
182 instOp.replaceAllUsesWith(gated);
183 opsToDelete.push_back(instOp);
189 for (
auto *op : opsToDelete)
194 return std::make_unique<StripSVPass>();
assert(baseType &&"element must be base type")
std::unique_ptr< mlir::Pass > createStripSVPass()
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
mlir::TypedValue< seq::ImmutableType > createConstantInitialValue(OpBuilder builder, Location loc, mlir::IntegerAttr attr)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)