mirror of https://github.com/KLayout/klayout.git
WIP: netlist comparer
This commit is contained in:
parent
e424a88c90
commit
25b7ab9dab
|
|
@ -12,6 +12,94 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
class NetlistCompareLogger
|
||||
{
|
||||
public:
|
||||
NetlistCompareLogger () { }
|
||||
virtual ~NetlistCompareLogger () { }
|
||||
|
||||
/**
|
||||
* @brief Begin logging for netlist a and b
|
||||
*/
|
||||
virtual void begin_netlist (const db::Netlist * /*a*/, const db::Netlist * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief End logging for netlist a and b
|
||||
*/
|
||||
virtual void end_netlist (const db::Netlist * /*a*/, const db::Netlist * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Begin logging for circuit a and b
|
||||
*/
|
||||
virtual void begin_circuit (const db::Circuit * /*a*/, const db::Circuit * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief End logging for circuit a and b
|
||||
*/
|
||||
virtual void end_circuit (const db::Circuit * /*a*/, const db::Circuit * /*b*/, bool /*matching*/) { }
|
||||
|
||||
/**
|
||||
* @brief There is a circuit mismatch
|
||||
* "a" is null if there is no match for b and vice versa.
|
||||
*/
|
||||
virtual void circuit_mismatch (const db::Circuit * /*a*/, const db::Circuit * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Nets a and b match exactly
|
||||
*/
|
||||
virtual void match_nets (const db::Net * /*a*/, const db::Net * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Nets a and b are matched, but are ambiguous
|
||||
* Other nets might also match with a and also with b. Matching this a and b is
|
||||
* an arbitrary decision.
|
||||
*/
|
||||
virtual void match_ambiguous_nets (const db::Net * /*a*/, const db::Net * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Net a or b doesn't match
|
||||
* "a" is null if there is no match for b and vice versa.
|
||||
*/
|
||||
virtual void net_mismatch (const db::Net * /*a*/, const db::Net * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Devices a and b match exactly
|
||||
*/
|
||||
virtual void match_devices (const db::Device * /*a*/, const db::Device * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Devices a and b are matched but have different parameters
|
||||
*/
|
||||
virtual void match_devices_with_different_parameters (const db::Device * /*a*/, const db::Device * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Devices a and b are matched but have different device classes
|
||||
*/
|
||||
virtual void match_devices_with_different_device_classes (const db::Device * /*a*/, const db::Device * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Pins a and b of the current circuit are matched
|
||||
*/
|
||||
virtual void match_pins (const db::Pin * /*a*/, const db::Pin * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Pin a or b doesn't match
|
||||
* "a" is null if there is no match for b and vice versa.
|
||||
*/
|
||||
virtual void pin_mismatch (const db::Pin * /*a*/, const db::Pin * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Subcircuits a and b match exactly
|
||||
*/
|
||||
virtual void match_subcircuits (const db::SubCircuit * /*a*/, const db::SubCircuit * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief SubCircuit a or b doesn't match
|
||||
* "a" is null if there is no match for b and vice versa.
|
||||
*/
|
||||
virtual void subcircuit_mismatch (const db::SubCircuit * /*a*/, const db::SubCircuit * /*b*/) { }
|
||||
};
|
||||
|
||||
struct DeviceCompare
|
||||
{
|
||||
bool operator() (const db::Device *d1, const db::Device *d2) const
|
||||
|
|
@ -215,15 +303,6 @@ namespace std
|
|||
namespace db
|
||||
{
|
||||
|
||||
static std::string net2string (const db::Net *net)
|
||||
{
|
||||
if (! net) {
|
||||
return "(null)";
|
||||
} else {
|
||||
return net->expanded_name ();
|
||||
}
|
||||
}
|
||||
|
||||
class NetDeviceGraph
|
||||
{
|
||||
public:
|
||||
|
|
@ -286,7 +365,7 @@ public:
|
|||
return m_nodes.end ();
|
||||
}
|
||||
|
||||
size_t derive_node_identities (size_t net_index, NetDeviceGraph &other)
|
||||
size_t derive_node_identities (size_t net_index, NetDeviceGraph &other, NetlistCompareLogger *logger)
|
||||
{
|
||||
size_t added = 0;
|
||||
|
||||
|
|
@ -346,7 +425,7 @@ public:
|
|||
}
|
||||
|
||||
if (count_other == 1) {
|
||||
confirm_identity (*this, begin () + ec->second.second, other, other.begin () + ec_other->second.second);
|
||||
confirm_identity (*this, begin () + ec->second.second, other, other.begin () + ec_other->second.second, logger);
|
||||
++added;
|
||||
more.push_back (ec->second.second);
|
||||
}
|
||||
|
|
@ -366,10 +445,10 @@ public:
|
|||
return added;
|
||||
}
|
||||
|
||||
static void confirm_identity (db::NetDeviceGraph &g1, db::NetDeviceGraph::node_iterator s1, db::NetDeviceGraph &g2, db::NetDeviceGraph::node_iterator s2)
|
||||
static void confirm_identity (db::NetDeviceGraph &g1, db::NetDeviceGraph::node_iterator s1, db::NetDeviceGraph &g2, db::NetDeviceGraph::node_iterator s2, db::NetlistCompareLogger *logger)
|
||||
{
|
||||
if (tl::verbosity () >= 30) {
|
||||
tl::log << tl::to_string (tr ("Net identity confirmed: ")) << net2string (s1->net ()) << " - " << net2string (s2->net ());
|
||||
if (logger) {
|
||||
logger->match_nets (s1->net (), s2->net ());
|
||||
}
|
||||
g1.identify (s1 - g1.begin (), s2 - g2.begin ());
|
||||
g2.identify (s2 - g2.begin (), s1 - g1.begin ());
|
||||
|
|
@ -382,7 +461,75 @@ private:
|
|||
std::map<const db::Net *, size_t> m_net_index;
|
||||
};
|
||||
|
||||
static bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2)
|
||||
class NetlistComparer
|
||||
{
|
||||
public:
|
||||
NetlistComparer (NetlistCompareLogger *logger)
|
||||
: mp_logger (logger)
|
||||
{ }
|
||||
|
||||
bool compare (const db::Netlist *a, const db::Netlist *b) const
|
||||
{
|
||||
bool good = true;
|
||||
|
||||
std::map<std::string, std::pair<const db::Circuit *, const db::Circuit *> > name2circuits;
|
||||
|
||||
for (db::Netlist::const_circuit_iterator i = a->begin_circuits (); i != a->end_circuits (); ++i) {
|
||||
name2circuits[i->name ()].first = i.operator-> ();
|
||||
}
|
||||
|
||||
for (db::Netlist::const_circuit_iterator i = b->begin_circuits (); i != b->end_circuits (); ++i) {
|
||||
name2circuits[i->name ()].second = i.operator-> ();
|
||||
}
|
||||
|
||||
if (mp_logger) {
|
||||
mp_logger->begin_netlist (a, b);
|
||||
}
|
||||
|
||||
for (std::map<std::string, std::pair<const db::Circuit *, const db::Circuit *> >::const_iterator i = name2circuits.begin (); i != name2circuits.end (); ++i) {
|
||||
if (! i->second.first || ! i->second.second) {
|
||||
good = false;
|
||||
if (mp_logger) {
|
||||
mp_logger->circuit_mismatch (i->second.first, i->second.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (db::Netlist::const_bottom_up_circuit_iterator c = a->begin_bottom_up (); c != a->end_bottom_up (); ++c) {
|
||||
|
||||
std::map<std::string, std::pair<const db::Circuit *, const db::Circuit *> >::const_iterator i = name2circuits.find ((*c)->name ());
|
||||
tl_assert (i != name2circuits.end ());
|
||||
|
||||
if (i->second.first && i->second.second) {
|
||||
if (mp_logger) {
|
||||
mp_logger->begin_circuit (i->second.first, i->second.second);
|
||||
}
|
||||
bool g = compare_circuits (i->second.first, i->second.second);
|
||||
if (! g) {
|
||||
good = false;
|
||||
}
|
||||
if (mp_logger) {
|
||||
mp_logger->end_circuit (i->second.first, i->second.second, g);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (mp_logger) {
|
||||
mp_logger->begin_netlist (a, b);
|
||||
}
|
||||
|
||||
return good;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2) const;
|
||||
|
||||
NetlistCompareLogger *mp_logger;
|
||||
};
|
||||
|
||||
bool
|
||||
NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2) const
|
||||
{
|
||||
db::NetDeviceGraph g1, g2;
|
||||
|
||||
|
|
@ -394,7 +541,7 @@ static bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2)
|
|||
size_t new_identities = 0;
|
||||
for (db::NetDeviceGraph::node_iterator i1 = g1.begin (); i1 != g1.end (); ++i1) {
|
||||
if (i1->has_other ()) {
|
||||
new_identities += g1.derive_node_identities (i1 - g1.begin (), g2);
|
||||
new_identities += g1.derive_node_identities (i1 - g1.begin (), g2, mp_logger);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -435,7 +582,7 @@ static bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2)
|
|||
|
||||
if (seeds == 1) {
|
||||
// found a candidate - a single node with the same edges
|
||||
db::NetDeviceGraph::confirm_identity (g1, s1, g2, s2);
|
||||
db::NetDeviceGraph::confirm_identity (g1, s1, g2, s2, mp_logger);
|
||||
++new_identities;
|
||||
} else if (seeds > 1) {
|
||||
ambiguous = true;
|
||||
|
|
@ -457,7 +604,7 @@ static bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2)
|
|||
|
||||
if (seeds == 1) {
|
||||
// found a candidate - a single node with the same edges
|
||||
db::NetDeviceGraph::confirm_identity (g1, s1, g2, s2);
|
||||
db::NetDeviceGraph::confirm_identity (g1, s1, g2, s2, mp_logger);
|
||||
++new_identities;
|
||||
} else if (seeds > 1) {
|
||||
ambiguous = true;
|
||||
|
|
@ -475,13 +622,13 @@ static bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2)
|
|||
tl::error << tr ("Unassigned in netlist A:");
|
||||
for (db::NetDeviceGraph::node_iterator i = g1.begin (); i != g1.end (); ++i) {
|
||||
if (! i->has_other ()) {
|
||||
tl::error << " " << net2string (i->net ());
|
||||
tl::error << " " << i->net ()->expanded_name ();
|
||||
}
|
||||
}
|
||||
tl::error << tr ("Unassigned in netlist B:");
|
||||
for (db::NetDeviceGraph::node_iterator i = g2.begin (); i != g2.end (); ++i) {
|
||||
if (! i->has_other ()) {
|
||||
tl::error << " " << net2string (i->net ());
|
||||
tl::error << " " << i->net ()->expanded_name ();
|
||||
}
|
||||
}
|
||||
// @@@
|
||||
|
|
@ -493,6 +640,112 @@ static bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2)
|
|||
|
||||
}
|
||||
|
||||
class NetlistCompareTestLogger
|
||||
: public db::NetlistCompareLogger
|
||||
{
|
||||
public:
|
||||
NetlistCompareTestLogger () { }
|
||||
|
||||
virtual void begin_circuit (const db::Circuit *a, const db::Circuit *b)
|
||||
{
|
||||
m_texts.push_back ("begin_circuit " + circuit2str (a) + " " + circuit2str (b));
|
||||
}
|
||||
|
||||
virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching)
|
||||
{
|
||||
m_texts.push_back ("end_circuit " + circuit2str (a) + " " + circuit2str (b) + " " + (matching ? "MATCH" : "NOMATCH"));
|
||||
}
|
||||
|
||||
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b)
|
||||
{
|
||||
m_texts.push_back ("circuit_mismatch " + circuit2str (a) + " " + circuit2str (b));
|
||||
}
|
||||
|
||||
virtual void match_nets (const db::Net *a, const db::Net *b)
|
||||
{
|
||||
m_texts.push_back ("match_nets " + net2str (a) + " " + net2str (b));
|
||||
}
|
||||
|
||||
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b)
|
||||
{
|
||||
m_texts.push_back ("match_ambiguous_nets " + net2str (a) + " " + net2str (b));
|
||||
}
|
||||
|
||||
virtual void net_mismatch (const db::Net *a, const db::Net *b)
|
||||
{
|
||||
m_texts.push_back ("net_mismatch " + net2str (a) + " " + net2str (b));
|
||||
}
|
||||
|
||||
virtual void match_devices (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
m_texts.push_back ("match_devices " + device2str (a) + " " + device2str (b));
|
||||
}
|
||||
|
||||
virtual void match_devices_with_different_parameters (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
m_texts.push_back ("match_devices_with_different_parameters " + device2str (a) + " " + device2str (b));
|
||||
}
|
||||
|
||||
virtual void match_devices_with_different_device_classes (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
m_texts.push_back ("match_devices_with_different_device_classes " + device2str (a) + " " + device2str (b));
|
||||
}
|
||||
|
||||
virtual void match_pins (const db::Pin *a, const db::Pin *b)
|
||||
{
|
||||
m_texts.push_back ("match_pins " + pin2str (a) + " " + pin2str (b));
|
||||
}
|
||||
|
||||
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b)
|
||||
{
|
||||
m_texts.push_back ("pin_mismatch " + pin2str (a) + " " + pin2str (b));
|
||||
}
|
||||
|
||||
virtual void match_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b)
|
||||
{
|
||||
m_texts.push_back ("match_subcircuits " + subcircuit2str (a) + " " + subcircuit2str (b));
|
||||
}
|
||||
|
||||
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b)
|
||||
{
|
||||
m_texts.push_back ("subcircuit_mismatch " + subcircuit2str (a) + " " + subcircuit2str (b));
|
||||
}
|
||||
|
||||
std::string text () const
|
||||
{
|
||||
return tl::join (m_texts, "\n");
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_texts;
|
||||
|
||||
std::string circuit2str (const db::Circuit *x) const
|
||||
{
|
||||
return x ? x->name () : "(null)";
|
||||
}
|
||||
|
||||
std::string device2str (const db::Device *x) const
|
||||
{
|
||||
return x ? x->expanded_name () : "(null)";
|
||||
}
|
||||
|
||||
std::string net2str (const db::Net *x) const
|
||||
{
|
||||
return x ? x->expanded_name () : "(null)";
|
||||
}
|
||||
|
||||
std::string pin2str (const db::Pin *x) const
|
||||
{
|
||||
return x ? x->expanded_name () : "(null)";
|
||||
}
|
||||
|
||||
std::string subcircuit2str (const db::SubCircuit *x) const
|
||||
{
|
||||
return x ? x->expanded_name () : "(null)";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TEST(1)
|
||||
{
|
||||
const char *nls2 =
|
||||
|
|
@ -603,5 +856,13 @@ TEST(1)
|
|||
nl1.from_string (nls1);
|
||||
nl2.from_string (nls2);
|
||||
|
||||
db::compare_circuits (nl1.circuit_by_name ("RINGO"), nl2.circuit_by_name ("RINGO"));
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
EXPECT_EQ (logger.text (),
|
||||
""
|
||||
);
|
||||
EXPECT_EQ (good, true);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue