13 #include "mlir/IR/ImplicitLocOpBuilder.h"
14 #include "mlir/Pass/Pass.h"
18 #define GEN_PASS_DEF_EXTERNALIZECLOCKGATE
19 #include "circt/Dialect/Seq/SeqPasses.h.inc"
23 using namespace circt;
28 struct ExternalizeClockGatePass
29 :
public circt::seq::impl::ExternalizeClockGateBase<
30 ExternalizeClockGatePass> {
31 using ExternalizeClockGateBase<
32 ExternalizeClockGatePass>::ExternalizeClockGateBase;
33 void runOnOperation()
override;
37 void ExternalizeClockGatePass::runOnOperation() {
38 SymbolTable &symtbl = getAnalysis<SymbolTable>();
41 DenseMap<HWModuleOp, SmallVector<ClockGateOp>> gatesInModule;
42 for (
auto module : getOperation().getOps<HWModuleOp>()) {
43 module.walk([&](ClockGateOp op) { gatesInModule[module].push_back(op); });
46 if (gatesInModule.empty()) {
47 markAllAnalysesPreserved();
52 auto builder = OpBuilder::atBlockBegin(getOperation().getBody());
53 auto i1Type = builder.getI1Type();
55 SmallVector<PortInfo, 4> modulePorts;
56 modulePorts.push_back({{builder.getStringAttr(inputName), i1Type,
58 modulePorts.push_back({{builder.getStringAttr(outputName), i1Type,
60 modulePorts.push_back({{builder.getStringAttr(enableName), i1Type,
62 bool hasTestEnable = !testEnableName.empty();
64 modulePorts.push_back({{builder.getStringAttr(testEnableName), i1Type,
68 getOperation().getLoc(), builder.getStringAttr(moduleName), modulePorts,
70 symtbl.insert(externModuleOp);
73 SmallVector<Value, 4> instPorts;
74 for (
auto &[module, clockGatesToReplace] : gatesInModule) {
75 DenseMap<Value, Value> fromClocks;
77 for (
auto ckgOp : clockGatesToReplace) {
78 ImplicitLocOpBuilder builder(ckgOp.getLoc(), ckgOp);
80 Value enable = ckgOp.getEnable();
81 Value testEnable = ckgOp.getTestEnable();
85 if (hasTestEnable && !testEnable) {
87 cstFalse = builder.create<
ConstantOp>(i1Type, 0);
89 testEnable = cstFalse;
94 if (!hasTestEnable && testEnable) {
95 enable = builder.createOrFold<
comb::OrOp>(enable, testEnable,
true);
99 Value input = ckgOp.getInput();
100 if (hw::type_isa<seq::ClockType>(input.getType())) {
101 auto it = fromClocks.try_emplace(input, Value{});
103 ImplicitLocOpBuilder builder(input.getLoc(), &getContext());
104 builder.setInsertionPointAfterValue(input);
105 it.first->second = builder.create<seq::FromClockOp>(input);
107 instPorts.push_back(it.first->second);
109 instPorts.push_back(input);
111 instPorts.push_back(enable);
113 instPorts.push_back(testEnable);
115 auto instOp = builder.create<InstanceOp>(
116 externModuleOp, builder.getStringAttr(instName), instPorts,
117 builder.getArrayAttr({}), ckgOp.getInnerSymAttr());
119 Value output = instOp.getResult(0);
120 if (hw::type_isa<seq::ClockType>(input.getType()))
121 output = builder.create<seq::ToClockOp>(output);
122 ckgOp.replaceAllUsesWith(output);
126 ++numClockGatesConverted;
132 const ExternalizeClockGateOptions &options) {
133 return std::make_unique<ExternalizeClockGatePass>(options);
std::unique_ptr< mlir::Pass > createExternalizeClockGatePass(const ExternalizeClockGateOptions &options={})
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.