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 
9 #include "PassDetails.h"
11 #include "circt/Dialect/HW/HWOps.h"
13 #include "mlir/IR/ImplicitLocOpBuilder.h"
14 
15 namespace circt {
16 namespace seq {
17 #define GEN_PASS_DEF_EXTERNALIZECLOCKGATE
18 #include "circt/Dialect/Seq/SeqPasses.h.inc"
19 } // namespace seq
20 } // namespace circt
21 
22 using namespace circt;
23 using namespace seq;
24 using namespace hw;
25 
26 namespace {
27 struct ExternalizeClockGatePass
28  : public impl::ExternalizeClockGateBase<ExternalizeClockGatePass> {
29  using ExternalizeClockGateBase<
30  ExternalizeClockGatePass>::ExternalizeClockGateBase;
31  void runOnOperation() override;
32 };
33 } // anonymous namespace
34 
35 void ExternalizeClockGatePass::runOnOperation() {
36  SymbolTable &symtbl = getAnalysis<SymbolTable>();
37 
38  // Collect all clock gate ops.
39  DenseMap<HWModuleOp, SmallVector<ClockGateOp>> gatesInModule;
40  for (auto module : getOperation().getOps<HWModuleOp>()) {
41  module.walk([&](ClockGateOp op) { gatesInModule[module].push_back(op); });
42  }
43 
44  if (gatesInModule.empty()) {
45  markAllAnalysesPreserved();
46  return;
47  }
48 
49  // Generate the external module declaration.
50  auto builder = OpBuilder::atBlockBegin(getOperation().getBody());
51  auto i1Type = builder.getI1Type();
52 
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();
61  if (hasTestEnable)
62  modulePorts.push_back({{builder.getStringAttr(testEnableName), i1Type,
64 
65  auto externModuleOp = builder.create<HWModuleExternOp>(
66  getOperation().getLoc(), builder.getStringAttr(moduleName), modulePorts,
67  moduleName);
68  symtbl.insert(externModuleOp);
69 
70  // Replace all clock gates with an instance of the external module.
71  SmallVector<Value, 4> instPorts;
72  for (auto &[module, clockGatesToReplace] : gatesInModule) {
73  DenseMap<Value, Value> fromClocks;
74  Value cstFalse;
75  for (auto ckgOp : clockGatesToReplace) {
76  ImplicitLocOpBuilder builder(ckgOp.getLoc(), ckgOp);
77 
78  Value enable = ckgOp.getEnable();
79  Value testEnable = ckgOp.getTestEnable();
80 
81  // If the clock gate has no test enable operand but the module does, add a
82  // constant 0 input.
83  if (hasTestEnable && !testEnable) {
84  if (!cstFalse) {
85  cstFalse = builder.create<ConstantOp>(i1Type, 0);
86  }
87  testEnable = cstFalse;
88  }
89 
90  // If the clock gate has a test enable operand but the module does not,
91  // add a `comb.or` to merge the two enable conditions.
92  if (!hasTestEnable && testEnable) {
93  enable = builder.createOrFold<comb::OrOp>(enable, testEnable, true);
94  testEnable = {};
95  }
96 
97  Value input = ckgOp.getInput();
98  if (hw::type_isa<seq::ClockType>(input.getType())) {
99  auto it = fromClocks.try_emplace(input, Value{});
100  if (it.second) {
101  ImplicitLocOpBuilder builder(input.getLoc(), &getContext());
102  builder.setInsertionPointAfterValue(input);
103  it.first->second = builder.create<seq::FromClockOp>(input);
104  }
105  instPorts.push_back(it.first->second);
106  } else {
107  instPorts.push_back(input);
108  }
109  instPorts.push_back(enable);
110  if (testEnable)
111  instPorts.push_back(testEnable);
112 
113  auto instOp = builder.create<InstanceOp>(
114  externModuleOp, builder.getStringAttr(instName), instPorts,
115  builder.getArrayAttr({}), ckgOp.getInnerSymAttr());
116 
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);
121  ckgOp.erase();
122 
123  instPorts.clear();
124  ++numClockGatesConverted;
125  }
126  }
127 }
128 
130  const ExternalizeClockGateOptions &options) {
131  return std::make_unique<ExternalizeClockGatePass>(options);
132 }
@ 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