WIP: a bit of simplification, renaming of methods, parents for subcircuits, devices. References for circuits pointing to subcircuits.

This commit is contained in:
Matthias Koefferlein 2018-12-28 22:51:11 +01:00
parent a5b9cbfe5b
commit 2f48479838
10 changed files with 482 additions and 263 deletions

View File

@ -46,7 +46,7 @@ Pin::Pin (const std::string &name)
// Device class implementation // Device class implementation
Device::Device () Device::Device ()
: mp_device_class (0), m_id (0) : mp_device_class (0), m_id (0), mp_circuit (0)
{ {
// .. nothing yet .. // .. nothing yet ..
} }
@ -61,13 +61,13 @@ Device::~Device ()
} }
Device::Device (DeviceClass *device_class, const std::string &name) Device::Device (DeviceClass *device_class, const std::string &name)
: mp_device_class (device_class), m_name (name), m_id (0) : mp_device_class (device_class), m_name (name), m_id (0), mp_circuit (0)
{ {
// .. nothing yet .. // .. nothing yet ..
} }
Device::Device (const Device &other) Device::Device (const Device &other)
: mp_device_class (0), m_id (0) : mp_device_class (0), m_id (0), mp_circuit (0)
{ {
operator= (other); operator= (other);
} }
@ -81,6 +81,11 @@ Device &Device::operator= (const Device &other)
return *this; return *this;
} }
void Device::set_circuit (Circuit *circuit)
{
mp_circuit = circuit;
}
void Device::set_name (const std::string &n) void Device::set_name (const std::string &n)
{ {
m_name = n; m_name = n;
@ -176,7 +181,7 @@ void Device::set_parameter_value (const std::string &name, double v)
// SubCircuit class implementation // SubCircuit class implementation
SubCircuit::SubCircuit () SubCircuit::SubCircuit ()
: m_id (0) : m_id (0), mp_circuit (0)
{ {
// .. nothing yet .. // .. nothing yet ..
} }
@ -191,13 +196,13 @@ SubCircuit::~SubCircuit()
} }
SubCircuit::SubCircuit (Circuit *circuit, const std::string &name) SubCircuit::SubCircuit (Circuit *circuit, const std::string &name)
: m_circuit (circuit), m_name (name), m_id (0) : m_circuit_ref (0), m_name (name), m_id (0), mp_circuit (0)
{ {
// .. nothing yet .. set_circuit_ref (circuit);
} }
SubCircuit::SubCircuit (const SubCircuit &other) SubCircuit::SubCircuit (const SubCircuit &other)
: m_id (0) : m_id (0), mp_circuit (0)
{ {
operator= (other); operator= (other);
} }
@ -206,8 +211,8 @@ SubCircuit &SubCircuit::operator= (const SubCircuit &other)
{ {
if (this != &other) { if (this != &other) {
m_name = other.m_name; m_name = other.m_name;
m_circuit = other.m_circuit;
m_trans = other.m_trans; m_trans = other.m_trans;
set_circuit_ref (const_cast<Circuit *> (other.circuit_ref ()));
} }
return *this; return *this;
} }
@ -230,6 +235,17 @@ void SubCircuit::set_pin_ref_for_pin (size_t pin_id, Net::pin_iterator iter)
m_pin_refs [pin_id] = iter; m_pin_refs [pin_id] = iter;
} }
void SubCircuit::set_circuit_ref (Circuit *c)
{
if (m_circuit_ref.get ()) {
m_circuit_ref->unregister_ref (this);
}
m_circuit_ref.reset (c);
if (m_circuit_ref.get ()) {
m_circuit_ref->register_ref (this);
}
}
const Net *SubCircuit::net_for_pin (size_t pin_id) const const Net *SubCircuit::net_for_pin (size_t pin_id) const
{ {
if (pin_id < m_pin_refs.size ()) { if (pin_id < m_pin_refs.size ()) {
@ -349,8 +365,8 @@ const Pin *NetPinRef::pin () const
if (mp_net && mp_net->circuit ()) { if (mp_net && mp_net->circuit ()) {
return mp_net->circuit ()->pin_by_id (m_pin_id); return mp_net->circuit ()->pin_by_id (m_pin_id);
} }
} else if (mp_subcircuit->circuit ()) { } else if (mp_subcircuit->circuit_ref ()) {
return mp_subcircuit->circuit ()->pin_by_id (m_pin_id); return mp_subcircuit->circuit_ref ()->pin_by_id (m_pin_id);
} }
return 0; return 0;
} }
@ -613,6 +629,8 @@ void Circuit::remove_net (Net *net)
void Circuit::add_device (Device *device) void Circuit::add_device (Device *device)
{ {
device->set_circuit (this);
size_t id = 0; size_t id = 0;
if (! m_devices.empty ()) { if (! m_devices.empty ()) {
tl_assert (m_devices.back () != 0); tl_assert (m_devices.back () != 0);
@ -658,6 +676,8 @@ Device *Circuit::device_by_id (size_t id)
void Circuit::add_subcircuit (SubCircuit *subcircuit) void Circuit::add_subcircuit (SubCircuit *subcircuit)
{ {
subcircuit->set_circuit (this);
size_t id = 0; size_t id = 0;
if (! m_subcircuits.empty ()) { if (! m_subcircuits.empty ()) {
tl_assert (m_subcircuits.back () != 0); tl_assert (m_subcircuits.back () != 0);
@ -701,12 +721,22 @@ SubCircuit *Circuit::subcircuit_by_id (size_t id)
return d != m_subcircuit_id_table.end () ? d->second : 0; return d != m_subcircuit_id_table.end () ? d->second : 0;
} }
void Circuit::register_ref (SubCircuit *r)
{
m_refs.push_back (r);
}
void Circuit::unregister_ref (SubCircuit *r)
{
m_refs.erase (r);
}
void Circuit::translate_circuits (const std::map<const Circuit *, Circuit *> &map) void Circuit::translate_circuits (const std::map<const Circuit *, Circuit *> &map)
{ {
for (subcircuit_iterator i = m_subcircuits.begin (); i != m_subcircuits.end (); ++i) { for (subcircuit_iterator i = m_subcircuits.begin (); i != m_subcircuits.end (); ++i) {
std::map<const Circuit *, Circuit *>::const_iterator m = map.find (i->circuit ()); std::map<const Circuit *, Circuit *>::const_iterator m = map.find (i->circuit_ref ());
tl_assert (m != map.end ()); tl_assert (m != map.end ());
i->set_circuit (m->second); i->set_circuit_ref (m->second);
} }
} }

View File

@ -608,6 +608,24 @@ public:
return m_id; return m_id;
} }
/**
* @brief Gets the circuit the device lives in (const version)
* This pointer is 0 if the device isn't added to a circuit
*/
const Circuit *circuit () const
{
return mp_circuit;
}
/**
* @brief Gets the circuit the device lives in (non-const version)
* This pointer is 0 if the device isn't added to a circuit
*/
Circuit *circuit ()
{
return mp_circuit;
}
/** /**
* @brief Sets the name * @brief Sets the name
*/ */
@ -675,6 +693,7 @@ private:
std::vector<Net::terminal_iterator> m_terminal_refs; std::vector<Net::terminal_iterator> m_terminal_refs;
std::vector<double> m_parameters; std::vector<double> m_parameters;
size_t m_id; size_t m_id;
Circuit *mp_circuit;
/** /**
* @brief Sets the terminal reference for a specific terminal * @brief Sets the terminal reference for a specific terminal
@ -696,6 +715,11 @@ private:
{ {
m_id = id; m_id = id;
} }
/**
* @brief Sets the circuit
*/
void set_circuit (Circuit *circuit);
}; };
/** /**
@ -727,7 +751,7 @@ public:
/** /**
* @brief Creates a subcircuit reference to the given circuit * @brief Creates a subcircuit reference to the given circuit
*/ */
SubCircuit (Circuit *circuit, const std::string &name = std::string ()); SubCircuit (Circuit *circuit_ref, const std::string &name = std::string ());
/** /**
* @brief Destructor * @brief Destructor
@ -746,19 +770,37 @@ public:
} }
/** /**
* @brief Gets the circuit the reference points to (const version) * @brief Gets the circuit the subcircuit lives in (const version)
* This pointer is 0 if the subcircuit isn't added to a circuit
*/ */
const Circuit *circuit () const const Circuit *circuit () const
{ {
return m_circuit.get (); return mp_circuit;
}
/**
* @brief Gets the circuit the subcircuit lives in (non-const version)
* This pointer is 0 if the subcircuit isn't added to a circuit
*/
Circuit *circuit ()
{
return mp_circuit;
}
/**
* @brief Gets the circuit the reference points to (const version)
*/
const Circuit *circuit_ref () const
{
return m_circuit_ref.get ();
} }
/** /**
* @brief Gets the circuit the reference points to (non-const version) * @brief Gets the circuit the reference points to (non-const version)
*/ */
Circuit *circuit () Circuit *circuit_ref ()
{ {
return m_circuit.get (); return m_circuit_ref.get ();
} }
/** /**
@ -820,11 +862,12 @@ private:
friend class Circuit; friend class Circuit;
friend class Net; friend class Net;
tl::weak_ptr<Circuit> m_circuit; tl::weak_ptr<Circuit> m_circuit_ref;
std::string m_name; std::string m_name;
db::DCplxTrans m_trans; db::DCplxTrans m_trans;
std::vector<Net::pin_iterator> m_pin_refs; std::vector<Net::pin_iterator> m_pin_refs;
size_t m_id; size_t m_id;
Circuit *mp_circuit;
/** /**
* @brief Sets the pin reference for a specific pin * @brief Sets the pin reference for a specific pin
@ -834,9 +877,14 @@ private:
/** /**
* @brief Sets the circuit reference * @brief Sets the circuit reference
*/ */
void set_circuit_ref (Circuit *c);
/**
* @brief Sets the circuit the subcircuit belongs to
*/
void set_circuit (Circuit *c) void set_circuit (Circuit *c)
{ {
m_circuit.reset (c); mp_circuit = c;
} }
/** /**
@ -870,6 +918,8 @@ public:
typedef tl::shared_collection<SubCircuit> subcircuit_list; typedef tl::shared_collection<SubCircuit> subcircuit_list;
typedef subcircuit_list::const_iterator const_subcircuit_iterator; typedef subcircuit_list::const_iterator const_subcircuit_iterator;
typedef subcircuit_list::iterator subcircuit_iterator; typedef subcircuit_list::iterator subcircuit_iterator;
typedef tl::weak_collection<SubCircuit>::const_iterator const_refs_iterator;
typedef tl::weak_collection<SubCircuit>::iterator refs_iterator;
/** /**
* @brief Constructor * @brief Constructor
@ -939,9 +989,44 @@ public:
return m_cell_index; return m_cell_index;
} }
/**
* @brief Gets the references to this circuit (begin, non-const version)
* This iterator will deliver all subcircuits referencing this circuit
*/
refs_iterator begin_refs ()
{
return m_refs.begin ();
}
/**
* @brief Gets the references to this circuit (end, non-const version)
* This iterator will deliver all subcircuits referencing this circuit
*/
refs_iterator end_refs ()
{
return m_refs.end ();
}
/**
* @brief Gets the references to this circuit (begin, const version)
* This iterator will deliver all subcircuits referencing this circuit
*/
const_refs_iterator begin_refs () const
{
return m_refs.begin ();
}
/**
* @brief Gets the references to this circuit (end, const version)
* This iterator will deliver all subcircuits referencing this circuit
*/
const_refs_iterator end_refs () const
{
return m_refs.end ();
}
/** /**
* @brief Adds a pin to this circuit * @brief Adds a pin to this circuit
*
* The circuit takes over ownership of the object. * The circuit takes over ownership of the object.
*/ */
const Pin &add_pin(const Pin &pin); const Pin &add_pin(const Pin &pin);
@ -1200,6 +1285,7 @@ public:
private: private:
friend class Netlist; friend class Netlist;
friend class Net; friend class Net;
friend class SubCircuit;
std::string m_name; std::string m_name;
db::cell_index_type m_cell_index; db::cell_index_type m_cell_index;
@ -1213,12 +1299,16 @@ private:
std::map<size_t, Device *> m_device_id_table; std::map<size_t, Device *> m_device_id_table;
bool m_valid_subcircuit_id_table; bool m_valid_subcircuit_id_table;
std::map<size_t, SubCircuit *> m_subcircuit_id_table; std::map<size_t, SubCircuit *> m_subcircuit_id_table;
tl::weak_collection<SubCircuit> m_refs;
/** /**
* @brief Sets the pin reference for a specific pin * @brief Sets the pin reference for a specific pin
*/ */
void set_pin_ref_for_pin (size_t ppin_id, Net::pin_iterator iter); void set_pin_ref_for_pin (size_t ppin_id, Net::pin_iterator iter);
void register_ref (SubCircuit *sc);
void unregister_ref (SubCircuit *sc);
void translate_circuits (const std::map<const Circuit *, Circuit *> &map); void translate_circuits (const std::map<const Circuit *, Circuit *> &map);
void translate_device_classes (const std::map<const DeviceClass *, DeviceClass *> &map); void translate_device_classes (const std::map<const DeviceClass *, DeviceClass *> &map);
void set_netlist (Netlist *netlist); void set_netlist (Netlist *netlist);

View File

@ -46,10 +46,10 @@ NetlistDeviceExtractorError::NetlistDeviceExtractorError (const std::string &cel
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
// NetlistDeviceExtractor implementation // NetlistDeviceExtractor implementation
NetlistDeviceExtractor::NetlistDeviceExtractor () NetlistDeviceExtractor::NetlistDeviceExtractor (const std::string &name)
: mp_layout (0), m_cell_index (0), mp_circuit (0) : mp_layout (0), m_cell_index (0), mp_circuit (0)
{ {
m_device_name_index = 0; m_name = name;
m_propname_id = 0; m_propname_id = 0;
} }
@ -67,8 +67,7 @@ const tl::Variant &NetlistDeviceExtractor::terminal_property_name ()
void NetlistDeviceExtractor::initialize (db::Netlist *nl) void NetlistDeviceExtractor::initialize (db::Netlist *nl)
{ {
m_layer_definitions.clear (); m_layer_definitions.clear ();
m_device_classes.clear (); mp_device_class = 0;
m_device_name_index = 0;
m_propname_id = 0; m_propname_id = 0;
m_netlist.reset (nl); m_netlist.reset (nl);
@ -108,16 +107,16 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, const NetlistDevi
} }
extract_without_initialize (dss.layout (), dss.initial_cell (), layers, nl); extract_without_initialize (dss.layout (), dss.initial_cell (), layers);
} }
void NetlistDeviceExtractor::extract (db::Layout &layout, db::Cell &cell, const std::vector<unsigned int> &layers, db::Netlist *nl) void NetlistDeviceExtractor::extract (db::Layout &layout, db::Cell &cell, const std::vector<unsigned int> &layers, db::Netlist *nl)
{ {
initialize (nl); initialize (nl);
extract_without_initialize (layout, cell, layers, nl); extract_without_initialize (layout, cell, layers);
} }
void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db::Cell &cell, const std::vector<unsigned int> &layers, db::Netlist *nl) void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db::Cell &cell, const std::vector<unsigned int> &layers)
{ {
tl_assert (layers.size () == m_layer_definitions.size ()); tl_assert (layers.size () == m_layer_definitions.size ());
@ -216,9 +215,16 @@ void NetlistDeviceExtractor::extract_devices (const std::vector<db::Region> & /*
void NetlistDeviceExtractor::register_device_class (DeviceClass *device_class) void NetlistDeviceExtractor::register_device_class (DeviceClass *device_class)
{ {
if (mp_device_class != 0) {
throw tl::Exception (tl::to_string (tr ("Device class already set")));
}
tl_assert (device_class != 0);
mp_device_class = device_class;
mp_device_class->set_name (m_name);
tl_assert (m_netlist.get () != 0); tl_assert (m_netlist.get () != 0);
m_netlist->add_device_class (device_class); m_netlist->add_device_class (device_class);
m_device_classes.push_back (device_class);
} }
void NetlistDeviceExtractor::define_layer (const std::string &name, const std::string &description) void NetlistDeviceExtractor::define_layer (const std::string &name, const std::string &description)
@ -226,11 +232,14 @@ void NetlistDeviceExtractor::define_layer (const std::string &name, const std::s
m_layer_definitions.push_back (db::NetlistDeviceExtractorLayerDefinition (name, description, m_layer_definitions.size ())); m_layer_definitions.push_back (db::NetlistDeviceExtractorLayerDefinition (name, description, m_layer_definitions.size ()));
} }
Device *NetlistDeviceExtractor::create_device (unsigned int device_class_index) Device *NetlistDeviceExtractor::create_device ()
{ {
if (mp_device_class == 0) {
throw tl::Exception (tl::to_string (tr ("No device class registered")));
}
tl_assert (mp_circuit != 0); tl_assert (mp_circuit != 0);
tl_assert (device_class_index < m_device_classes.size ()); Device *device = new Device (mp_device_class);
Device *device = new Device (m_device_classes[device_class_index], tl::to_string (++m_device_name_index));
mp_circuit->add_device (device); mp_circuit->add_device (device);
return device; return device;
} }

View File

@ -196,16 +196,24 @@ public:
typedef std::map<std::string, db::Region *> input_layers; typedef std::map<std::string, db::Region *> input_layers;
/** /**
* @brief Default constructor * @brief Constructor
*
* The name is the name of the device class of the devices generated.
*/ */
NetlistDeviceExtractor (); NetlistDeviceExtractor (const std::string &name);
/** /**
* @brief Destructor * @brief Destructor
*/ */
~NetlistDeviceExtractor (); ~NetlistDeviceExtractor ();
// TODO: Do we need to declare input layers? /**
* @brief Gets the name of the extractor and the device class
*/
const std::string &name ()
{
return m_name;
}
/** /**
* @brief Gets the property name for the device terminal annotation * @brief Gets the property name for the device terminal annotation
@ -292,8 +300,7 @@ protected:
* defining the device classes and setting up the device layers. * defining the device classes and setting up the device layers.
* *
* At least one device class needs to be defined. Use "register_device_class" to register * At least one device class needs to be defined. Use "register_device_class" to register
* the device classes you need. The first device class registered has device class index 0, * the device class you need.
* the further ones 1, 2, etc.
* *
* The device layers need to be defined by calling "define_layer" once or several times. * The device layers need to be defined by calling "define_layer" once or several times.
*/ */
@ -323,7 +330,8 @@ protected:
/** /**
* @brief Registers a device class * @brief Registers a device class
* The device class object will become owned by the netlist and must not be deleted by * The device class object will become owned by the netlist and must not be deleted by
* the caller. * the caller. The name of the device class will be changed to the name given to
* the device extractor.
* This method shall be used inside the implementation of "setup" to register * This method shall be used inside the implementation of "setup" to register
* the device classes. * the device classes.
*/ */
@ -343,7 +351,7 @@ protected:
* The device object returned can be configured by the caller, e.g. set parameters. * The device object returned can be configured by the caller, e.g. set parameters.
* It will be owned by the netlist and must not be deleted by the caller. * It will be owned by the netlist and must not be deleted by the caller.
*/ */
Device *create_device (unsigned int device_class_index = 0); Device *create_device ();
/** /**
* @brief Defines a device terminal in the layout (a polygon) * @brief Defines a device terminal in the layout (a polygon)
@ -436,19 +444,23 @@ private:
db::properties_id_type m_propname_id; db::properties_id_type m_propname_id;
db::cell_index_type m_cell_index; db::cell_index_type m_cell_index;
db::Circuit *mp_circuit; db::Circuit *mp_circuit;
std::vector<db::DeviceClass *> m_device_classes; db::DeviceClass *mp_device_class;
std::string m_name;
layer_definitions m_layer_definitions; layer_definitions m_layer_definitions;
std::vector<unsigned int> m_layers; std::vector<unsigned int> m_layers;
unsigned int m_device_name_index;
error_list m_errors; error_list m_errors;
// no copying
NetlistDeviceExtractor (const NetlistDeviceExtractor &);
NetlistDeviceExtractor &operator= (const NetlistDeviceExtractor &);
/** /**
* @brief Initializes the extractor * @brief Initializes the extractor
* This method will produce the device classes required for the device extraction. * This method will produce the device classes required for the device extraction.
*/ */
void initialize (db::Netlist *nl); void initialize (db::Netlist *nl);
void extract_without_initialize (db::Layout &layout, db::Cell &cell, const std::vector<unsigned int> &layers, db::Netlist *nl); void extract_without_initialize (db::Layout &layout, db::Cell &cell, const std::vector<unsigned int> &layers);
}; };
} }

View File

@ -51,6 +51,9 @@ Class<db::Device> decl_dbDevice ("db", "Device",
gsi::method ("device_class", &db::Device::device_class, gsi::method ("device_class", &db::Device::device_class,
"@brief Gets the device class the device belongs to.\n" "@brief Gets the device class the device belongs to.\n"
) + ) +
gsi::method ("circuit", (db::Circuit *(db::Device::*) ()) &db::Device::circuit,
"@brief Gets the circuit the device lives in."
) +
gsi::method ("id", &db::Device::id, gsi::method ("id", &db::Device::id,
"@brief Gets the device ID.\n" "@brief Gets the device ID.\n"
"The ID is a unique integer which identifies the device.\n" "The ID is a unique integer which identifies the device.\n"
@ -125,9 +128,13 @@ static void subcircuit_disconnect_pin1 (db::SubCircuit *subcircuit, const db::Pi
} }
Class<db::SubCircuit> decl_dbSubCircuit ("db", "SubCircuit", Class<db::SubCircuit> decl_dbSubCircuit ("db", "SubCircuit",
gsi::method ("circuit", (db::Circuit *(db::SubCircuit::*) ()) &db::SubCircuit::circuit, gsi::method ("circuit_ref", (db::Circuit *(db::SubCircuit::*) ()) &db::SubCircuit::circuit_ref,
"@brief Gets the circuit referenced by the subcircuit.\n" "@brief Gets the circuit referenced by the subcircuit.\n"
) + ) +
gsi::method ("circuit", (db::Circuit *(db::SubCircuit::*) ()) &db::SubCircuit::circuit,
"@brief Gets the circuit the subcircuit lives in.\n"
"This is NOT the circuit which is referenced. For getting the circuit that the subcircuit references, use \\circuit_ref."
) +
gsi::method ("id", &db::SubCircuit::id, gsi::method ("id", &db::SubCircuit::id,
"@brief Gets the subcircuit ID.\n" "@brief Gets the subcircuit ID.\n"
"The ID is a unique integer which identifies the subcircuit.\n" "The ID is a unique integer which identifies the subcircuit.\n"
@ -620,6 +627,9 @@ Class<db::Circuit> decl_dbCircuit ("db", "Circuit",
"to the outside through such a pin. The pin is added after all existing " "to the outside through such a pin. The pin is added after all existing "
"pins. For more details see the \\Pin class." "pins. For more details see the \\Pin class."
) + ) +
gsi::iterator ("each_ref", (db::Circuit::refs_iterator (db::Circuit::*) ()) &db::Circuit::begin_refs, (db::Circuit::refs_iterator (db::Circuit::*) ()) &db::Circuit::end_refs,
"@brief Iterates over the subcircuit objects referencing this circuit\n"
) +
gsi::iterator ("each_pin", (db::Circuit::pin_iterator (db::Circuit::*) ()) &db::Circuit::begin_pins, (db::Circuit::pin_iterator (db::Circuit::*) ()) &db::Circuit::end_pins, gsi::iterator ("each_pin", (db::Circuit::pin_iterator (db::Circuit::*) ()) &db::Circuit::begin_pins, (db::Circuit::pin_iterator (db::Circuit::*) ()) &db::Circuit::end_pins,
"@brief Iterates over the pins of the circuit" "@brief Iterates over the pins of the circuit"
) + ) +

View File

@ -54,6 +54,7 @@ namespace {
{ {
public: public:
DummyDeviceExtractor () DummyDeviceExtractor ()
: db::NetlistDeviceExtractor (std::string ("DUMMY"))
{ {
error ("msg1"); error ("msg1");
error ("msg2", db::Box (0, 1, 2, 3)); error ("msg2", db::Box (0, 1, 2, 3));

View File

@ -44,172 +44,6 @@
#include <memory> #include <memory>
#include <limits> #include <limits>
class MOSFETExtractor
: public db::NetlistDeviceExtractor
{
public:
MOSFETExtractor (db::Layout *debug_out)
: db::NetlistDeviceExtractor (), mp_debug_out (debug_out), m_ldiff (0), m_lgate (0)
{
if (mp_debug_out) {
m_ldiff = mp_debug_out->insert_layer (db::LayerProperties (100, 0));
m_lgate = mp_debug_out->insert_layer (db::LayerProperties (101, 0));
}
}
virtual void setup ()
{
define_layer ("PD", "P diffusion");
define_layer ("ND", "N diffusion");
define_layer ("G", "Gate");
define_layer ("P", "Poly");
db::DeviceClassMOS3Transistor *pmos_class = new db::DeviceClassMOS3Transistor ();
pmos_class->set_name ("PMOS");
register_device_class (pmos_class);
db::DeviceClassMOS3Transistor *nmos_class = new db::DeviceClassMOS3Transistor ();
nmos_class->set_name ("NMOS");
register_device_class (nmos_class);
}
virtual db::Connectivity get_connectivity (const db::Layout & /*layout*/, const std::vector<unsigned int> &layers) const
{
tl_assert (layers.size () == 4);
unsigned int lpdiff = layers [0];
unsigned int lndiff = layers [1];
unsigned int gate = layers [2];
// not used for device recognition: poly (3), but used for producing the gate terminals
// The layer definition is pdiff, ndiff, gate
db::Connectivity conn;
// collect all connected pdiff
conn.connect (lpdiff, lpdiff);
// collect all connected ndiff
conn.connect (lndiff, lndiff);
// collect all connected gate shapes
conn.connect (gate, gate);
// connect gate with pdiff
conn.connect (lpdiff, gate);
// connect gate with ndiff
conn.connect (lndiff, gate);
return conn;
}
virtual void extract_devices (const std::vector<db::Region> &layer_geometry)
{
const db::Region &rpdiff = layer_geometry [0];
const db::Region &rndiff = layer_geometry [1];
const db::Region &rgates = layer_geometry [2];
for (db::Region::const_iterator p = rgates.begin_merged (); !p.at_end (); ++p) {
db::Region rgate (*p);
db::Region rpdiff_on_gate = rpdiff.selected_interacting (rgate);
db::Region rndiff_on_gate = rndiff.selected_interacting (rgate);
if (! rpdiff_on_gate.empty () && ! rndiff_on_gate.empty ()) {
error (tl::to_string (tr ("Gate shape touches both ndiff and pdiff - ignored")), *p);
} else if (rpdiff_on_gate.empty () && rndiff_on_gate.empty ()) {
error (tl::to_string (tr ("Gate shape touches neither ndiff and pdiff - ignored")), *p);
} else {
bool is_pmos = ! rpdiff_on_gate.empty ();
db::Region &diff = (is_pmos ? rpdiff_on_gate : rndiff_on_gate);
unsigned int terminal_geometry_index = (is_pmos ? 0 : 1);
unsigned int gate_geometry_index = 3;
unsigned int device_class_index = (is_pmos ? 0 /*PMOS*/ : 1 /*NMOS*/);
if (diff.size () != 2) {
error (tl::sprintf (tl::to_string (tr ("Expected two polygons on diff interacting one gate shape (found %d) - gate shape ignored")), int (diff.size ())), *p);
continue;
}
db::Edges edges (rgate.edges () & diff.edges ());
if (edges.size () != 2) {
error (tl::sprintf (tl::to_string (tr ("Expected two edges interacting gate/diff (found %d) - width and length may be incorrect")), int (edges.size ())), *p);
continue;
}
if (! p->is_box ()) {
error (tl::to_string (tr ("Gate shape is not a box - width and length may be incorrect")), *p);
}
db::Device *device = create_device (device_class_index);
device->set_parameter_value ("W", dbu () * edges.length () * 0.5);
device->set_parameter_value ("L", dbu () * (p->perimeter () - edges.length ()) * 0.5);
int diff_index = 0;
for (db::Region::const_iterator d = diff.begin (); !d.at_end () && diff_index < 2; ++d, ++diff_index) {
// count the number of gate shapes attached to this shape and distribute the area of the
// diffusion region to the number of gates
int n = rgates.selected_interacting (db::Region (*d)).size ();
tl_assert (n > 0);
device->set_parameter_value (diff_index == 0 ? "AS" : "AD", dbu () * dbu () * d->area () / double (n));
define_terminal (device, device->device_class ()->terminal_id_for_name (diff_index == 0 ? "S" : "D"), terminal_geometry_index, *d);
}
define_terminal (device, device->device_class ()->terminal_id_for_name ("G"), gate_geometry_index, *p);
// output the device for debugging
device_out (device, diff, rgate);
}
}
}
private:
db::Layout *mp_debug_out;
unsigned int m_ldiff, m_lgate;
void device_out (const db::Device *device, const db::Region &diff, const db::Region &gate)
{
if (! mp_debug_out) {
return;
}
std::string cn = layout ()->cell_name (cell_index ());
std::pair<bool, db::cell_index_type> target_cp = mp_debug_out->cell_by_name (cn.c_str ());
tl_assert (target_cp.first);
db::cell_index_type dci = mp_debug_out->add_cell ((device->device_class ()->name () + "_" + device->name ()).c_str ());
mp_debug_out->cell (target_cp.second).insert (db::CellInstArray (db::CellInst (dci), db::Trans ()));
db::Cell &device_cell = mp_debug_out->cell (dci);
for (db::Region::const_iterator p = diff.begin (); ! p.at_end (); ++p) {
device_cell.shapes (m_ldiff).insert (*p);
}
for (db::Region::const_iterator p = gate.begin (); ! p.at_end (); ++p) {
device_cell.shapes (m_lgate).insert (*p);
}
std::string ps;
const std::vector<db::DeviceParameterDefinition> &pd = device->device_class ()->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
if (! ps.empty ()) {
ps += ",";
}
ps += i->name () + "=" + tl::to_string (device->parameter_value (i->id ()));
}
device_cell.shapes (m_ldiff).insert (db::Text (ps, db::Trans (diff.bbox ().center () - db::Point ())));
}
};
static unsigned int define_layer (db::Layout &ly, db::LayerMap &lmap, int gds_layer, int gds_datatype = 0)
{
unsigned int lid = ly.insert_layer (db::LayerProperties (gds_layer, gds_datatype));
lmap.map (ly.get_properties (lid), lid);
return lid;
}
static unsigned int layer_of (const db::Region &region) static unsigned int layer_of (const db::Region &region)
{ {
return db::DeepLayer (region).layer (); return db::DeepLayer (region).layer ();
@ -248,6 +82,153 @@ static std::string pin_name (const db::Pin &pin)
} }
} }
class MOSFETExtractor
: public db::NetlistDeviceExtractor
{
public:
MOSFETExtractor (const std::string &name, db::Layout *debug_out)
: db::NetlistDeviceExtractor (name), mp_debug_out (debug_out), m_ldiff (0), m_lgate (0)
{
if (mp_debug_out) {
m_ldiff = mp_debug_out->insert_layer (db::LayerProperties (100, 0));
m_lgate = mp_debug_out->insert_layer (db::LayerProperties (101, 0));
}
}
virtual void setup ()
{
define_layer ("SD", "Source/drain diffusion");
define_layer ("G", "Gate");
define_layer ("P", "Poly");
register_device_class (new db::DeviceClassMOS3Transistor ());
}
virtual db::Connectivity get_connectivity (const db::Layout & /*layout*/, const std::vector<unsigned int> &layers) const
{
tl_assert (layers.size () == 3);
unsigned int diff = layers [0];
unsigned int gate = layers [1];
// not used for device recognition: poly (2), but used for producing the gate terminals
// The layer definition is diff, gate
db::Connectivity conn;
// collect all connected diffusion shapes
conn.connect (diff, diff);
// collect all connected gate shapes
conn.connect (gate, gate);
// connect gate with diff to detect gate/diffusion boundary
conn.connect (diff, gate);
return conn;
}
virtual void extract_devices (const std::vector<db::Region> &layer_geometry)
{
const db::Region &rdiff = layer_geometry [0];
const db::Region &rgates = layer_geometry [1];
for (db::Region::const_iterator p = rgates.begin_merged (); !p.at_end (); ++p) {
db::Region rgate (*p);
db::Region rdiff2gate = rdiff.selected_interacting (rgate);
if (rdiff2gate.empty ()) {
error (tl::to_string (tr ("Gate shape touches no diffusion - ignored")), *p);
} else {
unsigned int terminal_geometry_index = 0;
unsigned int gate_geometry_index = 2;
if (rdiff2gate.size () != 2) {
error (tl::sprintf (tl::to_string (tr ("Expected two polygons on diff interacting one gate shape (found %d) - gate shape ignored")), int (rdiff2gate.size ())), *p);
continue;
}
db::Edges edges (rgate.edges () & rdiff2gate.edges ());
if (edges.size () != 2) {
error (tl::sprintf (tl::to_string (tr ("Expected two edges interacting gate/diff (found %d) - width and length may be incorrect")), int (edges.size ())), *p);
continue;
}
if (! p->is_box ()) {
error (tl::to_string (tr ("Gate shape is not a box - width and length may be incorrect")), *p);
}
db::Device *device = create_device ();
device->set_parameter_value ("W", dbu () * edges.length () * 0.5);
device->set_parameter_value ("L", dbu () * (p->perimeter () - edges.length ()) * 0.5);
int diff_index = 0;
for (db::Region::const_iterator d = rdiff2gate.begin (); !d.at_end () && diff_index < 2; ++d, ++diff_index) {
// count the number of gate shapes attached to this shape and distribute the area of the
// diffusion region to the number of gates
int n = rgates.selected_interacting (db::Region (*d)).size ();
tl_assert (n > 0);
device->set_parameter_value (diff_index == 0 ? "AS" : "AD", dbu () * dbu () * d->area () / double (n));
define_terminal (device, device->device_class ()->terminal_id_for_name (diff_index == 0 ? "S" : "D"), terminal_geometry_index, *d);
}
define_terminal (device, device->device_class ()->terminal_id_for_name ("G"), gate_geometry_index, *p);
// output the device for debugging
device_out (device, rdiff2gate, rgate);
}
}
}
private:
db::Layout *mp_debug_out;
unsigned int m_ldiff, m_lgate;
void device_out (const db::Device *device, const db::Region &diff, const db::Region &gate)
{
if (! mp_debug_out) {
return;
}
std::string cn = layout ()->cell_name (cell_index ());
std::pair<bool, db::cell_index_type> target_cp = mp_debug_out->cell_by_name (cn.c_str ());
tl_assert (target_cp.first);
db::cell_index_type dci = mp_debug_out->add_cell ((device->device_class ()->name () + "_" + device->circuit ()->name () + "_" + device_name (*device)).c_str ());
mp_debug_out->cell (target_cp.second).insert (db::CellInstArray (db::CellInst (dci), db::Trans ()));
db::Cell &device_cell = mp_debug_out->cell (dci);
for (db::Region::const_iterator p = diff.begin (); ! p.at_end (); ++p) {
device_cell.shapes (m_ldiff).insert (*p);
}
for (db::Region::const_iterator p = gate.begin (); ! p.at_end (); ++p) {
device_cell.shapes (m_lgate).insert (*p);
}
std::string ps;
const std::vector<db::DeviceParameterDefinition> &pd = device->device_class ()->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
if (! ps.empty ()) {
ps += ",";
}
ps += i->name () + "=" + tl::to_string (device->parameter_value (i->id ()));
}
device_cell.shapes (m_ldiff).insert (db::Text (ps, db::Trans (diff.bbox ().center () - db::Point ())));
}
};
static unsigned int define_layer (db::Layout &ly, db::LayerMap &lmap, int gds_layer, int gds_datatype = 0)
{
unsigned int lid = ly.insert_layer (db::LayerProperties (gds_layer, gds_datatype));
lmap.map (ly.get_properties (lid), lid);
return lid;
}
// @@@ TODO: move this somewhere else // @@@ TODO: move this somewhere else
static void dump_nets (const db::Netlist &nl, const db::hier_clusters<db::PolygonRef> &clusters, db::Layout &ly, const std::map<unsigned int, unsigned int> &lmap, const db::CellMapping &cmap) static void dump_nets (const db::Netlist &nl, const db::hier_clusters<db::PolygonRef> &clusters, db::Layout &ly, const std::map<unsigned int, unsigned int> &lmap, const db::CellMapping &cmap)
@ -329,14 +310,15 @@ static std::string netlist2string (const db::Netlist &nl)
for (db::Circuit::const_subcircuit_iterator sc = c->begin_subcircuits (); sc != c->end_subcircuits (); ++sc) { for (db::Circuit::const_subcircuit_iterator sc = c->begin_subcircuits (); sc != c->end_subcircuits (); ++sc) {
std::string ps; std::string ps;
const db::SubCircuit &subcircuit = *sc; const db::SubCircuit &subcircuit = *sc;
for (db::Circuit::const_pin_iterator p = sc->circuit ()->begin_pins (); p != sc->circuit ()->end_pins (); ++p) { const db::Circuit *circuit = sc->circuit_ref ();
if (p != sc->circuit ()->begin_pins ()) { for (db::Circuit::const_pin_iterator p = circuit->begin_pins (); p != circuit->end_pins (); ++p) {
if (p != circuit->begin_pins ()) {
ps += ","; ps += ",";
} }
const db::Pin &pin = *p; const db::Pin &pin = *p;
ps += pin_name (pin) + "=" + net_name (subcircuit.net_for_pin (pin.id ())); ps += pin_name (pin) + "=" + net_name (subcircuit.net_for_pin (pin.id ()));
} }
res += std::string (" X") + sc->circuit ()->name () + " " + subcircuit_name (*sc) + " (" + ps + ")\n"; res += std::string (" X") + circuit->name () + " " + subcircuit_name (*sc) + " (" + ps + ")\n";
} }
} }
@ -344,7 +326,7 @@ static std::string netlist2string (const db::Netlist &nl)
return res; return res;
} }
TEST(2_DeviceAndNetExtraction) TEST(1_DeviceAndNetExtraction)
{ {
db::Layout ly; db::Layout ly;
db::LayerMap lmap; db::LayerMap lmap;
@ -396,10 +378,14 @@ TEST(2_DeviceAndNetExtraction)
db::Region rmetal2_lbl (db::RecursiveShapeIterator (ly, tc, metal2_lbl), dss); db::Region rmetal2_lbl (db::RecursiveShapeIterator (ly, tc, metal2_lbl), dss);
// derived regions // derived regions
db::Region rgate = ractive & rpoly;
db::Region rsd = ractive - rgate; db::Region rpactive = ractive & rnwell;
db::Region rpdiff = rsd & rnwell; db::Region rpgate = rpactive & rpoly;
db::Region rndiff = rsd - rnwell; db::Region rpsd = rpactive - rpgate;
db::Region rnactive = ractive - rnwell;
db::Region rngate = rnactive & rpoly;
db::Region rnsd = rnactive - rngate;
// return the computed layers into the original layout and write it for debugging purposes // return the computed layers into the original layout and write it for debugging purposes
@ -408,10 +394,12 @@ TEST(2_DeviceAndNetExtraction)
unsigned int lpdiff = ly.insert_layer (db::LayerProperties (12, 0)); // 12/0 -> P Diffusion unsigned int lpdiff = ly.insert_layer (db::LayerProperties (12, 0)); // 12/0 -> P Diffusion
unsigned int lndiff = ly.insert_layer (db::LayerProperties (13, 0)); // 13/0 -> N Diffusion unsigned int lndiff = ly.insert_layer (db::LayerProperties (13, 0)); // 13/0 -> N Diffusion
rgate.insert_into (&ly, tc.cell_index (), lgate); rpgate.insert_into (&ly, tc.cell_index (), lgate);
rsd.insert_into (&ly, tc.cell_index (), lsd); rngate.insert_into (&ly, tc.cell_index (), lgate);
rpdiff.insert_into (&ly, tc.cell_index (), lpdiff); rpsd.insert_into (&ly, tc.cell_index (), lsd);
rndiff.insert_into (&ly, tc.cell_index (), lndiff); rnsd.insert_into (&ly, tc.cell_index (), lsd);
rpsd.insert_into (&ly, tc.cell_index (), lpdiff);
rnsd.insert_into (&ly, tc.cell_index (), lndiff);
// perform the extraction // perform the extraction
@ -420,15 +408,20 @@ TEST(2_DeviceAndNetExtraction)
// NOTE: the device extractor will add more debug layers for the transistors: // NOTE: the device extractor will add more debug layers for the transistors:
// 20/0 -> Diffusion // 20/0 -> Diffusion
// 21/0 -> Gate // 21/0 -> Gate
MOSFETExtractor ex (&ly); MOSFETExtractor pmos_ex ("PMOS", &ly);
MOSFETExtractor nmos_ex ("NMOS", &ly);
db::NetlistDeviceExtractor::input_layers dl; db::NetlistDeviceExtractor::input_layers dl;
dl["PD"] = &rpdiff;
dl["ND"] = &rndiff;
dl["G"] = &rgate;
dl["P"] = &rpoly;
ex.extract (dss, dl, &nl); dl["SD"] = &rpsd;
dl["G"] = &rpgate;
dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes
pmos_ex.extract (dss, dl, &nl);
dl["SD"] = &rnsd;
dl["G"] = &rngate;
dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes
nmos_ex.extract (dss, dl, &nl);
// perform the net extraction // perform the net extraction
@ -436,8 +429,8 @@ TEST(2_DeviceAndNetExtraction)
db::Connectivity conn; db::Connectivity conn;
// Intra-layer // Intra-layer
conn.connect (rpdiff); conn.connect (rpsd);
conn.connect (rndiff); conn.connect (rnsd);
conn.connect (rpoly); conn.connect (rpoly);
conn.connect (rdiff_cont); conn.connect (rdiff_cont);
conn.connect (rpoly_cont); conn.connect (rpoly_cont);
@ -445,8 +438,8 @@ TEST(2_DeviceAndNetExtraction)
conn.connect (rvia1); conn.connect (rvia1);
conn.connect (rmetal2); conn.connect (rmetal2);
// Inter-layer // Inter-layer
conn.connect (rpdiff, rdiff_cont); conn.connect (rpsd, rdiff_cont);
conn.connect (rndiff, rdiff_cont); conn.connect (rnsd, rdiff_cont);
conn.connect (rpoly, rpoly_cont); conn.connect (rpoly, rpoly_cont);
conn.connect (rpoly_cont, rmetal1); conn.connect (rpoly_cont, rmetal1);
conn.connect (rdiff_cont, rmetal1); conn.connect (rdiff_cont, rmetal1);
@ -468,9 +461,11 @@ TEST(2_DeviceAndNetExtraction)
// 206/0 -> Metal1 // 206/0 -> Metal1
// 207/0 -> Via1 // 207/0 -> Via1
// 208/0 -> Metal2 // 208/0 -> Metal2
// 210/0 -> N source/drain
// 211/0 -> P source/drain
std::map<unsigned int, unsigned int> dump_map; std::map<unsigned int, unsigned int> dump_map;
dump_map [layer_of (rpdiff) ] = ly.insert_layer (db::LayerProperties (210, 0)); dump_map [layer_of (rpsd) ] = ly.insert_layer (db::LayerProperties (210, 0));
dump_map [layer_of (rndiff) ] = ly.insert_layer (db::LayerProperties (211, 0)); dump_map [layer_of (rnsd) ] = ly.insert_layer (db::LayerProperties (211, 0));
dump_map [layer_of (rpoly) ] = ly.insert_layer (db::LayerProperties (203, 0)); dump_map [layer_of (rpoly) ] = ly.insert_layer (db::LayerProperties (203, 0));
dump_map [layer_of (rdiff_cont)] = ly.insert_layer (db::LayerProperties (204, 0)); dump_map [layer_of (rdiff_cont)] = ly.insert_layer (db::LayerProperties (204, 0));
dump_map [layer_of (rpoly_cont)] = ly.insert_layer (db::LayerProperties (205, 0)); dump_map [layer_of (rpoly_cont)] = ly.insert_layer (db::LayerProperties (205, 0));
@ -496,10 +491,10 @@ TEST(2_DeviceAndNetExtraction)
" XINV2 $9 ($1=$I6,$2=$I45,$3=$I7,$4=VSS,$5=VDD)\n" " XINV2 $9 ($1=$I6,$2=$I45,$3=$I7,$4=VSS,$5=VDD)\n"
" XINV2 $10 ($1=$I7,$2=$I46,$3=$I8,$4=VSS,$5=VDD)\n" " XINV2 $10 ($1=$I7,$2=$I46,$3=$I8,$4=VSS,$5=VDD)\n"
"Circuit INV2 ($1=IN,$2=$2,$3=OUT,$4=$4,$5=$5):\n" "Circuit INV2 ($1=IN,$2=$2,$3=OUT,$4=$4,$5=$5):\n"
" DPMOS 1 (S=$2,G=IN,D=$5) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" " DPMOS $1 (S=$2,G=IN,D=$5) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n"
" DPMOS 2 (S=$5,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" " DPMOS $2 (S=$5,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n"
" DNMOS 3 (S=$2,G=IN,D=$4) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" " DNMOS $3 (S=$2,G=IN,D=$4) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n"
" DNMOS 4 (S=$4,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" " DNMOS $4 (S=$4,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n"
" XTRANS $1 ($1=$2,$2=$4,$3=IN)\n" " XTRANS $1 ($1=$2,$2=$4,$3=IN)\n"
" XTRANS $2 ($1=$2,$2=$5,$3=IN)\n" " XTRANS $2 ($1=$2,$2=$5,$3=IN)\n"
" XTRANS $3 ($1=$5,$2=OUT,$3=$2)\n" " XTRANS $3 ($1=$5,$2=OUT,$3=$2)\n"
@ -523,19 +518,9 @@ TEST(2_DeviceAndNetExtraction)
// An attempt to simplify things. // An attempt to simplify things.
/* /*
- layers: use db::Region, or wrapper?
-> use regions, but test whether they are deep regions (?)
TODO: TODO:
- netlist query functions such as net_by_name, device_by_name, circuit_by_name - netlist query functions such as net_by_name, device_by_name, circuit_by_name
- terminal geometry (Polygon) for device, combined device geometry (all terminals) - terminal geometry (Polygon) for device, combined device geometry (all terminals)
- error interface for device extraction
// gets the device extraction errors
// device_extraction_error_iterator begin_device_extraction_errors () const;
// device_extraction_error_iterator end_device_extraction_errors () const;
// bool has_device_extraction_errors () const;
- device extractor needs to declare the layers to allow passing them by name
- netlist manipulation methods (i.e. flatten certain cells, purging etc.) - netlist manipulation methods (i.e. flatten certain cells, purging etc.)
*/ */
@ -551,23 +536,25 @@ public:
// the iterator provides the hierarchical selection (enabling/disabling cells etc.) // the iterator provides the hierarchical selection (enabling/disabling cells etc.)
LayoutToNetlist (const db::RecursiveShapeIterator &iter); LayoutToNetlist (const db::RecursiveShapeIterator &iter);
// --- preparation // --- Step 0: configuration
// returns a new'd region void set_threads (unsigned int n);
void set_area_ratio (double ar);
void set_max_vertex_count (size_t n);
// --- Step 1: preparation
// returns new'd regions
db::Region *make_layer (unsigned int layer_index); db::Region *make_layer (unsigned int layer_index);
db::Region *make_text_layer (unsigned int layer_index); db::Region *make_text_layer (unsigned int layer_index);
db::Region *make_polygon_layer (unsigned int layer_index); db::Region *make_polygon_layer (unsigned int layer_index);
// gets the internal layout and cell // --- Step 2: device extraction
const db::Layout &internal_layout () const;
const db::Cell &internal_top_cell () const;
// --- device extraction
// after this, the device extractor will have errors if some occured. // after this, the device extractor will have errors if some occured.
void extract_devices (db::NetlistDeviceExtractor *extractor, const std::map<std::string, const db::Region *> &layers); void extract_devices (db::NetlistDeviceExtractor &extractor, const std::map<std::string, db::Region *> &layers);
// --- net extraction // --- Step 3: net extraction
// define connectivity for the netlist extraction // define connectivity for the netlist extraction
void connect (const db::Region &l); void connect (const db::Region &l);
@ -576,7 +563,11 @@ public:
// runs the netlist extraction // runs the netlist extraction
void extract_netlist (); void extract_netlist ();
// --- retrieval // --- Step 4: retrieval
// gets the internal layout and cell (0 if not available)
const db::Layout *internal_layout () const;
const db::Cell *internal_top_cell () const;
// gets the internal layer index of the given region // gets the internal layer index of the given region
unsigned int layer_of (const db::Region &region) const; unsigned int layer_of (const db::Region &region) const;
@ -600,6 +591,11 @@ public:
// copies the shapes of the given net from a given layer // copies the shapes of the given net from a given layer
// (recursive true: include nets from subcircuits) // (recursive true: include nets from subcircuits)
db::Region shapes_of_net (const db::Net &net, const db::Region &of_layer, bool recursive); db::Region shapes_of_net (const db::Net &net, const db::Region &of_layer, bool recursive);
// finds the net by probing a specific location on the given layer looking through the
// hierarchy. Returns 0 if no net was found.
db::Net *probe_net (const db::Region &of_region, const db::DPoint &point);
db::Net *probe_net (const db::Region &of_region, const db::Point &point);
}; };
} }

View File

@ -165,7 +165,7 @@ static std::string net2string (const db::Net &n)
res += ","; res += ",";
} }
if (i->subcircuit ()) { if (i->subcircuit ()) {
res += i->subcircuit ()->circuit () ? i->subcircuit ()->circuit ()->name () : "(null)"; res += i->subcircuit ()->circuit_ref () ? i->subcircuit ()->circuit_ref ()->name () : "(null)";
res += ":"; res += ":";
} else { } else {
res += "+"; res += "+";
@ -221,15 +221,15 @@ static std::string netlist2 (const db::Circuit &c)
} }
for (db::Circuit::const_subcircuit_iterator s = c.begin_subcircuits (); s != c.end_subcircuits (); ++s) { for (db::Circuit::const_subcircuit_iterator s = c.begin_subcircuits (); s != c.end_subcircuits (); ++s) {
if (! s->circuit ()) { if (! s->circuit_ref ()) {
continue; continue;
} }
pins.clear (); pins.clear ();
for (size_t i = 0; i < s->circuit ()->pin_count (); ++i) { for (size_t i = 0; i < s->circuit_ref ()->pin_count (); ++i) {
if (! pins.empty ()) { if (! pins.empty ()) {
pins += ","; pins += ",";
} }
pins += s->circuit ()->pin_by_id (i)->name (); pins += s->circuit_ref ()->pin_by_id (i)->name ();
pins += "="; pins += "=";
const db::Net *net = s->net_for_pin (i); const db::Net *net = s->net_for_pin (i);
pins += net ? net->name () : std::string ("(null)"); pins += net ? net->name () : std::string ("(null)");
@ -268,7 +268,11 @@ TEST(4_CircuitDevices)
db::Device *d1 = new db::Device (&dc1, "d1"); db::Device *d1 = new db::Device (&dc1, "d1");
db::Device *d2a = new db::Device (&dc2, "d2a"); db::Device *d2a = new db::Device (&dc2, "d2a");
db::Device *d2b = new db::Device (&dc2, "d2b"); db::Device *d2b = new db::Device (&dc2, "d2b");
EXPECT_EQ (d1->circuit () == 0, true);
c->add_device (d1); c->add_device (d1);
EXPECT_EQ (d1->circuit () == c.get (), true);
EXPECT_EQ (d1->id (), size_t (1)); EXPECT_EQ (d1->id (), size_t (1));
EXPECT_EQ (c->device_by_id (d1->id ()) == d1, true); EXPECT_EQ (c->device_by_id (d1->id ()) == d1, true);
c->add_device (dd); c->add_device (dd);
@ -386,6 +390,18 @@ static std::string netlist2 (const db::Netlist &nl)
return res; return res;
} }
static std::string refs2string (const db::Circuit *c)
{
std::string res;
for (db::Circuit::const_refs_iterator r = c->begin_refs (); r != c->end_refs (); ++r) {
if (!res.empty ()) {
res += ",";
}
res += r->name ();
}
return res;
}
TEST(4_NetlistSubcircuits) TEST(4_NetlistSubcircuits)
{ {
std::auto_ptr<db::Netlist> nl (new db::Netlist ()); std::auto_ptr<db::Netlist> nl (new db::Netlist ());
@ -413,14 +429,19 @@ TEST(4_NetlistSubcircuits)
db::Device *d = new db::Device (dc, "D"); db::Device *d = new db::Device (dc, "D");
c2->add_device (d); c2->add_device (d);
EXPECT_EQ (refs2string (c2), "");
db::SubCircuit *sc1 = new db::SubCircuit (c2); db::SubCircuit *sc1 = new db::SubCircuit (c2);
sc1->set_name ("sc1"); sc1->set_name ("sc1");
EXPECT_EQ (refs2string (c2), "sc1");
EXPECT_EQ (sc1->circuit () == 0, true);
c1->add_subcircuit (sc1); c1->add_subcircuit (sc1);
EXPECT_EQ (sc1->circuit () == c1, true);
EXPECT_EQ (sc1->id (), size_t (1)); EXPECT_EQ (sc1->id (), size_t (1));
EXPECT_EQ (c1->subcircuit_by_id (sc1->id ()) == sc1, true); EXPECT_EQ (c1->subcircuit_by_id (sc1->id ()) == sc1, true);
db::SubCircuit *sc2 = new db::SubCircuit (c2); db::SubCircuit *sc2 = new db::SubCircuit (c2);
sc2->set_name ("sc2"); sc2->set_name ("sc2");
EXPECT_EQ (refs2string (c2), "sc1,sc2");
c1->add_subcircuit (sc2); c1->add_subcircuit (sc2);
EXPECT_EQ (sc2->id (), size_t (2)); EXPECT_EQ (sc2->id (), size_t (2));
EXPECT_EQ (c1->subcircuit_by_id (sc2->id ()) == sc2, true); EXPECT_EQ (c1->subcircuit_by_id (sc2->id ()) == sc2, true);
@ -778,3 +799,38 @@ TEST(10_NetPinRefBasics)
EXPECT_EQ (db::NetPinRef (&d1, 1) < db::NetPinRef (&d1, 0), false); EXPECT_EQ (db::NetPinRef (&d1, 1) < db::NetPinRef (&d1, 0), false);
EXPECT_NE ((db::NetPinRef (&d1, 0) < db::NetPinRef (&d2, 0)), (db::NetPinRef (&d2, 0) < db::NetPinRef (&d1, 0))); EXPECT_NE ((db::NetPinRef (&d1, 0) < db::NetPinRef (&d2, 0)), (db::NetPinRef (&d2, 0) < db::NetPinRef (&d1, 0)));
} }
TEST(11_NetlistCircuitRefs)
{
std::auto_ptr<db::Netlist> nl (new db::Netlist ());
db::Circuit *c1 = new db::Circuit ();
c1->set_name ("c1");
nl->add_circuit (c1);
db::Circuit *c2 = new db::Circuit ();
c2->set_name ("c2");
nl->add_circuit (c2);
db::SubCircuit *sc1 = new db::SubCircuit (c2);
sc1->set_name ("sc1");
EXPECT_EQ (refs2string (c2), "sc1");
c1->add_subcircuit (sc1);
db::SubCircuit *sc2 = new db::SubCircuit (c2);
sc2->set_name ("sc2");
EXPECT_EQ (refs2string (c2), "sc1,sc2");
c1->add_subcircuit (sc2);
*sc2 = db::SubCircuit ();
EXPECT_EQ (refs2string (c2), "sc1");
db::SubCircuit sc3 (c2);
sc3.set_name ("sc3");
*sc2 = sc3;
sc2->set_name ("sc2");
EXPECT_EQ (refs2string (c2), "sc1,sc3,sc2");
sc3 = db::SubCircuit ();
EXPECT_EQ (refs2string (c2), "sc1,sc2");
}

Binary file not shown.

View File

@ -258,22 +258,35 @@ class DBNetlist_TestClass < TestBase
sc1 = c.create_subcircuit(cc) sc1 = c.create_subcircuit(cc)
sc1.name = "SC1" sc1.name = "SC1"
assert_equal(sc1.circuit.object_id, c.object_id)
assert_equal(sc1.name, "SC1") assert_equal(sc1.name, "SC1")
assert_equal(sc1.circuit.name, "CC") assert_equal(sc1.circuit_ref.name, "CC")
assert_equal(c.subcircuit_by_id(sc1.id).id, 1) assert_equal(c.subcircuit_by_id(sc1.id).id, 1)
assert_equal(c.subcircuit_by_id(2).inspect, "nil") assert_equal(c.subcircuit_by_id(2).inspect, "nil")
refs = []
cc.each_ref { |r| refs << r.name }
assert_equal(refs.join(","), "SC1")
sc2 = c.create_subcircuit(cc) sc2 = c.create_subcircuit(cc)
sc2.name = "SC2" sc2.name = "SC2"
refs = []
cc.each_ref { |r| refs << r.name }
assert_equal(refs.join(","), "SC1,SC2")
names = [] names = []
ccn = [] ccn = []
c.each_subcircuit { |sc| names << sc.name; ccn << sc.circuit.name } c.each_subcircuit { |sc| names << sc.name; ccn << sc.circuit_ref.name }
assert_equal(names, [ "SC1", "SC2" ]) assert_equal(names, [ "SC1", "SC2" ])
assert_equal(ccn, [ "CC", "CC" ]) assert_equal(ccn, [ "CC", "CC" ])
c.remove_subcircuit(sc2) c.remove_subcircuit(sc2)
refs = []
cc.each_ref { |r| refs << r.name }
assert_equal(refs.join(","), "SC1")
names = [] names = []
c.each_subcircuit { |sc| names << sc.name} c.each_subcircuit { |sc| names << sc.name}
assert_equal(names, [ "SC1" ]) assert_equal(names, [ "SC1" ])
@ -282,7 +295,7 @@ class DBNetlist_TestClass < TestBase
names = [] names = []
ccn = [] ccn = []
c.each_subcircuit { |sc| names << sc.name; ccn << sc.circuit.name } c.each_subcircuit { |sc| names << sc.name; ccn << sc.circuit_ref.name }
assert_equal(names, [ "SC1", "SC2" ]) assert_equal(names, [ "SC1", "SC2" ])
assert_equal(ccn, [ "CC", "CC" ]) assert_equal(ccn, [ "CC", "CC" ])
@ -531,6 +544,8 @@ class DBNetlist_TestClass < TestBase
nl.add(c) nl.add(c)
d1 = c.create_device(dc) d1 = c.create_device(dc)
assert_equal(d1.circuit.object_id, c.object_id)
assert_equal(d1.parameter(0), 1.0) assert_equal(d1.parameter(0), 1.0)
assert_equal(d1.parameter("U"), 1.0) assert_equal(d1.parameter("U"), 1.0)
assert_equal(d1.parameter(1), 2.0) assert_equal(d1.parameter(1), 2.0)