From 833edf53b2a2a9ab8f27a5198bd61f65eb8aa170 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 2 Jan 2020 22:20:45 +0100 Subject: [PATCH] Implemented #462 (Generalize MOS transistor extraction to other gate figures) --- src/db/db/dbNetlistDeviceExtractorClasses.cc | 67 +- .../dbNetlistDeviceExtractorTests.cc | 720 ++++++++++++++++++ testdata/algo/dmos3_1.gds | Bin 0 -> 298 bytes testdata/algo/dmos3_2.gds | Bin 0 -> 442 bytes testdata/algo/dmos3_3.gds | Bin 0 -> 682 bytes testdata/algo/dmos4_1.gds | Bin 0 -> 362 bytes testdata/algo/dmos4_2.gds | Bin 0 -> 506 bytes testdata/algo/dmos4_3.gds | Bin 0 -> 746 bytes testdata/algo/mos3_1.gds | Bin 0 -> 298 bytes testdata/algo/mos3_2.gds | Bin 0 -> 442 bytes testdata/algo/mos3_3.gds | Bin 0 -> 682 bytes testdata/algo/mos4_1.gds | Bin 0 -> 362 bytes testdata/algo/mos4_2.gds | Bin 0 -> 506 bytes testdata/algo/mos4_3.gds | Bin 0 -> 746 bytes 14 files changed, 770 insertions(+), 17 deletions(-) create mode 100644 testdata/algo/dmos3_1.gds create mode 100644 testdata/algo/dmos3_2.gds create mode 100644 testdata/algo/dmos3_3.gds create mode 100644 testdata/algo/dmos4_1.gds create mode 100644 testdata/algo/dmos4_2.gds create mode 100644 testdata/algo/dmos4_3.gds create mode 100644 testdata/algo/mos3_1.gds create mode 100644 testdata/algo/mos3_2.gds create mode 100644 testdata/algo/mos3_3.gds create mode 100644 testdata/algo/mos4_1.gds create mode 100644 testdata/algo/mos4_2.gds create mode 100644 testdata/algo/mos4_3.gds diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.cc b/src/db/db/dbNetlistDeviceExtractorClasses.cc index 20215b670..e6e3afbb7 100644 --- a/src/db/db/dbNetlistDeviceExtractorClasses.cc +++ b/src/db/db/dbNetlistDeviceExtractorClasses.cc @@ -144,22 +144,39 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector widths; + for (db::Region::const_iterator d2g = rdiff2gate.begin (); ! d2g.at_end (); ++d2g) { + + db::Region rd2g; + rd2g.insert (*d2g); + + db::Edges edges (rgate.edges () & rd2g.edges ()); + db::Edges::length_type l = edges.length (); + if (l == 0) { + error (tl::to_string (tr ("Vanishing edges for interaction gate/diff (corner interaction) - gate shape ignored"))); + } else { + widths.push_back (l); + } + + } + + if (widths.size () != 2) { continue; } - if (! p->is_box ()) { - error (tl::to_string (tr ("Gate shape is not a box - width and length may be incorrect")), *p); - } + // Computation of the gate length and width - this scheme is compatible with + // non-rectangular gates and circular gates. The computation is based on the + // relationship: A(gate) = L(gate) * W(gate). W(gate) is determined from the + // accumulated edge lengths (average of left and right length). + double param_w = sdbu () * (widths[0] + widths[1]) * 0.5; + double param_l = sdbu () * sdbu () * double (rgate.area ()) / param_w; db::Device *device = create_device (); device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ())); - device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, sdbu () * edges.length () * 0.5); - device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, sdbu () * (p->perimeter () - edges.length ()) * 0.5); + device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, param_w); + device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, param_l); int diff_index = 0; for (db::Region::const_iterator d = rdiff2gate.begin (); !d.at_end () && diff_index < 2; ++d, ++diff_index) { @@ -230,24 +247,39 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vectoris_box ()) { - error (tl::to_string (tr ("Gate shape is not a box - width and length may be incorrect")), *p); + { + db::Edges edges (rgate.edges () & ddiff2gate.edges ()); + ddwidth = edges.length (); + if (ddwidth == 0) { + error (tl::to_string (tr ("Vanishing edges for interaction gate/drain diff (corner interaction) - gate shape ignored"))); + continue; + } } + // Computation of the gate length and width - this scheme is compatible with + // non-rectangular gates and circular gates. The computation is based on the + // relationship: A(gate) = L(gate) * W(gate). W(gate) is determined from the + // accumulated edge lengths (average of left and right length). + double param_w = sdbu () * (sdwidth + ddwidth) * 0.5; + double param_l = sdbu () * sdbu () * double (rgate.area ()) / param_w; + db::Device *device = create_device (); device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ())); - device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, sdbu () * edges.length () * 0.5); - device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, sdbu () * (p->perimeter () - edges.length ()) * 0.5); + device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, param_w); + device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, param_l); for (int diff_index = 0; diff_index < 2; ++diff_index) { @@ -272,6 +304,7 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector cl; + + db::NetlistDeviceExtractorMOS3Transistor ex ("MOS3"); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["SD"] = &l1; + dl["G"] = &l2; + dl["tS"] = &o1; + dl["tD"] = &o2; + dl["tG"] = &o3; + ex.extract (dss, 0, dl, nl, cl); + + EXPECT_EQ (nl.to_string (), + "circuit TOP ();\n" + " device MOS3 $1 (S=(null),G=(null),D=(null)) (L=0.3,W=0.8,AS=0.4,AD=0.16,PS=2.6,PD=2);\n" + "end;\n" + ); + EXPECT_EQ (o1.to_string (), "(-600,-200;-600,600;-100,600;-100,-200)"); + EXPECT_EQ (o2.to_string (), "(200,-200;200,600;400,600;400,-200)"); + EXPECT_EQ (o3.to_string (), "(-100,-200;-100,600;200,600;200,-200)"); +} + +TEST(11_MOS3DeviceExtractorTestNotRectangularGate) +{ + db::Layout ly; + + { + db::LoadLayoutOptions options; + + std::string fn (tl::testsrc ()); + fn = tl::combine_path (fn, "testdata"); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "mos3_2.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + db::Cell &tc = ly.cell (*ly.begin_top_down ()); + + db::DeepShapeStore dss; + dss.set_text_enlargement (1); + dss.set_text_property_name (tl::Variant ("LABEL")); + + // original layers + db::Region l1 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(1, 0))), dss); + db::Region l2 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(2, 0))), dss); + db::Region o1 (dss); + db::Region o2 (dss); + db::Region o3 (dss); + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS3Transistor ex ("MOS3"); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["SD"] = &l1; + dl["G"] = &l2; + dl["tS"] = &o1; + dl["tD"] = &o2; + dl["tG"] = &o3; + ex.extract (dss, 0, dl, nl, cl); + + EXPECT_EQ (nl.to_string (), + "circuit TOP ();\n" + " device MOS3 $1 (S=(null),G=(null),D=(null)) (L=0.3,W=1,AS=0.32,AD=0.18,PS=2.6,PD=2.4);\n" + "end;\n" + ); + EXPECT_EQ (o1.to_string (), "(-600,-200;-600,600;-300,600;-300,200;-100,200;-100,-200)"); + EXPECT_EQ (o2.to_string (), "(200,-200;200,500;0,500;0,600;400,600;400,-200)"); + EXPECT_EQ (o3.to_string (), "(-100,-200;-100,200;-300,200;-300,600;0,600;0,500;200,500;200,-200)"); +} + +TEST(12_MOS3DeviceExtractorTestCircular) +{ + db::Layout ly; + + { + db::LoadLayoutOptions options; + + std::string fn (tl::testsrc ()); + fn = tl::combine_path (fn, "testdata"); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "mos3_3.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + db::Cell &tc = ly.cell (*ly.begin_top_down ()); + + db::DeepShapeStore dss; + dss.set_text_enlargement (1); + dss.set_text_property_name (tl::Variant ("LABEL")); + + // original layers + db::Region l1 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(1, 0))), dss); + db::Region l2 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(2, 0))), dss); + db::Region o1 (dss); + db::Region o2 (dss); + db::Region o3 (dss); + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS3Transistor ex ("MOS3"); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["SD"] = &l1; + dl["G"] = &l2; + dl["tS"] = &o1; + dl["tD"] = &o2; + dl["tG"] = &o3; + ex.extract (dss, 0, dl, nl, cl); + + EXPECT_EQ (nl.to_string (), + "circuit TOP ();\n" + " device MOS3 $1 (S=(null),G=(null),D=(null)) (L=0.3,W=3.8,AS=0.4,AD=4.18,PS=2.6,PD=14.6);\n" + "end;\n" + ); + EXPECT_EQ (o1.to_string (), "(200,-200;200,600;700,600;700,-200)"); + EXPECT_EQ (o2.to_string (), "(-600,-1200;-600,1400;1600,1400;1600,-1200/-100,-500;1000,-500;1000,900;-100,900)"); + EXPECT_EQ (o3.to_string (), "(-100,-500;-100,900;1000,900;1000,-500/200,-200;700,-200;700,600;200,600)"); +} + +TEST(20_MOS4DeviceExtractorTest) +{ + db::Layout ly; + + { + db::LoadLayoutOptions options; + + std::string fn (tl::testsrc ()); + fn = tl::combine_path (fn, "testdata"); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "mos4_1.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + db::Cell &tc = ly.cell (*ly.begin_top_down ()); + + db::DeepShapeStore dss; + dss.set_text_enlargement (1); + dss.set_text_property_name (tl::Variant ("LABEL")); + + // original layers + db::Region l1 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(1, 0))), dss); + db::Region l2 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(2, 0))), dss); + db::Region l3 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(3, 0))), dss); + db::Region o1 (dss); + db::Region o2 (dss); + db::Region o3 (dss); + db::Region o4 (dss); + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS4Transistor ex ("MOS4"); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["SD"] = &l1; + dl["G"] = &l2; + dl["W"] = &l3; + dl["tS"] = &o1; + dl["tD"] = &o2; + dl["tG"] = &o3; + dl["tB"] = &o4; + ex.extract (dss, 0, dl, nl, cl); + + EXPECT_EQ (nl.to_string (), + "circuit TOP ();\n" + " device MOS4 $1 (S=(null),G=(null),D=(null),B=(null)) (L=0.3,W=0.8,AS=0.4,AD=0.16,PS=2.6,PD=2);\n" + "end;\n" + ); + EXPECT_EQ (o1.to_string (), "(-600,-200;-600,600;-100,600;-100,-200)"); + EXPECT_EQ (o2.to_string (), "(200,-200;200,600;400,600;400,-200)"); + EXPECT_EQ (o3.to_string (), "(-100,-200;-100,600;200,600;200,-200)"); + EXPECT_EQ (o4.to_string (), "(-100,-200;-100,600;200,600;200,-200)"); +} + +TEST(21_MOS4DeviceExtractorTestNotRectangularGate) +{ + db::Layout ly; + + { + db::LoadLayoutOptions options; + + std::string fn (tl::testsrc ()); + fn = tl::combine_path (fn, "testdata"); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "mos4_2.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + db::Cell &tc = ly.cell (*ly.begin_top_down ()); + + db::DeepShapeStore dss; + dss.set_text_enlargement (1); + dss.set_text_property_name (tl::Variant ("LABEL")); + + // original layers + db::Region l1 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(1, 0))), dss); + db::Region l2 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(2, 0))), dss); + db::Region l3 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(3, 0))), dss); + db::Region o1 (dss); + db::Region o2 (dss); + db::Region o3 (dss); + db::Region o4 (dss); + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS4Transistor ex ("MOS4"); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["SD"] = &l1; + dl["G"] = &l2; + dl["W"] = &l3; + dl["tS"] = &o1; + dl["tD"] = &o2; + dl["tG"] = &o3; + dl["tB"] = &o4; + ex.extract (dss, 0, dl, nl, cl); + + EXPECT_EQ (nl.to_string (), + "circuit TOP ();\n" + " device MOS4 $1 (S=(null),G=(null),D=(null),B=(null)) (L=0.3,W=1,AS=0.32,AD=0.18,PS=2.6,PD=2.4);\n" + "end;\n" + ); + EXPECT_EQ (o1.to_string (), "(-600,-200;-600,600;-300,600;-300,200;-100,200;-100,-200)"); + EXPECT_EQ (o2.to_string (), "(200,-200;200,500;0,500;0,600;400,600;400,-200)"); + EXPECT_EQ (o3.to_string (), "(-100,-200;-100,200;-300,200;-300,600;0,600;0,500;200,500;200,-200)"); + EXPECT_EQ (o4.to_string (), "(-100,-200;-100,200;-300,200;-300,600;0,600;0,500;200,500;200,-200)"); +} + +TEST(22_MOS4DeviceExtractorTestCircular) +{ + db::Layout ly; + + { + db::LoadLayoutOptions options; + + std::string fn (tl::testsrc ()); + fn = tl::combine_path (fn, "testdata"); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "mos4_3.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + db::Cell &tc = ly.cell (*ly.begin_top_down ()); + + db::DeepShapeStore dss; + dss.set_text_enlargement (1); + dss.set_text_property_name (tl::Variant ("LABEL")); + + // original layers + db::Region l1 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(1, 0))), dss); + db::Region l2 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(2, 0))), dss); + db::Region l3 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(3, 0))), dss); + db::Region o1 (dss); + db::Region o2 (dss); + db::Region o3 (dss); + db::Region o4 (dss); + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS4Transistor ex ("MOS4"); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["SD"] = &l1; + dl["G"] = &l2; + dl["W"] = &l3; + dl["tS"] = &o1; + dl["tD"] = &o2; + dl["tG"] = &o3; + dl["tB"] = &o4; + ex.extract (dss, 0, dl, nl, cl); + + EXPECT_EQ (nl.to_string (), + "circuit TOP ();\n" + " device MOS4 $1 (S=(null),G=(null),D=(null),B=(null)) (L=0.3,W=3.8,AS=0.4,AD=4.18,PS=2.6,PD=14.6);\n" + "end;\n" + ); + EXPECT_EQ (o1.to_string (), "(200,-200;200,600;700,600;700,-200)"); + EXPECT_EQ (o2.to_string (), "(-600,-1200;-600,1400;1600,1400;1600,-1200/-100,-500;1000,-500;1000,900;-100,900)"); + EXPECT_EQ (o3.to_string (), "(-100,-500;-100,900;1000,900;1000,-500/200,-200;700,-200;700,600;200,600)"); + EXPECT_EQ (o4.to_string (), "(-100,-500;-100,900;1000,900;1000,-500/200,-200;700,-200;700,600;200,600)"); +} + +TEST(30_DMOS3DeviceExtractorTest) +{ + db::Layout ly; + + { + db::LoadLayoutOptions options; + + std::string fn (tl::testsrc ()); + fn = tl::combine_path (fn, "testdata"); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "dmos3_1.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + db::Cell &tc = ly.cell (*ly.begin_top_down ()); + + db::DeepShapeStore dss; + dss.set_text_enlargement (1); + dss.set_text_property_name (tl::Variant ("LABEL")); + + // original layers + db::Region l0 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(0, 0))), dss); + db::Region l1 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(1, 0))), dss); + db::Region l2 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(2, 0))), dss); + db::Region o1 (dss); + db::Region o2 (dss); + db::Region o3 (dss); + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS3Transistor ex ("DMOS3", true); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["S"] = &l0; + dl["D"] = &l1; + dl["G"] = &l2; + dl["tS"] = &o1; + dl["tD"] = &o2; + dl["tG"] = &o3; + ex.extract (dss, 0, dl, nl, cl); + + EXPECT_EQ (nl.to_string (), + "circuit TOP ();\n" + " device DMOS3 $1 (S=(null),G=(null),D=(null)) (L=0.3,W=0.8,AS=0.4,AD=0.16,PS=2.6,PD=2);\n" + "end;\n" + ); + EXPECT_EQ (o1.to_string (), "(-600,-200;-600,600;-100,600;-100,-200)"); + EXPECT_EQ (o2.to_string (), "(200,-200;200,600;400,600;400,-200)"); + EXPECT_EQ (o3.to_string (), "(-100,-200;-100,600;200,600;200,-200)"); +} + +TEST(31_DMOS3DeviceExtractorTestNotRectangularGate) +{ + db::Layout ly; + + { + db::LoadLayoutOptions options; + + std::string fn (tl::testsrc ()); + fn = tl::combine_path (fn, "testdata"); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "dmos3_2.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + db::Cell &tc = ly.cell (*ly.begin_top_down ()); + + db::DeepShapeStore dss; + dss.set_text_enlargement (1); + dss.set_text_property_name (tl::Variant ("LABEL")); + + // original layers + db::Region l0 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(0, 0))), dss); + db::Region l1 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(1, 0))), dss); + db::Region l2 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(2, 0))), dss); + db::Region o1 (dss); + db::Region o2 (dss); + db::Region o3 (dss); + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS3Transistor ex ("DMOS3", true); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["S"] = &l0; + dl["D"] = &l1; + dl["G"] = &l2; + dl["tS"] = &o1; + dl["tD"] = &o2; + dl["tG"] = &o3; + ex.extract (dss, 0, dl, nl, cl); + + EXPECT_EQ (nl.to_string (), + "circuit TOP ();\n" + " device DMOS3 $1 (S=(null),G=(null),D=(null)) (L=0.3,W=1,AS=0.32,AD=0.18,PS=2.6,PD=2.4);\n" + "end;\n" + ); + EXPECT_EQ (o1.to_string (), "(-600,-200;-600,600;-300,600;-300,200;-100,200;-100,-200)"); + EXPECT_EQ (o2.to_string (), "(200,-200;200,500;0,500;0,600;400,600;400,-200)"); + EXPECT_EQ (o3.to_string (), "(-100,-200;-100,200;-300,200;-300,600;0,600;0,500;200,500;200,-200)"); +} + +TEST(32_DMOS3DeviceExtractorTestCircular) +{ + db::Layout ly; + + { + db::LoadLayoutOptions options; + + std::string fn (tl::testsrc ()); + fn = tl::combine_path (fn, "testdata"); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "dmos3_3.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + db::Cell &tc = ly.cell (*ly.begin_top_down ()); + + db::DeepShapeStore dss; + dss.set_text_enlargement (1); + dss.set_text_property_name (tl::Variant ("LABEL")); + + // original layers + db::Region l0 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(0, 0))), dss); + db::Region l1 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(1, 0))), dss); + db::Region l2 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(2, 0))), dss); + db::Region o1 (dss); + db::Region o2 (dss); + db::Region o3 (dss); + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS3Transistor ex ("DMOS3", true); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["S"] = &l0; + dl["D"] = &l1; + dl["G"] = &l2; + dl["tS"] = &o1; + dl["tD"] = &o2; + dl["tG"] = &o3; + ex.extract (dss, 0, dl, nl, cl); + + EXPECT_EQ (nl.to_string (), + "circuit TOP ();\n" + " device DMOS3 $1 (S=(null),G=(null),D=(null)) (L=0.3,W=3.8,AS=0.4,AD=4.18,PS=2.6,PD=14.6);\n" + "end;\n" + ); + EXPECT_EQ (o1.to_string (), "(200,-200;200,600;700,600;700,-200)"); + EXPECT_EQ (o2.to_string (), "(-600,-1200;-600,1400;1600,1400;1600,-1200/-100,-500;1000,-500;1000,900;-100,900)"); + EXPECT_EQ (o3.to_string (), "(-100,-500;-100,900;1000,900;1000,-500/200,-200;700,-200;700,600;200,600)"); +} + +TEST(40_DMOS4DeviceExtractorTest) +{ + db::Layout ly; + + { + db::LoadLayoutOptions options; + + std::string fn (tl::testsrc ()); + fn = tl::combine_path (fn, "testdata"); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "dmos4_1.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + db::Cell &tc = ly.cell (*ly.begin_top_down ()); + + db::DeepShapeStore dss; + dss.set_text_enlargement (1); + dss.set_text_property_name (tl::Variant ("LABEL")); + + // original layers + db::Region l0 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(0, 0))), dss); + db::Region l1 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(1, 0))), dss); + db::Region l2 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(2, 0))), dss); + db::Region l3 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(3, 0))), dss); + db::Region o1 (dss); + db::Region o2 (dss); + db::Region o3 (dss); + db::Region o4 (dss); + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS4Transistor ex ("DMOS4", true); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["S"] = &l0; + dl["D"] = &l1; + dl["G"] = &l2; + dl["W"] = &l3; + dl["tS"] = &o1; + dl["tD"] = &o2; + dl["tG"] = &o3; + dl["tB"] = &o4; + ex.extract (dss, 0, dl, nl, cl); + + EXPECT_EQ (nl.to_string (), + "circuit TOP ();\n" + " device DMOS4 $1 (S=(null),G=(null),D=(null),B=(null)) (L=0.3,W=0.8,AS=0.4,AD=0.16,PS=2.6,PD=2);\n" + "end;\n" + ); + EXPECT_EQ (o1.to_string (), "(-600,-200;-600,600;-100,600;-100,-200)"); + EXPECT_EQ (o2.to_string (), "(200,-200;200,600;400,600;400,-200)"); + EXPECT_EQ (o3.to_string (), "(-100,-200;-100,600;200,600;200,-200)"); + EXPECT_EQ (o4.to_string (), "(-100,-200;-100,600;200,600;200,-200)"); +} + +TEST(41_DMOS4DeviceExtractorTestNotRectangularGate) +{ + db::Layout ly; + + { + db::LoadLayoutOptions options; + + std::string fn (tl::testsrc ()); + fn = tl::combine_path (fn, "testdata"); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "dmos4_2.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + db::Cell &tc = ly.cell (*ly.begin_top_down ()); + + db::DeepShapeStore dss; + dss.set_text_enlargement (1); + dss.set_text_property_name (tl::Variant ("LABEL")); + + // original layers + db::Region l0 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(0, 0))), dss); + db::Region l1 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(1, 0))), dss); + db::Region l2 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(2, 0))), dss); + db::Region l3 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(3, 0))), dss); + db::Region o1 (dss); + db::Region o2 (dss); + db::Region o3 (dss); + db::Region o4 (dss); + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS4Transistor ex ("DMOS4", true); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["S"] = &l0; + dl["D"] = &l1; + dl["G"] = &l2; + dl["W"] = &l3; + dl["tS"] = &o1; + dl["tD"] = &o2; + dl["tG"] = &o3; + dl["tB"] = &o4; + ex.extract (dss, 0, dl, nl, cl); + + EXPECT_EQ (nl.to_string (), + "circuit TOP ();\n" + " device DMOS4 $1 (S=(null),G=(null),D=(null),B=(null)) (L=0.3,W=1,AS=0.32,AD=0.18,PS=2.6,PD=2.4);\n" + "end;\n" + ); + EXPECT_EQ (o1.to_string (), "(-600,-200;-600,600;-300,600;-300,200;-100,200;-100,-200)"); + EXPECT_EQ (o2.to_string (), "(200,-200;200,500;0,500;0,600;400,600;400,-200)"); + EXPECT_EQ (o3.to_string (), "(-100,-200;-100,200;-300,200;-300,600;0,600;0,500;200,500;200,-200)"); + EXPECT_EQ (o4.to_string (), "(-100,-200;-100,200;-300,200;-300,600;0,600;0,500;200,500;200,-200)"); +} + +TEST(42_DMOS4DeviceExtractorTestCircular) +{ + db::Layout ly; + + { + db::LoadLayoutOptions options; + + std::string fn (tl::testsrc ()); + fn = tl::combine_path (fn, "testdata"); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "dmos4_3.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + db::Cell &tc = ly.cell (*ly.begin_top_down ()); + + db::DeepShapeStore dss; + dss.set_text_enlargement (1); + dss.set_text_property_name (tl::Variant ("LABEL")); + + // original layers + db::Region l0 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(0, 0))), dss); + db::Region l1 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(1, 0))), dss); + db::Region l2 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(2, 0))), dss); + db::Region l3 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(3, 0))), dss); + db::Region o1 (dss); + db::Region o2 (dss); + db::Region o3 (dss); + db::Region o4 (dss); + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS4Transistor ex ("DMOS4", true); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["S"] = &l0; + dl["D"] = &l1; + dl["G"] = &l2; + dl["W"] = &l3; + dl["tS"] = &o1; + dl["tD"] = &o2; + dl["tG"] = &o3; + dl["tB"] = &o4; + ex.extract (dss, 0, dl, nl, cl); + + EXPECT_EQ (nl.to_string (), + "circuit TOP ();\n" + " device DMOS4 $1 (S=(null),G=(null),D=(null),B=(null)) (L=0.3,W=3.8,AS=0.4,AD=4.18,PS=2.6,PD=14.6);\n" + "end;\n" + ); + EXPECT_EQ (o1.to_string (), "(200,-200;200,600;700,600;700,-200)"); + EXPECT_EQ (o2.to_string (), "(-600,-1200;-600,1400;1600,1400;1600,-1200/-100,-500;1000,-500;1000,900;-100,900)"); + EXPECT_EQ (o3.to_string (), "(-100,-500;-100,900;1000,900;1000,-500/200,-200;700,-200;700,600;200,600)"); + EXPECT_EQ (o4.to_string (), "(-100,-500;-100,900;1000,900;1000,-500/200,-200;700,-200;700,600;200,600)"); +} diff --git a/testdata/algo/dmos3_1.gds b/testdata/algo/dmos3_1.gds new file mode 100644 index 0000000000000000000000000000000000000000..8147394b587e4c9827b3e48814e381e7395ea2c9 GIT binary patch literal 298 zcmZQzV_;&6V31*CVt>NG$iT!P%3#G{h0JE)U}E#}bYfr-VP>^+>@@d2w)}&o%MSeo zv!g;7WLWX&V`B^P4`5(m;b353<7EPx&c?^Yz`&p*zzif${Qv*o0z@+~0PSaBoB*R? z;$WIZ5TTz5p&uwW2P6-oA^KqEK+J{7Ga%~+x&mhZ|NnniK=l7z0n!gM2c{1u57EyK IbOQ?m0Fhi$UjP6A literal 0 HcmV?d00001 diff --git a/testdata/algo/dmos3_2.gds b/testdata/algo/dmos3_2.gds new file mode 100644 index 0000000000000000000000000000000000000000..f1a06d8eb8c7d7fa0b72b002ee3a3a75f67f6ca7 GIT binary patch literal 442 zcmaKoJr2S!4256ZHthl`5^OyJ5+grCNFWvj5)2&>H)87!0~wVV5Ea{^+Dk z*Bii(0NEg}E}I0P8+*L-5-&^k2X26)i!=S!Fa1p^H7Io=vwD%axM5XKr9bD6IV4u3`IXPy8}f)L?RtWK%yj}Km^f5Ah87n;v^h^hBH8sE*ya(HR2!?l=LVV zdyU0Hv{Zj&`}y16MSyb?)C;b-M*$9RXrrBdqvXQys|VD4-1%Iz2HT(GM}O1&UQWlT z$4|Hr#-jv?NK->v?`ruwe?GE(f7w_4ZEu^y=DOxn|04eb F5iSsA#qj_D literal 0 HcmV?d00001 diff --git a/testdata/algo/dmos4_1.gds b/testdata/algo/dmos4_1.gds new file mode 100644 index 0000000000000000000000000000000000000000..90c142e0b29f2a300ca9abaa8b63b30aee4d11c2 GIT binary patch literal 362 zcmaKnAr8Vo5Ji8d?Y0I23Ai4C1PN4-KxzmiASwtq!r?*S=n)WT!T~q}2S8xUFw17r zVlewR^Yi|nfdSDPiAT``9td5eNb7&ZWEQh2(DB3ZWILE&PtQ?y?jQG?97*_xGbUfI zfFK4;gCyNF2|%yq%X?$yp;bWo;q6p){?(ve@l^5R9jtHFahl_D)kmH8>wK9pzwgXt iCj3SEU#dE{`oqf=y1#IR>n{u2uX|{(`i_s}h5#R7eQSUK literal 0 HcmV?d00001 diff --git a/testdata/algo/dmos4_2.gds b/testdata/algo/dmos4_2.gds new file mode 100644 index 0000000000000000000000000000000000000000..7980087b66eaf8fc23257978f28caf746e785bea GIT binary patch literal 506 zcmaKou?_)25QhKVJ4-`I=sbc%iHk_cH9|t65O1W@Q|R0yDAeKsJc0*MXwRD2HL(h= zxbJRe|M~wN7-+pjQ|aOj3K|V0NWyQFw3&`aKs_o9hU?Dce7N`0V|%|{Ezm6d(HXOt z&4IWCn6jqnrlJ9~su8{EQ4de@2QGk6>cqJAOMkJ}c0W3`@p`q9x?`xwO$Pf2(3-kwr-vqL>?(e1BajYyaI X{CUQ{lEahz`CguKj_LChX{Rw>yVHuU literal 0 HcmV?d00001 diff --git a/testdata/algo/dmos4_3.gds b/testdata/algo/dmos4_3.gds new file mode 100644 index 0000000000000000000000000000000000000000..19d0be61ae11c05952a9ea4a2171a6d2745b417b GIT binary patch literal 746 zcmaKqF;2rk5Ji91_9g{HAVHTSAW;G-P=eebkZ|DwaS{$d!x>0HfdogOphg^mk|ITl z)I?#J@$kh45m(QeoxgwPuMrW#B?g_){Xho+yBK1aexn!S`RNI;lNHC~+k>;$$N5qD zynlapRbx=J=whrdDj@FxaWm-cu^#~JZDk_MCy}oWBaq#Q$b@9whwn%aOZQ)vBA+wOuhjhC gHNOXvb>qtX+Qk3I@^U}s#yz;#&v`R{SO1|L-_~B<{r~^~ literal 0 HcmV?d00001 diff --git a/testdata/algo/mos3_1.gds b/testdata/algo/mos3_1.gds new file mode 100644 index 0000000000000000000000000000000000000000..fec1a662aedac16847341d8ca175786d35c27d93 GIT binary patch literal 298 zcmZQzV_;&6V31*CVt>NG$iT!P${@sGiOgo;U}E#}bYfr-VP>^+>@@d2w)}&o%MSeo zv!g;7WLWX&V`B^P4`5(m;b353<7EPx&c?^Yz`&p*!2JLJ-xdG=|F;0q3=B*WK=vFM z4HE~^3@n0J^#e^g0hR~SAbkuBj1yoqOdLZ$6SDpP=YZsa7;G=dJcxdXxgc?bes-W6 GSQr2d`cb?9 literal 0 HcmV?d00001 diff --git a/testdata/algo/mos3_2.gds b/testdata/algo/mos3_2.gds new file mode 100644 index 0000000000000000000000000000000000000000..6750aa5f8771c0b9af8d255f1796c1020c42b729 GIT binary patch literal 442 zcmaJ-F$%&^41GUszg-j+-8_QeXax}z7g5lmL-9s#-R<-qqx^{2gFX@-~;$Qrxf8d2Zvd3>Hq)$ literal 0 HcmV?d00001 diff --git a/testdata/algo/mos3_3.gds b/testdata/algo/mos3_3.gds new file mode 100644 index 0000000000000000000000000000000000000000..380bb8857355d5fdd3ffb74a421b1e16e34be8ec GIT binary patch literal 682 zcmah{F>V4u5HquP3q?SQ1XMf$lrqpDf@q>3aRmj+OY#63-T(z1JRt=&;vp22^awUH zH=1xH0g97P)_OelEjGsLw_hhO@9V|B)%$v$Pd|pJ z#W!@`4+jYl6#!o(p6*Kop#JDWI4(mtJqQAB9732G8ZU_G>0doh*|4T52=M-(m7(z| zUe&u@Iv;K)zPw<^(D+;a=e=eB_*3HMGGRVQNG$iT!P%3#Q#jLc@>U}E#}bYfr-VP>^+>@@d2w)}&o%MSeo zv!g;7WLWX&V`B^P4`5(m;b353<7EPx&c?^Yz`&p*!2JLJ-xdG=|F;0q3=B*WK=vFM z4HE~^3@n0J^#e^g0hR~SAbkuBj1yoqOdLZ$6SDpP=YZsa7;G=dJcxdXxgc>2{mjVv h|GNDD|L+RW{VqU#dw}+TfzdE=5DjrZJJ1g-3;@=DYXJZN literal 0 HcmV?d00001 diff --git a/testdata/algo/mos4_2.gds b/testdata/algo/mos4_2.gds new file mode 100644 index 0000000000000000000000000000000000000000..98b1f4adbc882158c62dfe4b1259379d8bb45b26 GIT binary patch literal 506 zcmaJ-v1&p=5S-ihJZ&NdOlM~+h?NRKFuX<*h=qmtM|SpF*y$&vuogeSPsj&Y*y=fZ z_YR*(vdt{JJ2Sfr3y~=rM#{f15WJy-W-&)a?APc6s3)btaNhmgZ%+N}r@dazCTNuY z;aNNR9s_9wurES&TNMEBwZys0);ZTx1Z3*m^>{}d*jsVZW1Le&`ueQbswJFdm~%kh zL$2xtjCJDQeD&(xd1ev#W)bU8{*vEAfA&_|SIqaIzxVaJvH#%zz}Nfr-tY(J48Ol7 fd7U>E_fLxcmrS|*XGY#Gcn6GiukHC|{xHQ2F(ryG literal 0 HcmV?d00001 diff --git a/testdata/algo/mos4_3.gds b/testdata/algo/mos4_3.gds new file mode 100644 index 0000000000000000000000000000000000000000..bfcb04fc29d8906569a7be383be694a66e39e258 GIT binary patch literal 746 zcmah{u}%U}5FGa1Jt)Lzq8%Nr39%9zqvjf;iC0hU#453PKIF2>$<31kf*Hc6((Z31wx6POpz%%59|K)7S(fur+^$aeqK%aj+