More control over primary/secondary flag of parameters in device extraction

- Spice reader will set primary flag for all (known) parameters
  read from a Spice netlist
- "extract_devices" will return the device class object
- primary/secondary flag can be set on device class objects
  through "enable_devices"
This commit is contained in:
Matthias Koefferlein 2021-07-04 17:05:17 +02:00
parent 1a0b05e663
commit ce61145f1c
8 changed files with 105 additions and 6 deletions

View File

@ -179,6 +179,15 @@ const DeviceParameterDefinition *DeviceClass::parameter_definition (size_t id) c
}
}
DeviceParameterDefinition *DeviceClass::parameter_definition_non_const (size_t id)
{
if (id < m_parameter_definitions.size ()) {
return & m_parameter_definitions [id];
} else {
return 0;
}
}
bool DeviceClass::has_parameter_with_name (const std::string &name) const
{
const std::vector<db::DeviceParameterDefinition> &pd = parameter_definitions ();

View File

@ -508,6 +508,11 @@ public:
*/
const DeviceParameterDefinition *parameter_definition (size_t id) const;
/**
* @brief Gets the parameter definition from the ID (non-const version)
*/
DeviceParameterDefinition *parameter_definition_non_const (size_t id);
/**
* @brief Returns true, if the device has a parameter with the given name
*/

View File

@ -391,7 +391,7 @@ void NetlistDeviceExtractor::push_new_devices (const db::Vector &disp_cache)
std::string cell_name = "D$" + mp_device_class->name ();
db::Cell &device_cell = mp_layout->cell (mp_layout->add_cell (cell_name.c_str ()));
db::DeviceAbstract *dm = new db::DeviceAbstract (mp_device_class, mp_layout->cell_name (device_cell.cell_index ()));
db::DeviceAbstract *dm = new db::DeviceAbstract (mp_device_class.get (), mp_layout->cell_name (device_cell.cell_index ()));
m_netlist->add_device_abstract (dm);
dm->set_cell_index (device_cell.cell_index ());
@ -487,7 +487,7 @@ void NetlistDeviceExtractor::register_device_class (DeviceClass *device_class)
tl_assert (device_class != 0);
tl_assert (m_netlist.get () != 0);
if (mp_device_class != 0) {
if (mp_device_class.get () != 0) {
throw tl::Exception (tl::to_string (tr ("Device class already set")));
}
if (m_name.empty ()) {
@ -526,12 +526,12 @@ const db::NetlistDeviceExtractorLayerDefinition &NetlistDeviceExtractor::define_
Device *NetlistDeviceExtractor::create_device ()
{
if (mp_device_class == 0) {
if (mp_device_class.get () == 0) {
throw tl::Exception (tl::to_string (tr ("No device class registered")));
}
tl_assert (mp_circuit != 0);
Device *device = new Device (mp_device_class);
Device *device = new Device (mp_device_class.get ());
mp_circuit->add_device (device);
return device;
}

View File

@ -387,6 +387,16 @@ public:
*/
Device *create_device ();
/**
* @brief Gets the device class used during extraction
*
* This member is set in 'extract_devices' and holds the device class object used during extraction.
*/
DeviceClass *device_class ()
{
return mp_device_class.get ();
}
/**
* @brief Defines a device terminal in the layout (a region)
*/
@ -535,7 +545,7 @@ private:
const std::set<db::cell_index_type> *mp_breakout_cells;
double m_device_scaling;
db::Circuit *mp_circuit;
db::DeviceClass *mp_device_class;
tl::weak_ptr<db::DeviceClass> mp_device_class;
std::string m_name;
layer_definitions m_layer_definitions;
std::vector<unsigned int> m_layers;

View File

@ -625,6 +625,8 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
std::map<std::string, double>::const_iterator v = params.find (i->name ());
if (v != params.end ()) {
device->set_parameter_value (i->id (), v->second / i->si_scaling ());
// parameters read from the netlist are made primary so they are shown in the netlist browser
cls->parameter_definition_non_const (i->id ())->set_is_primary (true);
} else if (i->id () == defp) {
device->set_parameter_value (i->id (), value / i->si_scaling ());
}

View File

@ -927,6 +927,36 @@ static db::EqualDeviceParameters *get_equal_parameters (db::DeviceClass *cls)
return dynamic_cast<db::EqualDeviceParameters *> (cls->parameter_compare_delegate ());
}
static void enable_parameter (db::DeviceClass *cls, size_t id, bool en)
{
db::DeviceParameterDefinition *pd = cls->parameter_definition_non_const (id);
if (pd) {
pd->set_is_primary (en);
}
}
static void enable_parameter2 (db::DeviceClass *cls, const std::string &name, bool en)
{
if (! cls->has_parameter_with_name (name)) {
return;
}
size_t id = cls->parameter_id_for_name (name);
db::DeviceParameterDefinition *pd = cls->parameter_definition_non_const (id);
if (pd) {
pd->set_is_primary (en);
}
}
static const db::DeviceParameterDefinition *parameter_definition2 (const db::DeviceClass *cls, const std::string &name)
{
if (! cls->has_parameter_with_name (name)) {
return 0;
} else {
return cls->parameter_definition (cls->parameter_id_for_name (name));
}
}
Class<db::DeviceClass> decl_dbDeviceClass ("db", "DeviceClass",
gsi::method ("name", &db::DeviceClass::name,
"@brief Gets the name of the device class."
@ -981,6 +1011,33 @@ Class<db::DeviceClass> decl_dbDeviceClass ("db", "DeviceClass",
"Parameter definition IDs are used in some places to reference a specific parameter of a device. "
"This method obtains the corresponding definition object."
) +
gsi::method_ext ("parameter_definition", &parameter_definition2, gsi::arg ("parameter_name"),
"@brief Gets the parameter definition object for a given ID.\n"
"Parameter definition IDs are used in some places to reference a specific parameter of a device. "
"This method obtains the corresponding definition object."
"\n"
"This version accepts a parameter name.\n"
"\n"
"This method has been introduced in version 0.27.3.\n"
) +
gsi::method_ext ("enable_parameter", &enable_parameter, gsi::arg ("parameter_id"), gsi::arg ("enable"),
"@brief Enables or disables a parameter.\n"
"Some parameters are 'secondary' parameters which are extracted but not handled in device compare and are not shown in the netlist browser. "
"For example, the 'W' parameter of the resistor is such a secondary parameter. This method allows turning a parameter in a primary one ('enable') or "
"into a secondary one ('disable').\n"
"\n"
"This method has been introduced in version 0.27.3.\n"
) +
gsi::method_ext ("enable_parameter", &enable_parameter2, gsi::arg ("parameter_name"), gsi::arg ("enable"),
"@brief Enables or disables a parameter.\n"
"Some parameters are 'secondary' parameters which are extracted but not handled in device compare and are not shown in the netlist browser. "
"For example, the 'W' parameter of the resistor is such a secondary parameter. This method allows turning a parameter in a primary one ('enable') or "
"into a secondary one ('disable').\n"
"\n"
"This version accepts a parameter name.\n"
"\n"
"This method has been introduced in version 0.27.3.\n"
) +
gsi::method ("has_parameter?", &db::DeviceClass::has_parameter_with_name, gsi::arg ("name"),
"@brief Returns true, if the device class has a parameter with the given name.\n"
) +

View File

@ -214,6 +214,13 @@ Class<db::NetlistDeviceExtractor> decl_dbNetlistDeviceExtractor ("db", "DeviceEx
gsi::method ("name", &db::NetlistDeviceExtractor::name,
"@brief Gets the name of the device extractor and the device class."
) +
gsi::method ("device_class", &db::NetlistDeviceExtractor::device_class,
"@brief Gets the device class used during extraction\n"
"The attribute will hold the actual device class used in the device extraction. It "
"is valid only after 'extract_devices'.\n"
"\n"
"This method has been added in version 0.27.3.\n"
) +
gsi::iterator ("each_layer_definition", &db::NetlistDeviceExtractor::begin_layer_definitions, &db::NetlistDeviceExtractor::end_layer_definitions,
"@brief Iterates over all layer definitions."
) +
@ -251,9 +258,13 @@ Class<GenericDeviceExtractor> decl_GenericDeviceExtractor (decl_dbNetlistDeviceE
"This method shall raise an error, if the input layer are not properly defined (e.g.\n"
"too few etc.)\n"
"\n"
"This is not a connectivity definition in the electrical sense, but defines the cluster of shapes "
"which generates a specific device. In this case, 'connectivity' means 'definition of shapes that need to touch to form the device'.\n"
"\n"
"The 'layers' argument specifies the actual layer layouts for the logical device layers (see \\define_layer). "
"The list of layers corresponds to the number of layers defined. Use the layer indexes from this list "
"to build the connectivity with \\Connectivity#connect."
"to build the connectivity with \\Connectivity#connect. Note, that in order to capture a connected cluster of shapes on the "
"same layer you'll need to include a self-connection like 'connectivity.connect(layers[0], layers[0])'."
) +
gsi::callback ("extract_devices", &GenericDeviceExtractor::extract_devices, &GenericDeviceExtractor::cb_extract_devices,
gsi::arg ("layer_geometry"),

View File

@ -192,6 +192,9 @@ module DRC
#
# extract_devices(mos4("NMOS4"), { :SD => nsd, :G => gate, :P => poly, :W => bulk })
# @/code
#
# The return value of this method will be the device class of the devices
# generated in the extraction step (see \DeviceClass).
def extract_devices(devex, layer_selection)
@ -215,6 +218,8 @@ module DRC
end
devex.device_class
end
# %DRC%