Netlist compare: added the ability to filter small caps and high resistance devices

This commit is contained in:
Matthias Koefferlein 2019-04-06 19:46:13 +02:00
parent da5680ef24
commit aad52b77ba
5 changed files with 238 additions and 7 deletions

View File

@ -22,10 +22,11 @@
*/
#include "dbNetlistCompare.h"
#include "dbHash.h"
#include "dbNetlistDeviceClasses.h"
#include "tlProgress.h"
#include "tlTimer.h"
#include "tlEquivalenceClusters.h"
#include "tlLog.h"
namespace db
{
@ -169,6 +170,40 @@ private:
std::map<size_t, size_t> m_pin_map, m_rev_pin_map;
};
// --------------------------------------------------------------------------------------------------------------------
// DeviceFilter definition and implementation
class DeviceFilter
{
public:
DeviceFilter (double cap_threshold, double res_threshold)
: m_cap_threshold (cap_threshold), m_res_threshold (res_threshold)
{
// .. nothing yet ..
}
bool filter (const db::Device *device) const
{
const db::DeviceClassResistor *res = dynamic_cast<const db::DeviceClassResistor *> (device->device_class ());
const db::DeviceClassCapacitor *cap = dynamic_cast<const db::DeviceClassCapacitor *> (device->device_class ());
if (res) {
if (m_res_threshold > 0.0 && device->parameter_value (db::DeviceClassResistor::param_id_R) > m_res_threshold) {
return false;
}
} else if (cap) {
if (m_cap_threshold > 0.0 && device->parameter_value (db::DeviceClassCapacitor::param_id_C) < m_cap_threshold) {
return false;
}
}
return true;
}
private:
double m_cap_threshold, m_res_threshold;
};
// --------------------------------------------------------------------------------------------------------------------
// DeviceCategorizer definition and implementation
@ -418,7 +453,7 @@ public:
typedef std::vector<std::pair<std::vector<EdgeDesc>, std::pair<size_t, const db::Net *> > >::const_iterator edge_iterator;
NetGraphNode (const db::Net *net, DeviceCategorizer &device_categorizer, CircuitCategorizer &circuit_categorizer, const std::map<const db::Circuit *, CircuitMapper> *circuit_map, const CircuitPinMapper *pin_map)
NetGraphNode (const db::Net *net, DeviceCategorizer &device_categorizer, CircuitCategorizer &circuit_categorizer, const DeviceFilter &device_filter, 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) {
@ -517,6 +552,10 @@ public:
for (db::Net::const_terminal_iterator i = net->begin_terminals (); i != net->end_terminals (); ++i) {
const db::Device *d = i->device ();
if (! device_filter.filter (d)) {
continue;
}
size_t device_cat = device_categorizer.cat_for_device (d);
size_t terminal1_id = translate_terminal_id (i->terminal_id (), d);
@ -731,7 +770,7 @@ public:
// .. nothing yet ..
}
void build (const db::Circuit *c, DeviceCategorizer &device_categorizer, CircuitCategorizer &circuit_categorizer, const std::map<const db::Circuit *, CircuitMapper> *circuit_and_pin_mapping, const CircuitPinMapper *circuit_pin_mapper)
void build (const db::Circuit *c, DeviceCategorizer &device_categorizer, CircuitCategorizer &circuit_categorizer, const db::DeviceFilter &device_filter, const std::map<const db::Circuit *, CircuitMapper> *circuit_and_pin_mapping, const CircuitPinMapper *circuit_pin_mapper)
{
tl::SelfTimer timer (tl::verbosity () >= 31, tl::to_string (tr ("Building net graph for circuit: ")) + c->name ());
@ -739,7 +778,7 @@ public:
m_net_index.clear ();
// create a dummy node for a null net
m_nodes.push_back (NetGraphNode (0, device_categorizer, circuit_categorizer, circuit_and_pin_mapping, circuit_pin_mapper));
m_nodes.push_back (NetGraphNode (0, device_categorizer, circuit_categorizer, device_filter, 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) {
@ -748,7 +787,7 @@ public:
m_nodes.reserve (nets);
for (db::Circuit::const_net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) {
NetGraphNode node (n.operator-> (), device_categorizer, circuit_categorizer, circuit_and_pin_mapping, circuit_pin_mapper);
NetGraphNode node (n.operator-> (), device_categorizer, circuit_categorizer, device_filter, circuit_and_pin_mapping, circuit_pin_mapper);
m_nodes.push_back (node);
}
@ -906,6 +945,21 @@ NetlistComparer::NetlistComparer (NetlistCompareLogger *logger)
mp_device_categorizer.reset (new DeviceCategorizer ());
mp_circuit_categorizer.reset (new CircuitCategorizer ());
mp_circuit_pin_mapper.reset (new CircuitPinMapper ());
m_cap_threshold = -1.0; // not set
m_res_threshold = -1.0; // not set
}
void
NetlistComparer::exclude_caps (double threshold)
{
m_cap_threshold = threshold;
}
void
NetlistComparer::exclude_resistors (double threshold)
{
m_res_threshold = threshold;
}
void
@ -1112,12 +1166,14 @@ compute_subcircuit_key (const db::SubCircuit &subcircuit, const db::NetDeviceGra
bool
NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, db::DeviceCategorizer &device_categorizer, db::CircuitCategorizer &circuit_categorizer, const std::vector<std::pair<const Net *, const Net *> > &net_identity, bool &pin_mismatch, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping) const
{
db::DeviceFilter device_filter (m_cap_threshold, m_res_threshold);
db::NetDeviceGraph g1, g2;
// NOTE: for normalization we map all subcircuits of c1 to c2.
// Also, pin swapping will only happen there.
g1.build (c1, device_categorizer, circuit_categorizer, &c12_circuit_and_pin_mapping, mp_circuit_pin_mapper.get ());
g2.build (c2, device_categorizer, circuit_categorizer, &c22_circuit_and_pin_mapping, mp_circuit_pin_mapper.get ());
g1.build (c1, device_categorizer, circuit_categorizer, device_filter, &c12_circuit_and_pin_mapping, mp_circuit_pin_mapper.get ());
g2.build (c2, device_categorizer, circuit_categorizer, device_filter, &c22_circuit_and_pin_mapping, mp_circuit_pin_mapper.get ());
// Match dummy nodes for null nets
g1.identify (0, 0);
@ -1342,6 +1398,10 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
for (db::Circuit::const_device_iterator d = c1->begin_devices (); d != c1->end_devices (); ++d) {
if (! device_filter.filter (d.operator-> ())) {
continue;
}
std::vector<std::pair<size_t, size_t> > k = compute_device_key (*d, g1);
bool mapped = true;
@ -1365,6 +1425,10 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
for (db::Circuit::const_device_iterator d = c2->begin_devices (); d != c2->end_devices (); ++d) {
if (! device_filter.filter (d.operator-> ())) {
continue;
}
std::vector<std::pair<size_t, size_t> > k = compute_device_key (*d, g2);
bool mapped = true;

View File

@ -195,6 +195,16 @@ public:
*/
void same_circuits (const db::Circuit *ca, const db::Circuit *cb);
/**
* @brief Exclude caps with less than the given capacity value
*/
void exclude_caps (double threshold);
/**
* @brief Exclude resistors with more than the given resistance value
*/
void exclude_resistors (double threshold);
/**
* @brief Actually compares the two netlists
*/
@ -209,6 +219,8 @@ protected:
std::auto_ptr<CircuitPinMapper> mp_circuit_pin_mapper;
std::auto_ptr<DeviceCategorizer> mp_device_categorizer;
std::auto_ptr<CircuitCategorizer> mp_circuit_categorizer;
double m_cap_threshold;
double m_res_threshold;
};
}

View File

@ -454,6 +454,14 @@ Class<db::NetlistComparer> decl_dbNetlistComparer ("db", "NetlistComparer",
"This method makes a circuit circuit_a in netlist a identical to the corresponding\n"
"circuit circuit_b in netlist b (see \\compare). By default circuits with the same name are identical.\n"
) +
gsi::method ("min_capacitance=", &db::NetlistComparer::exclude_caps, gsi::arg ("threshold"),
"@brief Excludes all capacitor devices with a capacitance values less than the given threshold.\n"
"To reset this constraint, set this attribute to zero."
) +
gsi::method ("max_resistance=", &db::NetlistComparer::exclude_resistors, gsi::arg ("threshold"),
"@brief Excludes all resistor devices with a resistance values higher than the given threshold.\n"
"To reset this constraint, set this attribute to zero."
) +
gsi::method ("compare", &db::NetlistComparer::compare, gsi::arg ("netlist_a"), gsi::arg ("netlist_b"),
"@brief Compares two netlists.\n"
"This method will perform the actual netlist compare. It will return true if both netlists are identical. "

View File

@ -385,6 +385,73 @@ TEST(1_SimpleInverterMatchedDeviceClasses)
EXPECT_EQ (good, true);
}
TEST(1_SimpleInverterSkippedDevices)
{
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 CAP $2 (A=OUT,B=IN) (C=1e-12);\n"
" device NMOS $3 (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 CAP $2 (A=OUT,B=IN) (C=1e-13);\n"
" device RES $3 (A=OUT,B=IN) (R=1000);\n"
" device PMOS $4 (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 VDD VDD\n"
"match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
"match_pins $3 $2\n"
"match_devices $3 $1\n"
"match_devices_with_different_parameters $2 $2\n"
"device_mismatch (null) $3\n"
"match_devices $1 $4\n"
"end_circuit INV INV NOMATCH"
);
EXPECT_EQ (good, false);
comp.exclude_caps (1e-11);
comp.exclude_resistors (900.0);
logger.clear ();
good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (),
"begin_circuit INV INV\n"
"match_nets VDD VDD\n"
"match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
"match_pins $3 $2\n"
"match_devices $3 $1\n"
"match_devices $1 $4\n"
"end_circuit INV INV MATCH"
);
EXPECT_EQ (good, true);
}
TEST(2_SimpleInverterWithForcedNetAssignment)
{
const char *nls1 =

View File

@ -865,6 +865,86 @@ match_pins $4 $4
match_subcircuits $2 $1
match_subcircuits $1 $2
end_circuit TOP TOP MATCH
END
assert_equal(good, true)
end
def test_10
nls1 = <<"END"
circuit INV($1=IN,$2=OUT,$3=VDD,$4=VSS);
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);
device CAP $2 (A=OUT,B=IN) (C=1e-12);
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);
end;
END
nls2 = <<"END"
circuit INV($1=VDD,$2=IN,$3=VSS,$4=OUT);
device NMOSB $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);
device CAP $2 (A=OUT,B=IN) (C=1e-13);
device RES $3 (A=OUT,B=IN) (R=1000);
device PMOSB $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);
end;
END
nl1 = RBA::Netlist::new
nl2 = RBA::Netlist::new
prep_nl(nl1, nls1)
prep_nl(nl2, nls2)
logger = NetlistCompareTestLogger::new
comp = RBA::NetlistComparer::new(logger)
comp.same_device_classes(nl1.device_class_by_name("PMOS"), nl2.device_class_by_name("PMOSB"))
good = comp.compare(nl1, nl2)
assert_equal(good, false)
logger.clear
comp.same_device_classes(nl1.device_class_by_name("NMOS"), nl2.device_class_by_name("NMOSB"))
good = comp.compare(nl1, nl2)
assert_equal(logger.text(), <<"END")
begin_circuit INV INV
match_nets VDD VDD
match_nets VSS VSS
match_nets OUT OUT
match_nets IN IN
match_pins $0 $1
match_pins $1 $3
match_pins $2 $0
match_pins $3 $2
match_devices $3 $1
match_devices_with_different_parameters $2 $2
device_mismatch (null) $3
match_devices $1 $4
end_circuit INV INV NOMATCH
END
assert_equal(good, false)
comp.max_resistance = 900.0
comp.min_capacitance = 1e-11
logger.clear
good = comp.compare(nl1, nl2)
assert_equal(logger.text(), <<"END")
begin_circuit INV INV
match_nets VDD VDD
match_nets VSS VSS
match_nets OUT OUT
match_nets IN IN
match_pins $0 $1
match_pins $1 $3
match_pins $2 $0
match_pins $3 $2
match_devices $3 $1
match_devices $1 $4
end_circuit INV INV MATCH
END
assert_equal(good, true)