From c80e335cd6f39330de655919373206e2afe89899 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 7 Jan 2019 02:08:59 +0100 Subject: [PATCH] WIP: global nets integration in cluster builder. --- src/db/db/dbHierNetworkProcessor.cc | 387 +++++++++++++----- src/db/db/dbHierNetworkProcessor.h | 21 + src/db/db/dbLayoutToNetlist.cc | 6 +- src/db/db/dbLayoutToNetlist.h | 5 + src/db/db/dbNetlist.cc | 14 - src/db/db/dbNetlist.h | 26 -- src/db/db/dbNetlistDeviceClasses.cc | 16 - src/db/db/dbNetlistDeviceClasses.h | 11 +- src/db/db/dbNetlistDeviceExtractorClasses.cc | 36 +- src/db/db/dbNetlistDeviceExtractorClasses.h | 34 +- src/db/db/dbNetlistExtractor.cc | 78 +--- src/db/db/gsiDeclDbHierNetworkProcessor.cc | 5 +- src/db/db/gsiDeclDbNetlist.cc | 58 --- .../unit_tests/dbHierNetworkProcessorTests.cc | 34 +- src/db/unit_tests/dbLayoutToNetlistTests.cc | 364 ++++++++++++++-- src/db/unit_tests/dbNetlistExtractorTests.cc | 8 +- src/db/unit_tests/dbNetlistTests.cc | 50 --- testdata/algo/hc_test_au16.gds | Bin 0 -> 5570 bytes testdata/algo/hc_test_au16b.gds | Bin 0 -> 4874 bytes testdata/algo/hc_test_l16.gds | Bin 0 -> 1162 bytes testdata/ruby/dbNetlist.rb | 7 - 21 files changed, 749 insertions(+), 411 deletions(-) create mode 100644 testdata/algo/hc_test_au16.gds create mode 100644 testdata/algo/hc_test_au16b.gds create mode 100644 testdata/algo/hc_test_l16.gds diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index dccedd970..587f83790 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -104,17 +104,8 @@ Connectivity::end_global_connections (unsigned int l) const size_t Connectivity::connect_global (unsigned int l, const std::string &gn) { - for (std::vector::const_iterator i = m_global_net_names.begin (); i != m_global_net_names.end (); ++i) { - if (*i == gn) { - size_t id = i - m_global_net_names.begin (); - m_global_connections [l].insert (id); - return id; - } - } - - size_t id = m_global_net_names.size (); + size_t id = global_net_id (gn); m_global_connections [l].insert (id); - m_global_net_names.push_back (gn); return id; } @@ -131,6 +122,21 @@ Connectivity::global_net_name (size_t id) const return m_global_net_names [id]; } +size_t +Connectivity::global_net_id (const std::string &gn) +{ + for (std::vector::const_iterator i = m_global_net_names.begin (); i != m_global_net_names.end (); ++i) { + if (*i == gn) { + size_t id = i - m_global_net_names.begin (); + return id; + } + } + + size_t id = m_global_net_names.size (); + m_global_net_names.push_back (gn); + return id; +} + Connectivity::layer_iterator Connectivity::begin_layers () const { @@ -225,6 +231,7 @@ local_cluster::clear () m_size = 0; m_bbox = box_type (); m_attrs.clear (); + m_global_nets.clear (); } template @@ -262,6 +269,7 @@ local_cluster::join_with (const local_cluster &other) } m_attrs.insert (other.m_attrs.begin (), other.m_attrs.end ()); + m_global_nets.insert (other.m_global_nets.begin (), other.m_global_nets.end ()); m_size += other.size (); m_needs_update = true; @@ -1450,95 +1458,7 @@ private: */ ClusterInstance make_path (id_type id, const std::vector &path) const { - std::vector::const_iterator p = path.end (); - tl_assert (p != path.begin ()); - - while (true) { - - --p; - - ClusterInstance ci (id, *p); - if (p == path.begin ()) { - - // if we're attaching to a child which is root yet, we need to promote the - // cluster to the parent in all places - connected_clusters &child_cc = mp_tree->clusters_per_cell (p->inst_ptr.cell_index ()); - if (child_cc.is_root (id)) { - - const db::Cell &child_cell = mp_layout->cell (p->inst_ptr.cell_index ()); - for (db::Cell::parent_inst_iterator pi = child_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { - - connected_clusters &parent_cc = mp_tree->clusters_per_cell (pi->parent_cell_index ()); - for (db::CellInstArray::iterator pii = pi->child_inst ().begin (); ! pii.at_end (); ++pii) { - - ClusterInstance ci2 (id, db::InstElement (pi->child_inst (), pii)); - if (mp_cell->cell_index () != pi->parent_cell_index () || ci != ci2) { - - id_type id_dummy = parent_cc.insert_dummy (); - parent_cc.add_connection (id_dummy, ci2); - - } - - } - - } - - child_cc.reset_root (id); - - } - - return ci; - - } - - db::cell_index_type pci = p [-1].inst_ptr.cell_index (); - connected_clusters &target_cc = mp_tree->clusters_per_cell (pci); - id_type parent_cluster = target_cc.find_cluster_with_connection (ci); - - if (parent_cluster > 0) { - - // taken parent - id = parent_cluster; - - } else { - - id_type id_new = 0; - - // if we're attaching to a child which is root yet, we need to promote the - // cluster to the parent in all places - connected_clusters &child_cc = mp_tree->clusters_per_cell (p->inst_ptr.cell_index ()); - if (child_cc.is_root (id)) { - - const db::Cell &child_cell = mp_layout->cell (p->inst_ptr.cell_index ()); - for (db::Cell::parent_inst_iterator pi = child_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { - - connected_clusters &parent_cc = mp_tree->clusters_per_cell (pi->parent_cell_index ()); - for (db::CellInstArray::iterator pii = pi->child_inst ().begin (); ! pii.at_end (); ++pii) { - - id_type id_dummy = parent_cc.insert_dummy (); - ClusterInstance ci2 (id, db::InstElement (pi->child_inst (), pii)); - parent_cc.add_connection (id_dummy, ci2); - - if (pci == pi->parent_cell_index () && ci == ci2) { - id_new = id_dummy; - } - - } - - } - - child_cc.reset_root (id); - - } - - // no parent -> create vertical connector - id = id_new; - tl_assert (id != 0); - - } - - } - + return mp_tree->make_path (*mp_layout, *mp_cell, id, path); } }; @@ -1565,6 +1485,120 @@ private: } +template +ClusterInstance +hier_clusters::make_path (const db::Layout &layout, const db::Cell &cell, size_t id, const std::vector &path) +{ + std::vector::const_iterator p = path.end (); + tl_assert (p != path.begin ()); + + while (true) { + + --p; + + ClusterInstance ci (id, *p); + if (p == path.begin ()) { + + // if we're attaching to a child which is root yet, we need to promote the + // cluster to the parent in all places + connected_clusters &child_cc = clusters_per_cell (p->inst_ptr.cell_index ()); + if (child_cc.is_root (id)) { + + const db::Cell &child_cell = layout.cell (p->inst_ptr.cell_index ()); + for (db::Cell::parent_inst_iterator pi = child_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { + + connected_clusters &parent_cc = clusters_per_cell (pi->parent_cell_index ()); + for (db::CellInstArray::iterator pii = pi->child_inst ().begin (); ! pii.at_end (); ++pii) { + + ClusterInstance ci2 (id, db::InstElement (pi->child_inst (), pii)); + if (cell.cell_index () != pi->parent_cell_index () || ci != ci2) { + + size_t id_dummy; + + const typename db::local_cluster::global_nets &gn = child_cc.cluster_by_id (id).get_global_nets (); + if (gn.empty ()) { + id_dummy = parent_cc.insert_dummy (); + } else { + local_cluster *lc = parent_cc.insert (); + lc->set_global_nets (gn); + id_dummy = lc->id (); + } + + parent_cc.add_connection (id_dummy, ci2); + + } + + } + + } + + child_cc.reset_root (id); + + } + + return ci; + + } + + db::cell_index_type pci = p [-1].inst_ptr.cell_index (); + connected_clusters &target_cc = clusters_per_cell (pci); + size_t parent_cluster = target_cc.find_cluster_with_connection (ci); + + if (parent_cluster > 0) { + + // taken parent + id = parent_cluster; + + } else { + + size_t id_new = 0; + + // if we're attaching to a child which is root yet, we need to promote the + // cluster to the parent in all places + connected_clusters &child_cc = clusters_per_cell (p->inst_ptr.cell_index ()); + if (child_cc.is_root (id)) { + + const db::Cell &child_cell = layout.cell (p->inst_ptr.cell_index ()); + for (db::Cell::parent_inst_iterator pi = child_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { + + connected_clusters &parent_cc = clusters_per_cell (pi->parent_cell_index ()); + for (db::CellInstArray::iterator pii = pi->child_inst ().begin (); ! pii.at_end (); ++pii) { + + size_t id_dummy; + + const typename db::local_cluster::global_nets &gn = child_cc.cluster_by_id (id).get_global_nets (); + if (gn.empty ()) { + id_dummy = parent_cc.insert_dummy (); + } else { + local_cluster *lc = parent_cc.insert (); + lc->set_global_nets (gn); + id_dummy = lc->id (); + } + + ClusterInstance ci2 (id, db::InstElement (pi->child_inst (), pii)); + parent_cc.add_connection (id_dummy, ci2); + + if (pci == pi->parent_cell_index () && ci == ci2) { + id_new = id_dummy; + } + + } + + } + + child_cc.reset_root (id); + + } + + // no parent -> create vertical connector + id = id_new; + tl_assert (id != 0); + + } + + } +} + template void hier_clusters::do_build (cell_clusters_box_converter &cbc, const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn) @@ -1648,6 +1682,83 @@ hier_clusters::build_hier_connections_for_cells (cell_clusters_box_converter< } } +namespace { + +class GlobalNetClusterMaker +{ +public: + typedef std::pair, std::set > entry_type; + typedef std::list entry_list; + typedef entry_list::const_iterator entry_iterator; + + void + add (const std::set &global_nets, size_t cluster_id) + { + add (global_nets, ClusterInstance (cluster_id, db::InstElement ())); + } + + void + add (const std::set &global_nets, const ClusterInstance &inst) + { + if (global_nets.empty ()) { + return; + } + + std::set::const_iterator g0 = global_nets.begin (); + + std::map::iterator k = m_global_net_to_entries.find (*g0); + if (k == m_global_net_to_entries.end ()) { + + m_entries.push_back (entry_type ()); + m_entries.back ().first.insert (*g0); + + k = m_global_net_to_entries.insert (std::make_pair (*g0, --m_entries.end ())).first; + + } + + k->second->second.insert (inst); + + for (std::set::const_iterator g = ++g0; g != global_nets.end (); ++g) { + + std::map::iterator j = m_global_net_to_entries.find (*g); + if (j == m_global_net_to_entries.end ()) { + + k->second->first.insert (*g); + k->second->second.insert (inst); + + m_global_net_to_entries.insert (std::make_pair (*g, k->second)); + + } else if (k->second != j->second) { + + // joining required + k->second->first.insert (j->second->first.begin (), j->second->first.end ()); + k->second->second.insert (j->second->second.begin (), j->second->second.end ()); + + m_entries.erase (j->second); + j->second = k->second; + + } + + } + } + + entry_iterator begin () const + { + return m_entries.begin (); + } + + entry_iterator end () const + { + return m_entries.end (); + } + +private: + entry_list m_entries; + std::map m_global_net_to_entries; +}; + +} + template void hier_clusters::build_hier_connections (cell_clusters_box_converter &cbc, const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn) @@ -1662,7 +1773,7 @@ hier_clusters::build_hier_connections (cell_clusters_box_converter &cbc, c // NOTE: this is a receiver for both the child-to-child and // local to child interactions. - hc_receiver rec (layout, cell, local, *this, cbc, conn); + std::auto_ptr > rec (new hc_receiver (layout, cell, local, *this, cbc, conn)); cell_inst_clusters_box_converter cibc (cbc); // The box scanner needs pointers so we have to first store the instances @@ -1694,7 +1805,7 @@ hier_clusters::build_hier_connections (cell_clusters_box_converter &cbc, c bs.insert (inst.operator-> (), 0); } - bs.process (rec, 1 /*touching*/, cibc); + bs.process (*rec, 1 /*touching*/, cibc); } // handle local to instance connections @@ -1729,11 +1840,79 @@ hier_clusters::build_hier_connections (cell_clusters_box_converter &cbc, c bs2.insert2 (inst.operator-> (), 0); } - bs2.process (rec, 1 /*touching*/, local_cluster_box_convert (), cibc); + bs2.process (*rec, 1 /*touching*/, local_cluster_box_convert (), cibc); } - // finally join local clusters which got connected by child clusters - rec.join_superclusters (); + // join local clusters which got connected by child clusters + rec->join_superclusters (); + rec.reset (0); + + // finally connect global nets + { + static std::string desc = tl::to_string (tr ("Global net treatment")); + tl::SelfTimer timer (tl::verbosity () >= 51, desc); + + GlobalNetClusterMaker global_net_clusters; + + // insert the global nets from the subcircuits which need connection + + for (std::vector::const_iterator inst = inst_storage.begin (); inst != inst_storage.end (); ++inst) { + + const db::connected_clusters &cc = m_per_cell_clusters [inst->cell_index ()]; + for (typename db::connected_clusters::const_iterator cl = cc.begin (); cl != cc.end (); ++cl) { + + if (! cl->get_global_nets ().empty () && cc.is_root (cl->id ())) { + for (db::Instance::cell_inst_array_type::iterator i = inst->begin (); !i.at_end (); ++i) { + global_net_clusters.add (cl->get_global_nets (), db::ClusterInstance (cl->id (), db::InstElement (*inst, i))); + } + } + + } + } + + // insert the global nets from here + + for (typename db::connected_clusters::const_iterator cl = local.begin (); cl != local.end (); ++cl) { + if (! cl->get_global_nets ().empty ()) { + global_net_clusters.add (cl->get_global_nets (), db::ClusterInstance (cl->id (), db::InstElement ())); + } + } + + // now global_net_clusters knows what clusters need to be made for the global nets + + for (GlobalNetClusterMaker::entry_iterator ge = global_net_clusters.begin (); ge != global_net_clusters.end (); ++ge) { + + db::local_cluster *gc = local.insert (); + gc->set_global_nets (ge->first); + + for (std::set::const_iterator ci = ge->second.begin (); ci != ge->second.end (); ++ci) { + + if (ci->inst ().array_inst.at_end ()) { + + local.join_cluster_with (gc->id (), ci->id ()); + local.remove_cluster (ci->id ()); + + } else { + + std::vector p; + p.push_back (ci->inst ()); + ClusterInstance k = make_path (layout, cell, ci->id (), p); + + size_t other_id = local.find_cluster_with_connection (k); + if (other_id) { + local.join_cluster_with (gc->id (), other_id); + local.remove_cluster (other_id); + } else { + local.add_connection (gc->id (), k); + } + + } + + } + + } + + } } template diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index e1bfe3746..b33801e9f 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -99,6 +99,11 @@ public: */ const std::string &global_net_name (size_t id) const; + /** + * @brief Gets the global net ID for the given name + */ + size_t global_net_id (const std::string &gn); + /** * @brief Begin iterator for the layers involved */ @@ -306,6 +311,14 @@ public: return m_global_nets.end (); } + /** + * @brief Gets the global nets set + */ + const global_nets &get_global_nets () const + { + return m_global_nets; + } + /** * @brief Sets the global nets */ @@ -767,6 +780,14 @@ public: */ void clear (); + /** + * @brief Makes a valid path to a child cluster + * + * Cluster connections can only cross one level of hierarchy. This method + * creates necessary dummy entries for the given path. + */ + ClusterInstance make_path (const db::Layout &layout, const db::Cell &cell, size_t id, const std::vector &path); + private: void build_local_cluster (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn); void build_hier_connections (cell_clusters_box_converter &cbc, const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn); diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 2c4a09424..f6cceff9c 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -170,6 +170,11 @@ const std::string &LayoutToNetlist::global_net_name (size_t id) const return m_conn.global_net_name (id); } +size_t LayoutToNetlist::global_net_id (const std::string &name) +{ + return m_conn.global_net_id (name); +} + void LayoutToNetlist::extract_netlist () { if (m_netlist_extracted) { @@ -275,7 +280,6 @@ static void deliver_shapes_of_net_nonrecursive (const db::NetlistExtractor &nete tl_assert (circuit != 0); db::cell_index_type ci = circuit->cell_index (); - const db::local_cluster &lc = netex.clusters ().clusters_per_cell (ci).cluster_by_id (net.cluster_id ()); for (db::local_cluster::shape_iterator s = lc.begin (layer_id); !s.at_end (); ++s) { diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index c43cac8fb..ad6c8f033 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -176,6 +176,11 @@ public: */ const std::string &global_net_name (size_t id) const; + /** + * @brief Gets the global net ID for a given name name + */ + size_t global_net_id (const std::string &name); + /** * @brief Runs the netlist extraction * See the class description for more details. diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index eeb88a042..914f6a882 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -113,22 +113,8 @@ const Net *Device::net_for_terminal (size_t terminal_id) const return 0; } -void Device::connect_terminal_global (size_t terminal_id, size_t global_net_id) -{ - connect_terminal (terminal_id, 0); - m_global_connections.push_back (std::make_pair (terminal_id, global_net_id)); -} - void Device::connect_terminal (size_t terminal_id, Net *net) { - for (size_t i = 0; i < m_global_connections.size (); ) { - if (m_global_connections [i].first == terminal_id) { - m_global_connections.erase (m_global_connections.begin () + i); - } else { - ++i; - } - } - if (net_for_terminal (terminal_id) == net) { return; } diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index 3af81c79c..1c6acb2ad 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -884,31 +884,6 @@ public: return m_name; } - /** - * @brief Gets the global connections iterator (begin) - * Global connections are terminals attached to a global net. - * This iterator delivers a pair of terminal ID (first) - * and global net ID (second). - * See Connectivity for the definition of the global net ID. - */ - global_connections_iterator begin_global_connections () const - { - return m_global_connections.begin (); - } - - /** - * @brief Gets the global connections iterator (end) - */ - global_connections_iterator end_global_connections () const - { - return m_global_connections.end (); - } - - /** - * @brief Connects the given terminal to the given global net - */ - void connect_terminal_global (size_t terminal_id, size_t global_net_id); - /** * @brief Gets the net attached to a specific terminal * Returns 0 if no net is attached. @@ -966,7 +941,6 @@ private: std::vector m_parameters; size_t m_id; Circuit *mp_circuit; - global_connections m_global_connections; /** * @brief Sets the terminal reference for a specific terminal diff --git a/src/db/db/dbNetlistDeviceClasses.cc b/src/db/db/dbNetlistDeviceClasses.cc index 11f125a71..7b61d6a09 100644 --- a/src/db/db/dbNetlistDeviceClasses.cc +++ b/src/db/db/dbNetlistDeviceClasses.cc @@ -250,27 +250,11 @@ bool DeviceClassMOS3Transistor::combine_devices (Device *a, Device *b) const // ------------------------------------------------------------------------------------ // DeviceClassMOS4Transistor implementation -DB_PUBLIC size_t DeviceClassMOS4Transistor::param_id_L = 0; -DB_PUBLIC size_t DeviceClassMOS4Transistor::param_id_W = 1; -DB_PUBLIC size_t DeviceClassMOS4Transistor::param_id_AS = 2; -DB_PUBLIC size_t DeviceClassMOS4Transistor::param_id_AD = 3; - -DB_PUBLIC size_t DeviceClassMOS4Transistor::terminal_id_S = 0; -DB_PUBLIC size_t DeviceClassMOS4Transistor::terminal_id_G = 1; -DB_PUBLIC size_t DeviceClassMOS4Transistor::terminal_id_D = 2; DB_PUBLIC size_t DeviceClassMOS4Transistor::terminal_id_B = 3; DeviceClassMOS4Transistor::DeviceClassMOS4Transistor () { - add_terminal_definition (db::DeviceTerminalDefinition ("S", "Source")); - add_terminal_definition (db::DeviceTerminalDefinition ("G", "Gate")); - add_terminal_definition (db::DeviceTerminalDefinition ("D", "Drain")); add_terminal_definition (db::DeviceTerminalDefinition ("B", "Bulk")); - - add_parameter_definition (db::DeviceParameterDefinition ("L", "Gate length (micrometer)", 0.0)); - add_parameter_definition (db::DeviceParameterDefinition ("W", "Gate width (micrometer)", 0.0)); - add_parameter_definition (db::DeviceParameterDefinition ("AS", "Source area (square micrometer)", 0.0)); - add_parameter_definition (db::DeviceParameterDefinition ("AD", "Drain area (square micrometer)", 0.0)); } bool DeviceClassMOS4Transistor::combine_devices (Device *a, Device *b) const diff --git a/src/db/db/dbNetlistDeviceClasses.h b/src/db/db/dbNetlistDeviceClasses.h index dccc580d9..95408a2dd 100644 --- a/src/db/db/dbNetlistDeviceClasses.h +++ b/src/db/db/dbNetlistDeviceClasses.h @@ -181,19 +181,11 @@ public: * terminal for the bulk. */ class DB_PUBLIC DeviceClassMOS4Transistor - : public db::DeviceClass + : public DeviceClassMOS3Transistor { public: DeviceClassMOS4Transistor (); - static size_t param_id_L; - static size_t param_id_W; - static size_t param_id_AS; - static size_t param_id_AD; - - static size_t terminal_id_S; - static size_t terminal_id_G; - static size_t terminal_id_D; static size_t terminal_id_B; virtual db::DeviceClass *clone () const @@ -202,7 +194,6 @@ public: } virtual bool combine_devices (Device *a, Device *b) const; - virtual bool supports_parallel_combination () const { return true; } }; } diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.cc b/src/db/db/dbNetlistDeviceExtractorClasses.cc index 0eb21f6cc..0d3dafbd9 100644 --- a/src/db/db/dbNetlistDeviceExtractorClasses.cc +++ b/src/db/db/dbNetlistDeviceExtractorClasses.cc @@ -24,12 +24,12 @@ #include "dbNetlistDeviceExtractorClasses.h" #include "dbNetlistDeviceClasses.h" -// --------------------------------------------------------------------------------- -// NetlistDeviceExtractorMOS3Transistor implementation - namespace db { +// --------------------------------------------------------------------------------- +// NetlistDeviceExtractorMOS3Transistor implementation + NetlistDeviceExtractorMOS3Transistor::NetlistDeviceExtractorMOS3Transistor (const std::string &name) : db::NetlistDeviceExtractor (name) { @@ -47,7 +47,7 @@ void NetlistDeviceExtractorMOS3Transistor::setup () db::Connectivity NetlistDeviceExtractorMOS3Transistor::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const { - tl_assert (layers.size () == 3); + tl_assert (layers.size () >= 3); unsigned int diff = layers [0]; unsigned int gate = layers [1]; @@ -117,6 +117,9 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector & /*layer_geometry*/, db::Device *device) +{ + unsigned int well_geometry_index = 3; + define_terminal (device, db::DeviceClassMOS4Transistor::terminal_id_B, well_geometry_index, rgate); +} + } diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.h b/src/db/db/dbNetlistDeviceExtractorClasses.h index 32e2e538a..2a2b3cb35 100644 --- a/src/db/db/dbNetlistDeviceExtractorClasses.h +++ b/src/db/db/dbNetlistDeviceExtractorClasses.h @@ -35,7 +35,7 @@ namespace db * The device is defined by two basic input layers: the diffusion area * (source and drain) and the gate area. It requires a third layer * (poly) to put the gate terminals on. The separation between poly - * and allows separating the device recognition layer (gate) from the + * and gate allows separating the device recognition layer (gate) from the * conductive layer. * * The device class produced by this extractor is DeviceClassMOS3Transistor. @@ -56,13 +56,43 @@ public: protected: /** - * @brief A cappback when the device is produced + * @brief A callback when the device is produced * This callback is provided as a debugging port */ virtual void device_out (const db::Device * /*device*/, const db::Region & /*diff*/, const db::Region & /*gate*/) { // .. no specific implementation .. } + + /** + * @brief Allow derived classes to modify the device + */ + virtual void modify_device (const db::Polygon & /*rgate*/, const std::vector & /*layer_geometry*/, db::Device * /*device*/) + { + // .. no specific implementation .. + } + +}; + +/** + * @brief A device extractor for a four-terminal MOS transistor + * + * This class is like the MOS3Transistor extractor, but requires a forth + * input layer (Well). This layer will be used to output the bulk terminal. + * + * The device class produced by this extractor is DeviceClassMOS4Transistor. + * The extractor extracts the four parameters of this class: L, W, AS and AD. + */ +class DB_PUBLIC NetlistDeviceExtractorMOS4Transistor + : public NetlistDeviceExtractorMOS3Transistor +{ +public: + NetlistDeviceExtractorMOS4Transistor (const std::string &name); + + virtual void setup (); + +private: + virtual void modify_device (const db::Polygon &rgate, const std::vector &layer_geometry, db::Device *device); }; } diff --git a/src/db/db/dbNetlistExtractor.cc b/src/db/db/dbNetlistExtractor.cc index 7fe733bbf..38ae498df 100644 --- a/src/db/db/dbNetlistExtractor.cc +++ b/src/db/db/dbNetlistExtractor.cc @@ -65,8 +65,6 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect } std::map > pins_per_cluster_per_cell; - std::map > global_nets_per_cell; - for (db::Layout::bottom_up_const_iterator cid = layout.begin_bottom_up (); cid != layout.end_bottom_up (); ++cid) { const connected_clusters_type &clusters = m_net_clusters.clusters_per_cell (*cid); @@ -89,7 +87,6 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect circuit = k->second; } - std::map &global_nets = global_nets_per_cell [*cid]; std::map &c2p = pins_per_cluster_per_cell [*cid]; std::map subcircuits; @@ -100,12 +97,8 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect net->set_cluster_id (*c); circuit->add_net (net); - const db::local_cluster &cluster = clusters.cluster_by_id (*c); - - // collect global net assignments from clusters - for (std::set::const_iterator g = cluster.begin_global_nets (); g != cluster.end_global_nets (); ++g) { - tl_assert (global_nets.find (*g) == global_nets.end ()); - global_nets.insert (std::make_pair (*g, net)); + const db::local_cluster::global_nets &gn = clusters.cluster_by_id (*c).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); } @@ -134,73 +127,6 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect } - // make global net connections for devices - for (db::Circuit::device_iterator d = circuit->begin_devices (); d != circuit->end_devices (); ++d) { - - for (db::Device::global_connections_iterator g = d->begin_global_connections (); g != d->end_global_connections (); ++g) { - - db::Net *&net = global_nets [g->second]; - if (! net) { - net = new db::Net (conn.global_net_name (g->second)); - circuit->add_net (net); - } - - net->add_terminal (db::NetTerminalRef (d.operator-> (), g->first)); - - } - - } - - // if any of the subcircuits has global nets which this circuit doesn't have, propagate them - - std::set seen; - std::set global_nets_of_subcircuits; - for (db::Circuit::subcircuit_iterator sc = circuit->begin_subcircuits (); sc != circuit->end_subcircuits (); ++sc) { - - db::Circuit *subcircuit = sc->circuit_ref (); - if (seen.find (subcircuit) == seen.end ()) { - - seen.insert (subcircuit); - - const std::map &sc_gn = global_nets_per_cell [subcircuit->cell_index ()]; - for (std::map::const_iterator g = sc_gn.begin (); g != sc_gn.end (); ++g) { - global_nets_of_subcircuits.insert (g->first); - } - - } - - } - - for (std::set::const_iterator g = global_nets_of_subcircuits.begin (); g != global_nets_of_subcircuits.end (); ++g) { - - } - - // make the global net connections into subcircuits - if necessary by creating pins into the subcircuit - for (db::Circuit::subcircuit_iterator sc = circuit->begin_subcircuits (); sc != circuit->end_subcircuits (); ++sc) { - - db::Circuit *subcircuit = sc->circuit_ref (); - - const std::map &sc_gn = global_nets_per_cell [subcircuit->cell_index ()]; - for (std::map::const_iterator g = global_nets.begin (); g != global_nets.end (); ++g) { - - std::map::const_iterator gg = sc_gn.find (g->first); - if (gg != sc_gn.end ()) { - - size_t pin_id = 0; - if (gg->second->pin_count () > 0) { - pin_id = gg->second->begin_pins ()->pin_id (); - } else { - pin_id = subcircuit->add_pin (conn.global_net_name (gg->first)).id (); - subcircuit->connect_pin (pin_id, gg->second); - } - g->second->add_subcircuit_pin (db::NetSubcircuitPinRef (sc.operator-> (), pin_id)); - - } - - } - - } - } } diff --git a/src/db/db/gsiDeclDbHierNetworkProcessor.cc b/src/db/db/gsiDeclDbHierNetworkProcessor.cc index 3537bf7e1..d9c794a0a 100644 --- a/src/db/db/gsiDeclDbHierNetworkProcessor.cc +++ b/src/db/db/gsiDeclDbHierNetworkProcessor.cc @@ -37,8 +37,11 @@ Class decl_dbConnectivity ("db", "Connectivity", "@brief Connects the given layer to the global net given by name.\n" "Returns the ID of the global net." ) + - gsi::method ("global", &db::Connectivity::global_net_name, gsi::arg ("global_net_id"), + gsi::method ("global_net_name", &db::Connectivity::global_net_name, gsi::arg ("global_net_id"), "@brief Gets the name for a given global net ID.\n" + ) + + gsi::method ("global_net_id", &db::Connectivity::global_net_id, gsi::arg ("global_net_name"), + "@brief Gets the ID for a given global net name.\n" ), "@brief This class specifies connections between different layers." "Connections are build using \\connect. There are basically two flavours of connections: intra-layer and inter-layer.\n" diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index 716f909fd..6f87c25ac 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -61,44 +61,6 @@ static void device_disconnect_terminal_by_name (db::Device *device, const std::s device_connect_terminal_by_name (device, terminal_name, 0); } -static tl::Variant device_terminal_for_global_net (const db::Device *device, size_t global_net) -{ - for (db::Device::global_connections_iterator g = device->begin_global_connections (); g != device->end_global_connections (); ++g) { - if (g->second == global_net) { - return tl::Variant (g->first); - } - } - return tl::Variant (); -} - -static tl::Variant device_global_net_for_terminal (const db::Device *device, size_t terminal_id) -{ - for (db::Device::global_connections_iterator g = device->begin_global_connections (); g != device->end_global_connections (); ++g) { - if (g->first == terminal_id) { - return tl::Variant (g->second); - } - } - return tl::Variant (); -} - -static tl::Variant device_global_net_for_terminal_name (const db::Device *device, const std::string &terminal_name) -{ - if (! device->device_class ()) { - throw tl::Exception (tl::to_string (tr ("Device does not have a device class"))); - } - size_t terminal_id = device->device_class ()->terminal_id_for_name (terminal_name); - return device_global_net_for_terminal (device, terminal_id); -} - -static void device_connect_terminal_global_by_name (db::Device *device, const std::string &terminal_name, size_t global_net) -{ - if (! device->device_class ()) { - throw tl::Exception (tl::to_string (tr ("Device does not have a device class"))); - } - size_t terminal_id = device->device_class ()->terminal_id_for_name (terminal_name); - device->connect_terminal_global (terminal_id, global_net); -} - Class decl_dbDevice ("db", "Device", gsi::method ("device_class", &db::Device::device_class, "@brief Gets the device class the device belongs to.\n" @@ -140,26 +102,6 @@ Class decl_dbDevice ("db", "Device", "@brief Disconnects the given terminal from any net.\n" "This version accepts a terminal name. If the name is not a valid terminal name, an exception is raised." ) + - gsi::method ("connect_terminal_global", &db::Device::connect_terminal_global, gsi::arg ("terminal_id"), gsi::arg ("global_net_id"), - "@brief Connects the given terminal to the given global net.\n" - "The global net ID is taken from \\Connectivity (connect_global, etc.).\n" - "If the terminal was already connected to another net, it will be disconnected from there." - ) + - gsi::method_ext ("connect_terminal_global", &device_connect_terminal_global_by_name, gsi::arg ("terminal_name"), gsi::arg ("global_net_id"), - "@brief Connects the given terminal to the given global net.\n" - "This version accepts a terminal name. If the name is not a valid terminal name, an exception is raised." - ) + - gsi::method_ext ("terminal_on_global_net", &device_terminal_for_global_net, gsi::arg ("global_net_id"), - "@brief Gets the terminal ID for the given global net or nil if no terminal is not that global net.\n" - "The global net ID is managed by the \\Connectivity object." - ) + - gsi::method_ext ("global_net_on_terminal", &device_global_net_for_terminal, gsi::arg ("terminal_id"), - "@brief Gets the global net ID for the given terminal ID or nil if the terminal is not connected to a global net.\n" - ) + - gsi::method_ext ("global_net_on_terminal", &device_global_net_for_terminal_name, gsi::arg ("terminal_name"), - "@brief Gets the global net ID for the given terminal name or nil if the terminal is not connected to a global net.\n" - "If the name is not a valid terminal name, an exception is raised." - ) + gsi::method ("parameter", (double (db::Device::*) (size_t) const) &db::Device::parameter_value, gsi::arg ("param_id"), "@brief Gets the parameter value for the given parameter ID." ) + diff --git a/src/db/unit_tests/dbHierNetworkProcessorTests.cc b/src/db/unit_tests/dbHierNetworkProcessorTests.cc index 8890780a6..8ef049e6f 100644 --- a/src/db/unit_tests/dbHierNetworkProcessorTests.cc +++ b/src/db/unit_tests/dbHierNetworkProcessorTests.cc @@ -877,17 +877,12 @@ static void copy_cluster_shapes (const std::string *&attrs, db::Shapes &out, db: static void run_hc_test (tl::TestBase *_this, const std::string &file, const std::string &au_file) { db::Layout ly; - unsigned int l0 = 0, l1 = 0, l2 = 0, l3 = 0; + unsigned int l1 = 0, l2 = 0, l3 = 0, l4 = 0; { db::LayerProperties p; db::LayerMap lmap; - p.layer = 0; - p.datatype = 0; - lmap.map (db::LDPair (p.layer, p.datatype), l0 = ly.insert_layer ()); - ly.set_properties (l0, p); - p.layer = 1; p.datatype = 0; lmap.map (db::LDPair (p.layer, p.datatype), l1 = ly.insert_layer ()); @@ -903,6 +898,11 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std lmap.map (db::LDPair (p.layer, p.datatype), l3 = ly.insert_layer ()); ly.set_properties (l3, p); + p.layer = 4; + p.datatype = 0; + lmap.map (db::LDPair (p.layer, p.datatype), l4 = ly.insert_layer ()); + ly.set_properties (l4, p); + db::LoadLayoutOptions options; options.get_options ().layer_map = lmap; options.get_options ().create_other_layers = false; @@ -919,6 +919,7 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std normalize_layer (ly, strings, l1); normalize_layer (ly, strings, l2); normalize_layer (ly, strings, l3); + normalize_layer (ly, strings, l4); // connect 1 to 1, 1 to 2 and 1 to 3, but *not* 2 to 3 db::Connectivity conn; @@ -927,6 +928,9 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std conn.connect (l3, l3); conn.connect (l1, l2); conn.connect (l1, l3); + conn.connect (l1, l4); + + conn.connect_global (l4, "BULK"); db::hier_clusters hc; hc.build (ly, ly.cell (*ly.begin_top_down ()), db::ShapeIterator::Polygons, conn); @@ -989,7 +993,7 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::string &file, const std::string &au_file) { db::Layout ly; - unsigned int l1 = 0, l2 = 0, l3 = 0; + unsigned int l1 = 0, l2 = 0, l3 = 0, l4 = 0; { db::LayerProperties p; @@ -1010,6 +1014,11 @@ static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::str lmap.map (db::LDPair (p.layer, p.datatype), l3 = ly.insert_layer ()); ly.set_properties (l3, p); + p.layer = 4; + p.datatype = 0; + lmap.map (db::LDPair (p.layer, p.datatype), l4 = ly.insert_layer ()); + ly.set_properties (l4, p); + db::LoadLayoutOptions options; options.get_options ().layer_map = lmap; options.get_options ().create_other_layers = false; @@ -1026,6 +1035,7 @@ static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::str normalize_layer (ly, strings, l1); normalize_layer (ly, strings, l2); normalize_layer (ly, strings, l3); + normalize_layer (ly, strings, l4); // connect 1 to 1, 1 to 2 and 1 to 3, but *not* 2 to 3 db::Connectivity conn; @@ -1034,6 +1044,9 @@ static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::str conn.connect (l3, l3); conn.connect (l1, l2); conn.connect (l1, l3); + conn.connect (l1, l4); + + conn.connect_global (l4, "BULK"); db::hier_clusters hc; hc.build (ly, ly.cell (*ly.begin_top_down ()), db::ShapeIterator::Polygons, conn); @@ -1042,6 +1055,7 @@ static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::str lm[l1] = ly.insert_layer (db::LayerProperties (101, 0)); lm[l2] = ly.insert_layer (db::LayerProperties (102, 0)); lm[l3] = ly.insert_layer (db::LayerProperties (103, 0)); + lm[l4] = ly.insert_layer (db::LayerProperties (104, 0)); hc.return_to_hierarchy (ly, lm); CHECKPOINT(); @@ -1138,3 +1152,9 @@ TEST(115_HierClusters) run_hc_test_with_backannotation (_this, "hc_test_l15.gds", "hc_test_au15b.gds"); } +TEST(116_HierClusters) +{ + run_hc_test (_this, "hc_test_l16.gds", "hc_test_au16.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l16.gds", "hc_test_au16b.gds"); +} + diff --git a/src/db/unit_tests/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc index e631f9b26..565dc49fd 100644 --- a/src/db/unit_tests/dbLayoutToNetlistTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistTests.cc @@ -49,11 +49,39 @@ static std::string device_name (const db::Device &device) } } -class MOSFETExtractor +static void mos2layout (const db::Layout *layout, db::cell_index_type cell_index, db::Layout *debug_out, const db::Device *device, unsigned int ldiff, const db::Region &diff, unsigned int lgate, const db::Region &gate) +{ + std::string cn = layout->cell_name (cell_index); + std::pair target_cp = debug_out->cell_by_name (cn.c_str ()); + tl_assert (target_cp.first); + + db::cell_index_type dci = debug_out->add_cell ((device->device_class ()->name () + "_" + device->circuit ()->name () + "_" + device_name (*device)).c_str ()); + debug_out->cell (target_cp.second).insert (db::CellInstArray (db::CellInst (dci), db::Trans ())); + + db::Cell &device_cell = debug_out->cell (dci); + for (db::Region::const_iterator p = diff.begin (); ! p.at_end (); ++p) { + device_cell.shapes (ldiff).insert (*p); + } + for (db::Region::const_iterator p = gate.begin (); ! p.at_end (); ++p) { + device_cell.shapes (lgate).insert (*p); + } + + std::string ps; + const std::vector &pd = device->device_class ()->parameter_definitions (); + for (std::vector::const_iterator i = pd.begin (); i != pd.end (); ++i) { + if (! ps.empty ()) { + ps += ","; + } + ps += i->name () + "=" + tl::to_string (device->parameter_value (i->id ())); + } + device_cell.shapes (ldiff).insert (db::Text (ps, db::Trans (diff.bbox ().center () - db::Point ()))); +} + +class MOSFET3Extractor : public db::NetlistDeviceExtractorMOS3Transistor { public: - MOSFETExtractor (const std::string &name, db::Layout *debug_out) + MOSFET3Extractor (const std::string &name, db::Layout *debug_out) : db::NetlistDeviceExtractorMOS3Transistor (name), mp_debug_out (debug_out), m_ldiff (0), m_lgate (0) { if (mp_debug_out) { @@ -68,34 +96,34 @@ private: void device_out (const db::Device *device, const db::Region &diff, const db::Region &gate) { - if (! mp_debug_out) { - return; + if (mp_debug_out) { + mos2layout (layout (), cell_index (), mp_debug_out, device, m_ldiff, diff, m_lgate, gate); } + } +}; - std::string cn = layout ()->cell_name (cell_index ()); - std::pair target_cp = mp_debug_out->cell_by_name (cn.c_str ()); - tl_assert (target_cp.first); - - db::cell_index_type dci = mp_debug_out->add_cell ((device->device_class ()->name () + "_" + device->circuit ()->name () + "_" + device_name (*device)).c_str ()); - mp_debug_out->cell (target_cp.second).insert (db::CellInstArray (db::CellInst (dci), db::Trans ())); - - db::Cell &device_cell = mp_debug_out->cell (dci); - for (db::Region::const_iterator p = diff.begin (); ! p.at_end (); ++p) { - device_cell.shapes (m_ldiff).insert (*p); - } - for (db::Region::const_iterator p = gate.begin (); ! p.at_end (); ++p) { - device_cell.shapes (m_lgate).insert (*p); +class MOSFET4Extractor + : public db::NetlistDeviceExtractorMOS4Transistor +{ +public: + MOSFET4Extractor (const std::string &name, db::Layout *debug_out) + : db::NetlistDeviceExtractorMOS4Transistor (name), mp_debug_out (debug_out), m_ldiff (0), m_lgate (0) + { + if (mp_debug_out) { + m_ldiff = mp_debug_out->insert_layer (db::LayerProperties (100, 0)); + m_lgate = mp_debug_out->insert_layer (db::LayerProperties (101, 0)); } + } - std::string ps; - const std::vector &pd = device->device_class ()->parameter_definitions (); - for (std::vector::const_iterator i = pd.begin (); i != pd.end (); ++i) { - if (! ps.empty ()) { - ps += ","; - } - ps += i->name () + "=" + tl::to_string (device->parameter_value (i->id ())); +private: + db::Layout *mp_debug_out; + unsigned int m_ldiff, m_lgate; + + void device_out (const db::Device *device, const db::Region &diff, const db::Region &gate) + { + if (mp_debug_out) { + mos2layout (layout (), cell_index (), mp_debug_out, device, m_ldiff, diff, m_lgate, gate); } - device_cell.shapes (m_ldiff).insert (db::Text (ps, db::Trans (diff.bbox ().center () - db::Point ()))); } }; @@ -261,8 +289,8 @@ TEST(1_Basic) // NOTE: the device extractor will add more debug layers for the transistors: // 20/0 -> Diffusion // 21/0 -> Gate - MOSFETExtractor pmos_ex ("PMOS", &ly); - MOSFETExtractor nmos_ex ("NMOS", &ly); + MOSFET3Extractor pmos_ex ("PMOS", &ly); + MOSFET3Extractor nmos_ex ("NMOS", &ly); // device extraction @@ -617,8 +645,8 @@ TEST(2_Probing) // NOTE: the device extractor will add more debug layers for the transistors: // 20/0 -> Diffusion // 21/0 -> Gate - MOSFETExtractor pmos_ex ("PMOS", &ly); - MOSFETExtractor nmos_ex ("NMOS", &ly); + MOSFET3Extractor pmos_ex ("PMOS", &ly); + MOSFET3Extractor nmos_ex ("NMOS", &ly); // device extraction @@ -871,8 +899,8 @@ TEST(3_GlobalNetConnections) // NOTE: the device extractor will add more debug layers for the transistors: // 20/0 -> Diffusion // 21/0 -> Gate - MOSFETExtractor pmos_ex ("PMOS", &ly); - MOSFETExtractor nmos_ex ("NMOS", &ly); + MOSFET3Extractor pmos_ex ("PMOS", &ly); + MOSFET3Extractor nmos_ex ("NMOS", &ly); // device extraction @@ -1054,3 +1082,277 @@ TEST(3_GlobalNetConnections) EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "INV2PAIR:$I8"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "INV2PAIR:$I4"); } + +TEST(4_GlobalNetDeviceExtraction) +{ + 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 ())); + std::auto_ptr rnwell (l2n.make_layer (nwell)); + std::auto_ptr ractive (l2n.make_layer (active)); + std::auto_ptr rpplus (l2n.make_layer (pplus)); + std::auto_ptr rnplus (l2n.make_layer (nplus)); + std::auto_ptr rpoly (l2n.make_polygon_layer (poly)); + std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl)); + std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont)); + std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont)); + std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1)); + std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl)); + std::auto_ptr rvia1 (l2n.make_polygon_layer (via1)); + std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2)); + std::auto_ptr rmetal2_lbl (l2n.make_text_layer (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; + + 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; + + // 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); + + // NOTE: the device extractor will add more debug layers for the transistors: + // 20/0 -> Diffusion + // 21/0 -> Gate + MOSFET4Extractor pmos_ex ("PMOS", &ly); + MOSFET4Extractor nmos_ex ("NMOS", &ly); + + // 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 (); + + // debug layers produced for nets + // 201/0 -> Well + // 203/0 -> Poly + // 204/0 -> Diffusion contacts + // 205/0 -> Poly contacts + // 206/0 -> Metal1 + // 207/0 -> Via1 + // 208/0 -> Metal2 + // 210/0 -> N source/drain + // 211/0 -> P source/drain + // 212/0 -> N tie + // 213/0 -> P tie + std::map dump_map; + dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (210, 0)); + dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (211, 0)); + dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (212, 0)); + dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (213, 0)); + dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (201, 0)); + dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (203, 0)); + dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (204, 0)); + dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (205, 0)); + dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (206, 0)); + dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (207, 0)); + dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (208, 0)); + + // write nets to layout + db::CellMapping cm = l2n.cell_mapping_into (ly, tc); + dump_nets_to_layout (l2n, ly, dump_map, cm); + + dump_map.clear (); + dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (310, 0)); + dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (311, 0)); + dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (312, 0)); + dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (313, 0)); + dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (301, 0)); + dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (303, 0)); + dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (304, 0)); + dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (305, 0)); + dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (306, 0)); + dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (307, 0)); + dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (308, 0)); + + dump_recursive_nets_to_layout (l2n, ly, dump_map, cm); + + // compare netlist as string + EXPECT_EQ (l2n.netlist ()->to_string (), + "Circuit RINGO ():\n" + " XINV2PAIR $1 ($1=VSS,$2=VSS,$3=FB,$4=VDD,$5=VSS,$6=$I7,$7=OSC,$8=VDD)\n" + " XINV2PAIR $2 ($1=VSS,$2=VSS,$3=$I22,$4=VDD,$5=VSS,$6=FB,$7=$I13,$8=VDD)\n" + " XINV2PAIR $3 ($1=VSS,$2=VSS,$3=$I23,$4=VDD,$5=VSS,$6=$I13,$7=$I5,$8=VDD)\n" + " XINV2PAIR $4 ($1=VSS,$2=VSS,$3=$I24,$4=VDD,$5=VSS,$6=$I5,$7=$I6,$8=VDD)\n" + " XINV2PAIR $5 ($1=VSS,$2=VSS,$3=$I25,$4=VDD,$5=VSS,$6=$I6,$7=$I7,$8=VDD)\n" + "Circuit INV2PAIR ($1=$I10,$2=$I9,$3=$I8,$4=$I6,$5=$I5,$6=$I3,$7=$I2,$8=$I1):\n" + " XINV2 $1 ($1=$I1,IN=$I4,$3=$I8,BULK=$I10,OUT=$I2,VSS=$I5,VDD=$I6)\n" + " XINV2 $2 ($1=$I1,IN=$I3,$3=$I7,BULK=$I9,OUT=$I4,VSS=$I5,VDD=$I6)\n" + "Circuit INV2 ($1=$1,IN=IN,$3=$3,BULK=BULK,OUT=OUT,VSS=VSS,VDD=VDD):\n" + " DPMOS $1 (S=$3,G=IN,D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DPMOS $2 (S=VDD,G=$3,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DNMOS $3 (S=$3,G=IN,D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DNMOS $4 (S=VSS,G=$3,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " XTRANS $1 ($1=$3,$2=VSS,$3=IN)\n" + " XTRANS $2 ($1=$3,$2=VDD,$3=IN)\n" + " XTRANS $3 ($1=VDD,$2=OUT,$3=$3)\n" + " XTRANS $4 ($1=VSS,$2=OUT,$3=$3)\n" + "Circuit TRANS ($1=$1,$2=$2,$3=$3):\n" + ); + + // compare the collected test data + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "device_extract_au3_with_rec_nets.gds"); + + db::compare_layouts (_this, ly, au); + + // do some probing before purging + + // top level + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::DPoint (0.0, 1.8))), "RINGO:FB"); + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::Point (0, 1800))), "RINGO:FB"); + 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: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"); + + // doesn't do anything here, but we test that this does not destroy anything: + l2n.netlist ()->combine_devices (); + + // make pins for named nets of top-level circuits - this way they are not purged + l2n.netlist ()->make_top_level_pins (); + l2n.netlist ()->purge (); + + // compare netlist as string + EXPECT_EQ (l2n.netlist ()->to_string (), + "Circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,VSS=VSS):\n" + " XINV2PAIR $1 ($1=VSS,$2=VSS,$3=FB,$4=VDD,$5=VSS,$6=$I7,$7=OSC,$8=VDD)\n" + " XINV2PAIR $2 ($1=VSS,$2=VSS,$3=(null),$4=VDD,$5=VSS,$6=FB,$7=$I13,$8=VDD)\n" + " XINV2PAIR $3 ($1=VSS,$2=VSS,$3=(null),$4=VDD,$5=VSS,$6=$I13,$7=$I5,$8=VDD)\n" + " XINV2PAIR $4 ($1=VSS,$2=VSS,$3=(null),$4=VDD,$5=VSS,$6=$I5,$7=$I6,$8=VDD)\n" + " XINV2PAIR $5 ($1=VSS,$2=VSS,$3=(null),$4=VDD,$5=VSS,$6=$I6,$7=$I7,$8=VDD)\n" + "Circuit INV2PAIR ($1=$I10,$2=$I9,$3=$I8,$4=$I6,$5=$I5,$6=$I3,$7=$I2,$8=$I1):\n" + " XINV2 $1 ($1=$I1,IN=$I4,$3=$I8,BULK=$I10,OUT=$I2,VSS=$I5,VDD=$I6)\n" + " XINV2 $2 ($1=$I1,IN=$I3,$3=(null),BULK=$I9,OUT=$I4,VSS=$I5,VDD=$I6)\n" + "Circuit INV2 ($1=(null),IN=IN,$3=$3,BULK=(null),OUT=OUT,VSS=VSS,VDD=VDD):\n" + " DPMOS $1 (S=$3,G=IN,D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DPMOS $2 (S=VDD,G=$3,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DNMOS $3 (S=$3,G=IN,D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DNMOS $4 (S=VSS,G=$3,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + ); + + // do some probing after purging + + // top level + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::DPoint (0.0, 1.8))), "RINGO:FB"); + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::Point (0, 1800))), "RINGO:FB"); + 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"); + // the transistor which supplies this probe target has been optimized away by "purge". + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "(null)"); + + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "INV2PAIR:$I8"); + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "INV2PAIR:$I4"); +} diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index 6625e2c30..3dd6e3630 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -63,11 +63,11 @@ static std::string device_name (const db::Device &device) namespace { -class MOSFETExtractor +class MOSFET3Extractor : public db::NetlistDeviceExtractorMOS3Transistor { public: - MOSFETExtractor (const std::string &name, db::Layout *debug_out) + MOSFET3Extractor (const std::string &name, db::Layout *debug_out) : db::NetlistDeviceExtractorMOS3Transistor (name), mp_debug_out (debug_out), m_ldiff (0), m_lgate (0) { if (mp_debug_out) { @@ -239,8 +239,8 @@ TEST(1_DeviceAndNetExtraction) // NOTE: the device extractor will add more debug layers for the transistors: // 20/0 -> Diffusion // 21/0 -> Gate - MOSFETExtractor pmos_ex ("PMOS", &ly); - MOSFETExtractor nmos_ex ("NMOS", &ly); + MOSFET3Extractor pmos_ex ("PMOS", &ly); + MOSFET3Extractor nmos_ex ("NMOS", &ly); db::NetlistDeviceExtractor::input_layers dl; diff --git a/src/db/unit_tests/dbNetlistTests.cc b/src/db/unit_tests/dbNetlistTests.cc index 08ede9d34..07682ab06 100644 --- a/src/db/unit_tests/dbNetlistTests.cc +++ b/src/db/unit_tests/dbNetlistTests.cc @@ -1024,53 +1024,3 @@ TEST(12_NetlistTopology) EXPECT_EQ (td2string (nl.get ()), "c1,c3,c2"); EXPECT_EQ (bu2string (nl.get ()), "c2,c3,c1"); } - -TEST(13_DeviceGlobalNets) -{ - db::DeviceTerminalDefinition pd; - pd.set_name ("name"); - pd.set_description ("nothing yet"); - - db::DeviceTerminalDefinition pd2; - pd2.set_name ("name2"); - pd2.set_description ("now it has something"); - - db::DeviceClass dc; - dc.set_name ("devname"); - dc.set_description ("devdesc"); - dc.add_terminal_definition (pd); - dc.add_terminal_definition (pd2); - - db::Device d (&dc); - db::Net n; - - d.connect_terminal_global (0, 17); - - db::Device::global_connections_iterator g; - - g = d.begin_global_connections (); - EXPECT_EQ (g != d.end_global_connections (), true); - EXPECT_EQ (g->first, size_t (0)); - EXPECT_EQ (g->second, size_t (17)); - - ++g; - EXPECT_EQ (g == d.end_global_connections (), true); - - d.connect_terminal (0, &n); - g = d.begin_global_connections (); - EXPECT_EQ (g == d.end_global_connections (), true); - EXPECT_EQ (d.net_for_terminal (0) == &n, true); - - d.connect_terminal_global (0, 17); - EXPECT_EQ (d.net_for_terminal (0) == 0, true); - - g = d.begin_global_connections (); - EXPECT_EQ (g != d.end_global_connections (), true); - EXPECT_EQ (g->first, size_t (0)); - EXPECT_EQ (g->second, size_t (17)); - - d.connect_terminal (0, 0); - g = d.begin_global_connections (); - EXPECT_EQ (g == d.end_global_connections (), true); - EXPECT_EQ (d.net_for_terminal (0) == 0, true); -} diff --git a/testdata/algo/hc_test_au16.gds b/testdata/algo/hc_test_au16.gds new file mode 100644 index 0000000000000000000000000000000000000000..77d3c83edd3076e9aa32cbdd3e8595f89be73df8 GIT binary patch literal 5570 zcmeI0zfYZ27{|Zdd%4`=gc;TzlV?Tetc6Mapr?0*Wm;dKX)BbnmL&~rLofEfaoZH+CG=05VfBYYd96#%v_+%N_b2ZTP_1T*7xiEjmy26#1 z_AHEZ{5?)IrRijL{+aR4ZHzki*Q&_1+i>pBpNyu9^~M8DCBE+z0cIaBTrrxSF#G-a z5WjOz2ekI0;!f5&rRhm->W<&It$ZG@VSw zv!tI_rM)OLvr1o7y_PF^uEzqPk8+bV;pO{sz77bEQdj$^L_Zrjt=#bV8|L{{nlN^~Ns( zO(&zg+P?ACCYH8RR=A6Zg&oz08AA zc}?F(dG(xO9Xtla$|7*OJz0|XgaygE21O&o^@m|iiaCmbmeN}&=jekq(}EZN11Yn{`YLn4RdUH77#V|V(KB9PHvlbiBY!XYP~*K zO=5+pzWRi|M%79BKFVw88V~6SKzw134G$IPkrE>St1Vr)j!$!%WG$!)1v zymFZ#+J2j6EZM2j^DfP0pU-85bLm{D$;C=G7p)b)=AwF{Z8NaUwM^fKIJwtn_RAVC z)xYiE^3r!3O(%mFZ#VV4G)|{TGM;^=^;f@%rjt=#`#SwRM9uFI0yV$%eU#UM5uW-> zfLJL2hrbRqos9C*8NgFAISUk*J{wIZqr7w@()x&sO=pVHbTZ0ow#Q=GPKNs82~@AQU!l*%89*FkFCM!cXgV3ZcGxEr&!q=Gu1~M|xQwQg zQC_-7eK_IoQ)BmmBM%u@O4G?GuOsa|iyqU1{Jb;SgP+lKGRjMFon%joeO=sh_!vzm zgVzpwv^;bN7klP-weJWtoeW+(ti8_e?y^6_Pu*Z#8-UStGRmv{uD_p&=lX$zjLq0T z$$j6ykMcV31MiF6Tg7+p`8*m;C!@Udy{b=9cjH6Tfu@sDUOEq7uX3Lz-{hn9Gn!6D zd1*fHE%^DJuK@2eMx*Iu@Yy$-gjyx&~!4&YqutRt^ChxVl{ie*Ey{panDumH;aL$llAJW#_NrF{^m3w=6>}1 xv(a=i%1is5?#rU?`1-riX!;KK=$g3RxugHR1H{rTzyBCbC%47LzqJYl{0p!*62kxh literal 0 HcmV?d00001 diff --git a/testdata/algo/hc_test_au16b.gds b/testdata/algo/hc_test_au16b.gds new file mode 100644 index 0000000000000000000000000000000000000000..97fea40b2c4496069c240bacb1f733060625a975 GIT binary patch literal 4874 zcmd6qyKfv-6vjXAW4tkIvnHFDSt3IWB484~LLQhrYy*yLDHd45G6~g$qk|z<|Z&`)1~3?nGRL0%RWci{-NyzC1bh({~%EN0yE+d^0_X zMmg+@qG-4mr3w(W7WnL_t-z;u*NV>V+_wv8>h>?wMU>j{_kK6;+@DqF+&ob11j==z z>0;Rb=&Ey@4d=w2S?9L5Gn&5H2>X9srhm>k@zENv=W<5VH|KKxLiYZQ^&vAcldv>S z{~f+)O4CXI{XM^PTcghXzAiF%Th9IVqtSFR^qpzbTT;pYdz{_Kx}1oj?HE?oecWB*OPY_pIrd@_%24} zCcW?bKl9(8(W5e;|MaoD%GWZQP6qwGrHVPp2y>)95f%UIA7?cEiT=rr|02g!zD3pk6|N9Q z)5&=Je=sxpAJ2?FL>)~mO0`iQnpSoA7tfV__v6p;6I+s5)R)}pT#0MpziV!;?EQj$ z#yp9~7^|LSG@bPQxn3Wpw>k%i^1hcoLo}TX`rlcPXAf38*^utr)RMAc}TF&IrJWB*fXRf(d>OAN)IzG z+SC|x*HSLFTyE8Cww9^?^?jr1r2lR?zrL$gH1@EMl@Il^XgV46@AmjFjI*AzfH(%u zqs5G-lfn3pYycNmIgiPYm^;lwqv>SOuXRIvjo3TSEvz%6>15Ea`Os5M=EaHYK*ttf zG@T6kPp<%P-2ue&HQ+4!!Du=e^bg(u1~+(-L#6y>IvMou_V}uo{=_|(fuqYAO(%o# zzq-J?Gk{q50XQ>|(R9-H=hl|JU7S12yV$-B9OC1QrjtSc{t=$;SUa&+V*S6$XgV46 z@AmlW`*$aj{vW#w9KOf-m(p}H7=QhCvWJVx{XxzlqxSane$c=Fd!8MxF@L1`UE>=~ zCxia;Yrwft&KYvJhws8TjHZ)8|L`{FUWFd=!XPlpIvPzUgZ|wf|K&!~f1>sP?dL}I zUwYq$A~xJE1d8`h}VE7au13ji@=Gv!hY_PeAxIY3n3pV`T1 zIvMn9&(ppkYQH_fIvPzUgZ|wf|IJ(aMGlCSo5@~iG@bP0zvBOn&>CN5{zT0i^}f+` z@;~$I+;V9=IlsKWlI(*<)5+lY2UdaOBgy)$T6FL-nob7&T5I24O4eMRJI*a8=MT|z M@?Y`uY+WkhFOL|(sQ>@~ literal 0 HcmV?d00001 diff --git a/testdata/algo/hc_test_l16.gds b/testdata/algo/hc_test_l16.gds new file mode 100644 index 0000000000000000000000000000000000000000..f4bb6149eb0634fd6fa9143b50184b27d05b6e8d GIT binary patch literal 1162 zcma))F;Cl26opT0=fyyRQV69&9vGNVN<}gt5JDn!01>GjG9V@fhW>zz9WpRbsbdGE zGO%^&*db$wiiv@dfgutM9XcQ-p=ld&d#~+_Z3zn^J$=@3&hvTaJ{VZm4!n$&yFvyA z(^$dt_%mF~)VFFt$A?qfISOjOG?#+>HdC`sOu34hwq67gNUkky>$QYGxoQL zg#8O(WG|xX-B!YHMd#thfKHwLKlq>_RcFS}AM+FSHi`cJ5^{GvqCel2steQn zK+fg&b3%ZpkFkbQb)WI?+fja^+g0gaD7pQvL#po2Ce`2jD)Zv}O!r9okElA&HO0^K zzU01(0snmi@*a^=b*Asn;n7=KfiudtbVBZHzG!nFZJ@9j_>*s5zU8kaC+kGb0HYrz zO~COc5MQb@pPH_z%687V7{2 literal 0 HcmV?d00001 diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb index 86e1954c7..812304085 100644 --- a/testdata/ruby/dbNetlist.rb +++ b/testdata/ruby/dbNetlist.rb @@ -259,13 +259,6 @@ class DBNetlist_TestClass < TestBase d2.connect_terminal(0, net) assert_equal(net.terminal_count, 1) - d2.connect_terminal_global(0, 1) - assert_equal(net.terminal_count, 0) - - assert_equal(d2.terminal_on_global_net(1), 0) - assert_equal(d2.terminal_on_global_net(17).inspect, "nil") - assert_equal(d2.global_net_on_terminal(0), 1) - assert_equal(d2.global_net_on_terminal(1).inspect, "nil") end