Some updates (res/cap device ex, flatten preserved geometry)

- Two new device extractors for resistors and caps
  (two-terminal only)
- R and C device classes have A and P parameters now
- A generic concept to supply terminal output layers
  for device extractors (tX).
- Converted offset to transformation for devices:
  this was required to make circuit flattening preserve
  the geometry (transformation of devices)
  L2N/LVSDB formats have been extended for this.
This commit is contained in:
Matthias Koefferlein 2019-05-29 00:10:10 +02:00
parent f4939a6efc
commit 9d01cb5282
19 changed files with 674 additions and 149 deletions

View File

@ -358,6 +358,7 @@ void Circuit::flatten_subcircuit (SubCircuit *subcircuit)
if (! d->name ().empty ()) {
device->set_name (subcircuit->expanded_name () + "." + d->name ());
}
device->set_trans (subcircuit->trans () * device->trans ());
add_device (device);
const std::vector<db::DeviceTerminalDefinition> &td = d->device_class ()->terminal_definitions ();
@ -382,6 +383,7 @@ void Circuit::flatten_subcircuit (SubCircuit *subcircuit)
if (! new_subcircuit->name ().empty ()) {
new_subcircuit->set_name (subcircuit->expanded_name () + "." + new_subcircuit->name ());
}
new_subcircuit->set_trans (subcircuit->trans () * new_subcircuit->trans ());
add_subcircuit (new_subcircuit);
const db::Circuit *cr = sc->circuit_ref ();

View File

@ -67,7 +67,7 @@ Device &Device::operator= (const Device &other)
{
if (this != &other) {
m_name = other.m_name;
m_position = other.m_position;
m_trans = other.m_trans;
m_parameters = other.m_parameters;
mp_device_class = other.mp_device_class;
mp_device_abstract = other.mp_device_abstract;
@ -97,9 +97,9 @@ void Device::set_name (const std::string &n)
}
}
void Device::set_position (const db::DPoint &pt)
void Device::set_trans (const db::DCplxTrans &tr)
{
m_position = pt;
m_trans = tr;
}
void Device::set_terminal_ref_for_terminal (size_t terminal_id, Net::terminal_iterator iter)
@ -254,7 +254,7 @@ void Device::reroute_terminal (unsigned int this_terminal, db::Device *other, un
void Device::join_device (db::Device *other)
{
db::DVector d = other->position () - position ();
db::DCplxTrans d = trans ().inverted () * other->trans ();
m_other_abstracts.reserve (m_other_abstracts.size () + 1 + other->m_other_abstracts.size ());
@ -262,7 +262,7 @@ void Device::join_device (db::Device *other)
for (std::vector<db::DeviceAbstractRef>::const_iterator a = other->m_other_abstracts.begin (); a != other->m_other_abstracts.end (); ++a) {
m_other_abstracts.push_back (*a);
m_other_abstracts.back ().offset += d;
m_other_abstracts.back ().trans = d * m_other_abstracts.back ().trans;
}
}

View File

@ -27,6 +27,7 @@
#include "dbNet.h"
#include "dbPoint.h"
#include "dbVector.h"
#include "dbTrans.h"
#include "tlObject.h"
@ -68,20 +69,20 @@ struct DeviceReconnectedTerminal
*/
struct DeviceAbstractRef
{
DeviceAbstractRef (const db::DeviceAbstract *_device_abstract, const db::DVector &_offset)
: device_abstract (_device_abstract), offset (_offset)
DeviceAbstractRef (const db::DeviceAbstract *_device_abstract, const db::DCplxTrans &_trans)
: device_abstract (_device_abstract), trans (_trans)
{
// .. nothing yet ..
}
DeviceAbstractRef ()
: device_abstract (0), offset ()
: device_abstract (0), trans ()
{
// .. nothing yet ..
}
const db::DeviceAbstract *device_abstract;
db::DVector offset;
db::DCplxTrans trans;
};
/**
@ -212,19 +213,19 @@ public:
/**
* @brief Sets the device position
* The device position should be the center of the recognition shape or something similar.
* The device position should be the center and orientation of the recognition shape or something similar.
* Giving the device a position allows combining multiple devices with the same
* relative geometry into a single cell.
* The position has to be given in micrometer units.
* The transformation has to be given in micrometer units.
*/
void set_position (const db::DPoint &pos);
void set_trans (const db::DCplxTrans &tr);
/**
* @brief Gets the device position
*/
const db::DPoint &position () const
const db::DCplxTrans &trans () const
{
return m_position;
return m_trans;
}
/**
@ -355,7 +356,7 @@ private:
DeviceClass *mp_device_class;
DeviceAbstract *mp_device_abstract;
std::string m_name;
db::DPoint m_position;
db::DCplxTrans m_trans;
std::vector<Net::terminal_iterator> m_terminal_refs;
std::vector<double> m_parameters;
size_t m_id;

View File

@ -77,7 +77,8 @@ namespace db
*
* [combined-device]:
*
* device(<abstract> <dx> <dy>) - specifies an additional device component
* device(<abstract> [trans-def])
* - specifies an additional device component
* (for combined devices) with abstract <abstract>
* and offset dx, dy.
*
@ -113,7 +114,7 @@ namespace db
*
* [device-def]:
*
* location(<x> <y>) - location of the device [short key Y]
* [trans-def] - location of the device [short key Y]
* must be before terminal
* param(<name> <value>) - defines a parameter [short key E]
* terminal(<terminal-name> <net-id>)
@ -122,11 +123,15 @@ namespace db
*
* [subcircuit-def]:
*
* location(<x> <y>) - location of the subcircuit [short key Y]
* [trans-def] - location of the subcircuit [short key Y]
* pin(<pin-id> <net-id>) - specifies connection of the pin with a net [short key: P]
*
* [trans-def]:
*
* location(<x> <y>) - location of the instance [short key Y]
* rotation(<angle>) - rotation angle (in degree, default is 0) [short key O]
* mirror - if specified, the instance is mirrored before rotation [short key M]
* scale(<mag>) - magnification (default is 1) [short key S]
* pin(<pin-id> <net-id>) - specifies connection of the pin with a net [short key: P]
*/
namespace l2n_std_format

View File

@ -583,7 +583,8 @@ LayoutToNetlistStandardReader::read_device (db::Netlist *netlist, db::LayoutToNe
device->set_device_class (const_cast<db::DeviceClass *> (dm.second));
device->set_device_abstract (dm.first);
db::Coord x = 0, y = 0;
db::DCplxTrans trans;
db::CplxTrans dbu (m_dbu);
db::VCplxTrans dbu_inv (1.0 / m_dbu);
size_t max_tid = 0;
@ -596,29 +597,30 @@ LayoutToNetlistStandardReader::read_device (db::Netlist *netlist, db::LayoutToNe
read_word_or_quoted (name);
br_name.done ();
} else if (test (skeys::location_key) || test (lkeys::location_key)) {
} else if (read_trans_part (trans)) {
Brace br2 (this);
x = read_coord ();
y = read_coord ();
br2.done ();
// .. nothing yet ..
} else if (test (skeys::device_key) || test (lkeys::device_key)) {
std::string n;
db::DCplxTrans dm_trans;
Brace br2 (this);
read_word_or_quoted (n);
db::Coord dx = read_coord ();
db::Coord dy = read_coord ();
while (br2) {
if (! read_trans_part (dm_trans)) {
throw tl::Exception (tl::to_string (tr ("Invalid keyword inside device definition (location, scale, rotation or mirror expected)")));
}
}
br2.done ();
db::DeviceAbstract *da = device_model_by_name (netlist, n).first;
device->other_abstracts ().push_back (db::DeviceAbstractRef (da, db::DVector (m_dbu * dx, m_dbu * dy)));
device->other_abstracts ().push_back (db::DeviceAbstractRef (da, dm_trans));
} else if (test (skeys::connect_key) || test (lkeys::connect_key)) {
@ -691,7 +693,7 @@ LayoutToNetlistStandardReader::read_device (db::Netlist *netlist, db::LayoutToNe
device->set_parameter_value (pid, value);
} else {
throw tl::Exception (tl::to_string (tr ("Invalid keyword inside device definition (location, param or terminal expected)")));
throw tl::Exception (tl::to_string (tr ("Invalid keyword inside device definition (location, scale, mirror, rotation, param or terminal expected)")));
}
}
@ -702,7 +704,7 @@ LayoutToNetlistStandardReader::read_device (db::Netlist *netlist, db::LayoutToNe
map.id2device.insert (std::make_pair (id, device.get ()));
}
device->set_position (db::DPoint (m_dbu * x, m_dbu * y));
device->set_trans (trans);
device->set_name (name);
if (l2n && dm.first) {
@ -712,14 +714,14 @@ LayoutToNetlistStandardReader::read_device (db::Netlist *netlist, db::LayoutToNe
// make device cell instances
std::vector<db::CellInstArray> insts;
db::CellInstArray inst (db::CellInst (dm.first->cell_index ()), db::Trans (db::Vector (x, y)));
db::CellInstArray inst (db::CellInst (dm.first->cell_index ()), dbu_inv * trans * dbu);
ccell.insert (inst);
insts.push_back (inst);
const std::vector<db::DeviceAbstractRef> &other_devices = device->other_abstracts ();
for (std::vector<db::DeviceAbstractRef>::const_iterator i = other_devices.begin (); i != other_devices.end (); ++i) {
db::CellInstArray other_inst (db::CellInst (i->device_abstract->cell_index ()), db::Trans (db::Vector (x, y) + dbu_inv * i->offset));
db::CellInstArray other_inst (db::CellInst (i->device_abstract->cell_index ()), dbu_inv * trans * i->trans * dbu);
ccell.insert (other_inst);
insts.push_back (other_inst);
@ -764,6 +766,47 @@ LayoutToNetlistStandardReader::read_device (db::Netlist *netlist, db::LayoutToNe
circuit->add_device (device.release ());
}
bool
LayoutToNetlistStandardReader::read_trans_part (db::DCplxTrans &tr)
{
if (test (skeys::location_key) || test (lkeys::location_key)) {
Brace br2 (this);
db::Coord x = read_coord ();
db::Coord y = read_coord ();
br2.done ();
tr = db::DCplxTrans (tr.mag (), tr.angle (), tr.is_mirror (), db::DVector (m_dbu * x, m_dbu * y));
return true;
} else if (test (skeys::rotation_key) || test (lkeys::rotation_key)) {
Brace br2 (this);
double angle = read_double ();
br2.done ();
tr = db::DCplxTrans (tr.mag (), angle, tr.is_mirror (), tr.disp ());
return true;
} else if (test (skeys::mirror_key) || test (lkeys::mirror_key)) {
tr = db::DCplxTrans (tr.mag (), tr.angle (), true, tr.disp ());
return true;
} else if (test (skeys::scale_key) || test (lkeys::scale_key)) {
Brace br2 (this);
double mag = read_double ();
br2.done ();
tr = db::DCplxTrans (mag, tr.angle (), tr.is_mirror (), tr.disp ());
return true;
}
return false;
}
void
LayoutToNetlistStandardReader::read_subcircuit (db::Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, ObjectMap &map, std::map<db::CellInstArray, std::list<Connections> > &connections)
{
@ -785,12 +828,7 @@ LayoutToNetlistStandardReader::read_subcircuit (db::Netlist *netlist, db::Layout
std::auto_ptr<db::SubCircuit> subcircuit (new db::SubCircuit (circuit_ref));
db::Coord x = 0, y = 0;
bool mirror = false;
double angle = 0;
double mag = 1.0;
bool inst_made = false;
db::DCplxTrans trans;
while (br) {
@ -800,43 +838,9 @@ LayoutToNetlistStandardReader::read_subcircuit (db::Netlist *netlist, db::Layout
read_word_or_quoted (name);
br_name.done ();
} else if (test (skeys::location_key) || test (lkeys::location_key)) {
} else if (read_trans_part (trans)) {
Brace br2 (this);
x = read_coord ();
y = read_coord ();
br2.done ();
if (inst_made) {
throw tl::Exception (tl::to_string (tr ("location key must come before pin key in subcircuit definition")));
}
} else if (test (skeys::rotation_key) || test (lkeys::rotation_key)) {
Brace br2 (this);
angle = read_double ();
br2.done ();
if (inst_made) {
throw tl::Exception (tl::to_string (tr ("rotation key must come before pin key in subcircuit definition")));
}
} else if (test (skeys::mirror_key) || test (lkeys::mirror_key)) {
mirror = true;
if (inst_made) {
throw tl::Exception (tl::to_string (tr ("mirror key must come before pin key in subcircuit definition")));
}
} else if (test (skeys::scale_key) || test (lkeys::scale_key)) {
Brace br2 (this);
mag = read_double ();
br2.done ();
if (inst_made) {
throw tl::Exception (tl::to_string (tr ("scale key must come before pin key in subcircuit definition")));
}
// .. nothing yet ..
} else if (test (skeys::pin_key) || test (lkeys::pin_key)) {
@ -879,9 +883,9 @@ LayoutToNetlistStandardReader::read_subcircuit (db::Netlist *netlist, db::Layout
if (l2n) {
subcircuit->set_trans (db::DCplxTrans (mag, angle, mirror, db::DVector (m_dbu * x, m_dbu * y)));
subcircuit->set_trans (trans);
db::CellInstArray inst (db::CellInst (circuit_ref->cell_index ()), db::ICplxTrans (mag, angle, mirror, db::Vector (x, y)));
db::CellInstArray inst (db::CellInst (circuit_ref->cell_index ()), db::CplxTrans (m_dbu).inverted () * trans * db::CplxTrans (m_dbu));
db::Cell &ccell = l2n->internal_layout ()->cell (circuit->cell_index ());
ccell.insert (inst);

View File

@ -136,6 +136,7 @@ protected:
void read_pin (Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, ObjectMap &map);
void read_device (Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, ObjectMap &map, std::map<db::CellInstArray, std::list<Connections> > &connections);
void read_subcircuit (Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, ObjectMap &map, std::map<db::CellInstArray, std::list<Connections> > &connections);
bool read_trans_part (db::DCplxTrans &tr);
void read_abstract_terminal (db::LayoutToNetlist *l2n, db::DeviceAbstract *dm, db::DeviceClass *dc);
std::pair<unsigned int, db::PolygonRef> read_geometry (db::LayoutToNetlist *l2n);
void read_geometries (Brace &br, db::LayoutToNetlist *l2n, db::local_cluster<db::PolygonRef> &lc, db::Cell &cell);

View File

@ -418,19 +418,8 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Sub
}
if (l2n) {
const db::DCplxTrans &tr = subcircuit.trans ();
if (tr.is_mag ()) {
*mp_stream << " " << Keys::scale_key << "(" << tr.mag () << ")";
}
if (tr.is_mirror ()) {
*mp_stream << " " << Keys::mirror_key;
}
if (fabs (tr.angle ()) > 1e-6) {
*mp_stream << " " << Keys::rotation_key << "(" << tr.angle () << ")";
}
*mp_stream << " " << Keys::location_key << "(" << tr.disp ().x () / m_dbu << " " << tr.disp ().y () / m_dbu << ")";
*mp_stream << " ";
write (subcircuit.trans ());
}
// each pin in one line for more than a few pins
@ -478,7 +467,13 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Dev
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
const db::local_cluster<db::PolygonRef> &lc = clusters.clusters_per_cell (device_abstract.cell_index ()).cluster_by_id (device_abstract.cluster_id_for_terminal (t->id ()));
size_t cid = device_abstract.cluster_id_for_terminal (t->id ());
if (cid == 0) {
// no geometry
continue;
}
const db::local_cluster<db::PolygonRef> &lc = clusters.clusters_per_cell (device_abstract.cell_index ()).cluster_by_id (cid);
for (db::local_cluster<db::PolygonRef>::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) {
*mp_stream << indent << indent2;
@ -494,11 +489,41 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Dev
}
}
template <class Keys>
void std_writer_impl<Keys>::write (const db::DCplxTrans &tr)
{
bool first = true;
if (tr.is_mag ()) {
*mp_stream << Keys::scale_key << "(" << tr.mag () << ")";
first = false;
}
if (tr.is_mirror ()) {
if (! first) {
*mp_stream << " ";
}
*mp_stream << Keys::mirror_key;
first = false;
}
if (fabs (tr.angle ()) > 1e-6) {
if (! first) {
*mp_stream << " ";
}
*mp_stream << Keys::rotation_key << "(" << tr.angle () << ")";
first = false;
}
if (! first) {
*mp_stream << " ";
}
*mp_stream << Keys::location_key << "(" << tr.disp ().x () / m_dbu << " " << tr.disp ().y () / m_dbu << ")";
}
template <class Keys>
void std_writer_impl<Keys>::write (const db::LayoutToNetlist * /*l2n*/, const db::Device &device, std::map<const Net *, unsigned int> &net2id, const std::string &indent)
{
db::VCplxTrans dbu_inv (1.0 / m_dbu);
tl_assert (device.device_class () != 0);
const std::vector<DeviceTerminalDefinition> &td = device.device_class ()->terminal_definitions ();
const std::vector<DeviceParameterDefinition> &pd = device.device_class ()->parameter_definitions ();
@ -512,9 +537,9 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist * /*l2n*/, const db
const std::vector<db::DeviceAbstractRef> &other_abstracts = device.other_abstracts ();
for (std::vector<db::DeviceAbstractRef>::const_iterator a = other_abstracts.begin (); a != other_abstracts.end (); ++a) {
db::Vector pos = dbu_inv * a->offset;
*mp_stream << indent << indent2 << Keys::device_key << "(" << tl::to_word_or_quoted_string (a->device_abstract->name ()) << " " << pos.x () << " " << pos.y () << ")" << endl;
*mp_stream << indent << indent2 << Keys::device_key << "(" << tl::to_word_or_quoted_string (a->device_abstract->name ()) << " ";
write (a->trans);
*mp_stream << ")" << endl;
}
@ -527,8 +552,9 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist * /*l2n*/, const db
}
db::Point pos = dbu_inv * device.position ();
*mp_stream << indent << indent2 << Keys::location_key << "(" << pos.x () << " " << pos.y () << ")" << endl;
*mp_stream << indent << indent2;
write (device.trans ());
*mp_stream << endl;
} else {
*mp_stream << " " << tl::to_word_or_quoted_string (device.device_class ()->name ()) << endl;
@ -539,7 +565,7 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist * /*l2n*/, const db
}
for (std::vector<DeviceParameterDefinition>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
*mp_stream << indent << indent2 << Keys::param_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << device.parameter_value (i->id ()) << ")" << endl;
*mp_stream << indent << indent2 << Keys::param_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << tl::sprintf ("%.12g", device.parameter_value (i->id ())) << ")" << endl;
}
for (std::vector<DeviceTerminalDefinition>::const_iterator i = td.begin (); i != td.end (); ++i) {

View File

@ -59,6 +59,7 @@ protected:
void write (const db::LayoutToNetlist *l2n, const db::Device &device, std::map<const Net *, unsigned int> &net2id, const std::string &indent);
void write (const db::LayoutToNetlist *l2n, const db::DeviceAbstract &device_abstract, const std::string &indent);
void write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname, bool relative);
void write (const db::DCplxTrans &trans);
void reset_geometry_ref ();
tl::OutputStream &stream ()

View File

@ -96,6 +96,8 @@ bool DeviceClassTwoTerminalDevice::combine_devices (Device *a, Device *b) const
// DeviceClassResistor implementation
DB_PUBLIC size_t DeviceClassResistor::param_id_R = 0;
DB_PUBLIC size_t DeviceClassResistor::param_id_A = 1;
DB_PUBLIC size_t DeviceClassResistor::param_id_P = 2;
DB_PUBLIC size_t DeviceClassResistor::terminal_id_A = 0;
DB_PUBLIC size_t DeviceClassResistor::terminal_id_B = 1;
@ -106,6 +108,8 @@ DeviceClassResistor::DeviceClassResistor ()
add_terminal_definition (db::DeviceTerminalDefinition ("B", "Terminal B"));
add_parameter_definition (db::DeviceParameterDefinition ("R", "Resistance (Ohm)", 0.0));
add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0));
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0));
}
void DeviceClassResistor::parallel (Device *a, Device *b) const
@ -113,6 +117,16 @@ void DeviceClassResistor::parallel (Device *a, Device *b) const
double va = a->parameter_value (0);
double vb = b->parameter_value (0);
a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb));
// TODO: does this implementation make sense?
double aa = a->parameter_value (1);
double ab = b->parameter_value (1);
a->set_parameter_value (1, aa + ab);
// TODO: does this implementation make sense?
double pa = a->parameter_value (2);
double pb = b->parameter_value (2);
a->set_parameter_value (2, pa + pb);
}
void DeviceClassResistor::serial (Device *a, Device *b) const
@ -120,12 +134,22 @@ void DeviceClassResistor::serial (Device *a, Device *b) const
double va = a->parameter_value (0);
double vb = b->parameter_value (0);
a->set_parameter_value (0, va + vb);
double aa = a->parameter_value (1);
double ab = b->parameter_value (1);
a->set_parameter_value (1, aa + ab);
double pa = a->parameter_value (2);
double pb = b->parameter_value (2);
a->set_parameter_value (2, pa + pb);
}
// ------------------------------------------------------------------------------------
// DeviceClassCapacitor implementation
DB_PUBLIC size_t DeviceClassCapacitor::param_id_C = 0;
DB_PUBLIC size_t DeviceClassCapacitor::param_id_A = 1;
DB_PUBLIC size_t DeviceClassCapacitor::param_id_P = 2;
DB_PUBLIC size_t DeviceClassCapacitor::terminal_id_A = 0;
DB_PUBLIC size_t DeviceClassCapacitor::terminal_id_B = 1;
@ -136,6 +160,8 @@ DeviceClassCapacitor::DeviceClassCapacitor ()
add_terminal_definition (db::DeviceTerminalDefinition ("B", "Terminal B"));
add_parameter_definition (db::DeviceParameterDefinition ("C", "Capacitance (Farad)", 0.0));
add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0));
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0));
}
void DeviceClassCapacitor::serial (Device *a, Device *b) const
@ -143,6 +169,16 @@ void DeviceClassCapacitor::serial (Device *a, Device *b) const
double va = a->parameter_value (0);
double vb = b->parameter_value (0);
a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb));
// TODO: does this implementation make sense?
double aa = a->parameter_value (1);
double ab = b->parameter_value (1);
a->set_parameter_value (1, aa + ab);
// TODO: does this implementation make sense?
double pa = a->parameter_value (2);
double pb = b->parameter_value (2);
a->set_parameter_value (2, pa + pb);
}
void DeviceClassCapacitor::parallel (Device *a, Device *b) const
@ -150,6 +186,14 @@ void DeviceClassCapacitor::parallel (Device *a, Device *b) const
double va = a->parameter_value (0);
double vb = b->parameter_value (0);
a->set_parameter_value (0, va + vb);
double aa = a->parameter_value (1);
double ab = b->parameter_value (1);
a->set_parameter_value (1, aa + ab);
double pa = a->parameter_value (2);
double pb = b->parameter_value (2);
a->set_parameter_value (2, pa + pb);
}
// ------------------------------------------------------------------------------------

View File

@ -61,6 +61,8 @@ public:
}
static size_t param_id_R;
static size_t param_id_A;
static size_t param_id_P;
static size_t terminal_id_A;
static size_t terminal_id_B;
@ -91,6 +93,8 @@ public:
}
static size_t param_id_C;
static size_t param_id_A;
static size_t param_id_P;
static size_t terminal_id_A;
static size_t terminal_id_B;

View File

@ -132,9 +132,30 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layo
for (layer_definitions::const_iterator ld = begin_layer_definitions (); ld != end_layer_definitions (); ++ld) {
input_layers::const_iterator l = layer_map.find (ld->name);
size_t ld_index = ld->index;
input_layers::const_iterator l = layer_map.find (m_layer_definitions [ld_index].name);
while (l == layer_map.end () && m_layer_definitions [ld_index].fallback_index < m_layer_definitions.size ()) {
// try fallback layer
ld_index = m_layer_definitions [ld_index].fallback_index;
l = layer_map.find (m_layer_definitions [ld_index].name);
}
if (l == layer_map.end ()) {
throw tl::Exception (tl::to_string (tr ("Missing input layer for device extraction: ")) + ld->name);
// gets the layer names for the error message
std::string layer_names = m_layer_definitions [ld_index].name;
ld_index = ld->index;
l = layer_map.find (m_layer_definitions [ld_index].name);
while (l == layer_map.end () && m_layer_definitions [ld_index].fallback_index < m_layer_definitions.size ()) {
ld_index = m_layer_definitions [ld_index].fallback_index;
std::string ln = m_layer_definitions [ld_index].name;
layer_names += "/";
layer_names += ln;
l = layer_map.find (ln);
}
throw tl::Exception (tl::to_string (tr ("Missing input layer for device extraction: ")) + layer_names);
}
tl_assert (l->second != 0);
@ -339,8 +360,8 @@ void NetlistDeviceExtractor::push_new_devices (const db::Vector &disp_cache)
db::Device *device = d->second.first;
db::Vector disp = dbu_inv * device->position () - db::Point ();
device->set_position (device->position () + dbu * disp_cache);
db::Vector disp = dbu_inv * device->trans ().disp ();
device->set_trans (db::DCplxTrans (device->trans ().disp () + dbu * disp_cache));
DeviceCellKey key;
@ -426,11 +447,11 @@ void NetlistDeviceExtractor::push_cached_devices (const tl::vector<db::Device *>
for (std::vector<db::Device *>::const_iterator d = cached_devices.begin (); d != cached_devices.end (); ++d) {
db::Device *cached_device = *d;
db::Vector disp = dbu_inv * cached_device->position () - disp_cache - db::Point ();
db::Vector disp = dbu_inv * cached_device->trans ().disp () - disp_cache;
db::Device *device = new db::Device (*cached_device);
mp_circuit->add_device (device);
device->set_position (device->position () + dbu * (new_disp - disp_cache));
device->set_trans (db::DCplxTrans (device->trans ().disp () + dbu * (new_disp - disp_cache)));
// Build a property set for the device ID
ps.clear ();
@ -476,9 +497,16 @@ void NetlistDeviceExtractor::register_device_class (DeviceClass *device_class)
m_netlist->add_device_class (device_class);
}
void NetlistDeviceExtractor::define_layer (const std::string &name, const std::string &description)
const db::NetlistDeviceExtractorLayerDefinition &NetlistDeviceExtractor::define_layer (const std::string &name, const std::string &description)
{
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 (), std::numeric_limits<size_t>::max ()));
return m_layer_definitions.back ();
}
const db::NetlistDeviceExtractorLayerDefinition &NetlistDeviceExtractor::define_layer (const std::string &name, size_t fallback, const std::string &description)
{
m_layer_definitions.push_back (db::NetlistDeviceExtractorLayerDefinition (name, description, m_layer_definitions.size (), fallback));
return m_layer_definitions.back ();
}
Device *NetlistDeviceExtractor::create_device ()

View File

@ -162,8 +162,8 @@ public:
// .. nothing yet ..
}
NetlistDeviceExtractorLayerDefinition (const std::string &_name, const std::string &_description, size_t _index)
: name (_name), description (_description), index (_index)
NetlistDeviceExtractorLayerDefinition (const std::string &_name, const std::string &_description, size_t _index, size_t _fallback_index)
: name (_name), description (_description), index (_index), fallback_index (_fallback_index)
{
// .. nothing yet ..
}
@ -182,6 +182,12 @@ public:
* @brief The index of the layer
*/
size_t index;
/**
* @brief The index of the fallback layer
* This is the layer to be used when this layer isn't specified for input or (more important) output
*/
size_t fallback_index;
};
/**
@ -366,7 +372,14 @@ public:
* the device layers. The actual geometries are later available to "extract_devices"
* in the order the layers are defined.
*/
void define_layer (const std::string &name, const std::string &description = std::string ());
const db::NetlistDeviceExtractorLayerDefinition &define_layer (const std::string &name, const std::string &description = std::string ());
/**
* @brief Defines a layer with a fallback layer
* Like "define_layer" without fallback layer, but will fall back to the given layer
* (by index) if this layer isn't specified for input or terminal markup.
*/
const db::NetlistDeviceExtractorLayerDefinition &define_layer (const std::string &name, size_t fallback, const std::string &description = std::string ());
/**
* @brief Creates a device

View File

@ -38,9 +38,15 @@ NetlistDeviceExtractorMOS3Transistor::NetlistDeviceExtractorMOS3Transistor (cons
void NetlistDeviceExtractorMOS3Transistor::setup ()
{
define_layer ("SD", "Source/drain diffusion");
define_layer ("G", "Gate");
define_layer ("P", "Poly");
define_layer ("SD", "Source/drain diffusion"); // #0
define_layer ("G", "Gate input"); // #1
// for backward compatibility
define_layer ("P", 1, "Gate terminal output"); // #2
// terminal output
define_layer ("tG", 2, "Gate terminal output"); // #3
define_layer ("tS", 0, "Source terminal output (default is SD)"); // #4
define_layer ("tD", 0, "Drain terminal output (default is SD)"); // #5
register_device_class (new db::DeviceClassMOS3Transistor ());
}
@ -66,8 +72,14 @@ db::Connectivity NetlistDeviceExtractorMOS3Transistor::get_connectivity (const d
void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector<db::Region> &layer_geometry)
{
const db::Region &rdiff = layer_geometry [0];
const db::Region &rgates = layer_geometry [1];
unsigned int diff_geometry_index = 0;
unsigned int gate_geometry_index = 1;
unsigned int gate_terminal_geometry_index = 3;
unsigned int source_terminal_geometry_index = 4;
unsigned int drain_terminal_geometry_index = 5;
const db::Region &rdiff = layer_geometry [diff_geometry_index];
const db::Region &rgates = layer_geometry [gate_geometry_index];
for (db::Region::const_iterator p = rgates.begin_merged (); !p.at_end (); ++p) {
@ -81,11 +93,8 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector<db
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);
error (tl::sprintf (tl::to_string (tr ("Expected two polygons on diff interacting with one gate shape (found %d) - gate shape ignored")), int (rdiff2gate.size ())), *p);
continue;
}
@ -101,7 +110,7 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector<db
db::Device *device = create_device ();
device->set_position (db::CplxTrans (dbu ()) * p->box ().center ());
device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ()));
device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, dbu () * edges.length () * 0.5);
device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, dbu () * (p->perimeter () - edges.length ()) * 0.5);
@ -117,11 +126,12 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector<db
device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_AS : db::DeviceClassMOS3Transistor::param_id_AD, dbu () * dbu () * d->area () / double (n));
device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_PS : db::DeviceClassMOS3Transistor::param_id_PD, dbu () * d->perimeter () / double (n));
define_terminal (device, diff_index == 0 ? db::DeviceClassMOS3Transistor::terminal_id_S : db::DeviceClassMOS3Transistor::terminal_id_D, terminal_geometry_index, *d);
unsigned int sd_index = diff_index == 0 ? source_terminal_geometry_index : drain_terminal_geometry_index;
define_terminal (device, diff_index == 0 ? db::DeviceClassMOS3Transistor::terminal_id_S : db::DeviceClassMOS3Transistor::terminal_id_D, sd_index, *d);
}
define_terminal (device, db::DeviceClassMOS3Transistor::terminal_id_G, gate_geometry_index, *p);
define_terminal (device, db::DeviceClassMOS3Transistor::terminal_id_G, gate_terminal_geometry_index, *p);
// allow derived classes to modify the device
modify_device (*p, layer_geometry, device);
@ -145,18 +155,204 @@ NetlistDeviceExtractorMOS4Transistor::NetlistDeviceExtractorMOS4Transistor (cons
void NetlistDeviceExtractorMOS4Transistor::setup ()
{
define_layer ("SD", "Source/drain diffusion");
define_layer ("G", "Gate");
define_layer ("P", "Poly");
define_layer ("W", "Well");
define_layer ("SD", "Source/drain diffusion"); // #0
define_layer ("G", "Gate input"); // #1
// for backward compatibility
define_layer ("P", 1, "Gate terminal output"); // #2
// terminal output
define_layer ("tG", 1, "Gate terminal output"); // #3
define_layer ("tS", 0, "Source terminal output (default is SD)"); // #4
define_layer ("tD", 0, "Drain terminal output (default is SD)"); // #5
// for backward compatibility
define_layer ("W", "Well (bulk) terminal output"); // #6
define_layer ("tB", 6, "Well (bulk) terminal output"); // #7
register_device_class (new db::DeviceClassMOS4Transistor ());
}
void NetlistDeviceExtractorMOS4Transistor::modify_device (const db::Polygon &rgate, const std::vector<db::Region> & /*layer_geometry*/, db::Device *device)
{
unsigned int well_geometry_index = 3;
define_terminal (device, db::DeviceClassMOS4Transistor::terminal_id_B, well_geometry_index, rgate);
unsigned int bulk_terminal_geometry_index = 4;
define_terminal (device, db::DeviceClassMOS4Transistor::terminal_id_B, bulk_terminal_geometry_index, rgate);
}
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorResistor implementation
NetlistDeviceExtractorResistor::NetlistDeviceExtractorResistor (const std::string &name, double sheet_rho)
: db::NetlistDeviceExtractor (name), m_sheet_rho (sheet_rho)
{
// .. nothing yet ..
}
void NetlistDeviceExtractorResistor::setup ()
{
define_layer ("R", "Resistor");
define_layer ("C", "Contacts");
define_layer ("tA", 1, "A terminal output");
define_layer ("tB", 1, "B terminal output");
register_device_class (new db::DeviceClassResistor ());
}
db::Connectivity NetlistDeviceExtractorResistor::get_connectivity (const db::Layout & /*layout*/, const std::vector<unsigned int> &layers) const
{
tl_assert (layers.size () >= 2);
unsigned int res = layers [0];
unsigned int contact = layers [1];
// The layer definition is res, contact
db::Connectivity conn;
// collect all connected resistor shapes
conn.connect (res, res);
// connect res with contact for the contact shapes
conn.connect (res, contact);
return conn;
}
void NetlistDeviceExtractorResistor::extract_devices (const std::vector<db::Region> &layer_geometry)
{
size_t res_geometry_index = 0;
size_t contacts_geometry_index = 1;
size_t a_terminal_geometry_index = 2;
size_t b_terminal_geometry_index = 3;
const db::Region &res = layer_geometry [res_geometry_index];
const db::Region &contact = layer_geometry [contacts_geometry_index];
db::Region res_merged (res);
res_merged.set_base_verbosity (res.base_verbosity ());
db::Region contact_wo_res (contact);
contact_wo_res.set_base_verbosity (contact.base_verbosity ());
contact_wo_res -= res;
for (db::Region::const_iterator p = res_merged.begin_merged (); !p.at_end (); ++p) {
db::Region rres (*p);
db::Region contacts_per_res = contact_wo_res.selected_interacting (rres);
if (contacts_per_res.size () != 2) {
error (tl::sprintf (tl::to_string (tr ("Expected two polygons on contacts interacting with one resistor shape (found %d) - resistor shape ignored")), int (contacts_per_res.size ())), *p);
continue;
}
db::Device *device = create_device ();
device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ()));
// TODO: this is a very rough approximation for the general case - it assumes a "good" geometry
db::Edges eparallel = rres.edges ();
eparallel -= contacts_per_res.edges ();
db::Edges eperp = rres.edges ();
eperp &= contacts_per_res.edges ();
db::Coord length = eparallel.length ();
db::Coord width = eperp.length ();
if (width < 1) {
error (tl::to_string (tr ("Invalid contact geometry - resistor shape ignored")), *p);
continue;
}
device->set_parameter_value (db::DeviceClassResistor::param_id_R, m_sheet_rho * double (length) / double (width));
device->set_parameter_value (db::DeviceClassResistor::param_id_A, dbu () * dbu () * p->area ());
device->set_parameter_value (db::DeviceClassResistor::param_id_P, dbu () * p->perimeter ());
int cont_index = 0;
for (db::Region::const_iterator d = contacts_per_res.begin (); !d.at_end () && cont_index < 2; ++d, ++cont_index) {
size_t terminal_geometry_index = cont_index == 0 ? a_terminal_geometry_index : b_terminal_geometry_index;
define_terminal (device, cont_index == 0 ? db::DeviceClassResistor::terminal_id_A : db::DeviceClassResistor::terminal_id_B, terminal_geometry_index, *d);
}
// allow derived classes to modify the device
modify_device (*p, layer_geometry, device);
// output the device for debugging
device_out (device, rres, contacts_per_res);
}
}
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorCapacitor implementation
NetlistDeviceExtractorCapacitor::NetlistDeviceExtractorCapacitor (const std::string &name, double area_cap)
: db::NetlistDeviceExtractor (name), m_area_cap (area_cap)
{
// .. nothing yet ..
}
void NetlistDeviceExtractorCapacitor::setup ()
{
define_layer ("P1", "Plate 1");
define_layer ("P2", "Plate 2");
define_layer ("tA", 0, "A terminal output");
define_layer ("tB", 1, "B terminal output");
register_device_class (new db::DeviceClassCapacitor ());
}
db::Connectivity NetlistDeviceExtractorCapacitor::get_connectivity (const db::Layout & /*layout*/, const std::vector<unsigned int> &layers) const
{
tl_assert (layers.size () >= 2);
unsigned int plate1 = layers [0];
unsigned int plate2 = layers [1];
// The layer definition is plate1, plate2
db::Connectivity conn;
// collect all connected plate 1 shapes
conn.connect (plate1, plate1);
// collect all connected plate 1 shapes
conn.connect (plate2, plate2);
// connect the plates (NOTE that this is a logical, not a physical connection)
conn.connect (plate1, plate2);
return conn;
}
void NetlistDeviceExtractorCapacitor::extract_devices (const std::vector<db::Region> &layer_geometry)
{
size_t plate1_geometry_index = 0;
size_t plate2_geometry_index = 1;
size_t a_terminal_geometry_index = 2;
size_t b_terminal_geometry_index = 3;
const db::Region &plate1 = layer_geometry [plate1_geometry_index];
const db::Region &plate2 = layer_geometry [plate2_geometry_index];
db::Region overlap (plate1);
overlap.set_base_verbosity (plate1.base_verbosity ());
overlap &= plate2;
for (db::Region::const_iterator p = overlap.begin_merged (); !p.at_end (); ++p) {
db::Device *device = create_device ();
device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ()));
double area = p->area () * dbu () * dbu ();
device->set_parameter_value (db::DeviceClassCapacitor::param_id_C, m_area_cap * area);
device->set_parameter_value (db::DeviceClassCapacitor::param_id_A, area);
device->set_parameter_value (db::DeviceClassCapacitor::param_id_P, dbu () * p->perimeter ());
define_terminal (device, db::DeviceClassCapacitor::terminal_id_A, a_terminal_geometry_index, *p);
define_terminal (device, db::DeviceClassCapacitor::terminal_id_B, b_terminal_geometry_index, *p);
// allow derived classes to modify the device
modify_device (*p, layer_geometry, device);
// output the device for debugging
device_out (device, db::Region (*p));
}
}
}

View File

@ -95,6 +95,101 @@ private:
virtual void modify_device (const db::Polygon &rgate, const std::vector<db::Region> &layer_geometry, db::Device *device);
};
/**
* @brief A device extractor for a two-terminal resistor
*
* This class supplies the generic extractor for an resistor
* The resistor is defined by a "wire" with two connectors on
* each side.
*
* The resistance is computed from the width (W) and length (L) of the
* wire by R = L / W * sheet_rho.
*
* The device class produced by this extractor is DeviceClassResistor.
* The extractor extracts the three parameters of this class: R, A and P.
* A is the area of the wire and P is the perimeter.
*/
class DB_PUBLIC NetlistDeviceExtractorResistor
: public db::NetlistDeviceExtractor
{
public:
NetlistDeviceExtractorResistor (const std::string &name, double sheet_rho);
virtual void setup ();
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);
protected:
/**
* @brief A callback when the device is produced
* This callback is provided as a debugging port
*/
virtual void device_out (const db::Device * /*device*/, const db::Region & /*res*/, const db::Region & /*contacts*/)
{
// .. no specific implementation ..
}
/**
* @brief Allow derived classes to modify the device
*/
virtual void modify_device (const db::Polygon & /*res*/, const std::vector<db::Region> & /*layer_geometry*/, db::Device * /*device*/)
{
// .. no specific implementation ..
}
private:
double m_sheet_rho;
};
/**
* @brief A device extractor for a planar capacitor
*
* This class supplies the generic extractor for a planar capacitor.
* The capacitor is defined by two layers whose overlap area forms
* the capacitor.
*
* The resistance is computed from the area (A) of the overlapping region
* by C = A * area_cap.
*
* The device class produced by this extractor is DeviceClassCapacitor.
* The extractor extracts the three parameters of this class: C, A and P.
* A is the area of the overlap area and P is the perimeter.
*
* The layers are P1 and P2 for the plates. A and B are layers where
* the terminals for A and B are produced respectively.
*/
class DB_PUBLIC NetlistDeviceExtractorCapacitor
: public db::NetlistDeviceExtractor
{
public:
NetlistDeviceExtractorCapacitor (const std::string &name, double area_cap);
virtual void setup ();
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);
protected:
/**
* @brief A callback when the device is produced
* This callback is provided as a debugging port
*/
virtual void device_out (const db::Device * /*device*/, const db::Region & /*cap_area*/)
{
// .. no specific implementation ..
}
/**
* @brief Allow derived classes to modify the device
*/
virtual void modify_device (const db::Polygon & /*cap_area*/, const std::vector<db::Region> & /*layer_geometry*/, db::Device * /*device*/)
{
// .. no specific implementation ..
}
private:
double m_area_cap;
};
}
namespace tl
@ -112,6 +207,18 @@ template<> struct type_traits<db::NetlistDeviceExtractorMOS4Transistor> : public
typedef tl::false_tag has_default_constructor;
};
template<> struct type_traits<db::NetlistDeviceExtractorCapacitor> : public tl::type_traits<void>
{
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
template<> struct type_traits<db::NetlistDeviceExtractorResistor> : public tl::type_traits<void>
{
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
}
#endif

View File

@ -396,7 +396,7 @@ void NetlistSpiceWriter::do_write (const std::string &description)
for (db::Circuit::const_device_iterator i = circuit.begin_devices (); i != circuit.end_devices (); ++i) {
// TODO: make this configurable?
std::string comment = "device instance " + i->expanded_name () + " " + i->position ().to_string () + " " + i->device_class ()->name ();
std::string comment = "device instance " + i->expanded_name () + " " + i->trans ().to_string () + " " + i->device_class ()->name ();
emit_comment (comment);
mp_delegate->write_device (*i);

View File

@ -129,14 +129,14 @@ static void set_device_abstract (db::DeviceAbstractRef *obj, const db::DeviceAbs
obj->device_abstract = device_abstract;
}
static db::DVector get_offset (const db::DeviceAbstractRef *obj)
static db::DCplxTrans get_trans (const db::DeviceAbstractRef *obj)
{
return obj->offset;
return obj->trans;
}
static void set_offset (db::DeviceAbstractRef *obj, const db::DVector &offset)
static void set_trans (db::DeviceAbstractRef *obj, const db::DCplxTrans &trans)
{
obj->offset = offset;
obj->trans = trans;
}
Class<db::DeviceAbstractRef> decl_dbDeviceAbstractRef ("db", "DeviceAbstractRef",
@ -148,19 +148,19 @@ Class<db::DeviceAbstractRef> decl_dbDeviceAbstractRef ("db", "DeviceAbstractRef"
"@brief The getter for the device abstract reference.\n"
"See the class description for details."
) +
gsi::method_ext ("offset=", &set_offset, gsi::arg ("offset"),
"@brief The setter for the offset.\n"
gsi::method_ext ("trans=", &set_trans, gsi::arg ("tr"),
"@brief The setter for the relative transformation of the instance.\n"
"See the class description for details."
) +
gsi::method_ext ("offset", &get_offset,
"@brief The getter for the offset.\n"
gsi::method_ext ("trans", &get_trans,
"@brief The getter for the relative transformation of the instance.\n"
"See the class description for details."
),
"@brief Describes an additional device abstract reference for combined devices.\n"
"Combined devices are implemented as a generalization of the device abstract concept in \\Device. For "
"combined devices, multiple \\DeviceAbstract references are present. This class describes such an "
"additional reference. A reference is a pointer to an abstract plus an offset by which the abstract "
"is shifted geometrically as compared to the first (initial) abstract.\n"
"additional reference. A reference is a pointer to an abstract plus a transformation by which the abstract "
"is transformed geometrically as compared to the first (initial) abstract.\n"
"\n"
"This class has been introduced in version 0.26.\n"
);

View File

@ -183,6 +183,11 @@ static size_t ld_index (const db::NetlistDeviceExtractorLayerDefinition *ld)
return ld->index;
}
static size_t ld_fallback_index (const db::NetlistDeviceExtractorLayerDefinition *ld)
{
return ld->fallback_index;
}
Class<db::NetlistDeviceExtractorLayerDefinition> decl_dbNetlistDeviceExtractorLayerDefinition ("db", "NetlistDeviceExtractorLayerDefinition",
gsi::method_ext ("name", &ld_name,
"@brief Gets the name of the layer.\n"
@ -192,6 +197,10 @@ Class<db::NetlistDeviceExtractorLayerDefinition> decl_dbNetlistDeviceExtractorLa
) +
gsi::method_ext ("index", &ld_index,
"@brief Gets the index of the layer.\n"
) +
gsi::method_ext ("fallback_index", &ld_fallback_index,
"@brief Gets the index of the fallback layer.\n"
"This is the index of the layer to be used when this layer isn't specified for input or (more important) output.\n"
),
"@brief Describes a layer used in the device extraction\n"
"This read-only structure is used to describe a layer in the device extraction.\n"
@ -267,13 +276,21 @@ Class<GenericDeviceExtractor> decl_GenericDeviceExtractor (decl_dbNetlistDeviceE
"This method shall be used inside the implementation of \\setup to register\n"
"the device classes.\n"
) +
gsi::method ("define_layer", &GenericDeviceExtractor::define_layer, gsi::arg ("name"), gsi::arg ("description"),
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"
) +
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 with a fallback layer.\n"
"@return The layer descriptor object created for this layer (use 'index' to get the layer's index)\n"
"This version of 'define_layer' allows specification of a fallback layer. If this particular layer is not given "
"when the device is extracted, the fallback layer will be used. The fallback layer is given by it's "
"index and must be defined before the layer using the fallback layer is defined."
) +
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"
@ -438,4 +455,55 @@ Class<db::NetlistDeviceExtractorMOS4Transistor> decl_NetlistDeviceExtractorMOS4T
"This class has been introduced in version 0.26."
);
db::NetlistDeviceExtractorResistor *make_res_extractor (const std::string &name, double sheet_rho)
{
return new db::NetlistDeviceExtractorResistor (name, sheet_rho);
}
Class<db::NetlistDeviceExtractorResistor> decl_NetlistDeviceExtractorResistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorResistor",
gsi::constructor ("new", &make_res_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"),
"@brief Creates a new device extractor with the given name."
),
"@brief A device extractor for a two-terminal resistor\n"
"\n"
"This class supplies the generic extractor for a resistor device.\n"
"The device is defined by two geometry layers: the resistor 'wire' and "
"two contacts per wire. The contacts should be attached to the ends "
"of the wire. The wire length and width is computed from the "
"edge lengths between the contacts and along the contacts respectively.\n"
"\n"
"This simple computation is precise only when the resistor shape is "
"a rectangle.\n"
"\n"
"Using the given sheet resistance, the resistance value is computed by "
"'R = L / W * sheet_rho'.\n"
"\n"
"This class is a closed one and methods cannot be reimplemented. To reimplement "
"specific methods, see \\DeviceExtractor.\n"
"\n"
"This class has been introduced in version 0.26."
);
db::NetlistDeviceExtractorCapacitor *make_cap_extractor (const std::string &name, double area_cap)
{
return new db::NetlistDeviceExtractorCapacitor (name, area_cap);
}
Class<db::NetlistDeviceExtractorCapacitor> decl_NetlistDeviceExtractorCapacitor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorCapacitor",
gsi::constructor ("new", &make_cap_extractor, gsi::arg ("name"), gsi::arg ("area_cap"),
"@brief Creates a new device extractor with the given name."
),
"@brief A device extractor for a two-terminal capacitor\n"
"\n"
"This class supplies the generic extractor for a capacitor device.\n"
"The device is defined by two geometry layers forming the 'plates' of the capacitor.\n"
"The capacitance is computed from the overlapping area of the plates "
"using 'C = A * area_cap' (area_cap is the capacitance per square micrometer area).\n"
"\n"
"This class is a closed one and methods cannot be reimplemented. To reimplement "
"specific methods, see \\DeviceExtractor.\n"
"\n"
"This class has been introduced in version 0.26."
);
}

View File

@ -737,6 +737,33 @@ static std::string str_from_names (const std::pair<const Obj *, const Obj *> &ob
return s;
}
static
std::string formatted_value (double v)
{
double va = fabs (v);
if (va < 100e-15) {
return tl::to_string (v * 1e15) + "f";
} else if (va < 100e-12) {
return tl::to_string (v * 1e12) + "p";
} else if (va < 100e-9) {
return tl::to_string (v * 1e9) + "n";
} else if (va < 100e-6) {
return tl::to_string (v * 1e6) + "µ";
} else if (va < 100e-3) {
return tl::to_string (v * 1e3) + "m";
} else if (va < 100.0) {
return tl::to_string (v);
} else if (va < 100e3) {
return tl::to_string (v * 1e-3) + "k";
} else if (va < 100e6) {
return tl::to_string (v * 1e-6) + "M";
} else if (va < 100e9) {
return tl::to_string (v * 1e-9) + "G";
} else {
return tl::to_string (v);
}
}
static
std::string device_string (const db::Device *device)
{
@ -757,8 +784,7 @@ std::string device_string (const db::Device *device)
}
s += p->name ();
s += "=";
double v = device->parameter_value (p->id ());
s += tl::to_string (v);
s += formatted_value (device->parameter_value (p->id ()));
}
}
s += "]";

View File

@ -713,14 +713,13 @@ NetlistBrowserPage::enable_updates (bool f)
}
static db::Box
bbox_for_device_abstract (const db::Layout *layout, const db::DeviceAbstract *device_abstract, const db::DVector &offset)
bbox_for_device_abstract (const db::Layout *layout, const db::DeviceAbstract *device_abstract, const db::DCplxTrans &trans)
{
if (! device_abstract || ! layout->is_valid_cell_index (device_abstract->cell_index ())) {
return db::Box ();
}
return layout->cell (device_abstract->cell_index ()).bbox ().moved (db::VCplxTrans (1.0 / layout->dbu ()) * offset);
}
return layout->cell (device_abstract->cell_index ()).bbox ().transformed (db::CplxTrans (layout->dbu ()).inverted () * trans * db::CplxTrans (layout->dbu ()));}
static db::Box
bbox_for_subcircuit (const db::Layout *layout, const db::SubCircuit *subcircuit)
@ -782,11 +781,11 @@ NetlistBrowserPage::adjust_view ()
db::ICplxTrans trans = trans_for (*device, *mp_database->internal_layout (), *mp_database->internal_top_cell (), m_cell_context_cache);
bbox += trans * bbox_for_device_abstract (layout, (*device)->device_abstract (), db::DVector ());
bbox += trans * bbox_for_device_abstract (layout, (*device)->device_abstract (), db::DCplxTrans ());
const std::vector<db::DeviceAbstractRef> &oda = (*device)->other_abstracts ();
for (std::vector<db::DeviceAbstractRef>::const_iterator a = oda.begin (); a != oda.end (); ++a) {
bbox += trans * bbox_for_device_abstract (layout, a->device_abstract, a->offset);
bbox += trans * bbox_for_device_abstract (layout, a->device_abstract, a->trans);
}
}
@ -841,11 +840,11 @@ NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, siz
{
const db::Layout *layout = mp_database->internal_layout ();
const db::Cell *cell = mp_database->internal_top_cell ();
db::ICplxTrans device_trans = trans_for (device, *layout, *cell, m_cell_context_cache, db::DCplxTrans (device->position () - db::DPoint ()));
db::ICplxTrans device_trans = trans_for (device, *layout, *cell, m_cell_context_cache, device->trans ());
QColor color = make_valid_color (m_colorizer.marker_color ());
db::Box device_bbox = bbox_for_device_abstract (layout, device->device_abstract (), db::DVector ());
db::Box device_bbox = bbox_for_device_abstract (layout, device->device_abstract (), db::DCplxTrans ());
if (! device_bbox.empty ()) {
if (n_markers == m_max_shape_count) {
@ -864,7 +863,7 @@ NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, siz
const std::vector<db::DeviceAbstractRef> &oda = device->other_abstracts ();
for (std::vector<db::DeviceAbstractRef>::const_iterator a = oda.begin (); a != oda.end (); ++a) {
db::Box da_box = bbox_for_device_abstract (layout, a->device_abstract, a->offset);
db::Box da_box = bbox_for_device_abstract (layout, a->device_abstract, a->trans);
if (! da_box.empty ()) {
if (n_markers == m_max_shape_count) {