Implemented #462 (Generalize MOS transistor extraction to other gate figures)

This commit is contained in:
Matthias Koefferlein 2020-01-02 22:20:45 +01:00
parent 85c033db64
commit 833edf53b2
14 changed files with 770 additions and 17 deletions

View File

@ -144,22 +144,39 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector<db
continue;
}
db::Edges edges (rgate.edges () & rdiff2gate.edges ());
if (edges.size () != 2) {
error (tl::sprintf (tl::to_string (tr ("Expected two edges interacting gate/diff (found %d) - width and length may be incorrect")), int (edges.size ())), *p);
std::vector<db::Edges::length_type> 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::vector<db
continue;
}
db::Region diff2gate = sdiff2gate + ddiff2gate;
db::Edges::length_type sdwidth = 0, ddwidth = 0;
db::Edges edges (rgate.edges () & diff2gate.edges ());
if (edges.size () != 2) {
error (tl::sprintf (tl::to_string (tr ("Expected two edges interacting gate/diff (found %d) - width and length may be incorrect")), int (edges.size ())), *p);
continue;
{
db::Edges edges (rgate.edges () & sdiff2gate.edges ());
sdwidth = edges.length ();
if (sdwidth == 0) {
error (tl::to_string (tr ("Vanishing edges for interaction gate/source diff (corner interaction) - gate shape ignored")));
continue;
}
}
if (! p->is_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<db
modify_device (*p, layer_geometry, device);
// output the device for debugging
db::Region diff2gate = sdiff2gate + ddiff2gate;
device_out (device, diff2gate, rgate);
}

View File

@ -21,8 +21,14 @@
*/
#include "dbNetlistDeviceExtractor.h"
#include "dbLoadLayoutOptions.h"
#include "dbReader.h"
#include "dbRecursiveShapeIterator.h"
#include "dbNetlistDeviceExtractorClasses.h"
#include "tlUnitTest.h"
#include "tlFileUtils.h"
#include "tlStream.h"
TEST(1_NetlistDeviceExtractorErrorBasic)
{
@ -83,3 +89,717 @@ TEST(2_NetlistDeviceExtractorErrors)
EXPECT_EQ (error2string (errors [2]), ":cat1:desc1:():msg1");
EXPECT_EQ (error2string (errors [3]), ":cat1:desc1:(10,11;10,13;12,13;12,11):msg3");
}
TEST(10_MOS3DeviceExtractorTest)
{
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_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 o1 (dss);
db::Region o2 (dss);
db::Region o3 (dss);
// perform the extraction
db::Netlist nl;
db::hier_clusters<db::PolygonRef> 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<db::PolygonRef> 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<db::PolygonRef> 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<db::PolygonRef> 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<db::PolygonRef> 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<db::PolygonRef> 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<db::PolygonRef> 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<db::PolygonRef> 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<db::PolygonRef> 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<db::PolygonRef> 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<db::PolygonRef> 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<db::PolygonRef> 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)");
}

BIN
testdata/algo/dmos3_1.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/dmos3_2.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/dmos3_3.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/dmos4_1.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/dmos4_2.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/dmos4_3.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/mos3_1.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/mos3_2.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/mos3_3.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/mos4_1.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/mos4_2.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/mos4_3.gds vendored Normal file

Binary file not shown.