From c684633dd6972c7c4861c0dcac4dc4733616b4d5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 31 May 2019 00:11:28 +0200 Subject: [PATCH] Some enhancements for netlist extraction and writer * Spice writer can now be configure to skip the debug comments * < and > are allowed chars in spice names now * global net names have second prio over labels now --- src/db/db/dbNetlistExtractor.cc | 49 +++++++++++------- src/db/db/dbNetlistExtractor.h | 6 ++- src/db/db/dbNetlistSpiceWriter.cc | 33 +++++++----- src/db/db/dbNetlistSpiceWriter.h | 7 +++ src/db/db/gsiDeclDbNetlist.cc | 9 +++- src/db/unit_tests/dbLayoutToNetlistTests.cc | 42 +++++++-------- testdata/algo/device_extract_au1_flat.gds | Bin 78534 -> 78534 bytes .../algo/device_extract_au1_implicit_nets.gds | Bin 9160 -> 9160 bytes .../algo/device_extract_au3_with_rec_nets.gds | Bin 46986 -> 46966 bytes .../algo/device_extract_au4_with_rec_nets.gds | Bin 49546 -> 49526 bytes .../algo/device_extract_au5_with_rec_nets.gds | Bin 70690 -> 70670 bytes testdata/algo/l2n_reader_au_2.gds | Bin 25788 -> 25780 bytes testdata/algo/l2n_writer_au_2.gds | Bin 29606 -> 27126 bytes testdata/algo/l2n_writer_au_2.txt | 4 +- testdata/algo/l2n_writer_au_2_abs.txt | 4 +- testdata/algo/l2n_writer_au_2s.txt | 4 +- testdata/algo/lvs_test1_au.lvsdb | 8 +-- testdata/algo/lvs_test1b_au.lvsdb | 8 +-- testdata/algo/lvs_test2_au.lvsdb | 4 +- testdata/algo/lvs_test2b_au.lvsdb | 4 +- testdata/python/dbLayoutToNetlist.py | 22 ++++---- testdata/ruby/dbLayoutToNetlist.rb | 22 ++++---- 22 files changed, 131 insertions(+), 95 deletions(-) diff --git a/src/db/db/dbNetlistExtractor.cc b/src/db/db/dbNetlistExtractor.cc index 4ae5449da..81e6ac0db 100644 --- a/src/db/db/dbNetlistExtractor.cc +++ b/src/db/db/dbNetlistExtractor.cc @@ -142,11 +142,6 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo net->set_cluster_id (*c); circuit->add_net (net); - const db::local_cluster::global_nets &gn = lc.get_global_nets (); - for (db::local_cluster::global_nets::const_iterator g = gn.begin (); g != gn.end (); ++g) { - assign_net_name (conn.global_net_name (*g), net); - } - // make subcircuit connections (also make the subcircuits if required) from the connections of the clusters make_and_connect_subcircuits (circuit, clusters, *c, net, subcircuits, circuits, pins_per_cluster_per_cell); @@ -154,7 +149,18 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo connect_devices (circuit, clusters, *c, net); // collect labels to net names - collect_labels (clusters, *c, net); + std::set net_names; + collect_labels (clusters, *c, net_names); + + // add the global names as second priority + if (net_names.empty ()) { + const db::local_cluster::global_nets &gn = lc.get_global_nets (); + for (db::local_cluster::global_nets::const_iterator g = gn.begin (); g != gn.end (); ++g) { + net_names.insert (conn.global_net_name (*g)); + } + } + + assign_net_names (net, net_names); if (! clusters.is_root (*c)) { // a non-root cluster makes a pin @@ -167,6 +173,22 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo } } +void +NetlistExtractor::assign_net_names (db::Net *net, const std::set &net_names) +{ + std::string nn; + for (std::set::const_iterator n = net_names.begin (); n != net_names.end (); ++n) { + if (! n->empty ()) { + if (! nn.empty ()) { + nn += ","; + } + nn += *n; + } + } + + net->set_name (nn); +} + void NetlistExtractor::make_device_abstract_connections (db::DeviceAbstract *dm, const connected_clusters_type &clusters) { @@ -194,7 +216,7 @@ NetlistExtractor::make_device_abstract_connections (db::DeviceAbstract *dm, cons void NetlistExtractor::collect_labels (const connected_clusters_type &clusters, size_t cid, - db::Net *net) + std::set &net_names) { // collect the properties - we know that the cluster attributes are property ID's because the // cluster processor converts shape property IDs to attributes @@ -206,7 +228,7 @@ void NetlistExtractor::collect_labels (const connected_clusters_type &clusters, for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) { if (m_text_annot_name_id.first && j->first == m_text_annot_name_id.second) { - assign_net_name (j->second.to_string (), net); + net_names.insert (j->second.to_string ()); } } @@ -348,15 +370,4 @@ size_t NetlistExtractor::make_pin (db::Circuit *circuit, db::Net *net) return pin_id; } -void NetlistExtractor::assign_net_name (const std::string &n, db::Net *net) -{ - std::string nn = n; - if (! nn.empty ()) { - if (! net->name ().empty ()) { - nn = net->name () + "," + nn; - } - net->set_name (nn); - } -} - } diff --git a/src/db/db/dbNetlistExtractor.h b/src/db/db/dbNetlistExtractor.h index 6eba650f2..d1504f1d3 100644 --- a/src/db/db/dbNetlistExtractor.h +++ b/src/db/db/dbNetlistExtractor.h @@ -27,6 +27,8 @@ #include "dbHierNetworkProcessor.h" #include +#include +#include namespace db { @@ -92,9 +94,9 @@ private: std::pair m_device_annot_name_id; std::pair m_terminal_annot_name_id; - void assign_net_name (const std::string &n, db::Net *net); bool instance_is_device (db::properties_id_type prop_id) const; db::Device *device_from_instance (db::properties_id_type prop_id, db::Circuit *circuit) const; + void assign_net_names (db::Net *net, const std::set &net_names); /** * @brief Make a pin connection from clusters @@ -151,7 +153,7 @@ private: */ void collect_labels (const connected_clusters_type &clusters, size_t cid, - db::Net *net); + std::set &net_names); /** * @brief Makes the terminal to cluster ID connections of the device abstract diff --git a/src/db/db/dbNetlistSpiceWriter.cc b/src/db/db/dbNetlistSpiceWriter.cc index 3b38ed3f1..6efb0c1ef 100644 --- a/src/db/db/dbNetlistSpiceWriter.cc +++ b/src/db/db/dbNetlistSpiceWriter.cc @@ -31,7 +31,7 @@ namespace db { -static const char *allowed_name_chars = "_.:,!+$/&\\#[]"; +static const char *allowed_name_chars = "_.:,!+$/&\\#[]<>"; static const char *not_connect_prefix = "nc_"; // -------------------------------------------------------------------------------- @@ -197,7 +197,7 @@ std::string NetlistSpiceWriterDelegate::format_params (const db::Device &dev) co // -------------------------------------------------------------------------------- NetlistSpiceWriter::NetlistSpiceWriter (NetlistSpiceWriterDelegate *delegate) - : mp_netlist (0), mp_stream (0), mp_delegate (delegate), m_next_net_id (0), m_use_net_names (false) + : mp_netlist (0), mp_stream (0), mp_delegate (delegate), m_next_net_id (0), m_use_net_names (false), m_with_comments (true) { static NetlistSpiceWriterDelegate std_delegate; if (! delegate) { @@ -215,6 +215,11 @@ void NetlistSpiceWriter::set_use_net_names (bool use_net_names) m_use_net_names = use_net_names; } +void NetlistSpiceWriter::set_with_comments (bool with_comments) +{ + m_with_comments = with_comments; +} + void NetlistSpiceWriter::write (tl::OutputStream &stream, const db::Netlist &netlist, const std::string &description) { mp_stream = &stream; @@ -395,9 +400,10 @@ void NetlistSpiceWriter::do_write (const std::string &description) for (db::Circuit::const_device_iterator i = circuit.begin_devices (); i != circuit.end_devices (); ++i) { - // TODO: make this configurable? - std::string comment = "device instance " + i->expanded_name () + " " + i->trans ().to_string () + " " + i->device_class ()->name (); - emit_comment (comment); + if (m_with_comments) { + std::string comment = "device instance " + i->expanded_name () + " " + i->trans ().to_string () + " " + i->device_class ()->name (); + emit_comment (comment); + } mp_delegate->write_device (*i); @@ -410,9 +416,10 @@ void NetlistSpiceWriter::do_write (const std::string &description) void NetlistSpiceWriter::write_subcircuit_call (const db::SubCircuit &subcircuit) const { - // TODO: make this configurable? - std::string comment = "cell instance " + subcircuit.expanded_name() + " " + subcircuit.trans ().to_string (); - emit_comment (comment); + if (m_with_comments) { + std::string comment = "cell instance " + subcircuit.expanded_name() + " " + subcircuit.trans ().to_string (); + emit_comment (comment); + } std::ostringstream os; os << "X"; @@ -433,9 +440,11 @@ void NetlistSpiceWriter::write_circuit_header (const db::Circuit &circuit) const { emit_line (""); - emit_comment ("cell " + circuit.name ()); - for (db::Circuit::const_pin_iterator p = circuit.begin_pins (); p != circuit.end_pins (); ++p) { - emit_comment ("pin " + p->name ()); + if (m_with_comments) { + emit_comment ("cell " + circuit.name ()); + for (db::Circuit::const_pin_iterator p = circuit.begin_pins (); p != circuit.end_pins (); ++p) { + emit_comment ("pin " + p->name ()); + } } std::ostringstream os; @@ -450,7 +459,7 @@ void NetlistSpiceWriter::write_circuit_header (const db::Circuit &circuit) const emit_line (os.str ()); - if (! m_use_net_names) { + if (! m_use_net_names && m_with_comments) { for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) { if (! n->name ().empty ()) { emit_comment ("net " + net_to_string (n.operator-> ()) + " " + n->name ()); diff --git a/src/db/db/dbNetlistSpiceWriter.h b/src/db/db/dbNetlistSpiceWriter.h index 13f6c4546..503ca6352 100644 --- a/src/db/db/dbNetlistSpiceWriter.h +++ b/src/db/db/dbNetlistSpiceWriter.h @@ -92,6 +92,12 @@ public: return m_use_net_names; } + void set_with_comments (bool f); + bool with_comments () const + { + return m_with_comments; + } + private: friend class NetlistSpiceWriterDelegate; @@ -101,6 +107,7 @@ private: std::map m_net_to_spice_id; mutable size_t m_next_net_id; bool m_use_net_names; + bool m_with_comments; void do_write (const std::string &description); diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index c114a1d3d..e7cb9ab40 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -1544,8 +1544,15 @@ Class db_NetlistSpiceWriter (db_NetlistWriter, "db", "Ne "@brief Sets a value indicating whether to use net names (true) or net numbers (false).\n" "The default is to use net numbers." ) + - gsi::method ("use_net_names", &db::NetlistSpiceWriter::use_net_names, + gsi::method ("use_net_names?", &db::NetlistSpiceWriter::use_net_names, "@brief Gets a value indicating whether to use net names (true) or net numbers (false).\n" + ) + + gsi::method ("with_comments=", &db::NetlistSpiceWriter::set_with_comments, gsi::arg ("f"), + "@brief Sets a value indicating whether to embed comments for position etc. (true) or not (false).\n" + "The default is to embed comments." + ) + + gsi::method ("with_comments?", &db::NetlistSpiceWriter::with_comments, + "@brief Gets a value indicating whether to embed comments for position etc. (true) or not (false).\n" ), "@brief Implements a netlist writer for the SPICE format.\n" "Provide a delegate for customizing the way devices are written.\n" diff --git a/src/db/unit_tests/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc index 1c9bdc953..9cf89998a 100644 --- a/src/db/unit_tests/dbLayoutToNetlistTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistTests.cc @@ -1070,7 +1070,7 @@ TEST(3_GlobalNetConnections) EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::DPoint (-2.0, 1.8))), "(null)"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (-1.5, 1.8))), "RINGO:FB"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (24.5, 1.8))), "RINGO:OSC"); - EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "RINGO:BULK,VSS"); + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "RINGO:VSS"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "RINGO:$I22"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "INV2PAIR:$I4"); @@ -1085,12 +1085,12 @@ TEST(3_GlobalNetConnections) // compare netlist as string CHECKPOINT (); db::compare_netlist (_this, *l2n.netlist (), - "circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,'BULK,VSS'='BULK,VSS');\n" - " subcircuit INV2PAIR $1 (BULK='BULK,VSS',$2=FB,$3=VDD,$4='BULK,VSS',$5=$I7,$6=OSC,$7=VDD);\n" - " subcircuit INV2PAIR $2 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=FB,$6=$I13,$7=VDD);\n" - " subcircuit INV2PAIR $3 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I13,$6=$I5,$7=VDD);\n" - " subcircuit INV2PAIR $4 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I5,$6=$I6,$7=VDD);\n" - " subcircuit INV2PAIR $5 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I6,$6=$I7,$7=VDD);\n" + "circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,VSS=VSS);\n" + " subcircuit INV2PAIR $1 (BULK=VSS,$2=FB,$3=VDD,$4=VSS,$5=$I7,$6=OSC,$7=VDD);\n" + " subcircuit INV2PAIR $2 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=FB,$6=$I13,$7=VDD);\n" + " subcircuit INV2PAIR $3 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I13,$6=$I5,$7=VDD);\n" + " subcircuit INV2PAIR $4 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I5,$6=$I6,$7=VDD);\n" + " subcircuit INV2PAIR $5 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I6,$6=$I7,$7=VDD);\n" "end;\n" "circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1);\n" " subcircuit INV2 $1 ($1=$I1,IN=$I3,$3=(null),OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);\n" @@ -1357,7 +1357,7 @@ TEST(4_GlobalNetDeviceExtraction) EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::DPoint (-2.0, 1.8))), "(null)"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (-1.5, 1.8))), "RINGO:FB"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (24.5, 1.8))), "RINGO:OSC"); - EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "RINGO:BULK,VSS"); + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "RINGO:VSS"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "RINGO:$I22"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "INV2PAIR:$I4"); @@ -1372,12 +1372,12 @@ TEST(4_GlobalNetDeviceExtraction) // compare netlist as string CHECKPOINT (); db::compare_netlist (_this, *l2n.netlist (), - "circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,'BULK,VSS'='BULK,VSS');\n" - " subcircuit INV2PAIR $1 (BULK='BULK,VSS',$2=FB,$3=VDD,$4='BULK,VSS',$5=$I7,$6=OSC,$7=VDD);\n" - " subcircuit INV2PAIR $2 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=FB,$6=$I13,$7=VDD);\n" - " subcircuit INV2PAIR $3 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I13,$6=$I5,$7=VDD);\n" - " subcircuit INV2PAIR $4 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I5,$6=$I6,$7=VDD);\n" - " subcircuit INV2PAIR $5 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I6,$6=$I7,$7=VDD);\n" + "circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,VSS=VSS);\n" + " subcircuit INV2PAIR $1 (BULK=VSS,$2=FB,$3=VDD,$4=VSS,$5=$I7,$6=OSC,$7=VDD);\n" + " subcircuit INV2PAIR $2 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=FB,$6=$I13,$7=VDD);\n" + " subcircuit INV2PAIR $3 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I13,$6=$I5,$7=VDD);\n" + " subcircuit INV2PAIR $4 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I5,$6=$I6,$7=VDD);\n" + " subcircuit INV2PAIR $5 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I6,$6=$I7,$7=VDD);\n" "end;\n" "circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1);\n" " subcircuit INV2 $1 ($1=$I1,IN=$I3,$3=(null),OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);\n" @@ -1644,7 +1644,7 @@ TEST(5_DeviceExtractionWithDeviceCombination) EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::DPoint (-2.0, 1.8))), "(null)"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (-1.5, 1.8))), "RINGO:FB"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (24.5, 1.8))), "RINGO:OSC"); - EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "RINGO:BULK,VSS"); + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "RINGO:VSS"); // doesn't do anything here, but we test that this does not destroy anything: l2n.netlist ()->combine_devices (); @@ -1656,12 +1656,12 @@ TEST(5_DeviceExtractionWithDeviceCombination) // compare netlist as string CHECKPOINT (); db::compare_netlist (_this, *l2n.netlist (), - "circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,'BULK,VSS'='BULK,VSS');\n" - " subcircuit INV2PAIR $1 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=FB,$5=$I7,$6=OSC,$7=VDD);\n" - " subcircuit INV2PAIR $2 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=(null),$5=FB,$6=$I13,$7=VDD);\n" - " subcircuit INV2PAIR $3 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=(null),$5=$I13,$6=$I5,$7=VDD);\n" - " subcircuit INV2PAIR $4 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=(null),$5=$I5,$6=$I6,$7=VDD);\n" - " subcircuit INV2PAIR $5 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=(null),$5=$I6,$6=$I7,$7=VDD);\n" + "circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,VSS=VSS);\n" + " subcircuit INV2PAIR $1 (BULK=VSS,$2=VDD,$3=VSS,$4=FB,$5=$I7,$6=OSC,$7=VDD);\n" + " subcircuit INV2PAIR $2 (BULK=VSS,$2=VDD,$3=VSS,$4=(null),$5=FB,$6=$I13,$7=VDD);\n" + " subcircuit INV2PAIR $3 (BULK=VSS,$2=VDD,$3=VSS,$4=(null),$5=$I13,$6=$I5,$7=VDD);\n" + " subcircuit INV2PAIR $4 (BULK=VSS,$2=VDD,$3=VSS,$4=(null),$5=$I5,$6=$I6,$7=VDD);\n" + " subcircuit INV2PAIR $5 (BULK=VSS,$2=VDD,$3=VSS,$4=(null),$5=$I6,$6=$I7,$7=VDD);\n" "end;\n" "circuit INV2PAIR (BULK=BULK,$2=$I6,$3=$I5,$4=$I4,$5=$I3,$6=$I2,$7=$I1);\n" " subcircuit INV2 $1 ($1=$I1,IN=$I3,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);\n" diff --git a/testdata/algo/device_extract_au1_flat.gds b/testdata/algo/device_extract_au1_flat.gds index 1dc09360f3a9067942bd0a5ebeb10323bd831ad2..0c65698c9d6cf80e3e03f86bb8a84cc2f98661fb 100644 GIT binary patch delta 1692 zcmZ`%Ur19?9KL7HjV%A=bvm2dbpD-lPQ@S*kyVP?wwhPS$V@>_w)!$Q}! zkz#A=uMCeSHXW&drwo(nL|HHp>VeNz85V9X3pzw5HwBeTQ}0t(mcr8q(oFyV(7_p3 z`riM2b=m^=XPV&GObeWf*};oLo3X=a%x*aS6MQinJc_lztynhX&N(4>wjPFNo#4kY zF?$gVxPF4f$p2nT<1IHMSH?$_4 z5X6x{>`geA5{dT6vV4$@Gp=Q@HZEu4q#nXa%Ve!QoW=ZH(YY)(&NV8?*(4!OAtYy^ z?oKx9w8Oa7a&Ws&TbZ_U4(SM~gw$Nx>WDZ+#!1ejiI7T2p-GilBRA)=0M~Q}O2D2n0b zR_%DX^-^}7uey@)%g9$jS*uX4$FCrB8ByiQ_~n$UG8w-b`|0tklkv-u(c@Q=u$2k l^*11;;=@DqH=vzbOGnZh_)w(3K`p&OJsUHbCCO-%{s9=Fp-BJ$ delta 1684 zcmZ`%QAkr^6u$pl8%gHM>ufgX+|=A$(<$~KBC^UTbJDs(Mrj2>2?aqfg%48Ja?U}W z(GR`ULqxqqF{oaOo)n@8LD)k?5LC~7=eI!*`ybBPIp24_bMAL{7gn7MtIm+& zG8~RWhF>_`UkqV*4Fj>||N43;Tw9iSe7M2aR+ceLmn*f~nn>?W?HQTan~Du4>G74i z;uGKRbTX=Cy4j^wP3_RC z&h~0mR=-v?nAECbgIZN!pH}5eebl{;Uk9|Rl~Jwg)tFZG=%`k8=lEOQW6Ye?s?MKo z@Rk3U>E5LejpaY5N|$R_b82|xAbs|k^yunI6cNYoM@9v;~E!isww#ZboIREnHbOOmHfgqFXL*7Q@nFqEN%FDc(r4 zP7KhuD7rc^ByZGkS`v2N+!!h7mPKixmsBQv#PnBE@+ zT+c9%n?5m3Q~ljCgGqWF2e*}P`LQ4t#CAX6KR&=skeCgC{gZeEbTo+|3Z#O~V9S7eC{@T7CxyXu@ULaw-<4gmF>_)a8 z=ErHpxU$~L)*~hB+%31T^%iy=+OJ*^-f647+_@`-J1373?~39>m7iVbuN_kM9De^*Q_V_b|)0ddc0(v70P;-xFBDK Sg)0JJ`5Wg|95N5MaOpY2jYH4o zZ9L^n+E@dXL5z*f&ov}I$kWf=KR(RGMF)tZCi4l1PtNBrAxckhuufQTFi1}~4kxb@ vn2SRuK@f+`W+9;$ucsrLY#9zUKPj!dS>%0`FqR&5*AhQ delta 637 zcmX@%e!^XefsKKQDS|FG`aq2d9iOIVdamZ|5 z#U#y$UDM`U%s8dESh;cO(qg-fLu#@V2M$+E=Hk4L-4T<&abCqC^MDJNo-^Dy^laY7 zQ_iG~HBcGE*x3ABL*j!x{oMWI!(3dVbb!QUJ^}H``TQkB=?M-7>In`8>gmSea}LO>f>wxJK8rfm)W#sh#unt~8WJDm>F4er z9~K-uxj}oFEe(jP4nim<8}aw{S2E=EbYb>^%*PX;*gpw zwHjAaKeHNFdY=4e&3x<*p1fi0_Q|yp?3{>jS-4JR^89rvlkcwMpX?+dzFB{LGzS3C Crk@A^ delta 1124 zcmezNj;ZTClM(|P0~1pOgA5}R`(p-127U%n1`!4n_CzIRQS1^?(KsYd-Nr64c^4xt znN>`4vFq6!!z|5+L#l@br_>%+Zd|(Vu-(QXHTet&F8A%>#38eJ4Ocl64)7 z%j7?rIHm6C;gmXHd>)s9ODyi=lA2+QQ>w=ar&NRceHI<8sf|H`jV;K}H6%XB)6d;M z-YL|_TPG|ycyhkJ_~to2rK&hWL#;?w1BX<^tX^guQorWTW!J{;3^6t~EUqY6Au(Al z*-Pc XO`f$_KBwd~IY9Z}u?6|LhQtSX`nmhZ zhXn^uF3=a-yvV0i3r9fcl*{VkkcwN<%Zy!W(~7z5xE+9EKf~q|>$`D9ea5D_IHV>^ zZN-(;&uqn&o+tm=HXpl#CvVukeR8b?J0~Js7Vc1)Jby>Ze*= Cv9lKd delta 1124 zcmey?#N5@)ti-^^z{C{6Aj8PS{+NN0fuBK?L4<)BnLSZSSrofOR5T8WQ@628Oy0$a zOJ)_*T|fTG>vbBc_U`IMa|Ur@4J?5E5)xlaWsu3|U&oQgRPlciM8 z;xhSPpKA;&`>Lv)x{wdv80z7ht#j-bJ?}AJ41|(4T~!ZHc3pD z%P^R{W0Sz-I3WE4NY4Y(7Mleo-viPWKw2&nC=aCLfbQxbo1Ut++DESCZ9;Z}H)_pE@tZ~mE#Kson=Nb|pSCZ9;Z}H)_pD=tZ~mE!NwNk=Nb|pGaJ%O21m*@G{eSSsNTuCa+^Ta7Zote3wrfyEDYt*f3o&eIEy- z*!BZVjHOK2P2BFq$~YH?-1I-}j5reF_H`VLxDw9vdz_5k*ln9`$Hll^NK6RbrIYIg mB&PRrGxAN>s_QwpY4Dt*NKvD*oJyA(n6uU%JA`XcQ@z^CMyD;L= zGIjPlq+9hf5gTtnhj zEGAztmz->C!oFF~kf367xZ*iRI4%8PoQca9d8XNn3fSEPOm`sngarpr4m6kFEMqPx zOhBcJ%jAV#@|$zK2&wcBb_SX$1@`2=*r~W2ml2s_QwoN49pC?3~~&t$n1$q%A(jMq7rdPT!_amG1-L? zhnC5^7;)**W5T6p2@@_o63n>t^fBYo!^DD1PX!AuJ#TR8Nn*vN=NfA)j?nR7!zHte z4VP(p>^NjLFJgbsgu|j`T<@{VY+l8!&xk|n9S<(^Hh7fdZdm0(i?P)v0~PU*;Oh_N8WgpA$%NHUjM z0=qxN*d{ZYi%hPT4Z|Khlb^}v;?^4IC9=6*E)0+1jiw@-8I|-Haht(tA~HEz*#Nus zn-?g%;) zuVOJ-!9sGftqJ>PIYWYq&EbmY7~!<^gK;JDI$^=VV2k)I z*f&d=^9$n$E;}!4TvC0p2XVO}B|aTjmVc0lD`r}fxEc8cgup=tbK>S%$x@5}E@i?G diff --git a/testdata/algo/l2n_writer_au_2.gds b/testdata/algo/l2n_writer_au_2.gds index 0ca9523ff4edfa85ea05766ef1ad79ae9762a549..aad07a026da0bb3cb3972bf452a180ba8ab76961 100644 GIT binary patch delta 2216 zcmah}Uq};i9RJ;%H=Wb%ww*h@6>c}T-KG=goSL&VHLysfiOiLV4?aZyTqQ*>MGsL% zMtol)C7~iBD5M`m^iVyPL4PO+q!jZ(dWj+oqR@VK3ihzCz1;n{&!6x2`?>Gk?M3eA zJI+gZVlbqLn=_aeNG{n-TqH~y{yksuDq?mZJ%|8r2C@Ut#vu}T%wd{{0n^+vU>Ye0 z(~RW|NLi;L#XPi#PAD<%M4CTo#7w^$=Mc^3T&%@j9z&-2e#9+d!jStWtb-eQSe@d0 z3>nSG>io$M!&|cx`phyM7j5uF=3!VW;$raHTmi>K30{f?G*NKEfQ<0GFbqObNT+6s z&LXTlYZw+JCk$DOL6HTxYkh$*&)YPn3p(9S7&aThCp#c4IM>t;E(#vmK_3biu!ee^ zQC&1-b#T>;TnxM10!-O>u!%-}#)McxkBOt0fn8GdNDi@nwP?OX3gC%kg2h@V>qKB3 z%u5csrKE#HMz~rU0ZTj&D&zuPpmkBjo;YCAEU=z3qJ!n^f*-PfZB#)kWV74(w)WnR z*7kumU+3FGUzHQ1i4b=#`X3+`joHl#`KtfR)m=62IIs%&ucKS7gmKkR=hRZnrCSw2sg#(LkE?}=N*PIA}36{g7=+XwIKh#K27%N2>iI}Q;+=(F`^g*oy3uz{^*;|7KPZb0Esqe2ffqVTmu0Ok@Q8fZc(y;~V270jbqRW0hdAXiPVH_O=guUZ1I(x;Kq+huNJ)81qf=3Cu5zZPZ_ zDqES^ly)6UYuCelDi_zE$6 iLDS%oB}@>_TtY^9pSfwa*!B0IMb>h36TNZN$o&P!f3BJU delta 4732 zcma)8OH31C5dL=yt*oUKmTtNfyFgp$LMgO7Esvn$!531C4QUi&NF#~H$ie8vaPuH& zV#bRR2@xOBgPQEEiNY1*!NkOq35_1S89dZ@Ai>=>O)%-~w3lx3&wSrJzM233^M!ly zlWSpC#`Dvxk>hPY7{}@v&uUrq{_h7ZK3D03)FtHL^K9t@80Qcd$Z(iXn8$pc@tBX> zg8AIHU_N{W=5q@@`BkxvWcs}l<4IbvlaJPm2->g>J9%TnB6xZL=EgJ8p;4%NT(o!6Szqo(O^|o%UQ< z;gMn`tI1G{BsL{V1oWzU1))hf2$~H^f)Pd{y>b!|H;BQ?NkwIKEN+Ov@6Bi?h`=S^!b=6*p%UDn+CDqhd z7jQdeAi-Oy&fI8&K+%3m7dWKV)9x^mc%h39B|=I`f-SF%pcICX(88XZC_`Q>GFb*g zl=ZT)BT8?C1${b}D3}FF)ZWNjmc^165VKpY=XA}MitFSTFSc%?ZOeortmU-04 z|4