CIRCT  19.0.0git
ExternalizeClockGate.cpp
Go to the documentation of this file.
1 //===- ExternalizeClockGate.cpp - Convert clock gate to extern module -----===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 #include "circt/Dialect/HW/HWOps.h"
13 #include "mlir/IR/ImplicitLocOpBuilder.h"
14 #include "mlir/Pass/Pass.h"
15 
16 namespace circt {
17 namespace seq {
18 #define GEN_PASS_DEF_EXTERNALIZECLOCKGATE
19 #include "circt/Dialect/Seq/SeqPasses.h.inc"
20 } // namespace seq
21 } // namespace circt
22 
23 using namespace circt;
24 using namespace seq;
25 using namespace hw;
26 
27 namespace {
28 struct ExternalizeClockGatePass
29  : public circt::seq::impl::ExternalizeClockGateBase<
30  ExternalizeClockGatePass> {
31  using ExternalizeClockGateBase<
32  ExternalizeClockGatePass>::ExternalizeClockGateBase;
33  void runOnOperation() override;
34 };
35 } // anonymous namespace
36 
37 void ExternalizeClockGatePass::runOnOperation() {
38  SymbolTable &symtbl = getAnalysis<SymbolTable>();
39 
40  // Collect all clock gate ops.
41  DenseMap<HWModuleOp, SmallVector<ClockGateOp>> gatesInModule;
42  for (auto module : getOperation().getOps<HWModuleOp>()) {
43  module.walk([&](ClockGateOp op) { gatesInModule[module].push_back(op); });
44  }
45 
46  if (gatesInModule.empty()) {
47  markAllAnalysesPreserved();
48  return;
49  }
50 
51  // Generate the external module declaration.
52  auto builder = OpBuilder::atBlockBegin(getOperation().getBody());
53  auto i1Type = builder.getI1Type();
54 
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();
63  if (hasTestEnable)
64  modulePorts.push_back({{builder.getStringAttr(testEnableName), i1Type,
66 
67  auto externModuleOp = builder.create<HWModuleExternOp>(
68  getOperation().getLoc(), builder.getStringAttr(moduleName), modulePorts,
69  moduleName);
70  symtbl.insert(externModuleOp);
71 
72  // Replace all clock gates with an instance of the external module.
73  SmallVector<Value, 4> instPorts;
74  for (auto &[module, clockGatesToReplace] : gatesInModule) {
75  DenseMap<Value, Value> fromClocks;
76  Value cstFalse;
77  for (auto ckgOp : clockGatesToReplace) {
78  ImplicitLocOpBuilder builder(ckgOp.getLoc(), ckgOp);
79 
80  Value enable = ckgOp.getEnable();
81  Value testEnable = ckgOp.getTestEnable();
82 
83  // If the clock gate has no test enable operand but the module does, add a
84  // constant 0 input.
85  if (hasTestEnable && !testEnable) {
86  if (!cstFalse) {
87  cstFalse = builder.create<ConstantOp>(i1Type, 0);
88  }
89  testEnable = cstFalse;
90  }
91 
92  // If the clock gate has a test enable operand but the module does not,
93  // add a `comb.or` to merge the two enable conditions.
94  if (!hasTestEnable && testEnable) {
95  enable = builder.createOrFold<comb::OrOp>(enable, testEnable, true);
96  testEnable = {};
97  }
98 
99  Value input = ckgOp.getInput();
100  if (hw::type_isa<seq::ClockType>(input.getType())) {
101  auto it = fromClocks.try_emplace(input, Value{});
102  if (it.second) {
103  ImplicitLocOpBuilder builder(input.getLoc(), &getContext());
104  builder.setInsertionPointAfterValue(input);
105  it.first->second = builder.create<seq::FromClockOp>(input);
106  }
107  instPorts.push_back(it.first->second);
108  } else {
109  instPorts.push_back(input);
110  }
111  instPorts.push_back(enable);
112  if (testEnable)
113  instPorts.push_back(testEnable);
114 
115  auto instOp = builder.create<InstanceOp>(
116  externModuleOp, builder.getStringAttr(instName), instPorts,
117  builder.getArrayAttr({}), ckgOp.getInnerSymAttr());
118 
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);
123  ckgOp.erase();
124 
125  instPorts.clear();
126  ++numClockGatesConverted;
127  }
128  }
129 }
130 
132  const ExternalizeClockGateOptions &options) {
133  return std::make_unique<ExternalizeClockGatePass>(options);
134 }
@ Input
Definition: HW.h:35
@ Output
Definition: HW.h:35
Builder builder
std::unique_ptr< mlir::Pass > createExternalizeClockGatePass(const ExternalizeClockGateOptions &options={})
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
Definition: hw.py:1
Definition: seq.py:1