diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index c8f249a76..72e5528a8 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -25,7 +25,13 @@ #include "dbCellMapping.h" #include "dbLayoutUtils.h" #include "dbRegion.h" +#include "dbEdges.h" +#include "dbEdgePairs.h" +#include "dbTexts.h" #include "dbDeepRegion.h" +#include "dbDeepEdges.h" +#include "dbDeepEdgePairs.h" +#include "dbDeepTexts.h" #include "tlTimer.h" @@ -48,6 +54,30 @@ DeepLayer::DeepLayer (const Region ®ion) *this = dr->deep_layer (); } +DeepLayer::DeepLayer (const Texts &texts) + : mp_store (), m_layout (0), m_layer (0) +{ + const db::DeepTexts *dr = dynamic_cast (texts.delegate ()); + tl_assert (dr != 0); + *this = dr->deep_layer (); +} + +DeepLayer::DeepLayer (const Edges &edges) + : mp_store (), m_layout (0), m_layer (0) +{ + const db::DeepEdges *dr = dynamic_cast (edges.delegate ()); + tl_assert (dr != 0); + *this = dr->deep_layer (); +} + +DeepLayer::DeepLayer (const EdgePairs &edge_pairs) + : mp_store (), m_layout (0), m_layer (0) +{ + const db::DeepEdgePairs *dr = dynamic_cast (edge_pairs.delegate ()); + tl_assert (dr != 0); + *this = dr->deep_layer (); +} + DeepLayer::DeepLayer (const DeepLayer &x) : mp_store (x.mp_store), m_layout (x.m_layout), m_layer (x.m_layer) { diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index 032fb8aad..981bf5259 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -43,6 +43,8 @@ class DeepShapeStore; class DeepShapeStoreState; class Region; class Edges; +class EdgePairs; +class Texts; /** * @brief Represents a shape collection from the deep shape store @@ -75,6 +77,24 @@ public: */ DeepLayer (const Region ®ion); + /** + * @brief Conversion operator from texts collection to DeepLayer + * This requires the texts to be a DeepTexts. Otherwise, this constructor will assert + */ + DeepLayer (const Texts ®ion); + + /** + * @brief Conversion operator from edges collection to DeepLayer + * This requires the edges to be a DeepEdges. Otherwise, this constructor will assert + */ + DeepLayer (const Edges ®ion); + + /** + * @brief Conversion operator from edge pairs collection to DeepLayer + * This requires the edge pairs to be a DeepEdgePairs. Otherwise, this constructor will assert + */ + DeepLayer (const EdgePairs ®ion); + /** * @brief Copy constructor */ diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index fecf213be..c6864d444 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -25,10 +25,11 @@ #include "dbNetlistExtractor.h" #include "dbNetlistDeviceClasses.h" #include "dbLayout.h" -#include "dbDeepShapeStore.h" #include "dbRegion.h" +#include "dbTexts.h" #include "dbStream.h" #include "dbDeepRegion.h" +#include "dbDeepTexts.h" #include "dbDeepShapeStore.h" #include "dbReader.h" #include "dbWriter.h" @@ -52,6 +53,13 @@ static unsigned int layer_of (const db::Region ®ion) return dr->deep_layer ().layer (); } +static unsigned int layer_of (const db::Texts ®ion) +{ + const db::DeepTexts *dr = dynamic_cast (region.delegate ()); + tl_assert (dr != 0); + return dr->deep_layer ().layer (); +} + static unsigned int define_layer (db::Layout &ly, db::LayerMap &lmap, int gds_layer, int gds_datatype = 0) { unsigned int lid = ly.insert_layer (db::LayerProperties (gds_layer, gds_datatype)); @@ -291,14 +299,17 @@ TEST(1_DeviceAndNetExtraction) // 210/0 -> N source/drain // 211/0 -> P source/drain std::map dump_map; - dump_map [layer_of (rpsd) ] = ly.insert_layer (db::LayerProperties (210, 0)); - dump_map [layer_of (rnsd) ] = ly.insert_layer (db::LayerProperties (211, 0)); - dump_map [layer_of (rpoly) ] = ly.insert_layer (db::LayerProperties (203, 0)); - dump_map [layer_of (rdiff_cont)] = ly.insert_layer (db::LayerProperties (204, 0)); - dump_map [layer_of (rpoly_cont)] = ly.insert_layer (db::LayerProperties (205, 0)); - dump_map [layer_of (rmetal1) ] = ly.insert_layer (db::LayerProperties (206, 0)); - dump_map [layer_of (rvia1) ] = ly.insert_layer (db::LayerProperties (207, 0)); - dump_map [layer_of (rmetal2) ] = ly.insert_layer (db::LayerProperties (208, 0)); + dump_map [layer_of (rpsd) ] = ly.insert_layer (db::LayerProperties (210, 0)); + dump_map [layer_of (rnsd) ] = ly.insert_layer (db::LayerProperties (211, 0)); + dump_map [layer_of (rpoly) ] = ly.insert_layer (db::LayerProperties (203, 0)); + dump_map [layer_of (rpoly_lbl) ] = ly.insert_layer (db::LayerProperties (203, 1)); + dump_map [layer_of (rdiff_cont) ] = ly.insert_layer (db::LayerProperties (204, 0)); + dump_map [layer_of (rpoly_cont) ] = ly.insert_layer (db::LayerProperties (205, 0)); + dump_map [layer_of (rmetal1) ] = ly.insert_layer (db::LayerProperties (206, 0)); + dump_map [layer_of (rmetal1_lbl) ] = ly.insert_layer (db::LayerProperties (206, 1)); + dump_map [layer_of (rvia1) ] = ly.insert_layer (db::LayerProperties (207, 0)); + dump_map [layer_of (rmetal2) ] = ly.insert_layer (db::LayerProperties (208, 0)); + dump_map [layer_of (rmetal2_lbl) ] = ly.insert_layer (db::LayerProperties (208, 1)); // write nets to layout db::CellMapping cm = dss.cell_mapping_to_original (0, &ly, tc.cell_index ()); @@ -371,6 +382,206 @@ TEST(1_DeviceAndNetExtraction) " device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" "end;\n" ); + + // compare the collected test data + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "device_extract_au1.gds"); + + db::compare_layouts (_this, ly, au); +} + +TEST(1a_DeviceAndNetExtractionWithTextsAsLabels) +{ + db::Layout ly; + db::LayerMap lmap; + + unsigned int nwell = define_layer (ly, lmap, 1); + unsigned int active = define_layer (ly, lmap, 2); + unsigned int poly = define_layer (ly, lmap, 3); + unsigned int poly_lbl = define_layer (ly, lmap, 3, 1); + unsigned int diff_cont = define_layer (ly, lmap, 4); + unsigned int poly_cont = define_layer (ly, lmap, 5); + unsigned int metal1 = define_layer (ly, lmap, 6); + unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1); + unsigned int via1 = define_layer (ly, lmap, 7); + unsigned int metal2 = define_layer (ly, lmap, 8); + unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1); + + { + db::LoadLayoutOptions options; + options.get_options ().layer_map = lmap; + options.get_options ().create_other_layers = false; + + std::string fn (tl::testsrc ()); + fn = tl::combine_path (fn, "testdata"); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "device_extract_l1.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 rnwell (db::RecursiveShapeIterator (ly, tc, nwell), dss); + db::Region ractive (db::RecursiveShapeIterator (ly, tc, active), dss); + db::Region rpoly (db::RecursiveShapeIterator (ly, tc, poly), dss); + db::Texts rpoly_lbl (db::RecursiveShapeIterator (ly, tc, poly_lbl), dss); + db::Region rdiff_cont (db::RecursiveShapeIterator (ly, tc, diff_cont), dss); + db::Region rpoly_cont (db::RecursiveShapeIterator (ly, tc, poly_cont), dss); + db::Region rmetal1 (db::RecursiveShapeIterator (ly, tc, metal1), dss); + db::Texts rmetal1_lbl (db::RecursiveShapeIterator (ly, tc, metal1_lbl), dss); + db::Region rvia1 (db::RecursiveShapeIterator (ly, tc, via1), dss); + db::Region rmetal2 (db::RecursiveShapeIterator (ly, tc, metal2), dss); + db::Texts rmetal2_lbl (db::RecursiveShapeIterator (ly, tc, metal2_lbl), dss); + + // derived regions + + db::Region rpactive = ractive & rnwell; + db::Region rpgate = rpactive & rpoly; + db::Region rpsd = rpactive - rpgate; + + db::Region rnactive = ractive - rnwell; + db::Region rngate = rnactive & rpoly; + db::Region rnsd = rnactive - rngate; + + // return the computed layers into the original layout and write it for debugging purposes + + unsigned int lgate = ly.insert_layer (db::LayerProperties (10, 0)); // 10/0 -> Gate + unsigned int lsd = ly.insert_layer (db::LayerProperties (11, 0)); // 11/0 -> Source/Drain + unsigned int lpdiff = ly.insert_layer (db::LayerProperties (12, 0)); // 12/0 -> P Diffusion + unsigned int lndiff = ly.insert_layer (db::LayerProperties (13, 0)); // 13/0 -> N Diffusion + + rpgate.insert_into (&ly, tc.cell_index (), lgate); + rngate.insert_into (&ly, tc.cell_index (), lgate); + rpsd.insert_into (&ly, tc.cell_index (), lsd); + rnsd.insert_into (&ly, tc.cell_index (), lsd); + rpsd.insert_into (&ly, tc.cell_index (), lpdiff); + rnsd.insert_into (&ly, tc.cell_index (), lndiff); + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS"); + db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS"); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["SD"] = &rpsd; + dl["G"] = &rpgate; + dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes + pmos_ex.extract (dss, 0, dl, nl, cl); + + dl["SD"] = &rnsd; + dl["G"] = &rngate; + dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes + nmos_ex.extract (dss, 0, dl, nl, cl); + + // perform the net extraction + + db::NetlistExtractor net_ex; + + db::Connectivity conn; + // Intra-layer + conn.connect (rpsd); + conn.connect (rnsd); + conn.connect (rpoly); + conn.connect (rdiff_cont); + conn.connect (rpoly_cont); + conn.connect (rmetal1); + conn.connect (rvia1); + conn.connect (rmetal2); + // Inter-layer + conn.connect (rpsd, rdiff_cont); + conn.connect (rnsd, rdiff_cont); + conn.connect (rpoly, rpoly_cont); + conn.connect (rpoly_cont, rmetal1); + conn.connect (rdiff_cont, rmetal1); + conn.connect (rmetal1, rvia1); + conn.connect (rvia1, rmetal2); + conn.connect (rpoly, rpoly_lbl); // attaches labels + conn.connect (rmetal1, rmetal1_lbl); // attaches labels + conn.connect (rmetal2, rmetal2_lbl); // attaches labels + + // extract the nets + + net_ex.extract_nets (dss, 0, conn, nl, cl); + + // debug layers produced for nets + // 202/0 -> Active + // 203/0 -> Poly + // 204/0 -> Diffusion contacts + // 205/0 -> Poly contacts + // 206/0 -> Metal1 + // 207/0 -> Via1 + // 208/0 -> Metal2 + // 210/0 -> N source/drain + // 211/0 -> P source/drain + std::map dump_map; + dump_map [layer_of (rpsd) ] = ly.insert_layer (db::LayerProperties (210, 0)); + dump_map [layer_of (rnsd) ] = ly.insert_layer (db::LayerProperties (211, 0)); + dump_map [layer_of (rpoly) ] = ly.insert_layer (db::LayerProperties (203, 0)); + dump_map [layer_of (rpoly_lbl) ] = ly.insert_layer (db::LayerProperties (203, 1)); + dump_map [layer_of (rdiff_cont) ] = ly.insert_layer (db::LayerProperties (204, 0)); + dump_map [layer_of (rpoly_cont) ] = ly.insert_layer (db::LayerProperties (205, 0)); + dump_map [layer_of (rmetal1) ] = ly.insert_layer (db::LayerProperties (206, 0)); + dump_map [layer_of (rmetal1_lbl) ] = ly.insert_layer (db::LayerProperties (206, 1)); + dump_map [layer_of (rvia1) ] = ly.insert_layer (db::LayerProperties (207, 0)); + dump_map [layer_of (rmetal2) ] = ly.insert_layer (db::LayerProperties (208, 0)); + dump_map [layer_of (rmetal2_lbl) ] = ly.insert_layer (db::LayerProperties (208, 1)); + + // write nets to layout + db::CellMapping cm = dss.cell_mapping_to_original (0, &ly, tc.cell_index ()); + dump_nets_to_layout (nl, cl, ly, dump_map, cm); + + // compare netlist as string + CHECKPOINT (); + db::compare_netlist (_this, nl, + "circuit RINGO ();\n" + " subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD);\n" + "end;\n" + "circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n" + " device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + " device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + " subcircuit TRANS $1 ($1=$2,$2=$4,$3=IN);\n" + " subcircuit TRANS $2 ($1=$2,$2=$5,$3=IN);\n" + " subcircuit TRANS $3 ($1=$5,$2=OUT,$3=$2);\n" + " subcircuit TRANS $4 ($1=$4,$2=OUT,$3=$2);\n" + "end;\n" + "circuit TRANS ($1=$1,$2=$2,$3=$3);\n" + "end;\n" + ); + + // compare the collected test data + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "device_extract_au1a.gds"); + + db::compare_layouts (_this, ly, au); } TEST(2_DeviceAndNetExtractionFlat) diff --git a/src/db/unit_tests/dbShapesTests.cc b/src/db/unit_tests/dbShapesTests.cc index a43778b8f..c438c2e03 100644 --- a/src/db/unit_tests/dbShapesTests.cc +++ b/src/db/unit_tests/dbShapesTests.cc @@ -1318,6 +1318,9 @@ TEST(5) "text ('A',r0 10,35) #0\n" "text ('B',r90 20,25) #0\n" "text ('C',m90 30,15) #0\n" + "text ('A',r0 10,35) #1\n" + "text ('B',r90 20,25) #2\n" + "text ('C',m90 30,15) #3\n" "text ('A',r0 0,50) #0\n" "text ('B',r90 -90,140) #0\n" "text ('C',m90 -180,230) #0\n" @@ -1333,9 +1336,6 @@ TEST(5) "text ('A',r0 33010,40) #0\n" "text ('A',r0 33010,10040) #0\n" "text ('A',r0 33010,20040) #0\n" - "text ('A',r0 10,35) #1\n" - "text ('B',r90 20,25) #2\n" - "text ('C',m90 30,15) #3\n" "text ('A',r0 0,50) #5\n" "text ('B',r90 -90,140) #6\n" "text ('C',m90 -180,230) #7\n" @@ -1357,10 +1357,13 @@ TEST(5) for (db::Shapes::shape_iterator shape = topcell.shapes (lindex).begin (db::Shapes::shape_iterator::All); ! shape.at_end (); ++shape) { sa_copy.insert (*shape); } - EXPECT_EQ (shapes_to_string (_this, sa_copy), + EXPECT_EQ (shapes_to_string (_this, sa_copy), "text ('A',r0 10,35) #0\n" "text ('B',r90 20,25) #0\n" "text ('C',m90 30,15) #0\n" + "text ('A',r0 10,35) #1\n" + "text ('B',r90 20,25) #2\n" + "text ('C',m90 30,15) #3\n" "text ('A',r0 0,50) #0\n" "text ('B',r90 -90,140) #0\n" "text ('C',m90 -180,230) #0\n" @@ -1376,9 +1379,6 @@ TEST(5) "text ('A',r0 33010,40) #0\n" "text ('A',r0 33010,10040) #0\n" "text ('A',r0 33010,20040) #0\n" - "text ('A',r0 10,35) #1\n" - "text ('B',r90 20,25) #2\n" - "text ('C',m90 30,15) #3\n" "text ('A',r0 0,50) #5\n" "text ('B',r90 -90,140) #6\n" "text ('C',m90 -180,230) #7\n" diff --git a/testdata/algo/device_extract_au1.gds b/testdata/algo/device_extract_au1.gds index 903b6bf0d..776991004 100644 Binary files a/testdata/algo/device_extract_au1.gds and b/testdata/algo/device_extract_au1.gds differ diff --git a/testdata/algo/device_extract_au1a.gds b/testdata/algo/device_extract_au1a.gds new file mode 100644 index 000000000..79534b993 Binary files /dev/null and b/testdata/algo/device_extract_au1a.gds differ