Fixed #806: first, the internal error gone. Second, the implementation of custom comparers is simplified as the 'equals' method does not need to be implemented.

This commit is contained in:
Matthias Koefferlein 2021-05-26 22:39:28 +02:00
parent ef22ead019
commit fcb966393a
10 changed files with 204 additions and 44 deletions

View File

@ -79,18 +79,6 @@ bool EqualDeviceParameters::less (const db::Device &a, const db::Device &b) cons
return false; return false;
} }
bool EqualDeviceParameters::equal (const db::Device &a, const db::Device &b) const
{
for (std::vector<std::pair<size_t, std::pair<double, double> > >::const_iterator c = m_compare_set.begin (); c != m_compare_set.end (); ++c) {
int cmp = compare_parameters (a.parameter_value (c->first), b.parameter_value (c->first), c->second.first, c->second.second);
if (cmp != 0) {
return false;
}
}
return true;
}
EqualDeviceParameters &EqualDeviceParameters::operator+= (const EqualDeviceParameters &other) EqualDeviceParameters &EqualDeviceParameters::operator+= (const EqualDeviceParameters &other)
{ {
for (std::vector<std::pair<size_t, std::pair<double, double> > >::const_iterator c = other.m_compare_set.begin (); c != other.m_compare_set.end (); ++c) { for (std::vector<std::pair<size_t, std::pair<double, double> > >::const_iterator c = other.m_compare_set.begin (); c != other.m_compare_set.end (); ++c) {
@ -121,19 +109,6 @@ bool AllDeviceParametersAreEqual::less (const db::Device &a, const db::Device &b
return false; return false;
} }
bool AllDeviceParametersAreEqual::equal (const db::Device &a, const db::Device &b) const
{
const std::vector<db::DeviceParameterDefinition> &parameters = a.device_class ()->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::const_iterator c = parameters.begin (); c != parameters.end (); ++c) {
int cmp = compare_parameters (a.parameter_value (c->id ()), b.parameter_value (c->id ()), 0.0, m_relative);
if (cmp != 0) {
return false;
}
}
return true;
}
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
// DeviceClass class implementation // DeviceClass class implementation
@ -293,7 +268,7 @@ bool DeviceClass::equal (const db::Device &a, const db::Device &b)
} }
if (pcd != 0) { if (pcd != 0) {
return pcd->equal (a, b); return ! pcd->less (a, b) && ! pcd->less (b, a);
} else { } else {
const std::vector<db::DeviceParameterDefinition> &pd = a.device_class ()->parameter_definitions (); const std::vector<db::DeviceParameterDefinition> &pd = a.device_class ()->parameter_definitions ();

View File

@ -297,7 +297,6 @@ public:
virtual DeviceParameterCompareDelegate *clone () const = 0; virtual DeviceParameterCompareDelegate *clone () const = 0;
virtual bool less (const db::Device &a, const db::Device &b) const = 0; virtual bool less (const db::Device &a, const db::Device &b) const = 0;
virtual bool equal (const db::Device &a, const db::Device &b) const = 0;
}; };
/** /**
@ -315,7 +314,6 @@ public:
EqualDeviceParameters (size_t parameter_id, double relative, double absolute); EqualDeviceParameters (size_t parameter_id, double relative, double absolute);
virtual bool less (const db::Device &a, const db::Device &b) const; virtual bool less (const db::Device &a, const db::Device &b) const;
virtual bool equal (const db::Device &a, const db::Device &b) const;
virtual DeviceParameterCompareDelegate *clone () const virtual DeviceParameterCompareDelegate *clone () const
{ {
@ -345,7 +343,6 @@ public:
AllDeviceParametersAreEqual (double relative); AllDeviceParametersAreEqual (double relative);
virtual bool less (const db::Device &a, const db::Device &b) const; virtual bool less (const db::Device &a, const db::Device &b) const;
virtual bool equal (const db::Device &a, const db::Device &b) const;
virtual DeviceParameterCompareDelegate *clone () const virtual DeviceParameterCompareDelegate *clone () const
{ {

View File

@ -3052,7 +3052,7 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
db::DeviceClass *db = const_cast<db::DeviceClass *> (i->second.second); db::DeviceClass *db = const_cast<db::DeviceClass *> (i->second.second);
const db::DeviceParameterCompareDelegate *cmp = da->parameter_compare_delegate (); const db::DeviceParameterCompareDelegate *cmp = da->parameter_compare_delegate ();
db->set_parameter_compare_delegate (cmp ? cmp->clone () : 0); db->set_parameter_compare_delegate (const_cast<db::DeviceParameterCompareDelegate *> (cmp));
} }

View File

@ -843,15 +843,6 @@ public:
} }
} }
virtual bool equal (const db::Device &a, const db::Device &b) const
{
if (cb_equal.can_issue ()) {
return cb_equal.issue<db::EqualDeviceParameters, bool, const db::Device &, const db::Device &> (&db::EqualDeviceParameters::equal, a, b);
} else {
return db::EqualDeviceParameters::equal (a, b);
}
}
gsi::Callback cb_less, cb_equal; gsi::Callback cb_less, cb_equal;
}; };
@ -903,13 +894,12 @@ Class<db::EqualDeviceParameters> decl_dbEqualDeviceParameters ("db", "EqualDevic
); );
Class<GenericDeviceParameterCompare> decl_GenericDeviceParameterCompare (decl_dbEqualDeviceParameters, "db", "GenericDeviceParameterCompare", Class<GenericDeviceParameterCompare> decl_GenericDeviceParameterCompare (decl_dbEqualDeviceParameters, "db", "GenericDeviceParameterCompare",
gsi::callback ("equal", &GenericDeviceParameterCompare::equal, &GenericDeviceParameterCompare::cb_equal, gsi::arg ("device_a"), gsi::arg ("device_b"),
"@brief Compares the parameters of two devices for equality. "
"Returns true, if the parameters of device a and b are considered equal."
) +
gsi::callback ("less", &GenericDeviceParameterCompare::less, &GenericDeviceParameterCompare::cb_less, gsi::arg ("device_a"), gsi::arg ("device_b"), gsi::callback ("less", &GenericDeviceParameterCompare::less, &GenericDeviceParameterCompare::cb_less, gsi::arg ("device_a"), gsi::arg ("device_b"),
"@brief Compares the parameters of two devices for a begin less than b. " "@brief Compares the parameters of two devices for a begin less than b. "
"Returns true, if the parameters of device a are considered less than those of device b." "Returns true, if the parameters of device a are considered less than those of device b."
"The 'less' implementation needs to ensure strict weak ordering. Specifically, less(a,b) == false and less(b,a) implies that a is equal to b and "
"less(a,b) == true implies that less(b,a) is false and vice versa. If not, an internal error "
"will be encountered on netlist compare."
), ),
"@brief A class implementing the comparison of device parameters.\n" "@brief A class implementing the comparison of device parameters.\n"
"Reimplement this class to provide a custom device parameter compare scheme.\n" "Reimplement this class to provide a custom device parameter compare scheme.\n"
@ -919,7 +909,7 @@ Class<GenericDeviceParameterCompare> decl_GenericDeviceParameterCompare (decl_db
"This class is intended for special cases. In most scenarios it is easier to use \\EqualDeviceParameters instead of " "This class is intended for special cases. In most scenarios it is easier to use \\EqualDeviceParameters instead of "
"implementing a custom comparer class.\n" "implementing a custom comparer class.\n"
"\n" "\n"
"This class has been added in version 0.26." "This class has been added in version 0.26. The 'equal' method has been dropped in 0.27.1 as it can be expressed as !less(a,b) && !less(b,a)."
); );
static tl::id_type id_of_device_class (const db::DeviceClass *cls) static tl::id_type id_of_device_class (const db::DeviceClass *cls)

View File

@ -206,3 +206,8 @@ TEST(23_issue709)
run_test (_this, "empty_subcells", "empty_subcells.gds"); run_test (_this, "empty_subcells", "empty_subcells.gds");
} }
// empty gds
TEST(24_issue806)
{
run_test (_this, "custom_compare", "custom_compare.gds");
}

7
testdata/lvs/custom_compare.cir vendored Normal file
View File

@ -0,0 +1,7 @@
* Extracted by KLayout
* cell TOP
.SUBCKT TOP
* device instance $1 r0 *1 7.52,4.175 RES
R$1 2 1 51 RES
.ENDS TOP

BIN
testdata/lvs/custom_compare.gds vendored Normal file

Binary file not shown.

72
testdata/lvs/custom_compare.lvs vendored Normal file
View File

@ -0,0 +1,72 @@
source($lvs_test_source)
report_lvs($lvs_test_target_lvsdb, true)
target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
schematic("custom_compare_sch.cir")
deep
# -------------------------------------------------------------------
# Layers
# Drawing layers
nwell = input(1, 0)
active = input(2, 0)
pplus = input(3, 0)
nplus = input(4, 0)
poly = input(5, 0)
thickox = input(6, 0)
polyres = input(7, 0)
contact = input(8, 0)
metal1 = input(9, 0) # includes labels
via1 = input(10, 0)
metal2 = input(11, 0) # includes labels
# Bulk layer for terminal provisioning
bulk = polygon_layer
# Computed layers
poly_not_res = poly - polyres
poly_in_res = poly & polyres
# Resistor Definition
res_ex = resistor("RES", 1.0)
extract_devices(res_ex, { "C" => poly_not_res, "R" => poly_in_res })
# -------------------------------------------------------------------
# Connectivity
# Inter-layer
connect(poly_not_res, contact)
# -------------------------------------------------------------------
# Netlist and compare
class ResistorComparator < RBA::GenericDeviceParameterCompare
def less(device_a, device_b)
delta = 1
param_id = RBA::DeviceClassResistor::PARAM_R
param = "R"
if (device_a.parameter(param_id) - device_b.parameter(param_id)).abs > delta
result = device_a.parameter(param_id) < device_b.parameter(param_id)
return result
else
return false
end
end
end
netlist.device_class_by_name("RES").equal_parameters = ResistorComparator::new()
# Netlist normalization
netlist.simplify
# Hierarchy alignment (flatten out unmatched cells)
align
# Netlist vs. netlist
compare

111
testdata/lvs/custom_compare.lvsdb vendored Normal file
View File

@ -0,0 +1,111 @@
#%lvsdb-klayout
# Layout
layout(
top(TOP)
unit(0.001)
# Layer section
# This section lists the mask layers (drawing or derived) and their connections.
# Mask layers
layer(l3 '8/0')
layer(l1)
# Mask layer connectivity
connect(l3 l3 l1)
connect(l1 l3 l1)
# Device class section
class(RES RES)
# Device abstracts section
# Device abstracts list the pin shapes of the devices.
device(D$RES RES
terminal(A
rect(l1 (2225 -675) (200 250))
)
terminal(B
rect(l1 (-2425 425) (200 250))
)
)
# Circuit section
# Circuits are the hierarchical building blocks of the netlist.
circuit(TOP
# Circuit boundary
rect((0 0) (10255 5900))
# Nets with their geometries
net(1
rect(l3 (4850 4600) (180 180))
rect(l1 (-245 -250) (310 320))
rect(l1 (0 -250) (200 250))
)
net(2
rect(l3 (10010 3500) (180 180))
rect(l1 (-245 -250) (310 320))
rect(l1 (-510 -250) (200 250))
)
# Devices and their connections
device(1 D$RES
location(7520 4175)
param(R 51)
param(L 25.5)
param(W 0.5)
param(A 3.1875)
param(P 26)
terminal(A 2)
terminal(B 1)
)
)
)
# Reference netlist
reference(
# Device class section
class(RES RES)
# Circuit section
# Circuits are the hierarchical building blocks of the netlist.
circuit(TOP
# Nets
net(1 name(R1))
net(2 name(R2))
# Outgoing pins and their connections to nets
pin(1 name(R1))
pin(2 name(R2))
# Devices and their connections
device(1 RES
name('5')
param(R 50.1)
param(L 0)
param(W 0)
param(A 0)
param(P 0)
terminal(A 1)
terminal(B 2)
)
)
)
# Cross reference
xref(
circuit(TOP TOP match
xref(
net(1 1 warning)
net(2 2 warning)
pin(() 0 match)
pin(() 1 match)
device(1 1 match)
)
)
)

3
testdata/lvs/custom_compare_sch.cir vendored Normal file
View File

@ -0,0 +1,3 @@
.subckt top r1 r2
r5 r1 r2 50.1
.ends