mirror of https://github.com/KLayout/klayout.git
WIP: netlist compare, ambiguous net resolution, device mapping.
This commit is contained in:
parent
25b7ab9dab
commit
bb2d3765b8
|
|
@ -38,6 +38,12 @@ public:
|
|||
*/
|
||||
virtual void end_circuit (const db::Circuit * /*a*/, const db::Circuit * /*b*/, bool /*matching*/) { }
|
||||
|
||||
/**
|
||||
* @brief Circuits are skipped
|
||||
* Circuits are skipped if their subcircuits could not be matched.
|
||||
*/
|
||||
virtual void circuit_skipped (const db::Circuit * /*a*/, const db::Circuit * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief There is a circuit mismatch
|
||||
* "a" is null if there is no match for b and vice versa.
|
||||
|
|
@ -77,6 +83,12 @@ public:
|
|||
*/
|
||||
virtual void match_devices_with_different_device_classes (const db::Device * /*a*/, const db::Device * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Device a or b doesn't match
|
||||
* "a" is null if there is no match for b and vice versa.
|
||||
*/
|
||||
virtual void device_mismatch (const db::Device * /*a*/, const db::Device * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Pins a and b of the current circuit are matched
|
||||
*/
|
||||
|
|
@ -106,7 +118,7 @@ struct DeviceCompare
|
|||
{
|
||||
// @@@ TODO: device class identity should not be defined via name
|
||||
if (d1->device_class () != d2->device_class () && d1->device_class ()->name () != d2->device_class ()->name ()) {
|
||||
return d1->device_class ()->name () < d1->device_class ()->name ();
|
||||
return d1->device_class ()->name () < d2->device_class ()->name ();
|
||||
}
|
||||
|
||||
const std::vector<db::DeviceParameterDefinition> &dp = d1->device_class ()->parameter_definitions ();
|
||||
|
|
@ -267,6 +279,19 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
bool operator== (const NetDeviceGraphNode &node) const
|
||||
{
|
||||
if (m_edges.size () != node.m_edges.size ()) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < m_edges.size (); ++i) {
|
||||
if (m_edges [i].first != node.m_edges [i].first) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void swap (NetDeviceGraphNode &other)
|
||||
{
|
||||
std::swap (m_other_net_index, other.m_other_net_index);
|
||||
|
|
@ -343,13 +368,18 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
size_t index_for_net (const db::Net *net) const
|
||||
size_t node_index_for_net (const db::Net *net) const
|
||||
{
|
||||
std::map<const db::Net *, size_t>::const_iterator j = m_net_index.find (net);
|
||||
tl_assert (j != m_net_index.end ());
|
||||
return j->second;
|
||||
}
|
||||
|
||||
const db::Net *net_by_node_index (size_t net_index) const
|
||||
{
|
||||
return m_nodes [net_index].net ();
|
||||
}
|
||||
|
||||
void identify (size_t net_index, size_t other_net_index)
|
||||
{
|
||||
m_nodes [net_index].set_other_net (other_net_index);
|
||||
|
|
@ -445,10 +475,14 @@ public:
|
|||
return added;
|
||||
}
|
||||
|
||||
static void confirm_identity (db::NetDeviceGraph &g1, db::NetDeviceGraph::node_iterator s1, db::NetDeviceGraph &g2, db::NetDeviceGraph::node_iterator s2, db::NetlistCompareLogger *logger)
|
||||
static void confirm_identity (db::NetDeviceGraph &g1, db::NetDeviceGraph::node_iterator s1, db::NetDeviceGraph &g2, db::NetDeviceGraph::node_iterator s2, db::NetlistCompareLogger *logger, bool ambiguous = false)
|
||||
{
|
||||
if (logger) {
|
||||
logger->match_nets (s1->net (), s2->net ());
|
||||
if (ambiguous) {
|
||||
logger->match_ambiguous_nets (s1->net (), s2->net ());
|
||||
} else {
|
||||
logger->match_nets (s1->net (), s2->net ());
|
||||
}
|
||||
}
|
||||
g1.identify (s1 - g1.begin (), s2 - g2.begin ());
|
||||
g2.identify (s2 - g2.begin (), s1 - g1.begin ());
|
||||
|
|
@ -468,6 +502,11 @@ public:
|
|||
: mp_logger (logger)
|
||||
{ }
|
||||
|
||||
void same_nets (const db::Circuit *a, const db::Net *na, const db::Circuit *b, const db::Net *nb)
|
||||
{
|
||||
m_same_nets [std::make_pair (a, b)].push_back (std::make_pair (na, nb));
|
||||
}
|
||||
|
||||
bool compare (const db::Netlist *a, const db::Netlist *b) const
|
||||
{
|
||||
bool good = true;
|
||||
|
|
@ -495,22 +534,54 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
std::set<const db::Circuit *> verified_circuits_a, verified_circuits_b;
|
||||
|
||||
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);
|
||||
|
||||
const db::Circuit *ca = i->second.first;
|
||||
const db::Circuit *cb = i->second.second;
|
||||
|
||||
std::vector<std::pair<const Net *, const Net *> > empty;
|
||||
const std::vector<std::pair<const Net *, const Net *> > *net_identity = ∅
|
||||
std::map<std::pair<const db::Circuit *, const db::Circuit *>, std::vector<std::pair<const Net *, const Net *> > >::const_iterator sn = m_same_nets.find (std::make_pair (ca, cb));
|
||||
if (sn != m_same_nets.end ()) {
|
||||
net_identity = &sn->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 (all_subcircuits_verified (ca, verified_circuits_a) && all_subcircuits_verified (cb, verified_circuits_b)) {
|
||||
|
||||
if (mp_logger) {
|
||||
mp_logger->begin_circuit (ca, cb);
|
||||
}
|
||||
|
||||
bool pin_mismatch = false;
|
||||
bool g = compare_circuits (ca, cb, *net_identity, pin_mismatch);
|
||||
if (! g) {
|
||||
good = false;
|
||||
}
|
||||
|
||||
if (! pin_mismatch) {
|
||||
verified_circuits_a.insert (ca);
|
||||
verified_circuits_b.insert (cb);
|
||||
}
|
||||
|
||||
if (mp_logger) {
|
||||
mp_logger->end_circuit (ca, cb, g);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (mp_logger) {
|
||||
mp_logger->circuit_skipped (ca, cb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -523,20 +594,59 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2) const;
|
||||
bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2, const std::vector<std::pair<const Net *, const Net *> > &net_identity, bool &pin_mismatch) const;
|
||||
bool all_subcircuits_verified (const db::Circuit *c, const std::set<const db::Circuit *> &verified_circuits) const;
|
||||
|
||||
NetlistCompareLogger *mp_logger;
|
||||
std::map<std::pair<const db::Circuit *, const db::Circuit *>, std::vector<std::pair<const Net *, const Net *> > > m_same_nets;
|
||||
};
|
||||
|
||||
bool
|
||||
NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2) const
|
||||
NetlistComparer::all_subcircuits_verified (const db::Circuit *c, const std::set<const db::Circuit *> &verified_circuits) const
|
||||
{
|
||||
for (db::Circuit::const_subcircuit_iterator sc = c->begin_subcircuits (); sc != c->end_subcircuits (); ++sc) {
|
||||
if (verified_circuits.find (sc->circuit_ref ()) == verified_circuits.end ()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::vector<std::pair<size_t, size_t> >
|
||||
compute_device_key (const db::Device &device, const db::NetDeviceGraph &g)
|
||||
{
|
||||
std::vector<std::pair<size_t, size_t> > k;
|
||||
|
||||
const std::vector<db::DeviceTerminalDefinition> &td = device.device_class ()->terminal_definitions ();
|
||||
for (std::vector<db::DeviceTerminalDefinition>::const_iterator t = td.begin (); t != td.end (); ++t) {
|
||||
size_t terminal_id = translate_terminal_id (t->id (), &device);
|
||||
const db::Net *net = device.net_for_terminal (t->id ());
|
||||
size_t net_id = g.node_index_for_net (net);
|
||||
k.push_back (std::make_pair (terminal_id, net_id));
|
||||
}
|
||||
|
||||
std::sort (k.begin (), k.end ());
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
bool
|
||||
NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, const std::vector<std::pair<const Net *, const Net *> > &net_identity, bool &pin_mismatch) const
|
||||
{
|
||||
db::NetDeviceGraph g1, g2;
|
||||
|
||||
g1.build (c1);
|
||||
g2.build (c2);
|
||||
|
||||
while (true) {
|
||||
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);
|
||||
g1.identify (ni1, ni2);
|
||||
g2.identify (ni2, ni1);
|
||||
}
|
||||
|
||||
bool good = true;
|
||||
while (good) {
|
||||
|
||||
size_t new_identities = 0;
|
||||
for (db::NetDeviceGraph::node_iterator i1 = g1.begin (); i1 != g1.end (); ++i1) {
|
||||
|
|
@ -551,18 +661,13 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2)
|
|||
}
|
||||
|
||||
if (! any_without) {
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
bool ambiguous = false;
|
||||
|
||||
if (new_identities == 0) {
|
||||
|
||||
// derive new identities through topology
|
||||
|
||||
db::NetDeviceGraph::node_iterator s1 = g1.end (), s2 = g2.end ();
|
||||
size_t seeds = 0;
|
||||
|
||||
db::NetDeviceGraph::node_iterator i1 = g1.begin (), i2 = g2.begin ();
|
||||
for ( ; i1 != g1.end () && i2 != g2.end (); ) {
|
||||
|
||||
|
|
@ -571,71 +676,153 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2)
|
|||
} else if (i2->has_other ()) {
|
||||
++i2;
|
||||
} else if (*i1 < *i2) {
|
||||
seeds = 0;
|
||||
++i1;
|
||||
} else if (*i2 < *i1) {
|
||||
seeds = 0;
|
||||
++i2;
|
||||
} else {
|
||||
|
||||
if (seeds == 0 || *s1 < *i1) {
|
||||
|
||||
if (seeds == 1) {
|
||||
// found a candidate - a single node with the same edges
|
||||
db::NetDeviceGraph::confirm_identity (g1, s1, g2, s2, mp_logger);
|
||||
++new_identities;
|
||||
} else if (seeds > 1) {
|
||||
ambiguous = true;
|
||||
}
|
||||
|
||||
s1 = i1; s2 = i2;
|
||||
seeds = 1;
|
||||
|
||||
} else {
|
||||
++seeds;
|
||||
}
|
||||
db::NetDeviceGraph::node_iterator ii1 = i1, ii2 = i2;
|
||||
|
||||
++i1;
|
||||
++i2;
|
||||
|
||||
bool ambiguous = (i1 != g1.end () && *i1 == *ii1) || (i2 != g2.end () && *i2 == *ii2);
|
||||
|
||||
// found a candidate - a single node with the same edges
|
||||
db::NetDeviceGraph::confirm_identity (g1, ii1, g2, ii2, mp_logger, ambiguous);
|
||||
++new_identities;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (seeds == 1) {
|
||||
// found a candidate - a single node with the same edges
|
||||
db::NetDeviceGraph::confirm_identity (g1, s1, g2, s2, mp_logger);
|
||||
++new_identities;
|
||||
} else if (seeds > 1) {
|
||||
ambiguous = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (new_identities == 0) {
|
||||
// @@@
|
||||
if (ambiguous) {
|
||||
tl::error << tr ("No seed found - no non-ambiguous nets identified");
|
||||
} else {
|
||||
tl::error << tr ("No seed found - no equivalent nets identified");
|
||||
}
|
||||
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 << " " << 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 << " " << i->net ()->expanded_name ();
|
||||
}
|
||||
}
|
||||
// @@@
|
||||
return false;
|
||||
good = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Report missing net assignment
|
||||
|
||||
for (db::NetDeviceGraph::node_iterator i = g1.begin (); i != g1.end (); ++i) {
|
||||
if (! i->has_other ()) {
|
||||
mp_logger->net_mismatch (i->net (), 0);
|
||||
}
|
||||
}
|
||||
tl::error << tr ("Unassigned in netlist B:");
|
||||
for (db::NetDeviceGraph::node_iterator i = g2.begin (); i != g2.end (); ++i) {
|
||||
if (! i->has_other ()) {
|
||||
mp_logger->net_mismatch (0, i->net ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Report pin assignment
|
||||
|
||||
std::multimap<const db::Net *, const db::Pin *> net2pin;
|
||||
for (db::Circuit::const_pin_iterator p = c2->begin_pins (); p != c2->end_pins (); ++p) {
|
||||
const db::Net *net = c2->net_for_pin (p->id ());
|
||||
tl_assert (net != 0);
|
||||
net2pin.insert (std::make_pair (net, p.operator-> ()));
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
pin_mismatch = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const db::Net *other_net = g2.net_by_node_index (i->other_net_index ());
|
||||
|
||||
std::multimap<const db::Net *, const db::Pin *>::iterator np = net2pin.find (other_net);
|
||||
for (db::Net::const_pin_iterator pi = net->begin_pins (); pi != net->end_pins (); ++pi) {
|
||||
|
||||
if (np != net2pin.end () && np->first == other_net) {
|
||||
|
||||
mp_logger->match_pins (pi->pin (), np->second);
|
||||
|
||||
std::multimap<const db::Net *, const db::Pin *>::iterator np_delete = np;
|
||||
++np;
|
||||
net2pin.erase (np_delete);
|
||||
|
||||
} else {
|
||||
mp_logger->pin_mismatch (pi->pin (), 0);
|
||||
pin_mismatch = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (std::multimap<const db::Net *, const db::Pin *>::iterator np = net2pin.begin (); np != net2pin.end (); ++np) {
|
||||
mp_logger->pin_mismatch (0, np->second);
|
||||
pin_mismatch = true;
|
||||
}
|
||||
|
||||
// Report device assignment
|
||||
|
||||
std::map<std::vector<std::pair<size_t, size_t> >, const db::Device *> device_map;
|
||||
|
||||
for (db::Circuit::const_device_iterator d = c1->begin_devices (); d != c1->end_devices (); ++d) {
|
||||
|
||||
std::vector<std::pair<size_t, size_t> > k = compute_device_key (*d, g1);
|
||||
|
||||
bool mapped = true;
|
||||
for (std::vector<std::pair<size_t, size_t> >::iterator i = k.begin (); i != k.end () && mapped; ++i) {
|
||||
if (! g1.begin () [i->second].has_other ()) {
|
||||
mapped = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (! mapped) {
|
||||
mp_logger->device_mismatch (d.operator-> (), 0);
|
||||
} else {
|
||||
// TODO: report devices which cannot be distiguished topologically?
|
||||
device_map[k] = d.operator-> ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (db::Circuit::const_device_iterator d = c2->begin_devices (); d != c2->end_devices (); ++d) {
|
||||
|
||||
std::vector<std::pair<size_t, size_t> > k = compute_device_key (*d, g2);
|
||||
|
||||
bool mapped = true;
|
||||
for (std::vector<std::pair<size_t, size_t> >::iterator i = k.begin (); i != k.end (); ++i) {
|
||||
if (! g1.begin () [i->second].has_other ()) {
|
||||
mapped = false;
|
||||
} else {
|
||||
i->second = g2.begin () [i->second].other_net_index ();
|
||||
}
|
||||
}
|
||||
|
||||
std::sort (k.begin (), k.end ());
|
||||
|
||||
std::map<std::vector<std::pair<size_t, size_t> >, const db::Device *>::const_iterator dm = device_map.find (k);
|
||||
|
||||
if (! mapped || dm == device_map.end ()) {
|
||||
mp_logger->device_mismatch (0, d.operator-> ());
|
||||
} else {
|
||||
// @@@ compare parameters, device class
|
||||
mp_logger->match_devices (dm->second, d.operator-> ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return good;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -656,6 +843,11 @@ public:
|
|||
m_texts.push_back ("end_circuit " + circuit2str (a) + " " + circuit2str (b) + " " + (matching ? "MATCH" : "NOMATCH"));
|
||||
}
|
||||
|
||||
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b)
|
||||
{
|
||||
m_texts.push_back ("circuit_skipped " + circuit2str (a) + " " + circuit2str (b));
|
||||
}
|
||||
|
||||
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b)
|
||||
{
|
||||
m_texts.push_back ("circuit_mismatch " + circuit2str (a) + " " + circuit2str (b));
|
||||
|
|
@ -681,6 +873,11 @@ public:
|
|||
m_texts.push_back ("match_devices " + device2str (a) + " " + device2str (b));
|
||||
}
|
||||
|
||||
virtual void device_mismatch (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
m_texts.push_back ("device_mismatch " + 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));
|
||||
|
|
@ -745,8 +942,253 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
static void prep_nl (db::Netlist &nl, const char *str)
|
||||
{
|
||||
db::DeviceClass *dc;
|
||||
|
||||
TEST(1)
|
||||
dc = new db::DeviceClassMOS3Transistor ();
|
||||
dc->set_name ("PMOS");
|
||||
nl.add_device_class (dc);
|
||||
|
||||
dc = new db::DeviceClassMOS3Transistor ();
|
||||
dc->set_name ("NMOS");
|
||||
nl.add_device_class (dc);
|
||||
|
||||
nl.from_string (str);
|
||||
}
|
||||
|
||||
TEST(1_SimpleInverter)
|
||||
{
|
||||
const char *nls1 =
|
||||
"circuit INV ($1=IN,$2=OUT,$3=VDD,$4=VSS);\n"
|
||||
" device PMOS $1 (S=VDD,G=IN,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $2 (S=VSS,G=IN,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
"end;\n";
|
||||
|
||||
const char *nls2 =
|
||||
"circuit INV ($1=VDD,$2=IN,$3=VSS,$4=OUT);\n"
|
||||
" device NMOS $1 (S=OUT,G=IN,D=VSS) (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=IN,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\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 (),
|
||||
"begin_circuit INV INV\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_nets OUT OUT\n"
|
||||
"match_nets IN IN\n"
|
||||
"match_pins $3 $2\n"
|
||||
"match_pins $2 $0\n"
|
||||
"match_pins $1 $3\n"
|
||||
"match_pins $0 $1\n"
|
||||
"match_devices $2 $1\n"
|
||||
"match_devices $1 $2\n"
|
||||
"end_circuit INV INV MATCH"
|
||||
);
|
||||
EXPECT_EQ (good, true);
|
||||
}
|
||||
|
||||
TEST(2_SimpleInverterWithForcedNetAssignment)
|
||||
{
|
||||
const char *nls1 =
|
||||
"circuit INV ($1=IN,$2=OUT,$3=VDD,$4=VSS);\n"
|
||||
" device PMOS $1 (S=VDD,G=IN,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $2 (S=VSS,G=IN,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
"end;\n";
|
||||
|
||||
const char *nls2 =
|
||||
"circuit INV ($1=VDD,$2=IN,$3=VSS,$4=OUT);\n"
|
||||
" device NMOS $1 (S=OUT,G=IN,D=VSS) (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=IN,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
"end;\n";
|
||||
|
||||
db::Netlist nl1, nl2;
|
||||
prep_nl (nl1, nls1);
|
||||
prep_nl (nl2, nls2);
|
||||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
const db::Circuit *ca = nl1.circuit_by_name ("INV");
|
||||
const db::Circuit *cb = nl2.circuit_by_name ("INV");
|
||||
comp.same_nets (ca, ca->net_by_name ("VDD"), cb, cb->net_by_name ("VDD"));
|
||||
comp.same_nets (ca, ca->net_by_name ("VSS"), cb, cb->net_by_name ("VSS"));
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
EXPECT_EQ (logger.text (),
|
||||
"begin_circuit INV INV\n"
|
||||
"match_nets OUT OUT\n"
|
||||
"match_nets IN IN\n"
|
||||
"match_pins $3 $2\n"
|
||||
"match_pins $2 $0\n"
|
||||
"match_pins $1 $3\n"
|
||||
"match_pins $0 $1\n"
|
||||
"match_devices $2 $1\n"
|
||||
"match_devices $1 $2\n"
|
||||
"end_circuit INV INV MATCH"
|
||||
);
|
||||
EXPECT_EQ (good, true);
|
||||
}
|
||||
|
||||
TEST(3_Buffer)
|
||||
{
|
||||
const char *nls1 =
|
||||
"circuit BUF ($1=IN,$2=OUT,$3=VDD,$4=VSS);\n"
|
||||
" device PMOS $1 (S=VDD,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $2 (S=VSS,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $3 (S=VDD,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=VSS,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
"end;\n";
|
||||
|
||||
const char *nls2 =
|
||||
"circuit BUF ($1=VDD,$2=IN,$3=VSS,$4=OUT);\n"
|
||||
" device PMOS $1 (S=VDD,G=IN,D=$10) (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=$10,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $3 (S=$10,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=OUT,G=$10,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\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 (),
|
||||
"begin_circuit BUF BUF\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_nets OUT OUT\n"
|
||||
"match_nets IN IN\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_nets INT $10\n"
|
||||
"match_pins $3 $2\n"
|
||||
"match_pins $1 $3\n"
|
||||
"match_pins $0 $1\n"
|
||||
"match_pins $2 $0\n"
|
||||
"match_devices $1 $1\n"
|
||||
"match_devices $3 $2\n"
|
||||
"match_devices $2 $3\n"
|
||||
"match_devices $4 $4\n"
|
||||
"end_circuit BUF BUF MATCH"
|
||||
);
|
||||
EXPECT_EQ (good, true);
|
||||
}
|
||||
|
||||
TEST(4_BufferTwoPaths)
|
||||
{
|
||||
const char *nls1 =
|
||||
"circuit BUF ($1=IN,$2=OUT,$3=VDD,$4=VSS);\n"
|
||||
" device PMOS $1 (S=VDD,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $2 (S=VSS,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $3 (S=VDD,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=VSS,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $5 (S=VDD,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $6 (S=VSS,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $7 (S=VDD,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $8 (S=VSS,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
"end;\n";
|
||||
|
||||
const char *nls2 =
|
||||
"circuit BUF ($1=VDD,$2=IN,$3=VSS,$4=OUT);\n"
|
||||
" device PMOS $1 (S=VDD,G=IN,D=$10) (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=$10,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $3 (S=VDD,G=IN,D=$11) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $4 (S=VDD,G=$11,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $5 (S=$10,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $6 (S=OUT,G=$10,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $7 (S=$11,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $8 (S=OUT,G=$11,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\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 (),
|
||||
"begin_circuit BUF BUF\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_nets OUT OUT\n"
|
||||
"match_ambiguous_nets INT $10\n"
|
||||
"match_nets INT2 $11\n"
|
||||
"match_nets IN IN\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_pins $3 $2\n"
|
||||
"match_pins $1 $3\n"
|
||||
"match_pins $0 $1\n"
|
||||
"match_pins $2 $0\n"
|
||||
"match_devices $1 $1\n"
|
||||
"match_devices $3 $2\n"
|
||||
"match_devices $5 $3\n"
|
||||
"match_devices $7 $4\n"
|
||||
"match_devices $2 $5\n"
|
||||
"match_devices $4 $6\n"
|
||||
"match_devices $6 $7\n"
|
||||
"match_devices $8 $8\n"
|
||||
"end_circuit BUF BUF MATCH"
|
||||
);
|
||||
EXPECT_EQ (good, true);
|
||||
}
|
||||
|
||||
TEST(100_SimpleInverterWithWrongTransistorParameter)
|
||||
{
|
||||
return; // @@@ doesn't work yet.
|
||||
const char *nls1 =
|
||||
"circuit INV ($1=IN,$2=OUT,$3=VDD,$4=VSS);\n"
|
||||
" device PMOS $1 (S=VDD,G=IN,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $2 (S=VSS,G=IN,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
"end;\n";
|
||||
|
||||
const char *nls2 =
|
||||
"circuit INV ($1=VDD,$2=IN,$3=VSS,$4=OUT);\n"
|
||||
" device NMOS $1 (S=OUT,G=IN,D=VSS) (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=IN,D=OUT) (L=0.30,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
"end;\n";
|
||||
|
||||
db::Netlist nl1, nl2;
|
||||
prep_nl (nl1, nls1);
|
||||
prep_nl (nl2, nls2);
|
||||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
const db::Circuit *ca = nl1.circuit_by_name ("INV");
|
||||
const db::Circuit *cb = nl2.circuit_by_name ("INV");
|
||||
comp.same_nets (ca, ca->net_by_name ("VDD"), cb, cb->net_by_name ("VDD"));
|
||||
comp.same_nets (ca, ca->net_by_name ("VSS"), cb, cb->net_by_name ("VSS"));
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
EXPECT_EQ (logger.text (),
|
||||
"begin_circuit INV INV\n"
|
||||
"match_nets OUT OUT\n"
|
||||
"match_nets IN IN\n"
|
||||
"match_pins $3 $2\n"
|
||||
"match_pins $2 $0\n"
|
||||
"match_pins $1 $3\n"
|
||||
"match_pins $0 $1\n"
|
||||
"end_circuit INV INV MATCH"
|
||||
);
|
||||
EXPECT_EQ (good, true);
|
||||
}
|
||||
|
||||
#if 0
|
||||
TEST(2)
|
||||
{
|
||||
const char *nls2 =
|
||||
"circuit RINGO ();\n"
|
||||
|
|
@ -866,3 +1308,4 @@ TEST(1)
|
|||
);
|
||||
EXPECT_EQ (good, true);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue