@@ -59,6 +59,12 @@ struct CheckPass : public Pass {
59
59
log (" -assert\n " );
60
60
log (" produce a runtime error if any problems are found in the current design\n " );
61
61
log (" \n " );
62
+ log (" -force-detailed-loop-check\n " );
63
+ log (" for the detection of combinatorial loops, use a detailed connectivity\n " );
64
+ log (" model for all internal cells for which it is available. This disables\n " );
65
+ log (" falling back to a simpler overapproximating model for those cells for\n " );
66
+ log (" which the detailed model is expected costly.\n " );
67
+ log (" \n " );
62
68
}
63
69
void execute (std::vector<std::string> args, RTLIL::Design *design) override
64
70
{
@@ -68,6 +74,8 @@ struct CheckPass : public Pass {
68
74
bool mapped = false ;
69
75
bool allow_tbuf = false ;
70
76
bool assert_mode = false ;
77
+ bool force_detailed_loop_check = false ;
78
+ bool suggest_detail = false ;
71
79
72
80
size_t argidx;
73
81
for (argidx = 1 ; argidx < args.size (); argidx++) {
@@ -91,6 +99,10 @@ struct CheckPass : public Pass {
91
99
assert_mode = true ;
92
100
continue ;
93
101
}
102
+ if (args[argidx] == " -force-detailed-loop-check" ) {
103
+ force_detailed_loop_check = true ;
104
+ continue ;
105
+ }
94
106
break ;
95
107
}
96
108
extra_args (args, argidx, design);
@@ -154,9 +166,10 @@ struct CheckPass : public Pass {
154
166
struct CircuitEdgesDatabase : AbstractCellEdgesDatabase {
155
167
TopoSort<std::pair<RTLIL::IdString, int >> &topo;
156
168
SigMap sigmap;
169
+ bool force_detail;
157
170
158
- CircuitEdgesDatabase (TopoSort<std::pair<RTLIL::IdString, int >> &topo, SigMap &sigmap)
159
- : topo(topo), sigmap(sigmap) {}
171
+ CircuitEdgesDatabase (TopoSort<std::pair<RTLIL::IdString, int >> &topo, SigMap &sigmap, bool force_detail )
172
+ : topo(topo), sigmap(sigmap), force_detail(force_detail) {}
160
173
161
174
void add_edge (RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit,
162
175
RTLIL::IdString to_port, int to_bit, int ) override {
@@ -171,10 +184,41 @@ struct CheckPass : public Pass {
171
184
topo.edge (std::make_pair (from.wire ->name , from.offset ), std::make_pair (to.wire ->name , to.offset ));
172
185
}
173
186
174
- bool add_edges_from_cell (Cell *cell) {
175
- if (AbstractCellEdgesDatabase::add_edges_from_cell (cell))
187
+ bool detail_costly (Cell *cell) {
188
+ // Only those cell types for which the edge data can expode quadratically
189
+ // in port widths are those for us to check.
190
+ if (!cell->type .in (
191
+ ID ($add), ID ($sub),
192
+ ID ($shl), ID ($shr), ID ($sshl), ID ($sshr), ID ($shift), ID ($shiftx)))
193
+ return false ;
194
+
195
+ int in_widths = 0 , out_widths = 0 ;
196
+
197
+ for (auto &conn : cell->connections ()) {
198
+ if (cell->input (conn.first ))
199
+ in_widths += conn.second .size ();
200
+ if (cell->output (conn.first ))
201
+ out_widths += conn.second .size ();
202
+ }
203
+
204
+ const int threshold = 1024 ;
205
+
206
+ // if the multiplication may overflow we will catch it here
207
+ if (in_widths + out_widths >= threshold)
176
208
return true ;
177
209
210
+ if (in_widths * out_widths >= threshold)
211
+ return true ;
212
+
213
+ return false ;
214
+ }
215
+
216
+ bool add_edges_from_cell (Cell *cell) {
217
+ if (force_detail || !detail_costly (cell)) {
218
+ if (AbstractCellEdgesDatabase::add_edges_from_cell (cell))
219
+ return true ;
220
+ }
221
+
178
222
// We don't have accurate cell edges, do the fallback of all input-output pairs
179
223
for (auto &conn : cell->connections ()) {
180
224
if (cell->input (conn.first ))
@@ -189,12 +233,15 @@ struct CheckPass : public Pass {
189
233
topo.edge (std::make_pair (cell->name , -1 ),
190
234
std::make_pair (bit.wire ->name , bit.offset ));
191
235
}
192
- return true ;
236
+
237
+ // Return false to signify the fallback
238
+ return false ;
193
239
}
194
240
};
195
241
196
- CircuitEdgesDatabase edges_db (topo, sigmap);
242
+ CircuitEdgesDatabase edges_db (topo, sigmap, force_detailed_loop_check );
197
243
244
+ pool<Cell *> coarsened_cells;
198
245
for (auto cell : module->cells ())
199
246
{
200
247
if (mapped && cell->type .begins_with (" $" ) && design->module (cell->type ) == nullptr ) {
@@ -225,8 +272,10 @@ struct CheckPass : public Pass {
225
272
}
226
273
227
274
if (yosys_celltypes.cell_evaluable (cell->type ) || cell->type .in (ID ($mem_v2), ID ($memrd), ID ($memrd_v2)) \
228
- || RTLIL::builtin_ff_cell_types ().count (cell->type ))
229
- edges_db.add_edges_from_cell (cell);
275
+ || RTLIL::builtin_ff_cell_types ().count (cell->type )) {
276
+ if (!edges_db.add_edges_from_cell (cell))
277
+ coarsened_cells.insert (cell);
278
+ }
230
279
}
231
280
232
281
pool<SigBit> init_bits;
@@ -284,10 +333,10 @@ struct CheckPass : public Pass {
284
333
for (auto &loop : topo.loops ) {
285
334
string message = stringf (" found logic loop in module %s:\n " , log_id (module));
286
335
287
- // `loop` only contains wire bits, or an occassional special helper node for cells for
288
- // which we have done the edges fallback. The cell and its ports that led to an edge is
289
- // an information we need to recover now. For that we need to have the previous wire bit
290
- // of the loop at hand.
336
+ // `loop` only contains wire bits, or an occasional special helper node for cells for
337
+ // which we have done the edges fallback. The cell and its ports that led to an edge are
338
+ // a piece of information we need to recover now. For that we need to have the previous
339
+ // wire bit of the loop at hand.
291
340
SigBit prev;
292
341
for (auto it = loop.rbegin (); it != loop.rend (); it++)
293
342
if (it->second != -1 ) { // skip the fallback helper nodes
@@ -316,10 +365,10 @@ struct CheckPass : public Pass {
316
365
SigBit edge_to = sigmap (cell->getPort (to_port))[to_bit];
317
366
318
367
if (edge_from == from && edge_to == to && nhits++ < HITS_LIMIT)
319
- message += stringf (" %s[%d] --> %s[%d]\n " , log_id (from_port), from_bit,
368
+ message += stringf (" %s[%d] --> %s[%d]\n " , log_id (from_port), from_bit,
320
369
log_id (to_port), to_bit);
321
370
if (nhits == HITS_LIMIT)
322
- message += " ...\n " ;
371
+ message += " ...\n " ;
323
372
}
324
373
};
325
374
@@ -334,9 +383,16 @@ struct CheckPass : public Pass {
334
383
std::string src_attr = driver->get_src_attribute ();
335
384
driver_src = stringf (" source: %s" , src_attr.c_str ());
336
385
}
386
+
337
387
message += stringf (" cell %s (%s)%s\n " , log_id (driver), log_id (driver->type ), driver_src.c_str ());
338
- MatchingEdgePrinter printer (message, sigmap, prev, bit);
339
- printer.add_edges_from_cell (driver);
388
+
389
+ if (!coarsened_cells.count (driver)) {
390
+ MatchingEdgePrinter printer (message, sigmap, prev, bit);
391
+ printer.add_edges_from_cell (driver);
392
+ } else {
393
+ message += " (cell's internal connectivity overapproximated; loop may be a false positive)\n " ;
394
+ suggest_detail = true ;
395
+ }
340
396
341
397
if (wire->name .isPublic ()) {
342
398
std::string wire_src;
@@ -376,6 +432,9 @@ struct CheckPass : public Pass {
376
432
377
433
log (" Found and reported %d problems.\n " , counter);
378
434
435
+ if (suggest_detail)
436
+ log (" Consider re-running with '-force-detailed-loop-check' to rule out false positives.\n " );
437
+
379
438
if (assert_mode && counter > 0 )
380
439
log_error (" Found %d problems in 'check -assert'.\n " , counter);
381
440
}
0 commit comments