14#include "mlir/Pass/Pass.h"
20#define GEN_PASS_DEF_PREPAREFORBMC
21#include "circt/Tools/circt-bmc/Passes.h.inc"
25struct PrepareForBMCPass
26 :
public circt::impl::PrepareForBMCBase<PrepareForBMCPass> {
27 using PrepareForBMCBase::PrepareForBMCBase;
29 FailureOr<Value> getPreviousClock(Value clock, OpBuilder &builder) {
30 if (
auto it = previousClockValues.find(clock);
31 it != previousClockValues.end())
34 auto fromClock = clock.getDefiningOp<seq::FromClockOp>();
36 emitError(clock.getLoc(),
37 "expected a clock normalized by seq.from_clock");
41 auto initialValue = seq::createConstantInitialValue(
42 builder, clock.getLoc(),
43 builder.getIntegerAttr(builder.getI1Type(), 0));
48 builder, clock.getLoc(), clock, fromClock.getInput(), Value{},
49 Value{}, initialValue);
50 previousClockValues.try_emplace(clock, previousClock);
51 return previousClock.getData();
54 template <
typename ClockedOp,
typename UnclockedOp>
55 LogicalResult lowerClockedProperty(ClockedOp op) {
56 if (!op.getProperty().getType().isInteger(1)) {
57 op.emitError(
"unsupported clocked property after LTL lowering");
61 OpBuilder builder(op);
62 auto previousClock = getPreviousClock(op.getClock(), builder);
63 if (failed(previousClock))
68 switch (op.getEdge()) {
69 case verif::ClockEdge::Pos: {
70 auto notPreviousClock =
71 comb::XorOp::create(builder, op.getLoc(), *previousClock, trueValue);
72 active = comb::AndOp::create(builder, op.getLoc(), op.getClock(),
76 case verif::ClockEdge::Neg: {
77 auto notCurrentClock =
78 comb::XorOp::create(builder, op.getLoc(), op.getClock(), trueValue);
79 active = comb::AndOp::create(builder, op.getLoc(), notCurrentClock,
83 case verif::ClockEdge::Both:
84 active = comb::XorOp::create(builder, op.getLoc(), op.getClock(),
90 comb::AndOp::create(builder, op.getLoc(), active, op.getEnable());
93 comb::XorOp::create(builder, op.getLoc(), active, trueValue);
95 comb::OrOp::create(builder, op.getLoc(), inactive, op.getProperty());
96 UnclockedOp::create(builder, op.getLoc(), property, Value{},
106 auto *body =
module.getBodyBlock();
107 SmallVector<BlockArgument> clockArguments;
108 for (
auto argument : body->getArguments()) {
109 if (!argument.getType().isInteger(1))
111 if (llvm::any_of(argument.getUsers(), [](Operation *user) {
112 return isa<seq::ToClockOp>(user);
114 clockArguments.push_back(argument);
116 if (clockArguments.empty())
119 SmallVector<hw::ModulePort> ports(module.getHWModuleType().getPorts());
120 auto clockType = seq::ClockType::get(&getContext());
121 for (
auto argument : clockArguments) {
122 SmallVector<seq::ToClockOp> toClockOps;
123 SmallVector<OpOperand *> rawClockUses;
124 for (
auto &use : argument.getUses()) {
125 if (
auto toClock = dyn_cast<seq::ToClockOp>(use.getOwner()))
126 toClockOps.push_back(toClock);
128 rawClockUses.push_back(&use);
131 argument.setType(clockType);
132 OpBuilder builder = OpBuilder::atBlockBegin(body);
134 seq::FromClockOp::create(builder, argument.getLoc(), argument);
135 for (
auto *use : rawClockUses)
137 for (
auto toClock : toClockOps) {
138 toClock.replaceAllUsesWith(argument);
143 module.getHWModuleType().getPortIdForInputId(argument.getArgNumber());
144 ports[portID].type = clockType;
146 module.setHWModuleType(hw::ModuleType::get(&getContext(), ports));
149 void runOnOperation()
override {
150 previousClockValues.clear();
151 auto module = getOperation().lookupSymbol<hw::HWModuleOp>(topModule);
155 normalizeClockPorts(module);
156 LogicalResult result = success();
157 module->walk([&](Operation *operation) {
160 if (
auto assertOp = dyn_cast<verif::ClockedAssertOp>(operation))
161 result = lowerClockedProperty<verif::ClockedAssertOp, verif::AssertOp>(
163 else if (
auto assumeOp = dyn_cast<verif::ClockedAssumeOp>(operation))
164 result = lowerClockedProperty<verif::ClockedAssumeOp, verif::AssumeOp>(
171 DenseMap<Value, Value> previousClockValues;
create(cls, result_type, reset=None, reset_value=None, name=None, sym_name=None, **kwargs)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.