From 0b5db06ca8ee4de428593175dbf815da025c34e9 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 14 Jun 2019 23:45:04 +0200 Subject: [PATCH] WIP: tests for BJT extraction --- src/db/unit_tests/dbNetlistExtractorTests.cc | 242 +++++++++++++++++++ testdata/algo/bipolar_devices_nets.gds | Bin 0 -> 19116 bytes testdata/algo/bipolar_devices_test.oas | Bin 0 -> 1389 bytes 3 files changed, 242 insertions(+) create mode 100644 testdata/algo/bipolar_devices_nets.gds create mode 100644 testdata/algo/bipolar_devices_test.oas diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index 7c66997fa..3faf281bc 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -1355,3 +1355,245 @@ TEST(5_ResAndCapWithBulkExtraction) db::compare_layouts (_this, ly, au); } +TEST(6_BipolarTransistorExtraction) +{ + 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); + unsigned int pplus = define_layer (ly, lmap, 9); + unsigned int nplus = define_layer (ly, lmap, 10); + + { + 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, "bipolar_devices_test.oas"); + + 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::Region 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::Region 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::Region rmetal2_lbl (db::RecursiveShapeIterator (ly, tc, metal2_lbl), dss); + db::Region rpplus (db::RecursiveShapeIterator (ly, tc, pplus), dss); + db::Region rnplus (db::RecursiveShapeIterator (ly, tc, nplus), dss); + db::Region rbulk (new db::DeepRegion (dss.empty_layer ())); + + // derived regions + + db::Region rpactive = ractive & rnwell; + db::Region rbase = rpactive.selected_not_interacting (rpoly).selected_interacting (rpplus); + db::Region rpactive_mos = rpactive - rbase; + + db::Region rpgate = rpactive_mos & rpoly; + db::Region rpsd = rpactive_mos - rpgate; + + db::Region rnactive = ractive - rnwell; + db::Region rngate = rnactive & rpoly; + db::Region rnsd = rnactive - rngate; + + db::Region rntie = rnwell & rnplus; + db::Region remitter = rpplus & rbase; + + // 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 + unsigned int lbase = ly.insert_layer (db::LayerProperties (14, 0)); // 14/0 -> Base + unsigned int lemitter = ly.insert_layer (db::LayerProperties (15, 0)); // 15/0 -> Base + unsigned int lntie = ly.insert_layer (db::LayerProperties (16, 0)); // 16/0 -> N Tiedown + + 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); + rbase.insert_into (&ly, tc.cell_index (), lbase); + remitter.insert_into (&ly, tc.cell_index (), lemitter); + rntie.insert_into (&ly, tc.cell_index (), lntie); + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS4Transistor pmos_ex ("PMOS"); + db::NetlistDeviceExtractorMOS4Transistor nmos_ex ("NMOS"); + db::NetlistDeviceExtractorBipolarTransistor bjt_ex ("PNP"); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["SD"] = &rpsd; + dl["G"] = &rpgate; + dl["W"] = &rnwell; + // terminal patches + dl["tG"] = &rpoly; + dl["tS"] = &rpsd; + dl["tD"] = &rpsd; + pmos_ex.extract (dss, 0, dl, nl, cl); + + dl.clear (); + dl["SD"] = &rnsd; + dl["G"] = &rngate; + dl["W"] = &rbulk; + // terminal patches + dl["tG"] = &rpoly; + dl["tS"] = &rnsd; + dl["tD"] = &rnsd; + nmos_ex.extract (dss, 0, dl, nl, cl); + + dl.clear (); + dl["E"] = &remitter; + dl["B"] = &rbase; + dl["C"] = &rbulk; + // terminal patches + dl["tB"] = &rnwell; + bjt_ex.extract (dss, 0, dl, nl, cl); + + + // perform the net extraction + + db::NetlistExtractor net_ex; + + db::Connectivity conn; + // Intra-layer + conn.connect (rnwell); + conn.connect (rpsd); + conn.connect (rnsd); + conn.connect (rbase); + conn.connect (remitter); + conn.connect (rntie); + conn.connect (rpoly); + conn.connect (rdiff_cont); + conn.connect (rpoly_cont); + conn.connect (rmetal1); + conn.connect (rvia1); + conn.connect (rmetal2); + // Inter-layer + conn.connect (rntie, rnwell); + conn.connect (rntie, rdiff_cont); + conn.connect (remitter, rdiff_cont); + 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 + // Global nets + conn.connect_global (rbulk, "BULK"); + + // extract the nets + + net_ex.extract_nets (dss, 0, conn, nl, cl, "*"); + + // Flatten device circuits + + std::vector circuits_to_flatten; + circuits_to_flatten.push_back ("TRANS"); + circuits_to_flatten.push_back ("TRANS2"); + + for (std::vector::const_iterator i = circuits_to_flatten.begin (); i != circuits_to_flatten.end (); ++i) { + db::Circuit *c = nl.circuit_by_name (*i); + tl_assert (c != 0); + nl.flatten_circuit (c); + } + + // cleanup + completion + nl.combine_devices (); + nl.make_top_level_pins (); + nl.purge (); + + EXPECT_EQ (all_net_names_unique (nl), true); + + // debug layers produced for nets + // 201/0 -> n well + // 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 + // 212/0 -> Emitter + // 213/0 -> N tiedown + 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 (remitter) ] = ly.insert_layer (db::LayerProperties (212, 0)); + dump_map [layer_of (rntie) ] = ly.insert_layer (db::LayerProperties (213, 0)); + dump_map [layer_of (rnwell) ] = ly.insert_layer (db::LayerProperties (201, 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)); + + // 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, true /*with device cells*/); + + // compare netlist as string + CHECKPOINT (); + db::compare_netlist (_this, nl, + "circuit TOP (VSS=VSS,IN=IN,OUT=OUT,VDD=VDD,BULK=BULK);\n" + " device PMOS $1 (S=$4,G=VSS,D=VDD,B=VDD) (L=0.4,W=2.3,AS=1.38,AD=1.38,PS=5.8,PD=5.8);\n" + " device PMOS $2 (S=VDD,G=$4,D=OUT,B=VDD) (L=0.4,W=2.3,AS=1.38,AD=1.38,PS=5.8,PD=5.8);\n" + " device PMOS $3 (S=VDD,G=IN,D=$3,B=VDD) (L=0.4,W=2.3,AS=1.38,AD=1.38,PS=5.8,PD=5.8);\n" + " device NMOS $4 (S=VSS,G=$4,D=OUT,B=BULK) (L=0.4,W=4.6,AS=2.185,AD=2.185,PS=8.8,PD=8.8);\n" + " device PNP $6 (C=BULK,B=$3,E=$3) (AE=3.06,PE=7);\n" + " device PNP $7 (C=BULK,B=$3,E=$4) (AE=6.12,PE=14);\n" + " device NMOS $9 (S=VSS,G=IN,D=$3,B=BULK) (L=0.4,W=3.1,AS=1.86,AD=1.86,PS=7.4,PD=7.4);\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, "bipolar_devices_nets.gds"); + + db::compare_layouts (_this, ly, au); +} + diff --git a/testdata/algo/bipolar_devices_nets.gds b/testdata/algo/bipolar_devices_nets.gds new file mode 100644 index 0000000000000000000000000000000000000000..f27a728596b4e0f925c9ea35599b1ec47b7767b9 GIT binary patch literal 19116 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 Qw~3SsdjBn1`2K$PAH4e1ApigX literal 0 HcmV?d00001 diff --git a/testdata/algo/bipolar_devices_test.oas b/testdata/algo/bipolar_devices_test.oas new file mode 100644 index 0000000000000000000000000000000000000000..c60878984f0ed5468892a1eadd1b04cc2240121e GIT binary patch literal 1389 zcmd^+-%C?r7{}lDyyu+Fy=QZC?<{Sg6haU#f1oU~Xl_#v9k;P_rWw*8j3T<|N{*N` z!HWq|6THw6oYalr#RM;mEF5?-?-aZ^g3<&p^divMg;G%O*=#D+U(gHh;q!i<@AKn5 zZ;kBl6l;SXS(MEti0WN+V9x-~E~leXj&^$PMP;!);P*wvfZ}iWhojx1Pw6nSPP4NR zjs*T@a5_wKR0)QnUcV#>h!V>yVNXDA04$dW$mUfJb;&aQ_WI)B7m zpqoyIAdQ?NF45~3ayUKb+!6Dge#IlzBVO-x${2Nt9%P{6Z#Z!_AY;*)XDsBi8lsY? z)i2Q~6#h_7JoP6YzUVolU@jDrA~GtWXH|bIh@6)PmW*6ufRNY%?g>=PniPQy0(M`7?Gs&CJ@?z`DnF1ed?U zu_laY{0;XoY0Wa^rQZ60ww}L?LAKvY)CKE^A+`gDD~L*ma>X(*-A&Xz!xEPkK3pK$ z5_hnYml9~)l=%*4s_4vGbHce;cj(H`oN3&-26-@I*eEAcN%t&aD3kHbBL-y4$i(vP zq}y==LS75TXPC|4et5BN^DSJhObbL!x|3B0uHgo<&CM~i_q>8(-!vPJ*~tK(LtD2r zc0WwqTJyv=xZ@)&2M#*xSb*Ls%Y5XXt=UqLsPQ{Fq&+!w5H*K(E7HPogs9_Ja%j&` z&@z>ab+fg^opY{zhU=wdYl&Mgo$STNz8RK}F)=ia!ZGxdd61&z-XWH}(3*2d&%t1$ zyo~fNSkpC!4h$wB`*XB6%#fjyxaGY$(>POwVYbXl-y~VJVvm1<8cRZP%czA6nY895PXFPB rfz-HVw_?;XuMl;ke8s-_1s=BRFO|BPXtEEo03;r--DhI|^8(-(#k8}z literal 0 HcmV?d00001