This commit is contained in:
Matthias Koefferlein 2026-06-25 22:56:33 +02:00
parent 4561eebdc0
commit 50e0923ff6
14 changed files with 365 additions and 163 deletions

View File

@ -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<std::string, db::ShapeCollection *> &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 ());

View File

@ -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<db::NetShape> m_net_clusters;
std::unique_ptr<db::Netlist> mp_netlist;
tl::shared_collection<db::DeviceClass> m_device_classes;
std::set<db::DeepLayer> m_dlrefs;
std::map<std::string, db::DeepLayer> m_named_dls;
std::map<unsigned int, std::string> m_name_of_layer;

View File

@ -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 &region)
@ -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<unsigned int> 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<unsigned int> &layers, db::Netlist *nl, hier_clusters_type &clusters, double device_scaling, const std::set<db::cell_index_type> *breakout_cells)
// @@@ needed?
void NetlistDeviceExtractor::extract (db::Layout &layout, db::Cell &cell, const std::vector<unsigned int> &layers, hier_clusters_type &clusters, double device_scaling, const std::set<db::cell_index_type> *breakout_cells)
{
initialize (nl);
extract_without_initialize (layout, cell, clusters, layers, device_scaling, breakout_cells);
}

View File

@ -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<unsigned int> &layers, Netlist *netlist, hier_clusters_type &clusters, double device_scaling = 1.0, const std::set<cell_index_type> *breakout_cells = 0);
void extract (Layout &layout, Cell &cell, const std::vector<unsigned int> &layers, hier_clusters_type &clusters, double device_scaling = 1.0, const std::set<cell_index_type> *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
{

View File

@ -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<DeviceClassMOS3Transistor> ()),
: db::NetlistDeviceExtractorImplBase (name, factory ? factory : new db::device_class_factory<DeviceClassMOS3Transistor> (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<unsigned int> &layers) const
@ -323,7 +319,7 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector<db
// NetlistDeviceExtractorMOS4Transistor implementation
NetlistDeviceExtractorMOS4Transistor::NetlistDeviceExtractorMOS4Transistor (const std::string &name, bool strict, db::DeviceClassFactory *factory)
: NetlistDeviceExtractorMOS3Transistor (name, strict, factory ? factory : new db::device_class_factory<db::DeviceClassMOS4Transistor> ())
: NetlistDeviceExtractorMOS3Transistor (name, strict, factory ? factory : new db::device_class_factory<db::DeviceClassMOS4Transistor> (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<db::Region> & /*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<unsigned int> &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<db::Region> & /*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<unsigned int> &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<db::Region> & /*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<unsigned int> &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<db::Region> & /*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<unsigned int> &layers) const

View File

@ -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<unsigned int> &layers) const;
virtual void extract_devices (const std::vector<db::Region> &layer_geometry);
bool is_strict () const
virtual bool is_strict () const
{
return m_strict;
}

View File

@ -657,6 +657,30 @@ Class<db::LayoutToNetlist> 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"

View File

@ -321,101 +321,106 @@ Class<GenericDeviceExtractor> 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<db::Polygon>,
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<db::Box>,
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<db::Point>,
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"),

View File

@ -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<const MyDeviceClass *> (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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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");