13 #include "mlir/IR/ImplicitLocOpBuilder.h"
17 #define GEN_PASS_DEF_EXTERNALIZECLOCKGATE
18 #include "circt/Dialect/Seq/SeqPasses.h.inc"
22 using namespace circt;
27 struct ExternalizeClockGatePass
28 :
public impl::ExternalizeClockGateBase<ExternalizeClockGatePass> {
29 using ExternalizeClockGateBase<
30 ExternalizeClockGatePass>::ExternalizeClockGateBase;
31 void runOnOperation()
override;
35 void ExternalizeClockGatePass::runOnOperation() {
36 SymbolTable &symtbl = getAnalysis<SymbolTable>();
39 DenseMap<HWModuleOp, SmallVector<ClockGateOp>> gatesInModule;
40 for (
auto module : getOperation().getOps<HWModuleOp>()) {
41 module.walk([&](ClockGateOp op) { gatesInModule[module].push_back(op); });
44 if (gatesInModule.empty()) {
45 markAllAnalysesPreserved();
50 auto builder = OpBuilder::atBlockBegin(getOperation().getBody());
51 auto i1Type =
builder.getI1Type();
53 SmallVector<PortInfo, 4> modulePorts;
54 modulePorts.push_back({{
builder.getStringAttr(inputName), i1Type,
56 modulePorts.push_back({{
builder.getStringAttr(outputName), i1Type,
58 modulePorts.push_back({{
builder.getStringAttr(enableName), i1Type,
60 bool hasTestEnable = !testEnableName.empty();
62 modulePorts.push_back({{
builder.getStringAttr(testEnableName), i1Type,
66 getOperation().getLoc(),
builder.getStringAttr(moduleName), modulePorts,
68 symtbl.insert(externModuleOp);
71 SmallVector<Value, 4> instPorts;
72 for (
auto &[module, clockGatesToReplace] : gatesInModule) {
73 DenseMap<Value, Value> fromClocks;
75 for (
auto ckgOp : clockGatesToReplace) {
76 ImplicitLocOpBuilder
builder(ckgOp.getLoc(), ckgOp);
78 Value enable = ckgOp.getEnable();
79 Value testEnable = ckgOp.getTestEnable();
83 if (hasTestEnable && !testEnable) {
87 testEnable = cstFalse;
92 if (!hasTestEnable && testEnable) {
97 Value input = ckgOp.getInput();
98 if (hw::type_isa<seq::ClockType>(input.getType())) {
99 auto it = fromClocks.try_emplace(input, Value{});
101 ImplicitLocOpBuilder
builder(input.getLoc(), &getContext());
102 builder.setInsertionPointAfterValue(input);
103 it.first->second =
builder.create<seq::FromClockOp>(input);
105 instPorts.push_back(it.first->second);
107 instPorts.push_back(input);
109 instPorts.push_back(enable);
111 instPorts.push_back(testEnable);
113 auto instOp =
builder.create<InstanceOp>(
114 externModuleOp,
builder.getStringAttr(instName), instPorts,
115 builder.getArrayAttr({}), ckgOp.getInnerSymAttr());
117 Value output = instOp.getResult(0);
118 if (hw::type_isa<seq::ClockType>(input.getType()))
119 output =
builder.create<seq::ToClockOp>(output);
120 ckgOp.replaceAllUsesWith(output);
124 ++numClockGatesConverted;
130 const ExternalizeClockGateOptions &options) {
131 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.