From 924daa65b7bd0d4af1184f364d5ec4beb0177cd5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 16 May 2019 00:09:06 +0200 Subject: [PATCH] WIP: tests for netlist cross ref. --- src/db/db/db.pro | 6 +- src/db/db/dbNetlistCompare.cc | 2 +- src/db/db/dbNetlistCrossReference.cc | 471 +++++++++++++++ src/db/db/dbNetlistCrossReference.h | 194 +++++++ src/db/unit_tests/dbNetlistCompareTests.cc | 58 ++ .../laybasic/layNetlistCrossReferenceModel.cc | 36 +- .../laybasic/layNetlistCrossReferenceModel.h | 539 +----------------- 7 files changed, 754 insertions(+), 552 deletions(-) create mode 100644 src/db/db/dbNetlistCrossReference.cc create mode 100644 src/db/db/dbNetlistCrossReference.h diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 1556c253a..32614a4c6 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -176,7 +176,8 @@ SOURCES = \ dbNetlistCompare.cc \ dbNetlistReader.cc \ dbNetlistSpiceReader.cc \ - gsiDeclDbNetlistCompare.cc + gsiDeclDbNetlistCompare.cc \ + dbNetlistCrossReference.cc HEADERS = \ dbArray.h \ @@ -317,7 +318,8 @@ HEADERS = \ gsiDeclDbHelpers.h \ dbNetlistCompare.h \ dbNetlistReader.h \ - dbNetlistSpiceReader.h + dbNetlistSpiceReader.h \ + dbNetlistCrossReference.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 344f9e1b5..801101980 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -1772,7 +1772,7 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const } if (mp_logger) { - mp_logger->begin_netlist (a, b); + mp_logger->end_netlist (a, b); } return good; diff --git a/src/db/db/dbNetlistCrossReference.cc b/src/db/db/dbNetlistCrossReference.cc new file mode 100644 index 000000000..0034519a9 --- /dev/null +++ b/src/db/db/dbNetlistCrossReference.cc @@ -0,0 +1,471 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 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 +{ + per_circuit_data_iterator i = m_per_circuit_data.find (circuits); + if (i == m_per_circuit_data.end ()) { + return 0; + } else { + return & i->second; + } +} + +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 +{ + 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::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::pair (0, 0); +} + +namespace { + +struct CircuitsCompareByName +{ + bool operator() (const std::pair &a, const std::pair &b) + { + if ((a.first == 0) != (b.first == 0)) { + return (a.first == 0) > (b.first == 0); + } + if (a.first != 0 && a.first->name () != b.first->name ()) { + return a.first->name () < b.first->name (); + } + if ((a.second == 0) != (b.second == 0)) { + return (a.second == 0) > (b.second == 0); + } + if (a.second != 0 && a.second->name () != b.second->name ()) { + return a.second->name () < b.second->name (); + } + return false; + } +}; + +} + +void +NetlistCrossReference::end_netlist (const db::Netlist *, const db::Netlist *) +{ + m_circuits.reserve (m_per_circuit_data.size ()); + for (per_circuit_data_iterator i = begin_per_circuit_data (); i != end_per_circuit_data (); ++i) { + m_circuits.push_back (i->first); + } + + std::sort (m_circuits.begin (), m_circuits.end (), CircuitsCompareByName ()); +} + +void +NetlistCrossReference::device_class_mismatch (const db::DeviceClass *, const db::DeviceClass *) +{ + // .. nothing yet .. +} + +void +NetlistCrossReference::establish_pair (const db::Circuit *a, const db::Circuit *b) +{ + mp_per_circuit_data = & m_per_circuit_data [std::make_pair (a, b)]; + + 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) +{ + mp_per_circuit_data->nets.push_back (NetPairData (a, b, status)); + 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) +{ + mp_per_circuit_data->devices.push_back (DevicePairData (a, b, status)); + 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) +{ + mp_per_circuit_data->pins.push_back (PinPairData (a, b, status)); + 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) +{ + mp_per_circuit_data->subcircuits.push_back (SubCircuitPairData (a, b, status)); + if (a) { + m_other_subcircuit [a] = b; + } + if (b) { + m_other_subcircuit [b] = a; + } +} + +void +NetlistCrossReference::begin_circuit (const db::Circuit *a, const db::Circuit *b) +{ + m_current_circuits = std::pair (a, b); + establish_pair (a, b); +} + +void +NetlistCrossReference::end_circuit (const db::Circuit *, const db::Circuit *, bool matching) +{ + mp_per_circuit_data->status = matching ? Match : NoMatch; + + // @@@ TODO: sort per-circuit data vectors by name? + + m_current_circuits = std::pair (0, 0); + mp_per_circuit_data = 0; +} + +void +NetlistCrossReference::circuit_skipped (const db::Circuit *a, const db::Circuit *b) +{ + establish_pair (a, b); + mp_per_circuit_data->status = Skipped; +} + +void +NetlistCrossReference::circuit_mismatch (const db::Circuit *a, const db::Circuit *b) +{ + establish_pair (a, b); + mp_per_circuit_data->status = Mismatch; +} + +void +NetlistCrossReference::match_nets (const db::Net *a, const db::Net *b) +{ + establish_pair (a, b, Match); +} + +void +NetlistCrossReference::match_ambiguous_nets (const db::Net *a, const db::Net *b) +{ + establish_pair (a, b, MatchWithWarning); +} + +void +NetlistCrossReference::net_mismatch (const db::Net *a, const db::Net *b) +{ + establish_pair (a, b, Mismatch); +} + +void +NetlistCrossReference::match_devices (const db::Device *a, const db::Device *b) +{ + establish_pair (a, b, Match); +} + +void +NetlistCrossReference::match_devices_with_different_parameters (const db::Device *a, const db::Device *b) +{ + establish_pair (a, b, MatchWithWarning); +} + +void +NetlistCrossReference::match_devices_with_different_device_classes (const db::Device *a, const db::Device *b) +{ + establish_pair (a, b, MatchWithWarning); +} + +void +NetlistCrossReference::device_mismatch (const db::Device *a, const db::Device *b) +{ + establish_pair (a, b, Mismatch); +} + +void +NetlistCrossReference::match_pins (const db::Pin *a, const db::Pin *b) +{ + establish_pair (a, b, Match); +} + +void +NetlistCrossReference::pin_mismatch (const db::Pin *a, const db::Pin *b) +{ + establish_pair (a, b, Mismatch); +} + +void +NetlistCrossReference::match_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b) +{ + establish_pair (a, b, Match); +} + +void +NetlistCrossReference::subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b) +{ + establish_pair (a, b, Mismatch); +} + +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 ()) { + + 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)); + } +} + +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 ()) { + + const db::Pin *pb = ipb->second; + std::map::iterator b = p2r_b.find (pb); + if (b != p2r_b.end ()) { + prb = b->second; + // remove the entry so we won't find it again + p2r_b.erase (b); + break; + } + + } + + 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)); + } +} + +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->begin_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->begin_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 ()) { + + 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 ()) { + + 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); + } + + } + + } + + 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)); + } +} + +void +NetlistCrossReference::build_per_net_info (const std::pair &nets, PerNetData &data) const +{ + if (! nets.second) { + init_data_from_single (nets.first, data, true); + } else if (! nets.first) { + init_data_from_single (nets.second, data, false); + } else if (nets.first) { + build_terminal_refs (nets, data); + build_pin_refs (nets, data); + build_subcircuit_pin_refs (nets, data); + } +} + +} diff --git a/src/db/db/dbNetlistCrossReference.h b/src/db/db/dbNetlistCrossReference.h new file mode 100644 index 000000000..b20eb887c --- /dev/null +++ b/src/db/db/dbNetlistCrossReference.h @@ -0,0 +1,194 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 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 + +*/ + + +#ifndef HDR_dbNetlistCrossReference +#define HDR_dbNetlistCrossReference + +#include "dbCommon.h" +#include "dbNetlistCompare.h" +#include "tlObject.h" + +#include +#include + +namespace db +{ + +/** + * @brief The NetlistCrossReference class + * + * This class stores the results of a netlist compare in a form which is compatible + * with the netlist cross-reference model. The intention of this class is twofold: + * persisting the results of a netlist compare and display in the netlist browser. + */ +class DB_PUBLIC NetlistCrossReference + : public db::NetlistCompareLogger, public tl::Object +{ +public: + NetlistCrossReference (); + ~NetlistCrossReference (); + + enum Status { + None = 0, + Match, // objects are paired and match + NoMatch, // objects are paired, but don't match + Skipped, // objects are skipped + MatchWithWarning, // objects are paired and match, but with warning (i.e. ambiguous nets) + Mismatch // objects are not paired + }; + + struct NetPairData + { + NetPairData (const db::Net *a, const db::Net *b, Status s) : pair (a, b), status (s) { } + NetPairData () : pair (0, 0), status (None) { } + + std::pair pair; + Status status; + }; + + struct DevicePairData + { + DevicePairData (const db::Device *a, const db::Device *b, Status s) : pair (a, b), status (s) { } + DevicePairData () : pair (0, 0), status (None) { } + + std::pair pair; + Status status; + }; + + struct PinPairData + { + PinPairData (const db::Pin *a, const db::Pin *b, Status s) : pair (a, b), status (s) { } + PinPairData () : pair (0, 0), status (None) { } + + std::pair pair; + Status status; + }; + + struct SubCircuitPairData + { + SubCircuitPairData (const db::SubCircuit *a, const db::SubCircuit *b, Status s) : pair (a, b), status (s) { } + SubCircuitPairData () : pair (0, 0), status (None) { } + + std::pair pair; + Status status; + }; + + struct PerCircuitData + { + PerCircuitData () : status (None) { } + + Status status; + std::vector nets; + std::vector devices; + std::vector pins; + std::vector subcircuits; + }; + + struct PerNetData + { + std::vector > terminals; + std::vector > pins; + std::vector > subcircuit_pins; + }; + + virtual void begin_netlist (const db::Netlist *a, const db::Netlist *b); + virtual void end_netlist (const db::Netlist *a, const db::Netlist *b); + virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b); + virtual void begin_circuit (const db::Circuit *a, const db::Circuit *b); + virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching); + virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b); + virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b); + virtual void match_nets (const db::Net *a, const db::Net *b); + virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b); + virtual void net_mismatch (const db::Net *a, const db::Net *b); + virtual void match_devices (const db::Device *a, const db::Device *b); + virtual void match_devices_with_different_parameters (const db::Device *a, const db::Device *b); + virtual void match_devices_with_different_device_classes (const db::Device *a, const db::Device *b); + virtual void device_mismatch (const db::Device *a, const db::Device *b); + virtual void match_pins (const db::Pin *a, const db::Pin *b); + virtual void pin_mismatch (const db::Pin *a, const db::Pin *b); + virtual void match_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b); + virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b); + + size_t circuit_count () const + { + return m_per_circuit_data.size (); + } + + typedef std::map, PerCircuitData>::const_iterator per_circuit_data_iterator; + + per_circuit_data_iterator begin_per_circuit_data () const + { + return m_per_circuit_data.begin (); + } + + per_circuit_data_iterator end_per_circuit_data () const + { + return m_per_circuit_data.end (); + } + + const PerCircuitData *per_circuit_data_for (const std::pair &circuits) const; + + typedef std::vector >::const_iterator circuits_iterator; + + circuits_iterator begin_circuits () const + { + return m_circuits.begin (); + } + + circuits_iterator end_circuits () const + { + return m_circuits.end (); + } + + const db::Net *other_net_for (const db::Net *net) const; + const PerNetData *per_net_data_for (const std::pair &nets) const; + +private: + tl::weak_ptr mp_netlist_a, mp_netlist_b; + std::vector > m_circuits; + std::map, PerCircuitData> m_per_circuit_data; + mutable std::map, PerNetData> m_per_net_data; + std::map m_other_circuit; + std::map m_other_net; + std::map m_other_device; + std::map m_other_pin; + std::map m_other_subcircuit; + std::pair m_current_circuits; + PerCircuitData *mp_per_circuit_data; + + void establish_pair (const db::Circuit *a, const db::Circuit *b); + void establish_pair (const db::Net *a, const db::Net *b, Status status); + void establish_pair (const db::Device *a, const db::Device *b, Status status); + void establish_pair (const db::Pin *a, const db::Pin *b, Status status); + void establish_pair (const db::SubCircuit *a, const db::SubCircuit *b, Status status); + + void build_per_net_info (const std::pair &nets, PerNetData &data) const; + void build_subcircuit_pin_refs (const std::pair &nets, PerNetData &data) const; + void build_pin_refs (const std::pair &nets, PerNetData &data) const; + void build_terminal_refs (const std::pair &nets, PerNetData &data) const; +}; + +} + +#endif diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index bd6476908..9d793f8a6 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -23,6 +23,7 @@ #include "tlUnitTest.h" #include "dbNetlistDeviceClasses.h" #include "dbNetlistCompare.h" +#include "dbNetlistCrossReference.h" class NetlistCompareTestLogger : public db::NetlistCompareLogger @@ -162,6 +163,53 @@ private: } }; +std::string xref_status2s (db::NetlistCrossReference::Status status) +{ + if (status == db::NetlistCrossReference::Match) { + return "Match"; + } else if (status == db::NetlistCrossReference::Mismatch) { + return "Mismatch"; + } else if (status == db::NetlistCrossReference::NoMatch) { + return "NoMatch"; + } else if (status == db::NetlistCrossReference::MatchWithWarning) { + return "MatchWithWarning"; + } else if (status == db::NetlistCrossReference::Skipped) { + return "Skipped"; + } else { + return "None"; + } +} + +template +std::string name_of (const Obj *obj) +{ + return obj ? obj->name () : std::string ("(null)"); +} + +template +std::string expanded_name_of (const Obj *obj) +{ + return obj ? obj->expanded_name () : std::string ("(null)"); +} + +std::string xref2s (const db::NetlistCrossReference &xref) +{ + std::string s; + + for (db::NetlistCrossReference::circuits_iterator c = xref.begin_circuits (); c != xref.end_circuits (); ++c) { + + const db::NetlistCrossReference::PerCircuitData *pcd = xref.per_circuit_data_for (*c); + tl_assert (pcd != 0); + + s += name_of (c->first) + ":" + name_of (c->second) + " [" + xref_status2s (pcd->status) + "]:\n"; + + //@@@ + + } + + return s; +} + static void prep_nl (db::Netlist &nl, const char *str) { db::DeviceClass *dc; @@ -358,6 +406,16 @@ TEST(1_SimpleInverter) "end_circuit INV INV MATCH" ); EXPECT_EQ (good, true); + + db::NetlistCrossReference xref; + db::NetlistComparer comp_xref (&xref); + + good = comp_xref.compare (&nl1, &nl2); + + EXPECT_EQ (xref2s (xref), + "INV:INV [Match]:\n" + ); + EXPECT_EQ (good, true); } TEST(1_SimpleInverterMatchedDeviceClasses) diff --git a/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc b/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc index 8feda7e4c..2a4f01255 100644 --- a/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc +++ b/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc @@ -26,8 +26,8 @@ namespace lay { -NetlistCrossReferenceModel::NetlistCrossReferenceModel (db::NetlistCrossReference *cross_ref) - : mp_cross_ref (cross_ref) +NetlistCrossReferenceModel::NetlistCrossReferenceModel (const db::NetlistCrossReference *cross_ref) + : mp_cross_ref (const_cast (cross_ref)) { // .. nothing yet .. } @@ -79,7 +79,7 @@ template struct DataGetter; template <> struct DataGetter { - typedef typename std::vector >::const_iterator iterator_type; + typedef typename std::vector::const_iterator iterator_type; iterator_type begin (const db::NetlistCrossReference::PerCircuitData &data) const { return data.nets.begin (); } iterator_type end (const db::NetlistCrossReference::PerCircuitData &data) const { return data.nets.end (); } }; @@ -87,7 +87,7 @@ struct DataGetter template <> struct DataGetter { - typedef typename std::vector >::const_iterator iterator_type; + typedef typename std::vector::const_iterator iterator_type; iterator_type begin (const db::NetlistCrossReference::PerCircuitData &data) const { return data.devices.begin (); } iterator_type end (const db::NetlistCrossReference::PerCircuitData &data) const { return data.devices.end (); } }; @@ -95,7 +95,7 @@ struct DataGetter template <> struct DataGetter { - typedef typename std::vector >::const_iterator iterator_type; + typedef typename std::vector::const_iterator iterator_type; iterator_type begin (const db::NetlistCrossReference::PerCircuitData &data) const { return data.subcircuits.begin (); } iterator_type end (const db::NetlistCrossReference::PerCircuitData &data) const { return data.subcircuits.end (); } }; @@ -114,7 +114,7 @@ static IndexedNetlistModel::circuit_pair get_parent_of (const Pair &pair, const iterator_type b = getter_type ().begin (c->second); iterator_type e = getter_type ().end (c->second); for (iterator_type j = b; j != e; ++j) { - cache.insert (std::make_pair (*j, c->first)); + cache.insert (std::make_pair (j->pair, c->first)); } } @@ -149,7 +149,7 @@ IndexedNetlistModel::net_pair NetlistCrossReferenceModel::net_from_index (const { const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits); tl_assert (data != 0); - return data->nets [index]; + return data->nets [index].pair; } const db::Net *NetlistCrossReferenceModel::second_net_for (const db::Net *first) const @@ -182,21 +182,21 @@ IndexedNetlistModel::device_pair NetlistCrossReferenceModel::device_from_index ( { const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits); tl_assert (data != 0); - return data->devices [index]; + return data->devices [index].pair; } IndexedNetlistModel::pin_pair NetlistCrossReferenceModel::pin_from_index (const circuit_pair &circuits, size_t index) const { const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits); tl_assert (data != 0); - return data->pins [index]; + return data->pins [index].pair; } IndexedNetlistModel::subcircuit_pair NetlistCrossReferenceModel::subcircuit_from_index (const circuit_pair &circuits, size_t index) const { const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits); tl_assert (data != 0); - return data->subcircuits [index]; + return data->subcircuits [index].pair; } template @@ -207,7 +207,7 @@ static size_t get_index_of (const Pair &pair, Iter begin, Iter end, std::mappair, index)); } i = cache.find (pair); @@ -220,7 +220,19 @@ static size_t get_index_of (const Pair &pair, Iter begin, Iter end, std::mapbegin_circuits (), mp_cross_ref->end_circuits (), m_index_of_circuits); + typename std::map::iterator i = m_index_of_circuits.find (circuits); + if (i != m_index_of_circuits.end ()) { + + size_t index = 0; + for (db::NetlistCrossReference::circuits_iterator j = mp_cross_ref->begin_circuits (); j != mp_cross_ref->end_circuits (); ++j, ++index) { + m_index_of_circuits.insert (std::make_pair (*j, index)); + } + + i = m_index_of_circuits.find (circuits); + tl_assert (i != m_index_of_circuits.end ()); + } + + return i->second; } size_t NetlistCrossReferenceModel::net_index (const net_pair &nets) const diff --git a/src/laybasic/laybasic/layNetlistCrossReferenceModel.h b/src/laybasic/laybasic/layNetlistCrossReferenceModel.h index 3db0bbdfe..3d65696af 100644 --- a/src/laybasic/laybasic/layNetlistCrossReferenceModel.h +++ b/src/laybasic/laybasic/layNetlistCrossReferenceModel.h @@ -27,542 +27,7 @@ #include "laybasicCommon.h" #include "layIndexedNetlistModel.h" -#include "tlObject.h" -#include "dbNetlistCompare.h" // @@@ - -// @@@ -namespace db -{ - -class NetlistCrossReference - : public db::NetlistCompareLogger, public tl::Object -{ -public: - NetlistCrossReference (); - - enum status { - None = 0, - Match, // objects are paired and match - NoMatch, // objects are paired, but don't match - Skipped, // objects are skipped - MatchWithWarning, // objects are paired and match, but with warning (i.e. ambiguous nets) - Mismatch // objects are not paired - }; - - struct PerCircuitData - { - std::vector > nets; - std::vector > devices; - std::vector > pins; - std::vector > subcircuits; - }; - - struct PerNetData - { - std::vector > terminals; - std::vector > pins; - std::vector > subcircuit_pins; - }; - - virtual void begin_netlist (const db::Netlist *a, const db::Netlist *b); - virtual void end_netlist (const db::Netlist *a, const db::Netlist *b); - virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b); - virtual void begin_circuit (const db::Circuit *a, const db::Circuit *b); - virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching); - virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b); - virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b); - virtual void match_nets (const db::Net *a, const db::Net *b); - virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b); - virtual void net_mismatch (const db::Net *a, const db::Net *b); - virtual void match_devices (const db::Device *a, const db::Device *b); - virtual void match_devices_with_different_parameters (const db::Device *a, const db::Device *b); - virtual void match_devices_with_different_device_classes (const db::Device *a, const db::Device *b); - virtual void device_mismatch (const db::Device *a, const db::Device *b); - virtual void match_pins (const db::Pin *a, const db::Pin *b); - virtual void pin_mismatch (const db::Pin *a, const db::Pin *b); - virtual void match_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b); - virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b); - - size_t circuit_count () const - { - return m_per_circuit_data.size (); - } - - typedef std::map, PerCircuitData>::const_iterator per_circuit_data_iterator; - - per_circuit_data_iterator begin_per_circuit_data () const - { - return m_per_circuit_data.begin (); - } - - per_circuit_data_iterator end_per_circuit_data () const - { - return m_per_circuit_data.end (); - } - - const PerCircuitData *per_circuit_data_for (const std::pair &circuits) const - { - per_circuit_data_iterator i = m_per_circuit_data.find (circuits); - if (i == m_per_circuit_data.end ()) { - return 0; - } else { - return & i->second; - } - } - - typedef std::vector >::const_iterator circuits_iterator; - - circuits_iterator begin_circuits () const - { - return m_circuits.begin (); - } - - circuits_iterator end_circuits () const - { - return m_circuits.end (); - } - - const db::Net *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 PerNetData *per_net_data_for (const std::pair &nets) const - { - 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; - } - -private: - tl::weak_ptr mp_netlist_a, mp_netlist_b; - std::vector > m_circuits; - std::map, PerCircuitData> m_per_circuit_data; - mutable std::map, PerNetData> m_per_net_data; - std::map m_other_circuit; - std::map m_other_net; - std::map m_other_device; - std::map m_other_pin; - std::map m_other_subcircuit; - std::pair m_current_circuits; - std::map, status> m_circuit_status; - std::map, status> m_net_status; - std::map, status> m_device_status; - std::map, status> m_pin_status; - std::map, status> m_subcircuit_status; - PerCircuitData *mp_per_circuit_data; - - void establish_pair (const db::Circuit *a, const db::Circuit *b); - void establish_pair (const db::Net *a, const db::Net *b); - void establish_pair (const db::Device *a, const db::Device *b); - void establish_pair (const db::Pin *a, const db::Pin *b); - void establish_pair (const db::SubCircuit *a, const db::SubCircuit *b); - - void build_per_net_info (const std::pair &nets, PerNetData &data) const; - void build_subcircuit_pin_refs (const std::pair &nets, PerNetData &data) const; - void build_pin_refs (const std::pair &nets, PerNetData &data) const; - void build_terminal_refs (const std::pair &nets, PerNetData &data) const; -}; - -void -NetlistCrossReference::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::pair (0, 0); -} - -void -NetlistCrossReference::end_netlist (const db::Netlist *, const db::Netlist *) -{ - m_circuits.reserve (m_per_circuit_data.size ()); - for (per_circuit_data_iterator i = begin_per_circuit_data (); i != end_per_circuit_data (); ++i) { - m_circuits.push_back (i->first); - } - - - // @@@ TODO: sort m_circuits by name? -} - -void -NetlistCrossReference::device_class_mismatch (const db::DeviceClass *, const db::DeviceClass *) -{ - // .. nothing yet .. -} - -void -NetlistCrossReference::establish_pair (const db::Circuit *a, const db::Circuit *b) -{ - mp_per_circuit_data = & m_per_circuit_data [std::make_pair (a, b)]; - - 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) -{ - mp_per_circuit_data->nets.push_back (std::make_pair (a, b)); - 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) -{ - mp_per_circuit_data->devices.push_back (std::make_pair (a, b)); - 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) -{ - mp_per_circuit_data->pins.push_back (std::make_pair (a, b)); - 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) -{ - mp_per_circuit_data->subcircuits.push_back (std::make_pair (a, b)); - if (a) { - m_other_subcircuit [a] = b; - } - if (b) { - m_other_subcircuit [b] = a; - } -} - -void -NetlistCrossReference::begin_circuit (const db::Circuit *a, const db::Circuit *b) -{ - m_current_circuits = std::pair (a, b); - establish_pair (a, b); -} - -void -NetlistCrossReference::end_circuit (const db::Circuit *, const db::Circuit *, bool matching) -{ - if (matching) { - m_circuit_status [m_current_circuits] = Match; - } - - // @@@ TODO: sort per-circuit data vectors by name? - - m_current_circuits = std::pair (0, 0); - mp_per_circuit_data = 0; -} - -void -NetlistCrossReference::circuit_skipped (const db::Circuit *a, const db::Circuit *b) -{ - establish_pair (a, b); - m_circuit_status [std::pair (a, b)] = Skipped; -} - -void -NetlistCrossReference::circuit_mismatch (const db::Circuit *a, const db::Circuit *b) -{ - establish_pair (a, b); - m_circuit_status [std::pair (a, b)] = Mismatch; -} - -void -NetlistCrossReference::match_nets (const db::Net *a, const db::Net *b) -{ - establish_pair (a, b); - m_net_status [std::pair (a, b)] = Match; -} - -void -NetlistCrossReference::match_ambiguous_nets (const db::Net *a, const db::Net *b) -{ - establish_pair (a, b); - m_net_status [std::pair (a, b)] = MatchWithWarning; -} - -void -NetlistCrossReference::net_mismatch (const db::Net *a, const db::Net *b) -{ - establish_pair (a, b); - m_net_status [std::pair (a, b)] = Mismatch; -} - -void -NetlistCrossReference::match_devices (const db::Device *a, const db::Device *b) -{ - establish_pair (a, b); - m_device_status [std::pair (a, b)] = Match; -} - -void -NetlistCrossReference::match_devices_with_different_parameters (const db::Device *a, const db::Device *b) -{ - establish_pair (a, b); - m_device_status [std::pair (a, b)] = MatchWithWarning; -} - -void -NetlistCrossReference::match_devices_with_different_device_classes (const db::Device *a, const db::Device *b) -{ - establish_pair (a, b); - m_device_status [std::pair (a, b)] = MatchWithWarning; -} - -void -NetlistCrossReference::device_mismatch (const db::Device *a, const db::Device *b) -{ - establish_pair (a, b); - m_device_status [std::pair (a, b)] = Mismatch; -} - -void -NetlistCrossReference::match_pins (const db::Pin *a, const db::Pin *b) -{ - establish_pair (a, b); - m_pin_status [std::pair (a, b)] = Match; -} - -void -NetlistCrossReference::pin_mismatch (const db::Pin *a, const db::Pin *b) -{ - establish_pair (a, b); - m_pin_status [std::pair (a, b)] = Mismatch; -} - -void -NetlistCrossReference::match_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b) -{ - establish_pair (a, b); - m_subcircuit_status [std::pair (a, b)] = Match; -} - -void -NetlistCrossReference::subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b) -{ - establish_pair (a, b); - m_subcircuit_status [std::pair (a, b)] = Mismatch; -} - -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 ()) { - - 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)); - } -} - -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 ()) { - - const db::Pin *pb = ipb->second; - std::map::iterator b = p2r_b.find (pb); - if (b != p2r_b.end ()) { - prb = b->second; - // remove the entry so we won't find it again - p2r_b.erase (b); - break; - } - - } - - 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)); - } -} - -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->begin_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->begin_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 ()) { - - 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 ()) { - - 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); - } - - } - - } - - 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)); - } -} - -void -NetlistCrossReference::build_per_net_info (const std::pair &nets, PerNetData &data) const -{ - if (! nets.second) { - init_data_from_single (nets.first, data, true); - } else if (! nets.first) { - init_data_from_single (nets.second, data, false); - } else if (nets.first) { - build_terminal_refs (nets, data); - build_pin_refs (nets, data); - build_subcircuit_pin_refs (nets, data); - } -} - -} -// @@@ +#include "dbNetlistCrossReference.h" namespace lay { @@ -574,7 +39,7 @@ class LAYBASIC_PUBLIC NetlistCrossReferenceModel : public lay::IndexedNetlistModel { public: - NetlistCrossReferenceModel (db::NetlistCrossReference *cross_ref); + NetlistCrossReferenceModel (const db::NetlistCrossReference *cross_ref); virtual bool is_single () const { return false; }