CIRCT  19.0.0git
SimToSV.cpp
Go to the documentation of this file.
1 //===- LowerSimToSV.cpp - Sim to SV lowering ------------------------------===//
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 // This transform translates Sim ops to SV.
10 //
11 //===----------------------------------------------------------------------===//
12 
14 #include "../PassDetail.h"
16 #include "circt/Dialect/HW/HWOps.h"
17 #include "circt/Dialect/SV/SVOps.h"
21 #include "mlir/IR/Builders.h"
22 #include "mlir/IR/DialectImplementation.h"
23 #include "mlir/IR/ImplicitLocOpBuilder.h"
24 #include "mlir/IR/Threading.h"
25 #include "mlir/Pass/Pass.h"
26 #include "mlir/Transforms/DialectConversion.h"
27 
28 #define DEBUG_TYPE "lower-sim-to-sv"
29 
30 using namespace circt;
31 using namespace sim;
32 
33 namespace {
34 
35 struct SimConversionState {
36  std::atomic<bool> usedSynthesisMacro = false;
37 };
38 
39 template <typename T>
40 struct SimConversionPattern : public OpConversionPattern<T> {
41  explicit SimConversionPattern(MLIRContext *context, SimConversionState &state)
42  : OpConversionPattern<T>(context), state(state) {}
43 
44  SimConversionState &state;
45 };
46 
47 } // namespace
48 
49 // Lower `sim.plusargs.test` to a standard SV implementation.
50 //
51 class PlusArgsTestLowering : public SimConversionPattern<PlusArgsTestOp> {
52 public:
53  using SimConversionPattern<PlusArgsTestOp>::SimConversionPattern;
54 
55  LogicalResult
56  matchAndRewrite(PlusArgsTestOp op, OpAdaptor adaptor,
57  ConversionPatternRewriter &rewriter) const final {
58  auto loc = op.getLoc();
59  auto resultType = rewriter.getIntegerType(1);
60  auto str = rewriter.create<sv::ConstantStrOp>(loc, op.getFormatString());
61  auto reg = rewriter.create<sv::RegOp>(loc, resultType,
62  rewriter.getStringAttr("_pargs"));
63  rewriter.create<sv::InitialOp>(loc, [&] {
64  auto call = rewriter.create<sv::SystemFunctionOp>(
65  loc, resultType, "test$plusargs", ArrayRef<Value>{str});
66  rewriter.create<sv::BPAssignOp>(loc, reg, call);
67  });
68 
69  rewriter.replaceOpWithNewOp<sv::ReadInOutOp>(op, reg);
70  return success();
71  }
72 };
73 
74 // Lower `sim.plusargs.value` to a standard SV implementation.
75 //
76 class PlusArgsValueLowering : public SimConversionPattern<PlusArgsValueOp> {
77 public:
78  using SimConversionPattern<PlusArgsValueOp>::SimConversionPattern;
79 
80  LogicalResult
81  matchAndRewrite(PlusArgsValueOp op, OpAdaptor adaptor,
82  ConversionPatternRewriter &rewriter) const final {
83  auto loc = op.getLoc();
84 
85  auto i1ty = rewriter.getIntegerType(1);
86  auto type = op.getResult().getType();
87 
88  auto regv = rewriter.create<sv::RegOp>(loc, type,
89  rewriter.getStringAttr("_pargs_v_"));
90  auto regf = rewriter.create<sv::RegOp>(loc, i1ty,
91  rewriter.getStringAttr("_pargs_f"));
92 
93  state.usedSynthesisMacro = true;
94  rewriter.create<sv::IfDefOp>(
95  loc, "SYNTHESIS",
96  [&]() {
97  auto cstFalse = rewriter.create<hw::ConstantOp>(loc, APInt(1, 0));
98  auto cstZ = rewriter.create<sv::ConstantZOp>(loc, type);
99  auto assignZ = rewriter.create<sv::AssignOp>(loc, regv, cstZ);
101  assignZ,
103  rewriter.getContext(),
104  "This dummy assignment exists to avoid undriven lint "
105  "warnings (e.g., Verilator UNDRIVEN).",
106  /*emitAsComment=*/true));
107  rewriter.create<sv::AssignOp>(loc, regf, cstFalse);
108  },
109  [&]() {
110  rewriter.create<sv::InitialOp>(loc, [&] {
111  auto zero32 = rewriter.create<hw::ConstantOp>(loc, APInt(32, 0));
112  auto tmpResultType = rewriter.getIntegerType(32);
113  auto str =
114  rewriter.create<sv::ConstantStrOp>(loc, op.getFormatString());
115  auto call = rewriter.create<sv::SystemFunctionOp>(
116  loc, tmpResultType, "value$plusargs",
117  ArrayRef<Value>{str, regv});
118  auto test = rewriter.create<comb::ICmpOp>(
119  loc, comb::ICmpPredicate::ne, call, zero32, true);
120  rewriter.create<sv::BPAssignOp>(loc, regf, test);
121  });
122  });
123 
124  auto readf = rewriter.create<sv::ReadInOutOp>(loc, regf);
125  auto readv = rewriter.create<sv::ReadInOutOp>(loc, regv);
126  rewriter.replaceOp(op, {readf, readv});
127  return success();
128  }
129 };
130 
131 template <typename FromOp, typename ToOp>
132 class SimulatorStopLowering : public SimConversionPattern<FromOp> {
133 public:
134  using SimConversionPattern<FromOp>::SimConversionPattern;
135 
136  LogicalResult
137  matchAndRewrite(FromOp op, typename FromOp::Adaptor adaptor,
138  ConversionPatternRewriter &rewriter) const final {
139  auto loc = op.getLoc();
140 
141  Value clockCast = rewriter.create<seq::FromClockOp>(loc, adaptor.getClk());
142 
143  this->state.usedSynthesisMacro = true;
144  rewriter.create<sv::IfDefOp>(
145  loc, "SYNTHESIS", [&] {},
146  [&] {
147  rewriter.create<sv::AlwaysOp>(
148  loc, sv::EventControl::AtPosEdge, clockCast, [&] {
149  rewriter.create<sv::IfOp>(loc, adaptor.getCond(),
150  [&] { rewriter.create<ToOp>(loc); });
151  });
152  });
153 
154  rewriter.eraseOp(op);
155 
156  return success();
157  }
158 };
159 
160 namespace {
161 struct SimToSVPass : public LowerSimToSVBase<SimToSVPass> {
162  void runOnOperation() override {
163  auto circuit = getOperation();
164  MLIRContext *context = &getContext();
165 
166  SimConversionState state;
167  auto lowerModule = [&](hw::HWModuleOp module) {
168  ConversionTarget target(*context);
169  target.addIllegalDialect<SimDialect>();
170  target.addLegalDialect<sv::SVDialect>();
171  target.addLegalDialect<hw::HWDialect>();
172  target.addLegalDialect<seq::SeqDialect>();
173  target.addLegalDialect<comb::CombDialect>();
174 
175  RewritePatternSet patterns(context);
176  patterns.add<PlusArgsTestLowering>(context, state);
177  patterns.add<PlusArgsValueLowering>(context, state);
179  state);
181  state);
182  return applyPartialConversion(module, target, std::move(patterns));
183  };
184 
185  if (failed(mlir::failableParallelForEach(
186  context, circuit.getOps<hw::HWModuleOp>(), lowerModule)))
187  return signalPassFailure();
188 
189  if (state.usedSynthesisMacro) {
190  Operation *op = circuit.lookupSymbol("SYNTHESIS");
191  if (op) {
192  if (!isa<sv::MacroDeclOp>(op)) {
193  op->emitOpError("should be a macro declaration");
194  return signalPassFailure();
195  }
196  } else {
197  auto builder = ImplicitLocOpBuilder::atBlockBegin(
198  UnknownLoc::get(context), circuit.getBody());
199  builder.create<sv::MacroDeclOp>("SYNTHESIS");
200  }
201  }
202  }
203 };
204 } // anonymous namespace
205 
206 std::unique_ptr<Pass> circt::createLowerSimToSVPass() {
207  return std::make_unique<SimToSVPass>();
208 }
Builder builder
LogicalResult matchAndRewrite(PlusArgsTestOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const final
Definition: SimToSV.cpp:56
LogicalResult matchAndRewrite(PlusArgsValueOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const final
Definition: SimToSV.cpp:81
LogicalResult matchAndRewrite(FromOp op, typename FromOp::Adaptor adaptor, ConversionPatternRewriter &rewriter) const final
Definition: SimToSV.cpp:137
def create(data_type, value)
Definition: hw.py:393
def create(dest, src)
Definition: sv.py:98
Definition: sv.py:15
def create(value)
Definition: sv.py:106
Definition: sv.py:68
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:54
void setSVAttributes(mlir::Operation *op, mlir::ArrayAttr attrs)
Set the SV attributes of an operation.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
std::unique_ptr< mlir::Pass > createLowerSimToSVPass()
Definition: SimToSV.cpp:206
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
Definition: seq.py:20