CIRCT 20.0.0git
Loading...
Searching...
No Matches
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
13#include "mlir/IR/ImplicitLocOpBuilder.h"
14#include "mlir/Pass/Pass.h"
15
16namespace circt {
17namespace seq {
18#define GEN_PASS_DEF_EXTERNALIZECLOCKGATE
19#include "circt/Dialect/Seq/SeqPasses.h.inc"
20} // namespace seq
21} // namespace circt
22
23using namespace circt;
24using namespace seq;
25using namespace hw;
26
27namespace {
28struct ExternalizeClockGatePass
29 : public circt::seq::impl::ExternalizeClockGateBase<
30 ExternalizeClockGatePass> {
31 using ExternalizeClockGateBase<
32 ExternalizeClockGatePass>::ExternalizeClockGateBase;
33 void runOnOperation() override;
34};
35} // anonymous namespace
36
37void 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,
57 ModulePort::Direction::Input}});
58 modulePorts.push_back({{builder.getStringAttr(outputName), i1Type,
59 ModulePort::Direction::Output}});
60 modulePorts.push_back({{builder.getStringAttr(enableName), i1Type,
61 ModulePort::Direction::Input}});
62 bool hasTestEnable = !testEnableName.empty();
63 if (hasTestEnable)
64 modulePorts.push_back({{builder.getStringAttr(testEnableName), i1Type,
65 ModulePort::Direction::Input}});
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}
std::unique_ptr< mlir::Pass > createExternalizeClockGatePass(const ExternalizeClockGateOptions &options={})
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition hw.py:1
Definition seq.py:1