From 9d01cb5282813b6383c16b6fb6099290907b3b4b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 29 May 2019 00:10:10 +0200 Subject: [PATCH] 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. --- src/db/db/dbCircuit.cc | 2 + src/db/db/dbDevice.cc | 10 +- src/db/db/dbDevice.h | 21 +- src/db/db/dbLayoutToNetlistFormatDefs.h | 13 +- src/db/db/dbLayoutToNetlistReader.cc | 118 ++++----- src/db/db/dbLayoutToNetlistReader.h | 1 + src/db/db/dbLayoutToNetlistWriter.cc | 70 ++++-- src/db/db/dbLayoutToNetlistWriter.h | 1 + src/db/db/dbNetlistDeviceClasses.cc | 44 ++++ src/db/db/dbNetlistDeviceClasses.h | 4 + src/db/db/dbNetlistDeviceExtractor.cc | 44 +++- src/db/db/dbNetlistDeviceExtractor.h | 19 +- src/db/db/dbNetlistDeviceExtractorClasses.cc | 232 ++++++++++++++++-- src/db/db/dbNetlistDeviceExtractorClasses.h | 107 ++++++++ src/db/db/dbNetlistSpiceWriter.cc | 2 +- src/db/db/gsiDeclDbNetlist.cc | 20 +- src/db/db/gsiDeclDbNetlistDeviceExtractor.cc | 70 +++++- .../laybasic/layNetlistBrowserModel.cc | 30 ++- .../laybasic/layNetlistBrowserPage.cc | 15 +- 19 files changed, 674 insertions(+), 149 deletions(-) diff --git a/src/db/db/dbCircuit.cc b/src/db/db/dbCircuit.cc index f72b68a5c..0460bad9a 100644 --- a/src/db/db/dbCircuit.cc +++ b/src/db/db/dbCircuit.cc @@ -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 &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 (); diff --git a/src/db/db/dbDevice.cc b/src/db/db/dbDevice.cc index 070dab7a3..ca950ad2e 100644 --- a/src/db/db/dbDevice.cc +++ b/src/db/db/dbDevice.cc @@ -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::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; } } diff --git a/src/db/db/dbDevice.h b/src/db/db/dbDevice.h index de0afc06f..7e6b8af3e 100644 --- a/src/db/db/dbDevice.h +++ b/src/db/db/dbDevice.h @@ -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 m_terminal_refs; std::vector m_parameters; size_t m_id; diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h index c346ae853..19fd221c5 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.h +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -77,7 +77,8 @@ namespace db * * [combined-device]: * - * device( ) - specifies an additional device component + * device( [trans-def]) + * - specifies an additional device component * (for combined devices) with abstract * and offset dx, dy. * @@ -113,7 +114,7 @@ namespace db * * [device-def]: * - * location( ) - location of the device [short key Y] + * [trans-def] - location of the device [short key Y] * must be before terminal * param( ) - defines a parameter [short key E] * terminal( ) @@ -122,11 +123,15 @@ namespace db * * [subcircuit-def]: * - * location( ) - location of the subcircuit [short key Y] + * [trans-def] - location of the subcircuit [short key Y] + * pin( ) - specifies connection of the pin with a net [short key: P] + * + * [trans-def]: + * + * location( ) - location of the instance [short key Y] * rotation() - rotation angle (in degree, default is 0) [short key O] * mirror - if specified, the instance is mirrored before rotation [short key M] * scale() - magnification (default is 1) [short key S] - * pin( ) - specifies connection of the pin with a net [short key: P] */ namespace l2n_std_format diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc index 67703481f..2eb975ab6 100644 --- a/src/db/db/dbLayoutToNetlistReader.cc +++ b/src/db/db/dbLayoutToNetlistReader.cc @@ -583,7 +583,8 @@ LayoutToNetlistStandardReader::read_device (db::Netlist *netlist, db::LayoutToNe device->set_device_class (const_cast (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 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 &other_devices = device->other_abstracts (); for (std::vector::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 > &connections) { @@ -785,12 +828,7 @@ LayoutToNetlistStandardReader::read_subcircuit (db::Netlist *netlist, db::Layout std::auto_ptr 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); diff --git a/src/db/db/dbLayoutToNetlistReader.h b/src/db/db/dbLayoutToNetlistReader.h index bae030949..0a161ac86 100644 --- a/src/db/db/dbLayoutToNetlistReader.h +++ b/src/db/db/dbLayoutToNetlistReader.h @@ -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 > &connections); void read_subcircuit (Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, ObjectMap &map, std::map > &connections); + bool read_trans_part (db::DCplxTrans &tr); void read_abstract_terminal (db::LayoutToNetlist *l2n, db::DeviceAbstract *dm, db::DeviceClass *dc); std::pair read_geometry (db::LayoutToNetlist *l2n); void read_geometries (Brace &br, db::LayoutToNetlist *l2n, db::local_cluster &lc, db::Cell &cell); diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index 13737d037..1e19c5cef 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -418,19 +418,8 @@ void std_writer_impl::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::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 &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 &lc = clusters.clusters_per_cell (device_abstract.cell_index ()).cluster_by_id (cid); for (db::local_cluster::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) { *mp_stream << indent << indent2; @@ -494,11 +489,41 @@ void std_writer_impl::write (const db::LayoutToNetlist *l2n, const db::Dev } } +template +void std_writer_impl::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 void std_writer_impl::write (const db::LayoutToNetlist * /*l2n*/, const db::Device &device, std::map &net2id, const std::string &indent) { - db::VCplxTrans dbu_inv (1.0 / m_dbu); - tl_assert (device.device_class () != 0); const std::vector &td = device.device_class ()->terminal_definitions (); const std::vector &pd = device.device_class ()->parameter_definitions (); @@ -512,9 +537,9 @@ void std_writer_impl::write (const db::LayoutToNetlist * /*l2n*/, const db const std::vector &other_abstracts = device.other_abstracts (); for (std::vector::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::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::write (const db::LayoutToNetlist * /*l2n*/, const db } for (std::vector::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::const_iterator i = td.begin (); i != td.end (); ++i) { diff --git a/src/db/db/dbLayoutToNetlistWriter.h b/src/db/db/dbLayoutToNetlistWriter.h index a7879916f..fd4df0bf4 100644 --- a/src/db/db/dbLayoutToNetlistWriter.h +++ b/src/db/db/dbLayoutToNetlistWriter.h @@ -59,6 +59,7 @@ protected: void write (const db::LayoutToNetlist *l2n, const db::Device &device, std::map &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 () diff --git a/src/db/db/dbNetlistDeviceClasses.cc b/src/db/db/dbNetlistDeviceClasses.cc index 09378dfdf..111ed30b0 100644 --- a/src/db/db/dbNetlistDeviceClasses.cc +++ b/src/db/db/dbNetlistDeviceClasses.cc @@ -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); } // ------------------------------------------------------------------------------------ diff --git a/src/db/db/dbNetlistDeviceClasses.h b/src/db/db/dbNetlistDeviceClasses.h index 7162cbfbf..57c43820f 100644 --- a/src/db/db/dbNetlistDeviceClasses.h +++ b/src/db/db/dbNetlistDeviceClasses.h @@ -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; diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index 77edf3b83..4d66c23eb 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -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 for (std::vector::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::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 () diff --git a/src/db/db/dbNetlistDeviceExtractor.h b/src/db/db/dbNetlistDeviceExtractor.h index ed82c0266..ecf68c2cf 100644 --- a/src/db/db/dbNetlistDeviceExtractor.h +++ b/src/db/db/dbNetlistDeviceExtractor.h @@ -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 diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.cc b/src/db/db/dbNetlistDeviceExtractorClasses.cc index 91a22c45e..16b18be72 100644 --- a/src/db/db/dbNetlistDeviceExtractorClasses.cc +++ b/src/db/db/dbNetlistDeviceExtractorClasses.cc @@ -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 &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::vectorset_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::vectorset_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 & /*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 &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 &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 &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 &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)); + + } } } diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.h b/src/db/db/dbNetlistDeviceExtractorClasses.h index 904bf37dd..42c669d77 100644 --- a/src/db/db/dbNetlistDeviceExtractorClasses.h +++ b/src/db/db/dbNetlistDeviceExtractorClasses.h @@ -95,6 +95,101 @@ private: virtual void modify_device (const db::Polygon &rgate, const std::vector &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 &layers) const; + virtual void extract_devices (const std::vector &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 & /*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 &layers) const; + virtual void extract_devices (const std::vector &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 & /*layer_geometry*/, db::Device * /*device*/) + { + // .. no specific implementation .. + } + +private: + double m_area_cap; +}; + } namespace tl @@ -112,6 +207,18 @@ template<> struct type_traits : public typedef tl::false_tag has_default_constructor; }; +template<> struct type_traits : public tl::type_traits +{ + typedef tl::false_tag has_copy_constructor; + typedef tl::false_tag has_default_constructor; +}; + +template<> struct type_traits : public tl::type_traits +{ + typedef tl::false_tag has_copy_constructor; + typedef tl::false_tag has_default_constructor; +}; + } #endif diff --git a/src/db/db/dbNetlistSpiceWriter.cc b/src/db/db/dbNetlistSpiceWriter.cc index 2814c1f1c..3b38ed3f1 100644 --- a/src/db/db/dbNetlistSpiceWriter.cc +++ b/src/db/db/dbNetlistSpiceWriter.cc @@ -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); diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index 837937563..c114a1d3d 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -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 decl_dbDeviceAbstractRef ("db", "DeviceAbstractRef", @@ -148,19 +148,19 @@ Class 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" ); diff --git a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc index a814ca1a6..da5f8fbf2 100644 --- a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc +++ b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc @@ -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 decl_dbNetlistDeviceExtractorLayerDefinition ("db", "NetlistDeviceExtractorLayerDefinition", gsi::method_ext ("name", &ld_name, "@brief Gets the name of the layer.\n" @@ -192,6 +197,10 @@ Class 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 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 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 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 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." +); + } diff --git a/src/laybasic/laybasic/layNetlistBrowserModel.cc b/src/laybasic/laybasic/layNetlistBrowserModel.cc index b9663033a..03131cabe 100644 --- a/src/laybasic/laybasic/layNetlistBrowserModel.cc +++ b/src/laybasic/laybasic/layNetlistBrowserModel.cc @@ -737,6 +737,33 @@ static std::string str_from_names (const std::pair &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 += "]"; diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index 124f56f29..d6f624e84 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -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 &oda = (*device)->other_abstracts (); for (std::vector::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 &oda = device->other_abstracts (); for (std::vector::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) {