/* KLayout Layout Viewer Copyright (C) 2006-2019 Matthias Koefferlein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "dbLayoutToNetlist.h" #include "dbLayoutToNetlistWriter.h" #include "dbStream.h" #include "dbCommonReader.h" #include "dbNetlistDeviceExtractorClasses.h" #include "tlUnitTest.h" #include "tlStream.h" #include "tlFileUtils.h" 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)); lmap.map (ly.get_properties (lid), lid); return lid; } TEST(1_WriterBasic) { 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::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set ())); std::auto_ptr rnwell (l2n.make_layer (nwell)); std::auto_ptr ractive (l2n.make_layer (active)); std::auto_ptr rpoly (l2n.make_polygon_layer (poly)); std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl)); std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont)); std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont)); std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1)); std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl)); std::auto_ptr rvia1 (l2n.make_polygon_layer (via1)); std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2)); std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl)); // 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; db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS"); db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS"); // device extraction db::NetlistDeviceExtractor::input_layers dl; dl["SD"] = &rpsd; dl["G"] = &rpgate; dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes l2n.extract_devices (pmos_ex, dl); dl["SD"] = &rnsd; dl["G"] = &rngate; dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes l2n.extract_devices (nmos_ex, dl); // return the computed layers into the original layout and write it for debugging purposes // NOTE: this will include the device layers too 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 lpoly = ly.insert_layer (db::LayerProperties (14, 0)); // 14/0 -> Poly with gate terminal 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); rpoly->insert_into (&ly, tc.cell_index (), lpoly); // net extraction // Intra-layer l2n.connect (rpsd); l2n.connect (rnsd); l2n.connect (*rpoly); l2n.connect (*rdiff_cont); l2n.connect (*rpoly_cont); l2n.connect (*rmetal1); l2n.connect (*rvia1); l2n.connect (*rmetal2); // Inter-layer l2n.connect (rpsd, *rdiff_cont); l2n.connect (rnsd, *rdiff_cont); l2n.connect (*rpoly, *rpoly_cont); l2n.connect (*rpoly_cont, *rmetal1); l2n.connect (*rdiff_cont, *rmetal1); l2n.connect (*rmetal1, *rvia1); l2n.connect (*rvia1, *rmetal2); l2n.connect (*rpoly, *rpoly_lbl); // attaches labels l2n.connect (*rmetal1, *rmetal1_lbl); // attaches labels l2n.connect (*rmetal2, *rmetal2_lbl); // attaches labels // create some mess - we have to keep references to the layers to make them not disappear rmetal1_lbl.reset (0); rmetal2_lbl.reset (0); rpoly_lbl.reset (0); l2n.extract_netlist (); tl::OutputMemoryStream mem; { tl::OutputStream stream (mem); db::LayoutToNetlistStandardWriter writer (stream); writer.write (&l2n); } // TODO: too big for inlined text ... #if 0 EXPECT_EQ (std::string (mem.data (), mem.size ()), "" ); #endif }