2323#include " kernel/utils.h"
2424#include " kernel/celltypes.h"
2525#include " kernel/timinginfo.h"
26+ #include < optional>
2627
2728USING_YOSYS_NAMESPACE
2829PRIVATE_NAMESPACE_BEGIN
@@ -587,6 +588,7 @@ void break_scc(RTLIL::Module *module)
587588 auto id = it->second ;
588589 auto r = ids_seen.insert (id);
589590 cell->attributes .erase (it);
591+ // Cut exactly one representative cell per SCC id.
590592 if (!r.second )
591593 continue ;
592594 for (auto &c : cell->connections_ ) {
@@ -710,8 +712,6 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
710712
711713 SigMap sigmap (module );
712714
713- dict<SigBit, pool<IdString>> bit_drivers, bit_users;
714- TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
715715 dict<IdString, std::vector<IdString>> box_ports;
716716
717717 for (auto cell : module ->cells ()) {
@@ -750,39 +750,100 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
750750 }
751751 }
752752 }
753- else if (!yosys_celltypes.cell_known (cell->type ))
754- continue ;
755-
756- // TODO: Speed up toposort -- we care about box ordering only
757- for (auto conn : cell->connections ()) {
758- if (cell->input (conn.first ))
759- for (auto bit : sigmap (conn.second ))
760- bit_users[bit].insert (cell->name );
761-
762- if (cell->output (conn.first ) && !abc9_flop)
763- for (auto bit : sigmap (conn.second ))
764- bit_drivers[bit].insert (cell->name );
765- }
766- toposort.node (cell->name );
767753 }
768754
769755 if (box_ports.empty ())
770756 return ;
771757
772- for (auto &it : bit_users)
773- if (bit_drivers.count (it.first ))
774- for (auto driver_cell : bit_drivers.at (it.first ))
775- for (auto user_cell : it.second )
776- toposort.edge (driver_cell, user_cell);
758+ // Build the same topo graph for the initial pass and the optional retry.
759+ auto build_toposort = [&](TopoSort<IdString, RTLIL::sort_by_id_str> &toposort) {
760+ dict<SigBit, pool<IdString>> bit_drivers, bit_users;
777761
778- if (ys_debug (1 ))
779- toposort.analyze_loops = true ;
762+ for (auto cell : module ->cells ()) {
763+ if (cell->type .in (ID ($_DFF_N_), ID ($_DFF_P_)))
764+ continue ;
765+ if (cell->has_keep_attr ())
766+ continue ;
780767
781- bool no_loops = toposort.sort ();
768+ auto inst_module = design->module (cell->type );
769+ bool abc9_flop = inst_module && inst_module->get_bool_attribute (ID::abc9_flop);
770+ if (abc9_flop && !dff)
771+ continue ;
772+ if (!(inst_module && inst_module->get_bool_attribute (ID::abc9_box)) && !yosys_celltypes.cell_known (cell->type ))
773+ continue ;
774+
775+ // TODO: Speed up toposort -- we care about box ordering only
776+ for (auto conn : cell->connections ()) {
777+ if (cell->input (conn.first ))
778+ for (auto bit : sigmap (conn.second ))
779+ bit_users[bit].insert (cell->name );
780+
781+ if (cell->output (conn.first ) && !abc9_flop)
782+ for (auto bit : sigmap (conn.second ))
783+ bit_drivers[bit].insert (cell->name );
784+ }
785+ toposort.node (cell->name );
786+ }
787+
788+ // Build producer -> consumer edges on sigmapped nets.
789+ for (auto &it : bit_users)
790+ if (bit_drivers.count (it.first ))
791+ for (auto driver_cell : bit_drivers.at (it.first ))
792+ for (auto user_cell : it.second )
793+ toposort.edge (driver_cell, user_cell);
794+ if (ys_debug (1 ))
795+ toposort.analyze_loops = true ;
796+ return toposort.sort ();
797+ };
798+
799+ // Build TopoSort in a container, as we may need to conditionally rebuild it on retry.
800+ std::optional<TopoSort<IdString, RTLIL::sort_by_id_str>> toposort;
801+ toposort.emplace ();
802+ bool no_loops = build_toposort (toposort.value ());
803+
804+ // Fallback for residual loops after SCC cutting: insert additional
805+ // breakers on non-box loop cells, then re-run toposort checks.
806+ if (!no_loops) {
807+ SigSpec I, O;
808+ pool<IdString> broken_cells;
809+
810+ for (auto &loop : toposort.value ().loops )
811+ for (auto cell_name : loop) {
812+ // Loop reports can overlap; cut each cell at most once.
813+ if (!broken_cells.insert (cell_name).second )
814+ continue ;
815+ auto cell = module ->cell (cell_name);
816+ log_assert (cell);
817+ auto inst_module = design->module (cell->type );
818+ if (inst_module && inst_module->get_bool_attribute (ID::abc9_box))
819+ continue ;
820+ for (auto &c : cell->connections_ ) {
821+ if (c.second .is_fully_const ()) continue ;
822+ if (cell->output (c.first )) {
823+ Wire *w = module ->addWire (NEW_ID, GetSize (c.second ));
824+ I.append (w);
825+ O.append (c.second );
826+ c.second = w;
827+ }
828+ }
829+ }
830+
831+ if (!I.empty ()) {
832+ auto cell = module ->addCell (NEW_ID, ID ($__ABC9_SCC_BREAKER));
833+ log_assert (GetSize (I) == GetSize (O));
834+ cell->setParam (ID::WIDTH, GetSize (I));
835+ cell->setPort (ID::I, std::move (I));
836+ cell->setPort (ID::O, std::move (O));
837+
838+ // Rebuild topo ordering after inserting the additional breakers.
839+ toposort.emplace ();
840+ no_loops = build_toposort (toposort.value ());
841+ }
842+ }
782843
783844 if (ys_debug (1 )) {
784845 unsigned i = 0 ;
785- for (auto &it : toposort.loops ) {
846+ for (auto &it : toposort.value (). loops ) {
786847 log (" loop %d\n " , i++);
787848 for (auto cell_name : it) {
788849 auto cell = module ->cell (cell_name);
@@ -806,7 +867,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
806867 TimingInfo timing;
807868
808869 int port_id = 1 , box_count = 0 ;
809- for (auto cell_name : toposort.sorted ) {
870+ for (auto cell_name : toposort.value (). sorted ) {
810871 RTLIL::Cell *cell = module ->cell (cell_name);
811872 log_assert (cell);
812873
0 commit comments