diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index daeda3f53..73a9608e9 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -217,6 +217,11 @@ void LayoutToNetlist::extract_netlist () m_netlist_extracted = true; } +void LayoutToNetlist::set_netlist_extracted () +{ + m_netlist_extracted = true; +} + const db::Layout *LayoutToNetlist::internal_layout () const { return &m_dss.const_layout (); @@ -293,19 +298,30 @@ db::Netlist *LayoutToNetlist::make_netlist () return mp_netlist.get (); } +namespace +{ + struct StopOnFirst { }; +} template -static void deliver_shape (const db::PolygonRef &pr, db::Region ®ion, const Tr &tr) +static bool deliver_shape (const db::PolygonRef &, StopOnFirst, const Tr &) +{ + return false; +} + +template +static bool deliver_shape (const db::PolygonRef &pr, db::Region ®ion, const Tr &tr) { if (pr.obj ().is_box ()) { region.insert (pr.obj ().box ().transformed (pr.trans ()).transformed (tr)); } else { region.insert (pr.obj ().transformed (pr.trans ()).transformed (tr)); } + return true; } template -static void deliver_shape (const db::PolygonRef &pr, db::Shapes &shapes, const Tr &tr) +static bool deliver_shape (const db::PolygonRef &pr, db::Shapes &shapes, const Tr &tr) { if (pr.obj ().is_box ()) { shapes.insert (pr.obj ().box ().transformed (pr.trans ()).transformed (tr)); @@ -317,25 +333,51 @@ static void deliver_shape (const db::PolygonRef &pr, db::Shapes &shapes, const T shapes.insert (pr.obj ().transformed (pr.trans ()).transformed (tr)); } } + return true; } template -static void deliver_shapes_of_net_recursive (const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, To &to) +static bool deliver_shapes_of_net_recursive (const db::Netlist * /*nl*/, const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, const db::ICplxTrans &tr, To &to) { // deliver the net shapes for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { - deliver_shape (*rci, to, rci.trans ()); + if (! deliver_shape (*rci, to, tr * rci.trans ())) { + return false; + } } + return true; } template -static void deliver_shapes_of_net_nonrecursive (const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, To &to) +static bool deliver_shapes_of_net_nonrecursive (const db::Netlist *nl, const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, const db::ICplxTrans &tr, To &to) { - const db::local_cluster &lc = clusters.clusters_per_cell (ci).cluster_by_id (cid); + // NOTE: this scheme will deliver the shapes from the cell, including (!) + // subcells that are purged + + db::cell_index_type prev_ci = ci; + + // deliver the net shapes + for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ) { + + db::cell_index_type cci = rci.cell_index (); + if (cci != prev_ci && cci != ci && (! nl || nl->circuit_by_cell_index (cci) || nl->device_model_by_cell_index (cci))) { + + rci.skip_cell (); + + } else { + + if (! deliver_shape (*rci, to, tr * rci.trans ())) { + return false; + } + prev_ci = cci; + + ++rci; + + } - for (db::local_cluster::shape_iterator s = lc.begin (layer_id); !s.at_end (); ++s) { - deliver_shape (*s, to, db::UnitTrans ()); } + + return true; } void LayoutToNetlist::shapes_of_net (const db::Net &net, const db::Region &of_layer, bool recursive, db::Shapes &to) const @@ -345,9 +387,9 @@ void LayoutToNetlist::shapes_of_net (const db::Net &net, const db::Region &of_la tl_assert (circuit != 0); if (! recursive) { - deliver_shapes_of_net_nonrecursive (m_net_clusters, circuit->cell_index (), net.cluster_id (), lid, to); + deliver_shapes_of_net_nonrecursive (mp_netlist.get (), m_net_clusters, circuit->cell_index (), net.cluster_id (), lid, db::ICplxTrans (), to); } else { - deliver_shapes_of_net_recursive (m_net_clusters, circuit->cell_index (), net.cluster_id (), lid, to); + deliver_shapes_of_net_recursive (mp_netlist.get (), m_net_clusters, circuit->cell_index (), net.cluster_id (), lid, db::ICplxTrans (), to); } } @@ -360,31 +402,60 @@ db::Region *LayoutToNetlist::shapes_of_net (const db::Net &net, const db::Region std::auto_ptr res (new db::Region ()); if (! recursive) { - deliver_shapes_of_net_nonrecursive (m_net_clusters, circuit->cell_index (), net.cluster_id (), lid, *res); + deliver_shapes_of_net_nonrecursive (mp_netlist.get (), m_net_clusters, circuit->cell_index (), net.cluster_id (), lid, db::ICplxTrans (), *res); } else { - deliver_shapes_of_net_recursive (m_net_clusters, circuit->cell_index (), net.cluster_id (), lid, *res); + deliver_shapes_of_net_recursive (mp_netlist.get (), m_net_clusters, circuit->cell_index (), net.cluster_id (), lid, db::ICplxTrans (), *res); } return res.release (); } void -LayoutToNetlist::build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *cell_name_prefix, const char *device_cell_name_prefix, std::map, db::cell_index_type> &cmap) const +LayoutToNetlist::build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *net_cell_name_prefix, const char *cell_name_prefix, const char *device_cell_name_prefix, std::map, db::cell_index_type> &cmap, const db::ICplxTrans &tr) const { const db::Circuit *circuit = net.circuit (); tl_assert (circuit != 0); - build_net_rec (circuit->cell_index (), net.cluster_id (), target, target_cell, lmap, cell_name_prefix, device_cell_name_prefix, cmap); + build_net_rec (circuit->cell_index (), net.cluster_id (), target, target_cell, lmap, &net, net_cell_name_prefix, cell_name_prefix, device_cell_name_prefix, cmap, tr); } void -LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *cell_name_prefix, const char *device_cell_name_prefix, std::map, db::cell_index_type> &cmap) const +LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &target, db::Cell &tc, const std::map &lmap, const db::Net *net, const char *net_cell_name_prefix, const char *circuit_cell_name_prefix, const char *device_cell_name_prefix, std::map, db::cell_index_type> &cmap, const db::ICplxTrans &tr) const { - for (std::map::const_iterator l = lmap.begin (); l != lmap.end (); ++l) { - deliver_shapes_of_net_nonrecursive (m_net_clusters, ci, cid, layer_of (*l->second), target_cell.shapes (l->first)); + db::Cell *target_cell = &tc; + + if (net_cell_name_prefix) { + + const db::connected_clusters &ccl = m_net_clusters.clusters_per_cell (ci); + + bool any_connections = circuit_cell_name_prefix && ! ccl.connections_for_cluster (cid).empty (); + if (! any_connections) { + + bool consider_cell = any_connections; + for (std::map::const_iterator l = lmap.begin (); l != lmap.end () && !consider_cell; ++l) { + StopOnFirst sof; + consider_cell = deliver_shapes_of_net_nonrecursive (mp_netlist.get (), m_net_clusters, ci, cid, layer_of (*l->second), tr, sof); + } + + if (! consider_cell) { + // shortcut if cell is empty -> no net cell will be produced + return; + } + + } + + // make a specific cell for the net if requested + + target_cell = &target.cell (target.add_cell ((std::string (net_cell_name_prefix) + net->expanded_name ()).c_str ())); + tc.insert (db::CellInstArray (db::CellInst (target_cell->cell_index ()), db::Trans ())); + } - if (! cell_name_prefix && ! device_cell_name_prefix) { + for (std::map::const_iterator l = lmap.begin (); l != lmap.end (); ++l) { + deliver_shapes_of_net_nonrecursive (mp_netlist.get (), m_net_clusters, ci, cid, layer_of (*l->second), tr, target_cell->shapes (l->first)); + } + + if (! circuit_cell_name_prefix && ! device_cell_name_prefix) { return; } @@ -403,7 +474,7 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout & if (mp_netlist->device_model_by_cell_index (subci)) { name_prefix = device_cell_name_prefix; } else { - name_prefix = cell_name_prefix; + name_prefix = circuit_cell_name_prefix; } if (name_prefix) { @@ -413,7 +484,7 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout & db::cell_index_type target_ci = target.add_cell ((std::string (name_prefix) + cell_name).c_str ()); cm = cmap.insert (std::make_pair (std::make_pair (subci, subcid), target_ci)).first; - build_net_rec (subci, subcid, target, target.cell (target_ci), lmap, cell_name_prefix, device_cell_name_prefix, cmap); + build_net_rec (subci, subcid, target, target.cell (target_ci), lmap, 0, 0, circuit_cell_name_prefix, device_cell_name_prefix, cmap, db::ICplxTrans ()); } else { cm = cmap.insert (std::make_pair (std::make_pair (subci, subcid), std::numeric_limits::max ())).first; @@ -422,7 +493,7 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout & } if (cm->second != std::numeric_limits::max ()) { - target_cell.insert (db::CellInstArray (db::CellInst (cm->second), c->inst ().complex_trans ())); + target_cell->insert (db::CellInstArray (db::CellInst (cm->second), tr * c->inst ().complex_trans ())); } } @@ -437,7 +508,7 @@ LayoutToNetlist::build_net (const db::Net &net, db::Layout &target, db::Cell &ta std::map, db::cell_index_type> cell_map; - build_net_rec (net, target, target_cell, lmap, cell_name_prefix, device_cell_name_prefix, cell_map); + build_net_rec (net, target, target_cell, lmap, 0, cell_name_prefix, device_cell_name_prefix, cell_map, db::ICplxTrans ()); } void @@ -456,39 +527,55 @@ LayoutToNetlist::build_all_nets (const db::CellMapping &cmap, db::Layout &target continue; } + bool is_top_circuit = c->begin_parents () == c->end_parents (); + db::cell_index_type target_ci = cmap.cell_mapping (c->cell_index ()); for (db::Circuit::const_net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) { // exlude local nets in recursive mode - if (circuit_cell_name_prefix && n->pin_count () > 0) { + if (circuit_cell_name_prefix && ! is_top_circuit && n->pin_count () > 0) { continue; } - const db::connected_clusters &ccl = m_net_clusters.clusters_per_cell (c->cell_index ()); - const db::local_cluster &cl = ccl.cluster_by_id (n->cluster_id ()); + build_net_rec (*n, target, target.cell (target_ci), lmap, net_cell_name_prefix, circuit_cell_name_prefix, device_cell_name_prefix, cell_map, db::ICplxTrans ()); - bool any_connections = ! ccl.connections_for_cluster (n->cluster_id ()).empty (); + } - bool any_shapes = false; - for (std::map::const_iterator m = lmap.begin (); m != lmap.end () && !any_shapes; ++m) { - any_shapes = ! cl.begin (layer_of (*m->second)).at_end (); - } + if (circuit_cell_name_prefix) { - if (any_shapes || (circuit_cell_name_prefix && any_connections)) { + // with recursive nets we skip nets in subcircuits which are connected upwards. This means, nets will + // get lost if there is no connection to this pin from the outside. Hence we need to deliver nets from + // subcircuits as part of the circuit which calls the subcircuit - but NOT in a subcircuit cell, because + // this will just apply to nets from certain instances. But the net cell name will be formed as "subcircuit:net" - db::cell_index_type net_ci = target_ci; + const db::Circuit &circuit = *c; + for (db::Circuit::const_subcircuit_iterator sc = circuit.begin_subcircuits (); sc != circuit.end_subcircuits (); ++sc) { - if (net_cell_name_prefix) { + const db::SubCircuit &subcircuit = *sc; + for (db::Circuit::const_pin_iterator p = subcircuit.circuit_ref ()->begin_pins (); p != subcircuit.circuit_ref ()->end_pins (); ++p) { - db::Cell &tc = target.cell (target_ci); - net_ci = target.add_cell ((std::string (net_cell_name_prefix) + n->expanded_name ()).c_str ()); - tc.insert (db::CellInstArray (db::CellInst (net_ci), db::Trans ())); + if (! subcircuit.net_for_pin (p->id ())) { + + const db::Net *n = subcircuit.circuit_ref ()->net_for_pin (p->id ()); + if (n) { + + double dbu = target.dbu (); + db::ICplxTrans tr = db::CplxTrans (dbu).inverted () * subcircuit.trans () * db::CplxTrans (dbu); + + if (net_cell_name_prefix) { + std::string ncn = std::string (net_cell_name_prefix) + subcircuit.expanded_name () + ":"; + build_net_rec (*n, target, target.cell (target_ci), lmap, ncn.c_str (), circuit_cell_name_prefix, device_cell_name_prefix, cell_map, tr); + } else { + build_net_rec (*n, target, target.cell (target_ci), lmap, net_cell_name_prefix, circuit_cell_name_prefix, device_cell_name_prefix, cell_map, tr); + } + + } + + } } - build_net_rec (*n, target, target.cell (net_ci), lmap, circuit_cell_name_prefix, device_cell_name_prefix, cell_map); - } } diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 7a0be2655..c332d48a0 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -141,7 +141,6 @@ public: /** * @brief Creates a new region representing an original layer * "layer_index" is the layer index of the desired layer in the original layout. - * The Region object returned is a new object and must be deleted by the caller. * This variant produces polygons and takes texts for net name annotation. * A variant not taking texts is "make_polygon_layer". A Variant only taking * texts is "make_text_layer". @@ -211,6 +210,13 @@ public: */ void extract_netlist (); + /** + * @brief Marks the netlist as extracted + * NOTE: this method is provided for special cases such as netlist readers. Don't + * use it. + */ + void set_netlist_extracted (); + /** * @brief Gets the internal layout */ @@ -268,6 +274,8 @@ public: /** * @brief gets the netlist extracted or make on if none exists yet. + * NOTE: this method is provided for special cases like readers of persisted + * layout to netlist data. */ db::Netlist *make_netlist (); @@ -401,8 +409,8 @@ private: bool m_netlist_extracted; size_t search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster &test_cluster, std::vector &rev_inst_path); - void build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *cell_name_prefix, const char *device_cell_name_prefix, std::map, db::cell_index_type> &cmap) const; - void build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *cell_name_prefix, const char *device_cell_name_prefix, std::map, db::cell_index_type> &cmap) const; + void build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *net_cell_name_prefix, const char *cell_name_prefix, const char *device_cell_name_prefix, std::map, db::cell_index_type> &cmap, const ICplxTrans &tr) const; + void build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const Net *net, const char *net_cell_name_prefix, const char *cell_name_prefix, const char *device_cell_name_prefix, std::map, db::cell_index_type> &cmap, const ICplxTrans &tr) const; }; } diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h index 8d0a6e894..fd6793473 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.h +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -110,6 +110,8 @@ namespace l2n_std_format param_key, location_key, rotation_key, mirror_key, scale_key, pin_key, indent1, indent2; + + inline static bool is_short () { return Short; } }; } diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc index fe3a3ac5b..cc051af0b 100644 --- a/src/db/db/dbLayoutToNetlistReader.cc +++ b/src/db/db/dbLayoutToNetlistReader.cc @@ -51,6 +51,11 @@ public: m_layers.insert (std::make_pair (name, region)); } + bool has_layer (const std::string &name) const + { + return m_layers.find (name) != m_layers.end (); + } + db::Region &layer (const std::string &name) { std::map::const_iterator l = m_layers.find (name); @@ -180,6 +185,11 @@ void LayoutToNetlistStandardReader::read (db::LayoutToNetlist *l2n) } } +const db::Region *LayoutToNetlistStandardReader::layer_by_name (const std::string &name) +{ + return mp_layers->has_layer (name) ? &mp_layers->layer (name) : 0; +} + void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) { int version = 0; @@ -191,7 +201,7 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) l2n->make_netlist (); - Layers layers; + mp_layers.reset (new Layers ()); while (! at_end ()) { @@ -227,7 +237,7 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) Brace br (this); std::string layer; read_word_or_quoted (layer); - layers.add (layer, l2n->make_layer (layer)); + mp_layers->add (layer, l2n->make_layer (layer)); br.done (); } else if (test (skeys::connect_key) || test (lkeys::connect_key)) { @@ -238,7 +248,7 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) while (br) { std::string l2; read_word_or_quoted (l2); - l2n->connect (layers.layer (l1), layers.layer (l2)); + l2n->connect (mp_layers->layer (l1), mp_layers->layer (l2)); } br.done (); @@ -250,7 +260,7 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) while (br) { std::string g; read_word_or_quoted (g); - l2n->connect_global (layers.layer (l1), g); + l2n->connect_global (mp_layers->layer (l1), g); } br.done (); @@ -265,7 +275,8 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) l2n->netlist ()->add_circuit (circuit); db::Layout *ly = l2n->internal_layout (); - db::cell_index_type ci = ly->add_cell (name.c_str ()); + std::pair ci_old = ly->cell_by_name (name.c_str ()); + db::cell_index_type ci = ci_old.first ? ci_old.second : ly->add_cell (name.c_str ()); circuit->set_cell_index (ci); std::map > connections; @@ -273,7 +284,7 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) while (br) { if (test (skeys::net_key) || test (lkeys::net_key)) { - read_net (l2n, circuit, layers); + read_net (l2n, circuit); } else if (test (skeys::pin_key) || test (lkeys::pin_key)) { read_pin (l2n, circuit); } else if (test (skeys::device_key) || test (lkeys::device_key)) { @@ -340,7 +351,7 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) while (br) { if (test (skeys::terminal_key) || test (lkeys::terminal_key)) { - read_abstract_terminal (l2n, dm, gen_dc ? dc : 0, layers); + read_abstract_terminal (l2n, dm, gen_dc ? dc : 0); } else { throw tl::Exception (tl::to_string (tr ("Invalid keyword inside device abstract definition (terminal expected)"))); } @@ -352,10 +363,12 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) } } + + l2n->set_netlist_extracted (); } std::pair -LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n, Layers &layers) +LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n) { std::string lname; @@ -364,7 +377,7 @@ LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n, Layers & Brace br (this); read_word_or_quoted (lname); - unsigned int lid = l2n->layer_of (layers.layer (lname)); + unsigned int lid = l2n->layer_of (mp_layers->layer (lname)); db::Coord l = read_coord (); db::Coord b = read_coord (); @@ -381,7 +394,7 @@ LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n, Layers & Brace br (this); read_word_or_quoted (lname); - unsigned int lid = l2n->layer_of (layers.layer (lname)); + unsigned int lid = l2n->layer_of (mp_layers->layer (lname)); std::vector pt; @@ -403,7 +416,7 @@ LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n, Layers & } void -LayoutToNetlistStandardReader::read_net (db::LayoutToNetlist *l2n, db::Circuit *circuit, Layers &layers) +LayoutToNetlistStandardReader::read_net (db::LayoutToNetlist *l2n, db::Circuit *circuit) { Brace br (this); @@ -421,7 +434,7 @@ LayoutToNetlistStandardReader::read_net (db::LayoutToNetlist *l2n, db::Circuit * db::Cell &cell = l2n->internal_layout ()->cell (circuit->cell_index ()); while (br) { - std::pair pr = read_geometry (l2n, layers); + std::pair pr = read_geometry (l2n); lc.add (pr.second, pr.first); cell.shapes (pr.first).insert (pr.second); } @@ -675,7 +688,7 @@ LayoutToNetlistStandardReader::read_subcircuit (db::LayoutToNetlist *l2n, db::Ci } void -LayoutToNetlistStandardReader::read_abstract_terminal (db::LayoutToNetlist *l2n, db::DeviceModel *dm, db::DeviceClass *dc, Layers &layers) +LayoutToNetlistStandardReader::read_abstract_terminal (db::LayoutToNetlist *l2n, db::DeviceModel *dm, db::DeviceClass *dc) { Brace br (this); @@ -707,7 +720,7 @@ LayoutToNetlistStandardReader::read_abstract_terminal (db::LayoutToNetlist *l2n, db::Cell &cell = l2n->internal_layout ()->cell (dm->cell_index ()); while (br) { - std::pair pr = read_geometry (l2n, layers); + std::pair pr = read_geometry (l2n); lc.add (pr.second, pr.first); cell.shapes (pr.first).insert (pr.second); } diff --git a/src/db/db/dbLayoutToNetlistReader.h b/src/db/db/dbLayoutToNetlistReader.h index 6fe9a566a..276614197 100644 --- a/src/db/db/dbLayoutToNetlistReader.h +++ b/src/db/db/dbLayoutToNetlistReader.h @@ -40,6 +40,7 @@ class Circuit; class Cell; class DeviceModel; class DeviceClass; +class Region; /** * @brief The base class for a LayoutToNetlist writer @@ -64,6 +65,8 @@ public: void read (db::LayoutToNetlist *l2n); + const db::Region *layer_by_name (const std::string &name); + private: friend class l2n_std_reader::Brace; typedef l2n_std_reader::Brace Brace; @@ -82,6 +85,7 @@ private: std::string m_path; std::string m_line; tl::Extractor m_ex; + std::auto_ptr mp_layers; void do_read (db::LayoutToNetlist *l2n); @@ -94,12 +98,12 @@ private: bool at_end (); void skip (); - void read_net (db::LayoutToNetlist *l2n, db::Circuit *circuit, Layers &layers); + void read_net (db::LayoutToNetlist *l2n, db::Circuit *circuit); void read_pin (db::LayoutToNetlist *l2n, db::Circuit *circuit); db::CellInstArray read_device (db::LayoutToNetlist *l2n, db::Circuit *circuit, std::list &refs); db::CellInstArray read_subcircuit (db::LayoutToNetlist *l2n, db::Circuit *circuit, std::list &refs); - void read_abstract_terminal (db::LayoutToNetlist *l2n, db::DeviceModel *dm, db::DeviceClass *dc, Layers &layers); - std::pair read_geometry (db::LayoutToNetlist *l2n, Layers &layers); + void read_abstract_terminal (db::LayoutToNetlist *l2n, db::DeviceModel *dm, db::DeviceClass *dc); + std::pair read_geometry (db::LayoutToNetlist *l2n); }; } diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index 2daa621be..437ca16d8 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -83,23 +83,33 @@ void std_writer_impl::write (const db::LayoutToNetlist *l2n) const db::Layout *ly = l2n->internal_layout (); const db::Netlist *nl = l2n->netlist (); - *mp_stream << "# General section" << endl; - *mp_stream << "# Lists general definitions." << endl << endl; + *mp_stream << "#%l2n-klayout" << endl; + + if (! Keys::is_short ()) { + *mp_stream << endl << "# General section" << endl << endl; + } + if (version > 0) { *mp_stream << Keys::version_key << "(" << version << ")" << endl; } *mp_stream << Keys::top_key << "(" << tl::to_word_or_quoted_string (ly->cell_name (l2n->internal_top_cell ()->cell_index ())) << ")" << endl; *mp_stream << Keys::unit_key << "(" << ly->dbu () << ")" << endl; - *mp_stream << endl << "# Layer section" << endl; - *mp_stream << "# This section lists the mask layers (drawing or derived) and their connections." << endl; + if (! Keys::is_short ()) { + *mp_stream << endl << "# Layer section" << endl; + *mp_stream << "# This section lists the mask layers (drawing or derived) and their connections." << endl; + } - *mp_stream << endl << "# Mask layers" << endl; + if (! Keys::is_short ()) { + *mp_stream << endl << "# Mask layers" << endl; + } for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) { *mp_stream << Keys::layer_key << "(" << name_for_layer (ly, *l) << ")" << endl; } - *mp_stream << endl << "# Mask layer connectivity" << endl; + if (! Keys::is_short ()) { + *mp_stream << endl << "# Mask layer connectivity" << endl; + } for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) { db::Connectivity::layer_iterator ce = l2n->connectivity ().end_connected (*l); @@ -121,7 +131,9 @@ void std_writer_impl::write (const db::LayoutToNetlist *l2n) db::Connectivity::global_nets_iterator gb = l2n->connectivity ().begin_global_connections (*l); if (gb != ge) { if (! any) { - *mp_stream << endl << "# Global nets and connectivity" << endl; + if (! Keys::is_short ()) { + *mp_stream << endl << "# Global nets and connectivity" << endl; + } any = true; } *mp_stream << Keys::global_key << "(" << name_for_layer (ly, *l); @@ -133,7 +145,7 @@ void std_writer_impl::write (const db::LayoutToNetlist *l2n) } - if (nl->begin_device_models () != nl->end_device_models ()) { + if (nl->begin_device_models () != nl->end_device_models () && ! Keys::is_short ()) { *mp_stream << endl << "# Device abstracts section" << endl; *mp_stream << "# Device abstracts list the pin shapes of the devices." << endl; } @@ -145,8 +157,10 @@ void std_writer_impl::write (const db::LayoutToNetlist *l2n) } } - *mp_stream << endl << "# Circuit section" << endl; - *mp_stream << "# Circuits are the hierarchical building blocks of the netlist." << endl; + if (! Keys::is_short ()) { + *mp_stream << endl << "# Circuit section" << endl; + *mp_stream << "# Circuits are the hierarchical building blocks of the netlist." << endl; + } for (db::Netlist::const_bottom_up_circuit_iterator i = nl->begin_bottom_up (); i != nl->end_bottom_up (); ++i) { const db::Circuit *x = *i; *mp_stream << Keys::circuit_key << "(" << tl::to_word_or_quoted_string (x->name ()) << endl; @@ -159,14 +173,18 @@ template void std_writer_impl::write (const db::LayoutToNetlist *l2n, const db::Circuit &circuit) { if (circuit.begin_nets () != circuit.end_nets ()) { - *mp_stream << endl << indent1 << "# Nets with their geometries" << endl; + if (! Keys::is_short ()) { + *mp_stream << endl << indent1 << "# Nets with their geometries" << endl; + } for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) { write (l2n, *n); } } if (circuit.begin_pins () != circuit.end_pins ()) { - *mp_stream << endl << indent1 << "# Outgoing pins and their connections to nets" << endl; + if (! Keys::is_short ()) { + *mp_stream << endl << indent1 << "# Outgoing pins and their connections to nets" << endl; + } for (db::Circuit::const_pin_iterator p = circuit.begin_pins (); p != circuit.end_pins (); ++p) { const db::Net *net = circuit.net_for_pin (p->id ()); if (net) { @@ -176,20 +194,26 @@ void std_writer_impl::write (const db::LayoutToNetlist *l2n, const db::Cir } if (circuit.begin_devices () != circuit.end_devices ()) { - *mp_stream << endl << indent1 << "# Devices and their connections" << endl; + if (! Keys::is_short ()) { + *mp_stream << endl << indent1 << "# Devices and their connections" << endl; + } for (db::Circuit::const_device_iterator d = circuit.begin_devices (); d != circuit.end_devices (); ++d) { write (l2n, *d); } } if (circuit.begin_subcircuits () != circuit.end_subcircuits ()) { - *mp_stream << endl << indent1 << "# Subcircuits and their connections" << endl; + if (! Keys::is_short ()) { + *mp_stream << endl << indent1 << "# Subcircuits and their connections" << endl; + } for (db::Circuit::const_subcircuit_iterator x = circuit.begin_subcircuits (); x != circuit.end_subcircuits (); ++x) { write (l2n, *x); } } - *mp_stream << endl; + if (! Keys::is_short ()) { + *mp_stream << endl; + } } template diff --git a/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc index 8aa43816a..549466153 100644 --- a/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc @@ -26,6 +26,7 @@ #include "dbStream.h" #include "dbCommonReader.h" #include "dbNetlistDeviceExtractorClasses.h" +#include "dbTestSupport.h" #include "tlUnitTest.h" #include "tlStream.h" @@ -64,17 +65,59 @@ TEST(1_ReaderBasic) tl::absolute_file_path (au_path))); } + // test build_all_nets from read l2n -#if 0 + { + db::Layout ly2; + ly2.dbu (ly.dbu ()); + db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP")); - std::string path = tmp_file ("tmp_l2nwriter_1.txt"); + db::CellMapping cm = l2n.cell_mapping_into (ly2, top2, true /*with device cells*/); + + std::map lmap; + lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = reader.layer_by_name ("psd"); + lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = reader.layer_by_name ("nsd"); + lmap [ly2.insert_layer (db::LayerProperties (3, 0)) ] = reader.layer_by_name ("poly"); + lmap [ly2.insert_layer (db::LayerProperties (4, 0)) ] = reader.layer_by_name ("diff_cont"); + lmap [ly2.insert_layer (db::LayerProperties (5, 0)) ] = reader.layer_by_name ("poly_cont"); + lmap [ly2.insert_layer (db::LayerProperties (6, 0)) ] = reader.layer_by_name ("metal1"); + lmap [ly2.insert_layer (db::LayerProperties (7, 0)) ] = reader.layer_by_name ("via1"); + lmap [ly2.insert_layer (db::LayerProperties (8, 0)) ] = reader.layer_by_name ("metal2"); + + l2n.build_all_nets (cm, ly2, lmap, "NET_", 0, "DEVICE_"); + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "l2n_writer_au.gds"); + + db::compare_layouts (_this, ly2, au); + } +} + +TEST(2_ReaderBasicShort) +{ + db::Layout ly; + + db::Cell &tc = ly.cell (ly.add_cell ("TOP")); + db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set ())); + + std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_s.txt"); + tl::InputStream is_in (in_path); + + db::LayoutToNetlistStandardReader reader (is_in); + reader.read (&l2n); + + // verify against the input + + std::string path = tmp_file ("tmp_l2nreader_2.txt"); { tl::OutputStream stream (path); - db::LayoutToNetlistStandardWriter writer (stream, false); + db::LayoutToNetlistStandardWriter writer (stream, true); writer.write (&l2n); } - std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au.txt"); + std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_s.txt"); tl::InputStream is (path); tl::InputStream is_au (au_path); @@ -85,5 +128,4 @@ TEST(1_ReaderBasic) tl::absolute_file_path (au_path))); } -#endif } diff --git a/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc b/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc index 195f9b2c2..54f6f4b60 100644 --- a/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc @@ -25,6 +25,7 @@ #include "dbStream.h" #include "dbCommonReader.h" #include "dbNetlistDeviceExtractorClasses.h" +#include "dbTestSupport.h" #include "tlUnitTest.h" #include "tlStream.h" @@ -163,6 +164,7 @@ TEST(1_WriterBasic) rpoly_lbl.reset (0); l2n.extract_netlist (); + l2n.netlist ()->make_top_level_pins (); l2n.netlist ()->purge (); std::string path = tmp_file ("tmp_l2nwriter_1.txt"); @@ -174,12 +176,289 @@ TEST(1_WriterBasic) std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au.txt"); - tl::InputStream is (path); - tl::InputStream is_au (au_path); + { + tl::InputStream is (path); + tl::InputStream is_au (au_path); - if (is.read_all () != is_au.read_all ()) { - _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", - tl::absolute_file_path (path), - tl::absolute_file_path (au_path))); + if (is.read_all () != is_au.read_all ()) { + _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", + tl::absolute_file_path (path), + tl::absolute_file_path (au_path))); + } + } + + path = tmp_file ("tmp_l2nwriter_1s.txt"); + { + tl::OutputStream stream (path); + db::LayoutToNetlistStandardWriter writer (stream, true); + writer.write (&l2n); + } + + au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_s.txt"); + + { + tl::InputStream is (path); + tl::InputStream is_au (au_path); + + if (is.read_all () != is_au.read_all ()) { + _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", + tl::absolute_file_path (path), + tl::absolute_file_path (au_path))); + } + } + + // test build_all_nets (verify reference for reader) + + { + db::Layout ly2; + ly2.dbu (ly.dbu ()); + db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP")); + + db::CellMapping cm = l2n.cell_mapping_into (ly2, top2, true /*with device cells*/); + + std::map lmap; + lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = &rpsd; + lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = &rnsd; + lmap [ly2.insert_layer (db::LayerProperties (3, 0)) ] = rpoly.get (); + lmap [ly2.insert_layer (db::LayerProperties (4, 0)) ] = rdiff_cont.get (); + lmap [ly2.insert_layer (db::LayerProperties (5, 0)) ] = rpoly_cont.get (); + lmap [ly2.insert_layer (db::LayerProperties (6, 0)) ] = rmetal1.get (); + lmap [ly2.insert_layer (db::LayerProperties (7, 0)) ] = rvia1.get (); + lmap [ly2.insert_layer (db::LayerProperties (8, 0)) ] = rmetal2.get (); + + l2n.build_all_nets (cm, ly2, lmap, "NET_", 0, "DEVICE_"); + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "l2n_writer_au.gds"); + + db::compare_layouts (_this, ly2, au); + } +} + +TEST(2_WriterWithGlobalNets) +{ + db::Layout ly; + db::LayerMap lmap; + + unsigned int nwell = define_layer (ly, lmap, 1); + unsigned int active = define_layer (ly, lmap, 2); + unsigned int pplus = define_layer (ly, lmap, 10); + unsigned int nplus = define_layer (ly, lmap, 11); + 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_l3.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 rbulk (l2n.make_layer (ly.insert_layer (), "rbulk")); + std::auto_ptr rnwell (l2n.make_layer (nwell, "nwell")); + std::auto_ptr ractive (l2n.make_layer (active, "active")); + std::auto_ptr rpplus (l2n.make_layer (pplus, "pplus")); + std::auto_ptr rnplus (l2n.make_layer (nplus, "nplus")); + std::auto_ptr rpoly (l2n.make_polygon_layer (poly, "poly")); + std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); + std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); + std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont")); + std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); + std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); + std::auto_ptr rvia1 (l2n.make_polygon_layer (via1, "via1")); + std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); + std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); + + // derived regions + + db::Region ractive_in_nwell = *ractive & *rnwell; + db::Region rpactive = ractive_in_nwell & *rpplus; + db::Region rntie = ractive_in_nwell & *rnplus; + db::Region rpgate = rpactive & *rpoly; + db::Region rpsd = rpactive - rpgate; + l2n.name (rpactive, "pactive"); + l2n.name (rntie, "ntie"); + l2n.name (rpgate, "pgate"); + l2n.name (rpsd, "psd"); + + db::Region ractive_outside_nwell = *ractive - *rnwell; + db::Region rnactive = ractive_outside_nwell & *rnplus; + db::Region rptie = ractive_outside_nwell & *rpplus; + db::Region rngate = rnactive & *rpoly; + db::Region rnsd = rnactive - rngate; + l2n.name (rnactive, "nactive"); + l2n.name (rptie, "ptie"); + l2n.name (rngate, "ngate"); + l2n.name (rnsd, "nsd"); + + // return the computed layers into the original layout and write it for debugging purposes + + unsigned int lgate = ly.insert_layer (db::LayerProperties (20, 0)); // 20/0 -> Gate + unsigned int lsd = ly.insert_layer (db::LayerProperties (21, 0)); // 21/0 -> Source/Drain + unsigned int lpdiff = ly.insert_layer (db::LayerProperties (22, 0)); // 22/0 -> P Diffusion + unsigned int lndiff = ly.insert_layer (db::LayerProperties (23, 0)); // 23/0 -> N Diffusion + unsigned int lptie = ly.insert_layer (db::LayerProperties (24, 0)); // 24/0 -> P Tie + unsigned int lntie = ly.insert_layer (db::LayerProperties (25, 0)); // 25/0 -> N Tie + + 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); + rpsd.insert_into (&ly, tc.cell_index (), lptie); + rnsd.insert_into (&ly, tc.cell_index (), lntie); + + db::NetlistDeviceExtractorMOS4Transistor pmos_ex ("PMOS"); + db::NetlistDeviceExtractorMOS4Transistor 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 + dl["W"] = rnwell.get (); + 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 + dl["W"] = rbulk.get (); + l2n.extract_devices (nmos_ex, dl); + + // net extraction + + // Intra-layer + l2n.connect (rpsd); + l2n.connect (rnsd); + l2n.connect (*rnwell); + l2n.connect (*rpoly); + l2n.connect (*rdiff_cont); + l2n.connect (*rpoly_cont); + l2n.connect (*rmetal1); + l2n.connect (*rvia1); + l2n.connect (*rmetal2); + l2n.connect (rptie); + l2n.connect (rntie); + // 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 (*rdiff_cont, rptie); + l2n.connect (*rdiff_cont, rntie); + l2n.connect (*rnwell, rntie); + 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 + // Global + l2n.connect_global (rptie, "BULK"); + l2n.connect_global (*rbulk, "BULK"); + + // 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 (); + l2n.netlist ()->make_top_level_pins (); + l2n.netlist ()->purge (); + + std::string path = tmp_file ("tmp_l2nwriter_2.txt"); + { + tl::OutputStream stream (path); + db::LayoutToNetlistStandardWriter writer (stream, false); + writer.write (&l2n); + } + + std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_2.txt"); + + { + tl::InputStream is (path); + tl::InputStream is_au (au_path); + + if (is.read_all () != is_au.read_all ()) { + _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", + tl::absolute_file_path (path), + tl::absolute_file_path (au_path))); + } + } + + path = tmp_file ("tmp_l2nwriter_2s.txt"); + { + tl::OutputStream stream (path); + db::LayoutToNetlistStandardWriter writer (stream, true); + writer.write (&l2n); + } + + au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_2s.txt"); + + { + tl::InputStream is (path); + tl::InputStream is_au (au_path); + + if (is.read_all () != is_au.read_all ()) { + _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", + tl::absolute_file_path (path), + tl::absolute_file_path (au_path))); + } + } + + // test build_all_nets + + { + db::Layout ly2; + ly2.dbu (ly.dbu ()); + db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP")); + + db::CellMapping cm = l2n.cell_mapping_into (ly2, top2, true /*with device cells*/); + + std::map lmap; + lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = &rpsd; + lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = &rnsd; + lmap [ly2.insert_layer (db::LayerProperties (12, 0))] = rbulk.get (); + lmap [ly2.insert_layer (db::LayerProperties (13, 0))] = &rptie; + lmap [ly2.insert_layer (db::LayerProperties (14, 0))] = &rntie; + lmap [ly2.insert_layer (db::LayerProperties (1, 0)) ] = rnwell.get (); + lmap [ly2.insert_layer (db::LayerProperties (3, 0)) ] = rpoly.get (); + lmap [ly2.insert_layer (db::LayerProperties (4, 0)) ] = rdiff_cont.get (); + lmap [ly2.insert_layer (db::LayerProperties (5, 0)) ] = rpoly_cont.get (); + lmap [ly2.insert_layer (db::LayerProperties (6, 0)) ] = rmetal1.get (); + lmap [ly2.insert_layer (db::LayerProperties (7, 0)) ] = rvia1.get (); + lmap [ly2.insert_layer (db::LayerProperties (8, 0)) ] = rmetal2.get (); + + l2n.build_all_nets (cm, ly2, lmap, "NET_", "CIRCUIT_", "DEVICE_"); + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "l2n_writer_au_2.gds"); + + db::compare_layouts (_this, ly2, au); } } diff --git a/testdata/algo/l2n_writer_au.gds b/testdata/algo/l2n_writer_au.gds new file mode 100644 index 000000000..ff8630243 Binary files /dev/null and b/testdata/algo/l2n_writer_au.gds differ diff --git a/testdata/algo/l2n_writer_au.txt b/testdata/algo/l2n_writer_au.txt index 901b8799a..2861391d6 100644 --- a/testdata/algo/l2n_writer_au.txt +++ b/testdata/algo/l2n_writer_au.txt @@ -1,5 +1,6 @@ +#%l2n-klayout + # General section -# Lists general definitions. top(RINGO) unit(0.001) @@ -211,6 +212,15 @@ circuit(RINGO rect(metal2 -1720 1600 23160 2000) rect(metal2_lbl -1 1799 1 1801) ) + net(OSC + rect(diff_cont 24450 2890 24670 3110) + rect(diff_cont 24450 2490 24670 2710) + rect(diff_cont 24450 90 24670 310) + rect(diff_cont 24450 -310 24670 -90) + rect(via1 24435 1675 24685 1925) + rect(metal2 24360 1600 24760 2000) + rect(metal2_lbl 24559 1799 24561 1801) + ) net(VSS rect(diff_cont 2530 -310 2750 -90) rect(diff_cont 2530 90 2750 310) @@ -392,10 +402,17 @@ circuit(RINGO rect(diff_cont 3330 -310 3550 -90) ) + # Outgoing pins and their connections to nets + pin(FB FB) + pin(OSC OSC) + pin(VSS VSS) + pin(VDD VDD) + # Subcircuits and their connections circuit($1 INV2 location(23760 0) pin(IN $I8) pin($1 FB) + pin(OUT OSC) pin($3 VSS) pin($4 VDD) ) diff --git a/testdata/algo/l2n_writer_au_2.gds b/testdata/algo/l2n_writer_au_2.gds new file mode 100644 index 000000000..0ca9523ff Binary files /dev/null and b/testdata/algo/l2n_writer_au_2.gds differ diff --git a/testdata/algo/l2n_writer_au_2.txt b/testdata/algo/l2n_writer_au_2.txt new file mode 100644 index 000000000..f4e5c05c7 --- /dev/null +++ b/testdata/algo/l2n_writer_au_2.txt @@ -0,0 +1,566 @@ +#%l2n-klayout + +# General section + +top(RINGO) +unit(0.001) + +# Layer section +# This section lists the mask layers (drawing or derived) and their connections. + +# Mask layers +layer(rbulk) +layer(nwell) +layer(poly) +layer(poly_lbl) +layer(diff_cont) +layer(poly_cont) +layer(metal1) +layer(metal1_lbl) +layer(via1) +layer(metal2) +layer(metal2_lbl) +layer(ntie) +layer(psd) +layer(ptie) +layer(nsd) + +# Mask layer connectivity +connect(nwell nwell ntie) +connect(poly poly poly_lbl poly_cont) +connect(poly_lbl poly) +connect(diff_cont diff_cont metal1 ntie psd ptie nsd) +connect(poly_cont poly poly_cont metal1) +connect(metal1 diff_cont poly_cont metal1 metal1_lbl via1) +connect(metal1_lbl metal1) +connect(via1 metal1 via1 metal2) +connect(metal2 via1 metal2 metal2_lbl) +connect(metal2_lbl metal2) +connect(ntie nwell diff_cont ntie) +connect(psd diff_cont psd) +connect(ptie diff_cont ptie) +connect(nsd diff_cont nsd) + +# Global nets and connectivity +global(rbulk BULK) +global(ptie BULK) + +# Device abstracts section +# Device abstracts list the pin shapes of the devices. +device(D$PMOS PMOS + terminal(S + rect(psd -650 -475 -125 475) + ) + terminal(G + rect(poly -125 -475 125 475) + ) + terminal(D + rect(psd 125 -475 675 475) + ) + terminal(B + rect(nwell -125 -475 125 475) + ) +) +device(D$PMOS$1 PMOS + terminal(S + rect(psd -675 -475 -125 475) + ) + terminal(G + rect(poly -125 -475 125 475) + ) + terminal(D + rect(psd 125 -475 650 475) + ) + terminal(B + rect(nwell -125 -475 125 475) + ) +) +device(D$NMOS NMOS + terminal(S + rect(nsd -650 -475 -125 475) + ) + terminal(G + rect(poly -125 -475 125 475) + ) + terminal(D + rect(nsd 125 -475 675 475) + ) + terminal(B + rect(rbulk -125 -475 125 475) + ) +) +device(D$NMOS$1 NMOS + terminal(S + rect(nsd -675 -475 -125 475) + ) + terminal(G + rect(poly -125 -475 125 475) + ) + terminal(D + rect(nsd 125 -475 650 475) + ) + terminal(B + rect(rbulk -125 -475 125 475) + ) +) + +# Circuit section +# Circuits are the hierarchical building blocks of the netlist. +circuit(INV2 + + # Nets with their geometries + net($1 + rect(nwell -1400 1800 1400 4580) + rect(diff_cont -110 3930 110 4150) + rect(ntie -400 3700 400 4380) + ) + net(IN + rect(poly -525 -250 -275 2250) + rect(poly -1700 1620 -400 1980) + rect(poly -525 -800 -275 800) + rect(poly -525 2000 -275 3600) + rect(poly_lbl -801 1799 -799 1801) + rect(poly_cont -1630 1690 -1410 1910) + ) + net($3 + rect(poly 275 -250 525 2250) + rect(poly 220 820 580 1180) + rect(poly 275 2000 525 3600) + rect(poly 275 -800 525 800) + rect(diff_cont -910 2490 -690 2710) + rect(diff_cont -910 2890 -690 3110) + rect(diff_cont -910 -310 -690 -90) + rect(diff_cont -910 90 -690 310) + rect(poly_cont 290 890 510 1110) + rect(metal1 -800 820 580 1180) + rect(metal1 -980 -420 -620 2420) + rect(metal1 -980 2420 -620 3180) + rect(metal1 -980 -380 -620 380) + rect(psd -1050 2325 -525 3275) + rect(nsd -1050 -475 -525 475) + ) + net(OUT + rect(diff_cont 690 2890 910 3110) + rect(diff_cont 690 2490 910 2710) + rect(diff_cont 690 90 910 310) + rect(diff_cont 690 -310 910 -90) + polygon(metal1 800 20 800 380 940 380 940 1620 620 1620 620 2420 980 2420 980 1980 1300 1980 1300 20) + rect(metal1 620 2420 980 3180) + rect(metal1 620 -380 980 380) + rect(metal1_lbl 799 1799 801 1801) + rect(psd 525 2325 1050 3275) + rect(nsd 525 -475 1050 475) + ) + net(VSS + rect(diff_cont -110 -310 110 -90) + rect(diff_cont -110 90 110 310) + rect(diff_cont -110 90 110 310) + rect(diff_cont -110 -310 110 -90) + rect(metal1 -180 -380 180 380) + rect(metal1 -180 -380 180 380) + rect(via1 -125 -325 125 -75) + rect(via1 -125 75 125 325) + rect(metal2 -1400 -450 1400 450) + rect(metal2_lbl 1239 -91 1241 -89) + rect(nsd -275 -475 275 475) + ) + net(VDD + rect(diff_cont -110 2490 110 2710) + rect(diff_cont -110 2890 110 3110) + rect(diff_cont -110 2890 110 3110) + rect(diff_cont -110 2490 110 2710) + rect(metal1 -180 2420 180 3180) + rect(metal1 -180 2420 180 3180) + rect(via1 -125 2475 125 2725) + rect(via1 -125 2875 125 3125) + rect(metal2 -1400 2350 1400 3250) + rect(metal2_lbl 1249 2799 1251 2801) + rect(psd -275 2325 275 3275) + ) + net(BULK + rect(diff_cont -110 -1360 110 -1140) + rect(ptie -400 -1590 400 -910) + ) + + # Outgoing pins and their connections to nets + pin($0 $1) + pin(IN IN) + pin($2 $3) + pin(OUT OUT) + pin(VSS VSS) + pin(VDD VDD) + pin(BULK BULK) + + # Devices and their connections + device($1 D$PMOS + location(-400 2800) + param(L 0.25) + param(W 0.95) + param(AS 0.49875) + param(AD 0.26125) + terminal(S $3) + terminal(G IN) + terminal(D VDD) + terminal(B $1) + ) + device($2 D$PMOS$1 + location(400 2800) + param(L 0.25) + param(W 0.95) + param(AS 0.26125) + param(AD 0.49875) + terminal(S VDD) + terminal(G $3) + terminal(D OUT) + terminal(B $1) + ) + device($3 D$NMOS + location(-400 0) + param(L 0.25) + param(W 0.95) + param(AS 0.49875) + param(AD 0.26125) + terminal(S $3) + terminal(G IN) + terminal(D VSS) + terminal(B BULK) + ) + device($4 D$NMOS$1 + location(400 0) + param(L 0.25) + param(W 0.95) + param(AS 0.26125) + param(AD 0.49875) + terminal(S VSS) + terminal(G $3) + terminal(D OUT) + terminal(B BULK) + ) + +) +circuit(INV2PAIR + + # Nets with their geometries + net(BULK) + net($I8 + rect(diff_cont 3430 3290 3650 3510) + rect(diff_cont 3430 3690 3650 3910) + rect(diff_cont 3430 490 3650 710) + rect(diff_cont 3430 890 3650 1110) + ) + net($I6 + rect(diff_cont 4230 3290 4450 3510) + rect(diff_cont 4230 3690 4450 3910) + rect(diff_cont 4230 3690 4450 3910) + rect(diff_cont 4230 3290 4450 3510) + rect(diff_cont 1590 3290 1810 3510) + rect(diff_cont 1590 3690 1810 3910) + rect(diff_cont 1590 3690 1810 3910) + rect(diff_cont 1590 3290 1810 3510) + rect(metal1 4160 3220 4520 3980) + rect(metal1 4160 3220 4520 3980) + rect(metal1 1520 3220 1880 3980) + rect(metal1 1520 3220 1880 3980) + ) + net($I5 + rect(diff_cont 4230 490 4450 710) + rect(diff_cont 4230 890 4450 1110) + rect(diff_cont 4230 890 4450 1110) + rect(diff_cont 4230 490 4450 710) + rect(diff_cont 1590 490 1810 710) + rect(diff_cont 1590 890 1810 1110) + rect(diff_cont 1590 890 1810 1110) + rect(diff_cont 1590 490 1810 710) + rect(metal1 4160 420 4520 1180) + rect(metal1 4160 420 4520 1180) + rect(metal1 1520 420 1880 1180) + rect(metal1 1520 420 1880 1180) + ) + net($I4 + rect(diff_cont 2390 3690 2610 3910) + rect(diff_cont 2390 3290 2610 3510) + rect(diff_cont 2390 890 2610 1110) + rect(diff_cont 2390 490 2610 710) + ) + net($I3) + net($I2 + rect(diff_cont 5030 3690 5250 3910) + rect(diff_cont 5030 3290 5250 3510) + rect(diff_cont 5030 890 5250 1110) + rect(diff_cont 5030 490 5250 710) + ) + net($I1) + + # Outgoing pins and their connections to nets + pin(BULK BULK) + pin($1 $I8) + pin($2 $I6) + pin($3 $I5) + pin($4 $I3) + pin($5 $I2) + pin($6 $I1) + + # Subcircuits and their connections + circuit($1 INV2 location(1700 800) + pin($0 $I1) + pin(IN $I3) + pin(OUT $I4) + pin(VSS $I5) + pin(VDD $I6) + pin(BULK BULK) + ) + circuit($2 INV2 location(4340 800) + pin($0 $I1) + pin(IN $I4) + pin($2 $I8) + pin(OUT $I2) + pin(VSS $I5) + pin(VDD $I6) + pin(BULK BULK) + ) + +) +circuit(RINGO + + # Nets with their geometries + net(FB + rect(diff_cont 22850 2490 23070 2710) + rect(diff_cont 22850 2890 23070 3110) + rect(diff_cont 22850 -310 23070 -90) + rect(diff_cont 22850 90 23070 310) + rect(metal1 -1700 1620 -1340 1980) + rect(via1 -1645 1675 -1395 1925) + rect(via1 22835 1675 23085 1925) + rect(metal2 -1720 1600 23160 2000) + rect(metal2_lbl -1 1799 1 1801) + ) + net(OSC + rect(diff_cont 24450 2890 24670 3110) + rect(diff_cont 24450 2490 24670 2710) + rect(diff_cont 24450 90 24670 310) + rect(diff_cont 24450 -310 24670 -90) + rect(via1 24435 1675 24685 1925) + rect(metal2 24360 1600 24760 2000) + rect(metal2_lbl 24559 1799 24561 1801) + ) + net(VDD + rect(diff_cont 7810 2490 8030 2710) + rect(diff_cont 7810 2890 8030 3110) + rect(diff_cont 7810 2890 8030 3110) + rect(diff_cont 7810 2490 8030 2710) + rect(diff_cont 5170 2490 5390 2710) + rect(diff_cont 5170 2890 5390 3110) + rect(diff_cont 5170 2890 5390 3110) + rect(diff_cont 5170 2490 5390 2710) + rect(diff_cont 2530 2490 2750 2710) + rect(diff_cont 2530 2890 2750 3110) + rect(diff_cont 2530 2890 2750 3110) + rect(diff_cont 2530 2490 2750 2710) + rect(diff_cont -110 2490 110 2710) + rect(diff_cont -110 2890 110 3110) + rect(diff_cont -110 2890 110 3110) + rect(diff_cont -110 2490 110 2710) + rect(diff_cont 13090 2490 13310 2710) + rect(diff_cont 13090 2890 13310 3110) + rect(diff_cont 13090 2890 13310 3110) + rect(diff_cont 13090 2490 13310 2710) + rect(diff_cont 10450 2490 10670 2710) + rect(diff_cont 10450 2890 10670 3110) + rect(diff_cont 10450 2890 10670 3110) + rect(diff_cont 10450 2490 10670 2710) + rect(diff_cont 18370 2490 18590 2710) + rect(diff_cont 18370 2890 18590 3110) + rect(diff_cont 18370 2890 18590 3110) + rect(diff_cont 18370 2490 18590 2710) + rect(diff_cont 15730 2490 15950 2710) + rect(diff_cont 15730 2890 15950 3110) + rect(diff_cont 15730 2890 15950 3110) + rect(diff_cont 15730 2490 15950 2710) + rect(diff_cont 23650 2490 23870 2710) + rect(diff_cont 23650 2890 23870 3110) + rect(diff_cont 23650 2890 23870 3110) + rect(diff_cont 23650 2490 23870 2710) + rect(diff_cont 21010 2490 21230 2710) + rect(diff_cont 21010 2890 21230 3110) + rect(diff_cont 21010 2890 21230 3110) + rect(diff_cont 21010 2490 21230 2710) + rect(metal1 -180 3100 180 4220) + rect(metal1 2460 3100 2820 4220) + rect(metal1 5100 3100 5460 4220) + rect(metal1 7740 3100 8100 4220) + rect(metal1 10380 3100 10740 4220) + rect(metal1 13020 3100 13380 4220) + rect(metal1 15660 3100 16020 4220) + rect(metal1 18300 3100 18660 4220) + rect(metal1 20940 3100 21300 4220) + rect(metal1 23580 3100 23940 4220) + rect(metal1 7740 2420 8100 3180) + rect(metal1 7740 2420 8100 3180) + rect(metal1 5100 2420 5460 3180) + rect(metal1 5100 2420 5460 3180) + rect(metal1 2460 2420 2820 3180) + rect(metal1 2460 2420 2820 3180) + rect(metal1 -180 2420 180 3180) + rect(metal1 -180 2420 180 3180) + rect(metal1 13020 2420 13380 3180) + rect(metal1 13020 2420 13380 3180) + rect(metal1 10380 2420 10740 3180) + rect(metal1 10380 2420 10740 3180) + rect(metal1 18300 2420 18660 3180) + rect(metal1 18300 2420 18660 3180) + rect(metal1 15660 2420 16020 3180) + rect(metal1 15660 2420 16020 3180) + rect(metal1 23580 2420 23940 3180) + rect(metal1 23580 2420 23940 3180) + rect(metal1 20940 2420 21300 3180) + rect(metal1 20940 2420 21300 3180) + rect(metal2_lbl -1 2799 1 2801) + ) + net('BULK,VSS' + rect(diff_cont 7810 -310 8030 -90) + rect(diff_cont 7810 90 8030 310) + rect(diff_cont 7810 90 8030 310) + rect(diff_cont 7810 -310 8030 -90) + rect(diff_cont 5170 -310 5390 -90) + rect(diff_cont 5170 90 5390 310) + rect(diff_cont 5170 90 5390 310) + rect(diff_cont 5170 -310 5390 -90) + rect(diff_cont 2530 -310 2750 -90) + rect(diff_cont 2530 90 2750 310) + rect(diff_cont 2530 90 2750 310) + rect(diff_cont 2530 -310 2750 -90) + rect(diff_cont -110 -310 110 -90) + rect(diff_cont -110 90 110 310) + rect(diff_cont -110 90 110 310) + rect(diff_cont -110 -310 110 -90) + rect(diff_cont 13090 -310 13310 -90) + rect(diff_cont 13090 90 13310 310) + rect(diff_cont 13090 90 13310 310) + rect(diff_cont 13090 -310 13310 -90) + rect(diff_cont 10450 -310 10670 -90) + rect(diff_cont 10450 90 10670 310) + rect(diff_cont 10450 90 10670 310) + rect(diff_cont 10450 -310 10670 -90) + rect(diff_cont 18370 -310 18590 -90) + rect(diff_cont 18370 90 18590 310) + rect(diff_cont 18370 90 18590 310) + rect(diff_cont 18370 -310 18590 -90) + rect(diff_cont 15730 -310 15950 -90) + rect(diff_cont 15730 90 15950 310) + rect(diff_cont 15730 90 15950 310) + rect(diff_cont 15730 -310 15950 -90) + rect(diff_cont 23650 -310 23870 -90) + rect(diff_cont 23650 90 23870 310) + rect(diff_cont 23650 90 23870 310) + rect(diff_cont 23650 -310 23870 -90) + rect(diff_cont 21010 -310 21230 -90) + rect(diff_cont 21010 90 21230 310) + rect(diff_cont 21010 90 21230 310) + rect(diff_cont 21010 -310 21230 -90) + rect(metal1 -180 -1420 180 -300) + rect(metal1 2460 -1420 2820 -300) + rect(metal1 5100 -1420 5460 -300) + rect(metal1 7740 -1420 8100 -300) + rect(metal1 10380 -1420 10740 -300) + rect(metal1 13020 -1420 13380 -300) + rect(metal1 15660 -1420 16020 -300) + rect(metal1 18300 -1420 18660 -300) + rect(metal1 20940 -1420 21300 -300) + rect(metal1 23580 -1420 23940 -300) + rect(metal1 7740 -380 8100 380) + rect(metal1 7740 -380 8100 380) + rect(metal1 5100 -380 5460 380) + rect(metal1 5100 -380 5460 380) + rect(metal1 2460 -380 2820 380) + rect(metal1 2460 -380 2820 380) + rect(metal1 -180 -380 180 380) + rect(metal1 -180 -380 180 380) + rect(metal1 13020 -380 13380 380) + rect(metal1 13020 -380 13380 380) + rect(metal1 10380 -380 10740 380) + rect(metal1 10380 -380 10740 380) + rect(metal1 18300 -380 18660 380) + rect(metal1 18300 -380 18660 380) + rect(metal1 15660 -380 16020 380) + rect(metal1 15660 -380 16020 380) + rect(metal1 23580 -380 23940 380) + rect(metal1 23580 -380 23940 380) + rect(metal1 20940 -380 21300 380) + rect(metal1 20940 -380 21300 380) + rect(metal2_lbl -1 -1 1 1) + ) + net($I13 + rect(diff_cont 3330 2890 3550 3110) + rect(diff_cont 3330 2490 3550 2710) + rect(diff_cont 3330 90 3550 310) + rect(diff_cont 3330 -310 3550 -90) + ) + net($I7 + rect(diff_cont 19170 2890 19390 3110) + rect(diff_cont 19170 2490 19390 2710) + rect(diff_cont 19170 90 19390 310) + rect(diff_cont 19170 -310 19390 -90) + ) + net($I6 + rect(diff_cont 13890 2890 14110 3110) + rect(diff_cont 13890 2490 14110 2710) + rect(diff_cont 13890 90 14110 310) + rect(diff_cont 13890 -310 14110 -90) + ) + net($I5 + rect(diff_cont 8610 2890 8830 3110) + rect(diff_cont 8610 2490 8830 2710) + rect(diff_cont 8610 90 8830 310) + rect(diff_cont 8610 -310 8830 -90) + ) + + # Outgoing pins and their connections to nets + pin(FB FB) + pin(OSC OSC) + pin(VDD VDD) + pin('BULK,VSS' 'BULK,VSS') + + # Subcircuits and their connections + circuit($1 INV2PAIR location(19420 -800) + pin(BULK 'BULK,VSS') + pin($1 FB) + pin($2 VDD) + pin($3 'BULK,VSS') + pin($4 $I7) + pin($5 OSC) + pin($6 VDD) + ) + circuit($2 INV2PAIR location(-1700 -800) + pin(BULK 'BULK,VSS') + pin($2 VDD) + pin($3 'BULK,VSS') + pin($4 FB) + pin($5 $I13) + pin($6 VDD) + ) + circuit($3 INV2PAIR location(3580 -800) + pin(BULK 'BULK,VSS') + pin($2 VDD) + pin($3 'BULK,VSS') + pin($4 $I13) + pin($5 $I5) + pin($6 VDD) + ) + circuit($4 INV2PAIR location(8860 -800) + pin(BULK 'BULK,VSS') + pin($2 VDD) + pin($3 'BULK,VSS') + pin($4 $I5) + pin($5 $I6) + pin($6 VDD) + ) + circuit($5 INV2PAIR location(14140 -800) + pin(BULK 'BULK,VSS') + pin($2 VDD) + pin($3 'BULK,VSS') + pin($4 $I6) + pin($5 $I7) + pin($6 VDD) + ) + +) diff --git a/testdata/algo/l2n_writer_au_2s.txt b/testdata/algo/l2n_writer_au_2s.txt new file mode 100644 index 000000000..2465db56d --- /dev/null +++ b/testdata/algo/l2n_writer_au_2s.txt @@ -0,0 +1,527 @@ +#%l2n-klayout +W(RINGO) +U(0.001) +L(rbulk) +L(nwell) +L(poly) +L(poly_lbl) +L(diff_cont) +L(poly_cont) +L(metal1) +L(metal1_lbl) +L(via1) +L(metal2) +L(metal2_lbl) +L(ntie) +L(psd) +L(ptie) +L(nsd) +C(nwell nwell ntie) +C(poly poly poly_lbl poly_cont) +C(poly_lbl poly) +C(diff_cont diff_cont metal1 ntie psd ptie nsd) +C(poly_cont poly poly_cont metal1) +C(metal1 diff_cont poly_cont metal1 metal1_lbl via1) +C(metal1_lbl metal1) +C(via1 metal1 via1 metal2) +C(metal2 via1 metal2 metal2_lbl) +C(metal2_lbl metal2) +C(ntie nwell diff_cont ntie) +C(psd diff_cont psd) +C(ptie diff_cont ptie) +C(nsd diff_cont nsd) +G(rbulk BULK) +G(ptie BULK) +D(D$PMOS PMOS + T(S + R(psd -650 -475 -125 475) + ) + T(G + R(poly -125 -475 125 475) + ) + T(D + R(psd 125 -475 675 475) + ) + T(B + R(nwell -125 -475 125 475) + ) +) +D(D$PMOS$1 PMOS + T(S + R(psd -675 -475 -125 475) + ) + T(G + R(poly -125 -475 125 475) + ) + T(D + R(psd 125 -475 650 475) + ) + T(B + R(nwell -125 -475 125 475) + ) +) +D(D$NMOS NMOS + T(S + R(nsd -650 -475 -125 475) + ) + T(G + R(poly -125 -475 125 475) + ) + T(D + R(nsd 125 -475 675 475) + ) + T(B + R(rbulk -125 -475 125 475) + ) +) +D(D$NMOS$1 NMOS + T(S + R(nsd -675 -475 -125 475) + ) + T(G + R(poly -125 -475 125 475) + ) + T(D + R(nsd 125 -475 650 475) + ) + T(B + R(rbulk -125 -475 125 475) + ) +) +X(INV2 + N($1 + R(nwell -1400 1800 1400 4580) + R(diff_cont -110 3930 110 4150) + R(ntie -400 3700 400 4380) + ) + N(IN + R(poly -525 -250 -275 2250) + R(poly -1700 1620 -400 1980) + R(poly -525 -800 -275 800) + R(poly -525 2000 -275 3600) + R(poly_lbl -801 1799 -799 1801) + R(poly_cont -1630 1690 -1410 1910) + ) + N($3 + R(poly 275 -250 525 2250) + R(poly 220 820 580 1180) + R(poly 275 2000 525 3600) + R(poly 275 -800 525 800) + R(diff_cont -910 2490 -690 2710) + R(diff_cont -910 2890 -690 3110) + R(diff_cont -910 -310 -690 -90) + R(diff_cont -910 90 -690 310) + R(poly_cont 290 890 510 1110) + R(metal1 -800 820 580 1180) + R(metal1 -980 -420 -620 2420) + R(metal1 -980 2420 -620 3180) + R(metal1 -980 -380 -620 380) + R(psd -1050 2325 -525 3275) + R(nsd -1050 -475 -525 475) + ) + N(OUT + R(diff_cont 690 2890 910 3110) + R(diff_cont 690 2490 910 2710) + R(diff_cont 690 90 910 310) + R(diff_cont 690 -310 910 -90) + Q(metal1 800 20 800 380 940 380 940 1620 620 1620 620 2420 980 2420 980 1980 1300 1980 1300 20) + R(metal1 620 2420 980 3180) + R(metal1 620 -380 980 380) + R(metal1_lbl 799 1799 801 1801) + R(psd 525 2325 1050 3275) + R(nsd 525 -475 1050 475) + ) + N(VSS + R(diff_cont -110 -310 110 -90) + R(diff_cont -110 90 110 310) + R(diff_cont -110 90 110 310) + R(diff_cont -110 -310 110 -90) + R(metal1 -180 -380 180 380) + R(metal1 -180 -380 180 380) + R(via1 -125 -325 125 -75) + R(via1 -125 75 125 325) + R(metal2 -1400 -450 1400 450) + R(metal2_lbl 1239 -91 1241 -89) + R(nsd -275 -475 275 475) + ) + N(VDD + R(diff_cont -110 2490 110 2710) + R(diff_cont -110 2890 110 3110) + R(diff_cont -110 2890 110 3110) + R(diff_cont -110 2490 110 2710) + R(metal1 -180 2420 180 3180) + R(metal1 -180 2420 180 3180) + R(via1 -125 2475 125 2725) + R(via1 -125 2875 125 3125) + R(metal2 -1400 2350 1400 3250) + R(metal2_lbl 1249 2799 1251 2801) + R(psd -275 2325 275 3275) + ) + N(BULK + R(diff_cont -110 -1360 110 -1140) + R(ptie -400 -1590 400 -910) + ) + P($0 $1) + P(IN IN) + P($2 $3) + P(OUT OUT) + P(VSS VSS) + P(VDD VDD) + P(BULK BULK) + D($1 D$PMOS + Y(-400 2800) + E(L 0.25) + E(W 0.95) + E(AS 0.49875) + E(AD 0.26125) + T(S $3) + T(G IN) + T(D VDD) + T(B $1) + ) + D($2 D$PMOS$1 + Y(400 2800) + E(L 0.25) + E(W 0.95) + E(AS 0.26125) + E(AD 0.49875) + T(S VDD) + T(G $3) + T(D OUT) + T(B $1) + ) + D($3 D$NMOS + Y(-400 0) + E(L 0.25) + E(W 0.95) + E(AS 0.49875) + E(AD 0.26125) + T(S $3) + T(G IN) + T(D VSS) + T(B BULK) + ) + D($4 D$NMOS$1 + Y(400 0) + E(L 0.25) + E(W 0.95) + E(AS 0.26125) + E(AD 0.49875) + T(S VSS) + T(G $3) + T(D OUT) + T(B BULK) + ) +) +X(INV2PAIR + N(BULK) + N($I8 + R(diff_cont 3430 3290 3650 3510) + R(diff_cont 3430 3690 3650 3910) + R(diff_cont 3430 490 3650 710) + R(diff_cont 3430 890 3650 1110) + ) + N($I6 + R(diff_cont 4230 3290 4450 3510) + R(diff_cont 4230 3690 4450 3910) + R(diff_cont 4230 3690 4450 3910) + R(diff_cont 4230 3290 4450 3510) + R(diff_cont 1590 3290 1810 3510) + R(diff_cont 1590 3690 1810 3910) + R(diff_cont 1590 3690 1810 3910) + R(diff_cont 1590 3290 1810 3510) + R(metal1 4160 3220 4520 3980) + R(metal1 4160 3220 4520 3980) + R(metal1 1520 3220 1880 3980) + R(metal1 1520 3220 1880 3980) + ) + N($I5 + R(diff_cont 4230 490 4450 710) + R(diff_cont 4230 890 4450 1110) + R(diff_cont 4230 890 4450 1110) + R(diff_cont 4230 490 4450 710) + R(diff_cont 1590 490 1810 710) + R(diff_cont 1590 890 1810 1110) + R(diff_cont 1590 890 1810 1110) + R(diff_cont 1590 490 1810 710) + R(metal1 4160 420 4520 1180) + R(metal1 4160 420 4520 1180) + R(metal1 1520 420 1880 1180) + R(metal1 1520 420 1880 1180) + ) + N($I4 + R(diff_cont 2390 3690 2610 3910) + R(diff_cont 2390 3290 2610 3510) + R(diff_cont 2390 890 2610 1110) + R(diff_cont 2390 490 2610 710) + ) + N($I3) + N($I2 + R(diff_cont 5030 3690 5250 3910) + R(diff_cont 5030 3290 5250 3510) + R(diff_cont 5030 890 5250 1110) + R(diff_cont 5030 490 5250 710) + ) + N($I1) + P(BULK BULK) + P($1 $I8) + P($2 $I6) + P($3 $I5) + P($4 $I3) + P($5 $I2) + P($6 $I1) + X($1 INV2 Y(1700 800) + P($0 $I1) + P(IN $I3) + P(OUT $I4) + P(VSS $I5) + P(VDD $I6) + P(BULK BULK) + ) + X($2 INV2 Y(4340 800) + P($0 $I1) + P(IN $I4) + P($2 $I8) + P(OUT $I2) + P(VSS $I5) + P(VDD $I6) + P(BULK BULK) + ) +) +X(RINGO + N(FB + R(diff_cont 22850 2490 23070 2710) + R(diff_cont 22850 2890 23070 3110) + R(diff_cont 22850 -310 23070 -90) + R(diff_cont 22850 90 23070 310) + R(metal1 -1700 1620 -1340 1980) + R(via1 -1645 1675 -1395 1925) + R(via1 22835 1675 23085 1925) + R(metal2 -1720 1600 23160 2000) + R(metal2_lbl -1 1799 1 1801) + ) + N(OSC + R(diff_cont 24450 2890 24670 3110) + R(diff_cont 24450 2490 24670 2710) + R(diff_cont 24450 90 24670 310) + R(diff_cont 24450 -310 24670 -90) + R(via1 24435 1675 24685 1925) + R(metal2 24360 1600 24760 2000) + R(metal2_lbl 24559 1799 24561 1801) + ) + N(VDD + R(diff_cont 7810 2490 8030 2710) + R(diff_cont 7810 2890 8030 3110) + R(diff_cont 7810 2890 8030 3110) + R(diff_cont 7810 2490 8030 2710) + R(diff_cont 5170 2490 5390 2710) + R(diff_cont 5170 2890 5390 3110) + R(diff_cont 5170 2890 5390 3110) + R(diff_cont 5170 2490 5390 2710) + R(diff_cont 2530 2490 2750 2710) + R(diff_cont 2530 2890 2750 3110) + R(diff_cont 2530 2890 2750 3110) + R(diff_cont 2530 2490 2750 2710) + R(diff_cont -110 2490 110 2710) + R(diff_cont -110 2890 110 3110) + R(diff_cont -110 2890 110 3110) + R(diff_cont -110 2490 110 2710) + R(diff_cont 13090 2490 13310 2710) + R(diff_cont 13090 2890 13310 3110) + R(diff_cont 13090 2890 13310 3110) + R(diff_cont 13090 2490 13310 2710) + R(diff_cont 10450 2490 10670 2710) + R(diff_cont 10450 2890 10670 3110) + R(diff_cont 10450 2890 10670 3110) + R(diff_cont 10450 2490 10670 2710) + R(diff_cont 18370 2490 18590 2710) + R(diff_cont 18370 2890 18590 3110) + R(diff_cont 18370 2890 18590 3110) + R(diff_cont 18370 2490 18590 2710) + R(diff_cont 15730 2490 15950 2710) + R(diff_cont 15730 2890 15950 3110) + R(diff_cont 15730 2890 15950 3110) + R(diff_cont 15730 2490 15950 2710) + R(diff_cont 23650 2490 23870 2710) + R(diff_cont 23650 2890 23870 3110) + R(diff_cont 23650 2890 23870 3110) + R(diff_cont 23650 2490 23870 2710) + R(diff_cont 21010 2490 21230 2710) + R(diff_cont 21010 2890 21230 3110) + R(diff_cont 21010 2890 21230 3110) + R(diff_cont 21010 2490 21230 2710) + R(metal1 -180 3100 180 4220) + R(metal1 2460 3100 2820 4220) + R(metal1 5100 3100 5460 4220) + R(metal1 7740 3100 8100 4220) + R(metal1 10380 3100 10740 4220) + R(metal1 13020 3100 13380 4220) + R(metal1 15660 3100 16020 4220) + R(metal1 18300 3100 18660 4220) + R(metal1 20940 3100 21300 4220) + R(metal1 23580 3100 23940 4220) + R(metal1 7740 2420 8100 3180) + R(metal1 7740 2420 8100 3180) + R(metal1 5100 2420 5460 3180) + R(metal1 5100 2420 5460 3180) + R(metal1 2460 2420 2820 3180) + R(metal1 2460 2420 2820 3180) + R(metal1 -180 2420 180 3180) + R(metal1 -180 2420 180 3180) + R(metal1 13020 2420 13380 3180) + R(metal1 13020 2420 13380 3180) + R(metal1 10380 2420 10740 3180) + R(metal1 10380 2420 10740 3180) + R(metal1 18300 2420 18660 3180) + R(metal1 18300 2420 18660 3180) + R(metal1 15660 2420 16020 3180) + R(metal1 15660 2420 16020 3180) + R(metal1 23580 2420 23940 3180) + R(metal1 23580 2420 23940 3180) + R(metal1 20940 2420 21300 3180) + R(metal1 20940 2420 21300 3180) + R(metal2_lbl -1 2799 1 2801) + ) + N('BULK,VSS' + R(diff_cont 7810 -310 8030 -90) + R(diff_cont 7810 90 8030 310) + R(diff_cont 7810 90 8030 310) + R(diff_cont 7810 -310 8030 -90) + R(diff_cont 5170 -310 5390 -90) + R(diff_cont 5170 90 5390 310) + R(diff_cont 5170 90 5390 310) + R(diff_cont 5170 -310 5390 -90) + R(diff_cont 2530 -310 2750 -90) + R(diff_cont 2530 90 2750 310) + R(diff_cont 2530 90 2750 310) + R(diff_cont 2530 -310 2750 -90) + R(diff_cont -110 -310 110 -90) + R(diff_cont -110 90 110 310) + R(diff_cont -110 90 110 310) + R(diff_cont -110 -310 110 -90) + R(diff_cont 13090 -310 13310 -90) + R(diff_cont 13090 90 13310 310) + R(diff_cont 13090 90 13310 310) + R(diff_cont 13090 -310 13310 -90) + R(diff_cont 10450 -310 10670 -90) + R(diff_cont 10450 90 10670 310) + R(diff_cont 10450 90 10670 310) + R(diff_cont 10450 -310 10670 -90) + R(diff_cont 18370 -310 18590 -90) + R(diff_cont 18370 90 18590 310) + R(diff_cont 18370 90 18590 310) + R(diff_cont 18370 -310 18590 -90) + R(diff_cont 15730 -310 15950 -90) + R(diff_cont 15730 90 15950 310) + R(diff_cont 15730 90 15950 310) + R(diff_cont 15730 -310 15950 -90) + R(diff_cont 23650 -310 23870 -90) + R(diff_cont 23650 90 23870 310) + R(diff_cont 23650 90 23870 310) + R(diff_cont 23650 -310 23870 -90) + R(diff_cont 21010 -310 21230 -90) + R(diff_cont 21010 90 21230 310) + R(diff_cont 21010 90 21230 310) + R(diff_cont 21010 -310 21230 -90) + R(metal1 -180 -1420 180 -300) + R(metal1 2460 -1420 2820 -300) + R(metal1 5100 -1420 5460 -300) + R(metal1 7740 -1420 8100 -300) + R(metal1 10380 -1420 10740 -300) + R(metal1 13020 -1420 13380 -300) + R(metal1 15660 -1420 16020 -300) + R(metal1 18300 -1420 18660 -300) + R(metal1 20940 -1420 21300 -300) + R(metal1 23580 -1420 23940 -300) + R(metal1 7740 -380 8100 380) + R(metal1 7740 -380 8100 380) + R(metal1 5100 -380 5460 380) + R(metal1 5100 -380 5460 380) + R(metal1 2460 -380 2820 380) + R(metal1 2460 -380 2820 380) + R(metal1 -180 -380 180 380) + R(metal1 -180 -380 180 380) + R(metal1 13020 -380 13380 380) + R(metal1 13020 -380 13380 380) + R(metal1 10380 -380 10740 380) + R(metal1 10380 -380 10740 380) + R(metal1 18300 -380 18660 380) + R(metal1 18300 -380 18660 380) + R(metal1 15660 -380 16020 380) + R(metal1 15660 -380 16020 380) + R(metal1 23580 -380 23940 380) + R(metal1 23580 -380 23940 380) + R(metal1 20940 -380 21300 380) + R(metal1 20940 -380 21300 380) + R(metal2_lbl -1 -1 1 1) + ) + N($I13 + R(diff_cont 3330 2890 3550 3110) + R(diff_cont 3330 2490 3550 2710) + R(diff_cont 3330 90 3550 310) + R(diff_cont 3330 -310 3550 -90) + ) + N($I7 + R(diff_cont 19170 2890 19390 3110) + R(diff_cont 19170 2490 19390 2710) + R(diff_cont 19170 90 19390 310) + R(diff_cont 19170 -310 19390 -90) + ) + N($I6 + R(diff_cont 13890 2890 14110 3110) + R(diff_cont 13890 2490 14110 2710) + R(diff_cont 13890 90 14110 310) + R(diff_cont 13890 -310 14110 -90) + ) + N($I5 + R(diff_cont 8610 2890 8830 3110) + R(diff_cont 8610 2490 8830 2710) + R(diff_cont 8610 90 8830 310) + R(diff_cont 8610 -310 8830 -90) + ) + P(FB FB) + P(OSC OSC) + P(VDD VDD) + P('BULK,VSS' 'BULK,VSS') + X($1 INV2PAIR Y(19420 -800) + P(BULK 'BULK,VSS') + P($1 FB) + P($2 VDD) + P($3 'BULK,VSS') + P($4 $I7) + P($5 OSC) + P($6 VDD) + ) + X($2 INV2PAIR Y(-1700 -800) + P(BULK 'BULK,VSS') + P($2 VDD) + P($3 'BULK,VSS') + P($4 FB) + P($5 $I13) + P($6 VDD) + ) + X($3 INV2PAIR Y(3580 -800) + P(BULK 'BULK,VSS') + P($2 VDD) + P($3 'BULK,VSS') + P($4 $I13) + P($5 $I5) + P($6 VDD) + ) + X($4 INV2PAIR Y(8860 -800) + P(BULK 'BULK,VSS') + P($2 VDD) + P($3 'BULK,VSS') + P($4 $I5) + P($5 $I6) + P($6 VDD) + ) + X($5 INV2PAIR Y(14140 -800) + P(BULK 'BULK,VSS') + P($2 VDD) + P($3 'BULK,VSS') + P($4 $I6) + P($5 $I7) + P($6 VDD) + ) +) diff --git a/testdata/algo/l2n_writer_au_s.txt b/testdata/algo/l2n_writer_au_s.txt new file mode 100644 index 000000000..2ff91db45 --- /dev/null +++ b/testdata/algo/l2n_writer_au_s.txt @@ -0,0 +1,444 @@ +#%l2n-klayout +W(RINGO) +U(0.001) +L(poly) +L(poly_lbl) +L(diff_cont) +L(poly_cont) +L(metal1) +L(metal1_lbl) +L(via1) +L(metal2) +L(metal2_lbl) +L(psd) +L(nsd) +C(poly poly poly_lbl poly_cont) +C(poly_lbl poly) +C(diff_cont diff_cont metal1 psd nsd) +C(poly_cont poly poly_cont metal1) +C(metal1 diff_cont poly_cont metal1 metal1_lbl via1) +C(metal1_lbl metal1) +C(via1 metal1 via1 metal2) +C(metal2 via1 metal2 metal2_lbl) +C(metal2_lbl metal2) +C(psd diff_cont psd) +C(nsd diff_cont nsd) +D(D$PMOS PMOS + T(S + R(psd -650 -475 -125 475) + ) + T(G + R(poly -125 -475 125 475) + ) + T(D + R(psd 125 -475 675 475) + ) +) +D(D$PMOS$1 PMOS + T(S + R(psd -675 -475 -125 475) + ) + T(G + R(poly -125 -475 125 475) + ) + T(D + R(psd 125 -475 650 475) + ) +) +D(D$NMOS NMOS + T(S + R(nsd -650 -475 -125 475) + ) + T(G + R(poly -125 -475 125 475) + ) + T(D + R(nsd 125 -475 675 475) + ) +) +D(D$NMOS$1 NMOS + T(S + R(nsd -675 -475 -125 475) + ) + T(G + R(poly -125 -475 125 475) + ) + T(D + R(nsd 125 -475 650 475) + ) +) +X(INV2 + N(IN + R(poly -525 -250 -275 2250) + R(poly -1700 1620 -400 1980) + R(poly -525 -800 -275 800) + R(poly -525 2000 -275 3600) + R(poly_lbl -801 1799 -799 1801) + R(poly_cont -1630 1690 -1410 1910) + ) + N($2 + R(poly 275 -250 525 2250) + R(poly 220 820 580 1180) + R(poly 275 2000 525 3600) + R(poly 275 -800 525 800) + R(diff_cont -910 2490 -690 2710) + R(diff_cont -910 2890 -690 3110) + R(diff_cont -910 -310 -690 -90) + R(diff_cont -910 90 -690 310) + R(poly_cont 290 890 510 1110) + R(metal1 -800 820 580 1180) + R(metal1 -980 -420 -620 2420) + R(metal1 -980 2420 -620 3180) + R(metal1 -980 -380 -620 380) + R(psd -1050 2325 -525 3275) + R(nsd -1050 -475 -525 475) + ) + N(OUT + R(diff_cont 690 2890 910 3110) + R(diff_cont 690 2490 910 2710) + R(diff_cont 690 90 910 310) + R(diff_cont 690 -310 910 -90) + Q(metal1 800 20 800 380 940 380 940 1620 620 1620 620 2420 980 2420 980 1980 1300 1980 1300 20) + R(metal1 620 2420 980 3180) + R(metal1 620 -380 980 380) + R(metal1_lbl 799 1799 801 1801) + R(psd 525 2325 1050 3275) + R(nsd 525 -475 1050 475) + ) + N($4 + R(diff_cont -110 -310 110 -90) + R(diff_cont -110 90 110 310) + R(diff_cont -110 90 110 310) + R(diff_cont -110 -310 110 -90) + R(metal1 -180 -380 180 380) + R(metal1 -180 -380 180 380) + R(via1 -125 -325 125 -75) + R(via1 -125 75 125 325) + R(metal2 -1400 -450 1400 450) + R(nsd -275 -475 275 475) + ) + N($5 + R(diff_cont -110 2490 110 2710) + R(diff_cont -110 2890 110 3110) + R(diff_cont -110 2890 110 3110) + R(diff_cont -110 2490 110 2710) + R(metal1 -180 2420 180 3180) + R(metal1 -180 2420 180 3180) + R(via1 -125 2475 125 2725) + R(via1 -125 2875 125 3125) + R(metal2 -1400 2350 1400 3250) + R(psd -275 2325 275 3275) + ) + P(IN IN) + P($1 $2) + P(OUT OUT) + P($3 $4) + P($4 $5) + D($1 D$PMOS + Y(-400 2800) + E(L 0.25) + E(W 0.95) + E(AS 0.49875) + E(AD 0.26125) + T(S $2) + T(G IN) + T(D $5) + ) + D($2 D$PMOS$1 + Y(400 2800) + E(L 0.25) + E(W 0.95) + E(AS 0.26125) + E(AD 0.49875) + T(S $5) + T(G $2) + T(D OUT) + ) + D($3 D$NMOS + Y(-400 0) + E(L 0.25) + E(W 0.95) + E(AS 0.49875) + E(AD 0.26125) + T(S $2) + T(G IN) + T(D $4) + ) + D($4 D$NMOS$1 + Y(400 0) + E(L 0.25) + E(W 0.95) + E(AS 0.26125) + E(AD 0.49875) + T(S $4) + T(G $2) + T(D OUT) + ) +) +X(RINGO + N(FB + R(diff_cont 22850 2490 23070 2710) + R(diff_cont 22850 2890 23070 3110) + R(diff_cont 22850 -310 23070 -90) + R(diff_cont 22850 90 23070 310) + R(metal1 -1700 1620 -1340 1980) + R(via1 -1645 1675 -1395 1925) + R(via1 22835 1675 23085 1925) + R(metal2 -1720 1600 23160 2000) + R(metal2_lbl -1 1799 1 1801) + ) + N(OSC + R(diff_cont 24450 2890 24670 3110) + R(diff_cont 24450 2490 24670 2710) + R(diff_cont 24450 90 24670 310) + R(diff_cont 24450 -310 24670 -90) + R(via1 24435 1675 24685 1925) + R(metal2 24360 1600 24760 2000) + R(metal2_lbl 24559 1799 24561 1801) + ) + N(VSS + R(diff_cont 2530 -310 2750 -90) + R(diff_cont 2530 90 2750 310) + R(diff_cont 2530 90 2750 310) + R(diff_cont 2530 -310 2750 -90) + R(diff_cont -110 -310 110 -90) + R(diff_cont -110 90 110 310) + R(diff_cont -110 90 110 310) + R(diff_cont -110 -310 110 -90) + R(diff_cont 5170 -310 5390 -90) + R(diff_cont 5170 90 5390 310) + R(diff_cont 5170 90 5390 310) + R(diff_cont 5170 -310 5390 -90) + R(diff_cont 7810 -310 8030 -90) + R(diff_cont 7810 90 8030 310) + R(diff_cont 7810 90 8030 310) + R(diff_cont 7810 -310 8030 -90) + R(diff_cont 10450 -310 10670 -90) + R(diff_cont 10450 90 10670 310) + R(diff_cont 10450 90 10670 310) + R(diff_cont 10450 -310 10670 -90) + R(diff_cont 13090 -310 13310 -90) + R(diff_cont 13090 90 13310 310) + R(diff_cont 13090 90 13310 310) + R(diff_cont 13090 -310 13310 -90) + R(diff_cont 15730 -310 15950 -90) + R(diff_cont 15730 90 15950 310) + R(diff_cont 15730 90 15950 310) + R(diff_cont 15730 -310 15950 -90) + R(diff_cont 18370 -310 18590 -90) + R(diff_cont 18370 90 18590 310) + R(diff_cont 18370 90 18590 310) + R(diff_cont 18370 -310 18590 -90) + R(diff_cont 21010 -310 21230 -90) + R(diff_cont 21010 90 21230 310) + R(diff_cont 21010 90 21230 310) + R(diff_cont 21010 -310 21230 -90) + R(diff_cont 23650 -310 23870 -90) + R(diff_cont 23650 90 23870 310) + R(diff_cont 23650 90 23870 310) + R(diff_cont 23650 -310 23870 -90) + R(metal1 2460 -380 2820 380) + R(metal1 2460 -380 2820 380) + R(metal1 -180 -380 180 380) + R(metal1 -180 -380 180 380) + R(metal1 5100 -380 5460 380) + R(metal1 5100 -380 5460 380) + R(metal1 7740 -380 8100 380) + R(metal1 7740 -380 8100 380) + R(metal1 10380 -380 10740 380) + R(metal1 10380 -380 10740 380) + R(metal1 13020 -380 13380 380) + R(metal1 13020 -380 13380 380) + R(metal1 15660 -380 16020 380) + R(metal1 15660 -380 16020 380) + R(metal1 18300 -380 18660 380) + R(metal1 18300 -380 18660 380) + R(metal1 20940 -380 21300 380) + R(metal1 20940 -380 21300 380) + R(metal1 23580 -380 23940 380) + R(metal1 23580 -380 23940 380) + R(metal2_lbl -1 -1 1 1) + ) + N(VDD + R(diff_cont 2530 2490 2750 2710) + R(diff_cont 2530 2890 2750 3110) + R(diff_cont 2530 2890 2750 3110) + R(diff_cont 2530 2490 2750 2710) + R(diff_cont -110 2490 110 2710) + R(diff_cont -110 2890 110 3110) + R(diff_cont -110 2890 110 3110) + R(diff_cont -110 2490 110 2710) + R(diff_cont 5170 2490 5390 2710) + R(diff_cont 5170 2890 5390 3110) + R(diff_cont 5170 2890 5390 3110) + R(diff_cont 5170 2490 5390 2710) + R(diff_cont 7810 2490 8030 2710) + R(diff_cont 7810 2890 8030 3110) + R(diff_cont 7810 2890 8030 3110) + R(diff_cont 7810 2490 8030 2710) + R(diff_cont 10450 2490 10670 2710) + R(diff_cont 10450 2890 10670 3110) + R(diff_cont 10450 2890 10670 3110) + R(diff_cont 10450 2490 10670 2710) + R(diff_cont 13090 2490 13310 2710) + R(diff_cont 13090 2890 13310 3110) + R(diff_cont 13090 2890 13310 3110) + R(diff_cont 13090 2490 13310 2710) + R(diff_cont 15730 2490 15950 2710) + R(diff_cont 15730 2890 15950 3110) + R(diff_cont 15730 2890 15950 3110) + R(diff_cont 15730 2490 15950 2710) + R(diff_cont 18370 2490 18590 2710) + R(diff_cont 18370 2890 18590 3110) + R(diff_cont 18370 2890 18590 3110) + R(diff_cont 18370 2490 18590 2710) + R(diff_cont 21010 2490 21230 2710) + R(diff_cont 21010 2890 21230 3110) + R(diff_cont 21010 2890 21230 3110) + R(diff_cont 21010 2490 21230 2710) + R(diff_cont 23650 2490 23870 2710) + R(diff_cont 23650 2890 23870 3110) + R(diff_cont 23650 2890 23870 3110) + R(diff_cont 23650 2490 23870 2710) + R(metal1 2460 2420 2820 3180) + R(metal1 2460 2420 2820 3180) + R(metal1 -180 2420 180 3180) + R(metal1 -180 2420 180 3180) + R(metal1 5100 2420 5460 3180) + R(metal1 5100 2420 5460 3180) + R(metal1 7740 2420 8100 3180) + R(metal1 7740 2420 8100 3180) + R(metal1 10380 2420 10740 3180) + R(metal1 10380 2420 10740 3180) + R(metal1 13020 2420 13380 3180) + R(metal1 13020 2420 13380 3180) + R(metal1 15660 2420 16020 3180) + R(metal1 15660 2420 16020 3180) + R(metal1 18300 2420 18660 3180) + R(metal1 18300 2420 18660 3180) + R(metal1 20940 2420 21300 3180) + R(metal1 20940 2420 21300 3180) + R(metal1 23580 2420 23940 3180) + R(metal1 23580 2420 23940 3180) + R(metal2_lbl -1 2799 1 2801) + ) + N($I19 + R(diff_cont 690 2890 910 3110) + R(diff_cont 690 2490 910 2710) + R(diff_cont 690 90 910 310) + R(diff_cont 690 -310 910 -90) + ) + N($I8 + R(diff_cont 21810 2890 22030 3110) + R(diff_cont 21810 2490 22030 2710) + R(diff_cont 21810 90 22030 310) + R(diff_cont 21810 -310 22030 -90) + ) + N($I7 + R(diff_cont 19170 2890 19390 3110) + R(diff_cont 19170 2490 19390 2710) + R(diff_cont 19170 90 19390 310) + R(diff_cont 19170 -310 19390 -90) + ) + N($I6 + R(diff_cont 16530 2890 16750 3110) + R(diff_cont 16530 2490 16750 2710) + R(diff_cont 16530 90 16750 310) + R(diff_cont 16530 -310 16750 -90) + ) + N($I5 + R(diff_cont 13890 2890 14110 3110) + R(diff_cont 13890 2490 14110 2710) + R(diff_cont 13890 90 14110 310) + R(diff_cont 13890 -310 14110 -90) + ) + N($I4 + R(diff_cont 11250 2890 11470 3110) + R(diff_cont 11250 2490 11470 2710) + R(diff_cont 11250 90 11470 310) + R(diff_cont 11250 -310 11470 -90) + ) + N($I3 + R(diff_cont 8610 2890 8830 3110) + R(diff_cont 8610 2490 8830 2710) + R(diff_cont 8610 90 8830 310) + R(diff_cont 8610 -310 8830 -90) + ) + N($I2 + R(diff_cont 5970 2890 6190 3110) + R(diff_cont 5970 2490 6190 2710) + R(diff_cont 5970 90 6190 310) + R(diff_cont 5970 -310 6190 -90) + ) + N($I1 + R(diff_cont 3330 2890 3550 3110) + R(diff_cont 3330 2490 3550 2710) + R(diff_cont 3330 90 3550 310) + R(diff_cont 3330 -310 3550 -90) + ) + P(FB FB) + P(OSC OSC) + P(VSS VSS) + P(VDD VDD) + X($1 INV2 Y(23760 0) + P(IN $I8) + P($1 FB) + P(OUT OSC) + P($3 VSS) + P($4 VDD) + ) + X($2 INV2 Y(0 0) + P(IN FB) + P(OUT $I19) + P($3 VSS) + P($4 VDD) + ) + X($3 INV2 Y(2640 0) + P(IN $I19) + P(OUT $I1) + P($3 VSS) + P($4 VDD) + ) + X($4 INV2 Y(5280 0) + P(IN $I1) + P(OUT $I2) + P($3 VSS) + P($4 VDD) + ) + X($5 INV2 Y(7920 0) + P(IN $I2) + P(OUT $I3) + P($3 VSS) + P($4 VDD) + ) + X($6 INV2 Y(10560 0) + P(IN $I3) + P(OUT $I4) + P($3 VSS) + P($4 VDD) + ) + X($7 INV2 Y(13200 0) + P(IN $I4) + P(OUT $I5) + P($3 VSS) + P($4 VDD) + ) + X($8 INV2 Y(15840 0) + P(IN $I5) + P(OUT $I6) + P($3 VSS) + P($4 VDD) + ) + X($9 INV2 Y(18480 0) + P(IN $I6) + P(OUT $I7) + P($3 VSS) + P($4 VDD) + ) + X($10 INV2 Y(21120 0) + P(IN $I7) + P(OUT $I8) + P($3 VSS) + P($4 VDD) + ) +)