Skip to content

Commit

Permalink
Fixed issue #1608 (Device extractor error shape)
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthias Koefferlein committed Feb 5, 2024
1 parent 1e51cf6 commit f768be6
Show file tree
Hide file tree
Showing 6 changed files with 243 additions and 10 deletions.
26 changes: 22 additions & 4 deletions src/db/db/dbNetlistDeviceExtractor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
20 changes: 14 additions & 6 deletions src/lvs/unit_tests/lvsSimpleTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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*/);
}

18 changes: 18 additions & 0 deletions testdata/lvs/custom_resistors.cir
Original file line number Diff line number Diff line change
@@ -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 added testdata/lvs/custom_resistors.gds
Binary file not shown.
103 changes: 103 additions & 0 deletions testdata/lvs/custom_resistors.l2n
Original file line number Diff line number Diff line change
@@ -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)
)
)
86 changes: 86 additions & 0 deletions testdata/lvs/custom_resistors.lvs
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit f768be6

Please sign in to comment.