klayout/src/db/db/dbNetlistCrossReference.cc

659 lines
20 KiB
C++

/*
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<const db::Circuit *, const db::Circuit *> &circuits) const
{
std::map<const db::Circuit *, PerCircuitData *>::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 db::Pin *, const db::Pin *>::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 db::Device *, const db::Device *>::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 db::SubCircuit *, const db::SubCircuit *>::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 db::Circuit *, const db::Circuit *>::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 db::Net *, const db::Net *>::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<const db::Net *, const db::Net *> &nets) const
{
if (! nets.first && ! nets.second) {
return 0;
}
std::map<std::pair<const db::Net *, const db::Net *>, 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 <db::Netlist *> (a));
mp_netlist_b.reset (const_cast <db::Netlist *> (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 <class Obj>
struct by_name_value_compare
{
int operator() (const Obj &a, const Obj &b) const
{
return string_value_compare (a.name (), b.name ());
}
};
template <class Obj>
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 <class Obj>
struct net_object_compare;
template <>
struct net_object_compare<db::NetTerminalRef>
{
int operator() (const db::NetTerminalRef &a, const db::NetTerminalRef &b) const
{
int ct = by_expanded_name_value_compare<db::Device> () (*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<db::NetSubcircuitPinRef>
{
int operator() (const db::NetSubcircuitPinRef &a, const db::NetSubcircuitPinRef &b) const
{
int ct = by_expanded_name_value_compare<db::SubCircuit> () (*a.subcircuit (), *b.subcircuit ());
if (ct == 0) {
return by_expanded_name_value_compare<db::Pin> () (*a.pin (), *b.pin ());
} else {
return ct;
}
}
};
template <>
struct net_object_compare<db::NetPinRef>
{
int operator() (const db::NetPinRef &a, const db::NetPinRef &b) const
{
return by_expanded_name_value_compare<db::Pin> () (*a.pin (), *b.pin ());
}
};
template <class Obj, class ValueCompare>
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 <class Obj, class ValueCompare>
struct two_pair_compare
{
bool operator() (const std::pair<const Obj *, const Obj *> &a, const std::pair<const Obj *, const Obj *> &b)
{
int ct = two_pointer_compare<Obj, ValueCompare> () (a.first, b.first);
if (ct != 0) {
return ct < 0;
}
return two_pointer_compare<Obj, ValueCompare> () (a.second, b.second) < 0;
}
};
template <class PairData, class ValueCompare>
struct pair_data_compare
{
bool operator () (const PairData &a, const PairData &b) const
{
return two_pair_compare<typename PairData::object_type, ValueCompare> () (a.pair, b.pair);
}
};
struct CircuitsCompareByName
: public two_pair_compare<db::Circuit, by_name_value_compare<db::Circuit> >
{
// .. nothing yet ..
};
struct SortNetTerminals
: public two_pair_compare<db::NetTerminalRef, net_object_compare<db::NetTerminalRef> >
{
// .. nothing yet ..
};
struct SortNetPins
: public two_pair_compare<db::NetPinRef, net_object_compare<db::NetPinRef> >
{
// .. nothing yet ..
};
struct SortNetSubCircuitPins
: public two_pair_compare<db::NetSubcircuitPinRef, net_object_compare<db::NetSubcircuitPinRef> >
{
// .. 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<const db::Circuit *, const db::Circuit *> (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<DevicePairData, ByDeviceClassNameCompare> ());
std::stable_sort (mp_per_circuit_data->subcircuits.begin (), mp_per_circuit_data->subcircuits.end (), pair_data_compare<SubCircuitPairData, ByRefCircuitNameCompare> ());
std::stable_sort (mp_per_circuit_data->pins.begin (), mp_per_circuit_data->pins.end (), pair_data_compare<PinPairData, by_name_value_compare<db::Pin> > ());
std::stable_sort (mp_per_circuit_data->nets.begin (), mp_per_circuit_data->nets.end (), pair_data_compare<NetPairData, by_name_value_compare<db::Net> > ());
}
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<const db::Net *, const db::Net *> &nets, PerNetData &data) const
{
std::map<std::pair<const db::Device *, size_t>, 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<std::pair<const db::Device *, size_t>, 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 db::Device *, const db::Device *>::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<db::DeviceTerminalDefinition> &termdefs_b = db->device_class ()->terminal_definitions ();
for (std::vector<db::DeviceTerminalDefinition>::const_iterator t = termdefs_b.begin (); t != termdefs_b.end (); ++t) {
if (atid == db->device_class ()->normalize_terminal_id (t->id ())) {
std::map<std::pair<const db::Device *, size_t>, 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<std::pair<const db::Device *, size_t>, 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<const db::Net *, const db::Net *> &nets, PerNetData &data) const
{
std::map<const db::Pin *, const db::NetPinRef *> 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 Pin *, const db::NetPinRef *>::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 db::Pin *, const db::Pin *>::const_iterator ipb = m_other_pin.find (pa);
if (ipb != m_other_pin.end () && ipb->second) {
std::map<const Pin *, const db::NetPinRef *>::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 Pin *, const db::NetPinRef *>::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<const db::Net *, const db::Net *> &nets, PerNetData &data) const
{
std::map<std::pair<const db::SubCircuit *, size_t>, 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<std::pair<const db::SubCircuit *, size_t>, 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 db::SubCircuit *, const db::SubCircuit *>::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 db::Pin *, const db::Pin *>::const_iterator ipb = m_other_pin.find (pa);
if (ipb != m_other_pin.end () && ipb->second) {
std::map<std::pair<const db::SubCircuit *, size_t>, 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<std::pair<const db::SubCircuit *, size_t>, 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<std::pair<const db::SubCircuit *, size_t>, 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<const db::Net *, const db::Net *> &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);
}
}
}