/* KLayout Layout Viewer Copyright (C) 2006-2022 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 "tlUnitTest.h" #include "dbNetTracerIO.h" #include "dbNetTracer.h" #include "dbRecursiveShapeIterator.h" #include "dbLayoutDiff.h" #include "dbTestSupport.h" #include "dbWriter.h" #include "dbReader.h" static db::NetTracerConnectionInfo connection (const std::string &a, const std::string &v, const std::string &b) { return db::NetTracerConnectionInfo (db::NetTracerLayerExpressionInfo::compile (a), db::NetTracerLayerExpressionInfo::compile (v), db::NetTracerLayerExpressionInfo::compile (b)); } static db::NetTracerConnectionInfo connection (const std::string &a, const std::string &b) { return db::NetTracerConnectionInfo (db::NetTracerLayerExpressionInfo::compile (a), db::NetTracerLayerExpressionInfo::compile (b)); } static db::NetTracerSymbolInfo symbol (const std::string &s, const std::string &e) { return db::NetTracerSymbolInfo (s, e); } static int layer_for (const db::Layout &layout, const db::LayerProperties &lp) { for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) { if ((*l).second->log_equal (lp)) { return int ((*l).first); } } return -1; } #if 0 // not used yet: static db::NetTracerShape find_shape (const db::Layout &layout, const db::Cell &cell, int l, const db::Point &pt) { if (l < 0 || ! layout.is_valid_layer ((unsigned int) l)) { return db::NetTracerShape (); } db::RecursiveShapeIterator s (layout, cell, (unsigned int) l, db::Box (pt, pt)); if (! s.at_end ()) { return db::NetTracerShape (s.itrans (), s.shape (), (unsigned int) l, s.cell_index ()); } else { return db::NetTracerShape (); } } #endif static db::NetTracerNet trace (db::NetTracer &tracer, const db::Layout &layout, const db::Cell &cell, const db::NetTracerConnectivity &tc, unsigned int l_start, const db::Point &p_start) { db::NetTracerData tracer_data = tc.get_tracer_data (layout); tracer.trace (layout, cell, p_start, l_start, tracer_data); return db::NetTracerNet (tracer, db::ICplxTrans (), layout, cell.cell_index (), std::string (), std::string (), tracer_data); } static db::NetTracerNet trace (db::NetTracer &tracer, const db::Layout &layout, const db::Cell &cell, const db::NetTracerConnectivity &tc, unsigned int l_start, const db::Point &p_start, unsigned int l_stop, const db::Point &p_stop) { db::NetTracerData tracer_data = tc.get_tracer_data (layout); tracer.trace (layout, cell, p_start, l_start, p_stop, l_stop, tracer_data); return db::NetTracerNet (tracer, db::ICplxTrans (), layout, cell.cell_index (), std::string (), std::string (), tracer_data); } void run_test (tl::TestBase *_this, const std::string &file, const db::NetTracerConnectivity &tc, const db::LayerProperties &lp_start, const db::Point &p_start, const std::string &file_au, const char *net_name = 0, size_t depth = 0) { db::Manager m (false); db::Layout layout_org (&m); { std::string fn (tl::testdata ()); fn += "/net_tracer/"; fn += file; tl::InputStream stream (fn); db::Reader reader (stream); reader.read (layout_org); } const db::Cell &cell = layout_org.cell (*layout_org.begin_top_down ()); db::NetTracer tracer; tracer.set_trace_depth (depth); db::NetTracerNet net = trace (tracer, layout_org, cell, tc, layer_for (layout_org, lp_start), p_start); if (net_name) { EXPECT_EQ (net.name (), std::string (net_name)); } EXPECT_EQ (net.incomplete (), depth != 0); if (depth > 0) { EXPECT_EQ (net.size () <= depth, true); } db::Layout layout_net; net.export_net (layout_net, layout_net.cell (layout_net.add_cell ("NET"))); std::string fn (tl::testdata ()); fn += "/net_tracer/"; fn += file_au; CHECKPOINT (); db::compare_layouts (_this, layout_net, fn, db::WriteOAS); } void run_test2 (tl::TestBase *_this, const std::string &file, const db::NetTracerConnectivity &tc, const db::LayerProperties &lp_start, const db::Point &p_start, const db::LayerProperties &lp_stop, const db::Point &p_stop, const std::string &file_au, const char *net_name = 0) { db::Manager m (false); db::Layout layout_org (&m); { std::string fn (tl::testdata ()); fn += "/net_tracer/"; fn += file; tl::InputStream stream (fn); db::Reader reader (stream); reader.read (layout_org); } const db::Cell &cell = layout_org.cell (*layout_org.begin_top_down ()); db::NetTracer tracer; db::NetTracerNet net = trace (tracer, layout_org, cell, tc, layer_for (layout_org, lp_start), p_start, layer_for (layout_org, lp_stop), p_stop); if (net_name) { EXPECT_EQ (net.name (), std::string (net_name)); } db::Layout layout_net; net.export_net (layout_net, layout_net.cell (layout_net.add_cell ("NET"))); std::string fn (tl::testdata ()); fn += "/net_tracer/"; fn += file_au; CHECKPOINT (); db::compare_layouts (_this, layout_net, fn, db::WriteOAS); } TEST(1) { std::string file = "t1.oas.gz"; std::string file_au = "t1_net.oas.gz"; db::NetTracerConnectivity tc; tc.add (connection ("1/0", "2/0", "3/0")); run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au, "THE_NAME"); } TEST(1b) { std::string file = "t1.oas.gz"; std::string file_au = "t1b_net.oas.gz"; db::NetTracerConnectivity tc; tc.add (connection ("1/0", "2/0", "3/0")); // point is off net ... run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 15000), file_au); } TEST(1c) { std::string file = "t1.oas.gz"; std::string file_au = "t1_net.oas.gz"; db::NetTracerConnectivity tc; tc.add_symbol (symbol ("a", "1/0")); tc.add_symbol (symbol ("c", "cc")); tc.add_symbol (symbol ("cc", "3/0")); tc.add (connection ("a", "2/0", "cc")); run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au, "THE_NAME"); } TEST(1d) { std::string file = "t1.oas.gz"; std::string file_au = "t1d_net.oas.gz"; db::NetTracerConnectivity tc; tc.add (connection ("1/0", "10/0", "11/0")); // some layers are non-existing run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au); } TEST(2) { std::string file = "t2.oas.gz"; std::string file_au = "t2_net.oas.gz"; db::NetTracerConnectivity tc; tc.add (connection ("1/0", "2/0", "3/0")); run_test2 (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), db::LayerProperties (3, 0), db::Point (4000, -20000), file_au, "THE_NAME"); } TEST(3) { std::string file = "t3.oas.gz"; std::string file_au = "t3_net.oas.gz"; db::NetTracerConnectivity tc; tc.add (connection ("1/0", "2/0", "3/0")); std::string msg; try { run_test2 (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), db::LayerProperties (3, 0), db::Point (4000, -20000), file_au); } catch (tl::Exception &ex) { msg = ex.msg (); } EXPECT_EQ (msg, "Nets are not connected"); } TEST(4) { std::string file = "t4.oas.gz"; std::string file_au = "t4_net.oas.gz"; db::NetTracerConnectivity tc; tc.add (connection ("1/0", "2/0", "3/0")); run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au, ""); } TEST(4b) { std::string file = "t4.oas.gz"; std::string file_au = "t4b_net.oas.gz"; db::NetTracerConnectivity tc; tc.add (connection ("1/0", "3/0")); run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au, "THE_NAME"); } TEST(5) { std::string file = "t5.oas.gz"; std::string file_au = "t5_net.oas.gz"; db::NetTracerConnectivity tc; tc.add (connection ("1/0*10/0", "2/0", "3/0")); run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au, "THE_NAME"); } TEST(5b) { std::string file = "t5.oas.gz"; std::string file_au = "t5b_net.oas.gz"; db::NetTracerConnectivity tc; tc.add (connection ("1/0", "2/0*10/0", "3/0")); run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au, "THE_NAME"); } TEST(5c) { std::string file = "t5.oas.gz"; std::string file_au = "t5c_net.oas.gz"; db::NetTracerConnectivity tc; tc.add (connection ("1/0", "2/0-11/0", "3/0")); run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au, ""); } TEST(5d) { std::string file = "t5.oas.gz"; std::string file_au = "t5d_net.oas.gz"; db::NetTracerConnectivity tc; tc.add (connection ("1/0-12/0", "2/0", "3/0-12/0")); run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au, "THE_NAME"); } TEST(5e) { std::string file = "t5.oas.gz"; std::string file_au = "t5e_net.oas.gz"; db::NetTracerConnectivity tc; tc.add (connection ("1/0-12/0", "2/0", "3/0-12/0")); run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (7000, 1500), file_au, "THE_NAME"); } TEST(5f) { std::string file = "t5.oas.gz"; std::string file_au = "t5f_net.oas.gz"; db::NetTracerConnectivity tc; tc.add_symbol (symbol ("x", "3-14")); tc.add (connection ("10-13", "x")); tc.add (connection ("x", "2", "1+13")); run_test (_this, file, tc, db::LayerProperties (10, 0), db::Point (7000, 1500), file_au, "THE_NAME"); } TEST(6) { std::string file = "t6.oas.gz"; std::string file_au = "t6_net.oas.gz"; db::NetTracerConnectivity tc; tc.add (connection ("1-10", "2", "3")); tc.add (connection ("3", "4", "5")); run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (-2250, -900), file_au, "IN_B"); } TEST(6b) { std::string file = "t6.oas.gz"; std::string file_au = "t6b_net.oas.gz"; db::NetTracerConnectivity tc; tc.add (connection ("1-10", "2", "3")); tc.add (connection ("3", "4", "5")); run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (-2250, -900), file_au, "IN_B", 10); } TEST(7) { std::string file = "t7.oas.gz"; std::string file_au = "t7_net.oas.gz"; db::NetTracerConnectivity tc; tc.add (connection ("15", "14", "2-7")); tc.add (connection ("15", "14", "7")); run_test (_this, file, tc, db::LayerProperties (15, 0), db::Point (-700, 300), file_au, ""); } // bug #456: OASIS box arrays and net tracer TEST(8) { std::string file = "t8.oas.gz"; std::string file_au = "t8_net.oas.gz"; db::NetTracerConnectivity tc; tc.add (connection ("15", "14", "7")); run_test (_this, file, tc, db::LayerProperties (15, 0), db::Point (4000, 10000), file_au, ""); } TEST(9) { std::string file = "t9.oas.gz"; std::string file_au = "t9_net.oas.gz"; db::NetTracerConnectivity tc; tc.add_symbol (symbol ("a", "8-12")); tc.add_symbol (symbol ("b", "a+7")); tc.add_symbol (symbol ("c", "15*26")); tc.add (connection ("b", "7")); tc.add (connection ("b", "c", "9")); run_test (_this, file, tc, db::LayerProperties (8, 0), db::Point (3000, 6800), file_au, "A"); }