/* KLayout Layout Viewer Copyright (C) 2006-2023 Matthias Koefferlein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "dbNetlistCrossReference.h" namespace db { NetlistCrossReference::NetlistCrossReference () { // .. nothing yet .. } NetlistCrossReference::~NetlistCrossReference () { // .. nothing yet .. } const NetlistCrossReference::PerCircuitData * NetlistCrossReference::per_circuit_data_for (const std::pair &circuits) const { std::map::const_iterator i; if (circuits.first) { i = m_data_refs.find (circuits.first); if (i != m_data_refs.end ()) { return i->second; } } if (circuits.second) { i = m_data_refs.find (circuits.second); if (i != m_data_refs.end ()) { return i->second; } } return 0; } const db::Pin * NetlistCrossReference::other_pin_for (const db::Pin *pin) const { std::map::const_iterator i = m_other_pin.find (pin); if (i != m_other_pin.end ()) { return i->second; } else { return 0; } } const db::Device * NetlistCrossReference::other_device_for (const db::Device *device) const { std::map::const_iterator i = m_other_device.find (device); if (i != m_other_device.end ()) { return i->second; } else { return 0; } } const db::SubCircuit * NetlistCrossReference::other_subcircuit_for (const db::SubCircuit *subcircuit) const { std::map::const_iterator i = m_other_subcircuit.find (subcircuit); if (i != m_other_subcircuit.end ()) { return i->second; } else { return 0; } } const db::Circuit * NetlistCrossReference::other_circuit_for (const db::Circuit *circuit) const { std::map::const_iterator i = m_other_circuit.find (circuit); if (i != m_other_circuit.end ()) { return i->second; } else { return 0; } } const db::Net * NetlistCrossReference::other_net_for (const db::Net *net) const { std::map::const_iterator i = m_other_net.find (net); if (i != m_other_net.end ()) { return i->second; } else { return 0; } } const NetlistCrossReference::PerNetData * NetlistCrossReference::per_net_data_for (const std::pair &nets) const { if (! nets.first && ! nets.second) { return 0; } std::map, PerNetData>::iterator i = m_per_net_data.find (nets); if (i == m_per_net_data.end ()) { i = m_per_net_data.insert (std::make_pair (nets, PerNetData ())).first; build_per_net_info (nets, i->second); } return &i->second; } void NetlistCrossReference::clear () { mp_netlist_a.reset (0); mp_netlist_b.reset (0); m_circuits.clear (); m_per_circuit_data.clear (); m_data_refs.clear (); m_per_net_data.clear (); m_other_circuit.clear (); m_other_net.clear (); m_other_device.clear (); m_other_pin.clear (); m_other_subcircuit.clear (); m_current_circuits.first = 0; m_current_circuits.second = 0; mp_per_circuit_data = 0; } void NetlistCrossReference::gen_begin_netlist (const db::Netlist *a, const db::Netlist *b) { mp_netlist_a.reset (const_cast (a)); mp_netlist_b.reset (const_cast (b)); m_current_circuits = std::make_pair ((const db::Circuit *)0, (const db::Circuit *)0); } namespace { static int string_value_compare (const std::string &a, const std::string &b) { return a == b ? 0 : (a < b ? -1 : 1); } template struct by_name_value_compare { int operator() (const Obj &a, const Obj &b) const { return string_value_compare (a.name (), b.name ()); } }; template struct by_expanded_name_value_compare { int operator() (const Obj &a, const Obj &b) const { return string_value_compare (a.expanded_name (), b.expanded_name ()); } }; struct ByDeviceClassNameCompare { int operator() (const db::Device &a, const db::Device &b) const { if ((a.device_class () == 0) != (b.device_class () == 0)) { return a.device_class () == 0 ? -1 : 1; } if (a.device_class () == 0) { return 0; } else { return string_value_compare (a.device_class ()->name (), b.device_class ()->name ()); } } }; struct ByRefCircuitNameCompare { int operator() (const db::SubCircuit &a, const db::SubCircuit &b) const { if ((a.circuit_ref () == 0) != (b.circuit_ref () == 0)) { return a.circuit_ref () == 0 ? -1 : 1; } if (a.circuit_ref () == 0) { return 0; } else { return string_value_compare (a.circuit_ref ()->name (), b.circuit_ref ()->name ()); } } }; template struct net_object_compare; template <> struct net_object_compare { int operator() (const db::NetTerminalRef &a, const db::NetTerminalRef &b) const { int ct = by_expanded_name_value_compare () (*a.device (), *b.device ()); if (ct == 0) { return (a.terminal_id () != b.terminal_id () ? (a.terminal_id () < b.terminal_id () ? -1 : 1) : 0); } else { return ct; } } }; template <> struct net_object_compare { int operator() (const db::NetSubcircuitPinRef &a, const db::NetSubcircuitPinRef &b) const { int ct = by_expanded_name_value_compare () (*a.subcircuit (), *b.subcircuit ()); if (ct == 0) { return by_expanded_name_value_compare () (*a.pin (), *b.pin ()); } else { return ct; } } }; template <> struct net_object_compare { int operator() (const db::NetPinRef &a, const db::NetPinRef &b) const { return by_expanded_name_value_compare () (*a.pin (), *b.pin ()); } }; template struct two_pointer_compare { int operator() (const Obj *a, const Obj *b) const { if ((a == 0) != (b == 0)) { return (a == 0) > (b == 0) ? -1 : 1; } if (a != 0) { return ValueCompare () (*a, *b); } else { return 0; } } }; template struct two_pair_compare { bool operator() (const std::pair &a, const std::pair &b) { int ct = two_pointer_compare () (a.first, b.first); if (ct != 0) { return ct < 0; } return two_pointer_compare () (a.second, b.second) < 0; } }; template struct pair_data_compare { bool operator () (const PairData &a, const PairData &b) const { return two_pair_compare () (a.pair, b.pair); } }; struct CircuitsCompareByName : public two_pair_compare > { // .. nothing yet .. }; struct SortNetTerminals : public two_pair_compare > { // .. nothing yet .. }; struct SortNetPins : public two_pair_compare > { // .. nothing yet .. }; struct SortNetSubCircuitPins : public two_pair_compare > { // .. nothing yet .. }; } void NetlistCrossReference::sort_netlist () { std::sort (m_circuits.begin (), m_circuits.end (), CircuitsCompareByName ()); } void NetlistCrossReference::gen_end_netlist (const db::Netlist *, const db::Netlist *) { // .. nothing yet .. } void NetlistCrossReference::establish_pair (const db::Circuit *a, const db::Circuit *b) { m_circuits.push_back (std::make_pair (a, b)); m_per_circuit_data.push_back (PerCircuitData ()); mp_per_circuit_data = & m_per_circuit_data.back (); m_data_refs [a] = mp_per_circuit_data; m_data_refs [b] = mp_per_circuit_data; if (a) { m_other_circuit [a] = b; } if (b) { m_other_circuit [b] = a; } } void NetlistCrossReference::establish_pair (const db::Net *a, const db::Net *b, Status status, const std::string &msg) { mp_per_circuit_data->nets.push_back (NetPairData (a, b, status, msg)); if (a) { m_other_net [a] = b; } if (b) { m_other_net [b] = a; } } void NetlistCrossReference::establish_pair (const db::Device *a, const db::Device *b, Status status, const std::string &msg) { mp_per_circuit_data->devices.push_back (DevicePairData (a, b, status, msg)); if (a) { m_other_device [a] = b; } if (b) { m_other_device [b] = a; } } void NetlistCrossReference::establish_pair (const db::Pin *a, const db::Pin *b, Status status, const std::string &msg) { mp_per_circuit_data->pins.push_back (PinPairData (a, b, status, msg)); if (a) { m_other_pin [a] = b; } if (b) { m_other_pin [b] = a; } } void NetlistCrossReference::establish_pair (const db::SubCircuit *a, const db::SubCircuit *b, Status status, const std::string &msg) { mp_per_circuit_data->subcircuits.push_back (SubCircuitPairData (a, b, status, msg)); if (a) { m_other_subcircuit [a] = b; } if (b) { m_other_subcircuit [b] = a; } } void NetlistCrossReference::gen_begin_circuit (const db::Circuit *a, const db::Circuit *b) { m_current_circuits = std::pair (a, b); establish_pair (a, b); } void NetlistCrossReference::sort_circuit () { std::stable_sort (mp_per_circuit_data->devices.begin (), mp_per_circuit_data->devices.end (), pair_data_compare ()); std::stable_sort (mp_per_circuit_data->subcircuits.begin (), mp_per_circuit_data->subcircuits.end (), pair_data_compare ()); std::stable_sort (mp_per_circuit_data->pins.begin (), mp_per_circuit_data->pins.end (), pair_data_compare > ()); std::stable_sort (mp_per_circuit_data->nets.begin (), mp_per_circuit_data->nets.end (), pair_data_compare > ()); } void NetlistCrossReference::gen_end_circuit (const db::Circuit *, const db::Circuit *, Status status, const std::string &msg) { mp_per_circuit_data->status = status; mp_per_circuit_data->msg = msg; m_current_circuits = std::make_pair((const db::Circuit *)0, (const db::Circuit *)0); mp_per_circuit_data = 0; } void NetlistCrossReference::gen_log_entry (Severity severity, const std::string &msg) { if (mp_per_circuit_data) { mp_per_circuit_data->log_entries.push_back (LogEntryData (severity, msg)); } else { m_other_log_entries.push_back (LogEntryData (severity, msg)); } } void NetlistCrossReference::gen_nets (const db::Net *a, const db::Net *b, Status status, const std::string &msg) { establish_pair (a, b, status, msg); } void NetlistCrossReference::gen_devices (const db::Device *a, const db::Device *b, Status status, const std::string &msg) { establish_pair (a, b, status, msg); } void NetlistCrossReference::gen_pins (const db::Pin *a, const db::Pin *b, Status status, const std::string &msg) { establish_pair (a, b, status, msg); } void NetlistCrossReference::gen_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b, Status status, const std::string &msg) { establish_pair (a, b, status, msg); } static void init_data_from_single (const db::Net *net, NetlistCrossReference::PerNetData &data, bool first) { data.pins.reserve (net->pin_count ()); for (db::Net::const_pin_iterator i = net->begin_pins (); i != net->end_pins (); ++i) { if (! first) { data.pins.push_back (std::make_pair ((const db::NetPinRef *) 0, i.operator-> ())); } else { data.pins.push_back (std::make_pair (i.operator-> (), (const db::NetPinRef *) 0)); } } data.subcircuit_pins.reserve (net->subcircuit_pin_count ()); for (db::Net::const_subcircuit_pin_iterator i = net->begin_subcircuit_pins (); i != net->end_subcircuit_pins (); ++i) { if (! first) { data.subcircuit_pins.push_back (std::make_pair ((const db::NetSubcircuitPinRef *) 0, i.operator-> ())); } else { data.subcircuit_pins.push_back (std::make_pair (i.operator-> (), (const db::NetSubcircuitPinRef *) 0)); } } data.terminals.reserve (net->terminal_count ()); for (db::Net::const_terminal_iterator i = net->begin_terminals (); i != net->end_terminals (); ++i) { if (! first) { data.terminals.push_back (std::make_pair ((const db::NetTerminalRef *) 0, i.operator-> ())); } else { data.terminals.push_back (std::make_pair (i.operator-> (), (const db::NetTerminalRef *) 0)); } } } void NetlistCrossReference::build_terminal_refs (const std::pair &nets, PerNetData &data) const { std::map, const db::NetTerminalRef *> d2t_a, d2t_b; for (db::Net::const_terminal_iterator i = nets.first->begin_terminals (); i != nets.first->end_terminals (); ++i) { d2t_a.insert (std::make_pair (std::make_pair (i->device (), i->terminal_id ()), i.operator-> ())); } for (db::Net::const_terminal_iterator i = nets.second->begin_terminals (); i != nets.second->end_terminals (); ++i) { d2t_b.insert (std::make_pair (std::make_pair (i->device (), i->terminal_id ()), i.operator-> ())); } for (std::map, const db::NetTerminalRef *>::const_iterator a = d2t_a.begin (); a != d2t_a.end (); ++a) { const db::Device *da = a->first.first; const db::NetTerminalRef *pb = 0; std::map::const_iterator idb = m_other_device.find (da); if (idb != m_other_device.end () && idb->second) { const db::Device *db = idb->second; // we have a device pair - now we need to match the terminals: we do so on the basis // of normalized terminal ID's size_t atid = da->device_class ()->normalize_terminal_id (a->first.second); const std::vector &termdefs_b = db->device_class ()->terminal_definitions (); for (std::vector::const_iterator t = termdefs_b.begin (); t != termdefs_b.end (); ++t) { if (atid == db->device_class ()->normalize_terminal_id (t->id ())) { std::map, const db::NetTerminalRef *>::iterator b = d2t_b.find (std::make_pair (db, t->id ())); if (b != d2t_b.end ()) { pb = b->second; // remove the entry so we won't find it again d2t_b.erase (b); break; } } } } data.terminals.push_back (std::make_pair (a->second, pb)); } for (std::map, const db::NetTerminalRef *>::const_iterator b = d2t_b.begin (); b != d2t_b.end (); ++b) { data.terminals.push_back (std::make_pair ((const db::NetTerminalRef *) 0, b->second)); } std::stable_sort (data.terminals.begin (), data.terminals.end (), SortNetTerminals ()); } void NetlistCrossReference::build_pin_refs (const std::pair &nets, PerNetData &data) const { std::map p2r_a, p2r_b; for (db::Net::const_pin_iterator i = nets.first->begin_pins (); i != nets.first->end_pins (); ++i) { p2r_a.insert (std::make_pair (i->pin (), i.operator-> ())); } for (db::Net::const_pin_iterator i = nets.second->begin_pins (); i != nets.second->end_pins (); ++i) { p2r_b.insert (std::make_pair (i->pin (), i.operator-> ())); } for (std::map::const_iterator a = p2r_a.begin (); a != p2r_a.end (); ++a) { const db::Pin *pa = a->first; const db::NetPinRef *prb = 0; std::map::const_iterator ipb = m_other_pin.find (pa); if (ipb != m_other_pin.end () && ipb->second) { std::map::iterator b = p2r_b.find (ipb->second); if (b != p2r_b.end ()) { prb = b->second; // remove the entry so we won't find it again p2r_b.erase (b); } } data.pins.push_back (std::make_pair (a->second, prb)); } for (std::map::const_iterator b = p2r_b.begin (); b != p2r_b.end (); ++b) { data.pins.push_back (std::make_pair ((const db::NetPinRef *) 0, b->second)); } std::stable_sort (data.pins.begin (), data.pins.end (), SortNetPins ()); } void NetlistCrossReference::build_subcircuit_pin_refs (const std::pair &nets, PerNetData &data) const { std::map, const db::NetSubcircuitPinRef *> s2t_a, s2t_b; for (db::Net::const_subcircuit_pin_iterator i = nets.first->begin_subcircuit_pins (); i != nets.first->end_subcircuit_pins (); ++i) { s2t_a.insert (std::make_pair (std::make_pair (i->subcircuit (), i->pin_id ()), i.operator-> ())); } for (db::Net::const_subcircuit_pin_iterator i = nets.second->begin_subcircuit_pins (); i != nets.second->end_subcircuit_pins (); ++i) { s2t_b.insert (std::make_pair (std::make_pair (i->subcircuit (), i->pin_id ()), i.operator-> ())); } for (std::map, const db::NetSubcircuitPinRef *>::const_iterator a = s2t_a.begin (); a != s2t_a.end (); ++a) { const db::SubCircuit *sa = a->first.first; const db::NetSubcircuitPinRef *pb = 0; std::map::const_iterator isb = m_other_subcircuit.find (sa); if (isb != m_other_subcircuit.end () && isb->second) { const db::SubCircuit *sb = isb->second; // we have a subcircuit pair - now we need to match the pins: we do so on the basis // pin matching const db::Pin *pa = sa->circuit_ref ()->pin_by_id (a->first.second); std::map::const_iterator ipb = m_other_pin.find (pa); if (ipb != m_other_pin.end () && ipb->second) { std::map, const db::NetSubcircuitPinRef *>::iterator b = s2t_b.find (std::make_pair (sb, ipb->second->id ())); if (b != s2t_b.end ()) { pb = b->second; // remove the entry so we won't find it again s2t_b.erase (b); } } // Fallback for swappable pins: match based on the subcircuit alone if (! pb) { std::map, const db::NetSubcircuitPinRef *>::iterator b = s2t_b.lower_bound (std::make_pair (sb, 0)); if (b != s2t_b.end () && b->first.first == sb) { pb = b->second; // remove the entry so we won't find it again s2t_b.erase (b); } } } data.subcircuit_pins.push_back (std::make_pair (a->second, pb)); } for (std::map, const db::NetSubcircuitPinRef *>::const_iterator b = s2t_b.begin (); b != s2t_b.end (); ++b) { data.subcircuit_pins.push_back (std::make_pair ((const db::NetSubcircuitPinRef *) 0, b->second)); } std::stable_sort (data.subcircuit_pins.begin (), data.subcircuit_pins.end (), SortNetSubCircuitPins ()); } void NetlistCrossReference::build_per_net_info (const std::pair &nets, PerNetData &data) const { if (! nets.first && ! nets.second) { // .. nothing .. } else if (! nets.second) { init_data_from_single (nets.first, data, true); } else if (! nets.first) { init_data_from_single (nets.second, data, false); } else { build_terminal_refs (nets, data); build_pin_refs (nets, data); build_subcircuit_pin_refs (nets, data); } } }