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 000000000..8147394b5 Binary files /dev/null and b/testdata/algo/dmos3_1.gds differ diff --git a/testdata/algo/dmos3_2.gds b/testdata/algo/dmos3_2.gds new file mode 100644 index 000000000..f1a06d8eb Binary files /dev/null and b/testdata/algo/dmos3_2.gds differ diff --git a/testdata/algo/dmos3_3.gds b/testdata/algo/dmos3_3.gds new file mode 100644 index 000000000..06339dfd6 Binary files /dev/null and b/testdata/algo/dmos3_3.gds differ diff --git a/testdata/algo/dmos4_1.gds b/testdata/algo/dmos4_1.gds new file mode 100644 index 000000000..90c142e0b Binary files /dev/null and b/testdata/algo/dmos4_1.gds differ diff --git a/testdata/algo/dmos4_2.gds b/testdata/algo/dmos4_2.gds new file mode 100644 index 000000000..7980087b6 Binary files /dev/null and b/testdata/algo/dmos4_2.gds differ diff --git a/testdata/algo/dmos4_3.gds b/testdata/algo/dmos4_3.gds new file mode 100644 index 000000000..19d0be61a Binary files /dev/null and b/testdata/algo/dmos4_3.gds differ diff --git a/testdata/algo/mos3_1.gds b/testdata/algo/mos3_1.gds new file mode 100644 index 000000000..fec1a662a Binary files /dev/null and b/testdata/algo/mos3_1.gds differ diff --git a/testdata/algo/mos3_2.gds b/testdata/algo/mos3_2.gds new file mode 100644 index 000000000..6750aa5f8 Binary files /dev/null and b/testdata/algo/mos3_2.gds differ diff --git a/testdata/algo/mos3_3.gds b/testdata/algo/mos3_3.gds new file mode 100644 index 000000000..380bb8857 Binary files /dev/null and b/testdata/algo/mos3_3.gds differ diff --git a/testdata/algo/mos4_1.gds b/testdata/algo/mos4_1.gds new file mode 100644 index 000000000..537a540ef Binary files /dev/null and b/testdata/algo/mos4_1.gds differ diff --git a/testdata/algo/mos4_2.gds b/testdata/algo/mos4_2.gds new file mode 100644 index 000000000..98b1f4adb Binary files /dev/null and b/testdata/algo/mos4_2.gds differ diff --git a/testdata/algo/mos4_3.gds b/testdata/algo/mos4_3.gds new file mode 100644 index 000000000..bfcb04fc2 Binary files /dev/null and b/testdata/algo/mos4_3.gds differ