mirror of https://github.com/KLayout/klayout.git
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:
parent
df2bd5e80a
commit
f6836b96a2
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 (),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Reference in New Issue