diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 5bac02736..3e54f5cac 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -262,6 +262,21 @@ void LayoutToNetlist::ensure_netlist () } } +void LayoutToNetlist::register_device_class (const DeviceClass &device_class) +{ + m_device_classes.push_back (device_class.clone ()); +} + +const DeviceClass *LayoutToNetlist::device_class_by_name (const std::string &name) const +{ + for (auto d = m_device_classes.begin (); d != m_device_classes.end (); ++d) { + if (d->name () == name) { + return d.operator-> (); + } + } + return 0; +} + void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, const std::map &layers) { if (m_netlist_extracted) { @@ -271,7 +286,34 @@ void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, co ensure_netlist (); extractor.clear_log_entries (); - extractor.extract (dss (), m_layout_index, layers, *mp_netlist, m_net_clusters, m_device_scaling); + + extractor.initialize (mp_netlist.get ()); + + // Try finding the device class in the registered devices in the following order: + // 1.) Registered by the extractor during setup() (called by initialize()) + // 2.) A corresponding device class already present in the netlist (done during initialize()) + // 3.) Registered in LayoutToNetlist through register_device_class() + // 4.) The default class + + if (! extractor.device_class ()) { + const db::DeviceClass *dc = device_class_by_name (extractor.name ()); + if (dc) { + extractor.register_device_class (dc->clone ()); + } + } + + if (! extractor.device_class ()) { + db::DeviceClass *ddc = extractor.default_device_class (); + if (ddc) { + extractor.register_device_class (ddc); + } + } + + if (! extractor.device_class ()) { + throw tl::Exception (tl::to_string (tr ("No device class registered for device extractor '%s' - cannot extract devices.")), extractor.name ()); + } + + extractor.extract (dss (), m_layout_index, layers, m_net_clusters, m_device_scaling); // transfer errors to log entries m_log_entries.insert (m_log_entries.end (), extractor.begin_log_entries (), extractor.end_log_entries ()); diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 8c0c31d9a..55808bd6b 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -725,6 +725,25 @@ public: return m_netlist_extracted; } + /** + * @brief Registers a device class + * + * This method registers a device class for device extraction. + * This way of registering device classes is provided alternatively to + * the private device class provided by the device extractors. + * This way, device class management is centralized, which is in + * favor of device-class specific configurations such as SPICE + * profiles. + */ + void register_device_class (const DeviceClass &device_class); + + /** + * @brief Gets a device class by device class name + * + * If there is no class with that name, a null pointer is returned. + */ + const DeviceClass *device_class_by_name (const std::string &name) const; + /** * @brief Gets the internal DeepShapeStore object * @@ -1226,6 +1245,7 @@ private: db::Connectivity m_conn; db::hier_clusters m_net_clusters; std::unique_ptr mp_netlist; + tl::shared_collection m_device_classes; std::set m_dlrefs; std::map m_named_dls; std::map m_name_of_layer; diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index 9424007b8..db7f31c73 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -78,6 +78,10 @@ void NetlistDeviceExtractor::initialize (db::Netlist *nl) m_netlist.reset (nl); setup (); + + if (! mp_device_class.get () && nl) { + mp_device_class.reset (nl->device_class_by_name (m_name)); + } } static void insert_into_region (const db::NetShape &s, const db::ICplxTrans &tr, db::Region ®ion) @@ -88,10 +92,8 @@ static void insert_into_region (const db::NetShape &s, const db::ICplxTrans &tr, } } -void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layout_index, const NetlistDeviceExtractor::input_layers &layer_map, db::Netlist &nl, hier_clusters_type &clusters, double device_scaling) +void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layout_index, const NetlistDeviceExtractor::input_layers &layer_map, hier_clusters_type &clusters, double device_scaling) { - initialize (&nl); - std::vector layers; layers.reserve (m_layer_definitions.size ()); @@ -153,9 +155,9 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layo extract_without_initialize (dss.layout (layout_index), dss.initial_cell (layout_index), clusters, layers, device_scaling, dss.breakout_cells (layout_index)); } -void NetlistDeviceExtractor::extract (db::Layout &layout, db::Cell &cell, const std::vector &layers, db::Netlist *nl, hier_clusters_type &clusters, double device_scaling, const std::set *breakout_cells) +// @@@ needed? +void NetlistDeviceExtractor::extract (db::Layout &layout, db::Cell &cell, const std::vector &layers, hier_clusters_type &clusters, double device_scaling, const std::set *breakout_cells) { - initialize (nl); extract_without_initialize (layout, cell, clusters, layers, device_scaling, breakout_cells); } diff --git a/src/db/db/dbNetlistDeviceExtractor.h b/src/db/db/dbNetlistDeviceExtractor.h index 3da7e5489..f76413619 100644 --- a/src/db/db/dbNetlistDeviceExtractor.h +++ b/src/db/db/dbNetlistDeviceExtractor.h @@ -124,6 +124,13 @@ public: */ static const tl::Variant &device_class_property_name (); + /** + * @brief Initializes the extractor and connects to a netlist + * + * This method needs to be called before "extract" + */ + void initialize (Netlist *netlist); + /** * @brief Performs the extraction * @@ -140,7 +147,7 @@ public: * * The definition of the input layers is device class specific. */ - void extract (Layout &layout, Cell &cell, const std::vector &layers, Netlist *netlist, hier_clusters_type &clusters, double device_scaling = 1.0, const std::set *breakout_cells = 0); + void extract (Layout &layout, Cell &cell, const std::vector &layers, hier_clusters_type &clusters, double device_scaling = 1.0, const std::set *breakout_cells = 0); /** * @brief Extracts the devices from a list of regions @@ -149,7 +156,7 @@ public: * named regions for input. These regions need to be of deep region type and * originate from the same layout than the DeepShapeStore. */ - void extract (DeepShapeStore &dss, unsigned int layout_index, const input_layers &layers, Netlist &netlist, hier_clusters_type &clusters, double device_scaling = 1.0); + void extract (DeepShapeStore &dss, unsigned int layout_index, const input_layers &layers, hier_clusters_type &clusters, double device_scaling = 1.0); /** * @brief Clears the log entries @@ -283,6 +290,23 @@ public: return mp_device_class.get (); } + /** + * @brief Gets the default device class + * + * The default device class is a fallback device class which is used when + * 1.) No device class is registered in the constructor + * 2.) No corresponding device class is present in the netlist on extraction + * 3.) No corresponding device class is registered in the LayoutToNetlist object + * The object returned is a new object and must be deleted by the caller. + * + * This method is mainly used by internal device extractors to link them + * to a default class. + */ + virtual DeviceClass *default_device_class () + { + return 0; + } + /** * @brief Defines a device terminal in the layout (a region) */ @@ -425,13 +449,6 @@ public: */ std::string cell_name () const; - /** - * @brief Initializes the extractor - * This method will produce the device classes required for the device extraction. - * It is mainly provided for test purposes. Don't call it directly. - */ - void initialize (db::Netlist *nl); - private: struct DeviceCellKey { diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.cc b/src/db/db/dbNetlistDeviceExtractorClasses.cc index c439cc1dd..e1e049180 100644 --- a/src/db/db/dbNetlistDeviceExtractorClasses.cc +++ b/src/db/db/dbNetlistDeviceExtractorClasses.cc @@ -31,7 +31,7 @@ namespace db // NetlistDeviceExtractorMOS3Transistor implementation NetlistDeviceExtractorMOS3Transistor::NetlistDeviceExtractorMOS3Transistor (const std::string &name, bool strict, db::DeviceClassFactory *factory) - : db::NetlistDeviceExtractorImplBase (name, factory ? factory : new db::device_class_factory ()), + : db::NetlistDeviceExtractorImplBase (name, factory ? factory : new db::device_class_factory (strict)), m_strict (strict) { // .. nothing yet .. @@ -65,10 +65,6 @@ void NetlistDeviceExtractorMOS3Transistor::setup () define_layer ("tD", 1, "Drain terminal output (default is D)"); // #6 } - - db::DeviceClass *cls = make_class (); - cls->set_strict (m_strict); - register_device_class (cls); } db::Connectivity NetlistDeviceExtractorMOS3Transistor::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const @@ -323,7 +319,7 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector ()) + : NetlistDeviceExtractorMOS3Transistor (name, strict, factory ? factory : new db::device_class_factory (strict)) { // .. nothing yet .. } @@ -366,10 +362,6 @@ void NetlistDeviceExtractorMOS4Transistor::setup () define_layer ("tB", 7, "Well (bulk) terminal output"); // #8 -> W } - - db::DeviceClass *cls = make_class (); - 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) @@ -395,8 +387,6 @@ void NetlistDeviceExtractorResistor::setup () define_layer ("C", "Contacts"); // #1 define_layer ("tA", 1, "A terminal output"); // #2 -> C define_layer ("tB", 1, "B terminal output"); // #3 -> C - - register_device_class (make_class ()); } db::Connectivity NetlistDeviceExtractorResistor::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const @@ -508,8 +498,6 @@ void NetlistDeviceExtractorResistorWithBulk::setup () define_layer ("tB", 1, "B terminal output"); // #3 -> C define_layer ("W", "Well/Bulk"); // #4 define_layer ("tW", 4, "W terminal output"); // #5 -> W - - register_device_class (make_class ()); } void NetlistDeviceExtractorResistorWithBulk::modify_device (const db::Polygon &res, const std::vector & /*layer_geometry*/, db::Device *device) @@ -533,8 +521,6 @@ void NetlistDeviceExtractorCapacitor::setup () define_layer ("P2", "Plate 2"); // #1 define_layer ("tA", 0, "A terminal output"); // #2 -> P1 define_layer ("tB", 1, "B terminal output"); // #3 -> P2 - - register_device_class (make_class ()); } db::Connectivity NetlistDeviceExtractorCapacitor::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const @@ -610,8 +596,6 @@ void NetlistDeviceExtractorCapacitorWithBulk::setup () define_layer ("tB", 1, "B terminal output"); // #3 -> P2 define_layer ("W", "Well/Bulk"); // #4 define_layer ("tW", 4, "W terminal output"); // #5 -> W - - register_device_class (make_class ()); } void NetlistDeviceExtractorCapacitorWithBulk::modify_device (const db::Polygon &cap, const std::vector & /*layer_geometry*/, db::Device *device) @@ -639,8 +623,6 @@ void NetlistDeviceExtractorBJT3Transistor::setup () define_layer ("tC", 0, "Collector terminal output"); // #3 -> C define_layer ("tB", 1, "Base terminal output"); // #4 -> B define_layer ("tE", 2, "Emitter terminal output"); // #5 -> E - - register_device_class (make_class ()); } db::Connectivity NetlistDeviceExtractorBJT3Transistor::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const @@ -774,8 +756,6 @@ void NetlistDeviceExtractorBJT4Transistor::setup () define_layer ("S", "Substrate (bulk) terminal output"); // #6 define_layer ("tS", 6, "Substrate (bulk) terminal output"); // #7 -> S - - register_device_class (make_class ()); } void NetlistDeviceExtractorBJT4Transistor::modify_device (const db::Polygon &emitter, const std::vector & /*layer_geometry*/, db::Device *device) @@ -799,8 +779,6 @@ void NetlistDeviceExtractorDiode::setup () define_layer ("N", "N region"); // #1 define_layer ("tA", 0, "A terminal output"); // #2 -> P define_layer ("tC", 1, "C terminal output"); // #3 -> N - - register_device_class (make_class ()); } db::Connectivity NetlistDeviceExtractorDiode::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.h b/src/db/db/dbNetlistDeviceExtractorClasses.h index e43221e06..959d7a234 100644 --- a/src/db/db/dbNetlistDeviceExtractorClasses.h +++ b/src/db/db/dbNetlistDeviceExtractorClasses.h @@ -49,7 +49,20 @@ class DB_PUBLIC_TEMPLATE device_class_factory : public DeviceClassFactory { public: - virtual db::DeviceClass *create_class () const { return new C (); } + device_class_factory () : m_strict (-1) { } + device_class_factory (bool strict) : m_strict (strict ? 1 : 0) { } + + virtual db::DeviceClass *create_class () const + { + C *c = new C (); + if (m_strict >= 0) { + c->set_strict (m_strict != 0); + } + return c; + } + +private: + int m_strict; }; /** @@ -71,9 +84,9 @@ public: } /** - * @brief Creates the device class object + * @brief Creates the default device class object */ - db::DeviceClass *make_class () + db::DeviceClass *default_device_class () { return mp_factory->create_class (); } @@ -108,7 +121,7 @@ public: 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 + virtual bool is_strict () const { return m_strict; } diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index c3368a735..9bde313e0 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -657,6 +657,30 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "\n" "This method has been introduced in version 0.27.1.\n" ) + + gsi::method ("register_device_class", &db::LayoutToNetlist::register_device_class, gsi::arg ("device_class"), + "@brief Registers a device class for device extraction\n" + "\n" + "There are two ways of defining the device class for the devices a specific device extractor " + "delivers: locally inside the device extractor, and globally inside the \\LayoutToNetlist object. " + "The global approach allows to centrally manage device classes outside the device extractors. " + "This enables reusing the same device class for SPICE reading and generation and is the key " + "for using SPICE profiles in LVS decks for example.\n" + "\n" + "When you use this method, the given device class is registered and associated with a device " + "extractor in \\extract_devices by name. In that case, the device extractor should not register " + "a local device class inside a reimplementation of \\GenericDeviceExtractor#setup.\n" + "\n" + "A corresponding method to query device classes is \\device_class_by_name.\n" + "\n" + "This method has been introduced in version 0.31.0.\n" + ) + + gsi::method ("device_class_by_name", &db::LayoutToNetlist::device_class_by_name, gsi::arg ("name"), + "@brief Gets a device class by name\n" + "\n" + "See \\register_device_class for details about this feature.\n" + "\n" + "This method has been introduced in version 0.31.0.\n" + ) + gsi::method ("connect", (void (db::LayoutToNetlist::*) (const db::Region &)) &db::LayoutToNetlist::connect, gsi::arg ("l"), "@brief Defines an intra-layer connection for the given layer.\n" "The layer as a Region object, representing either an original layer created with \\make_layer and its variants or\n" diff --git a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc index 0f3b6682e..b5c64173b 100644 --- a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc +++ b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc @@ -321,101 +321,106 @@ Class decl_GenericDeviceExtractor (decl_dbNetlistDeviceE "to the new devices.\n" ) + gsi::method ("register_device_class", &GenericDeviceExtractor::register_device_class, gsi::arg ("device_class"), - "@brief Registers a device class.\n" - "The device class object will become owned by the netlist and must not be deleted by\n" - "the caller. The name of the device class will be changed to the name given to\n" - "the device extractor.\n" - "This method shall be used inside the implementation of \\setup to register\n" - "the device classes.\n" + "@brief Registers a device class.\n" + "The device class object will become owned by the netlist and must not be deleted by\n" + "the caller. The name of the device class will be changed to the name given to\n" + "the device extractor.\n" + "This method shall be used inside the implementation of \\setup to register\n" + "the device classes.\n" + "\n" + "Registering a device class in the Extractor is optional. Alternatively, the device class can also " + "be registered inside the \\Netter object. In that case the device class corresponding to the " + "extractor's name will be used during \\Netter#extract_devices.\n" ) + gsi::method ("define_layer", (const db::NetlistDeviceExtractorLayerDefinition &(GenericDeviceExtractor::*) (const std::string &name, const std::string &)) &GenericDeviceExtractor::define_layer, gsi::arg ("name"), gsi::arg ("description"), - "@brief Defines a layer.\n" - "@return The layer descriptor object created for this layer (use 'index' to get the layer's index)\n" - "Each call will define one more layer for the device extraction.\n" - "This method shall be used inside the implementation of \\setup to define\n" - "the device layers. The actual geometries are later available to \\extract_devices\n" - "in the order the layers are defined.\n" + "@brief Defines a layer.\n" + "@return The layer descriptor object created for this layer (use 'index' to get the layer's index)\n" + "Each call will define one more layer for the device extraction.\n" + "This method shall be used inside the implementation of \\setup to define\n" + "the device layers. The actual geometries are later available to \\extract_devices\n" + "in the order the layers are defined.\n" ) + gsi::method ("define_opt_layer", (const db::NetlistDeviceExtractorLayerDefinition &(GenericDeviceExtractor::*) (const std::string &name, size_t fallback, const std::string &)) &GenericDeviceExtractor::define_layer, gsi::arg ("name"), gsi::arg ("fallback"), gsi::arg ("description"), - "@brief Defines a layer with a fallback layer.\n" - "@return The layer descriptor object created for this layer (use 'index' to get the layer's index)\n" - "As \\define_layer, this method allows specification of device extraction layer. In addition to \\define_layout, it features " - "a fallback layer. If in the device extraction statement, the primary layer is not given, " - "the fallback layer will be used. Hence, this layer is optional. The fallback layer is given by its " - "index and must be defined before the layer using the fallback layer is defined. " - "For the index, 0 is the first layer defined, 1 the second and so forth." + "@brief Defines a layer with a fallback layer.\n" + "@return The layer descriptor object created for this layer (use 'index' to get the layer's index)\n" + "As \\define_layer, this method allows specification of device extraction layer. In addition to \\define_layer, it features " + "a fallback layer. If in the device extraction statement, the primary layer is not given, " + "the fallback layer will be used. Hence, this layer is optional. The fallback layer is given by its " + "index and must be defined before the layer using the fallback layer is defined. " + "For the index, 0 is the first layer defined, 1 the second and so forth." ) + gsi::method ("create_device", &GenericDeviceExtractor::create_device, - "@brief Creates a device.\n" - "The device object returned can be configured by the caller, e.g. set parameters.\n" - "It will be owned by the netlist and must not be deleted by the caller.\n" + "@brief Creates a device.\n" + "The device object returned can be configured by the caller, e.g. set parameters.\n" + "It will be owned by the netlist and must not be deleted by the caller.\n" + "The device created will have the device class specified by \\register_device_class.\n" ) + gsi::method ("define_terminal", (void (GenericDeviceExtractor::*) (db::Device *, size_t, size_t, const db::Polygon &)) &GenericDeviceExtractor::define_terminal, gsi::arg ("device"), gsi::arg ("terminal_id"), gsi::arg ("layer_index"), gsi::arg ("shape"), - "@brief Defines a device terminal.\n" - "This method will define a terminal to the given device and the given terminal ID. \n" - "The terminal will be placed on the layer given by \"layer_index\". The layer index \n" - "is the index of the layer during layer definition. The first layer is 0, the second layer 1 etc.\n" - "\n" - "This version produces a terminal with a shape given by the polygon. Note that the polygon is\n" - "specified in database units.\n" + "@brief Defines a device terminal.\n" + "This method will define a terminal to the given device and the given terminal ID. \n" + "The terminal will be placed on the layer given by \"layer_index\". The layer index \n" + "is the index of the layer during layer definition. The first layer is 0, the second layer 1 etc.\n" + "\n" + "This version produces a terminal with a shape given by the polygon. Note that the polygon is\n" + "specified in database units.\n" ) + gsi::method ("define_terminal", (void (GenericDeviceExtractor::*) (db::Device *, size_t, size_t, const db::Box &)) &GenericDeviceExtractor::define_terminal, gsi::arg ("device"), gsi::arg ("terminal_id"), gsi::arg ("layer_index"), gsi::arg ("shape"), - "@brief Defines a device terminal.\n" - "This method will define a terminal to the given device and the given terminal ID. \n" - "The terminal will be placed on the layer given by \"layer_index\". The layer index \n" - "is the index of the layer during layer definition. The first layer is 0, the second layer 1 etc.\n" - "\n" - "This version produces a terminal with a shape given by the box. Note that the box is\n" - "specified in database units.\n" + "@brief Defines a device terminal.\n" + "This method will define a terminal to the given device and the given terminal ID. \n" + "The terminal will be placed on the layer given by \"layer_index\". The layer index \n" + "is the index of the layer during layer definition. The first layer is 0, the second layer 1 etc.\n" + "\n" + "This version produces a terminal with a shape given by the box. Note that the box is\n" + "specified in database units.\n" ) + gsi::method ("define_terminal", (void (GenericDeviceExtractor::*) (db::Device *, size_t, size_t, const db::Point &)) &GenericDeviceExtractor::define_terminal, gsi::arg ("device"), gsi::arg ("terminal_id"), gsi::arg ("layer_index"), gsi::arg ("point"), - "@brief Defines a device terminal.\n" - "This method will define a terminal to the given device and the given terminal ID. \n" - "The terminal will be placed on the layer given by \"layer_index\". The layer index \n" - "is the index of the layer during layer definition. The first layer is 0, the second layer 1 etc.\n" - "\n" - "This version produces a point-like terminal. Note that the point is\n" - "specified in database units.\n" + "@brief Defines a device terminal.\n" + "This method will define a terminal to the given device and the given terminal ID. \n" + "The terminal will be placed on the layer given by \"layer_index\". The layer index \n" + "is the index of the layer during layer definition. The first layer is 0, the second layer 1 etc.\n" + "\n" + "This version produces a point-like terminal. Note that the point is\n" + "specified in database units.\n" ) + gsi::method_ext ("define_terminal", &define_terminal_by_names, gsi::arg ("device"), gsi::arg ("terminal_name"), gsi::arg ("layer_name"), gsi::arg ("shape"), - "@brief Defines a device terminal using names for terminal and layer.\n" - "\n" - "This convenience version of the ID-based \\define_terminal methods allows using names for terminal and layer.\n" - "It has been introduced in version 0.28." + "@brief Defines a device terminal using names for terminal and layer.\n" + "\n" + "This convenience version of the ID-based \\define_terminal methods allows using names for terminal and layer.\n" + "It has been introduced in version 0.28." ) + gsi::method_ext ("define_terminal", &define_terminal_by_names, gsi::arg ("device"), gsi::arg ("terminal_name"), gsi::arg ("layer_name"), gsi::arg ("shape"), - "@brief Defines a device terminal using names for terminal and layer.\n" - "\n" - "This convenience version of the ID-based \\define_terminal methods allows using names for terminal and layer.\n" - "It has been introduced in version 0.28." + "@brief Defines a device terminal using names for terminal and layer.\n" + "\n" + "This convenience version of the ID-based \\define_terminal methods allows using names for terminal and layer.\n" + "It has been introduced in version 0.28." ) + gsi::method_ext ("define_terminal", &define_terminal_by_names, gsi::arg ("device"), gsi::arg ("terminal_name"), gsi::arg ("layer_name"), gsi::arg ("point"), - "@brief Defines a device terminal using names for terminal and layer.\n" - "\n" - "This convenience version of the ID-based \\define_terminal methods allows using names for terminal and layer.\n" - "It has been introduced in version 0.28." + "@brief Defines a device terminal using names for terminal and layer.\n" + "\n" + "This convenience version of the ID-based \\define_terminal methods allows using names for terminal and layer.\n" + "It has been introduced in version 0.28." ) + gsi::method ("dbu", &GenericDeviceExtractor::dbu, - "@brief Gets the database unit\n" + "@brief Gets the database unit\n" ) + gsi::method ("sdbu", &GenericDeviceExtractor::sdbu, - "@brief Gets the scaled database unit\n" - "Use this unit to compute device properties. It is the database unit multiplied with the\n" - "device scaling factor." + "@brief Gets the scaled database unit\n" + "Use this unit to compute device properties. It is the database unit multiplied with the\n" + "device scaling factor." ) + gsi::method ("error", (void (GenericDeviceExtractor::*) (const std::string &)) &GenericDeviceExtractor::error, gsi::arg ("message"), - "@brief Issues an error with the given message\n" + "@brief Issues an error with the given message\n" ) + gsi::method ("error", (void (GenericDeviceExtractor::*) (const std::string &, const db::DPolygon &)) &GenericDeviceExtractor::error, gsi::arg ("message"), gsi::arg ("geometry"), - "@brief Issues an error with the given message and micrometer-units polygon geometry\n" + "@brief Issues an error with the given message and micrometer-units polygon geometry\n" ) + gsi::method_ext ("error", &error1, gsi::arg ("message"), gsi::arg ("geometry"), diff --git a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc index bd5cc8a3f..8074dc0a3 100644 --- a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc @@ -149,7 +149,8 @@ TEST(3_ClassFactoryTest) dl["tS"] = &o1; dl["tD"] = &o2; dl["tG"] = &o3; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); // the generated objects are of MyDeviceClassType EXPECT_EQ (dynamic_cast (ex.device_class ()) != 0, true); @@ -199,7 +200,8 @@ TEST(10_MOS3DeviceExtractorTest) dl["tS"] = &o1; dl["tD"] = &o2; dl["tG"] = &o3; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); EXPECT_EQ (nl.to_string (), "circuit TOP ();\n" @@ -254,7 +256,8 @@ TEST(11_MOS3DeviceExtractorTestNotRectangularGate) dl["tS"] = &o1; dl["tD"] = &o2; dl["tG"] = &o3; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); EXPECT_EQ (nl.to_string (), "circuit TOP ();\n" @@ -309,7 +312,8 @@ TEST(12_MOS3DeviceExtractorTestCircular) dl["tS"] = &o1; dl["tD"] = &o2; dl["tG"] = &o3; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); EXPECT_EQ (nl.to_string (), "circuit TOP ();\n" @@ -368,7 +372,8 @@ TEST(20_MOS4DeviceExtractorTest) dl["tD"] = &o2; dl["tG"] = &o3; dl["tB"] = &o4; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); EXPECT_EQ (nl.to_string (), "circuit TOP ();\n" @@ -428,7 +433,8 @@ TEST(21_MOS4DeviceExtractorTestNotRectangularGate) dl["tD"] = &o2; dl["tG"] = &o3; dl["tB"] = &o4; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); EXPECT_EQ (nl.to_string (), "circuit TOP ();\n" @@ -488,7 +494,8 @@ TEST(22_MOS4DeviceExtractorTestCircular) dl["tD"] = &o2; dl["tG"] = &o3; dl["tB"] = &o4; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); EXPECT_EQ (nl.to_string (), "circuit TOP ();\n" @@ -546,7 +553,8 @@ TEST(30_DMOS3DeviceExtractorTest) dl["tS"] = &o1; dl["tD"] = &o2; dl["tG"] = &o3; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); EXPECT_EQ (nl.to_string (), "circuit TOP ();\n" @@ -603,7 +611,8 @@ TEST(31_DMOS3DeviceExtractorTestNotRectangularGate) dl["tS"] = &o1; dl["tD"] = &o2; dl["tG"] = &o3; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); EXPECT_EQ (nl.to_string (), "circuit TOP ();\n" @@ -660,7 +669,8 @@ TEST(32_DMOS3DeviceExtractorTestCircular) dl["tS"] = &o1; dl["tD"] = &o2; dl["tG"] = &o3; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); EXPECT_EQ (nl.to_string (), "circuit TOP ();\n" @@ -721,7 +731,8 @@ TEST(40_DMOS4DeviceExtractorTest) dl["tD"] = &o2; dl["tG"] = &o3; dl["tB"] = &o4; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); EXPECT_EQ (nl.to_string (), "circuit TOP ();\n" @@ -783,7 +794,8 @@ TEST(41_DMOS4DeviceExtractorTestNotRectangularGate) dl["tD"] = &o2; dl["tG"] = &o3; dl["tB"] = &o4; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); EXPECT_EQ (nl.to_string (), "circuit TOP ();\n" @@ -845,7 +857,8 @@ TEST(42_DMOS4DeviceExtractorTestCircular) dl["tD"] = &o2; dl["tG"] = &o3; dl["tB"] = &o4; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); EXPECT_EQ (nl.to_string (), "circuit TOP ();\n" @@ -903,7 +916,8 @@ TEST(50_BJT3DeviceExtractorTest) dl["tE"] = &o1; dl["tB"] = &o2; dl["tC"] = &o3; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); EXPECT_EQ (nl.to_string (), "circuit TOP ();\n" @@ -960,7 +974,8 @@ TEST(51_BJT3DeviceExtractorTest) dl["tE"] = &o1; dl["tB"] = &o2; dl["tC"] = &o3; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); EXPECT_EQ (nl.to_string (), "circuit TOP ();\n" @@ -1017,7 +1032,8 @@ TEST(52_BJT3DeviceExtractorTestLateral) dl["tE"] = &o1; dl["tB"] = &o2; dl["tC"] = &o3; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); EXPECT_EQ (nl.to_string (), "circuit TOP ();\n" @@ -1074,7 +1090,8 @@ TEST(53_BJT3DeviceExtractorTestMultEmitter) dl["tE"] = &o1; dl["tB"] = &o2; dl["tC"] = &o3; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); EXPECT_EQ (nl.to_string (), "circuit TOP ();\n" @@ -1136,7 +1153,8 @@ TEST(54_BJT4DeviceExtractorTest) dl["tB"] = &o2; dl["tC"] = &o3; dl["tS"] = &o4; - ex.extract (dss, 0, dl, nl, cl); + ex.initialize (&nl); + ex.extract (dss, 0, dl, cl); EXPECT_EQ (nl.to_string (), "circuit TOP ();\n" diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index 421decbbb..fbb6751bf 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -259,12 +259,14 @@ TEST(1_DeviceAndNetExtraction) dl["SD"] = &rpsd; dl["G"] = &rpgate; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - pmos_ex.extract (dss, 0, dl, nl, cl); + pmos_ex.initialize (&nl); + pmos_ex.extract (dss, 0, dl, cl); dl["SD"] = &rnsd; dl["G"] = &rngate; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - nmos_ex.extract (dss, 0, dl, nl, cl); + nmos_ex.initialize (&nl); + nmos_ex.extract (dss, 0, dl, cl); // perform the net extraction @@ -495,12 +497,14 @@ TEST(1a_DeviceAndNetExtractionWithTextsAsLabels) dl["SD"] = &rpsd; dl["G"] = &rpgate; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - pmos_ex.extract (dss, 0, dl, nl, cl); + pmos_ex.initialize (&nl); + pmos_ex.extract (dss, 0, dl, cl); dl["SD"] = &rnsd; dl["G"] = &rngate; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - nmos_ex.extract (dss, 0, dl, nl, cl); + nmos_ex.initialize (&nl); + nmos_ex.extract (dss, 0, dl, cl); // perform the net extraction @@ -693,12 +697,14 @@ TEST(2_DeviceAndNetExtractionFlat) dl["SD"] = &rpsd; dl["G"] = &rpgate; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - pmos_ex.extract (dss, 0, dl, nl, cl); + pmos_ex.initialize (&nl); + pmos_ex.extract (dss, 0, dl, cl); dl["SD"] = &rnsd; dl["G"] = &rngate; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - nmos_ex.extract (dss, 0, dl, nl, cl); + nmos_ex.initialize (&nl); + nmos_ex.extract (dss, 0, dl, cl); // perform the net extraction @@ -925,12 +931,14 @@ TEST(3_DeviceAndNetExtractionWithImplicitConnections) dl["SD"] = &rpsd; dl["G"] = &rpgate; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - pmos_ex.extract (dss, 0, dl, nl, cl); + pmos_ex.initialize (&nl); + pmos_ex.extract (dss, 0, dl, cl); dl["SD"] = &rnsd; dl["G"] = &rngate; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - nmos_ex.extract (dss, 0, dl, nl, cl); + nmos_ex.initialize (&nl); + nmos_ex.extract (dss, 0, dl, cl); // perform the net extraction @@ -1196,7 +1204,8 @@ TEST(4_ResAndCapExtraction) dl["tG"] = &rpoly; dl["tS"] = &rpsd; dl["tD"] = &rpsd; - pmos_ex.extract (dss, 0, dl, nl, cl); + pmos_ex.initialize (&nl); + pmos_ex.extract (dss, 0, dl, cl); dl.clear (); dl["SD"] = &rnsd; @@ -1205,7 +1214,8 @@ TEST(4_ResAndCapExtraction) dl["tG"] = &rpoly; dl["tS"] = &rnsd; dl["tD"] = &rnsd; - nmos_ex.extract (dss, 0, dl, nl, cl); + nmos_ex.initialize (&nl); + nmos_ex.extract (dss, 0, dl, cl); dl.clear (); dl["R"] = &rpoly_res; @@ -1213,7 +1223,8 @@ TEST(4_ResAndCapExtraction) // terminal patches dl["tA"] = &rpoly; dl["tB"] = &rpoly; - res_ex.extract (dss, 0, dl, nl, cl); + res_ex.initialize (&nl); + res_ex.extract (dss, 0, dl, cl); dl.clear (); dl["P1"] = &rcap1; @@ -1221,7 +1232,8 @@ TEST(4_ResAndCapExtraction) // terminal patches dl["tA"] = &rmetal1; dl["tB"] = &rmetal2; - cap_ex.extract (dss, 0, dl, nl, cl); + cap_ex.initialize (&nl); + cap_ex.extract (dss, 0, dl, cl); // perform the net extraction @@ -1446,7 +1458,8 @@ TEST(5_ResAndCapWithBulkExtraction) dl["tG"] = &rpoly; dl["tS"] = &rpsd; dl["tD"] = &rpsd; - pmos_ex.extract (dss, 0, dl, nl, cl); + pmos_ex.initialize (&nl); + pmos_ex.extract (dss, 0, dl, cl); dl.clear (); dl["SD"] = &rnsd; @@ -1456,7 +1469,8 @@ TEST(5_ResAndCapWithBulkExtraction) dl["tG"] = &rpoly; dl["tS"] = &rnsd; dl["tD"] = &rnsd; - nmos_ex.extract (dss, 0, dl, nl, cl); + nmos_ex.initialize (&nl); + nmos_ex.extract (dss, 0, dl, cl); dl.clear (); dl["R"] = &rpoly_res_sub; @@ -1465,7 +1479,8 @@ TEST(5_ResAndCapWithBulkExtraction) // terminal patches dl["tA"] = &rpoly; dl["tB"] = &rpoly; - res_substrate_ex.extract (dss, 0, dl, nl, cl); + res_substrate_ex.initialize (&nl); + res_substrate_ex.extract (dss, 0, dl, cl); dl.clear (); dl["R"] = &rpoly_res_nw; @@ -1474,7 +1489,8 @@ TEST(5_ResAndCapWithBulkExtraction) // terminal patches dl["tA"] = &rpoly; dl["tB"] = &rpoly; - res_nwell_ex.extract (dss, 0, dl, nl, cl); + res_nwell_ex.initialize (&nl); + res_nwell_ex.extract (dss, 0, dl, cl); dl.clear (); dl["P1"] = &rcap1_sub; @@ -1483,7 +1499,8 @@ TEST(5_ResAndCapWithBulkExtraction) // terminal patches dl["tA"] = &rmetal1; dl["tB"] = &rmetal2; - cap_substrate_ex.extract (dss, 0, dl, nl, cl); + cap_substrate_ex.initialize (&nl); + cap_substrate_ex.extract (dss, 0, dl, cl); dl.clear (); dl["P1"] = &rcap1_nw; @@ -1492,7 +1509,8 @@ TEST(5_ResAndCapWithBulkExtraction) // terminal patches dl["tA"] = &rmetal1; dl["tB"] = &rmetal2; - cap_nwell_ex.extract (dss, 0, dl, nl, cl); + cap_nwell_ex.initialize (&nl); + cap_nwell_ex.extract (dss, 0, dl, cl); // perform the net extraction @@ -1710,7 +1728,8 @@ TEST(6_BJT3TransistorExtraction) dl["tG"] = &rpoly; dl["tS"] = &rpsd; dl["tD"] = &rpsd; - pmos_ex.extract (dss, 0, dl, nl, cl); + pmos_ex.initialize (&nl); + pmos_ex.extract (dss, 0, dl, cl); dl.clear (); dl["SD"] = &rnsd; @@ -1720,7 +1739,8 @@ TEST(6_BJT3TransistorExtraction) dl["tG"] = &rpoly; dl["tS"] = &rnsd; dl["tD"] = &rnsd; - nmos_ex.extract (dss, 0, dl, nl, cl); + nmos_ex.initialize (&nl); + nmos_ex.extract (dss, 0, dl, cl); dl.clear (); dl["E"] = &remitter; @@ -1728,8 +1748,8 @@ TEST(6_BJT3TransistorExtraction) dl["C"] = &rbulk; // terminal patches dl["tB"] = &rnwell; - bjt_ex.extract (dss, 0, dl, nl, cl); - + bjt_ex.initialize (&nl); + bjt_ex.extract (dss, 0, dl, cl); // perform the net extraction @@ -1911,7 +1931,8 @@ TEST(7_DiodeExtraction) dl["N"] = &rn; dl["P"] = &rpplus; dl["tC"] = &rnwell; - diode_ex.extract (dss, 0, dl, nl, cl); + diode_ex.initialize (&nl); + diode_ex.extract (dss, 0, dl, cl); // perform the net extraction @@ -2045,7 +2066,8 @@ TEST(8_DiodeExtractionScaled) dl["N"] = &rn; dl["P"] = &rpplus; dl["tC"] = &rnwell; - diode_ex.extract (dss, 0, dl, nl, cl, 2.0); + diode_ex.initialize (&nl); + diode_ex.extract (dss, 0, dl, cl, 2.0); // perform the net extraction @@ -2208,13 +2230,15 @@ TEST(9_StrictDeviceExtraction) 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); + pmos_ex.initialize (&nl); + pmos_ex.extract (dss, 0, dl, 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); + nmos_ex.initialize (&nl); + nmos_ex.extract (dss, 0, dl, cl); // perform the net extraction @@ -2443,12 +2467,14 @@ TEST(10_DeviceExtractionWithBreakoutCells) dl["SD"] = &rpsd; dl["G"] = &rpgate; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - pmos_ex.extract (dss, 0, dl, nl, cl); + pmos_ex.initialize (&nl); + pmos_ex.extract (dss, 0, dl, cl); dl["SD"] = &rnsd; dl["G"] = &rngate; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - nmos_ex.extract (dss, 0, dl, nl, cl); + nmos_ex.initialize (&nl); + nmos_ex.extract (dss, 0, dl, cl); dss.pop_state (); @@ -2602,12 +2628,14 @@ TEST(11_DeviceExtractionWithSameClass) db::NetlistDeviceExtractor::input_layers dl; dl["R"] = &rpoly_res; dl["C"] = &rpoly_cap; - polyres_ex.extract (dss, 0, dl, nl, cl); + polyres_ex.initialize (&nl); + polyres_ex.extract (dss, 0, dl, cl); dl.clear (); dl["R"] = &rdiff_res; dl["C"] = &rdiff_cap; - diffres_ex.extract (dss, 0, dl, nl, cl); + diffres_ex.initialize (&nl); + diffres_ex.extract (dss, 0, dl, cl); // perform the net extraction @@ -2725,12 +2753,14 @@ TEST(12_FloatingSubcircuitExtraction) dl["SD"] = &rpsd; dl["G"] = &rpgate; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - pmos_ex.extract (dss, 0, dl, nl, cl); + pmos_ex.initialize (&nl); + pmos_ex.extract (dss, 0, dl, cl); dl["SD"] = &rnsd; dl["G"] = &rngate; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - nmos_ex.extract (dss, 0, dl, nl, cl); + nmos_ex.initialize (&nl); + nmos_ex.extract (dss, 0, dl, cl); // perform the net extraction @@ -2878,12 +2908,14 @@ TEST(13_RemoveDummyPins) dl["SD"] = &rpsd; dl["G"] = &rpgate; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - pmos_ex.extract (dss, 0, dl, nl, cl); + pmos_ex.initialize (&nl); + pmos_ex.extract (dss, 0, dl, cl); dl["SD"] = &rnsd; dl["G"] = &rngate; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - nmos_ex.extract (dss, 0, dl, nl, cl); + nmos_ex.initialize (&nl); + nmos_ex.extract (dss, 0, dl, cl); // perform the net extraction @@ -3027,13 +3059,15 @@ TEST(14_JoinNets) dl["G"] = &rpgate; dl["W"] = &rnwell; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - pmos_ex.extract (dss, 0, dl, nl, cl); + pmos_ex.initialize (&nl); + pmos_ex.extract (dss, 0, dl, cl); dl["SD"] = &rnsd; dl["G"] = &rngate; dl["W"] = &bulk; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - nmos_ex.extract (dss, 0, dl, nl, cl); + nmos_ex.initialize (&nl); + nmos_ex.extract (dss, 0, dl, cl); // perform the net extraction @@ -3315,13 +3349,15 @@ TEST(15_SoftConnections) dl["G"] = &rpgate; dl["W"] = &rnwell; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - pmos_ex.extract (dss, 0, dl, nl, cl); + pmos_ex.initialize (&nl); + pmos_ex.extract (dss, 0, dl, cl); dl["SD"] = &rnsd; dl["G"] = &rngate; dl["W"] = &bulk; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - nmos_ex.extract (dss, 0, dl, nl, cl); + nmos_ex.initialize (&nl); + nmos_ex.extract (dss, 0, dl, cl); // perform the net extraction @@ -3578,7 +3614,8 @@ TEST(100_issue954) dl["G"] = &rpgate; dl["W"] = &bulk; dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes - pmos_ex.extract (dss, 0, dl, nl, cl); + pmos_ex.initialize (&nl); + pmos_ex.extract (dss, 0, dl, cl); // perform the net extraction diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index d8d207390..72b18dcd1 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -2550,6 +2550,18 @@ CODE # The netlist is a RBA::Netlist object. If no netlist is extracted # yet, this method will trigger the extraction process. # See \Netter#netlist for a description of this function. + + # %DRC% + # @name register_device_class + # Registers a device class for extraction and netlist output. + # Registering a device class is optional. However, using registered + # device classed simplify SPICE netlist writing, as device classes + # can be configured with SPICE profiles to customize SPICE output. + # In the LVS context, \register_device_class also controls the way + # schematic netlists are read from SPICE. + # See \Netter#register_device_class for a description of this function. + # Also see \Netter#extract_devices for how to use it with registered + # device classes. %w( antenna_check @@ -2567,6 +2579,7 @@ CODE top_level ignore_extraction_errors extract_devices + register_device_class netlist l2n_data _l2n_object diff --git a/src/drc/drc/built-in-macros/_drc_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb index 75506aae2..591090e4e 100644 --- a/src/drc/drc/built-in-macros/_drc_netter.rb +++ b/src/drc/drc/built-in-macros/_drc_netter.rb @@ -217,7 +217,6 @@ module DRC # @name extract_devices # @brief Extracts devices based on the given extractor class, name and device layer selection # @synopsis extract_devices(extractor, layer_hash) - # @synopsis extract_devices(extractor_class, name, layer_hash) # Runs the device extraction for given device extractor class. In the first # form, the extractor object is given. In the second form, the extractor's # class object and the new extractor's name is given. @@ -1039,6 +1038,23 @@ module DRC end + def _register_device_class(cls) + if @devcls_by_name && @devcls_by_name[cls] + raise("A device class with name '#{cls.name}' is already registered") + end + @devcls ||= [] + @devcls_by_name ||= {} + @devcls << cls + @devcls_by_name[cls.name] = cls + end + + def _devcls_by_name(name) + if ! @devcls_by_name || ! @devcls_by_name[name] + raise("No device class registered with name #{name}") + end + @devcls_by_name[name] + end + private def cleanup diff --git a/src/lvs/lvs/built-in-macros/_lvs_engine.rb b/src/lvs/lvs/built-in-macros/_lvs_engine.rb index 11959cf40..5c91397ff 100644 --- a/src/lvs/lvs/built-in-macros/_lvs_engine.rb +++ b/src/lvs/lvs/built-in-macros/_lvs_engine.rb @@ -231,10 +231,20 @@ module LVS # @synopsis flag_missing_ports # See \Netter#flag_missing_ports for a description of that function. + # %LVS% + # @name register_device_class + # Registers a device class for extraction and netlist input and output. + # Registering a device class is optional. However, using registered + # device classed simplify SPICE netlist reading and writing, as device classes + # can be configured with SPICE profiles to customize SPICE input and output. + # See \Netter#register_device_class for a description of this function. + # Also see \Netter#extract_devices for how to use it with registered + # device classes. + %w(schematic compare split_gates join_symmetric_nets tolerance ignore_parameter enable_parameter disable_parameter blank_circuit align same_nets same_nets! same_circuits same_device_classes equivalent_pins min_caps max_res max_depth max_branch_complexity consider_net_names lvs_data no_lvs_hints - flag_missing_ports).each do |f| + flag_missing_ports register_device_class).each do |f| eval <<"CODE" def #{f}(*args) _netter.#{f}(*args) diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc index ae092428e..4255a0084 100644 --- a/src/lvs/unit_tests/lvsSimpleTests.cc +++ b/src/lvs/unit_tests/lvsSimpleTests.cc @@ -171,6 +171,13 @@ TEST(13_simple_ringo_device_subcircuits) run_test (_this, "ringo_device_subcircuits", "ringo.gds", false, true, std::string (), true); } +TEST(13b_simple_ringo_device_subcircuits_devcls) +{ + run_test (_this, "ringo_device_subcircuits_devcls", "ringo.gds"); + // change case + run_test (_this, "ringo_device_subcircuits_devcls", "ringo.gds", false, true, std::string (), true); +} + TEST(14_simple_ringo_mixed_hierarchy) { run_test (_this, "ringo_mixed_hierarchy", "ringo_mixed_hierarchy.gds");