mirror of https://github.com/KLayout/klayout.git
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:
parent
f4939a6efc
commit
9d01cb5282
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 ()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 ()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 += "]";
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue