diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index bf5de8610..4114a7e9f 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -46,7 +46,7 @@ Pin::Pin (const std::string &name) // Device class implementation Device::Device () - : mp_device_class (0), m_id (0) + : mp_device_class (0), m_id (0), mp_circuit (0) { // .. nothing yet .. } @@ -61,13 +61,13 @@ Device::~Device () } Device::Device (DeviceClass *device_class, const std::string &name) - : mp_device_class (device_class), m_name (name), m_id (0) + : mp_device_class (device_class), m_name (name), m_id (0), mp_circuit (0) { // .. nothing yet .. } Device::Device (const Device &other) - : mp_device_class (0), m_id (0) + : mp_device_class (0), m_id (0), mp_circuit (0) { operator= (other); } @@ -81,6 +81,11 @@ Device &Device::operator= (const Device &other) return *this; } +void Device::set_circuit (Circuit *circuit) +{ + mp_circuit = circuit; +} + void Device::set_name (const std::string &n) { m_name = n; @@ -176,7 +181,7 @@ void Device::set_parameter_value (const std::string &name, double v) // SubCircuit class implementation SubCircuit::SubCircuit () - : m_id (0) + : m_id (0), mp_circuit (0) { // .. nothing yet .. } @@ -191,13 +196,13 @@ SubCircuit::~SubCircuit() } SubCircuit::SubCircuit (Circuit *circuit, const std::string &name) - : m_circuit (circuit), m_name (name), m_id (0) + : m_circuit_ref (0), m_name (name), m_id (0), mp_circuit (0) { - // .. nothing yet .. + set_circuit_ref (circuit); } SubCircuit::SubCircuit (const SubCircuit &other) - : m_id (0) + : m_id (0), mp_circuit (0) { operator= (other); } @@ -206,8 +211,8 @@ SubCircuit &SubCircuit::operator= (const SubCircuit &other) { if (this != &other) { m_name = other.m_name; - m_circuit = other.m_circuit; m_trans = other.m_trans; + set_circuit_ref (const_cast (other.circuit_ref ())); } return *this; } @@ -230,6 +235,17 @@ void SubCircuit::set_pin_ref_for_pin (size_t pin_id, Net::pin_iterator iter) m_pin_refs [pin_id] = iter; } +void SubCircuit::set_circuit_ref (Circuit *c) +{ + if (m_circuit_ref.get ()) { + m_circuit_ref->unregister_ref (this); + } + m_circuit_ref.reset (c); + if (m_circuit_ref.get ()) { + m_circuit_ref->register_ref (this); + } +} + const Net *SubCircuit::net_for_pin (size_t pin_id) const { if (pin_id < m_pin_refs.size ()) { @@ -349,8 +365,8 @@ const Pin *NetPinRef::pin () const if (mp_net && mp_net->circuit ()) { return mp_net->circuit ()->pin_by_id (m_pin_id); } - } else if (mp_subcircuit->circuit ()) { - return mp_subcircuit->circuit ()->pin_by_id (m_pin_id); + } else if (mp_subcircuit->circuit_ref ()) { + return mp_subcircuit->circuit_ref ()->pin_by_id (m_pin_id); } return 0; } @@ -613,6 +629,8 @@ void Circuit::remove_net (Net *net) void Circuit::add_device (Device *device) { + device->set_circuit (this); + size_t id = 0; if (! m_devices.empty ()) { tl_assert (m_devices.back () != 0); @@ -658,6 +676,8 @@ Device *Circuit::device_by_id (size_t id) void Circuit::add_subcircuit (SubCircuit *subcircuit) { + subcircuit->set_circuit (this); + size_t id = 0; if (! m_subcircuits.empty ()) { tl_assert (m_subcircuits.back () != 0); @@ -701,12 +721,22 @@ SubCircuit *Circuit::subcircuit_by_id (size_t id) return d != m_subcircuit_id_table.end () ? d->second : 0; } +void Circuit::register_ref (SubCircuit *r) +{ + m_refs.push_back (r); +} + +void Circuit::unregister_ref (SubCircuit *r) +{ + m_refs.erase (r); +} + void Circuit::translate_circuits (const std::map &map) { for (subcircuit_iterator i = m_subcircuits.begin (); i != m_subcircuits.end (); ++i) { - std::map::const_iterator m = map.find (i->circuit ()); + std::map::const_iterator m = map.find (i->circuit_ref ()); tl_assert (m != map.end ()); - i->set_circuit (m->second); + i->set_circuit_ref (m->second); } } diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index cf44b1c84..2530ccc02 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -608,6 +608,24 @@ public: return m_id; } + /** + * @brief Gets the circuit the device lives in (const version) + * This pointer is 0 if the device isn't added to a circuit + */ + const Circuit *circuit () const + { + return mp_circuit; + } + + /** + * @brief Gets the circuit the device lives in (non-const version) + * This pointer is 0 if the device isn't added to a circuit + */ + Circuit *circuit () + { + return mp_circuit; + } + /** * @brief Sets the name */ @@ -675,6 +693,7 @@ private: std::vector m_terminal_refs; std::vector m_parameters; size_t m_id; + Circuit *mp_circuit; /** * @brief Sets the terminal reference for a specific terminal @@ -696,6 +715,11 @@ private: { m_id = id; } + + /** + * @brief Sets the circuit + */ + void set_circuit (Circuit *circuit); }; /** @@ -727,7 +751,7 @@ public: /** * @brief Creates a subcircuit reference to the given circuit */ - SubCircuit (Circuit *circuit, const std::string &name = std::string ()); + SubCircuit (Circuit *circuit_ref, const std::string &name = std::string ()); /** * @brief Destructor @@ -746,19 +770,37 @@ public: } /** - * @brief Gets the circuit the reference points to (const version) + * @brief Gets the circuit the subcircuit lives in (const version) + * This pointer is 0 if the subcircuit isn't added to a circuit */ const Circuit *circuit () const { - return m_circuit.get (); + return mp_circuit; + } + + /** + * @brief Gets the circuit the subcircuit lives in (non-const version) + * This pointer is 0 if the subcircuit isn't added to a circuit + */ + Circuit *circuit () + { + return mp_circuit; + } + + /** + * @brief Gets the circuit the reference points to (const version) + */ + const Circuit *circuit_ref () const + { + return m_circuit_ref.get (); } /** * @brief Gets the circuit the reference points to (non-const version) */ - Circuit *circuit () + Circuit *circuit_ref () { - return m_circuit.get (); + return m_circuit_ref.get (); } /** @@ -820,11 +862,12 @@ private: friend class Circuit; friend class Net; - tl::weak_ptr m_circuit; + tl::weak_ptr m_circuit_ref; std::string m_name; db::DCplxTrans m_trans; std::vector m_pin_refs; size_t m_id; + Circuit *mp_circuit; /** * @brief Sets the pin reference for a specific pin @@ -834,9 +877,14 @@ private: /** * @brief Sets the circuit reference */ + void set_circuit_ref (Circuit *c); + + /** + * @brief Sets the circuit the subcircuit belongs to + */ void set_circuit (Circuit *c) { - m_circuit.reset (c); + mp_circuit = c; } /** @@ -870,6 +918,8 @@ public: typedef tl::shared_collection subcircuit_list; typedef subcircuit_list::const_iterator const_subcircuit_iterator; typedef subcircuit_list::iterator subcircuit_iterator; + typedef tl::weak_collection::const_iterator const_refs_iterator; + typedef tl::weak_collection::iterator refs_iterator; /** * @brief Constructor @@ -939,9 +989,44 @@ public: return m_cell_index; } + /** + * @brief Gets the references to this circuit (begin, non-const version) + * This iterator will deliver all subcircuits referencing this circuit + */ + refs_iterator begin_refs () + { + return m_refs.begin (); + } + + /** + * @brief Gets the references to this circuit (end, non-const version) + * This iterator will deliver all subcircuits referencing this circuit + */ + refs_iterator end_refs () + { + return m_refs.end (); + } + + /** + * @brief Gets the references to this circuit (begin, const version) + * This iterator will deliver all subcircuits referencing this circuit + */ + const_refs_iterator begin_refs () const + { + return m_refs.begin (); + } + + /** + * @brief Gets the references to this circuit (end, const version) + * This iterator will deliver all subcircuits referencing this circuit + */ + const_refs_iterator end_refs () const + { + return m_refs.end (); + } + /** * @brief Adds a pin to this circuit - * * The circuit takes over ownership of the object. */ const Pin &add_pin(const Pin &pin); @@ -1200,6 +1285,7 @@ public: private: friend class Netlist; friend class Net; + friend class SubCircuit; std::string m_name; db::cell_index_type m_cell_index; @@ -1213,12 +1299,16 @@ private: std::map m_device_id_table; bool m_valid_subcircuit_id_table; std::map m_subcircuit_id_table; + tl::weak_collection m_refs; /** * @brief Sets the pin reference for a specific pin */ void set_pin_ref_for_pin (size_t ppin_id, Net::pin_iterator iter); + void register_ref (SubCircuit *sc); + void unregister_ref (SubCircuit *sc); + void translate_circuits (const std::map &map); void translate_device_classes (const std::map &map); void set_netlist (Netlist *netlist); diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index 5664a0884..f0ce1a7f3 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -46,10 +46,10 @@ NetlistDeviceExtractorError::NetlistDeviceExtractorError (const std::string &cel // ---------------------------------------------------------------------------------------- // NetlistDeviceExtractor implementation -NetlistDeviceExtractor::NetlistDeviceExtractor () +NetlistDeviceExtractor::NetlistDeviceExtractor (const std::string &name) : mp_layout (0), m_cell_index (0), mp_circuit (0) { - m_device_name_index = 0; + m_name = name; m_propname_id = 0; } @@ -67,8 +67,7 @@ const tl::Variant &NetlistDeviceExtractor::terminal_property_name () void NetlistDeviceExtractor::initialize (db::Netlist *nl) { m_layer_definitions.clear (); - m_device_classes.clear (); - m_device_name_index = 0; + mp_device_class = 0; m_propname_id = 0; m_netlist.reset (nl); @@ -108,16 +107,16 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, const NetlistDevi } - extract_without_initialize (dss.layout (), dss.initial_cell (), layers, nl); + extract_without_initialize (dss.layout (), dss.initial_cell (), layers); } void NetlistDeviceExtractor::extract (db::Layout &layout, db::Cell &cell, const std::vector &layers, db::Netlist *nl) { initialize (nl); - extract_without_initialize (layout, cell, layers, nl); + extract_without_initialize (layout, cell, layers); } -void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db::Cell &cell, const std::vector &layers, db::Netlist *nl) +void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db::Cell &cell, const std::vector &layers) { tl_assert (layers.size () == m_layer_definitions.size ()); @@ -216,9 +215,16 @@ void NetlistDeviceExtractor::extract_devices (const std::vector & /* void NetlistDeviceExtractor::register_device_class (DeviceClass *device_class) { + if (mp_device_class != 0) { + throw tl::Exception (tl::to_string (tr ("Device class already set"))); + } + + tl_assert (device_class != 0); + mp_device_class = device_class; + mp_device_class->set_name (m_name); + tl_assert (m_netlist.get () != 0); m_netlist->add_device_class (device_class); - m_device_classes.push_back (device_class); } void NetlistDeviceExtractor::define_layer (const std::string &name, const std::string &description) @@ -226,11 +232,14 @@ void NetlistDeviceExtractor::define_layer (const std::string &name, const std::s m_layer_definitions.push_back (db::NetlistDeviceExtractorLayerDefinition (name, description, m_layer_definitions.size ())); } -Device *NetlistDeviceExtractor::create_device (unsigned int device_class_index) +Device *NetlistDeviceExtractor::create_device () { + if (mp_device_class == 0) { + throw tl::Exception (tl::to_string (tr ("No device class registered"))); + } + tl_assert (mp_circuit != 0); - tl_assert (device_class_index < m_device_classes.size ()); - Device *device = new Device (m_device_classes[device_class_index], tl::to_string (++m_device_name_index)); + Device *device = new Device (mp_device_class); mp_circuit->add_device (device); return device; } diff --git a/src/db/db/dbNetlistDeviceExtractor.h b/src/db/db/dbNetlistDeviceExtractor.h index 5f4d458cf..871fc27a1 100644 --- a/src/db/db/dbNetlistDeviceExtractor.h +++ b/src/db/db/dbNetlistDeviceExtractor.h @@ -196,16 +196,24 @@ public: typedef std::map input_layers; /** - * @brief Default constructor + * @brief Constructor + * + * The name is the name of the device class of the devices generated. */ - NetlistDeviceExtractor (); + NetlistDeviceExtractor (const std::string &name); /** * @brief Destructor */ ~NetlistDeviceExtractor (); - // TODO: Do we need to declare input layers? + /** + * @brief Gets the name of the extractor and the device class + */ + const std::string &name () + { + return m_name; + } /** * @brief Gets the property name for the device terminal annotation @@ -292,8 +300,7 @@ protected: * defining the device classes and setting up the device layers. * * At least one device class needs to be defined. Use "register_device_class" to register - * the device classes you need. The first device class registered has device class index 0, - * the further ones 1, 2, etc. + * the device class you need. * * The device layers need to be defined by calling "define_layer" once or several times. */ @@ -323,7 +330,8 @@ protected: /** * @brief Registers a device class * The device class object will become owned by the netlist and must not be deleted by - * the caller. + * the caller. The name of the device class will be changed to the name given to + * the device extractor. * This method shall be used inside the implementation of "setup" to register * the device classes. */ @@ -343,7 +351,7 @@ protected: * The device object returned can be configured by the caller, e.g. set parameters. * It will be owned by the netlist and must not be deleted by the caller. */ - Device *create_device (unsigned int device_class_index = 0); + Device *create_device (); /** * @brief Defines a device terminal in the layout (a polygon) @@ -436,19 +444,23 @@ private: db::properties_id_type m_propname_id; db::cell_index_type m_cell_index; db::Circuit *mp_circuit; - std::vector m_device_classes; + db::DeviceClass *mp_device_class; + std::string m_name; layer_definitions m_layer_definitions; std::vector m_layers; - unsigned int m_device_name_index; error_list m_errors; + // no copying + NetlistDeviceExtractor (const NetlistDeviceExtractor &); + NetlistDeviceExtractor &operator= (const NetlistDeviceExtractor &); + /** * @brief Initializes the extractor * This method will produce the device classes required for the device extraction. */ void initialize (db::Netlist *nl); - void extract_without_initialize (db::Layout &layout, db::Cell &cell, const std::vector &layers, db::Netlist *nl); + void extract_without_initialize (db::Layout &layout, db::Cell &cell, const std::vector &layers); }; } diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index 32abccf50..126bff37c 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -51,6 +51,9 @@ Class decl_dbDevice ("db", "Device", gsi::method ("device_class", &db::Device::device_class, "@brief Gets the device class the device belongs to.\n" ) + + gsi::method ("circuit", (db::Circuit *(db::Device::*) ()) &db::Device::circuit, + "@brief Gets the circuit the device lives in." + ) + gsi::method ("id", &db::Device::id, "@brief Gets the device ID.\n" "The ID is a unique integer which identifies the device.\n" @@ -125,9 +128,13 @@ static void subcircuit_disconnect_pin1 (db::SubCircuit *subcircuit, const db::Pi } Class decl_dbSubCircuit ("db", "SubCircuit", - gsi::method ("circuit", (db::Circuit *(db::SubCircuit::*) ()) &db::SubCircuit::circuit, + gsi::method ("circuit_ref", (db::Circuit *(db::SubCircuit::*) ()) &db::SubCircuit::circuit_ref, "@brief Gets the circuit referenced by the subcircuit.\n" ) + + gsi::method ("circuit", (db::Circuit *(db::SubCircuit::*) ()) &db::SubCircuit::circuit, + "@brief Gets the circuit the subcircuit lives in.\n" + "This is NOT the circuit which is referenced. For getting the circuit that the subcircuit references, use \\circuit_ref." + ) + gsi::method ("id", &db::SubCircuit::id, "@brief Gets the subcircuit ID.\n" "The ID is a unique integer which identifies the subcircuit.\n" @@ -620,6 +627,9 @@ Class decl_dbCircuit ("db", "Circuit", "to the outside through such a pin. The pin is added after all existing " "pins. For more details see the \\Pin class." ) + + gsi::iterator ("each_ref", (db::Circuit::refs_iterator (db::Circuit::*) ()) &db::Circuit::begin_refs, (db::Circuit::refs_iterator (db::Circuit::*) ()) &db::Circuit::end_refs, + "@brief Iterates over the subcircuit objects referencing this circuit\n" + ) + gsi::iterator ("each_pin", (db::Circuit::pin_iterator (db::Circuit::*) ()) &db::Circuit::begin_pins, (db::Circuit::pin_iterator (db::Circuit::*) ()) &db::Circuit::end_pins, "@brief Iterates over the pins of the circuit" ) + diff --git a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc index a9eaa5ec8..f8450667b 100644 --- a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc @@ -54,6 +54,7 @@ namespace { { public: DummyDeviceExtractor () + : db::NetlistDeviceExtractor (std::string ("DUMMY")) { error ("msg1"); error ("msg2", db::Box (0, 1, 2, 3)); diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index bbf7c72ab..14f6517c4 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -44,172 +44,6 @@ #include #include -class MOSFETExtractor - : public db::NetlistDeviceExtractor -{ -public: - MOSFETExtractor (db::Layout *debug_out) - : db::NetlistDeviceExtractor (), 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)); - } - } - - virtual void setup () - { - define_layer ("PD", "P diffusion"); - define_layer ("ND", "N diffusion"); - define_layer ("G", "Gate"); - define_layer ("P", "Poly"); - - db::DeviceClassMOS3Transistor *pmos_class = new db::DeviceClassMOS3Transistor (); - pmos_class->set_name ("PMOS"); - register_device_class (pmos_class); - - db::DeviceClassMOS3Transistor *nmos_class = new db::DeviceClassMOS3Transistor (); - nmos_class->set_name ("NMOS"); - register_device_class (nmos_class); - } - - virtual db::Connectivity get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const - { - tl_assert (layers.size () == 4); - - unsigned int lpdiff = layers [0]; - unsigned int lndiff = layers [1]; - unsigned int gate = layers [2]; - // not used for device recognition: poly (3), but used for producing the gate terminals - - // The layer definition is pdiff, ndiff, gate - db::Connectivity conn; - // collect all connected pdiff - conn.connect (lpdiff, lpdiff); - // collect all connected ndiff - conn.connect (lndiff, lndiff); - // collect all connected gate shapes - conn.connect (gate, gate); - // connect gate with pdiff - conn.connect (lpdiff, gate); - // connect gate with ndiff - conn.connect (lndiff, gate); - return conn; - } - - virtual void extract_devices (const std::vector &layer_geometry) - { - const db::Region &rpdiff = layer_geometry [0]; - const db::Region &rndiff = layer_geometry [1]; - const db::Region &rgates = layer_geometry [2]; - - for (db::Region::const_iterator p = rgates.begin_merged (); !p.at_end (); ++p) { - - db::Region rgate (*p); - db::Region rpdiff_on_gate = rpdiff.selected_interacting (rgate); - db::Region rndiff_on_gate = rndiff.selected_interacting (rgate); - - if (! rpdiff_on_gate.empty () && ! rndiff_on_gate.empty ()) { - error (tl::to_string (tr ("Gate shape touches both ndiff and pdiff - ignored")), *p); - } else if (rpdiff_on_gate.empty () && rndiff_on_gate.empty ()) { - error (tl::to_string (tr ("Gate shape touches neither ndiff and pdiff - ignored")), *p); - } else { - - bool is_pmos = ! rpdiff_on_gate.empty (); - - db::Region &diff = (is_pmos ? rpdiff_on_gate : rndiff_on_gate); - unsigned int terminal_geometry_index = (is_pmos ? 0 : 1); - unsigned int gate_geometry_index = 3; - unsigned int device_class_index = (is_pmos ? 0 /*PMOS*/ : 1 /*NMOS*/); - - if (diff.size () != 2) { - error (tl::sprintf (tl::to_string (tr ("Expected two polygons on diff interacting one gate shape (found %d) - gate shape ignored")), int (diff.size ())), *p); - continue; - } - - db::Edges edges (rgate.edges () & diff.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_class_index); - - device->set_parameter_value ("W", dbu () * edges.length () * 0.5); - device->set_parameter_value ("L", dbu () * (p->perimeter () - edges.length ()) * 0.5); - - int diff_index = 0; - for (db::Region::const_iterator d = diff.begin (); !d.at_end () && diff_index < 2; ++d, ++diff_index) { - - // count the number of gate shapes attached to this shape and distribute the area of the - // diffusion region to the number of gates - int n = rgates.selected_interacting (db::Region (*d)).size (); - tl_assert (n > 0); - - device->set_parameter_value (diff_index == 0 ? "AS" : "AD", dbu () * dbu () * d->area () / double (n)); - - define_terminal (device, device->device_class ()->terminal_id_for_name (diff_index == 0 ? "S" : "D"), terminal_geometry_index, *d); - - } - - define_terminal (device, device->device_class ()->terminal_id_for_name ("G"), gate_geometry_index, *p); - - // output the device for debugging - device_out (device, diff, rgate); - - } - - } - } - -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) { - return; - } - - 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->name ()).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); - } - - 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 (m_ldiff).insert (db::Text (ps, db::Trans (diff.bbox ().center () - db::Point ()))); - } -}; - -static unsigned int define_layer (db::Layout &ly, db::LayerMap &lmap, int gds_layer, int gds_datatype = 0) -{ - unsigned int lid = ly.insert_layer (db::LayerProperties (gds_layer, gds_datatype)); - lmap.map (ly.get_properties (lid), lid); - return lid; -} - static unsigned int layer_of (const db::Region ®ion) { return db::DeepLayer (region).layer (); @@ -248,6 +82,153 @@ static std::string pin_name (const db::Pin &pin) } } + +class MOSFETExtractor + : public db::NetlistDeviceExtractor +{ +public: + MOSFETExtractor (const std::string &name, db::Layout *debug_out) + : db::NetlistDeviceExtractor (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)); + } + } + + virtual void setup () + { + define_layer ("SD", "Source/drain diffusion"); + define_layer ("G", "Gate"); + define_layer ("P", "Poly"); + + register_device_class (new db::DeviceClassMOS3Transistor ()); + } + + virtual db::Connectivity get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const + { + tl_assert (layers.size () == 3); + + unsigned int diff = layers [0]; + unsigned int gate = layers [1]; + // not used for device recognition: poly (2), but used for producing the gate terminals + + // 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; + } + + virtual void extract_devices (const std::vector &layer_geometry) + { + const db::Region &rdiff = layer_geometry [0]; + const db::Region &rgates = layer_geometry [1]; + + for (db::Region::const_iterator p = rgates.begin_merged (); !p.at_end (); ++p) { + + db::Region rgate (*p); + db::Region rdiff2gate = rdiff.selected_interacting (rgate); + + if (rdiff2gate.empty ()) { + error (tl::to_string (tr ("Gate shape touches no diffusion - ignored")), *p); + } else { + + unsigned int terminal_geometry_index = 0; + unsigned int gate_geometry_index = 2; + + if (rdiff2gate.size () != 2) { + error (tl::sprintf (tl::to_string (tr ("Expected two polygons on diff interacting one gate shape (found %d) - gate shape ignored")), int (rdiff2gate.size ())), *p); + continue; + } + + 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 (! 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_parameter_value ("W", dbu () * edges.length () * 0.5); + device->set_parameter_value ("L", dbu () * (p->perimeter () - edges.length ()) * 0.5); + + int diff_index = 0; + for (db::Region::const_iterator d = rdiff2gate.begin (); !d.at_end () && diff_index < 2; ++d, ++diff_index) { + + // count the number of gate shapes attached to this shape and distribute the area of the + // diffusion region to the number of gates + int n = rgates.selected_interacting (db::Region (*d)).size (); + tl_assert (n > 0); + + device->set_parameter_value (diff_index == 0 ? "AS" : "AD", dbu () * dbu () * d->area () / double (n)); + + define_terminal (device, device->device_class ()->terminal_id_for_name (diff_index == 0 ? "S" : "D"), terminal_geometry_index, *d); + + } + + define_terminal (device, device->device_class ()->terminal_id_for_name ("G"), gate_geometry_index, *p); + + // output the device for debugging + device_out (device, rdiff2gate, rgate); + + } + + } + } + +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) { + return; + } + + 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); + } + + 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 (m_ldiff).insert (db::Text (ps, db::Trans (diff.bbox ().center () - db::Point ()))); + } +}; + +static unsigned int define_layer (db::Layout &ly, db::LayerMap &lmap, int gds_layer, int gds_datatype = 0) +{ + unsigned int lid = ly.insert_layer (db::LayerProperties (gds_layer, gds_datatype)); + lmap.map (ly.get_properties (lid), lid); + return lid; +} + // @@@ TODO: move this somewhere else static void dump_nets (const db::Netlist &nl, const db::hier_clusters &clusters, db::Layout &ly, const std::map &lmap, const db::CellMapping &cmap) @@ -329,14 +310,15 @@ static std::string netlist2string (const db::Netlist &nl) for (db::Circuit::const_subcircuit_iterator sc = c->begin_subcircuits (); sc != c->end_subcircuits (); ++sc) { std::string ps; const db::SubCircuit &subcircuit = *sc; - for (db::Circuit::const_pin_iterator p = sc->circuit ()->begin_pins (); p != sc->circuit ()->end_pins (); ++p) { - if (p != sc->circuit ()->begin_pins ()) { + const db::Circuit *circuit = sc->circuit_ref (); + for (db::Circuit::const_pin_iterator p = circuit->begin_pins (); p != circuit->end_pins (); ++p) { + if (p != circuit->begin_pins ()) { ps += ","; } const db::Pin &pin = *p; ps += pin_name (pin) + "=" + net_name (subcircuit.net_for_pin (pin.id ())); } - res += std::string (" X") + sc->circuit ()->name () + " " + subcircuit_name (*sc) + " (" + ps + ")\n"; + res += std::string (" X") + circuit->name () + " " + subcircuit_name (*sc) + " (" + ps + ")\n"; } } @@ -344,7 +326,7 @@ static std::string netlist2string (const db::Netlist &nl) return res; } -TEST(2_DeviceAndNetExtraction) +TEST(1_DeviceAndNetExtraction) { db::Layout ly; db::LayerMap lmap; @@ -396,10 +378,14 @@ TEST(2_DeviceAndNetExtraction) db::Region rmetal2_lbl (db::RecursiveShapeIterator (ly, tc, metal2_lbl), dss); // derived regions - db::Region rgate = ractive & rpoly; - db::Region rsd = ractive - rgate; - db::Region rpdiff = rsd & rnwell; - db::Region rndiff = rsd - rnwell; + + db::Region rpactive = ractive & rnwell; + db::Region rpgate = rpactive & rpoly; + db::Region rpsd = rpactive - rpgate; + + db::Region rnactive = ractive - rnwell; + db::Region rngate = rnactive & rpoly; + db::Region rnsd = rnactive - rngate; // return the computed layers into the original layout and write it for debugging purposes @@ -408,10 +394,12 @@ TEST(2_DeviceAndNetExtraction) unsigned int lpdiff = ly.insert_layer (db::LayerProperties (12, 0)); // 12/0 -> P Diffusion unsigned int lndiff = ly.insert_layer (db::LayerProperties (13, 0)); // 13/0 -> N Diffusion - rgate.insert_into (&ly, tc.cell_index (), lgate); - rsd.insert_into (&ly, tc.cell_index (), lsd); - rpdiff.insert_into (&ly, tc.cell_index (), lpdiff); - rndiff.insert_into (&ly, tc.cell_index (), lndiff); + 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); // perform the extraction @@ -420,15 +408,20 @@ TEST(2_DeviceAndNetExtraction) // NOTE: the device extractor will add more debug layers for the transistors: // 20/0 -> Diffusion // 21/0 -> Gate - MOSFETExtractor ex (&ly); + MOSFETExtractor pmos_ex ("PMOS", &ly); + MOSFETExtractor nmos_ex ("NMOS", &ly); db::NetlistDeviceExtractor::input_layers dl; - dl["PD"] = &rpdiff; - dl["ND"] = &rndiff; - dl["G"] = &rgate; - dl["P"] = &rpoly; - ex.extract (dss, dl, &nl); + dl["SD"] = &rpsd; + dl["G"] = &rpgate; + dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes + pmos_ex.extract (dss, dl, &nl); + + dl["SD"] = &rnsd; + dl["G"] = &rngate; + dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes + nmos_ex.extract (dss, dl, &nl); // perform the net extraction @@ -436,8 +429,8 @@ TEST(2_DeviceAndNetExtraction) db::Connectivity conn; // Intra-layer - conn.connect (rpdiff); - conn.connect (rndiff); + conn.connect (rpsd); + conn.connect (rnsd); conn.connect (rpoly); conn.connect (rdiff_cont); conn.connect (rpoly_cont); @@ -445,8 +438,8 @@ TEST(2_DeviceAndNetExtraction) conn.connect (rvia1); conn.connect (rmetal2); // Inter-layer - conn.connect (rpdiff, rdiff_cont); - conn.connect (rndiff, rdiff_cont); + conn.connect (rpsd, rdiff_cont); + conn.connect (rnsd, rdiff_cont); conn.connect (rpoly, rpoly_cont); conn.connect (rpoly_cont, rmetal1); conn.connect (rdiff_cont, rmetal1); @@ -468,9 +461,11 @@ TEST(2_DeviceAndNetExtraction) // 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 (rpdiff) ] = ly.insert_layer (db::LayerProperties (210, 0)); - dump_map [layer_of (rndiff) ] = ly.insert_layer (db::LayerProperties (211, 0)); + dump_map [layer_of (rpsd) ] = ly.insert_layer (db::LayerProperties (210, 0)); + dump_map [layer_of (rnsd) ] = ly.insert_layer (db::LayerProperties (211, 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)); @@ -496,10 +491,10 @@ TEST(2_DeviceAndNetExtraction) " XINV2 $9 ($1=$I6,$2=$I45,$3=$I7,$4=VSS,$5=VDD)\n" " XINV2 $10 ($1=$I7,$2=$I46,$3=$I8,$4=VSS,$5=VDD)\n" "Circuit INV2 ($1=IN,$2=$2,$3=OUT,$4=$4,$5=$5):\n" - " DPMOS 1 (S=$2,G=IN,D=$5) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" - " DPMOS 2 (S=$5,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" - " DNMOS 3 (S=$2,G=IN,D=$4) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" - " DNMOS 4 (S=$4,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DPMOS $1 (S=$2,G=IN,D=$5) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DPMOS $2 (S=$5,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DNMOS $3 (S=$2,G=IN,D=$4) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DNMOS $4 (S=$4,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" " XTRANS $1 ($1=$2,$2=$4,$3=IN)\n" " XTRANS $2 ($1=$2,$2=$5,$3=IN)\n" " XTRANS $3 ($1=$5,$2=OUT,$3=$2)\n" @@ -523,19 +518,9 @@ TEST(2_DeviceAndNetExtraction) // An attempt to simplify things. /* -- layers: use db::Region, or wrapper? --> use regions, but test whether they are deep regions (?) - TODO: - netlist query functions such as net_by_name, device_by_name, circuit_by_name - terminal geometry (Polygon) for device, combined device geometry (all terminals) -- error interface for device extraction - // gets the device extraction errors - // device_extraction_error_iterator begin_device_extraction_errors () const; - // device_extraction_error_iterator end_device_extraction_errors () const; - // bool has_device_extraction_errors () const; - -- device extractor needs to declare the layers to allow passing them by name - netlist manipulation methods (i.e. flatten certain cells, purging etc.) */ @@ -551,23 +536,25 @@ public: // the iterator provides the hierarchical selection (enabling/disabling cells etc.) LayoutToNetlist (const db::RecursiveShapeIterator &iter); - // --- preparation + // --- Step 0: configuration - // returns a new'd region + void set_threads (unsigned int n); + void set_area_ratio (double ar); + void set_max_vertex_count (size_t n); + + // --- Step 1: preparation + + // returns new'd regions db::Region *make_layer (unsigned int layer_index); db::Region *make_text_layer (unsigned int layer_index); db::Region *make_polygon_layer (unsigned int layer_index); - // gets the internal layout and cell - const db::Layout &internal_layout () const; - const db::Cell &internal_top_cell () const; - - // --- device extraction + // --- Step 2: device extraction // after this, the device extractor will have errors if some occured. - void extract_devices (db::NetlistDeviceExtractor *extractor, const std::map &layers); + void extract_devices (db::NetlistDeviceExtractor &extractor, const std::map &layers); - // --- net extraction + // --- Step 3: net extraction // define connectivity for the netlist extraction void connect (const db::Region &l); @@ -576,7 +563,11 @@ public: // runs the netlist extraction void extract_netlist (); - // --- retrieval + // --- Step 4: retrieval + + // gets the internal layout and cell (0 if not available) + const db::Layout *internal_layout () const; + const db::Cell *internal_top_cell () const; // gets the internal layer index of the given region unsigned int layer_of (const db::Region ®ion) const; @@ -600,6 +591,11 @@ public: // copies the shapes of the given net from a given layer // (recursive true: include nets from subcircuits) db::Region shapes_of_net (const db::Net &net, const db::Region &of_layer, bool recursive); + + // finds the net by probing a specific location on the given layer looking through the + // hierarchy. Returns 0 if no net was found. + db::Net *probe_net (const db::Region &of_region, const db::DPoint &point); + db::Net *probe_net (const db::Region &of_region, const db::Point &point); }; } diff --git a/src/db/unit_tests/dbNetlistTests.cc b/src/db/unit_tests/dbNetlistTests.cc index e1df6d1df..9a2a172d4 100644 --- a/src/db/unit_tests/dbNetlistTests.cc +++ b/src/db/unit_tests/dbNetlistTests.cc @@ -165,7 +165,7 @@ static std::string net2string (const db::Net &n) res += ","; } if (i->subcircuit ()) { - res += i->subcircuit ()->circuit () ? i->subcircuit ()->circuit ()->name () : "(null)"; + res += i->subcircuit ()->circuit_ref () ? i->subcircuit ()->circuit_ref ()->name () : "(null)"; res += ":"; } else { res += "+"; @@ -221,15 +221,15 @@ static std::string netlist2 (const db::Circuit &c) } for (db::Circuit::const_subcircuit_iterator s = c.begin_subcircuits (); s != c.end_subcircuits (); ++s) { - if (! s->circuit ()) { + if (! s->circuit_ref ()) { continue; } pins.clear (); - for (size_t i = 0; i < s->circuit ()->pin_count (); ++i) { + for (size_t i = 0; i < s->circuit_ref ()->pin_count (); ++i) { if (! pins.empty ()) { pins += ","; } - pins += s->circuit ()->pin_by_id (i)->name (); + pins += s->circuit_ref ()->pin_by_id (i)->name (); pins += "="; const db::Net *net = s->net_for_pin (i); pins += net ? net->name () : std::string ("(null)"); @@ -268,7 +268,11 @@ TEST(4_CircuitDevices) db::Device *d1 = new db::Device (&dc1, "d1"); db::Device *d2a = new db::Device (&dc2, "d2a"); db::Device *d2b = new db::Device (&dc2, "d2b"); + + EXPECT_EQ (d1->circuit () == 0, true); + c->add_device (d1); + EXPECT_EQ (d1->circuit () == c.get (), true); EXPECT_EQ (d1->id (), size_t (1)); EXPECT_EQ (c->device_by_id (d1->id ()) == d1, true); c->add_device (dd); @@ -386,6 +390,18 @@ static std::string netlist2 (const db::Netlist &nl) return res; } +static std::string refs2string (const db::Circuit *c) +{ + std::string res; + for (db::Circuit::const_refs_iterator r = c->begin_refs (); r != c->end_refs (); ++r) { + if (!res.empty ()) { + res += ","; + } + res += r->name (); + } + return res; +} + TEST(4_NetlistSubcircuits) { std::auto_ptr nl (new db::Netlist ()); @@ -413,14 +429,19 @@ TEST(4_NetlistSubcircuits) db::Device *d = new db::Device (dc, "D"); c2->add_device (d); + EXPECT_EQ (refs2string (c2), ""); db::SubCircuit *sc1 = new db::SubCircuit (c2); sc1->set_name ("sc1"); + EXPECT_EQ (refs2string (c2), "sc1"); + EXPECT_EQ (sc1->circuit () == 0, true); c1->add_subcircuit (sc1); + EXPECT_EQ (sc1->circuit () == c1, true); EXPECT_EQ (sc1->id (), size_t (1)); EXPECT_EQ (c1->subcircuit_by_id (sc1->id ()) == sc1, true); db::SubCircuit *sc2 = new db::SubCircuit (c2); sc2->set_name ("sc2"); + EXPECT_EQ (refs2string (c2), "sc1,sc2"); c1->add_subcircuit (sc2); EXPECT_EQ (sc2->id (), size_t (2)); EXPECT_EQ (c1->subcircuit_by_id (sc2->id ()) == sc2, true); @@ -778,3 +799,38 @@ TEST(10_NetPinRefBasics) EXPECT_EQ (db::NetPinRef (&d1, 1) < db::NetPinRef (&d1, 0), false); EXPECT_NE ((db::NetPinRef (&d1, 0) < db::NetPinRef (&d2, 0)), (db::NetPinRef (&d2, 0) < db::NetPinRef (&d1, 0))); } + +TEST(11_NetlistCircuitRefs) +{ + std::auto_ptr nl (new db::Netlist ()); + + db::Circuit *c1 = new db::Circuit (); + c1->set_name ("c1"); + nl->add_circuit (c1); + + db::Circuit *c2 = new db::Circuit (); + c2->set_name ("c2"); + nl->add_circuit (c2); + + db::SubCircuit *sc1 = new db::SubCircuit (c2); + sc1->set_name ("sc1"); + EXPECT_EQ (refs2string (c2), "sc1"); + c1->add_subcircuit (sc1); + + db::SubCircuit *sc2 = new db::SubCircuit (c2); + sc2->set_name ("sc2"); + EXPECT_EQ (refs2string (c2), "sc1,sc2"); + c1->add_subcircuit (sc2); + + *sc2 = db::SubCircuit (); + EXPECT_EQ (refs2string (c2), "sc1"); + + db::SubCircuit sc3 (c2); + sc3.set_name ("sc3"); + *sc2 = sc3; + sc2->set_name ("sc2"); + EXPECT_EQ (refs2string (c2), "sc1,sc3,sc2"); + + sc3 = db::SubCircuit (); + EXPECT_EQ (refs2string (c2), "sc1,sc2"); +} diff --git a/testdata/algo/device_extract_au1.gds b/testdata/algo/device_extract_au1.gds index 05c3b013f..a970a662c 100644 Binary files a/testdata/algo/device_extract_au1.gds and b/testdata/algo/device_extract_au1.gds differ diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb index eeead78df..04249daab 100644 --- a/testdata/ruby/dbNetlist.rb +++ b/testdata/ruby/dbNetlist.rb @@ -258,22 +258,35 @@ class DBNetlist_TestClass < TestBase sc1 = c.create_subcircuit(cc) sc1.name = "SC1" + assert_equal(sc1.circuit.object_id, c.object_id) assert_equal(sc1.name, "SC1") - assert_equal(sc1.circuit.name, "CC") + assert_equal(sc1.circuit_ref.name, "CC") assert_equal(c.subcircuit_by_id(sc1.id).id, 1) assert_equal(c.subcircuit_by_id(2).inspect, "nil") + refs = [] + cc.each_ref { |r| refs << r.name } + assert_equal(refs.join(","), "SC1") + sc2 = c.create_subcircuit(cc) sc2.name = "SC2" + refs = [] + cc.each_ref { |r| refs << r.name } + assert_equal(refs.join(","), "SC1,SC2") + names = [] ccn = [] - c.each_subcircuit { |sc| names << sc.name; ccn << sc.circuit.name } + c.each_subcircuit { |sc| names << sc.name; ccn << sc.circuit_ref.name } assert_equal(names, [ "SC1", "SC2" ]) assert_equal(ccn, [ "CC", "CC" ]) c.remove_subcircuit(sc2) + refs = [] + cc.each_ref { |r| refs << r.name } + assert_equal(refs.join(","), "SC1") + names = [] c.each_subcircuit { |sc| names << sc.name} assert_equal(names, [ "SC1" ]) @@ -282,7 +295,7 @@ class DBNetlist_TestClass < TestBase names = [] ccn = [] - c.each_subcircuit { |sc| names << sc.name; ccn << sc.circuit.name } + c.each_subcircuit { |sc| names << sc.name; ccn << sc.circuit_ref.name } assert_equal(names, [ "SC1", "SC2" ]) assert_equal(ccn, [ "CC", "CC" ]) @@ -531,6 +544,8 @@ class DBNetlist_TestClass < TestBase nl.add(c) d1 = c.create_device(dc) + assert_equal(d1.circuit.object_id, c.object_id) + assert_equal(d1.parameter(0), 1.0) assert_equal(d1.parameter("U"), 1.0) assert_equal(d1.parameter(1), 2.0)