Skip to content

Commit 5f8489d

Browse files
authored
Merge pull request YosysHQ#5666 from YosysHQ/emil/equiv_induct-missing-model-errors
equiv_induct: error on missing model
2 parents fd1ac58 + 77f64de commit 5f8489d

9 files changed

Lines changed: 165 additions & 136 deletions

File tree

kernel/satgen.cc

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "kernel/satgen.h"
2121
#include "kernel/ff.h"
22+
#include "kernel/yosys_common.h"
2223

2324
USING_YOSYS_NAMESPACE
2425

@@ -1378,7 +1379,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
13781379
return true;
13791380
}
13801381

1381-
if (cell->type == ID($scopeinfo))
1382+
if (cell->type == ID($scopeinfo) || cell->type == ID($input_port))
13821383
{
13831384
return true;
13841385
}
@@ -1387,3 +1388,22 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
13871388
// .. and all sequential cells with asynchronous inputs
13881389
return false;
13891390
}
1391+
1392+
namespace Yosys {
1393+
1394+
void report_missing_model(bool warn_only, RTLIL::Cell* cell)
1395+
{
1396+
std::string s;
1397+
if (cell->is_builtin_ff())
1398+
s = stringf("No SAT model available for async FF cell %s (%s). Consider running `async2sync` or `clk2fflogic` first.\n", log_id(cell), log_id(cell->type));
1399+
else
1400+
s = stringf("No SAT model available for cell %s (%s).\n", log_id(cell), log_id(cell->type));
1401+
1402+
if (warn_only) {
1403+
log_formatted_warning_noprefix(s);
1404+
} else {
1405+
log_formatted_error(s);
1406+
}
1407+
}
1408+
1409+
}

kernel/satgen.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,8 @@ struct SatGen
293293
bool importCell(RTLIL::Cell *cell, int timestep = -1);
294294
};
295295

296+
void report_missing_model(bool warn_only, RTLIL::Cell* cell);
297+
296298
YOSYS_NAMESPACE_END
297299

298300
#endif

passes/equiv/equiv.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#ifndef EQUIV_H
2+
#define EQUIV_H
3+
4+
#include "kernel/log.h"
5+
#include "kernel/yosys_common.h"
6+
#include "kernel/sigtools.h"
7+
#include "kernel/satgen.h"
8+
9+
YOSYS_NAMESPACE_BEGIN
10+
11+
struct EquivBasicConfig {
12+
bool model_undef = false;
13+
int max_seq = 1;
14+
bool set_assumes = false;
15+
bool ignore_unknown_cells = false;
16+
17+
bool parse(const std::vector<std::string>& args, size_t& idx) {
18+
if (args[idx] == "-undef") {
19+
model_undef = true;
20+
return true;
21+
}
22+
if (args[idx] == "-seq" && idx+1 < args.size()) {
23+
max_seq = atoi(args[++idx].c_str());
24+
return true;
25+
}
26+
if (args[idx] == "-set-assumes") {
27+
set_assumes = true;
28+
return true;
29+
}
30+
if (args[idx] == "-ignore-unknown-cells") {
31+
ignore_unknown_cells = true;
32+
return true;
33+
}
34+
return false;
35+
}
36+
static std::string help(const char* default_seq) {
37+
return stringf(
38+
" -undef\n"
39+
" enable modelling of undef states\n"
40+
"\n"
41+
" -seq <N>\n"
42+
" the max. number of time steps to be considered (default = %s)\n"
43+
"\n"
44+
" -set-assumes\n"
45+
" set all assumptions provided via $assume cells\n"
46+
"\n"
47+
" -ignore-unknown-cells\n"
48+
" ignore all cells that can not be matched to a SAT model\n"
49+
, default_seq);
50+
}
51+
};
52+
53+
template<typename Config = EquivBasicConfig>
54+
struct EquivWorker {
55+
RTLIL::Module *module;
56+
57+
ezSatPtr ez;
58+
SatGen satgen;
59+
Config cfg;
60+
61+
EquivWorker(RTLIL::Module *module, const SigMap *sigmap, Config cfg) : module(module), satgen(ez.get(), sigmap), cfg(cfg) {
62+
satgen.model_undef = cfg.model_undef;
63+
}
64+
};
65+
66+
YOSYS_NAMESPACE_END
67+
#endif // EQUIV_H

passes/equiv/equiv_induct.cc

Lines changed: 17 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -18,49 +18,34 @@
1818
*/
1919

2020
#include "kernel/yosys.h"
21-
#include "kernel/satgen.h"
22-
#include "kernel/sigtools.h"
21+
#include "passes/equiv/equiv.h"
2322

2423
USING_YOSYS_NAMESPACE
2524
PRIVATE_NAMESPACE_BEGIN
2625

27-
struct EquivInductWorker
26+
struct EquivInductWorker : public EquivWorker<>
2827
{
29-
Module *module;
3028
SigMap sigmap;
3129

3230
vector<Cell*> cells;
3331
pool<Cell*> workset;
3432

35-
ezSatPtr ez;
36-
SatGen satgen;
37-
38-
int max_seq;
3933
int success_counter;
40-
bool set_assumes;
4134

4235
dict<int, int> ez_step_is_consistent;
43-
pool<Cell*> cell_warn_cache;
4436
SigPool undriven_signals;
4537

46-
EquivInductWorker(Module *module, const pool<Cell*> &unproven_equiv_cells, bool model_undef, int max_seq, bool set_assumes) : module(module), sigmap(module),
38+
EquivInductWorker(Module *module, const pool<Cell*> &unproven_equiv_cells, EquivBasicConfig cfg) : EquivWorker<>(module, &sigmap, cfg), sigmap(module),
4739
cells(module->selected_cells()), workset(unproven_equiv_cells),
48-
satgen(ez.get(), &sigmap), max_seq(max_seq), success_counter(0), set_assumes(set_assumes)
49-
{
50-
satgen.model_undef = model_undef;
51-
}
40+
success_counter(0) {}
5241

5342
void create_timestep(int step)
5443
{
5544
vector<int> ez_equal_terms;
5645

5746
for (auto cell : cells) {
58-
if (!satgen.importCell(cell, step) && !cell_warn_cache.count(cell)) {
59-
if (cell->is_builtin_ff())
60-
log_warning("No SAT model available for async FF cell %s (%s). Consider running `async2sync` or `clk2fflogic` first.\n", log_id(cell), log_id(cell->type));
61-
else
62-
log_warning("No SAT model available for cell %s (%s).\n", log_id(cell), log_id(cell->type));
63-
cell_warn_cache.insert(cell);
47+
if (!satgen.importCell(cell, step)) {
48+
report_missing_model(cfg.ignore_unknown_cells, cell);
6449
}
6550
if (cell->type == ID($equiv)) {
6651
SigBit bit_a = sigmap(cell->getPort(ID::A)).as_bit();
@@ -78,7 +63,7 @@ struct EquivInductWorker
7863
}
7964
}
8065

81-
if (set_assumes) {
66+
if (cfg.set_assumes) {
8267
if (step == 1) {
8368
RTLIL::SigSpec assumes_a, assumes_en;
8469
satgen.getAssumes(assumes_a, assumes_en, step);
@@ -123,7 +108,7 @@ struct EquivInductWorker
123108
GetSize(satgen.initial_state), GetSize(undriven_signals));
124109
}
125110

126-
for (int step = 1; step <= max_seq; step++)
111+
for (int step = 1; step <= cfg.max_seq; step++)
127112
{
128113
ez->assume(ez_step_is_consistent[step]);
129114

@@ -146,7 +131,7 @@ struct EquivInductWorker
146131
return;
147132
}
148133

149-
log(" Proof for induction step failed. %s\n", step != max_seq ? "Extending to next time step." : "Trying to prove individual $equiv from workset.");
134+
log(" Proof for induction step failed. %s\n", step != cfg.max_seq ? "Extending to next time step." : "Trying to prove individual $equiv from workset.");
150135
}
151136

152137
workset.sort();
@@ -158,12 +143,12 @@ struct EquivInductWorker
158143

159144
log(" Trying to prove $equiv for %s:", log_signal(sigmap(cell->getPort(ID::Y))));
160145

161-
int ez_a = satgen.importSigBit(bit_a, max_seq+1);
162-
int ez_b = satgen.importSigBit(bit_b, max_seq+1);
146+
int ez_a = satgen.importSigBit(bit_a, cfg.max_seq+1);
147+
int ez_b = satgen.importSigBit(bit_b, cfg.max_seq+1);
163148
int cond = ez->XOR(ez_a, ez_b);
164149

165150
if (satgen.model_undef)
166-
cond = ez->AND(cond, ez->NOT(satgen.importUndefSigBit(bit_a, max_seq+1)));
151+
cond = ez->AND(cond, ez->NOT(satgen.importUndefSigBit(bit_a, cfg.max_seq+1)));
167152

168153
if (!ez->solve(cond)) {
169154
log(" success!\n");
@@ -189,14 +174,7 @@ struct EquivInductPass : public Pass {
189174
log("Only selected $equiv cells are proven and only selected cells are used to\n");
190175
log("perform the proof.\n");
191176
log("\n");
192-
log(" -undef\n");
193-
log(" enable modelling of undef states\n");
194-
log("\n");
195-
log(" -seq <N>\n");
196-
log(" the max. number of time steps to be considered (default = 4)\n");
197-
log("\n");
198-
log(" -set-assumes\n");
199-
log(" set all assumptions provided via $assume cells\n");
177+
EquivBasicConfig::help("4");
200178
log("\n");
201179
log("This command is very effective in proving complex sequential circuits, when\n");
202180
log("the internal state of the circuit quickly propagates to $equiv cells.\n");
@@ -214,25 +192,15 @@ struct EquivInductPass : public Pass {
214192
void execute(std::vector<std::string> args, Design *design) override
215193
{
216194
int success_counter = 0;
217-
bool model_undef = false, set_assumes = false;
218-
int max_seq = 4;
195+
EquivBasicConfig cfg {};
196+
cfg.max_seq = 4;
219197

220198
log_header(design, "Executing EQUIV_INDUCT pass.\n");
221199

222200
size_t argidx;
223201
for (argidx = 1; argidx < args.size(); argidx++) {
224-
if (args[argidx] == "-undef") {
225-
model_undef = true;
202+
if (cfg.parse(args, argidx))
226203
continue;
227-
}
228-
if (args[argidx] == "-seq" && argidx+1 < args.size()) {
229-
max_seq = atoi(args[++argidx].c_str());
230-
continue;
231-
}
232-
if (args[argidx] == "-set-assumes") {
233-
set_assumes = true;
234-
continue;
235-
}
236204
break;
237205
}
238206
extra_args(args, argidx, design);
@@ -253,7 +221,7 @@ struct EquivInductPass : public Pass {
253221
continue;
254222
}
255223

256-
EquivInductWorker worker(module, unproven_equiv_cells, model_undef, max_seq, set_assumes);
224+
EquivInductWorker worker(module, unproven_equiv_cells, cfg);
257225
worker.run();
258226
success_counter += worker.success_counter;
259227
}

0 commit comments

Comments
 (0)