2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include "kernel/yosys.h"
21 #include "kernel/satgen.h"
22 #include "kernel/sigtools.h"
25 PRIVATE_NAMESPACE_BEGIN
27 struct EquivInductWorker
41 dict
<int, int> ez_step_is_consistent
;
42 pool
<Cell
*> cell_warn_cache
;
43 SigPool undriven_signals
;
45 EquivInductWorker(Module
*module
, const pool
<Cell
*> &unproven_equiv_cells
, bool model_undef
, int max_seq
) : module(module
), sigmap(module
),
46 cells(module
->selected_cells()), workset(unproven_equiv_cells
),
47 satgen(ez
.get(), &sigmap
), max_seq(max_seq
), success_counter(0)
49 satgen
.model_undef
= model_undef
;
52 void create_timestep(int step
)
54 vector
<int> ez_equal_terms
;
56 for (auto cell
: cells
) {
57 if (!satgen
.importCell(cell
, step
) && !cell_warn_cache
.count(cell
)) {
58 log_warning("No SAT model available for cell %s (%s).\n", log_id(cell
), log_id(cell
->type
));
59 cell_warn_cache
.insert(cell
);
61 if (cell
->type
== "$equiv") {
62 SigBit bit_a
= sigmap(cell
->getPort("\\A")).as_bit();
63 SigBit bit_b
= sigmap(cell
->getPort("\\B")).as_bit();
65 int ez_a
= satgen
.importSigBit(bit_a
, step
);
66 int ez_b
= satgen
.importSigBit(bit_b
, step
);
67 int cond
= ez
->IFF(ez_a
, ez_b
);
68 if (satgen
.model_undef
)
69 cond
= ez
->OR(cond
, satgen
.importUndefSigBit(bit_a
, step
));
70 ez_equal_terms
.push_back(cond
);
75 if (satgen
.model_undef
) {
76 for (auto bit
: undriven_signals
.export_all())
77 ez
->assume(ez
->NOT(satgen
.importUndefSigBit(bit
, step
)));
80 log_assert(!ez_step_is_consistent
.count(step
));
81 ez_step_is_consistent
[step
] = ez
->expression(ez
->OpAnd
, ez_equal_terms
);
86 log("Found %d unproven $equiv cells in module %s:\n", GetSize(workset
), log_id(module
));
88 if (satgen
.model_undef
) {
89 for (auto cell
: cells
)
90 if (yosys_celltypes
.cell_known(cell
->type
))
91 for (auto &conn
: cell
->connections())
92 if (yosys_celltypes
.cell_input(cell
->type
, conn
.first
))
93 undriven_signals
.add(sigmap(conn
.second
));
94 for (auto cell
: cells
)
95 if (yosys_celltypes
.cell_known(cell
->type
))
96 for (auto &conn
: cell
->connections())
97 if (yosys_celltypes
.cell_output(cell
->type
, conn
.first
))
98 undriven_signals
.del(sigmap(conn
.second
));
103 if (satgen
.model_undef
) {
104 for (auto bit
: satgen
.initial_state
.export_all())
105 ez
->assume(ez
->NOT(satgen
.importUndefSigBit(bit
, 1)));
106 log(" Undef modelling: force def on %d initial reg values and %d inputs.\n",
107 GetSize(satgen
.initial_state
), GetSize(undriven_signals
));
110 for (int step
= 1; step
<= max_seq
; step
++)
112 ez
->assume(ez_step_is_consistent
[step
]);
114 log(" Proving existence of base case for step %d. (%d clauses over %d variables)\n", step
, ez
->numCnfClauses(), ez
->numCnfVariables());
116 log(" Proof for base case failed. Circuit inherently diverges!\n");
120 create_timestep(step
+1);
121 int new_step_not_consistent
= ez
->NOT(ez_step_is_consistent
[step
+1]);
122 ez
->bind(new_step_not_consistent
);
124 log(" Proving induction step %d. (%d clauses over %d variables)\n", step
, ez
->numCnfClauses(), ez
->numCnfVariables());
125 if (!ez
->solve(new_step_not_consistent
)) {
126 log(" Proof for induction step holds. Entire workset of %d cells proven!\n", GetSize(workset
));
127 for (auto cell
: workset
)
128 cell
->setPort("\\B", cell
->getPort("\\A"));
129 success_counter
+= GetSize(workset
);
133 log(" Proof for induction step failed. %s\n", step
!= max_seq
? "Extending to next time step." : "Trying to prove individual $equiv from workset.");
138 for (auto cell
: workset
)
140 SigBit bit_a
= sigmap(cell
->getPort("\\A")).as_bit();
141 SigBit bit_b
= sigmap(cell
->getPort("\\B")).as_bit();
143 log(" Trying to prove $equiv for %s:", log_signal(sigmap(cell
->getPort("\\Y"))));
145 int ez_a
= satgen
.importSigBit(bit_a
, max_seq
+1);
146 int ez_b
= satgen
.importSigBit(bit_b
, max_seq
+1);
147 int cond
= ez
->XOR(ez_a
, ez_b
);
149 if (satgen
.model_undef
)
150 cond
= ez
->AND(cond
, ez
->NOT(satgen
.importUndefSigBit(bit_a
, max_seq
+1)));
152 if (!ez
->solve(cond
)) {
154 cell
->setPort("\\B", cell
->getPort("\\A"));
163 struct EquivInductPass
: public Pass
{
164 EquivInductPass() : Pass("equiv_induct", "proving $equiv cells using temporal induction") { }
167 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
169 log(" equiv_induct [options] [selection]\n");
171 log("Uses a version of temporal induction to prove $equiv cells.\n");
173 log("Only selected $equiv cells are proven and only selected cells are used to\n");
174 log("perform the proof.\n");
177 log(" enable modelling of undef states\n");
180 log(" the max. number of time steps to be considered (default = 4)\n");
182 log("This command is very effective in proving complex sequential circuits, when\n");
183 log("the internal state of the circuit quickly propagates to $equiv cells.\n");
185 log("However, this command uses a weak definition of 'equivalence': This command\n");
186 log("proves that the two circuits will not diverge after they produce equal\n");
187 log("outputs (observable points via $equiv) for at least <N> cycles (the <N>\n");
188 log("specified via -seq).\n");
190 log("Combined with simulation this is very powerful because simulation can give\n");
191 log("you confidence that the circuits start out synced for at least <N> cycles\n");
192 log("after reset.\n");
195 virtual void execute(std::vector
<std::string
> args
, Design
*design
)
197 int success_counter
= 0;
198 bool model_undef
= false;
201 log_header(design
, "Executing EQUIV_INDUCT pass.\n");
204 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
205 if (args
[argidx
] == "-undef") {
209 if (args
[argidx
] == "-seq" && argidx
+1 < args
.size()) {
210 max_seq
= atoi(args
[++argidx
].c_str());
215 extra_args(args
, argidx
, design
);
217 for (auto module
: design
->selected_modules())
219 pool
<Cell
*> unproven_equiv_cells
;
221 for (auto cell
: module
->selected_cells())
222 if (cell
->type
== "$equiv") {
223 if (cell
->getPort("\\A") != cell
->getPort("\\B"))
224 unproven_equiv_cells
.insert(cell
);
227 if (unproven_equiv_cells
.empty()) {
228 log("No selected unproven $equiv cells found in %s.\n", log_id(module
));
232 EquivInductWorker
worker(module
, unproven_equiv_cells
, model_undef
, max_seq
);
234 success_counter
+= worker
.success_counter
;
237 log("Proved %d previously unproven $equiv cells.\n", success_counter
);
241 PRIVATE_NAMESPACE_END