mirror of https://github.com/KLayout/klayout.git
WIP: netlist compare deployed for netlist extractors
Some enhancements were required: * Clusters left over from joined clusters must not be turned into nets: this leads to dummy nets. * null Nets can happen as targets of edges. Don't assert in this case but treat null nets as identical for both netlists. * Don't resolve ambiguous nets if there are options to do this non-ambiguously. * logger can be null * Added compare_netlists to dbTestSupport
This commit is contained in:
parent
f06d435b05
commit
2452c72d2d
|
|
@ -267,6 +267,13 @@ local_cluster<T>::clear ()
|
|||
m_global_nets.clear ();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
local_cluster<T>::empty () const
|
||||
{
|
||||
return m_global_nets.empty () && m_shapes.empty ();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
local_cluster<T>::set_global_nets (const global_nets &gn)
|
||||
|
|
|
|||
|
|
@ -218,6 +218,11 @@ public:
|
|||
*/
|
||||
void clear ();
|
||||
|
||||
/**
|
||||
* @brief Returns true if the cluster is empty
|
||||
*/
|
||||
bool empty () const;
|
||||
|
||||
/**
|
||||
* @brief Adds a shape with the given layer to the cluster
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -415,6 +415,10 @@ public:
|
|||
NetDeviceGraphNode (const db::Net *net, DeviceCategorizer &device_categorizer, CircuitCategorizer &circuit_categorizer, const std::map<const db::Circuit *, CircuitMapper> *circuit_map, const CircuitPinMapper *pin_map)
|
||||
: mp_net (net), m_other_net_index (std::numeric_limits<size_t>::max ())
|
||||
{
|
||||
if (! net) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::map<const db::Net *, size_t> n2entry;
|
||||
|
||||
for (db::Net::const_subcircuit_pin_iterator i = net->begin_subcircuit_pins (); i != net->end_subcircuit_pins (); ++i) {
|
||||
|
|
@ -648,6 +652,9 @@ public:
|
|||
m_nodes.clear ();
|
||||
m_net_index.clear ();
|
||||
|
||||
// create a dummy node for a null net
|
||||
m_nodes.push_back (NetDeviceGraphNode (0, device_categorizer, circuit_categorizer, circuit_and_pin_mapping, circuit_pin_mapper));
|
||||
|
||||
size_t nets = 0;
|
||||
for (db::Circuit::const_net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) {
|
||||
++nets;
|
||||
|
|
@ -1025,6 +1032,10 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
g1.build (c1, device_categorizer, circuit_categorizer, &circuit_and_pin_mapping, mp_circuit_pin_mapper.get ());
|
||||
g2.build (c2, device_categorizer, circuit_categorizer, 0, mp_circuit_pin_mapper.get ());
|
||||
|
||||
// Match dummy nodes for null nets
|
||||
g1.identify (0, 0);
|
||||
g2.identify (0, 0);
|
||||
|
||||
for (std::vector<std::pair<const Net *, const Net *> >::const_iterator p = net_identity.begin (); p != net_identity.end (); ++p) {
|
||||
size_t ni1 = g1.node_index_for_net (p->first);
|
||||
size_t ni2 = g2.node_index_for_net (p->second);
|
||||
|
|
@ -1069,31 +1080,45 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::log << "checking topological identity ...";
|
||||
#endif
|
||||
// derive new identities through topology
|
||||
|
||||
db::NetDeviceGraph::node_iterator i1 = g1.begin (), i2 = g2.begin ();
|
||||
for ( ; i1 != g1.end () && i2 != g2.end (); ) {
|
||||
// first pass: without ambiguities, second pass: match ambiguous nets
|
||||
for (int pass = 0; pass < 2 && new_identities == 0; ++pass) {
|
||||
|
||||
if (i1->has_other ()) {
|
||||
++i1;
|
||||
} else if (i2->has_other ()) {
|
||||
++i2;
|
||||
} else if (*i1 < *i2) {
|
||||
++i1;
|
||||
} else if (*i2 < *i1) {
|
||||
++i2;
|
||||
} else {
|
||||
// derive new identities through topology
|
||||
|
||||
db::NetDeviceGraph::node_iterator ii1 = i1, ii2 = i2;
|
||||
bool same_as_prev = false;
|
||||
|
||||
++i1;
|
||||
++i2;
|
||||
db::NetDeviceGraph::node_iterator i1 = g1.begin (), i2 = g2.begin ();
|
||||
for ( ; i1 != g1.end () && i2 != g2.end (); ) {
|
||||
|
||||
bool ambiguous = (i1 != g1.end () && *i1 == *ii1) || (i2 != g2.end () && *i2 == *ii2);
|
||||
bool same_as_next = false;
|
||||
|
||||
// found a candidate - a single node with the same edges
|
||||
db::NetDeviceGraph::confirm_identity (g1, ii1, g2, ii2, mp_logger, ambiguous);
|
||||
++new_identities;
|
||||
if (i1->has_other ()) {
|
||||
++i1;
|
||||
} else if (i2->has_other ()) {
|
||||
++i2;
|
||||
} else if (*i1 < *i2) {
|
||||
++i1;
|
||||
} else if (*i2 < *i1) {
|
||||
++i2;
|
||||
} else {
|
||||
|
||||
db::NetDeviceGraph::node_iterator ii1 = i1, ii2 = i2;
|
||||
|
||||
++i1;
|
||||
++i2;
|
||||
|
||||
same_as_next = (i1 != g1.end () && *i1 == *ii1) || (i2 != g2.end () && *i2 == *ii2);
|
||||
|
||||
// found a candidate - a single node with the same edges
|
||||
if (! (same_as_next || same_as_prev) || pass) {
|
||||
db::NetDeviceGraph::confirm_identity (g1, ii1, g2, ii2, mp_logger, same_as_next || same_as_prev);
|
||||
++new_identities;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
same_as_prev = same_as_next;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1111,13 +1136,13 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
// Report missing net assignment
|
||||
|
||||
for (db::NetDeviceGraph::node_iterator i = g1.begin (); i != g1.end (); ++i) {
|
||||
if (! i->has_other ()) {
|
||||
if (! i->has_other () && mp_logger) {
|
||||
mp_logger->net_mismatch (i->net (), 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (db::NetDeviceGraph::node_iterator i = g2.begin (); i != g2.end (); ++i) {
|
||||
if (! i->has_other ()) {
|
||||
if (! i->has_other () && mp_logger) {
|
||||
mp_logger->net_mismatch (0, i->net ());
|
||||
}
|
||||
}
|
||||
|
|
@ -1138,15 +1163,15 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
for (db::NetDeviceGraph::node_iterator i = g1.begin (); i != g1.end (); ++i) {
|
||||
|
||||
const db::Net *net = i->net ();
|
||||
tl_assert (net != 0);
|
||||
|
||||
if (net->pin_count () == 0) {
|
||||
if (! net || net->pin_count () == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! i->has_other ()) {
|
||||
for (db::Net::const_pin_iterator pi = net->begin_pins (); pi != net->end_pins (); ++pi) {
|
||||
mp_logger->pin_mismatch (pi->pin (), 0);
|
||||
if (mp_logger) {
|
||||
mp_logger->pin_mismatch (pi->pin (), 0);
|
||||
}
|
||||
pin_mismatch = true;
|
||||
good = false;
|
||||
}
|
||||
|
|
@ -1160,7 +1185,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
|
||||
if (np != net2pin.end () && np->first == other_net) {
|
||||
|
||||
mp_logger->match_pins (pi->pin (), np->second);
|
||||
if (mp_logger) {
|
||||
mp_logger->match_pins (pi->pin (), np->second);
|
||||
}
|
||||
pin_mapping.map_pin (pi->pin ()->id (), np->second->id ());
|
||||
|
||||
std::multimap<const db::Net *, const db::Pin *>::iterator np_delete = np;
|
||||
|
|
@ -1168,9 +1195,13 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
net2pin.erase (np_delete);
|
||||
|
||||
} else {
|
||||
mp_logger->pin_mismatch (pi->pin (), 0);
|
||||
|
||||
if (mp_logger) {
|
||||
mp_logger->pin_mismatch (pi->pin (), 0);
|
||||
}
|
||||
pin_mismatch = true;
|
||||
good = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1178,7 +1209,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
}
|
||||
|
||||
for (std::multimap<const db::Net *, const db::Pin *>::iterator np = net2pin.begin (); np != net2pin.end (); ++np) {
|
||||
mp_logger->pin_mismatch (0, np->second);
|
||||
if (mp_logger) {
|
||||
mp_logger->pin_mismatch (0, np->second);
|
||||
}
|
||||
pin_mismatch = true;
|
||||
good = false;
|
||||
}
|
||||
|
|
@ -1200,7 +1233,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
}
|
||||
|
||||
if (! mapped) {
|
||||
mp_logger->device_mismatch (d.operator-> (), 0);
|
||||
if (mp_logger) {
|
||||
mp_logger->device_mismatch (d.operator-> (), 0);
|
||||
}
|
||||
good = false;
|
||||
} else {
|
||||
// TODO: report devices which cannot be distiguished topologically?
|
||||
|
|
@ -1228,7 +1263,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
|
||||
if (! mapped || dm == device_map.end () || dm->first != k) {
|
||||
|
||||
mp_logger->device_mismatch (0, d.operator-> ());
|
||||
if (mp_logger) {
|
||||
mp_logger->device_mismatch (0, d.operator-> ());
|
||||
}
|
||||
good = false;
|
||||
|
||||
} else {
|
||||
|
|
@ -1239,14 +1276,20 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
|
||||
if (! dc.equals (dm->second, std::make_pair (d.operator-> (), device_cat))) {
|
||||
if (dm->second.second != device_cat) {
|
||||
mp_logger->match_devices_with_different_device_classes (dm->second.first, d.operator-> ());
|
||||
if (mp_logger) {
|
||||
mp_logger->match_devices_with_different_device_classes (dm->second.first, d.operator-> ());
|
||||
}
|
||||
good = false;
|
||||
} else {
|
||||
mp_logger->match_devices_with_different_parameters (dm->second.first, d.operator-> ());
|
||||
if (mp_logger) {
|
||||
mp_logger->match_devices_with_different_parameters (dm->second.first, d.operator-> ());
|
||||
}
|
||||
good = false;
|
||||
}
|
||||
} else {
|
||||
mp_logger->match_devices (dm->second.first, d.operator-> ());
|
||||
if (mp_logger) {
|
||||
mp_logger->match_devices (dm->second.first, d.operator-> ());
|
||||
}
|
||||
}
|
||||
|
||||
device_map.erase (dm);
|
||||
|
|
@ -1256,7 +1299,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
}
|
||||
|
||||
for (std::multimap<std::vector<std::pair<size_t, size_t> >, std::pair<const db::Device *, size_t> >::const_iterator dm = device_map.begin (); dm != device_map.end (); ++dm) {
|
||||
mp_logger->device_mismatch (dm->second.first, 0);
|
||||
if (mp_logger) {
|
||||
mp_logger->device_mismatch (dm->second.first, 0);
|
||||
}
|
||||
good = false;
|
||||
}
|
||||
|
||||
|
|
@ -1277,7 +1322,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
}
|
||||
|
||||
if (! mapped) {
|
||||
mp_logger->subcircuit_mismatch (sc.operator-> (), 0);
|
||||
if (mp_logger) {
|
||||
mp_logger->subcircuit_mismatch (sc.operator-> (), 0);
|
||||
}
|
||||
good = false;
|
||||
} else if (! k.empty ()) {
|
||||
// TODO: report devices which cannot be distiguished topologically?
|
||||
|
|
@ -1305,7 +1352,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
|
||||
if (! mapped || scm == subcircuit_map.end ()) {
|
||||
|
||||
mp_logger->subcircuit_mismatch (0, sc.operator-> ());
|
||||
if (mp_logger) {
|
||||
mp_logger->subcircuit_mismatch (0, sc.operator-> ());
|
||||
}
|
||||
good = false;
|
||||
|
||||
} else {
|
||||
|
|
@ -1314,10 +1363,14 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
size_t sc_cat = circuit_categorizer.cat_for_subcircuit (sc.operator-> ());
|
||||
|
||||
if (! scc.equals (scm->second, std::make_pair (sc.operator-> (), sc_cat))) {
|
||||
mp_logger->subcircuit_mismatch (scm->second.first, sc.operator-> ());
|
||||
if (mp_logger) {
|
||||
mp_logger->subcircuit_mismatch (scm->second.first, sc.operator-> ());
|
||||
}
|
||||
good = false;
|
||||
} else {
|
||||
mp_logger->match_subcircuits (scm->second.first, sc.operator-> ());
|
||||
if (mp_logger) {
|
||||
mp_logger->match_subcircuits (scm->second.first, sc.operator-> ());
|
||||
}
|
||||
}
|
||||
|
||||
subcircuit_map.erase (scm);
|
||||
|
|
@ -1327,7 +1380,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
}
|
||||
|
||||
for (std::multimap<std::vector<std::pair<size_t, size_t> >, std::pair<const db::SubCircuit *, size_t> >::const_iterator scm = subcircuit_map.begin (); scm != subcircuit_map.end (); ++scm) {
|
||||
mp_logger->subcircuit_mismatch (scm->second.first, 0);
|
||||
if (mp_logger) {
|
||||
mp_logger->subcircuit_mismatch (scm->second.first, 0);
|
||||
}
|
||||
good = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -127,11 +127,18 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
|
||||
for (connected_clusters_type::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) {
|
||||
|
||||
const db::local_cluster<db::PolygonRef> &lc = clusters.cluster_by_id (*c);
|
||||
if (clusters.connections_for_cluster (*c).empty () && lc.empty ()) {
|
||||
// this is an entirely empty cluster so we skip it.
|
||||
// Such clusters are left over when joining clusters.
|
||||
continue;
|
||||
}
|
||||
|
||||
db::Net *net = new db::Net ();
|
||||
net->set_cluster_id (*c);
|
||||
circuit->add_net (net);
|
||||
|
||||
const db::local_cluster<db::PolygonRef>::global_nets &gn = clusters.cluster_by_id (*c).get_global_nets ();
|
||||
const db::local_cluster<db::PolygonRef>::global_nets &gn = lc.get_global_nets ();
|
||||
for (db::local_cluster<db::PolygonRef>::global_nets::const_iterator g = gn.begin (); g != gn.end (); ++g) {
|
||||
assign_net_name (conn.global_net_name (*g), net);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
#include "dbCell.h"
|
||||
#include "dbCellInst.h"
|
||||
#include "dbLayoutDiff.h"
|
||||
#include "dbNetlist.h"
|
||||
#include "dbNetlistCompare.h"
|
||||
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlFileUtils.h"
|
||||
|
|
@ -152,4 +154,152 @@ void compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std::
|
|||
}
|
||||
}
|
||||
|
||||
class CompareLogger
|
||||
: public db::NetlistCompareLogger
|
||||
{
|
||||
public:
|
||||
CompareLogger ()
|
||||
: m_new_circuit (true) { }
|
||||
|
||||
void out (const std::string &text)
|
||||
{
|
||||
if (m_new_circuit) {
|
||||
tl::log << m_circuit;
|
||||
m_new_circuit = false;
|
||||
}
|
||||
tl::log << text;
|
||||
}
|
||||
|
||||
virtual void begin_netlist ()
|
||||
{
|
||||
tl::log << "Comparing netlists:";
|
||||
}
|
||||
|
||||
virtual void end_netlist ()
|
||||
{
|
||||
tl::log << "End of difference log.";
|
||||
}
|
||||
|
||||
virtual void begin_circuit (const db::Circuit *a, const db::Circuit *b)
|
||||
{
|
||||
m_new_circuit = true;
|
||||
m_circuit = circuit2str (a) + " vs. " + circuit2str (b);
|
||||
}
|
||||
|
||||
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b)
|
||||
{
|
||||
out ("circuit_skipped " + circuit2str (a) + " " + circuit2str (b));
|
||||
}
|
||||
|
||||
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b)
|
||||
{
|
||||
out ("circuit_mismatch " + circuit2str (a) + " " + circuit2str (b));
|
||||
}
|
||||
|
||||
virtual void match_nets (const db::Net *a, const db::Net *b)
|
||||
{
|
||||
out ("match_nets " + net2str (a) + " " + net2str (b));
|
||||
}
|
||||
|
||||
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b)
|
||||
{
|
||||
out ("match_ambiguous_nets " + net2str (a) + " " + net2str (b));
|
||||
}
|
||||
|
||||
virtual void net_mismatch (const db::Net *a, const db::Net *b)
|
||||
{
|
||||
out ("net_mismatch " + net2str (a) + " " + net2str (b));
|
||||
}
|
||||
|
||||
virtual void match_devices (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
out ("match_devices " + device2str (a) + " " + device2str (b));
|
||||
}
|
||||
|
||||
virtual void device_mismatch (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
out ("device_mismatch " + device2str (a) + " " + device2str (b));
|
||||
}
|
||||
|
||||
virtual void match_devices_with_different_parameters (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
out ("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)
|
||||
{
|
||||
out ("match_devices_with_different_device_classes " + device2str (a) + " " + device2str (b));
|
||||
}
|
||||
|
||||
virtual void match_pins (const db::Pin *a, const db::Pin *b)
|
||||
{
|
||||
out ("match_pins " + pin2str (a) + " " + pin2str (b));
|
||||
}
|
||||
|
||||
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b)
|
||||
{
|
||||
out ("pin_mismatch " + pin2str (a) + " " + pin2str (b));
|
||||
}
|
||||
|
||||
virtual void match_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b)
|
||||
{
|
||||
out ("match_subcircuits " + subcircuit2str (a) + " " + subcircuit2str (b));
|
||||
}
|
||||
|
||||
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b)
|
||||
{
|
||||
out ("subcircuit_mismatch " + subcircuit2str (a) + " " + subcircuit2str (b));
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_new_circuit;
|
||||
std::string m_circuit;
|
||||
|
||||
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)";
|
||||
}
|
||||
};
|
||||
|
||||
void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const std::string &au_nl_string)
|
||||
{
|
||||
db::NetlistComparer comp (0);
|
||||
|
||||
db::Netlist au_nl;
|
||||
for (db::Netlist::const_device_class_iterator d = netlist.begin_device_classes (); d != netlist.end_device_classes (); ++d) {
|
||||
au_nl.add_device_class (d->clone ());
|
||||
}
|
||||
|
||||
au_nl.from_string (au_nl_string);
|
||||
|
||||
if (! comp.compare (&netlist, &au_nl)) {
|
||||
_this->raise ("Compare failed - see log for details.\n\nActual:\n" + netlist.to_string () + "\nGolden:\n" + au_nl_string);
|
||||
// Compare once again - this time with logger
|
||||
CompareLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.compare (&netlist, &au_nl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ namespace db
|
|||
class Layout;
|
||||
class Cell;
|
||||
class LayerMap;
|
||||
class Netlist;
|
||||
|
||||
/**
|
||||
* @brief Specifies the normalization mode for compare_layouts
|
||||
|
|
@ -73,6 +74,11 @@ void DB_PUBLIC compare_layouts (tl::TestBase *_this, const db::Layout &layout, c
|
|||
*/
|
||||
void DB_PUBLIC compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std::string &au_file, const db::LayerMap &lmap, bool read_all_others, NormalizationMode norm = WriteGDS2, db::Coord tolerance = 0);
|
||||
|
||||
/**
|
||||
* @brief Compares a netlist against a string
|
||||
*/
|
||||
void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const std::string &au_nl_string);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -412,11 +412,11 @@ TEST(4_BufferTwoPaths)
|
|||
EXPECT_EQ (logger.text (),
|
||||
"begin_circuit BUF BUF\n"
|
||||
"match_nets OUT OUT\n"
|
||||
"match_ambiguous_nets INT $10\n"
|
||||
"match_nets INT2 $11\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_nets IN IN\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_ambiguous_nets INT $10\n"
|
||||
"match_ambiguous_nets INT2 $11\n"
|
||||
"match_pins $1 $3\n"
|
||||
"match_pins $2 $0\n"
|
||||
"match_pins $0 $1\n"
|
||||
|
|
@ -1312,3 +1312,74 @@ TEST(14_Subcircuit2MatchWithSwap)
|
|||
|
||||
EXPECT_EQ (good, true);
|
||||
}
|
||||
|
||||
TEST(15_EmptySubCircuitTest)
|
||||
{
|
||||
const char *nls1 =
|
||||
"circuit RINGO ();\n"
|
||||
" subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" subcircuit TRANS $1 (S=$2,G=$4,D=IN);\n"
|
||||
" subcircuit TRANS $2 (S=$2,G=$5,D=IN);\n"
|
||||
" subcircuit TRANS $3 (S=$5,G=OUT,D=$2);\n"
|
||||
" subcircuit TRANS $4 (S=$4,G=OUT,D=$2);\n"
|
||||
"end;\n"
|
||||
"circuit TRANS (S=$1,G=$2,D=$3);\n"
|
||||
"end;\n";
|
||||
|
||||
const char *nls2 =
|
||||
"circuit RINGO ();\n"
|
||||
" subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $4 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $5 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $6 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" subcircuit TRANS $1 (G=$4,S=$2,D=IN);\n"
|
||||
" subcircuit TRANS $2 (G=$5,S=$2,D=IN);\n"
|
||||
" subcircuit TRANS $3 (G=OUT,S=$5,D=$2);\n"
|
||||
" subcircuit TRANS $4 (G=OUT,S=$4,D=$2);\n"
|
||||
"end;\n"
|
||||
// This circuit is an abstract and it's pins are defined by the pin names
|
||||
"circuit TRANS (G=$1,S=$2,D=$3);\n"
|
||||
"end;\n";
|
||||
|
||||
db::Netlist nl1, nl2;
|
||||
prep_nl (nl1, nls1);
|
||||
prep_nl (nl2, nls2);
|
||||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
EXPECT_EQ (logger.text (),
|
||||
"..."
|
||||
);
|
||||
|
||||
EXPECT_EQ (good, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "dbCommonReader.h"
|
||||
#include "dbTestSupport.h"
|
||||
#include "dbCellMapping.h"
|
||||
#include "dbTestSupport.h"
|
||||
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlString.h"
|
||||
|
|
@ -280,7 +281,8 @@ TEST(1_DeviceAndNetExtraction)
|
|||
dump_nets_to_layout (nl, cl, ly, dump_map, cm);
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, nl,
|
||||
"circuit RINGO ();\n"
|
||||
" subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);\n"
|
||||
|
|
@ -321,9 +323,11 @@ TEST(1_DeviceAndNetExtraction)
|
|||
// make pins for named nets of top-level circuits - this way they are not purged
|
||||
nl.make_top_level_pins ();
|
||||
nl.purge ();
|
||||
nl.purge_nets ();
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, nl,
|
||||
"circuit RINGO (FB=FB,OSC=OSC,VSS=VSS,VDD=VDD);\n"
|
||||
" subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $2 (IN=FB,$2=(null),OUT=$I19,$4=VSS,$5=VDD);\n"
|
||||
|
|
@ -508,7 +512,8 @@ TEST(2_DeviceAndNetExtractionFlat)
|
|||
// compare netlist as string
|
||||
// NOTE: some of the nets are called IN,OUT but are different ones. They
|
||||
// happen to be the same because they share the same label.
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, nl,
|
||||
"circuit RINGO ();\n"
|
||||
" device PMOS $1 (S=$16,G='IN,OUT',D=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=VDD,G=$16,D='IN,OUT') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
|
|
@ -742,7 +747,8 @@ TEST(3_DeviceAndNetExtractionWithImplicitConnections)
|
|||
dump_nets_to_layout (nl, cl, ly, dump_map, cm);
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, nl,
|
||||
"circuit RINGO ();\n"
|
||||
" subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
|
|
@ -777,7 +783,8 @@ TEST(3_DeviceAndNetExtractionWithImplicitConnections)
|
|||
nl.purge ();
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, nl,
|
||||
"circuit RINGO (FB=FB,OSC=OSC,NEXT=NEXT,'VSSZ,VSS'='VSSZ,VSS','VDDZ,VDD'='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $2 (IN=FB,$2=(null),OUT=$I19,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
|
|
|
|||
Loading…
Reference in New Issue