mirror of https://github.com/KLayout/klayout.git
Fixed #807 - now supporting incremental connect and clear_connections in DRC/LVS
This commit is contained in:
parent
58afc47071
commit
1c8442f485
|
|
@ -246,11 +246,21 @@ void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, co
|
|||
extractor.extract (dss (), m_layout_index, layers, *mp_netlist, m_net_clusters, m_device_scaling);
|
||||
}
|
||||
|
||||
void LayoutToNetlist::connect (const db::Region &l)
|
||||
void LayoutToNetlist::reset_extracted ()
|
||||
{
|
||||
if (m_netlist_extracted) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
||||
|
||||
m_net_clusters.clear ();
|
||||
mp_netlist.reset (0);
|
||||
|
||||
m_netlist_extracted = false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlist::connect (const db::Region &l)
|
||||
{
|
||||
reset_extracted ();
|
||||
|
||||
if (! is_persisted (l)) {
|
||||
register_layer (l, make_new_name ());
|
||||
|
|
@ -265,9 +275,8 @@ void LayoutToNetlist::connect (const db::Region &l)
|
|||
|
||||
void LayoutToNetlist::connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b)
|
||||
{
|
||||
if (m_netlist_extracted) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
||||
}
|
||||
reset_extracted ();
|
||||
|
||||
if (! is_persisted (a)) {
|
||||
register_layer (a, make_new_name ());
|
||||
}
|
||||
|
|
@ -286,9 +295,8 @@ void LayoutToNetlist::connect_impl (const db::ShapeCollection &a, const db::Shap
|
|||
|
||||
size_t LayoutToNetlist::connect_global_impl (const db::ShapeCollection &l, const std::string &gn)
|
||||
{
|
||||
if (m_netlist_extracted) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
||||
}
|
||||
reset_extracted ();
|
||||
|
||||
if (! is_persisted (l)) {
|
||||
register_layer (l, make_new_name ());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -359,6 +359,14 @@ public:
|
|||
*/
|
||||
void extract_devices (db::NetlistDeviceExtractor &extractor, const std::map<std::string, db::ShapeCollection *> &layers);
|
||||
|
||||
/**
|
||||
* @brief Resets the extracted netlist
|
||||
*
|
||||
* This method will invalidate the netlist and extraction. It is called automatically when
|
||||
* cone of the connect methods is called.
|
||||
*/
|
||||
void reset_extracted ();
|
||||
|
||||
/**
|
||||
* @brief Defines an intra-layer connection for the given layer.
|
||||
* The layer is either an original layer created with "make_layer" and it's variants or
|
||||
|
|
@ -532,6 +540,14 @@ public:
|
|||
*/
|
||||
void set_netlist_extracted ();
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the netlist has been extracted
|
||||
*/
|
||||
bool is_netlist_extracted () const
|
||||
{
|
||||
return m_netlist_extracted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the internal DeepShapeStore object
|
||||
*
|
||||
|
|
|
|||
|
|
@ -394,6 +394,18 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
"\n"
|
||||
"If errors occur, the device extractor will contain theses errors.\n"
|
||||
) +
|
||||
gsi::method ("reset_extracted", &db::LayoutToNetlist::reset_extracted,
|
||||
"@brief Resets the extracted netlist and enables re-extraction\n"
|
||||
"This method is implicitly called when using \\connect or \\connect_global after a netlist has been extracted.\n"
|
||||
"This enables incremental connect with re-extraction.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.1.\n"
|
||||
) +
|
||||
gsi::method ("is_extracted?", &db::LayoutToNetlist::is_netlist_extracted,
|
||||
"@brief Gets a value indicating whether the netlist has been extracted\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.1.\n"
|
||||
) +
|
||||
gsi::method ("connect", (void (db::LayoutToNetlist::*) (const db::Region &)) &db::LayoutToNetlist::connect, gsi::arg ("l"),
|
||||
"@brief Defines an intra-layer connection for the given layer.\n"
|
||||
"The layer is either an original layer created with \\make_incluidelayer and it's variants or\n"
|
||||
|
|
|
|||
|
|
@ -64,7 +64,6 @@ module DRC
|
|||
|
||||
def initialize(engine)
|
||||
@engine = engine
|
||||
@netlisted = false
|
||||
@connect_implicit = []
|
||||
@connect_implicit_per_cell = {}
|
||||
@connect_explicit = []
|
||||
|
|
@ -240,7 +239,6 @@ module DRC
|
|||
# See \connect for more details.
|
||||
|
||||
def clear_connections
|
||||
@netlisted = false
|
||||
@connect_implicit = []
|
||||
@connect_implicit_per_cell = {}
|
||||
@connect_explicit = []
|
||||
|
|
@ -544,7 +542,7 @@ module DRC
|
|||
ensure_data
|
||||
|
||||
# run extraction in a timed environment
|
||||
if ! @netlisted
|
||||
if ! @l2n.is_extracted?
|
||||
|
||||
# configure implicit net connections
|
||||
@l2n.clear_join_net_names
|
||||
|
|
@ -569,7 +567,6 @@ module DRC
|
|||
end
|
||||
|
||||
@engine._cmd(@l2n, :extract_netlist)
|
||||
@netlisted = true
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -609,13 +606,13 @@ module DRC
|
|||
end
|
||||
|
||||
def _l2n_data
|
||||
@netlisted && self.l2n_data
|
||||
@l2n && @l2n.is_extracted? && self.l2n_data
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def cleanup
|
||||
@netlisted && clear_connections
|
||||
@l2n && @l2n.is_extracted? && clear_connections
|
||||
end
|
||||
|
||||
def ensure_data
|
||||
|
|
@ -644,14 +641,13 @@ module DRC
|
|||
def register_layer(data)
|
||||
|
||||
id = data.data_id
|
||||
ensure_data
|
||||
|
||||
if @layers && @layers[id]
|
||||
# already registered
|
||||
return
|
||||
end
|
||||
|
||||
ensure_data
|
||||
|
||||
@layers[id] = data
|
||||
@lnum += 1
|
||||
|
||||
|
|
|
|||
|
|
@ -225,6 +225,46 @@ TEST(5_FlatAntenna)
|
|||
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
||||
TEST(5_FlatAntennaIncremental)
|
||||
{
|
||||
std::string rs = tl::testdata ();
|
||||
rs += "/drc/drcSimpleTests_5i.drc";
|
||||
|
||||
std::string input = tl::testdata ();
|
||||
input += "/drc/antenna_l1.gds";
|
||||
|
||||
std::string au = tl::testdata ();
|
||||
au += "/drc/drcSimpleTests_au5.gds";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.gds");
|
||||
|
||||
{
|
||||
// Set some variables
|
||||
lym::Macro config;
|
||||
config.set_text (tl::sprintf (
|
||||
"$drc_test_source = '%s'\n"
|
||||
"$drc_test_target = '%s'\n"
|
||||
, input, output)
|
||||
);
|
||||
config.set_interpreter (lym::Macro::Ruby);
|
||||
EXPECT_EQ (config.run (), 0);
|
||||
}
|
||||
|
||||
lym::Macro drc;
|
||||
drc.load_from (rs);
|
||||
EXPECT_EQ (drc.run (), 0);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
||||
TEST(6_HierarchicalAntenna)
|
||||
{
|
||||
std::string rs = tl::testdata ();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
# Hierarchical antenna check
|
||||
# Flat antenna check
|
||||
|
||||
source($drc_test_source, "RINGO")
|
||||
target($drc_test_target)
|
||||
|
|
@ -14,6 +14,17 @@ metal2 = input(8, 0)
|
|||
|
||||
gate = diff & poly
|
||||
|
||||
connect(gate, poly)
|
||||
connect(poly, poly_cont)
|
||||
connect(poly_cont, metal1)
|
||||
|
||||
antenna_check(gate, metal1, 1.0).output(201)
|
||||
antenna_check(gate, metal1, 2.0).output(202)
|
||||
antenna_check(gate, metal1, 3.0).output(203)
|
||||
antenna_check(gate, metal1, 4.0).output(204)
|
||||
|
||||
clear_connections
|
||||
|
||||
connect(gate, poly)
|
||||
connect(poly, poly_cont)
|
||||
connect(poly_cont, metal1)
|
||||
|
|
@ -24,3 +35,4 @@ antenna_check(gate, metal2, 1.0).output(101)
|
|||
antenna_check(gate, metal2, 5.0).output(105)
|
||||
antenna_check(gate, metal2, 10.0).output(110)
|
||||
antenna_check(gate, metal2, 50.0).output(150)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
# Flat antenna check
|
||||
|
||||
source($drc_test_source, "RINGO")
|
||||
target($drc_test_target)
|
||||
|
||||
diff = input(2, 0)
|
||||
poly = input(3, 0)
|
||||
contact = input(4, 0)
|
||||
poly_cont = input(5, 0)
|
||||
metal1 = input(6, 0)
|
||||
via1 = input(7, 0)
|
||||
metal2 = input(8, 0)
|
||||
|
||||
gate = diff & poly
|
||||
|
||||
connect(gate, poly)
|
||||
connect(poly, poly_cont)
|
||||
connect(poly_cont, metal1)
|
||||
|
||||
antenna_check(gate, metal1, 1.0).output(201)
|
||||
antenna_check(gate, metal1, 2.0).output(202)
|
||||
antenna_check(gate, metal1, 3.0).output(203)
|
||||
antenna_check(gate, metal1, 4.0).output(204)
|
||||
|
||||
connect(metal1, via1)
|
||||
connect(via1, metal2)
|
||||
|
||||
antenna_check(gate, metal2, 1.0).output(101)
|
||||
antenna_check(gate, metal2, 5.0).output(105)
|
||||
antenna_check(gate, metal2, 10.0).output(110)
|
||||
antenna_check(gate, metal2, 50.0).output(150)
|
||||
|
||||
Binary file not shown.
|
|
@ -576,6 +576,54 @@ end;
|
|||
self.assertEqual(str(a1_10.flatten() ^ pya.Region(ly_au.top_cell().begin_shapes_rec(ly_au.layer(101, 0)))), "")
|
||||
self.assertEqual(str(a1_30.flatten() ^ pya.Region(ly_au.top_cell().begin_shapes_rec(ly_au.layer(102, 0)))), "")
|
||||
|
||||
# --- simple incremental antenna check with metal1 + metal2
|
||||
|
||||
l2n._destroy()
|
||||
l2n = pya.LayoutToNetlist(dss)
|
||||
|
||||
l2n.register(rdiode, "diode")
|
||||
l2n.register(rpoly, "poly")
|
||||
l2n.register(rcont, "cont")
|
||||
l2n.register(rmetal1, "metal1")
|
||||
l2n.register(rvia1, "via1")
|
||||
l2n.register(rmetal2, "metal2")
|
||||
|
||||
l2n.connect(rpoly)
|
||||
l2n.connect(rcont)
|
||||
l2n.connect(rmetal1)
|
||||
l2n.connect(rmetal2)
|
||||
l2n.connect(rpoly, rcont)
|
||||
l2n.connect(rcont, rmetal1)
|
||||
|
||||
self.assertEqual(l2n.is_extracted(), False)
|
||||
l2n.extract_netlist()
|
||||
self.assertEqual(l2n.is_extracted(), True)
|
||||
|
||||
a1_3 = l2n.antenna_check(rpoly, rmetal1, 3)
|
||||
a1_10 = l2n.antenna_check(rpoly, rmetal1, 10)
|
||||
a1_30 = l2n.antenna_check(rpoly, rmetal1, 30)
|
||||
|
||||
# Note: flatten.merged performs some normalization
|
||||
self.assertEqual(str(a1_3.flatten() ^ pya.Region(ly_au.top_cell().begin_shapes_rec(ly_au.layer(100, 0)))), "")
|
||||
self.assertEqual(str(a1_10.flatten() ^ pya.Region(ly_au.top_cell().begin_shapes_rec(ly_au.layer(101, 0)))), "")
|
||||
self.assertEqual(str(a1_30.flatten() ^ pya.Region(ly_au.top_cell().begin_shapes_rec(ly_au.layer(102, 0)))), "")
|
||||
|
||||
l2n.connect(rmetal1, rvia1)
|
||||
l2n.connect(rvia1, rmetal2)
|
||||
|
||||
self.assertEqual(l2n.is_extracted(), False)
|
||||
l2n.extract_netlist()
|
||||
self.assertEqual(l2n.is_extracted(), True)
|
||||
|
||||
a2_5 = l2n.antenna_check(rpoly, rmetal2, 5)
|
||||
a2_10 = l2n.antenna_check(rpoly, rmetal2, 10)
|
||||
a2_17 = l2n.antenna_check(rpoly, rmetal2, 17)
|
||||
|
||||
# Note: flatten.merged performs some normalization
|
||||
self.assertEqual(str(a2_5.flatten() ^ pya.Region(ly_au.top_cell().begin_shapes_rec(ly_au.layer(200, 0)))), "")
|
||||
self.assertEqual(str(a2_10.flatten() ^ pya.Region(ly_au.top_cell().begin_shapes_rec(ly_au.layer(201, 0)))), "")
|
||||
self.assertEqual(str(a2_17.flatten() ^ pya.Region(ly_au.top_cell().begin_shapes_rec(ly_au.layer(202, 0)))), "")
|
||||
|
||||
# --- simple antenna check with metal2
|
||||
|
||||
l2n._destroy()
|
||||
|
|
|
|||
|
|
@ -170,7 +170,8 @@ class DBLayoutToNetlist_TestClass < TestBase
|
|||
# Perform netlist extraction
|
||||
l2n.extract_netlist
|
||||
|
||||
assert_equal(l2n.netlist.to_s, <<END)
|
||||
nl_string = l2n.netlist.to_s
|
||||
assert_equal(nl_string, <<END)
|
||||
circuit TRANS ($1=$1,$2=$2);
|
||||
end;
|
||||
circuit INV2 (OUT=OUT,$2=$3,$3=$4);
|
||||
|
|
@ -218,6 +219,15 @@ END
|
|||
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)")
|
||||
|
||||
assert_equal(l2n.is_extracted?, true)
|
||||
l2n.reset_extracted
|
||||
assert_equal(l2n.is_extracted?, false)
|
||||
assert_equal(l2n.netlist.inspect, "nil")
|
||||
|
||||
l2n.extract_netlist
|
||||
assert_equal(l2n.is_extracted?, true)
|
||||
assert_equal(l2n.netlist.to_s, nl_string)
|
||||
|
||||
end
|
||||
|
||||
def test_10_LayoutToNetlistExtractionWithoutDevices
|
||||
|
|
@ -755,6 +765,54 @@ END
|
|||
assert_equal((a2_10.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(201, 0)))).to_s, "")
|
||||
assert_equal((a2_17.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(202, 0)))).to_s, "")
|
||||
|
||||
# --- simple incremental antenna check with metal1 + metal2
|
||||
|
||||
l2n._destroy
|
||||
l2n = RBA::LayoutToNetlist::new(dss)
|
||||
|
||||
l2n.register(rdiode, "diode")
|
||||
l2n.register(rpoly, "poly")
|
||||
l2n.register(rcont, "cont")
|
||||
l2n.register(rmetal1, "metal1")
|
||||
l2n.register(rvia1, "via1")
|
||||
l2n.register(rmetal2, "metal2")
|
||||
|
||||
l2n.connect(rpoly)
|
||||
l2n.connect(rcont)
|
||||
l2n.connect(rmetal1)
|
||||
l2n.connect(rmetal2)
|
||||
l2n.connect(rpoly, rcont)
|
||||
l2n.connect(rcont, rmetal1)
|
||||
|
||||
assert_equal(l2n.is_extracted?, false)
|
||||
l2n.extract_netlist
|
||||
assert_equal(l2n.is_extracted?, true)
|
||||
|
||||
a1_3 = l2n.antenna_check(rpoly, rmetal1, 3)
|
||||
a1_10 = l2n.antenna_check(rpoly, rmetal1, 10)
|
||||
a1_30 = l2n.antenna_check(rpoly, rmetal1, 30)
|
||||
|
||||
# Note: flatten.merged performs some normalization
|
||||
assert_equal((a1_3.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(100, 0)))).to_s, "")
|
||||
assert_equal((a1_10.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(101, 0)))).to_s, "")
|
||||
assert_equal((a1_30.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(102, 0)))).to_s, "")
|
||||
|
||||
l2n.connect(rmetal1, rvia1)
|
||||
l2n.connect(rvia1, rmetal2)
|
||||
|
||||
assert_equal(l2n.is_extracted?, false)
|
||||
l2n.extract_netlist
|
||||
assert_equal(l2n.is_extracted?, true)
|
||||
|
||||
a2_5 = l2n.antenna_check(rpoly, rmetal2, 5)
|
||||
a2_10 = l2n.antenna_check(rpoly, rmetal2, 10)
|
||||
a2_17 = l2n.antenna_check(rpoly, rmetal2, 17)
|
||||
|
||||
# Note: flatten.merged performs some normalization
|
||||
assert_equal((a2_5.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(200, 0)))).to_s, "")
|
||||
assert_equal((a2_10.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(201, 0)))).to_s, "")
|
||||
assert_equal((a2_17.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(202, 0)))).to_s, "")
|
||||
|
||||
# --- antenna check with diodes and antenna effect reduction
|
||||
|
||||
l2n._destroy
|
||||
|
|
|
|||
Loading…
Reference in New Issue