mirror of https://github.com/KLayout/klayout.git
Issue 1608 (#1615)
* Fixed issue #1608 (Device extractor error shape) * New test data * Add-on: pressing Esc on the netlist or marker browser clears markers * Updated test data --------- Co-authored-by: Matthias Koefferlein <matthias@klayout.de>
This commit is contained in:
parent
df59641cad
commit
f37e37340c
|
|
@ -287,19 +287,37 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db:
|
|||
extractor_cache_type::const_iterator ec = extractor_cache.find (layer_geometry);
|
||||
if (ec == extractor_cache.end ()) {
|
||||
|
||||
log_entry_list log_entries;
|
||||
m_log_entries.swap (log_entries);
|
||||
|
||||
// do the actual device extraction
|
||||
extract_devices (layer_geometry);
|
||||
|
||||
// push the new devices to the layout
|
||||
push_new_devices (disp);
|
||||
|
||||
ExtractorCacheValueType &ecv = extractor_cache [layer_geometry];
|
||||
ecv.disp = disp;
|
||||
if (m_log_entries.empty ()) {
|
||||
|
||||
// cache unless log entries are produced
|
||||
ExtractorCacheValueType &ecv = extractor_cache [layer_geometry];
|
||||
ecv.disp = disp;
|
||||
|
||||
for (std::map<size_t, std::pair<db::Device *, geometry_per_terminal_type> >::const_iterator d = m_new_devices.begin (); d != m_new_devices.end (); ++d) {
|
||||
ecv.devices.push_back (d->second.first);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// transform the marker geometries from the log entries to match the device
|
||||
db::DVector disp_dbu = db::CplxTrans (dbu ()) * disp;
|
||||
for (auto l = m_log_entries.begin (); l != m_log_entries.end (); ++l) {
|
||||
l->set_geometry (l->geometry ().moved (disp_dbu));
|
||||
}
|
||||
|
||||
for (std::map<size_t, std::pair<db::Device *, geometry_per_terminal_type> >::const_iterator d = m_new_devices.begin (); d != m_new_devices.end (); ++d) {
|
||||
ecv.devices.push_back (d->second.first);
|
||||
}
|
||||
|
||||
m_log_entries.splice (m_log_entries.begin (), log_entries);
|
||||
|
||||
m_new_devices.clear ();
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -95,6 +95,16 @@ Browser::accept ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Browser::reject ()
|
||||
{
|
||||
if (active ()) {
|
||||
m_active = false;
|
||||
deactivated ();
|
||||
QDialog::reject ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ private:
|
|||
|
||||
void closeEvent (QCloseEvent *);
|
||||
void accept ();
|
||||
void reject ();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
#include "lymMacro.h"
|
||||
#include "tlFileUtils.h"
|
||||
|
||||
void run_test (tl::TestBase *_this, const std::string &suffix, const std::string &layout, bool with_l2n = false, const std::string &top = std::string (), bool change_case = false)
|
||||
void run_test (tl::TestBase *_this, const std::string &suffix, const std::string &layout, bool with_l2n = false, bool with_lvs = true, const std::string &top = std::string (), bool change_case = false)
|
||||
{
|
||||
std::string rs = tl::testdata ();
|
||||
rs += "/lvs/" + suffix + ".lvs";
|
||||
|
|
@ -70,7 +70,9 @@ void run_test (tl::TestBase *_this, const std::string &suffix, const std::string
|
|||
lvs.load_from (rs);
|
||||
EXPECT_EQ (lvs.run (), 0);
|
||||
|
||||
_this->compare_text_files (output_lvsdb, au_lvsdb);
|
||||
if (with_lvs) {
|
||||
_this->compare_text_files (output_lvsdb, au_lvsdb);
|
||||
}
|
||||
_this->compare_text_files (output_cir, au_cir);
|
||||
if (with_l2n) {
|
||||
_this->compare_text_files (output_l2n, au_l2n);
|
||||
|
|
@ -121,14 +123,14 @@ TEST(6_simple_pin_swapping)
|
|||
{
|
||||
run_test (_this, "ringo_simple_pin_swapping", "ringo.gds");
|
||||
// change case
|
||||
run_test (_this, "ringo_simple_pin_swapping", "ringo.gds", false, std::string (), true);
|
||||
run_test (_this, "ringo_simple_pin_swapping", "ringo.gds", false, true, std::string (), true);
|
||||
}
|
||||
|
||||
TEST(7_net_and_circuit_equivalence)
|
||||
{
|
||||
run_test (_this, "ringo_simple_net_and_circuit_equivalence", "ringo_renamed.gds");
|
||||
// change case
|
||||
run_test (_this, "ringo_simple_net_and_circuit_equivalence", "ringo_renamed.gds", false, std::string (), true);
|
||||
run_test (_this, "ringo_simple_net_and_circuit_equivalence", "ringo_renamed.gds", false, true, std::string (), true);
|
||||
}
|
||||
|
||||
TEST(8_simplification)
|
||||
|
|
@ -166,7 +168,7 @@ TEST(13_simple_ringo_device_subcircuits)
|
|||
{
|
||||
run_test (_this, "ringo_device_subcircuits", "ringo.gds");
|
||||
// change case
|
||||
run_test (_this, "ringo_device_subcircuits", "ringo.gds", false, std::string (), true);
|
||||
run_test (_this, "ringo_device_subcircuits", "ringo.gds", false, true, std::string (), true);
|
||||
}
|
||||
|
||||
TEST(14_simple_ringo_mixed_hierarchy)
|
||||
|
|
@ -181,7 +183,7 @@ TEST(15_simple_dummy_device)
|
|||
|
||||
TEST(16_floating)
|
||||
{
|
||||
run_test (_this, "floating", "floating.gds", false, "TOP");
|
||||
run_test (_this, "floating", "floating.gds", false, true, "TOP");
|
||||
}
|
||||
|
||||
TEST(17_layout_variants)
|
||||
|
|
@ -287,3 +289,9 @@ TEST(31_MustConnect2)
|
|||
run_test (_this, "must_connect2", "must_connect2.gds");
|
||||
}
|
||||
|
||||
// issue 1609
|
||||
TEST(40_DeviceExtractorErrors)
|
||||
{
|
||||
run_test (_this, "custom_resistors", "custom_resistors.gds", true, false /*no LVS*/);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ TEST(20_private)
|
|||
|
||||
TEST(21_private)
|
||||
{
|
||||
run_test (_this, "test_21.lylvs", "test_21.cir.gz", "test_21.gds.gz", true, "test_21_3.lvsdb");
|
||||
run_test (_this, "test_21.lylvs", "test_21.cir.gz", "test_21.gds.gz", true, "test_21_4.lvsdb");
|
||||
}
|
||||
|
||||
// issue #1021
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
* cell TOP
|
||||
.SUBCKT TOP
|
||||
* cell instance $1 r180 *1 2,2.6
|
||||
X$1 6 1 A
|
||||
* cell instance $2 r0 *1 2.2,1
|
||||
X$2 6 5 A
|
||||
* device instance $1 r0 *1 0.8,0.75 RPP1
|
||||
R$1 2 1 0.555555555556 RPP1
|
||||
.ENDS TOP
|
||||
|
||||
* cell A
|
||||
* pin
|
||||
* pin
|
||||
.SUBCKT A 1 2
|
||||
* device instance $1 r0 *1 -0.2,0.4 RPP1
|
||||
R$1 1 2 1.25 RPP1
|
||||
.ENDS A
|
||||
Binary file not shown.
|
|
@ -0,0 +1,103 @@
|
|||
#%l2n-klayout
|
||||
W(TOP)
|
||||
U(0.001)
|
||||
L(l4 '15/0')
|
||||
L(l3 '16/0')
|
||||
L(l1)
|
||||
C(l4 l4 l3 l1)
|
||||
C(l3 l4 l3)
|
||||
C(l1 l4 l1)
|
||||
H(E B('Resistor shape does not touch marker border in exactly two places') C(TOP) X('device-extract') Q('(0.8,0.75;0.8,1.15;1,1.15;1,0.75)'))
|
||||
H(E B('Resistor shape does not touch marker border in exactly two places') C(TOP) X('device-extract') Q('(0,0.75;0,1.15;0.2,1.15;0.2,0.75)'))
|
||||
H(E B('Resistor shape does not touch marker border in exactly two places') C(A) X('device-extract') Q('(0.85,-0.4;0.85,-0.2;1.25,-0.2;1.25,-0.4)'))
|
||||
K(RPP1 RES)
|
||||
D(D$RPP1 RPP1
|
||||
T(A
|
||||
R(l1 (0 400) (200 300))
|
||||
)
|
||||
T(B
|
||||
R(l1 (0 1200) (200 250))
|
||||
)
|
||||
)
|
||||
D(D$RPP1$1 RPP1
|
||||
T(A
|
||||
R(l1 (0 0) (250 200))
|
||||
)
|
||||
T(B
|
||||
R(l1 (750 0) (250 200))
|
||||
)
|
||||
)
|
||||
X(A
|
||||
R((-200 -450) (1750 1350))
|
||||
N(1
|
||||
R(l4 (-150 450) (100 100))
|
||||
R(l3 (-150 -150) (200 500))
|
||||
R(l1 (-200 -500) (250 200))
|
||||
)
|
||||
N(2
|
||||
R(l4 (650 450) (100 100))
|
||||
R(l4 (-100 -900) (100 100))
|
||||
R(l3 (-150 200) (200 650))
|
||||
R(l3 (-200 -1000) (200 500))
|
||||
R(l1 (-250 300) (250 200))
|
||||
R(l1 (-200 -1000) (250 200))
|
||||
)
|
||||
N(3
|
||||
R(l4 (1450 -350) (100 100))
|
||||
)
|
||||
P(1)
|
||||
P(2)
|
||||
D(1 D$RPP1$1
|
||||
Y(-200 400)
|
||||
E(R 1.25)
|
||||
E(L 0.5)
|
||||
E(W 0.2)
|
||||
E(A 0.1)
|
||||
E(P 1.4)
|
||||
T(A 1)
|
||||
T(B 2)
|
||||
)
|
||||
)
|
||||
X(TOP
|
||||
R((-50 450) (3800 2600))
|
||||
N(1
|
||||
R(l4 (850 2050) (100 100))
|
||||
R(l3 (-150 -150) (500 200))
|
||||
R(l1 (-500 -250) (200 250))
|
||||
)
|
||||
N(2
|
||||
R(l4 (850 1250) (100 100))
|
||||
R(l4 (-100 -100) (100 100))
|
||||
R(l4 (-900 -100) (100 100))
|
||||
R(l3 (200 -150) (650 200))
|
||||
R(l3 (-1000 -200) (500 200))
|
||||
R(l1 (300 -250) (200 300))
|
||||
R(l1 (-1000 -300) (200 250))
|
||||
)
|
||||
N(3
|
||||
R(l4 (50 450) (100 100))
|
||||
)
|
||||
N(4
|
||||
R(l4 (850 450) (100 100))
|
||||
)
|
||||
N(5)
|
||||
N(6)
|
||||
D(1 D$RPP1
|
||||
Y(800 750)
|
||||
E(R 0.555555555556)
|
||||
E(L 0.333333333333)
|
||||
E(W 0.3)
|
||||
E(A 0.1)
|
||||
E(P 1.26666666667)
|
||||
T(A 2)
|
||||
T(B 1)
|
||||
)
|
||||
X(1 A O(180) Y(2000 2600)
|
||||
P(0 6)
|
||||
P(1 1)
|
||||
)
|
||||
X(2 A Y(2200 1000)
|
||||
P(0 6)
|
||||
P(1 5)
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
#%l2n-klayout
|
||||
W(TOP)
|
||||
U(0.001)
|
||||
L(l4 '15/0')
|
||||
L(l3 '16/0')
|
||||
L(l1)
|
||||
C(l4 l4 l3 l1)
|
||||
C(l3 l4 l3)
|
||||
C(l1 l4 l1)
|
||||
H(E B('Resistor shape does not touch marker border in exactly two places') C(TOP) X('device-extract') Q('(0,0.75;0,1.15;0.2,1.15;0.2,0.75)'))
|
||||
H(E B('Resistor shape does not touch marker border in exactly two places') C(TOP) X('device-extract') Q('(0.8,0.75;0.8,1.15;1,1.15;1,0.75)'))
|
||||
H(E B('Resistor shape does not touch marker border in exactly two places') C(A) X('device-extract') Q('(0.85,-0.4;0.85,-0.2;1.25,-0.2;1.25,-0.4)'))
|
||||
K(RPP1 RES)
|
||||
D(D$RPP1 RPP1
|
||||
T(A
|
||||
R(l1 (0 400) (200 300))
|
||||
)
|
||||
T(B
|
||||
R(l1 (0 1200) (200 250))
|
||||
)
|
||||
)
|
||||
D(D$RPP1$1 RPP1
|
||||
T(A
|
||||
R(l1 (0 0) (250 200))
|
||||
)
|
||||
T(B
|
||||
R(l1 (750 0) (250 200))
|
||||
)
|
||||
)
|
||||
X(A
|
||||
R((-200 -450) (1750 1350))
|
||||
N(1
|
||||
R(l4 (-150 450) (100 100))
|
||||
R(l3 (-150 -150) (200 500))
|
||||
R(l1 (-200 -500) (250 200))
|
||||
)
|
||||
N(2
|
||||
R(l4 (650 450) (100 100))
|
||||
R(l4 (-100 -900) (100 100))
|
||||
R(l3 (-150 200) (200 650))
|
||||
R(l3 (-200 -1000) (200 500))
|
||||
R(l1 (-250 300) (250 200))
|
||||
R(l1 (-200 -1000) (250 200))
|
||||
)
|
||||
N(3
|
||||
R(l4 (1450 -350) (100 100))
|
||||
)
|
||||
P(1)
|
||||
P(2)
|
||||
D(1 D$RPP1$1
|
||||
Y(-200 400)
|
||||
E(R 1.25)
|
||||
E(L 0.5)
|
||||
E(W 0.2)
|
||||
E(A 0.1)
|
||||
E(P 1.4)
|
||||
T(A 1)
|
||||
T(B 2)
|
||||
)
|
||||
)
|
||||
X(TOP
|
||||
R((-50 450) (3800 2600))
|
||||
N(1
|
||||
R(l4 (850 2050) (100 100))
|
||||
R(l3 (-150 -150) (500 200))
|
||||
R(l1 (-500 -250) (200 250))
|
||||
)
|
||||
N(2
|
||||
R(l4 (850 1250) (100 100))
|
||||
R(l4 (-100 -100) (100 100))
|
||||
R(l4 (-900 -100) (100 100))
|
||||
R(l3 (200 -150) (650 200))
|
||||
R(l3 (-1000 -200) (500 200))
|
||||
R(l1 (300 -250) (200 300))
|
||||
R(l1 (-1000 -300) (200 250))
|
||||
)
|
||||
N(3
|
||||
R(l4 (50 450) (100 100))
|
||||
)
|
||||
N(4
|
||||
R(l4 (850 450) (100 100))
|
||||
)
|
||||
N(5)
|
||||
N(6)
|
||||
D(1 D$RPP1
|
||||
Y(800 750)
|
||||
E(R 0.555555555556)
|
||||
E(L 0.333333333333)
|
||||
E(W 0.3)
|
||||
E(A 0.1)
|
||||
E(P 1.26666666667)
|
||||
T(A 2)
|
||||
T(B 1)
|
||||
)
|
||||
X(1 A O(180) Y(2000 2600)
|
||||
P(0 6)
|
||||
P(1 1)
|
||||
)
|
||||
X(2 A Y(2200 1000)
|
||||
P(0 6)
|
||||
P(1 5)
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
|
||||
source($lvs_test_source, "TOP")
|
||||
|
||||
report_netlist($lvs_test_target_l2n)
|
||||
target_netlist($lvs_test_target_cir)
|
||||
|
||||
deep
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# Layers
|
||||
|
||||
poly_dg = input(13, 0)
|
||||
cont = input(15, 0)
|
||||
met1_dg = input(16, 0)
|
||||
sblk = input(34, 0)
|
||||
rp_1 = sblk & poly_dg
|
||||
p1trm = poly_dg - rp_1
|
||||
|
||||
class ResistorExtractor < RBA::GenericDeviceExtractor
|
||||
|
||||
def initialize(name, sheet_rho)
|
||||
self.name = name
|
||||
@sheet_rho = sheet_rho
|
||||
end
|
||||
|
||||
def setup
|
||||
define_layer("C", "Conductor")
|
||||
define_layer("R", "Resistor")
|
||||
register_device_class(RBA::DeviceClassResistor::new)
|
||||
end
|
||||
|
||||
def get_connectivity(layout, layers)
|
||||
# this "connectivity" forms the shape clusters that make up the device
|
||||
conn = RBA::Connectivity::new
|
||||
conn.connect(layers[0], layers[1]) # collect touching contacts
|
||||
conn.connect(layers[1], layers[1]) # combine resistor shapes into one area
|
||||
conn
|
||||
end
|
||||
|
||||
def extract_devices(layer_geometry)
|
||||
# layer_geometry provides the input layers in the order they are defined with "define_layer"
|
||||
conductor = layer_geometry[0]
|
||||
resistor = layer_geometry[1]
|
||||
|
||||
resistor_regions = resistor.merged
|
||||
|
||||
resistor_regions.each do |r|
|
||||
terminals = conductor.interacting(RBA::Region::new(r))
|
||||
if terminals.size != 2
|
||||
error("Resistor shape does not touch marker border in exactly two places", r)
|
||||
else
|
||||
double_width = 0
|
||||
(terminals.edges & resistor.edges).merged.each do |e|
|
||||
double_width += e.length
|
||||
end
|
||||
# A = L*W
|
||||
# -> L = A/W
|
||||
a = r.area*dbu*dbu
|
||||
w = (double_width / 2.0)*dbu
|
||||
l = a / w
|
||||
|
||||
device = create_device
|
||||
device.set_parameter(RBA::DeviceClassResistor::PARAM_R, @sheet_rho * l / w);
|
||||
|
||||
device.set_parameter(RBA::DeviceClassResistor::PARAM_A, a)
|
||||
device.set_parameter(RBA::DeviceClassResistor::PARAM_L, l)
|
||||
device.set_parameter(RBA::DeviceClassResistor::PARAM_P, 2*l+2*w)
|
||||
device.set_parameter(RBA::DeviceClassResistor::PARAM_W, w)
|
||||
define_terminal(device, "A", "C", terminals[0]);
|
||||
define_terminal(device, "B", "C", terminals[1]);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
extract_devices(ResistorExtractor::new("RPP1", 0.5), # intentionally wrong: 1565.15/5
|
||||
{ "C" => p1trm, "R" => rp_1 })
|
||||
|
||||
connect(met1_dg, cont)
|
||||
connect(p1trm, cont)
|
||||
|
||||
begin
|
||||
netlist
|
||||
rescue => ex
|
||||
end
|
||||
|
||||
Loading…
Reference in New Issue