CIRCT 20.0.0git
Loading...
Searching...
No Matches
VerifToSV.cpp
Go to the documentation of this file.
1//===- VerifToSV.cpp - HW To SV Conversion Pass ---------------------------===//
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 is the main Verif to SV Conversion Pass Implementation.
10//
11//===----------------------------------------------------------------------===//
12
20#include "mlir/Pass/Pass.h"
21#include "mlir/Transforms/DialectConversion.h"
22#include "llvm/ADT/TypeSwitch.h"
23
24namespace circt {
25#define GEN_PASS_DEF_LOWERVERIFTOSV
26#include "circt/Conversion/Passes.h.inc"
27} // namespace circt
28
29using namespace mlir;
30using namespace circt;
31using namespace sv;
32using namespace verif;
33
34//===----------------------------------------------------------------------===//
35// Conversion Patterns
36//===----------------------------------------------------------------------===//
37
38namespace {
39struct PrintOpConversionPattern : public OpConversionPattern<PrintOp> {
41
42 LogicalResult
43 matchAndRewrite(PrintOp op, OpAdaptor operands,
44 ConversionPatternRewriter &rewriter) const override {
45
46 // Printf's will be emitted to stdout (32'h8000_0001 in IEEE Std 1800-2012).
47 Value fdStdout =
48 rewriter.create<hw::ConstantOp>(op.getLoc(), APInt(32, 0x80000001));
49
50 auto fstrOp =
51 dyn_cast_or_null<FormatVerilogStringOp>(op.getString().getDefiningOp());
52 if (!fstrOp)
53 return op->emitOpError() << "expected FormatVerilogStringOp as the "
54 "source of the formatted string";
55
56 rewriter.replaceOpWithNewOp<sv::FWriteOp>(
57 op, fdStdout, fstrOp.getFormatString(), fstrOp.getSubstitutions());
58 return success();
59 }
60};
61
62struct HasBeenResetConversion : public OpConversionPattern<HasBeenResetOp> {
63 using OpConversionPattern<HasBeenResetOp>::OpConversionPattern;
64
65 LogicalResult
66 matchAndRewrite(HasBeenResetOp op, OpAdaptor operands,
67 ConversionPatternRewriter &rewriter) const override {
68 auto i1 = rewriter.getI1Type();
69 auto constOne = rewriter.create<hw::ConstantOp>(op.getLoc(), i1, 1);
70 auto constZero = rewriter.create<hw::ConstantOp>(op.getLoc(), i1, 0);
71 auto constX = rewriter.create<sv::ConstantXOp>(op.getLoc(), i1);
72
73 // Declare the register that will track the reset state.
74 auto reg = rewriter.create<sv::RegOp>(
75 op.getLoc(), i1, rewriter.getStringAttr("hasBeenResetReg"));
76
77 auto clock = operands.getClock();
78 auto reset = operands.getReset();
79
80 // Explicitly initialize the register in an `initial` block. In general, the
81 // register will come up as X, but this may be overridden by simulator
82 // configuration options.
83 //
84 // In case the reset is async, check if the reset is already active during
85 // the `initial` block and immediately set the register to 1. Otherwise
86 // initialize to X.
87 rewriter.create<sv::InitialOp>(op.getLoc(), [&] {
88 auto assignOne = [&] {
89 rewriter.create<sv::BPAssignOp>(op.getLoc(), reg, constOne);
90 };
91 auto assignX = [&] {
92 rewriter.create<sv::BPAssignOp>(op.getLoc(), reg, constX);
93 };
94 if (op.getAsync())
95 rewriter.create<sv::IfOp>(op.getLoc(), reset, assignOne, assignX);
96 else
97 assignX();
98 });
99
100 // Create the `always` block that sets the register to 1 as soon as the
101 // reset is initiated. For async resets this happens at the reset's posedge;
102 // for sync resets this happens on the clock's posedge if the reset is set.
103 Value triggerOn = op.getAsync() ? reset : clock;
104 rewriter.create<sv::AlwaysOp>(
105 op.getLoc(), sv::EventControl::AtPosEdge, triggerOn, [&] {
106 auto assignOne = [&] {
107 rewriter.create<sv::PAssignOp>(op.getLoc(), reg, constOne);
108 };
109 if (op.getAsync())
110 assignOne();
111 else
112 rewriter.create<sv::IfOp>(op.getLoc(), reset, assignOne);
113 });
114
115 // Derive the actual result value:
116 // hasBeenReset = (hasBeenResetReg === 1) && (reset === 0);
117 auto regRead = rewriter.create<sv::ReadInOutOp>(op.getLoc(), reg);
118 auto regIsOne = rewriter.createOrFold<comb::ICmpOp>(
119 op.getLoc(), comb::ICmpPredicate::ceq, regRead, constOne);
120 auto resetIsZero = rewriter.createOrFold<comb::ICmpOp>(
121 op.getLoc(), comb::ICmpPredicate::ceq, reset, constZero);
122 auto resetStartedAndEnded = rewriter.createOrFold<comb::AndOp>(
123 op.getLoc(), regIsOne, resetIsZero, true);
124 rewriter.replaceOpWithNewOp<hw::WireOp>(
125 op, resetStartedAndEnded, rewriter.getStringAttr("hasBeenReset"));
126
127 return success();
128 }
129};
130
131// Conversion from one event control enum to another
132static sv::EventControl verifToSVEventControl(verif::ClockEdge ce) {
133 switch (ce) {
134 case verif::ClockEdge::Pos:
135 return sv::EventControl::AtPosEdge;
136 case verif::ClockEdge::Neg:
137 return sv::EventControl::AtNegEdge;
138 case verif::ClockEdge::Both:
139 return sv::EventControl::AtEdge;
140 }
141 llvm_unreachable("Unknown event control kind");
142}
143
144// Generic conversion for verif.assert, verif.assume and verif.cover
145template <typename Op, typename TargetOp>
146struct VerifAssertLikeConversion : public OpConversionPattern<Op> {
148 using OpAdaptor = typename OpConversionPattern<Op>::OpAdaptor;
149
150 // Convert the verif.assert like op that uses an enable, into an equivalent
151 // sv.assert_property op that has the negated enable as its disable.
152 LogicalResult
153 matchAndRewrite(Op op, OpAdaptor operands,
154 ConversionPatternRewriter &rewriter) const override {
155 // Negate the enable if it exists
156 Value disable;
157 if (auto enable = operands.getEnable()) {
158 Value constOne = rewriter.createOrFold<hw::ConstantOp>(
159 op.getLoc(), rewriter.getI1Type(), 1);
160 disable =
161 rewriter.createOrFold<comb::XorOp>(op.getLoc(), enable, constOne);
162 }
163
164 rewriter.replaceOpWithNewOp<TargetOp>(op, operands.getProperty(), disable,
165 operands.getLabelAttr());
166
167 return success();
168 }
169};
170
171// Generic conversion for verif.clocked_assert, verif.clocked_assume and
172// verif.clocked_cover
173template <typename Op, typename TargetOp>
174struct VerifClockedAssertLikeConversion : public OpConversionPattern<Op> {
176 using OpAdaptor = typename OpConversionPattern<Op>::OpAdaptor;
177
178 // Convert the verif.assert like op that uses an enable, into an equivalent
179 // sv.assert_property op that has the negated enable as its disable.
180 LogicalResult
181 matchAndRewrite(Op op, OpAdaptor operands,
182 ConversionPatternRewriter &rewriter) const override {
183 // Negate the enable if it exists
184 Value disable;
185 if (auto enable = operands.getEnable()) {
186 Value constOne = rewriter.createOrFold<hw::ConstantOp>(
187 op.getLoc(), rewriter.getI1Type(), 1);
188 disable =
189 rewriter.createOrFold<comb::XorOp>(op.getLoc(), enable, constOne);
190 }
191 // Convert a verif clock edge into an sv event control
192 auto eventattr = sv::EventControlAttr::get(
193 op.getContext(), verifToSVEventControl(operands.getEdge()));
194
195 rewriter.replaceOpWithNewOp<TargetOp>(op, operands.getProperty(), eventattr,
196 operands.getClock(), disable,
197 operands.getLabelAttr());
198
199 return success();
200 }
201};
202
203} // namespace
204
205//===----------------------------------------------------------------------===//
206// Pass Infrastructure
207//===----------------------------------------------------------------------===//
208
209namespace {
210struct VerifToSVPass : public circt::impl::LowerVerifToSVBase<VerifToSVPass> {
211 void runOnOperation() override;
212};
213} // namespace
214
215void VerifToSVPass::runOnOperation() {
216 MLIRContext &context = getContext();
217 hw::HWModuleOp module = getOperation();
218
219 ConversionTarget target(context);
220 RewritePatternSet patterns(&context);
221
222 target.addIllegalOp<PrintOp, HasBeenResetOp, verif::AssertOp, verif::AssumeOp,
223 verif::CoverOp, ClockedAssertOp, ClockedAssumeOp,
224 ClockedCoverOp>();
225 target.addLegalDialect<sv::SVDialect, hw::HWDialect, comb::CombDialect>();
226 patterns.add<
227 PrintOpConversionPattern, HasBeenResetConversion,
228 VerifAssertLikeConversion<verif::AssertOp, AssertPropertyOp>,
229 VerifAssertLikeConversion<verif::AssumeOp, AssumePropertyOp>,
230 VerifAssertLikeConversion<verif::CoverOp, CoverPropertyOp>,
231 VerifClockedAssertLikeConversion<verif::ClockedAssertOp,
232 AssertPropertyOp>,
233 VerifClockedAssertLikeConversion<verif::ClockedAssumeOp,
234 AssumePropertyOp>,
235 VerifClockedAssertLikeConversion<verif::ClockedCoverOp, CoverPropertyOp>>(
236 &context);
237
238 if (failed(applyPartialConversion(module, target, std::move(patterns))))
239 signalPassFailure();
240}
241
242std::unique_ptr<OperationPass<hw::HWModuleOp>>
244 return std::make_unique<VerifToSVPass>();
245}
create(data_type, value)
Definition hw.py:433
Definition sv.py:68
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< OperationPass< hw::HWModuleOp > > createLowerVerifToSVPass()
Create the Verif to SV conversion pass.
reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
Definition seq.py:21
Definition sv.py:1
Definition verif.py:1