mirror of
https://github.com/KLayout/klayout.git
synced 2026-09-07 02:36:15 +02:00
Using primary(layout) netlist as reference for primary parameters and compare delegate - this also removes some potential glitches
This commit is contained in:
@@ -90,6 +90,16 @@ void Device::set_circuit (Circuit *circuit)
|
||||
mp_circuit = circuit;
|
||||
}
|
||||
|
||||
const Netlist *Device::netlist () const
|
||||
{
|
||||
return mp_circuit ? mp_circuit->netlist () : 0;
|
||||
}
|
||||
|
||||
Netlist *Device::netlist ()
|
||||
{
|
||||
return mp_circuit ? mp_circuit->netlist () : 0;
|
||||
}
|
||||
|
||||
void Device::set_name (const std::string &n)
|
||||
{
|
||||
m_name = n;
|
||||
|
||||
@@ -193,6 +193,16 @@ public:
|
||||
return mp_circuit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the netlist, the device lives in
|
||||
*/
|
||||
const Netlist *netlist () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the netlist, the device lives in
|
||||
*/
|
||||
Netlist *netlist ();
|
||||
|
||||
/**
|
||||
* @brief Sets the name
|
||||
*/
|
||||
|
||||
+29
-20
@@ -22,11 +22,34 @@
|
||||
|
||||
#include "dbDeviceClass.h"
|
||||
#include "dbDevice.h"
|
||||
#include "dbNetlist.h"
|
||||
#include "tlClassRegistry.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Returns the primary device class for both given devices
|
||||
* One of the devices lives in a primary netlist. This one is taken for the device class.
|
||||
*/
|
||||
static const db::DeviceClass *primary_device_class (const db::Device &a, const db::Device &b)
|
||||
{
|
||||
tl_assert (a.device_class () != 0);
|
||||
tl_assert (b.device_class () != 0);
|
||||
|
||||
const db::DeviceClass *dca = a.device_class ()->primary_class () ? a.device_class ()->primary_class () : a.device_class ();
|
||||
const db::DeviceClass *dcb = b.device_class ()->primary_class () ? b.device_class ()->primary_class () : b.device_class ();
|
||||
|
||||
if (dca != dcb) {
|
||||
// different devices, same category while sorting devices - take the one with the "lower" name
|
||||
return dca->name () < dcb->name () ? dca : dcb;
|
||||
} else {
|
||||
return dca;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// EqualDeviceParameters implementation
|
||||
|
||||
@@ -36,7 +59,6 @@ const double default_relative_tolerance = 1e-6;
|
||||
|
||||
const double default_absolute_tolerance = 0.0;
|
||||
|
||||
|
||||
static int compare_parameters (double pa, double pb, double absolute = default_absolute_tolerance, double relative = default_relative_tolerance)
|
||||
{
|
||||
// absolute value < 0 means: ignore this parameter (= always match)
|
||||
@@ -112,21 +134,14 @@ bool EqualDeviceParameters::less (const db::Device &a, const db::Device &b) cons
|
||||
seen.insert (c->first);
|
||||
}
|
||||
|
||||
const std::vector<db::DeviceParameterDefinition> &pd = a.device_class ()->parameter_definitions ();
|
||||
const std::vector<db::DeviceParameterDefinition> &pd = primary_device_class (a, b)->parameter_definitions ();
|
||||
for (std::vector<db::DeviceParameterDefinition>::const_iterator p = pd.begin (); p != pd.end (); ++p) {
|
||||
|
||||
if (seen.find (p->id ()) != seen.end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const db::DeviceParameterDefinition *pdb = b.device_class ()->parameter_definition (p->id ());
|
||||
if (pdb && pdb->is_primary () && p->is_primary ()) {
|
||||
if (p->is_primary () && seen.find (p->id ()) == seen.end ()) {
|
||||
int cmp = compare_parameters (a.parameter_value (p->id ()), b.parameter_value (p->id ()));
|
||||
if (cmp != 0) {
|
||||
return cmp < 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -166,13 +181,13 @@ bool AllDeviceParametersAreEqual::less (const db::Device &a, const db::Device &b
|
||||
// DeviceClass class implementation
|
||||
|
||||
DeviceClass::DeviceClass ()
|
||||
: m_strict (false), mp_netlist (0), m_supports_parallel_combination (false), m_supports_serial_combination (false)
|
||||
: m_strict (false), mp_netlist (0), m_supports_parallel_combination (false), m_supports_serial_combination (false), mp_primary_class (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
DeviceClass::DeviceClass (const DeviceClass &other)
|
||||
: gsi::ObjectBase (other), tl::Object (other), tl::UniqueId (other), m_strict (false), mp_netlist (0), m_supports_parallel_combination (false), m_supports_serial_combination (false)
|
||||
: gsi::ObjectBase (other), tl::Object (other), tl::UniqueId (other), m_strict (false), mp_netlist (0), m_supports_parallel_combination (false), m_supports_serial_combination (false), mp_primary_class (0)
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
@@ -299,10 +314,7 @@ bool DeviceClass::less (const db::Device &a, const db::Device &b)
|
||||
tl_assert (a.device_class () != 0);
|
||||
tl_assert (b.device_class () != 0);
|
||||
|
||||
const db::DeviceParameterCompareDelegate *pcd = a.device_class ()->mp_pc_delegate.get ();
|
||||
if (! pcd) {
|
||||
pcd = b.device_class ()->mp_pc_delegate.get ();
|
||||
}
|
||||
const db::DeviceParameterCompareDelegate *pcd = primary_device_class (a, b)->parameter_compare_delegate ();
|
||||
if (! pcd) {
|
||||
pcd = &default_compare;
|
||||
}
|
||||
@@ -315,10 +327,7 @@ bool DeviceClass::equal (const db::Device &a, const db::Device &b)
|
||||
tl_assert (a.device_class () != 0);
|
||||
tl_assert (b.device_class () != 0);
|
||||
|
||||
const db::DeviceParameterCompareDelegate *pcd = a.device_class ()->mp_pc_delegate.get ();
|
||||
if (! pcd) {
|
||||
pcd = b.device_class ()->mp_pc_delegate.get ();
|
||||
}
|
||||
const db::DeviceParameterCompareDelegate *pcd = primary_device_class (a, b)->parameter_compare_delegate ();
|
||||
if (! pcd) {
|
||||
pcd = &default_compare;
|
||||
}
|
||||
|
||||
@@ -734,6 +734,22 @@ public:
|
||||
return mp_device_combiner.get ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Internally used by the netlist comparer to temporarily attach a device class pointing to the primary one
|
||||
*/
|
||||
void set_primary_class (const db::DeviceClass *primary) const
|
||||
{
|
||||
mp_primary_class = primary;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Internally used by the netlist comparer to temporarily attach a device class pointing to the primary one
|
||||
*/
|
||||
const db::DeviceClass *primary_class () const
|
||||
{
|
||||
return mp_primary_class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate memory statistics
|
||||
*/
|
||||
@@ -762,6 +778,7 @@ private:
|
||||
bool m_supports_parallel_combination;
|
||||
bool m_supports_serial_combination;
|
||||
std::map<size_t, size_t> m_equivalent_terminal_ids;
|
||||
mutable const db::DeviceClass *mp_primary_class;
|
||||
|
||||
void set_netlist (db::Netlist *nl)
|
||||
{
|
||||
|
||||
@@ -44,7 +44,7 @@ Netlist::Netlist (NetlistManipulationCallbacks *callbacks)
|
||||
}
|
||||
|
||||
Netlist::Netlist (const Netlist &other)
|
||||
: gsi::ObjectBase (other), tl::Object (other), m_case_sensitive (true),
|
||||
: gsi::ObjectBase (other), tl::Object (other),
|
||||
m_valid_topology (false), m_lock_count (0),
|
||||
m_circuit_by_name (this, &Netlist::begin_circuits, &Netlist::end_circuits),
|
||||
m_circuit_by_cell_index (this, &Netlist::begin_circuits, &Netlist::end_circuits),
|
||||
|
||||
@@ -3059,9 +3059,37 @@ NetlistComparer::unmatched_circuits (db::Netlist *a, db::Netlist *b, std::vector
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_primary_classes (const db::Netlist *nl)
|
||||
{
|
||||
for (db::Netlist::const_device_class_iterator dc = nl->begin_device_classes (); dc != nl->end_device_classes (); ++dc) {
|
||||
dc->set_primary_class (0);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
|
||||
{
|
||||
bool res = false;
|
||||
|
||||
try {
|
||||
res = compare_impl (a, b);
|
||||
clear_primary_classes (a);
|
||||
clear_primary_classes (b);
|
||||
} catch (...) {
|
||||
clear_primary_classes (a);
|
||||
clear_primary_classes (b);
|
||||
throw;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool
|
||||
NetlistComparer::compare_impl (const db::Netlist *a, const db::Netlist *b) const
|
||||
{
|
||||
clear_primary_classes (a);
|
||||
clear_primary_classes (b);
|
||||
|
||||
m_case_sensitive = combined_case_sensitive (a, b);
|
||||
|
||||
// we need to create a copy because this method is supposed to be const.
|
||||
@@ -3130,21 +3158,12 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
|
||||
}
|
||||
}
|
||||
|
||||
// impose the compare tolerances of the layout (first netlist) on the schematic (second netlist)
|
||||
// TODO: this is kind of clumsy. But it's very important to use the same device sorting for both netlists, so we play this trick.
|
||||
// A better solution was to have a common compare framework for both netlists.
|
||||
// Register the primary netlist's device classes as primary ones for the second netlist's device classes.
|
||||
// This way, the tolerances and parameter definitions are imposed on the second netlist, creating a common basis.
|
||||
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) {
|
||||
|
||||
const db::DeviceClass *da = i->second.first;
|
||||
db::DeviceClass *db = const_cast<db::DeviceClass *> (i->second.second);
|
||||
|
||||
const db::DeviceParameterCompareDelegate *cmp = da->parameter_compare_delegate ();
|
||||
db->set_parameter_compare_delegate (const_cast<db::DeviceParameterCompareDelegate *> (cmp));
|
||||
|
||||
i->second.second->set_primary_class (i->second.first);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// decide whether to use a device category in strict mode
|
||||
|
||||
@@ -354,6 +354,7 @@ private:
|
||||
NetlistComparer &operator= (const NetlistComparer &);
|
||||
|
||||
protected:
|
||||
bool compare_impl (const db::Netlist *a, const db::Netlist *b) const;
|
||||
bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2, db::DeviceCategorizer &device_categorizer, db::CircuitCategorizer &circuit_categorizer, db::CircuitPinMapper &circuit_pin_mapper, const std::vector<std::pair<std::pair<const Net *, const Net *>, bool> > &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;
|
||||
bool all_subcircuits_verified (const db::Circuit *c, const std::set<const db::Circuit *> &verified_circuits) const;
|
||||
std::string generate_subcircuits_not_verified_warning (const db::Circuit *ca, const std::set<const db::Circuit *> &verified_circuits_a, const db::Circuit *cb, const std::set<const db::Circuit *> &verified_circuits_b) const;
|
||||
|
||||
@@ -625,9 +625,6 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
||||
std::map<std::string, double>::const_iterator v = params.find (i->name ());
|
||||
if (v != params.end ()) {
|
||||
device->set_parameter_value (i->id (), v->second / i->si_scaling ());
|
||||
// Make given parameters primary. This way they are netlisted again and participate in netlist compare when
|
||||
// they are made primary in the extracted netlist too.
|
||||
i->set_is_primary (true);
|
||||
} else if (i->id () == defp) {
|
||||
device->set_parameter_value (i->id (), value / i->si_scaling ());
|
||||
}
|
||||
|
||||
@@ -404,6 +404,13 @@ TEST(0_EqualDeviceParameters)
|
||||
d1.set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, 0.5);
|
||||
d2.set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, 0.2);
|
||||
|
||||
EXPECT_EQ (dc.equal (d1, d2), false);
|
||||
EXPECT_EQ (dc.equal (d2, d1), false);
|
||||
EXPECT_EQ (dc.less (d1, d2), false);
|
||||
EXPECT_EQ (dc.less (d2, d1), true);
|
||||
|
||||
*eqp += db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_W, true); // ignore W
|
||||
|
||||
EXPECT_EQ (dc.equal (d1, d2), true);
|
||||
EXPECT_EQ (dc.equal (d2, d1), true);
|
||||
EXPECT_EQ (dc.less (d1, d2), false);
|
||||
@@ -959,7 +966,9 @@ TEST(5_BufferTwoPathsDifferentParameters)
|
||||
EXPECT_EQ (good, false);
|
||||
|
||||
logger.clear ();
|
||||
nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 1.5, 0.0));
|
||||
db::EqualDeviceParameters *eql = new db::EqualDeviceParameters ();
|
||||
*eql += db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 1.5, 0.0);
|
||||
nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (eql);
|
||||
good = comp.compare (&nl1, &nl2);
|
||||
|
||||
EXPECT_EQ (logger.text (),
|
||||
|
||||
Reference in New Issue
Block a user