@@ -59,6 +59,12 @@ struct CheckPass : public Pass {
5959 log (" -assert\n " );
6060 log (" produce a runtime error if any problems are found in the current design\n " );
6161 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 " );
6268 }
6369 void execute (std::vector<std::string> args, RTLIL::Design *design) override
6470 {
@@ -68,6 +74,8 @@ struct CheckPass : public Pass {
6874 bool mapped = false ;
6975 bool allow_tbuf = false ;
7076 bool assert_mode = false ;
77+ bool force_detailed_loop_check = false ;
78+ bool suggest_detail = false ;
7179
7280 size_t argidx;
7381 for (argidx = 1 ; argidx < args.size (); argidx++) {
@@ -91,6 +99,10 @@ struct CheckPass : public Pass {
9199 assert_mode = true ;
92100 continue ;
93101 }
102+ if (args[argidx] == " -force-detailed-loop-check" ) {
103+ force_detailed_loop_check = true ;
104+ continue ;
105+ }
94106 break ;
95107 }
96108 extra_args (args, argidx, design);
@@ -154,9 +166,10 @@ struct CheckPass : public Pass {
154166 struct CircuitEdgesDatabase : AbstractCellEdgesDatabase {
155167 TopoSort<std::pair<RTLIL::IdString, int >> &topo;
156168 SigMap sigmap;
169+ bool force_detail;
157170
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) {}
160173
161174 void add_edge (RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit,
162175 RTLIL::IdString to_port, int to_bit, int ) override {
@@ -171,10 +184,41 @@ struct CheckPass : public Pass {
171184 topo.edge (std::make_pair (from.wire ->name , from.offset ), std::make_pair (to.wire ->name , to.offset ));
172185 }
173186
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)
176208 return true ;
177209
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+
178222 // We don't have accurate cell edges, do the fallback of all input-output pairs
179223 for (auto &conn : cell->connections ()) {
180224 if (cell->input (conn.first ))
@@ -189,12 +233,15 @@ struct CheckPass : public Pass {
189233 topo.edge (std::make_pair (cell->name , -1 ),
190234 std::make_pair (bit.wire ->name , bit.offset ));
191235 }
192- return true ;
236+
237+ // Return false to signify the fallback
238+ return false ;
193239 }
194240 };
195241
196- CircuitEdgesDatabase edges_db (topo, sigmap);
242+ CircuitEdgesDatabase edges_db (topo, sigmap, force_detailed_loop_check );
197243
244+ pool<Cell *> coarsened_cells;
198245 for (auto cell : module ->cells ())
199246 {
200247 if (mapped && cell->type .begins_with (" $" ) && design->module (cell->type ) == nullptr ) {
@@ -225,8 +272,10 @@ struct CheckPass : public Pass {
225272 }
226273
227274 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+ }
230279 }
231280
232281 pool<SigBit> init_bits;
@@ -284,10 +333,10 @@ struct CheckPass : public Pass {
284333 for (auto &loop : topo.loops ) {
285334 string message = stringf (" found logic loop in module %s:\n " , log_id (module ));
286335
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.
291340 SigBit prev;
292341 for (auto it = loop.rbegin (); it != loop.rend (); it++)
293342 if (it->second != -1 ) { // skip the fallback helper nodes
@@ -316,10 +365,10 @@ struct CheckPass : public Pass {
316365 SigBit edge_to = sigmap (cell->getPort (to_port))[to_bit];
317366
318367 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,
320369 log_id (to_port), to_bit);
321370 if (nhits == HITS_LIMIT)
322- message += " ...\n " ;
371+ message += " ...\n " ;
323372 }
324373 };
325374
@@ -334,9 +383,16 @@ struct CheckPass : public Pass {
334383 std::string src_attr = driver->get_src_attribute ();
335384 driver_src = stringf (" source: %s" , src_attr.c_str ());
336385 }
386+
337387 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+ }
340396
341397 if (wire->name .isPublic ()) {
342398 std::string wire_src;
@@ -376,6 +432,9 @@ struct CheckPass : public Pass {
376432
377433 log (" Found and reported %d problems.\n " , counter);
378434
435+ if (suggest_detail)
436+ log (" Consider re-running with '-force-detailed-loop-check' to rule out false positives.\n " );
437+
379438 if (assert_mode && counter > 0 )
380439 log_error (" Found %d problems in 'check -assert'.\n " , counter);
381440 }
0 commit comments