WIP Netlist probing will deliver an instantiation path now.

This commit is contained in:
Matthias Koefferlein 2020-06-14 22:04:16 +02:00
parent b72f819d57
commit 880b9904cf
10 changed files with 208 additions and 56 deletions

View File

@ -1041,9 +1041,9 @@ LayoutToNetlist::build_nets (const std::vector<const db::Net *> *nets, const db:
} }
} }
db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::DPoint &point) db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::DPoint &point, std::vector<db::SubCircuit *> *sc_path_out)
{ {
return probe_net (of_region, db::CplxTrans (internal_layout ()->dbu ()).inverted () * point); return probe_net (of_region, db::CplxTrans (internal_layout ()->dbu ()).inverted () * point, sc_path_out);
} }
size_t LayoutToNetlist::search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster<db::NetShape> &test_cluster, std::vector<db::InstElement> &rev_inst_path) size_t LayoutToNetlist::search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster<db::NetShape> &test_cluster, std::vector<db::InstElement> &rev_inst_path)
@ -1077,7 +1077,7 @@ size_t LayoutToNetlist::search_net (const db::ICplxTrans &trans, const db::Cell
return 0; return 0;
} }
db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Point &point) db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Point &point, std::vector<db::SubCircuit *> *sc_path_out)
{ {
if (! m_netlist_extracted) { if (! m_netlist_extracted) {
throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet"))); throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet")));
@ -1142,38 +1142,57 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Poin
} }
std::vector<db::SubCircuit *> sc_path;
db::Net *topmost_net = net;
// follow the path up in the net hierarchy using the transformation and the upper cell index as the // follow the path up in the net hierarchy using the transformation and the upper cell index as the
// guide line // guide line
while (! inst_path.empty () && net->pin_count () > 0) { while (circuit && ! inst_path.empty ()) {
cell_indexes.pop_back (); cell_indexes.pop_back ();
const db::Pin *pin = circuit->pin_by_id (net->begin_pins ()->pin_id ()); const db::Pin *pin = 0;
tl_assert (pin != 0); if (net && net->pin_count () > 0) {
pin = circuit->pin_by_id (net->begin_pins ()->pin_id ());
tl_assert (pin != 0);
}
db::DCplxTrans dtrans = dbu_trans * inst_path.back ().complex_trans () * dbu_trans_inv; db::DCplxTrans dtrans = dbu_trans * inst_path.back ().complex_trans () * dbu_trans_inv;
// try to find a parent circuit which connects to this net // try to find a parent circuit which connects to this net
db::Circuit *upper_circuit = 0; db::Circuit *upper_circuit = 0;
db::SubCircuit *subcircuit = 0;
db::Net *upper_net = 0; db::Net *upper_net = 0;
for (db::Circuit::refs_iterator r = circuit->begin_refs (); r != circuit->end_refs () && ! upper_net; ++r) { for (db::Circuit::refs_iterator r = circuit->begin_refs (); r != circuit->end_refs () && ! upper_circuit; ++r) {
if (r->trans ().equal (dtrans) && r->circuit () && r->circuit ()->cell_index () == cell_indexes.back ()) { if (r->trans ().equal (dtrans) && r->circuit () && r->circuit ()->cell_index () == cell_indexes.back ()) {
upper_net = r->net_for_pin (pin->id ()); subcircuit = r.operator-> ();
upper_circuit = r->circuit (); if (pin) {
upper_net = subcircuit->net_for_pin (pin->id ());
}
upper_circuit = subcircuit->circuit ();
} }
} }
net = upper_net;
if (upper_net) { if (upper_net) {
circuit = upper_circuit; topmost_net = upper_net;
net = upper_net;
inst_path.pop_back ();
} else { } else {
break; sc_path.push_back (subcircuit);
} }
circuit = upper_circuit;
inst_path.pop_back ();
} }
return net; if (sc_path_out) {
std::reverse (sc_path.begin (), sc_path.end ());
*sc_path_out = sc_path;
}
return topmost_net;
} else { } else {
return 0; return 0;

View File

@ -709,8 +709,11 @@ public:
* *
* This variant accepts a micrometer-unit location. The location is given in the * This variant accepts a micrometer-unit location. The location is given in the
* coordinate space of the initial cell. * coordinate space of the initial cell.
*
* The subcircuit path leading to the topmost net is stored in *sc_path_out if this
* pointer is non-null.
*/ */
db::Net *probe_net (const db::Region &of_region, const db::DPoint &point); db::Net *probe_net (const db::Region &of_region, const db::DPoint &point, std::vector<SubCircuit *> *sc_path_out = 0);
/** /**
* @brief Finds the net by probing a specific location on the given layer * @brief Finds the net by probing a specific location on the given layer
@ -718,7 +721,7 @@ public:
* This variant accepts a database-unit location. The location is given in the * This variant accepts a database-unit location. The location is given in the
* coordinate space of the initial cell. * coordinate space of the initial cell.
*/ */
db::Net *probe_net (const db::Region &of_region, const db::Point &point); db::Net *probe_net (const db::Region &of_region, const db::Point &point, std::vector<SubCircuit *> *sc_path_out = 0);
/** /**
* @brief Runs an antenna check on the extracted clusters * @brief Runs an antenna check on the extracted clusters

View File

@ -543,7 +543,7 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
gsi::method_ext ("build_nets", &build_nets, gsi::arg ("nets"), gsi::arg ("cmap"), gsi::arg ("target"), gsi::arg ("lmap"), gsi::arg ("net_cell_name_prefix", tl::Variant (), "nil"), gsi::arg ("netname_prop", tl::Variant (), "nil"), gsi::arg ("hier_mode", db::LayoutToNetlist::BNH_Flatten, "BNH_Flatten"), gsi::arg ("circuit_cell_name_prefix", tl::Variant (), "nil"), gsi::arg ("device_cell_name_prefix", tl::Variant (), "nil"), gsi::method_ext ("build_nets", &build_nets, gsi::arg ("nets"), gsi::arg ("cmap"), gsi::arg ("target"), gsi::arg ("lmap"), gsi::arg ("net_cell_name_prefix", tl::Variant (), "nil"), gsi::arg ("netname_prop", tl::Variant (), "nil"), gsi::arg ("hier_mode", db::LayoutToNetlist::BNH_Flatten, "BNH_Flatten"), gsi::arg ("circuit_cell_name_prefix", tl::Variant (), "nil"), gsi::arg ("device_cell_name_prefix", tl::Variant (), "nil"),
"@brief Like \\build_all_nets, but with the ability to select some nets." "@brief Like \\build_all_nets, but with the ability to select some nets."
) + ) +
gsi::method ("probe_net", (db::Net *(db::LayoutToNetlist::*) (const db::Region &, const db::DPoint &)) &db::LayoutToNetlist::probe_net, gsi::arg ("of_layer"), gsi::arg ("point"), gsi::method ("probe_net", (db::Net *(db::LayoutToNetlist::*) (const db::Region &, const db::DPoint &, std::vector<db::SubCircuit *> *)) &db::LayoutToNetlist::probe_net, gsi::arg ("of_layer"), gsi::arg ("point"), gsi::arg ("sc_path_out", (std::vector<db::SubCircuit *> *) 0, "nil"),
"@brief Finds the net by probing a specific location on the given layer\n" "@brief Finds the net by probing a specific location on the given layer\n"
"\n" "\n"
"This method will find a net looking at the given layer at the specific position.\n" "This method will find a net looking at the given layer at the specific position.\n"
@ -557,14 +557,21 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
"Optimization functions such as \\Netlist#purge will remove parts of the net which means\n" "Optimization functions such as \\Netlist#purge will remove parts of the net which means\n"
"shape to net probing may no longer work for these nets.\n" "shape to net probing may no longer work for these nets.\n"
"\n" "\n"
"If non-null and an array, 'sc_path_out' will receive a list of \\SubCircuits objects which lead to the "
"net from the top circuit of the database.\n"
"\n"
"This variant accepts a micrometer-unit location. The location is given in the\n" "This variant accepts a micrometer-unit location. The location is given in the\n"
"coordinate space of the initial cell.\n" "coordinate space of the initial cell.\n"
"\n"
"The \\sc_path_out parameter has been added in version 0.27.\n"
) + ) +
gsi::method ("probe_net", (db::Net *(db::LayoutToNetlist::*) (const db::Region &, const db::Point &)) &db::LayoutToNetlist::probe_net, gsi::arg ("of_layer"), gsi::arg ("point"), gsi::method ("probe_net", (db::Net *(db::LayoutToNetlist::*) (const db::Region &, const db::Point &, std::vector<db::SubCircuit *> *)) &db::LayoutToNetlist::probe_net, gsi::arg ("of_layer"), gsi::arg ("point"), gsi::arg ("sc_path_out", (std::vector<db::SubCircuit *> *) 0, "nil"),
"@brief Finds the net by probing a specific location on the given layer\n" "@brief Finds the net by probing a specific location on the given layer\n"
"See the description of the other \\probe_net variant.\n" "See the description of the other \\probe_net variant.\n"
"This variant accepts a database-unit location. The location is given in the\n" "This variant accepts a database-unit location. The location is given in the\n"
"coordinate space of the initial cell.\n" "coordinate space of the initial cell.\n"
"\n"
"The \\sc_path_out parameter has been added in version 0.27.\n"
) + ) +
gsi::method ("write|write_l2n", &db::LayoutToNetlist::save, gsi::arg ("path"), gsi::arg ("short_format", false), gsi::method ("write|write_l2n", &db::LayoutToNetlist::save, gsi::arg ("path"), gsi::arg ("short_format", false),
"@brief Writes the extracted netlist to a file.\n" "@brief Writes the extracted netlist to a file.\n"

View File

@ -466,6 +466,21 @@ Class<db::SubCircuit> decl_dbSubCircuit (decl_dbNetlistObject, "db", "SubCircuit
gsi::method_ext ("disconnect_pin", &gsi::subcircuit_disconnect_pin1, gsi::arg ("pin"), gsi::method_ext ("disconnect_pin", &gsi::subcircuit_disconnect_pin1, gsi::arg ("pin"),
"@brief Disconnects the given pin from any net.\n" "@brief Disconnects the given pin from any net.\n"
"This version takes a \\Pin reference instead of a pin ID." "This version takes a \\Pin reference instead of a pin ID."
) +
gsi::method ("trans", &db::SubCircuit::trans,
"@brief Gets the physical transformation for the subcircuit.\n"
"\n"
"This property applies to subcircuits derived from a layout. It specifies the "
"placement of the respective cell.\n"
"\n"
"This property has been introduced in version 0.27."
) +
gsi::method ("trans=", &db::SubCircuit::set_trans, gsi::arg ("trans"),
"@brief Sets the physical transformation for the subcircuit.\n"
"\n"
"See \\trans for details about this property.\n"
"\n"
"This property has been introduced in version 0.27."
), ),
"@brief A subcircuit inside a circuit.\n" "@brief A subcircuit inside a circuit.\n"
"Circuits may instantiate other circuits as subcircuits similar to cells " "Circuits may instantiate other circuits as subcircuits similar to cells "

View File

@ -0,0 +1,67 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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 "gsiDecl.h"
#include "gsiDeclBasic.h"
#include "layNetlistBrowserDialog.h"
#include "layLayoutView.h"
namespace tl
{
// disable copy and default constructor for NetlistBrowserDialog
template <> struct type_traits<lay::NetlistBrowserDialog> : public type_traits<void>
{
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
}
namespace gsi
{
Class<lay::NetlistBrowserDialog> decl_NetlistBrowserDialog ("lay", "NetlistBrowserDialog",
gsi::Methods (),
"@brief ..."
);
static lay::NetlistBrowserDialog *netlist_browser (lay::LayoutView *lv)
{
return lv->get_plugin<lay::NetlistBrowserDialog> ();
}
// extend lay::LayoutView with the getter for the netlist browser
static
gsi::ClassExt<lay::LayoutView> decl_ext_layout_view (
gsi::method_ext ("netlist_browser", &netlist_browser,
"@brief Gets the netlist browser object for the given layout view\n"
"\n"
"\nThis method has been added in version 0.27.\n"
)
);
}

View File

@ -183,7 +183,8 @@ SOURCES = \
layGenericSyntaxHighlighter.cc \ layGenericSyntaxHighlighter.cc \
layDispatcher.cc \ layDispatcher.cc \
laySelectCellViewForm.cc \ laySelectCellViewForm.cc \
layLayoutStatisticsForm.cc layLayoutStatisticsForm.cc \
gsiDeclLayNetlistBrowserDialog.cc
HEADERS = \ HEADERS = \
gtf.h \ gtf.h \

View File

@ -935,6 +935,12 @@ struct test_arg_func<gsi::VectorType>
{ {
void operator() (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose) void operator() (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose)
{ {
if ((atype.is_cptr () || atype.is_ptr ()) && arg == Py_None) {
// for ptr or cptr, null is an allowed value
*ret = true;
return;
}
if (! PyTuple_Check (arg) && ! PyList_Check (arg)) { if (! PyTuple_Check (arg) && ! PyList_Check (arg)) {
*ret = false; *ret = false;
return; return;
@ -971,6 +977,12 @@ struct test_arg_func<gsi::MapType>
{ {
void operator () (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose) void operator () (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose)
{ {
if ((atype.is_cptr () || atype.is_ptr ()) && arg == Py_None) {
// for ptr or cptr, null is an allowed value
*ret = true;
return;
}
if (! PyDict_Check (arg)) { if (! PyDict_Check (arg)) {
*ret = false; *ret = false;
return; return;
@ -999,6 +1011,7 @@ struct test_arg_func<gsi::MapType>
} }
} }
}; };
template <> template <>
struct test_arg_func<gsi::ObjectType> struct test_arg_func<gsi::ObjectType>
{ {

View File

@ -956,7 +956,7 @@ struct test_arg_func<gsi::VectorType>
if ((atype.is_cptr () || atype.is_ptr ()) && arg == Qnil) { if ((atype.is_cptr () || atype.is_ptr ()) && arg == Qnil) {
// for pointers to vectors, nil is a valid value // for pointers to vectors, nil is a valid value
*ret = true; *ret = true;
} if (TYPE (arg) != T_ARRAY) { } else if (TYPE (arg) != T_ARRAY) {
*ret = false; *ret = false;
} else { } else {

View File

@ -69,7 +69,7 @@ class DBLayoutToNetlistTests(unittest.TestCase):
ut_testsrc = os.getenv("TESTSRC") ut_testsrc = os.getenv("TESTSRC")
ly = pya.Layout() ly = pya.Layout()
ly.read(os.path.join(ut_testsrc, "testdata", "algo", "device_extract_l1.gds")) ly.read(os.path.join(ut_testsrc, "testdata", "algo", "device_extract_l1_with_inv_nodes.gds"))
l2n = pya.LayoutToNetlist(pya.RecursiveShapeIterator(ly, ly.top_cell(), [])) l2n = pya.LayoutToNetlist(pya.RecursiveShapeIterator(ly, ly.top_cell(), []))
@ -97,40 +97,56 @@ class DBLayoutToNetlistTests(unittest.TestCase):
self.assertEqual(str(l2n.netlist()), """circuit TRANS ($1=$1,$2=$2); self.assertEqual(str(l2n.netlist()), """circuit TRANS ($1=$1,$2=$2);
end; end;
circuit INV2 (OUT=OUT,$2=$2,$3=$3,$4=$4); circuit INV2 (OUT=OUT,$2=$3,$3=$4);
subcircuit TRANS $1 ($1=$4,$2=OUT); subcircuit TRANS $1 ($1=$4,$2=OUT);
subcircuit TRANS $2 ($1=$3,$2=OUT); subcircuit TRANS $2 ($1=$3,$2=OUT);
subcircuit TRANS $3 ($1=$2,$2=$4); subcircuit TRANS $3 ($1=$2,$2=$4);
subcircuit TRANS $4 ($1=$2,$2=$3); subcircuit TRANS $4 ($1=$2,$2=$3);
end; end;
circuit RINGO (); circuit RINGO ();
subcircuit INV2 $1 (OUT=OSC,$2=FB,$3=VSS,$4=VDD); subcircuit INV2 $1 (OUT='FB,OSC',$2=VSS,$3=VDD);
subcircuit INV2 $2 (OUT=$I29,$2=$I20,$3=VSS,$4=VDD); subcircuit INV2 $2 (OUT=$I20,$2=VSS,$3=VDD);
subcircuit INV2 $3 (OUT=$I28,$2=$I19,$3=VSS,$4=VDD); subcircuit INV2 $3 (OUT=$I19,$2=VSS,$3=VDD);
subcircuit INV2 $4 (OUT=$I30,$2=$I21,$3=VSS,$4=VDD); subcircuit INV2 $4 (OUT=$I21,$2=VSS,$3=VDD);
subcircuit INV2 $5 (OUT=$I31,$2=$I22,$3=VSS,$4=VDD); subcircuit INV2 $5 (OUT=$I22,$2=VSS,$3=VDD);
subcircuit INV2 $6 (OUT=$I32,$2=$I23,$3=VSS,$4=VDD); subcircuit INV2 $6 (OUT=$I23,$2=VSS,$3=VDD);
subcircuit INV2 $7 (OUT=$I33,$2=$I24,$3=VSS,$4=VDD); subcircuit INV2 $7 (OUT=$I24,$2=VSS,$3=VDD);
subcircuit INV2 $8 (OUT=$I34,$2=$I25,$3=VSS,$4=VDD); subcircuit INV2 $8 (OUT=$I25,$2=VSS,$3=VDD);
subcircuit INV2 $9 (OUT=$I35,$2=$I26,$3=VSS,$4=VDD); subcircuit INV2 $9 (OUT=$I26,$2=VSS,$3=VDD);
subcircuit INV2 $10 (OUT=$I36,$2=$I27,$3=VSS,$4=VDD); subcircuit INV2 $10 (OUT=$I27,$2=VSS,$3=VDD);
end; end;
""") """)
self.assertEqual(str(l2n.probe_net(rmetal2, pya.DPoint(0.0, 1.8))), "RINGO:FB") self.assertEqual(str(l2n.probe_net(rmetal2, pya.DPoint(0.0, 1.8))), "RINGO:FB,OSC")
sc_path = []
self.assertEqual(str(l2n.probe_net(rmetal2, pya.DPoint(0.0, 1.8), sc_path)), "RINGO:FB,OSC")
self.assertEqual(len(sc_path), 0)
self.assertEqual(repr(l2n.probe_net(rmetal2, pya.DPoint(-2.0, 1.8))), "None") self.assertEqual(repr(l2n.probe_net(rmetal2, pya.DPoint(-2.0, 1.8))), "None")
n = l2n.probe_net(rmetal1, pya.Point(2600, 1000)) n = l2n.probe_net(rmetal1, pya.Point(2600, 1000), None)
self.assertEqual(str(n), "RINGO:$I20") self.assertEqual(str(n), "INV2:$2")
sc_path = []
n = l2n.probe_net(rmetal1, pya.Point(2600, 1000), sc_path)
self.assertEqual(str(n), "INV2:$2")
self.assertEqual(len(sc_path), 1)
a = []
t = pya.DCplxTrans()
for sc in sc_path:
a.append(sc.expanded_name())
t = t * sc.trans
self.assertEqual(",".join(a), "$2")
self.assertEqual(str(t), "r0 *1 2.64,0")
self.assertEqual(str(l2n.shapes_of_net(n, rmetal1, True)), "(1660,-420;1660,2420;2020,2420;2020,-420);(1840,820;1840,1180;3220,1180;3220,820);(1660,2420;1660,3180;2020,3180;2020,2420);(1660,-380;1660,380;2020,380;2020,-380)") self.assertEqual(str(l2n.shapes_of_net(n, rmetal1, True)),
"(-980,-420;-980,2420;-620,2420;-620,-420);(-800,820;-800,1180;580,1180;580,820);(-980,2420;-980,3180;-620,3180;-620,2420);(-980,-380;-980,380;-620,380;-620,-380)")
shapes = pya.Shapes() shapes = pya.Shapes()
l2n.shapes_of_net(n, rmetal1, True, shapes) l2n.shapes_of_net(n, rmetal1, True, shapes)
r = pya.Region() r = pya.Region()
for s in shapes.each(): for s in shapes.each():
r.insert(s.polygon) r.insert(s.polygon)
self.assertEqual(str(r), "(1660,-420;1660,2420;2020,2420;2020,-420);(1840,820;1840,1180;3220,1180;3220,820);(1660,2420;1660,3180;2020,3180;2020,2420);(1660,-380;1660,380;2020,380;2020,-380)") self.assertEqual(str(r),
"(-980,-420;-980,2420;-620,2420;-620,-420);(-800,820;-800,1180;580,1180;580,820);(-980,2420;-980,3180;-620,3180;-620,2420);(-980,-380;-980,380;-620,380;-620,-380)")
def test_10_LayoutToNetlistExtractionWithoutDevices(self): def test_10_LayoutToNetlistExtractionWithoutDevices(self):

View File

@ -104,7 +104,7 @@ class DBLayoutToNetlist_TestClass < TestBase
def test_2_ShapesFromNet def test_2_ShapesFromNet
ly = RBA::Layout::new ly = RBA::Layout::new
ly.read(File.join($ut_testsrc, "testdata", "algo", "device_extract_l1.gds")) ly.read(File.join($ut_testsrc, "testdata", "algo", "device_extract_l1_with_inv_nodes.gds"))
l2n = RBA::LayoutToNetlist::new(RBA::RecursiveShapeIterator::new(ly, ly.top_cell, [])) l2n = RBA::LayoutToNetlist::new(RBA::RecursiveShapeIterator::new(ly, ly.top_cell, []))
@ -133,39 +133,50 @@ class DBLayoutToNetlist_TestClass < TestBase
assert_equal(l2n.netlist.to_s, <<END) assert_equal(l2n.netlist.to_s, <<END)
circuit TRANS ($1=$1,$2=$2); circuit TRANS ($1=$1,$2=$2);
end; end;
circuit INV2 (OUT=OUT,$2=$2,$3=$3,$4=$4); circuit INV2 (OUT=OUT,$2=$3,$3=$4);
subcircuit TRANS $1 ($1=$4,$2=OUT); subcircuit TRANS $1 ($1=$4,$2=OUT);
subcircuit TRANS $2 ($1=$3,$2=OUT); subcircuit TRANS $2 ($1=$3,$2=OUT);
subcircuit TRANS $3 ($1=$2,$2=$4); subcircuit TRANS $3 ($1=$2,$2=$4);
subcircuit TRANS $4 ($1=$2,$2=$3); subcircuit TRANS $4 ($1=$2,$2=$3);
end; end;
circuit RINGO (); circuit RINGO ();
subcircuit INV2 $1 (OUT=OSC,$2=FB,$3=VSS,$4=VDD); subcircuit INV2 $1 (OUT='FB,OSC',$2=VSS,$3=VDD);
subcircuit INV2 $2 (OUT=$I29,$2=$I20,$3=VSS,$4=VDD); subcircuit INV2 $2 (OUT=$I20,$2=VSS,$3=VDD);
subcircuit INV2 $3 (OUT=$I28,$2=$I19,$3=VSS,$4=VDD); subcircuit INV2 $3 (OUT=$I19,$2=VSS,$3=VDD);
subcircuit INV2 $4 (OUT=$I30,$2=$I21,$3=VSS,$4=VDD); subcircuit INV2 $4 (OUT=$I21,$2=VSS,$3=VDD);
subcircuit INV2 $5 (OUT=$I31,$2=$I22,$3=VSS,$4=VDD); subcircuit INV2 $5 (OUT=$I22,$2=VSS,$3=VDD);
subcircuit INV2 $6 (OUT=$I32,$2=$I23,$3=VSS,$4=VDD); subcircuit INV2 $6 (OUT=$I23,$2=VSS,$3=VDD);
subcircuit INV2 $7 (OUT=$I33,$2=$I24,$3=VSS,$4=VDD); subcircuit INV2 $7 (OUT=$I24,$2=VSS,$3=VDD);
subcircuit INV2 $8 (OUT=$I34,$2=$I25,$3=VSS,$4=VDD); subcircuit INV2 $8 (OUT=$I25,$2=VSS,$3=VDD);
subcircuit INV2 $9 (OUT=$I35,$2=$I26,$3=VSS,$4=VDD); subcircuit INV2 $9 (OUT=$I26,$2=VSS,$3=VDD);
subcircuit INV2 $10 (OUT=$I36,$2=$I27,$3=VSS,$4=VDD); subcircuit INV2 $10 (OUT=$I27,$2=VSS,$3=VDD);
end; end;
END END
assert_equal(l2n.probe_net(rmetal2, RBA::DPoint::new(0.0, 1.8)).to_s, "RINGO:FB") assert_equal(l2n.probe_net(rmetal2, RBA::DPoint::new(0.0, 1.8)).to_s, "RINGO:FB,OSC")
sc_path = []
assert_equal(l2n.probe_net(rmetal2, RBA::DPoint::new(0.0, 1.8), sc_path).to_s, "RINGO:FB,OSC")
assert_equal(sc_path.size, 0)
assert_equal(l2n.probe_net(rmetal2, RBA::DPoint::new(-2.0, 1.8)).inspect, "nil") assert_equal(l2n.probe_net(rmetal2, RBA::DPoint::new(-2.0, 1.8)).inspect, "nil")
n = l2n.probe_net(rmetal1, RBA::Point::new(2600, 1000)) n = l2n.probe_net(rmetal1, RBA::Point::new(2600, 1000), nil)
assert_equal(n.to_s, "RINGO:$I20") assert_equal(n.to_s, "INV2:$2")
sc_path = []
n = l2n.probe_net(rmetal1, RBA::Point::new(2600, 1000), sc_path)
assert_equal(n.to_s, "INV2:$2")
assert_equal(sc_path.size, 1)
assert_equal(sc_path.collect(&:expanded_name).join(","), "$2")
assert_equal(sc_path.collect(&:trans).inject(&:*).to_s, "r0 *1 2.64,0")
assert_equal(l2n.shapes_of_net(n, rmetal1, true).to_s, "(1660,-420;1660,2420;2020,2420;2020,-420);(1840,820;1840,1180;3220,1180;3220,820);(1660,2420;1660,3180;2020,3180;2020,2420);(1660,-380;1660,380;2020,380;2020,-380)") assert_equal(l2n.shapes_of_net(n, rmetal1, true).to_s,
"(-980,-420;-980,2420;-620,2420;-620,-420);(-800,820;-800,1180;580,1180;580,820);(-980,2420;-980,3180;-620,3180;-620,2420);(-980,-380;-980,380;-620,380;-620,-380)")
shapes = RBA::Shapes::new shapes = RBA::Shapes::new
l2n.shapes_of_net(n, rmetal1, true, shapes) l2n.shapes_of_net(n, rmetal1, true, shapes)
r = RBA::Region::new r = RBA::Region::new
shapes.each { |s| r.insert(s.polygon) } shapes.each { |s| r.insert(s.polygon) }
assert_equal(r.to_s, "(1660,-420;1660,2420;2020,2420;2020,-420);(1840,820;1840,1180;3220,1180;3220,820);(1660,2420;1660,3180;2020,3180;2020,2420);(1660,-380;1660,380;2020,380;2020,-380)") assert_equal(r.to_s,
"(-980,-420;-980,2420;-620,2420;-620,-420);(-800,820;-800,1180;580,1180;580,820);(-980,2420;-980,3180;-620,3180;-620,2420);(-980,-380;-980,380;-620,380;-620,-380)")
end end