WIP: some enhancements

Spice writer: don't prefix model name with "M"
Added "device_class_mismatch" message to netlist compare
Assertion if device classes or circuits are nil on
"same_..."
This commit is contained in:
Matthias Koefferlein 2019-04-07 10:15:57 +02:00
parent df2bd5e80a
commit f6836b96a2
12 changed files with 132 additions and 10 deletions

View File

@ -319,6 +319,8 @@ void Circuit::unregister_ref (SubCircuit *r)
void Circuit::flatten_subcircuit (SubCircuit *subcircuit)
{
tl_assert (subcircuit != 0);
const db::Circuit *c = subcircuit->circuit_ref ();
// copy the nets, produce a net map
@ -395,7 +397,7 @@ void Circuit::flatten_subcircuit (SubCircuit *subcircuit)
}
remove_subcircuit (subcircuit);
delete subcircuit;
}
void Circuit::translate_circuits (const std::map<const Circuit *, Circuit *> &map)

View File

@ -371,6 +371,8 @@ void Netlist::remove_circuit (Circuit *circuit)
void Netlist::flatten_circuit (Circuit *circuit)
{
tl_assert (circuit != 0);
std::vector<db::SubCircuit *> refs;
for (db::Circuit::refs_iterator sc = circuit->begin_refs (); sc != circuit->end_refs (); ++sc) {
refs.push_back (sc.operator-> ());
@ -380,7 +382,7 @@ void Netlist::flatten_circuit (Circuit *circuit)
(*r)->circuit ()->flatten_subcircuit (*r);
}
remove_circuit (circuit);
delete circuit;
}
DeviceClass *Netlist::device_class_by_name (const std::string &name)

View File

@ -230,6 +230,16 @@ public:
return 0;
}
return cat_for_device_class (cls);
}
bool has_cat_for_device_class (const db::DeviceClass *cls)
{
return m_cat_by_ptr.find (cls) != m_cat_by_ptr.end ();
}
size_t cat_for_device_class (const db::DeviceClass *cls)
{
std::map<const db::DeviceClass *, size_t>::const_iterator cp = m_cat_by_ptr.find (cls);
if (cp != m_cat_by_ptr.end ()) {
return cp->second;
@ -983,12 +993,16 @@ NetlistComparer::equivalent_pins (const db::Circuit *cb, const std::vector<size_
void
NetlistComparer::same_device_classes (const db::DeviceClass *ca, const db::DeviceClass *cb)
{
tl_assert (ca != 0);
tl_assert (cb != 0);
mp_device_categorizer->same_class (ca, cb);
}
void
NetlistComparer::same_circuits (const db::Circuit *ca, const db::Circuit *cb)
{
tl_assert (ca != 0);
tl_assert (cb != 0);
mp_circuit_categorizer->same_circuit (ca, cb);
}
@ -1017,6 +1031,31 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
mp_logger->begin_netlist (a, b);
}
// check for device classes that don't match
std::map<size_t, std::pair<const db::DeviceClass *, const db::DeviceClass *> > cat2dc;
for (db::Netlist::const_device_class_iterator dc = a->begin_device_classes (); dc != a->end_device_classes (); ++dc) {
size_t cat = device_categorizer.cat_for_device_class (dc.operator-> ());
cat2dc.insert (std::make_pair (cat, std::make_pair ((const db::DeviceClass *) 0, (const db::DeviceClass *) 0))).first->second.first = dc.operator-> ();
}
for (db::Netlist::const_device_class_iterator dc = b->begin_device_classes (); dc != b->end_device_classes (); ++dc) {
size_t cat = device_categorizer.cat_for_device_class (dc.operator-> ());
cat2dc.insert (std::make_pair (cat, std::make_pair ((const db::DeviceClass *) 0, (const db::DeviceClass *) 0))).first->second.second = dc.operator-> ();
}
for (std::map<size_t, std::pair<const db::DeviceClass *, const db::DeviceClass *> >::const_iterator i = cat2dc.begin (); i != cat2dc.end (); ++i) {
if (! i->second.first || ! i->second.second) {
good = false;
if (mp_logger) {
mp_logger->device_class_mismatch (i->second.first, i->second.second);
}
}
}
// check for circuits that don't match
for (std::map<size_t, std::pair<const db::Circuit *, const db::Circuit *> >::const_iterator i = cat2circuits.begin (); i != cat2circuits.end (); ++i) {
if (! i->second.first || ! i->second.second) {
good = false;

View File

@ -56,6 +56,12 @@ public:
*/
virtual void end_netlist (const db::Netlist * /*a*/, const db::Netlist * /*b*/) { }
/**
* @brief There is a device class mismatch
* "a" is null if there is no match for b and vice versa.
*/
virtual void device_class_mismatch (const db::DeviceClass * /*a*/, const db::DeviceClass * /*b*/) { }
/**
* @brief Begin logging for circuit a and b
*/

View File

@ -141,8 +141,8 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
os << net_to_string (dev.net_for_terminal (db::DeviceClassMOS3Transistor::terminal_id_S));
}
// Use "M" + device class name for the model
os << " M";
// Use device class name for the model
os << " ";
os << format_name (dev.device_class ()->name ());
os << " L=" << tl::sprintf ("%.12gU", dev.parameter_value (db::DeviceClassMOS3Transistor::param_id_L));

View File

@ -186,6 +186,11 @@ public:
m_circuit = circuit2str (a) + " vs. " + circuit2str (b);
}
virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b)
{
out ("device_class_mismatch " + a->name () + " " + b->name ());
}
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b)
{
out ("circuit_skipped " + circuit2str (a) + " " + circuit2str (b));

View File

@ -66,6 +66,20 @@ public:
db::NetlistCompareLogger::end_netlist (a, b);
}
virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b)
{
if (cb_device_class_mismatch.can_issue ()) {
cb_device_class_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::device_class_mismatch_fb, a, b);
} else {
db::NetlistCompareLogger::device_class_mismatch (a, b);
}
}
void device_class_mismatch_fb (const db::DeviceClass *a, const db::DeviceClass *b)
{
db::NetlistCompareLogger::device_class_mismatch (a, b);
}
virtual void begin_circuit (const db::Circuit *a, const db::Circuit *b)
{
if (cb_begin_circuit.can_issue ()) {
@ -278,6 +292,7 @@ public:
gsi::Callback cb_begin_netlist;
gsi::Callback cb_end_netlist;
gsi::Callback cb_device_class_mismatch;
gsi::Callback cb_begin_circuit;
gsi::Callback cb_end_circuit;
gsi::Callback cb_circuit_skipped;
@ -309,6 +324,11 @@ Class<GenericNetlistCompareLogger> decl_GenericNetlistCompareLogger ("db", "Gene
"@brief This function is called at the end of the compare process.\n"
"This method is called once when the compare run ended.\n"
) +
gsi::callback ("device_class_mismatch", &GenericNetlistCompareLogger::device_class_mismatch, &GenericNetlistCompareLogger::cb_device_class_mismatch, gsi::arg ("a"), gsi::arg ("b"),
"@brief This function is called when device classes can't be compared.\n"
"This method is called when a device class can't be mapped to a partner in the other netlist. In this case, "
"this method is called with the one device class and nil for the other class.\n"
) +
gsi::callback ("begin_circuit", &GenericNetlistCompareLogger::begin_circuit, &GenericNetlistCompareLogger::cb_begin_circuit, gsi::arg ("a"), gsi::arg ("b"),
"@brief This function is called when a new circuit is compared.\n"
"This compare procedure will run the netlist compare circuit vs. circuit in a bottom-up fashion.\n"

View File

@ -58,6 +58,11 @@ public:
out ("circuit_mismatch " + circuit2str (a) + " " + circuit2str (b));
}
virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b)
{
out ("device_class_mismatch " + dc2str (a) + " " + dc2str (b));
}
virtual void match_nets (const db::Net *a, const db::Net *b)
{
out ("match_nets " + net2str (a) + " " + net2str (b));
@ -126,6 +131,11 @@ public:
private:
std::vector<std::string> m_texts;
std::string dc2str (const db::DeviceClass *x) const
{
return x ? x->name () : "(null)";
}
std::string circuit2str (const db::Circuit *x) const
{
return x ? x->name () : "(null)";
@ -366,6 +376,9 @@ TEST(1_SimpleInverterMatchedDeviceClasses)
logger.clear ();
comp.same_device_classes (nl1.device_class_by_name ("NMOS"), nl2.device_class_by_name ("NMOSB"));
// avoids device class mismatch errors:
comp.same_device_classes (nl1.device_class_by_name ("NMOSB"), nl2.device_class_by_name ("NMOS"));
comp.same_device_classes (nl1.device_class_by_name ("PMOSB"), nl2.device_class_by_name ("PMOS"));
good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (),

View File

@ -10,7 +10,7 @@
* net 3 n3
* net 4 n4
* device instance $1 0,0 M3CLS
M$1 1 4 3 1 MM3CLS L=0.25U W=0.18U AS=1.2P AD=0.75P PS=2.2U PD=1.75U
M$1 1 4 3 1 M3CLS L=0.25U W=0.18U AS=1.2P AD=0.75P PS=2.2U PD=1.75U
* device instance $2 0,0 M3CLS
M$2 3 4 2 3 MM3CLS L=1.4U W=0.25U AS=1.3P AD=0.85P PS=2.3U PD=1.85U
M$2 3 4 2 3 M3CLS L=1.4U W=0.25U AS=1.3P AD=0.85P PS=2.3U PD=1.85U
.ENDS C1

View File

@ -12,7 +12,7 @@
* net 4 n4
* net 5 n5
* device instance $1 0,0 M4CLS
M$1 1 4 3 5 MM4CLS L=0.25U W=0.18U AS=1.2P AD=0.75P PS=2.2U PD=1.75U
M$1 1 4 3 5 M4CLS L=0.25U W=0.18U AS=1.2P AD=0.75P PS=2.2U PD=1.75U
* device instance $2 0,0 M4CLS
M$2 3 4 2 5 MM4CLS L=1.4U W=0.25U AS=1.3P AD=0.85P PS=2.3U PD=1.85U
M$2 3 4 2 5 M4CLS L=1.4U W=0.25U AS=1.3P AD=0.85P PS=2.3U PD=1.85U
.ENDS C1

View File

@ -28,7 +28,7 @@ XSC2 3 2 4 3 C1
* net 4 n4
* net 5 n5
* device instance $1 0,0 M4CLS
M$1 1 4 3 5 MM4CLS L=0.25U W=0.18U AS=1.2P AD=0.75P PS=2.2U PD=1.75U
M$1 1 4 3 5 M4CLS L=0.25U W=0.18U AS=1.2P AD=0.75P PS=2.2U PD=1.75U
* device instance $2 0,0 M4CLS
M$2 3 4 2 5 MM4CLS L=1.4U W=0.25U AS=1.3P AD=0.85P PS=2.3U PD=1.85U
M$2 3 4 2 5 M4CLS L=1.4U W=0.25U AS=1.3P AD=0.85P PS=2.3U PD=1.85U
.ENDS C1

View File

@ -33,6 +33,10 @@ class NetlistCompareTestLogger < RBA::GenericNetlistCompareLogger
@texts << text
end
def device_class_mismatch(a, b)
out("device_class_mismatch " + dc2str(a) + " " + dc2str(b))
end
def begin_circuit(a, b)
out("begin_circuit " + circuit2str(a) + " " + circuit2str(b))
end
@ -101,6 +105,10 @@ class NetlistCompareTestLogger < RBA::GenericNetlistCompareLogger
@texts = []
end
def dc2str(x)
return x ? x.name : "(null)"
end
def circuit2str(x)
return x ? x.name : "(null)"
end
@ -173,6 +181,27 @@ class NetlistCompare_TestClass < TestBase
def test_1
nl1 = RBA::Netlist::new
nl2 = RBA::Netlist::new
dc = RBA::DeviceClass::new
dc.name = "A"
nl1.add(dc)
dc = RBA::DeviceClass::new
dc.name = "B"
nl2.add(dc)
logger = NetlistCompareTestLogger::new
comp = RBA::NetlistComparer::new(logger)
good = comp.compare(nl1, nl2)
assert_equal(logger.text, <<"END")
device_class_mismatch A (null)
device_class_mismatch (null) B
END
assert_equal(good, false)
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);
@ -247,6 +276,9 @@ END
logger.clear
comp.same_device_classes(nl1.device_class_by_name("NMOS"), nl2.device_class_by_name("NMOSB"))
# avoids device class mismatch errors
comp.same_device_classes(nl1.device_class_by_name("NMOSB"), nl2.device_class_by_name("NMOS"))
comp.same_device_classes(nl1.device_class_by_name("PMOSB"), nl2.device_class_by_name("PMOS"))
good = comp.compare(nl1, nl2)
assert_equal(logger.text(), <<"END")
@ -905,6 +937,9 @@ END
logger.clear
comp.same_device_classes(nl1.device_class_by_name("NMOS"), nl2.device_class_by_name("NMOSB"))
# avoids device class mismatch errors
comp.same_device_classes(nl1.device_class_by_name("NMOSB"), nl2.device_class_by_name("NMOS"))
comp.same_device_classes(nl1.device_class_by_name("PMOSB"), nl2.device_class_by_name("PMOS"))
good = comp.compare(nl1, nl2)
assert_equal(logger.text(), <<"END")