From 45cdefcf9a33ea381f4d958b5cef27396fb5cfad Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 20 Aug 2019 23:12:17 +0200 Subject: [PATCH] Provide strict mode for device classes, dmos3/dmos4 for LVS --- src/db/db/dbDeviceClass.cc | 5 +- src/db/db/dbDeviceClass.h | 21 + src/db/db/dbNetlistCompare.cc | 43 +- src/db/db/dbNetlistDeviceExtractorClasses.cc | 334 +++++-- src/db/db/dbNetlistDeviceExtractorClasses.h | 11 +- src/db/db/gsiDeclDbNetlist.cc | 18 +- src/db/db/gsiDeclDbNetlistDeviceExtractor.cc | 22 +- src/db/unit_tests/dbNetlistExtractorTests.cc | 244 +++++ src/drc/drc/built-in-macros/_drc_engine.rb | 26 + src/lay/lay/doc/about/drc_ref_global.xml | 24 + .../lay/doc/manual/lvs_device_extractors.xml | 21 + src/lvs/unit_tests/lvsSimpleTests.cc | 5 + testdata/algo/device_extract_au9.gds | Bin 0 -> 7982 bytes testdata/algo/device_extract_l9.gds | Bin 0 -> 2826 bytes testdata/lvs/ringo.gds | Bin 9954 -> 10210 bytes testdata/lvs/ringo_simple_dmos.cir | 83 ++ testdata/lvs/ringo_simple_dmos.lvs | 81 ++ testdata/lvs/ringo_simple_dmos.lvsdb | 925 ++++++++++++++++++ testdata/ruby/dbNetlist.rb | 4 + 19 files changed, 1763 insertions(+), 104 deletions(-) create mode 100644 testdata/algo/device_extract_au9.gds create mode 100644 testdata/algo/device_extract_l9.gds create mode 100644 testdata/lvs/ringo_simple_dmos.cir create mode 100644 testdata/lvs/ringo_simple_dmos.lvs create mode 100644 testdata/lvs/ringo_simple_dmos.lvsdb diff --git a/src/db/db/dbDeviceClass.cc b/src/db/db/dbDeviceClass.cc index 7ff6619f3..d16daf212 100644 --- a/src/db/db/dbDeviceClass.cc +++ b/src/db/db/dbDeviceClass.cc @@ -136,13 +136,13 @@ bool AllDeviceParametersAreEqual::equal (const db::Device &a, const db::Device & // DeviceClass class implementation DeviceClass::DeviceClass () - : mp_netlist (0) + : mp_netlist (0), m_strict (false) { // .. nothing yet .. } DeviceClass::DeviceClass (const DeviceClass &other) - : gsi::ObjectBase (other), tl::Object (other), tl::UniqueId (other), mp_netlist (0) + : gsi::ObjectBase (other), tl::Object (other), tl::UniqueId (other), mp_netlist (0), m_strict (false) { operator= (other); } @@ -154,6 +154,7 @@ DeviceClass &DeviceClass::operator= (const DeviceClass &other) m_parameter_definitions = other.m_parameter_definitions; m_name = other.m_name; m_description = other.m_description; + m_strict = other.m_strict; mp_pc_delegate.reset (const_cast (other.mp_pc_delegate.get ())); } return *this; diff --git a/src/db/db/dbDeviceClass.h b/src/db/db/dbDeviceClass.h index 62530e712..ff3d96b15 100644 --- a/src/db/db/dbDeviceClass.h +++ b/src/db/db/dbDeviceClass.h @@ -350,6 +350,26 @@ public: return mp_netlist; } + /** + * @brief Sets a value indicating whether this class performs strict terminal mapping + * + * Classes with this flag set don't allow terminal swapping, independently of the + * "normalize_terminal_id" implementation. If two classes are involved in a compare, + * both classes are treated strict if one of them operates in strict mode. + */ + void set_strict (bool s) + { + m_strict = s; + } + + /** + * @brief Gets a value indicating whether this class performs strict terminal mapping + */ + bool is_strict () const + { + return m_strict; + } + /** * @brief Gets the name of the device class * @@ -555,6 +575,7 @@ private: std::string m_name, m_description; std::vector m_terminal_definitions; std::vector m_parameter_definitions; + bool m_strict; db::Netlist *mp_netlist; tl::shared_ptr mp_pc_delegate; diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index dbcb61d3c..f76bb6235 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -447,6 +447,24 @@ public: { return generic_categorizer::cat_for (cls); } + + void clear_strict_device_categories () + { + m_strict_device_categories.clear (); + } + + void set_strict_device_category (size_t cat) + { + m_strict_device_categories.insert (cat); + } + + bool is_strict_device_category (size_t cat) const + { + return m_strict_device_categories.find (cat) != m_strict_device_categories.end (); + } + +private: + std::set m_strict_device_categories; }; // -------------------------------------------------------------------------------------------------------------------- @@ -1070,14 +1088,17 @@ NetGraphNode::NetGraphNode (const db::Net *net, DeviceCategorizer &device_catego continue; } - size_t terminal1_id = translate_terminal_id (i->terminal_id (), d); + bool is_strict = device_categorizer.is_strict_device_category (device_cat); + + // strict device checking means no terminal swapping + size_t terminal1_id = is_strict ? i->terminal_id () : translate_terminal_id (i->terminal_id (), d); const std::vector &td = d->device_class ()->terminal_definitions (); for (std::vector::const_iterator it = td.begin (); it != td.end (); ++it) { if (it->id () != i->terminal_id ()) { - size_t terminal2_id = translate_terminal_id (it->id (), d); + size_t terminal2_id = is_strict ? it->id () : translate_terminal_id (it->id (), d); Transition ed2 (d, device_cat, terminal1_id, terminal2_id); const db::Net *net2 = d->net_for_terminal (it->id ()); @@ -2203,6 +2224,16 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const } } + // device whether to use a device category in strict mode + + device_categorizer.clear_strict_device_categories (); + + for (std::map >::const_iterator i = cat2dc.begin (); i != cat2dc.end (); ++i) { + if (i->second.first && i->second.second && (i->second.first->is_strict () || i->second.second->is_strict ())) { + device_categorizer.set_strict_device_category (i->first); + } + } + // check for circuits that don't match for (std::map >::const_iterator i = cat2circuits.begin (); i != cat2circuits.end (); ++i) { @@ -2333,13 +2364,13 @@ NetlistComparer::all_subcircuits_verified (const db::Circuit *c, const std::set< } static std::vector > -compute_device_key (const db::Device &device, const db::NetGraph &g) +compute_device_key (const db::Device &device, const db::NetGraph &g, bool strict) { std::vector > k; const std::vector &td = device.device_class ()->terminal_definitions (); for (std::vector::const_iterator t = td.begin (); t != td.end (); ++t) { - size_t terminal_id = translate_terminal_id (t->id (), &device); + size_t terminal_id = strict ? t->id () : translate_terminal_id (t->id (), &device); const db::Net *net = device.net_for_terminal (t->id ()); size_t net_id = g.node_index_for_net (net); k.push_back (std::make_pair (terminal_id, net_id)); @@ -2872,7 +2903,7 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph continue; } - std::vector > k = compute_device_key (*d, g1); + std::vector > k = compute_device_key (*d, g1, device_categorizer.is_strict_device_category (device_cat)); bool mapped = true; for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { @@ -2906,7 +2937,7 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph continue; } - std::vector > k = compute_device_key (*d, g2); + std::vector > k = compute_device_key (*d, g2, device_categorizer.is_strict_device_category (device_cat)); bool mapped = true; for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.cc b/src/db/db/dbNetlistDeviceExtractorClasses.cc index 394c74bad..01406124e 100644 --- a/src/db/db/dbNetlistDeviceExtractorClasses.cc +++ b/src/db/db/dbNetlistDeviceExtractorClasses.cc @@ -30,114 +30,252 @@ namespace db // --------------------------------------------------------------------------------- // NetlistDeviceExtractorMOS3Transistor implementation -NetlistDeviceExtractorMOS3Transistor::NetlistDeviceExtractorMOS3Transistor (const std::string &name) - : db::NetlistDeviceExtractor (name) +NetlistDeviceExtractorMOS3Transistor::NetlistDeviceExtractorMOS3Transistor (const std::string &name, bool strict) + : db::NetlistDeviceExtractor (name), + m_strict (strict) { // .. nothing yet .. } void NetlistDeviceExtractorMOS3Transistor::setup () { - define_layer ("SD", "Source/drain diffusion"); // #0 - define_layer ("G", "Gate input"); // #1 - // for backward compatibility - define_layer ("P", 1, "Gate terminal output"); // #2 -> G + if (! is_strict ()) { - // terminal output - define_layer ("tG", 2, "Gate terminal output"); // #3 -> P -> G - define_layer ("tS", 0, "Source terminal output (default is SD)"); // #4 - define_layer ("tD", 0, "Drain terminal output (default is SD)"); // #5 + define_layer ("SD", "Source/drain diffusion"); // #0 + define_layer ("G", "Gate input"); // #1 + // for backward compatibility + define_layer ("P", 1, "Gate terminal output"); // #2 -> G - register_device_class (new db::DeviceClassMOS3Transistor ()); + // terminal output + define_layer ("tG", 2, "Gate terminal output"); // #3 -> P -> G + define_layer ("tS", 0, "Source terminal output (default is SD)"); // #4 + define_layer ("tD", 0, "Drain terminal output (default is SD)"); // #5 + + } else { + + define_layer ("S", "Source diffusion"); // #0 + define_layer ("D", "Drain diffusion"); // #1 + define_layer ("G", "Gate input"); // #2 + // for backward compatibility + define_layer ("P", 2, "Gate terminal output"); // #3 -> G + + // terminal output + define_layer ("tG", 3, "Gate terminal output"); // #4 -> P -> G + define_layer ("tS", 0, "Source terminal output (default is S)"); // #5 + define_layer ("tD", 1, "Drain terminal output (default is D)"); // #6 + + } + + db::DeviceClass *cls = new db::DeviceClassMOS3Transistor (); + cls->set_strict (m_strict); + register_device_class (cls); } db::Connectivity NetlistDeviceExtractorMOS3Transistor::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const { - tl_assert (layers.size () >= 3); + if (! is_strict ()) { - unsigned int diff = layers [0]; - unsigned int gate = layers [1]; - // not used for device recognition: poly (2), but used for producing the gate terminals + tl_assert (layers.size () >= 3); - // The layer definition is diff, gate - db::Connectivity conn; - // collect all connected diffusion shapes - conn.connect (diff, diff); - // collect all connected gate shapes - conn.connect (gate, gate); - // connect gate with diff to detect gate/diffusion boundary - conn.connect (diff, gate); - return conn; + unsigned int diff = layers [0]; + unsigned int gate = layers [1]; + + // The layer definition is diff, gate + db::Connectivity conn; + // collect all connected diffusion shapes + conn.connect (diff, diff); + // collect all connected gate shapes + conn.connect (gate, gate); + // connect gate with diff to detect gate/diffusion boundary + conn.connect (diff, gate); + return conn; + + } else { + + + tl_assert (layers.size () >= 4); + + unsigned int sdiff = layers [0]; + unsigned int ddiff = layers [1]; + unsigned int gate = layers [2]; + + // The layer definition is diff, gate + db::Connectivity conn; + // collect all connected diffusion shapes + conn.connect (sdiff, sdiff); + conn.connect (ddiff, ddiff); + // collect all connected gate shapes + conn.connect (gate, gate); + // connect gate with diff to detect gate/diffusion boundary + conn.connect (sdiff, gate); + conn.connect (ddiff, gate); + return conn; + + } } void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector &layer_geometry) { - unsigned int diff_geometry_index = 0; - unsigned int gate_geometry_index = 1; - unsigned int gate_terminal_geometry_index = 3; - unsigned int source_terminal_geometry_index = 4; - unsigned int drain_terminal_geometry_index = 5; + if (! is_strict ()) { - const db::Region &rdiff = layer_geometry [diff_geometry_index]; - const db::Region &rgates = layer_geometry [gate_geometry_index]; + // See setup() for the geometry indexes + unsigned int diff_geometry_index = 0; + unsigned int gate_geometry_index = 1; + unsigned int gate_terminal_geometry_index = 3; + unsigned int source_terminal_geometry_index = 4; + unsigned int drain_terminal_geometry_index = 5; - for (db::Region::const_iterator p = rgates.begin_merged (); !p.at_end (); ++p) { + const db::Region &rdiff = layer_geometry [diff_geometry_index]; + const db::Region &rgates = layer_geometry [gate_geometry_index]; - db::Region rgate (*p); - rgate.set_base_verbosity (rgates.base_verbosity ()); + for (db::Region::const_iterator p = rgates.begin_merged (); !p.at_end (); ++p) { - db::Region rdiff2gate = rdiff.selected_interacting (rgate); - rdiff2gate.set_base_verbosity (rdiff.base_verbosity ()); + db::Region rgate (*p); + rgate.set_base_verbosity (rgates.base_verbosity ()); - if (rdiff2gate.empty ()) { - error (tl::to_string (tr ("Gate shape touches no diffusion - ignored")), *p); - } else { + db::Region rdiff2gate = rdiff.selected_interacting (rgate); + rdiff2gate.set_base_verbosity (rdiff.base_verbosity ()); - if (rdiff2gate.size () != 2) { - error (tl::sprintf (tl::to_string (tr ("Expected two polygons on diff interacting with one gate shape (found %d) - gate shape ignored")), int (rdiff2gate.size ())), *p); - continue; - } + if (rdiff2gate.empty ()) { + error (tl::to_string (tr ("Gate shape touches no diffusion - ignored")), *p); + } else { - db::Edges edges (rgate.edges () & rdiff2gate.edges ()); - if (edges.size () != 2) { - error (tl::sprintf (tl::to_string (tr ("Expected two edges interacting gate/diff (found %d) - width and length may be incorrect")), int (edges.size ())), *p); - continue; - } + if (rdiff2gate.size () != 2) { + error (tl::sprintf (tl::to_string (tr ("Expected two polygons on diff interacting with one gate shape (found %d) - gate shape ignored")), int (rdiff2gate.size ())), *p); + continue; + } - if (! p->is_box ()) { - error (tl::to_string (tr ("Gate shape is not a box - width and length may be incorrect")), *p); - } + db::Edges edges (rgate.edges () & rdiff2gate.edges ()); + if (edges.size () != 2) { + error (tl::sprintf (tl::to_string (tr ("Expected two edges interacting gate/diff (found %d) - width and length may be incorrect")), int (edges.size ())), *p); + continue; + } - db::Device *device = create_device (); + if (! p->is_box ()) { + error (tl::to_string (tr ("Gate shape is not a box - width and length may be incorrect")), *p); + } - device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ())); + db::Device *device = create_device (); - device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, sdbu () * edges.length () * 0.5); - device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, sdbu () * (p->perimeter () - edges.length ()) * 0.5); + device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ())); - int diff_index = 0; - for (db::Region::const_iterator d = rdiff2gate.begin (); !d.at_end () && diff_index < 2; ++d, ++diff_index) { + device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, sdbu () * edges.length () * 0.5); + device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, sdbu () * (p->perimeter () - edges.length ()) * 0.5); - // count the number of gate shapes attached to this shape and distribute the area of the - // diffusion region to the number of gates - size_t n = rgates.selected_interacting (db::Region (*d)).size (); - tl_assert (n > 0); + int diff_index = 0; + for (db::Region::const_iterator d = rdiff2gate.begin (); !d.at_end () && diff_index < 2; ++d, ++diff_index) { - device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_AS : db::DeviceClassMOS3Transistor::param_id_AD, sdbu () * sdbu () * d->area () / double (n)); - device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_PS : db::DeviceClassMOS3Transistor::param_id_PD, sdbu () * d->perimeter () / double (n)); + // count the number of gate shapes attached to this shape and distribute the area of the + // diffusion region to the number of gates + size_t n = rgates.selected_interacting (db::Region (*d)).size (); + tl_assert (n > 0); - unsigned int sd_index = diff_index == 0 ? source_terminal_geometry_index : drain_terminal_geometry_index; - define_terminal (device, diff_index == 0 ? db::DeviceClassMOS3Transistor::terminal_id_S : db::DeviceClassMOS3Transistor::terminal_id_D, sd_index, *d); + device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_AS : db::DeviceClassMOS3Transistor::param_id_AD, sdbu () * sdbu () * d->area () / double (n)); + device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_PS : db::DeviceClassMOS3Transistor::param_id_PD, sdbu () * d->perimeter () / double (n)); + + unsigned int sd_index = diff_index == 0 ? source_terminal_geometry_index : drain_terminal_geometry_index; + define_terminal (device, diff_index == 0 ? db::DeviceClassMOS3Transistor::terminal_id_S : db::DeviceClassMOS3Transistor::terminal_id_D, sd_index, *d); + + } + + define_terminal (device, db::DeviceClassMOS3Transistor::terminal_id_G, gate_terminal_geometry_index, *p); + + // allow derived classes to modify the device + modify_device (*p, layer_geometry, device); + + // output the device for debugging + device_out (device, rdiff2gate, rgate); } - define_terminal (device, db::DeviceClassMOS3Transistor::terminal_id_G, gate_terminal_geometry_index, *p); + } - // allow derived classes to modify the device - modify_device (*p, layer_geometry, device); + } else { - // output the device for debugging - device_out (device, rdiff2gate, rgate); + // See setup() for the geometry indexes + unsigned int source_geometry_index = 0; + unsigned int drain_geometry_index = 1; + unsigned int gate_geometry_index = 2; + unsigned int gate_terminal_geometry_index = 4; + unsigned int source_terminal_geometry_index = 5; + unsigned int drain_terminal_geometry_index = 6; + + const db::Region &sdiff = layer_geometry [source_geometry_index]; + const db::Region &ddiff = layer_geometry [drain_geometry_index]; + const db::Region &rgates = layer_geometry [gate_geometry_index]; + + for (db::Region::const_iterator p = rgates.begin_merged (); !p.at_end (); ++p) { + + db::Region rgate (*p); + rgate.set_base_verbosity (rgates.base_verbosity ()); + + db::Region sdiff2gate = sdiff.selected_interacting (rgate); + sdiff2gate.set_base_verbosity (sdiff.base_verbosity ()); + + db::Region ddiff2gate = ddiff.selected_interacting (rgate); + ddiff2gate.set_base_verbosity (ddiff.base_verbosity ()); + + if (sdiff2gate.empty () && ddiff2gate.empty ()) { + error (tl::to_string (tr ("Gate shape touches no diffusion - ignored")), *p); + } else if (sdiff2gate.empty () || ddiff2gate.empty ()) { + error (tl::to_string (tr ("Gate shape touches a single diffusion only - ignored")), *p); + } else { + + if (sdiff2gate.size () != 1) { + error (tl::sprintf (tl::to_string (tr ("Expected one polygons on source diff interacting with one gate shape (found %d) - gate shape ignored")), int (sdiff2gate.size ())), *p); + continue; + } + + if (ddiff2gate.size () != 1) { + error (tl::sprintf (tl::to_string (tr ("Expected one polygons on drain diff interacting with one gate shape (found %d) - gate shape ignored")), int (ddiff2gate.size ())), *p); + continue; + } + + db::Region diff2gate = sdiff2gate + ddiff2gate; + + db::Edges edges (rgate.edges () & diff2gate.edges ()); + if (edges.size () != 2) { + error (tl::sprintf (tl::to_string (tr ("Expected two edges interacting gate/diff (found %d) - width and length may be incorrect")), int (edges.size ())), *p); + continue; + } + + if (! p->is_box ()) { + error (tl::to_string (tr ("Gate shape is not a box - width and length may be incorrect")), *p); + } + + db::Device *device = create_device (); + + device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ())); + + device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, sdbu () * edges.length () * 0.5); + device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, sdbu () * (p->perimeter () - edges.length ()) * 0.5); + + for (int diff_index = 0; diff_index < 2; ++diff_index) { + + const db::Region *diff = diff_index == 0 ? &sdiff2gate : &ddiff2gate; + + // count the number of gate shapes attached to this shape and distribute the area of the + // diffusion region to the number of gates + size_t n = rgates.selected_interacting (*diff).size (); + tl_assert (n > 0); + + device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_AS : db::DeviceClassMOS3Transistor::param_id_AD, sdbu () * sdbu () * diff->area () / double (n)); + device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_PS : db::DeviceClassMOS3Transistor::param_id_PD, sdbu () * diff->perimeter () / double (n)); + + unsigned int sd_index = diff_index == 0 ? source_terminal_geometry_index : drain_terminal_geometry_index; + define_terminal (device, diff_index == 0 ? db::DeviceClassMOS3Transistor::terminal_id_S : db::DeviceClassMOS3Transistor::terminal_id_D, sd_index, *diff); + + } + + define_terminal (device, db::DeviceClassMOS3Transistor::terminal_id_G, gate_terminal_geometry_index, *p); + + // allow derived classes to modify the device + modify_device (*p, layer_geometry, device); + + // output the device for debugging + device_out (device, diff2gate, rgate); + + } } @@ -147,35 +285,61 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector G + if (! is_strict ()) { - // terminal output - define_layer ("tG", 2, "Gate terminal output"); // #3 -> P -> G - define_layer ("tS", 0, "Source terminal output (default is SD)"); // #4 - define_layer ("tD", 0, "Drain terminal output (default is SD)"); // #5 + define_layer ("SD", "Source/drain diffusion"); // #0 + define_layer ("G", "Gate input"); // #1 + // for backward compatibility + define_layer ("P", 1, "Gate terminal output"); // #2 -> G - // for backward compatibility - define_layer ("W", "Well (bulk) terminal output"); // #6 + // terminal output + define_layer ("tG", 2, "Gate terminal output"); // #3 -> P -> G + define_layer ("tS", 0, "Source terminal output (default is SD)"); // #4 + define_layer ("tD", 0, "Drain terminal output (default is SD)"); // #5 - define_layer ("tB", 6, "Well (bulk) terminal output"); // #7 -> W + // for backward compatibility + define_layer ("W", "Well (bulk) terminal output"); // #6 - register_device_class (new db::DeviceClassMOS4Transistor ()); + define_layer ("tB", 6, "Well (bulk) terminal output"); // #7 -> W + + } else { + + define_layer ("S", "Source diffusion"); // #0 + define_layer ("D", "Drain diffusion"); // #1 + define_layer ("G", "Gate input"); // #2 + // for backward compatibility + define_layer ("P", 2, "Gate terminal output"); // #3 -> G + + // terminal output + define_layer ("tG", 3, "Gate terminal output"); // #4 -> P -> G + define_layer ("tS", 0, "Source terminal output (default is S)"); // #5 + define_layer ("tD", 1, "Drain terminal output (default is D)"); // #6 + + // for backward compatibility + define_layer ("W", "Well (bulk) terminal output"); // #7 + + define_layer ("tB", 7, "Well (bulk) terminal output"); // #8 -> W + + } + + db::DeviceClass *cls = new db::DeviceClassMOS4Transistor (); + cls->set_strict (is_strict ()); + register_device_class (cls); } void NetlistDeviceExtractorMOS4Transistor::modify_device (const db::Polygon &rgate, const std::vector & /*layer_geometry*/, db::Device *device) { - unsigned int bulk_terminal_geometry_index = 7; + // see setup() for the layer indexes: + unsigned int bulk_terminal_geometry_index = is_strict () ? 8 : 7; + define_terminal (device, db::DeviceClassMOS4Transistor::terminal_id_B, bulk_terminal_geometry_index, rgate); } diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.h b/src/db/db/dbNetlistDeviceExtractorClasses.h index d623bd486..0dbb0743e 100644 --- a/src/db/db/dbNetlistDeviceExtractorClasses.h +++ b/src/db/db/dbNetlistDeviceExtractorClasses.h @@ -48,12 +48,17 @@ class DB_PUBLIC NetlistDeviceExtractorMOS3Transistor : public db::NetlistDeviceExtractor { public: - NetlistDeviceExtractorMOS3Transistor (const std::string &name); + NetlistDeviceExtractorMOS3Transistor (const std::string &name, bool strict = false); virtual void setup (); virtual db::Connectivity get_connectivity (const db::Layout &layout, const std::vector &layers) const; virtual void extract_devices (const std::vector &layer_geometry); + bool is_strict () const + { + return m_strict; + } + protected: /** * @brief A callback when the device is produced @@ -72,6 +77,8 @@ protected: // .. no specific implementation .. } +private: + bool m_strict; }; /** @@ -87,7 +94,7 @@ class DB_PUBLIC NetlistDeviceExtractorMOS4Transistor : public NetlistDeviceExtractorMOS3Transistor { public: - NetlistDeviceExtractorMOS4Transistor (const std::string &name); + NetlistDeviceExtractorMOS4Transistor (const std::string &name, bool strict = false); virtual void setup (); diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index 9523e7b7f..2b5d4b559 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -809,6 +809,20 @@ Class decl_dbDeviceClass ("db", "DeviceClass", gsi::method ("name=", &db::DeviceClass::set_name, gsi::arg ("name"), "@brief Sets the name of the device class." ) + + gsi::method ("strict?", &db::DeviceClass::is_strict, + "@brief Gets a value indicating whether this class performs strict terminal mapping\n" + "See \\strict= for details about this attribute." + ) + + gsi::method ("strict=", &db::DeviceClass::set_strict, gsi::arg ("s"), + "@brief Sets a value indicating whether this class performs strict terminal mapping\n" + "\n" + "Classes with this flag set never allow terminal swapping, even if the device symmetry supports that. " + "If two classes are involved in a netlist compare,\n" + "terminal swapping will be disabled if one of the classes is in strict mode.\n" + "\n" + "By default, device classes are not strict and terminal swapping is allowed as far as the " + "device symmetry supports that." + ) + gsi::method ("description", &db::DeviceClass::description, "@brief Gets the description text of the device class." ) + @@ -1014,7 +1028,9 @@ Class decl_GenericDeviceClass (decl_dbDeviceClass, "db", "Ge gsi::method ("equivalent_terminal_id", &GenericDeviceClass::equivalent_terminal_id, gsi::arg ("original_id"), gsi::arg ("equivalent_id"), "@brief Specifies a terminal to be equivalent to another.\n" "Use this method to specify two terminals to be exchangeable. For example to make S and D of a MOS transistor equivalent, " - "call this method with S and D terminal IDs. In netlist matching, S will be translated to D and thus made equivalent to D." + "call this method with S and D terminal IDs. In netlist matching, S will be translated to D and thus made equivalent to D.\n" + "\n" + "Note that terminal equivalence is not effective if the device class operates in strict mode (see \\DeviceClass#strict=)." ), "@brief A generic device class\n" "This class allows building generic device classes. Specificially, terminals can be defined " diff --git a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc index 0851b5f4f..9b2275b5c 100644 --- a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc +++ b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc @@ -397,14 +397,19 @@ Class decl_GenericDeviceExtractor (decl_dbNetlistDeviceE "This class has been introduced in version 0.26." ); -db::NetlistDeviceExtractorMOS3Transistor *make_mos3_extractor (const std::string &name) +static db::NetlistDeviceExtractorMOS3Transistor *make_mos3_extractor (const std::string &name, bool strict) { - return new db::NetlistDeviceExtractorMOS3Transistor (name); + return new db::NetlistDeviceExtractorMOS3Transistor (name, strict); } Class decl_NetlistDeviceExtractorMOS3Transistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorMOS3Transistor", - gsi::constructor ("new", &make_mos3_extractor, gsi::arg ("name"), - "@brief Creates a new device extractor with the given name." + gsi::constructor ("new", &make_mos3_extractor, gsi::arg ("name"), gsi::arg ("strict", false), + "@brief Creates a new device extractor with the given name.\n" + "If \\strict is true, the MOS device extraction will happen in strict mode. That is, source and drain " + "are not interchangeable." + ) + + gsi::method ("strict?", &db::NetlistDeviceExtractorMOS3Transistor::is_strict, + "@brief Returns a value indicating whether extraction happens in strict mode." ), "@brief A device extractor for a three-terminal MOS transistor\n" "\n" @@ -418,7 +423,8 @@ Class decl_NetlistDeviceExtractorMOS3T "The device class produced by this extractor is \\DeviceClassMOS3Transistor.\n" "The extractor extracts the six parameters of this class: L, W, AS, AD, PS and PD.\n" "\n" - "The device recognition layer names are 'SD' (source/drain) and 'G' (gate).\n" + "In strict mode, the device recognition layer names are 'S' (source), 'D' (drain) and 'G' (gate).\n" + "Otherwise, they are 'SD' (source/drain) and 'G' (gate).\n" "The terminal output layer names are 'tS' (source), 'tG' (gate) and 'tD' (drain).\n" "\n" "The diffusion area is distributed on the number of gates connecting to\n" @@ -430,13 +436,13 @@ Class decl_NetlistDeviceExtractorMOS3T "This class has been introduced in version 0.26." ); -db::NetlistDeviceExtractorMOS4Transistor *make_mos4_extractor (const std::string &name) +static db::NetlistDeviceExtractorMOS4Transistor *make_mos4_extractor (const std::string &name, bool strict) { - return new db::NetlistDeviceExtractorMOS4Transistor (name); + return new db::NetlistDeviceExtractorMOS4Transistor (name, strict); } Class decl_NetlistDeviceExtractorMOS4Transistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorMOS4Transistor", - gsi::constructor ("new", &make_mos4_extractor, gsi::arg ("name"), + gsi::constructor ("new", &make_mos4_extractor, gsi::arg ("name"), gsi::arg ("strict", false), "@brief Creates a new device extractor with the given name." ), "@brief A device extractor for a four-terminal MOS transistor\n" diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index e841c2cb8..38c2d7789 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -36,6 +36,7 @@ #include "dbTestSupport.h" #include "dbCellMapping.h" #include "dbTestSupport.h" +#include "dbNetlistCompare.h" #include "tlUnitTest.h" #include "tlString.h" @@ -1864,3 +1865,246 @@ TEST(8_DiodeExtractionScaled) db::compare_layouts (_this, ly, au); } + +TEST(9_StrictDeviceExtraction) +{ + db::Layout ly; + db::LayerMap lmap; + + unsigned int nwell = define_layer (ly, lmap, 1); + unsigned int active = define_layer (ly, lmap, 2); + 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); + unsigned int source = define_layer (ly, lmap, 10); + + { + 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_l9.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + db::Cell &tc = ly.cell (*ly.begin_top_down ()); + + db::DeepShapeStore dss; + dss.set_text_enlargement (1); + dss.set_text_property_name (tl::Variant ("LABEL")); + + // original layers + db::Region rnwell (db::RecursiveShapeIterator (ly, tc, nwell), dss); + db::Region ractive (db::RecursiveShapeIterator (ly, tc, active), dss); + db::Region rpoly (db::RecursiveShapeIterator (ly, tc, poly), dss); + db::Region rpoly_lbl (db::RecursiveShapeIterator (ly, tc, poly_lbl), dss); + db::Region rdiff_cont (db::RecursiveShapeIterator (ly, tc, diff_cont), dss); + db::Region rpoly_cont (db::RecursiveShapeIterator (ly, tc, poly_cont), dss); + db::Region rmetal1 (db::RecursiveShapeIterator (ly, tc, metal1), dss); + db::Region rmetal1_lbl (db::RecursiveShapeIterator (ly, tc, metal1_lbl), dss); + db::Region rvia1 (db::RecursiveShapeIterator (ly, tc, via1), dss); + db::Region rmetal2 (db::RecursiveShapeIterator (ly, tc, metal2), dss); + db::Region rmetal2_lbl (db::RecursiveShapeIterator (ly, tc, metal2_lbl), dss); + db::Region rsource (db::RecursiveShapeIterator (ly, tc, source), dss); + + // derived regions + + db::Region rpactive = ractive & rnwell; + db::Region rpgate = rpactive & rpoly; + db::Region rpsd = rpactive - rpgate; + db::Region rps = rpsd & rsource; + db::Region rpd = rpsd - rsource; + + db::Region rnactive = ractive - rnwell; + db::Region rngate = rnactive & rpoly; + db::Region rnsd = rnactive - rngate; + db::Region rns = rnsd & rsource; + db::Region rnd = rnsd - rsource; + + // return the computed layers into the original layout and write it for debugging purposes + + unsigned int lgate = ly.insert_layer (db::LayerProperties (20, 0)); // 10/0 -> Gate + unsigned int lsd = ly.insert_layer (db::LayerProperties (21, 0)); // 11/0 -> Source/Drain + unsigned int lpdiff = ly.insert_layer (db::LayerProperties (22, 0)); // 12/0 -> P Diffusion + unsigned int lndiff = ly.insert_layer (db::LayerProperties (23, 0)); // 13/0 -> N Diffusion + + rpgate.insert_into (&ly, tc.cell_index (), lgate); + rngate.insert_into (&ly, tc.cell_index (), lgate); + rps.insert_into (&ly, tc.cell_index (), lsd); + rpd.insert_into (&ly, tc.cell_index (), lsd); + rns.insert_into (&ly, tc.cell_index (), lsd); + rnd.insert_into (&ly, tc.cell_index (), lsd); + rpsd.insert_into (&ly, tc.cell_index (), lpdiff); + rnsd.insert_into (&ly, tc.cell_index (), lndiff); + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS", true /*strict*/); + db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS", true /*strict*/); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["S"] = &rps; + dl["D"] = &rpd; + dl["G"] = &rpgate; + dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes + pmos_ex.extract (dss, 0, dl, nl, cl); + + dl["S"] = &rns; + dl["D"] = &rnd; + dl["G"] = &rngate; + dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes + nmos_ex.extract (dss, 0, dl, nl, cl); + + // perform the net extraction + + db::NetlistExtractor net_ex; + + db::Connectivity conn; + // Intra-layer + conn.connect (rps); + conn.connect (rpd); + conn.connect (rns); + conn.connect (rnd); + conn.connect (rpoly); + conn.connect (rdiff_cont); + conn.connect (rpoly_cont); + conn.connect (rmetal1); + conn.connect (rvia1); + conn.connect (rmetal2); + // Inter-layer + conn.connect (rps, rdiff_cont); + conn.connect (rpd, rdiff_cont); + conn.connect (rns, rdiff_cont); + conn.connect (rnd, rdiff_cont); + conn.connect (rpoly, rpoly_cont); + conn.connect (rpoly_cont, rmetal1); + conn.connect (rdiff_cont, rmetal1); + conn.connect (rmetal1, rvia1); + conn.connect (rvia1, rmetal2); + conn.connect (rpoly, rpoly_lbl); // attaches labels + conn.connect (rmetal1, rmetal1_lbl); // attaches labels + conn.connect (rmetal2, rmetal2_lbl); // attaches labels + + // extract the nets + + net_ex.extract_nets (dss, 0, conn, nl, cl); + + // debug layers produced for nets + // 202/0 -> Active + // 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 + std::map dump_map; + dump_map [layer_of (rps) ] = ly.insert_layer (db::LayerProperties (210, 0)); + dump_map [layer_of (rpd) ] = ly.insert_layer (db::LayerProperties (211, 0)); + dump_map [layer_of (rns) ] = ly.insert_layer (db::LayerProperties (212, 0)); + dump_map [layer_of (rnd) ] = ly.insert_layer (db::LayerProperties (213, 0)); + dump_map [layer_of (rpoly) ] = ly.insert_layer (db::LayerProperties (203, 0)); + dump_map [layer_of (rdiff_cont)] = ly.insert_layer (db::LayerProperties (204, 0)); + dump_map [layer_of (rpoly_cont)] = ly.insert_layer (db::LayerProperties (205, 0)); + dump_map [layer_of (rmetal1) ] = ly.insert_layer (db::LayerProperties (206, 0)); + dump_map [layer_of (rvia1) ] = ly.insert_layer (db::LayerProperties (207, 0)); + dump_map [layer_of (rmetal2) ] = ly.insert_layer (db::LayerProperties (208, 0)); + + // write nets to layout + db::CellMapping cm = dss.cell_mapping_to_original (0, &ly, tc.cell_index ()); + dump_nets_to_layout (nl, cl, ly, dump_map, cm); + + std::string nl_au_string = + "circuit RINGO ();\n" + " subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD);\n" + "end;\n" + "circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n" + " device PMOS $1 (S=$5,G=IN,D=$2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + " device NMOS $3 (S=$4,G=IN,D=$2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + " subcircuit TRANS $1 ($1=$2,$2=$4,$3=IN);\n" + " subcircuit TRANS $2 ($1=$2,$2=$5,$3=IN);\n" + " subcircuit TRANS $3 ($1=$5,$2=OUT,$3=$2);\n" + " subcircuit TRANS $4 ($1=$4,$2=OUT,$3=$2);\n" + "end;\n" + "circuit TRANS ($1=$1,$2=$2,$3=$3);\n" + "end;\n"; + + // compare netlist as string + CHECKPOINT (); + db::compare_netlist (_this, nl, nl_au_string); + + { + // compare vs. non-strict device classes + db::Netlist au_nl; + // non-strict + db::DeviceClass *dc; + dc = new db::DeviceClassMOS3Transistor (); + dc->set_name ("PMOS"); + au_nl.add_device_class (dc); + dc = new db::DeviceClassMOS3Transistor (); + dc->set_name ("NMOS"); + au_nl.add_device_class (dc); + au_nl.from_string (nl_au_string); + + CHECKPOINT (); + db::compare_netlist (_this, nl, au_nl); + } + + { + std::string nl_au_string_wrong_terminals = nl_au_string; + nl_au_string_wrong_terminals = tl::replaced (nl_au_string_wrong_terminals, "(S=$5,G=IN,D=$2)", "(S=$2,G=IN,D=$5)"); + nl_au_string_wrong_terminals = tl::replaced (nl_au_string_wrong_terminals, "(S=$4,G=IN,D=$2)", "(S=$2,G=IN,D=$4)"); + + // compare vs. non-strict device classes with WRONG terminal assignment + db::Netlist au_nl; + // non-strict + db::DeviceClass *dc; + dc = new db::DeviceClassMOS3Transistor (); + dc->set_name ("PMOS"); + au_nl.add_device_class (dc); + dc = new db::DeviceClassMOS3Transistor (); + dc->set_name ("NMOS"); + au_nl.add_device_class (dc); + au_nl.from_string (nl_au_string_wrong_terminals); + + db::NetlistComparer comp (0); + EXPECT_EQ (comp.compare (&nl, &au_nl), false); + } + + // 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_au9.gds"); + + db::compare_layouts (_this, ly, au); +} diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 9ffaf7d79..ab1373625 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -161,6 +161,32 @@ module DRC RBA::DeviceExtractorMOS4Transistor::new(name) end + # %DRC% + # @brief Supplies the DMOS3 transistor extractor class + # @name dmos3 + # @synopsis dmos3(name) + # Use this class with \extract_devices to specify extraction of a + # three-terminal DMOS transistor. A DMOS transistor is essentially + # the same than a MOS transistor, but source and drain are + # separated. + + def dmos3(name) + RBA::DeviceExtractorMOS3Transistor::new(name, true) + end + + # %DRC% + # @brief Supplies the MOS4 transistor extractor class + # @name dmos4 + # @synopsis dmos4(name) + # Use this class with \extract_devices to specify extraction of a + # four-terminal DMOS transistor. A DMOS transistor is essentially + # the same than a MOS transistor, but source and drain are + # separated. + + def dmos4(name) + RBA::DeviceExtractorMOS4Transistor::new(name, true) + end + # %DRC% # @brief Supplies the BJT3 transistor extractor class # @name bjt3 diff --git a/src/lay/lay/doc/about/drc_ref_global.xml b/src/lay/lay/doc/about/drc_ref_global.xml index 0b3b3b2a6..ef89cacdd 100644 --- a/src/lay/lay/doc/about/drc_ref_global.xml +++ b/src/lay/lay/doc/about/drc_ref_global.xml @@ -204,6 +204,30 @@ See Netter#device_scaling Use this class with extract_devices to specify extraction of a planar diode

+

"dmos3" - Supplies the DMOS3 transistor extractor class

+ +

Usage:

+
    +
  • dmos3(name)
  • +
+

+Use this class with extract_devices to specify extraction of a +three-terminal DMOS transistor. A DMOS transistor is essentially +the same than a MOS transistor, but source and drain are +separated. +

+

"dmos4" - Supplies the MOS4 transistor extractor class

+ +

Usage:

+
    +
  • dmos4(name)
  • +
+

+Use this class with extract_devices to specify extraction of a +four-terminal DMOS transistor. A DMOS transistor is essentially +the same than a MOS transistor, but source and drain are +separated. +

"edge" - Creates an edge object

Usage:

diff --git a/src/lay/lay/doc/manual/lvs_device_extractors.xml b/src/lay/lay/doc/manual/lvs_device_extractors.xml index c3d07fd71..4af511c2a 100644 --- a/src/lay/lay/doc/manual/lvs_device_extractors.xml +++ b/src/lay/lay/doc/manual/lvs_device_extractors.xml @@ -187,6 +187,27 @@ extract_devices(mos4(model_name), { "SD" => (active - poly) & pplus, "G" =>

+

Diffusion MOS transistor extractor (dmos3 and dmos4)

+ +

+ DMOS devices are basically identical to MOS devices, but for those source and drain are + separated. This is often the case for diffusion MOS transistory, hence this name. +

+ +

+ DMOS and MOS devices share the same device class. DMOS devices are configured + such that source and drain cannot be swapped. The netlist compare will report + source/drain swapping as errors for such devices. +

+ +

+ DMOS transistors are recognized by their gate ("G" input), source ("S" input) and drain ("D" input) + regions. Source and drain needs to be separated from the gate shape. The touching edges of gate and + source/drain regions define the width of the device, the perpendicular dimension the gate length. + The terminal output layers for DMOS devices are the same than for MOS devices: "tS" for source, + "tD" for drain, "tG" for gate, "tB" for bulk (4-terminal version). +

+

Bipolar transistor extractor (bjt3 and bjt4)

diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc index 5c3319b22..1a7c9143c 100644 --- a/src/lvs/unit_tests/lvsSimpleTests.cc +++ b/src/lvs/unit_tests/lvsSimpleTests.cc @@ -129,3 +129,8 @@ TEST(11_device_scaling) run_test (_this, "ringo_simple_device_scaling", "ringo.gds"); } +TEST(12_simple_dmos) +{ + run_test (_this, "ringo_simple_dmos", "ringo.gds"); +} + diff --git a/testdata/algo/device_extract_au9.gds b/testdata/algo/device_extract_au9.gds new file mode 100644 index 0000000000000000000000000000000000000000..f8c19fbd8fd9cc2435e62cf928a5d7bcbd9b653b GIT binary patch literal 7982 zcmc&(Ux<`d6u!XxA79ytBs z?2Oqkkj)#4qRBlo^D_r_O-|1@$4t3uOti9SE}Cdn(HJu_REp#H%{absjc811Bc!h@ zs+?%bw;5Bem>l{>Tl&6F^chpQCytjc2*ziCOVI65?tvAKT8fVGJZyWgusvPL^ zfAsa6tI&TO-?$3iYsM7E6;*CAzr9;J*^6%#@w*@xp8@_(dj(aVZ7+GWSFo^+JlZR$ z@@#wK_~uubdz?r+p}VQ5a$=tNPD~ygoo_yb{ovyBbK+lo>$)+uHG=hv&~>{piYl+I z3F7mU&*wg@ot6DK_^IqiMU~giF3(@FUHEk@lKWXvDH$jyzonMX*&OY&1 zVUPGrQRQY|z)$%L`ge%G3SW!A1XWJV?XRh4W?K8}m&9Kt%ltRi4^k zzlMCQXOr;hXYvG9Zn0DTm>Vj&+}IFg{wRIU^CTF};JYs%$vUjP4EbfO%V7m)aG+s~ zBC@^Y+(vHyG)I&D>dg zcR$#>4*CUEucFFR`a}K*{4)ps2;&a_eW0jvV(xfPOu`J8Z#{o8KJ=%=smgl>`BzZo z%lSKw|DNN16|C^CIKurYsB-LQ-(Q};!TT8eQ-YPF$OCVH?@;B@sh;euN6~n5^69DR zW^$JXx$@>AtP6Yd<{`utdy{vCpvsBCT7$FC+{m-fJAr4u__m_T+xUU6nPaJ6^d{et z?^2%dyVOd9YHKU1o~8Vi@FTMs)@+f997!dimGR6hn04Zs%NQ2jd;tWiv4T*3S^~0V}^$PPGgIy^QLrv zHgmMi8SP=tSo<8e*NaKUPkSYOs&!oUdQCc@lH*5r7qQCfYOZ$CG-TD1`?>nk#^8jM zeXV`e^(j6S~QJ?a$L!xTtx2=)Q^!_22Yi!_wy-n3#NW zYJO_^@#LoTDrIBlUqbNT5v-gr=J1QSsT`^t=-+f+r3>D@;O`WyTmt_b_zqPLwEQmF z-*x7);wN^uvPDoyq;KZMZ{%hsX57r4y||Izr@exe6S$e*rM-eGPuc77jd^ZN{6(an zX75js{&M3P{(|1U^p_z0G>cA3QRO}Qs~Sb@I&H2Q9M;T(EQ39SdIf))Wjc%wE_4`; z))$VUFy@IbyqEEX)Ew_SF5lTsn3dTw`A)iJRO{X5u;b}Ar-{P2>l`$_o#wzZ<4t=v zVO0F)Syb0i)LxcNuXy8@&DxBkZCSYyCGonevGcvir1i{56EvHNyr zkBx;DY_OKcu4VJ~KA1gr;8^z9+@)a5Rl}`rrjvh$<%PiO(b{Hpy0g=DQV%^)aF_Mb z19|*bk7IkC9($mG-$&0G+=Y31sP?-wU(f1l9_UYMo_Xv@)Ml)CY+ucP1@1JD`$6ha gcC*XP!bE)S;PkXRJ6T^t@4JU5Xa~3d;WIc)6~o&L!zXh!YtAZkwne@h@qh`DG~J8B@mK`s1Qo9Bnawc z9VEyO-hx2TQ$&QPjzJMZ=Rok}Bj5I&ogH^q+%-WzkD1^1H^1M^{N_o9Eb9i)ZeKa*pbtKFSM)#;M9j;H5(zPw*;=~_57`+6u(wI%VooH6cU`x5lu4BOL1aBss+~!h-GM$6))y`Km+=d_bKtLlYA-G)>2Z=F z)+25+>jSEthT`;CTL;au(47N|9ABvR`1q{j_`*~(>+tJS?OWoT@clQI5dR7Cw*=h- z#6F@_J2P_rkRGvrdVY{~$bXko?SVck^-KHl&0(&hQ<28s0##Qs$#ws(Fp1KKB&tn` z{oxqX-8*=OGC87LmG(**_eOEd+sLc^_TJp8#E5v!fz$*McEC+u#O$zTjqc;$P%{*| zVd@t5t9L7+uV}_m?CjGTkEl~V1@1pNwPHA$8;Z=_yI zwWpgRdaakdw>9*LLEJTzj^E86rP`TsdSrBu=LcDb_`8&9Pu6pv;e1}d>A96^Pdfkl zFq$y$x=fpUA3dT}yU9n+?}Xn=VG5cy*DXxpE}w`>?kUyIOwyxX4WcjmAbO?Rvkeh_ zDjJ{rMD*p~MXyvl`Y1f_N&-F3T8I4I7iI=Q%nPO3!5BUA_7?e@5!#r&g-1A#Pqmww zh~5t3qqdKcpGBej5p{fs&py>&TujnK)5Ch4{UYlFs-1e0_1SsR=iZ54srKxAvc9xc z^krv7uT*kdQ%X$z|1C4Sx%K7}Na!hfa5I9&Vi{h0iiinEx|R)~{e) zJKhs$Bi0b+iBj#RJ<&(8y@-AqT~ zhx9}@8(A;3CvpChtQV?1Nk4K&^i0-`-VVrm-|yAie^0o7@KQ!rvECtmDFYY$zSwRZ jS5e;GrB1m`+$t=@Zi52@JM4z&Ji$&=(#aah16WW-+2!N9=A%f!IPz{bbKz`&p*zzif$Ffa(KKxio)1_tI9 z1_l@n69>{Pf(#5Sxb(B$f#~P@0MQSlVd6jl8Ai{d<109JZWjsO4v delta 334 zcmaFl|HxN~fsKKQDS|eC$GGUk6 z7!}HlU1qb4qA)J=#Kbc=<=7b*WLR;!bF&-25j!C@6FB7=C+9NqPTs>?JUN${dvX<@ j>12IAhsEo;m?!@im7RQsFBOODBG{F2cxkhX(mYlGooFw0 diff --git a/testdata/lvs/ringo_simple_dmos.cir b/testdata/lvs/ringo_simple_dmos.cir new file mode 100644 index 000000000..d517e69ba --- /dev/null +++ b/testdata/lvs/ringo_simple_dmos.cir @@ -0,0 +1,83 @@ +* Extracted by KLayout + +* cell RINGO +* pin FB +* pin VDD +* pin OUT +* pin ENABLE +* pin VSS +.SUBCKT RINGO 11 12 13 14 15 +* net 11 FB +* net 12 VDD +* net 13 OUT +* net 14 ENABLE +* net 15 VSS +* cell instance $1 r0 *1 1.8,0 +X$1 12 1 15 12 11 14 15 ND2X1 +* cell instance $2 r0 *1 4.2,0 +X$2 12 2 15 12 1 15 INVX1 +* cell instance $3 r0 *1 6,0 +X$3 12 3 15 12 2 15 INVX1 +* cell instance $4 r0 *1 7.8,0 +X$4 12 4 15 12 3 15 INVX1 +* cell instance $5 r0 *1 9.6,0 +X$5 12 5 15 12 4 15 INVX1 +* cell instance $6 r0 *1 11.4,0 +X$6 12 6 15 12 5 15 INVX1 +* cell instance $7 r0 *1 13.2,0 +X$7 12 7 15 12 6 15 INVX1 +* cell instance $8 r0 *1 15,0 +X$8 12 8 15 12 7 15 INVX1 +* cell instance $9 r0 *1 16.8,0 +X$9 12 9 15 12 8 15 INVX1 +* cell instance $10 r0 *1 18.6,0 +X$10 12 10 15 12 9 15 INVX1 +* cell instance $11 r0 *1 20.4,0 +X$11 12 11 15 12 10 15 INVX1 +* cell instance $12 r0 *1 22.2,0 +X$12 12 13 15 12 11 15 INVX1 +.ENDS RINGO + +* cell INVX1 +* pin VDD +* pin OUT +* pin VSS +* pin +* pin IN +* pin SUBSTRATE +.SUBCKT INVX1 1 2 3 4 5 6 +* net 1 VDD +* net 2 OUT +* net 3 VSS +* net 5 IN +* net 6 SUBSTRATE +* device instance $1 r0 *1 0.85,5.8 PMOS +M$1 1 5 2 4 PMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U +* device instance $2 r0 *1 0.85,2.135 NMOS +M$2 3 5 2 6 NMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U +.ENDS INVX1 + +* cell ND2X1 +* pin VDD +* pin OUT +* pin VSS +* pin +* pin B +* pin A +* pin SUBSTRATE +.SUBCKT ND2X1 1 2 3 5 6 7 8 +* net 1 VDD +* net 2 OUT +* net 3 VSS +* net 6 B +* net 7 A +* net 8 SUBSTRATE +* device instance $1 r0 *1 0.85,5.8 PMOS +M$1 1 7 2 5 PMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U +* device instance $2 r0 *1 1.55,5.8 PMOS +M$2 1 6 2 5 PMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U +* device instance $3 r0 *1 0.85,2.135 NMOS +M$3 4 7 3 8 NMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U +* device instance $4 r0 *1 1.55,2.135 NMOS +M$4 4 6 2 8 NMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U +.ENDS ND2X1 diff --git a/testdata/lvs/ringo_simple_dmos.lvs b/testdata/lvs/ringo_simple_dmos.lvs new file mode 100644 index 000000000..0879f5e1b --- /dev/null +++ b/testdata/lvs/ringo_simple_dmos.lvs @@ -0,0 +1,81 @@ + +source($lvs_test_source, "RINGO") + +report_lvs($lvs_test_target_lvsdb, true) + +target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout") + +schematic("ringo.cir") + +deep + +# Drawing layers + +nwell = input(1, 0) +active = input(2, 0) +pplus = input(3, 0) +nplus = input(4, 0) +poly = input(5, 0) +contact = input(8, 0) +metal1 = input(9, 0) +via1 = input(10, 0) +metal2 = input(11, 0) +source = input(14, 0) + +# Bulk layer for terminal provisioning + +bulk = polygon_layer + +# Computed layers + +active_in_nwell = active & nwell +pactive = active_in_nwell & pplus +pgate = pactive & poly +psd = pactive - pgate +ps = psd & source +pd = psd - source +ntie = active_in_nwell & nplus + +active_outside_nwell = active - nwell +nactive = active_outside_nwell & nplus +ngate = nactive & poly +nsd = nactive - ngate +ns = nsd & source +nd = nsd - source +ptie = active_outside_nwell & pplus + +# Device extraction + +# PMOS transistor device extraction +extract_devices(dmos4("PMOS"), { "S" => ps, "D" => pd, "G" => pgate, "W" => nwell, + "tS" => ps, "tD" => pd, "tG" => poly, "tW" => nwell }) + +# NMOS transistor device extraction +extract_devices(dmos4("NMOS"), { "S" => ns, "D" => nd, "G" => ngate, "W" => bulk, + "tS" => ns, "tD" => nd, "tG" => poly, "tW" => bulk }) + +# Define connectivity for netlist extraction + +# Inter-layer +connect(ps, contact) +connect(pd, contact) +connect(ns, contact) +connect(nd, contact) +connect(poly, contact) +connect(ntie, contact) +connect(nwell, ntie) +connect(ptie, contact) +connect(contact, metal1) +connect(metal1, via1) +connect(via1, metal2) + +# Global +connect_global(bulk, "SUBSTRATE") +connect_global(ptie, "SUBSTRATE") + +# Compare section + +netlist.simplify + +compare + diff --git a/testdata/lvs/ringo_simple_dmos.lvsdb b/testdata/lvs/ringo_simple_dmos.lvsdb new file mode 100644 index 000000000..9e3146d88 --- /dev/null +++ b/testdata/lvs/ringo_simple_dmos.lvsdb @@ -0,0 +1,925 @@ +#%lvsdb-klayout + +# Layout +layout( + top(RINGO) + unit(0.001) + + # Layer section + # This section lists the mask layers (drawing or derived) and their connections. + + # Mask layers + layer(l4 '1/0') + layer(l5 '5/0') + layer(l10 '8/0') + layer(l13 '9/0') + layer(l14 '10/0') + layer(l15 '11/0') + layer(l9) + layer(l3) + layer(l1) + layer(l11) + layer(l8) + layer(l6) + layer(l12) + + # Mask layer connectivity + connect(l4 l4 l11) + connect(l5 l5 l10) + connect(l10 l5 l10 l13 l3 l1 l11 l8 l6 l12) + connect(l13 l10 l13 l14) + connect(l14 l13 l14 l15) + connect(l15 l14 l15) + connect(l9 l9) + connect(l3 l10 l3) + connect(l1 l10 l1) + connect(l11 l4 l10 l11) + connect(l8 l10 l8) + connect(l6 l10 l6) + connect(l12 l10 l12) + + # Global nets and connectivity + global(l9 SUBSTRATE) + global(l12 SUBSTRATE) + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Device abstracts section + # Device abstracts list the pin shapes of the devices. + device(D$PMOS PMOS + terminal(S + rect(l3 (125 -750) (450 1500)) + ) + terminal(G + rect(l5 (-125 -750) (250 1500)) + ) + terminal(D + rect(l1 (-550 -750) (425 1500)) + ) + terminal(B + rect(l4 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$1 PMOS + terminal(S + rect(l3 (-575 -750) (450 1500)) + ) + terminal(G + rect(l5 (-125 -750) (250 1500)) + ) + terminal(D + rect(l1 (125 -750) (425 1500)) + ) + terminal(B + rect(l4 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$2 PMOS + terminal(S + rect(l3 (-550 -750) (425 1500)) + ) + terminal(G + rect(l5 (-125 -750) (250 1500)) + ) + terminal(D + rect(l1 (125 -750) (425 1500)) + ) + terminal(B + rect(l4 (-125 -750) (250 1500)) + ) + ) + device(D$NMOS NMOS + terminal(S + rect(l8 (125 -475) (450 950)) + ) + terminal(G + rect(l5 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (-550 -475) (425 950)) + ) + terminal(B + rect(l9 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$1 NMOS + terminal(S + rect(l8 (-575 -475) (450 950)) + ) + terminal(G + rect(l5 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l9 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$2 NMOS + terminal(S + rect(l8 (-550 -475) (425 950)) + ) + terminal(G + rect(l5 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l9 (-125 -475) (250 950)) + ) + ) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Circuit boundary + rect((-100 400) (2600 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l10 (1110 5160) (180 180)) + rect(l10 (-180 920) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l13 (-240 -790) (300 1700)) + rect(l13 (-1350 0) (2400 800)) + rect(l13 (-1151 -401) (2 2)) + rect(l3 (-276 -2151) (425 1500)) + rect(l3 (-400 -1500) (425 1500)) + ) + net(2 name(OUT) + rect(l10 (1810 1770) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l10 (-1580 3760) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l10 (1220 920) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l10 (-180 370) (180 180)) + polygon(l13 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) + rect(l13 (-110 1390) (300 1400)) + polygon(l13 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) + rect(l13 (-141 -501) (2 2)) + rect(l13 (-1751 1099) (300 1400)) + rect(l13 (1100 -1700) (300 300)) + rect(l13 (-300 0) (300 1400)) + rect(l1 (-1750 -1450) (425 1500)) + rect(l1 (950 -1500) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l10 (410 1770) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l13 (-240 -1300) (300 1360)) + rect(l13 (-650 -2160) (2400 800)) + rect(l13 (-1151 -401) (2 2)) + rect(l6 (-951 859) (425 950)) + ) + net(4 + rect(l8 (975 1660) (425 950)) + rect(l8 (-400 -950) (425 950)) + ) + net(5 + rect(l4 (-100 4500) (2600 3500)) + ) + net(6 name(B) + rect(l5 (1425 2860) (250 1940)) + rect(l5 (-345 -950) (300 300)) + rect(l5 (-205 650) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l10 (-285 1050) (180 180)) + rect(l13 (-71 -91) (2 2)) + rect(l13 (-171 -151) (300 300)) + ) + net(7 name(A) + rect(l5 (725 2860) (250 1940)) + rect(l5 (-325 -1850) (300 300)) + rect(l5 (-225 1550) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l10 (-265 150) (180 180)) + rect(l13 (-91 -91) (2 2)) + rect(l13 (-151 -151) (300 300)) + ) + net(8 name(SUBSTRATE)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(5) + pin(6 name(B)) + pin(7 name(A)) + pin(8 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.3375) + param(AD 0.6375) + param(PS 1.95) + param(PD 3.85) + terminal(S 1) + terminal(G 7) + terminal(D 2) + terminal(B 5) + ) + device(2 D$PMOS$1 + location(1550 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.3375) + param(AD 0.6375) + param(PS 1.95) + param(PD 3.85) + terminal(S 1) + terminal(G 6) + terminal(D 2) + terminal(B 5) + ) + device(3 D$NMOS + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.21375) + param(AD 0.40375) + param(PS 1.4) + param(PD 2.75) + terminal(S 4) + terminal(G 7) + terminal(D 3) + terminal(B 8) + ) + device(4 D$NMOS$1 + location(1550 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.21375) + param(AD 0.40375) + param(PS 1.4) + param(PD 2.75) + terminal(S 4) + terminal(G 6) + terminal(D 2) + terminal(B 8) + ) + + ) + circuit(INVX1 + + # Circuit boundary + rect((-100 400) (2000 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l10 (410 6260) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l13 (-240 -240) (300 1400)) + rect(l13 (-650 300) (1800 800)) + rect(l13 (-1450 -1100) (300 300)) + rect(l13 (299 399) (2 2)) + rect(l3 (-651 -2151) (425 1500)) + ) + net(2 name(OUT) + rect(l10 (1110 5160) (180 180)) + rect(l10 (-180 920) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l10 (-180 -4120) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l13 (-240 -790) (300 4790)) + rect(l13 (-151 -2501) (2 2)) + rect(l1 (-226 1049) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l10 (410 1770) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l13 (-240 -1300) (300 1360)) + rect(l13 (-650 -2160) (1800 800)) + rect(l13 (-851 -401) (2 2)) + rect(l8 (-651 859) (425 950)) + ) + net(4 + rect(l4 (-100 4500) (2000 3500)) + ) + net(5 name(IN) + rect(l5 (725 2860) (250 1940)) + rect(l5 (-525 -1850) (300 300)) + rect(l5 (-25 1550) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l10 (-465 150) (180 180)) + rect(l13 (-91 -91) (2 2)) + rect(l13 (-151 -151) (300 300)) + ) + net(6 name(SUBSTRATE)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4) + pin(5 name(IN)) + pin(6 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS$2 + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.6375) + param(PS 3.85) + param(PD 3.85) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 D$NMOS$2 + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.40375) + param(PS 2.75) + param(PD 2.75) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Circuit boundary + rect((0 350) (25800 7650)) + + # Nets with their geometries + net(1 + rect(l10 (4710 3010) (180 180)) + rect(l13 (-850 -240) (610 300)) + ) + net(2 + rect(l10 (6510 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(3 + rect(l10 (8310 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(4 + rect(l10 (10110 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(5 + rect(l10 (11910 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(6 + rect(l10 (13710 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(7 + rect(l10 (15510 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(8 + rect(l10 (17310 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(9 + rect(l10 (19110 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(10 + rect(l10 (20910 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(11 name(FB) + rect(l10 (22710 3010) (180 180)) + rect(l10 (-19700 720) (180 180)) + rect(l13 (18380 -1140) (900 300)) + rect(l13 (-19530 590) (320 320)) + rect(l13 (17820 -320) (320 320)) + rect(l14 (-18400 -260) (200 200)) + rect(l14 (17940 -200) (200 200)) + rect(l15 (-18040 -300) (17740 400)) + rect(l15 (-17921 -201) (2 2)) + rect(l15 (-221 -201) (400 400)) + rect(l15 (17740 -400) (400 400)) + ) + net(12 name(VDD) + rect(l4 (500 4500) (1400 3500)) + rect(l4 (-1900 -3500) (600 3500)) + rect(l4 (23300 -3500) (1400 3500)) + rect(l4 (-100 -3500) (600 3500)) + rect(l10 (-24690 -1240) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l10 (23220 370) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l13 (-21741 859) (2 2)) + rect(l13 (-2351 -451) (1200 800)) + rect(l13 (-750 -1450) (300 1400)) + rect(l13 (-101 -351) (2 2)) + rect(l13 (-1251 -401) (600 800)) + rect(l13 (23400 -800) (1200 800)) + rect(l13 (-750 -1450) (300 1400)) + rect(l13 (-101 -351) (2 2)) + rect(l13 (549 -401) (600 800)) + rect(l11 (-24850 -1500) (500 1500)) + rect(l11 (22900 -1500) (500 1500)) + ) + net(13 name(OUT) + rect(l13 (23440 3840) (320 320)) + rect(l14 (-260 -260) (200 200)) + rect(l15 (-101 -101) (2 2)) + rect(l15 (-201 -201) (400 400)) + ) + net(14 name(ENABLE) + rect(l10 (2510 3010) (180 180)) + rect(l13 (-250 -250) (320 320)) + rect(l14 (-260 -260) (200 200)) + rect(l15 (-101 -101) (2 2)) + rect(l15 (-201 -201) (400 400)) + ) + net(15 name(VSS) + rect(l10 (1110 1610) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l10 (23220 370) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l13 (-21741 -391) (2 2)) + rect(l13 (-1901 -401) (300 1400)) + rect(l13 (-750 -1450) (1200 800)) + rect(l13 (-551 -401) (2 2)) + rect(l13 (-1251 -401) (600 800)) + rect(l13 (23850 -750) (300 1400)) + rect(l13 (-750 -1450) (1200 800)) + rect(l13 (-551 -401) (2 2)) + rect(l13 (549 -401) (600 800)) + rect(l12 (-24850 -800) (500 1500)) + rect(l12 (22900 -1500) (500 1500)) + ) + + # Outgoing pins and their connections to nets + pin(11 name(FB)) + pin(12 name(VDD)) + pin(13 name(OUT)) + pin(14 name(ENABLE)) + pin(15 name(VSS)) + + # Subcircuits and their connections + circuit(1 ND2X1 location(1800 0) + pin(0 12) + pin(1 1) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 14) + pin(6 15) + ) + circuit(2 INVX1 location(4200 0) + pin(0 12) + pin(1 2) + pin(2 15) + pin(3 12) + pin(4 1) + pin(5 15) + ) + circuit(3 INVX1 location(6000 0) + pin(0 12) + pin(1 3) + pin(2 15) + pin(3 12) + pin(4 2) + pin(5 15) + ) + circuit(4 INVX1 location(7800 0) + pin(0 12) + pin(1 4) + pin(2 15) + pin(3 12) + pin(4 3) + pin(5 15) + ) + circuit(5 INVX1 location(9600 0) + pin(0 12) + pin(1 5) + pin(2 15) + pin(3 12) + pin(4 4) + pin(5 15) + ) + circuit(6 INVX1 location(11400 0) + pin(0 12) + pin(1 6) + pin(2 15) + pin(3 12) + pin(4 5) + pin(5 15) + ) + circuit(7 INVX1 location(13200 0) + pin(0 12) + pin(1 7) + pin(2 15) + pin(3 12) + pin(4 6) + pin(5 15) + ) + circuit(8 INVX1 location(15000 0) + pin(0 12) + pin(1 8) + pin(2 15) + pin(3 12) + pin(4 7) + pin(5 15) + ) + circuit(9 INVX1 location(16800 0) + pin(0 12) + pin(1 9) + pin(2 15) + pin(3 12) + pin(4 8) + pin(5 15) + ) + circuit(10 INVX1 location(18600 0) + pin(0 12) + pin(1 10) + pin(2 15) + pin(3 12) + pin(4 9) + pin(5 15) + ) + circuit(11 INVX1 location(20400 0) + pin(0 12) + pin(1 11) + pin(2 15) + pin(3 12) + pin(4 10) + pin(5 15) + ) + circuit(12 INVX1 location(22200 0) + pin(0 12) + pin(1 13) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 15) + ) + + ) +) + +# Reference netlist +reference( + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(B)) + net(6 name(A)) + net(7 name(BULK)) + net(8 name('1')) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(B)) + pin(6 name(A)) + pin(7 name(BULK)) + + # Devices and their connections + device(1 PMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 2) + terminal(G 6) + terminal(D 1) + terminal(B 4) + ) + device(2 PMOS + name($2) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(3 NMOS + name($3) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 6) + terminal(D 8) + terminal(B 7) + ) + device(4 NMOS + name($4) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 8) + terminal(G 5) + terminal(D 2) + terminal(B 7) + ) + + ) + circuit(INVX1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(IN)) + net(6 name(BULK)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(IN)) + pin(6 name(BULK)) + + # Devices and their connections + device(1 PMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 NMOS + name($2) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Nets + net(1 name(VSS)) + net(2 name(VDD)) + net(3 name(FB)) + net(4 name(ENABLE)) + net(5 name(OUT)) + net(6 name('1')) + net(7 name('2')) + net(8 name('3')) + net(9 name('4')) + net(10 name('5')) + net(11 name('6')) + net(12 name('7')) + net(13 name('8')) + net(14 name('9')) + net(15 name('10')) + + # Outgoing pins and their connections to nets + pin(1 name(VSS)) + pin(2 name(VDD)) + pin(3 name(FB)) + pin(4 name(ENABLE)) + pin(5 name(OUT)) + + # Subcircuits and their connections + circuit(1 ND2X1 name($1) + pin(0 2) + pin(1 6) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 4) + pin(6 1) + ) + circuit(2 INVX1 name($2) + pin(0 2) + pin(1 7) + pin(2 1) + pin(3 2) + pin(4 6) + pin(5 1) + ) + circuit(3 INVX1 name($3) + pin(0 2) + pin(1 8) + pin(2 1) + pin(3 2) + pin(4 7) + pin(5 1) + ) + circuit(4 INVX1 name($4) + pin(0 2) + pin(1 9) + pin(2 1) + pin(3 2) + pin(4 8) + pin(5 1) + ) + circuit(5 INVX1 name($5) + pin(0 2) + pin(1 10) + pin(2 1) + pin(3 2) + pin(4 9) + pin(5 1) + ) + circuit(6 INVX1 name($6) + pin(0 2) + pin(1 11) + pin(2 1) + pin(3 2) + pin(4 10) + pin(5 1) + ) + circuit(7 INVX1 name($7) + pin(0 2) + pin(1 12) + pin(2 1) + pin(3 2) + pin(4 11) + pin(5 1) + ) + circuit(8 INVX1 name($8) + pin(0 2) + pin(1 13) + pin(2 1) + pin(3 2) + pin(4 12) + pin(5 1) + ) + circuit(9 INVX1 name($9) + pin(0 2) + pin(1 14) + pin(2 1) + pin(3 2) + pin(4 13) + pin(5 1) + ) + circuit(10 INVX1 name($10) + pin(0 2) + pin(1 15) + pin(2 1) + pin(3 2) + pin(4 14) + pin(5 1) + ) + circuit(11 INVX1 name($11) + pin(0 2) + pin(1 3) + pin(2 1) + pin(3 2) + pin(4 15) + pin(5 1) + ) + circuit(12 INVX1 name($12) + pin(0 2) + pin(1 5) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 1) + ) + + ) +) + +# Cross reference +xref( + circuit(INVX1 INVX1 match + xref( + net(4 4 match) + net(5 5 match) + net(2 2 match) + net(6 6 match) + net(1 1 match) + net(3 3 match) + pin(3 3 match) + pin(4 4 match) + pin(1 1 match) + pin(5 5 match) + pin(0 0 match) + pin(2 2 match) + device(2 2 match) + device(1 1 match) + ) + ) + circuit(ND2X1 ND2X1 nomatch + xref( + net(4 8 mismatch) + net(5 4 mismatch) + net(7 6 match) + net(6 5 match) + net(2 2 mismatch) + net(8 7 mismatch) + net(1 1 mismatch) + net(3 3 mismatch) + pin(3 3 match) + pin(5 5 match) + pin(4 4 match) + pin(1 1 match) + pin(6 6 match) + pin(0 0 match) + pin(2 2 match) + device(4 4 match) + device(3 3 mismatch) + device(2 2 match) + device(1 1 mismatch) + ) + ) + circuit(RINGO RINGO match + xref( + net(1 6 match) + net(10 15 match) + net(2 7 match) + net(3 8 match) + net(4 9 match) + net(5 10 match) + net(6 11 match) + net(7 12 match) + net(8 13 match) + net(9 14 match) + net(14 4 match) + net(11 3 match) + net(13 5 match) + net(12 2 match) + net(15 1 match) + pin(3 3 match) + pin(0 2 match) + pin(2 4 match) + pin(1 1 match) + pin(4 0 match) + circuit(2 2 match) + circuit(3 3 match) + circuit(4 4 match) + circuit(5 5 match) + circuit(6 6 match) + circuit(7 7 match) + circuit(8 8 match) + circuit(9 9 match) + circuit(10 10 match) + circuit(11 11 match) + circuit(12 12 match) + circuit(1 1 match) + ) + ) +) diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb index 43f2f3a09..13665f01a 100644 --- a/testdata/ruby/dbNetlist.rb +++ b/testdata/ruby/dbNetlist.rb @@ -115,6 +115,10 @@ class DBNetlist_TestClass < TestBase assert_equal(nl.device_class_by_name("UVW") == cc, true) assert_equal(nl.device_class_by_name("doesntexist") == nil, true) + assert_equal(cc.strict?, false) + cc.strict = true + assert_equal(cc.strict?, true) + names = [] nl.each_device_class { |i| names << i.name } assert_equal(names, [ c.name, cc.name ])