CIRCT  19.0.0git
AddTaps.cpp
Go to the documentation of this file.
1 //===- AddTaps.cpp --------------------------------------------------------===//
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 
11 #include "circt/Dialect/SV/SVOps.h"
13 #include "mlir/Pass/Pass.h"
14 
15 namespace circt {
16 namespace arc {
17 #define GEN_PASS_DEF_ADDTAPS
18 #include "circt/Dialect/Arc/ArcPasses.h.inc"
19 } // namespace arc
20 } // namespace circt
21 
22 using namespace circt;
23 using namespace arc;
24 using namespace hw;
25 
26 namespace {
27 struct AddTapsPass : public arc::impl::AddTapsBase<AddTapsPass> {
28  using AddTapsBase::AddTapsBase;
29 
30  void runOnOperation() override {
31  getOperation().walk([&](Operation *op) {
32  TypeSwitch<Operation *>(op)
33  .Case<HWModuleOp, sv::WireOp, hw::WireOp>([&](auto op) { tap(op); })
34  .Default([&](auto) { tapIfNamed(op); });
35  });
36  }
37 
38  // Add taps for all module ports.
39  void tap(HWModuleOp moduleOp) {
40  if (!tapPorts)
41  return;
42  auto *outputOp = moduleOp.getBodyBlock()->getTerminator();
43  ModulePortInfo ports(moduleOp.getPortList());
44 
45  // Add taps to inputs.
46  auto builder = OpBuilder::atBlockBegin(moduleOp.getBodyBlock());
47  for (auto [port, arg] :
48  llvm::zip(ports.getInputs(), moduleOp.getBodyBlock()->getArguments()))
49  buildTap(builder, arg.getLoc(), arg, port.getName());
50 
51  // Add taps to outputs.
52  builder.setInsertionPoint(outputOp);
53  for (auto [port, result] :
54  llvm::zip(ports.getOutputs(), outputOp->getOperands()))
55  buildTap(builder, result.getLoc(), result, port.getName());
56  }
57 
58  // Add taps for SV wires.
59  void tap(sv::WireOp wireOp) {
60  if (!tapWires)
61  return;
62  sv::ReadInOutOp readOp;
63  for (auto *user : wireOp->getUsers())
64  if (auto op = dyn_cast<sv::ReadInOutOp>(user))
65  readOp = op;
66 
67  OpBuilder builder(wireOp);
68  if (!readOp)
69  readOp = builder.create<sv::ReadInOutOp>(wireOp.getLoc(), wireOp);
70  buildTap(builder, readOp.getLoc(), readOp, wireOp.getName());
71  }
72 
73  // Add taps for HW wires.
74  void tap(hw::WireOp wireOp) {
75  if (auto name = wireOp.getName(); name && tapWires) {
76  OpBuilder builder(wireOp);
77  buildTap(builder, wireOp.getLoc(), wireOp, *name);
78  }
79  wireOp.getResult().replaceAllUsesWith(wireOp.getInput());
80  wireOp->erase();
81  }
82 
83  // Add taps for named values.
84  void tapIfNamed(Operation *op) {
85  if (!tapNamedValues || op->getNumResults() != 1)
86  return;
87  if (auto name = op->getAttrOfType<StringAttr>("sv.namehint")) {
88  OpBuilder builder(op);
89  buildTap(builder, op->getLoc(), op->getResult(0), name);
90  }
91  }
92 
93  void buildTap(OpBuilder &builder, Location loc, Value value, StringRef name) {
94  if (name.empty())
95  return;
96  if (isa<seq::ClockType>(value.getType()))
97  value = builder.createOrFold<seq::FromClockOp>(loc, value);
98  builder.create<arc::TapOp>(loc, value, name);
99  }
100 };
101 } // namespace
102 
103 std::unique_ptr<Pass> arc::createAddTapsPass(const AddTapsOptions &options) {
104  return std::make_unique<AddTapsPass>(options);
105 }
Builder builder
Definition: sv.py:35
std::unique_ptr< mlir::Pass > createAddTapsPass(const AddTapsOptions &options={})
Definition: AddTaps.cpp:103
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
Definition: hw.py:1
This holds a decoded list of input/inout and output ports for a module or instance.