From 41fdd7418999089994bc27ab30de130aeaa8c8f5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 10 Mar 2019 22:37:32 +0100 Subject: [PATCH] Custom devices for device extractor - tests in the DRC framework --- src/db/db/gsiDeclDbNetlistDeviceExtractor.cc | 6 +- src/drc/unit_tests/drcSimpleTests.cc | 60 ++++++ testdata/drc/drcSimpleTests_10.drc | 2 +- testdata/drc/drcSimpleTests_11.drc | 204 +++++++++++++++++++ testdata/drc/drcSimpleTests_au11a.cir | 17 ++ testdata/drc/drcSimpleTests_au11b.cir | 19 ++ testdata/drc/vdiv.gds | Bin 0 -> 4288 bytes 7 files changed, 304 insertions(+), 4 deletions(-) create mode 100644 testdata/drc/drcSimpleTests_11.drc create mode 100644 testdata/drc/drcSimpleTests_au11a.cir create mode 100644 testdata/drc/drcSimpleTests_au11b.cir create mode 100644 testdata/drc/vdiv.gds diff --git a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc index 29c04a5eb..911e40aed 100644 --- a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc +++ b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc @@ -100,9 +100,9 @@ namespace tl template<> struct type_traits : public tl::type_traits { - // mark "NetlistDeviceExtractor" as not having a default ctor and no copy ctor + // mark "NetlistDeviceExtractor" as having a default ctor and no copy ctor typedef tl::false_tag has_copy_constructor; - typedef tl::false_tag has_default_constructor; + typedef tl::true_tag has_default_constructor; }; } @@ -212,7 +212,7 @@ Class decl_dbNetlistDeviceExtractor ("db", "DeviceEx "@brief Iterates over all errors collected in the device extractor." ), "@brief The base class for all device extractors.\n" - "This is an abstract base class for device extractors. See \\NetlistDeviceExtractor for a generic " + "This is an abstract base class for device extractors. See \\GenericDeviceExtractor for a generic " "class which you can reimplement to supply your own customized device extractor. " "In many cases using one of the preconfigured specific device extractors may be useful already and " "it's not required to implement a custom one. For an example about a preconfigured device extractor see " diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index e89defa34..885495d8c 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -438,6 +438,66 @@ TEST(10_NetlistExtractionFlat) EXPECT_EQ (drc.run (), 0); + // verify + + { + tl::InputStream is (output); + tl::InputStream is_au (au); + + if (is.read_all () != is_au.read_all ()) { + _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", + tl::absolute_file_path (output), + tl::absolute_file_path (au))); + } + } + + { + tl::InputStream is (output_simplified); + tl::InputStream is_au (au_simplified); + + if (is.read_all () != is_au.read_all ()) { + _this->raise (tl::sprintf ("Compare failed (simplified netlist) - see\n actual: %s\n golden: %s", + tl::absolute_file_path (output_simplified), + tl::absolute_file_path (au_simplified))); + } + } +} + +TEST(11_CustomDevices) +{ + std::string rs = tl::testsrc (); + rs += "/testdata/drc/drcSimpleTests_11.drc"; + + std::string input = tl::testsrc (); + input += "/testdata/drc/vdiv.gds"; + + std::string au = tl::testsrc (); + au += "/testdata/drc/drcSimpleTests_au11a.cir"; + + std::string au_simplified = tl::testsrc (); + au_simplified += "/testdata/drc/drcSimpleTests_au11b.cir"; + + std::string output = this->tmp_file ("tmp.cir"); + std::string output_simplified = this->tmp_file ("tmp_simplified.cir"); + + { + // Set some variables + lym::Macro config; + config.set_text (tl::sprintf ( + "$drc_test_source = '%s'\n" + "$drc_test_target = '%s'\n" + "$drc_test_target_simplified = '%s'\n" + , input, output, output_simplified) + ); + config.set_interpreter (lym::Macro::Ruby); + EXPECT_EQ (config.run (), 0); + } + + lym::Macro drc; + drc.load_from (rs); + EXPECT_EQ (drc.run (), 0); + + // verify { diff --git a/testdata/drc/drcSimpleTests_10.drc b/testdata/drc/drcSimpleTests_10.drc index 83cf1ed6d..743acbd8c 100644 --- a/testdata/drc/drcSimpleTests_10.drc +++ b/testdata/drc/drcSimpleTests_10.drc @@ -1,4 +1,4 @@ -# Hierarchical extraction +# Flat extraction source($drc_test_source) diff --git a/testdata/drc/drcSimpleTests_11.drc b/testdata/drc/drcSimpleTests_11.drc new file mode 100644 index 000000000..e9a059603 --- /dev/null +++ b/testdata/drc/drcSimpleTests_11.drc @@ -0,0 +1,204 @@ + +source($drc_test_source) + +# Drawing layers + +nwell = input(1, 0) +diff = 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) +via = input(10, 0) +metal2 = input(11, 0) + +# Special layer for bulk terminals + +bulk = make_layer + +# Computed layers + +poly_not_res = poly - polyres +poly_in_res = poly & polyres + +diff_in_nwell = diff & nwell +pdiff = diff_in_nwell - nplus +ntie = diff_in_nwell & nplus +pgate = pdiff & poly_not_res +psd = pdiff - pgate +hv_pgate = pgate & thickox +lv_pgate = pgate - hv_pgate +hv_psd = psd & thickox +lv_psd = psd - thickox + +diff_outside_nwell = diff - nwell +ndiff = diff_outside_nwell - pplus +ptie = diff_outside_nwell & pplus +ngate = ndiff & poly_not_res +nsd = ndiff - ngate +hv_ngate = ngate & thickox +lv_ngate = ngate - hv_ngate +hv_nsd = nsd & thickox +lv_nsd = nsd - thickox + +# Resistor device extraction + +class CustomResistorExtraction < RBA::GenericDeviceExtractor + + def initialize(name, sheet_rho) + self.name = name + @sheet_rho = sheet_rho + end + + def setup + + define_layer("M", "Marker") + define_layer("C", "Conductor") + define_layer("R", "Resistor") + + register_device_class (RBA::DeviceClassResistor::new); + + end + + def extract_devices(layer_geometry) + + marker = layer_geometry[0] + conductor = layer_geometry[1] + resistor = layer_geometry[2] + + conductor_geometry_index = 1 + + resistor_merged = resistor.merged + + marker_edges = marker.merged.edges & resistor_merged.edges + + resistor_merged.each do |r| + + connection_edges = marker_edges.interacting(RBA::Region::new(r)) + + terminals = connection_edges.extended_out(1) + + if terminals.size != 2 + error("Resistor shape does not touch marker border in exactly two places", r) + else + + # A = L*W + # P = 2*(L+W) + # -> L = p+sqrt(p*p-A) + # -> W = p-sqrt(p*p-A) + # (p=P/4) + + p = 0.25 * r.perimeter + a = r.area + + d = Math.sqrt(p * p - a) + l = p + d + w = p - d + + if w > 1e-3 + + device = create_device + + device.set_parameter(RBA::DeviceClassResistor::PARAM_R, @sheet_rho * l / w); + + define_terminal(device, RBA::DeviceClassResistor::TERMINAL_A, conductor_geometry_index, terminals[0]); + define_terminal(device, RBA::DeviceClassResistor::TERMINAL_B, conductor_geometry_index, terminals[1]); + + end + + end + + end + + end + + def get_connectivity(layout, layers) + + # the layer definition is marker, conductor, resistor + # * resistor is used for extraction + # * conductor is used for producing the terminals + # * marker is included because it's required for the extraction + + marker = layers[0] + conductor = layers[1] + resistor = layers[2] + + conn = RBA::Connectivity::new + + conn.connect(resistor, resistor) + conn.connect(conductor, resistor) + conn.connect(marker, resistor) + + return conn; + + end + +end + + + +# Resistor + +# Assumes a sheet rho of 150 Ohm/Square +res_ex = CustomResistorExtraction::new("RES", 150.0) +extract_devices(res_ex, { "C" => poly_not_res, "R" => poly_in_res, "M" => polyres }) + +# PMOS transistor device extraction + +hvpmos_ex = RBA::DeviceExtractorMOS4Transistor::new("HVPMOS") +extract_devices(hvpmos_ex, { "SD" => psd, "G" => hv_pgate, "P" => poly_not_res, "W" => nwell }) + +lvpmos_ex = RBA::DeviceExtractorMOS4Transistor::new("LVPMOS") +extract_devices(lvpmos_ex, { "SD" => psd, "G" => lv_pgate, "P" => poly_not_res, "W" => nwell }) + +# NMOS transistor device extraction + +lvnmos_ex = RBA::DeviceExtractorMOS4Transistor::new("LVNMOS") +extract_devices(lvnmos_ex, { "SD" => nsd, "G" => lv_ngate, "P" => poly_not_res, "W" => bulk }) + +hvnmos_ex = RBA::DeviceExtractorMOS4Transistor::new("HVNMOS") +extract_devices(hvnmos_ex, { "SD" => nsd, "G" => hv_ngate, "P" => poly_not_res, "W" => bulk }) + + +# Define connectivity for netlist extraction + +# Inter-layer +connect(contact, ntie) +connect(contact, ptie) +connect(nwell, ntie) +connect(psd, contact) +connect(nsd, contact) +connect(poly_not_res, contact) +connect(contact, metal1) +connect(metal1, via) +connect(via, metal2) + +# Global connections +connect_global(ptie, "BULK") +connect_global(bulk, "BULK") + +# Actually performs the extraction + +netlist = l2n_data.netlist + +# Write the netlist + +writer = RBA::NetlistSpiceWriter::new + +writer = RBA::NetlistSpiceWriter::new +netlist.write($drc_test_target, writer, "VDIV netlist before simplification") + +# Netlist simplification + +# NOTE: use make_top_level_pins before combine_devices as the pin +# stops the three resistors to be combined into one +netlist.make_top_level_pins +netlist.combine_devices +netlist.purge +netlist.purge_nets + +netlist.write($drc_test_target_simplified, writer, "VDIV netlist after simplification") + diff --git a/testdata/drc/drcSimpleTests_au11a.cir b/testdata/drc/drcSimpleTests_au11a.cir new file mode 100644 index 000000000..8b06b1937 --- /dev/null +++ b/testdata/drc/drcSimpleTests_au11a.cir @@ -0,0 +1,17 @@ +* VDIV netlist before simplification + +* cell TOP +.SUBCKT TOP +* net 1 OUT +* net 2 GND +* net 4 IN +* net 7 VDD +* device instance $1 1.025,0.335 RES +R$1 6 1 7650 +* device instance $2 2.85,0.335 RES +R$2 3 1 7650 +* device instance $3 4.665,0.335 RES +R$3 3 2 2670 +* device instance $4 1.765,7.485 HVPMOS +M$4 6 4 7 7 MHVPMOS L=0.25U W=1.5U AS=0.63P AD=0.63P PS=3.84U PD=3.84U +.ENDS TOP diff --git a/testdata/drc/drcSimpleTests_au11b.cir b/testdata/drc/drcSimpleTests_au11b.cir new file mode 100644 index 000000000..a98b9510e --- /dev/null +++ b/testdata/drc/drcSimpleTests_au11b.cir @@ -0,0 +1,19 @@ +* VDIV netlist after simplification + +* cell TOP +* pin OUT +* pin GND +* pin IN +* pin VDD +.SUBCKT TOP 1 2 3 5 +* net 1 OUT +* net 2 GND +* net 3 IN +* net 5 VDD +* device instance $1 1.025,0.335 RES +R$1 4 1 7650 +* device instance $2 2.85,0.335 RES +R$2 2 1 10320 +* device instance $4 1.765,7.485 HVPMOS +M$4 4 3 5 5 MHVPMOS L=0.25U W=1.5U AS=0.63P AD=0.63P PS=3.84U PD=3.84U +.ENDS TOP diff --git a/testdata/drc/vdiv.gds b/testdata/drc/vdiv.gds new file mode 100644 index 0000000000000000000000000000000000000000..48f2d16f9d3d864bdac06e644e602c4aaae6d27c GIT binary patch literal 4288 zcmcJSO>7la6vxke-I+d${oqkse5RoV`ZVR!Di943EU8%NBT$H7VvHd%5L`%Hm}m?O z6LqH>Bq1TJKw>n;n5YXk#JFIiF>Fbi_>mY0VSx)-^zlD)-g$GbW?D+iB=dglnfsq} z@45ebXNDYw;mcGD!t{5Fs6u_zMH}tkl!b2Zo?S%MDA}>|t=>XZCR zjf16nzCX8PvX1jBH9nu-eI@!7_hG$K<6voi?mxFfpu=dT-@srG<(p<9o(CULv(Dyqy!Sq+;|E-|L!KKtkUj8Fey8z5Wc(J2kzH`cT zn}4x-=j9)fu?Jv=z0^HhFt3eV&-2f-Q)kW{*nJRFh9TG|np=%=QPvgV_b!cfgTXVX z^gl#B-xZ90!On9DXN$pQJXY&yd)ceLw|nypCtLUzDNo6Ll^O?a^*lY_pZ=0O?6#G! ziW`|42d&=Qy=f=%zk{}*8wD{YrN+Thef2o{3|-C{Xjq>Als5w+2eKA}{FP zgm!a5je|D7r?0Mu_6G8U;cDcE+mspytv>bKGYdVAeD}ucUGbW%UM3$L$C2yr%RQK@ zIo(rL_uQ{LxVn6VC(#?YPN{Lwj&8}_5x|w~4t5v2L#c7l=J(vS6z*V0usgyx#2reF zgEs#|b4T=nxI>9vEzlj)js0*^1v^Qv>@#jvaGI#Imh9p;Ts}J49dUp=H)K?3UFmhL z_s63Bx6)kNSI!Xizhc|B-potd^RC>#q21o}hI>#;Ug(~Y+vmMmHbm6-<$qdlq4vG~ z)+>K3TF?~GYk&?ivgmxN{xdyzo)O@{W_S2 zCHOu4G$!lmf*J=)^(k@>ccK4a{X_KsT0xD2rTU(CvBSQHryj`tUGaWFjf16n&O3NV z@^e1Uuhcl0>pNxsG5)>~c65&h{Drv+YlAu;OP+r!KgMJQRNxAy;Py-{Jo~bjFsn11y>SSWYpdtIDe{-%&>-F~z$Z7s1z7h= zje}P2y(y*`+R$}WAFTgC)UmCg#zCu(?XxoNh5ifZ!TJs8PZZQRX!XmjUN#l^UH>Uo Q{xKq@xt8nktc_#32R04HC;$Ke literal 0 HcmV?d00001