mirror of https://github.com/KLayout/klayout.git
WIP: Support for combined devices
This commit is contained in:
parent
8aeab5f131
commit
9a361ee234
|
|
@ -422,11 +422,7 @@ void Circuit::translate_device_classes (const std::map<const DeviceClass *, Devi
|
|||
void Circuit::translate_device_abstracts (const std::map<const DeviceAbstract *, DeviceAbstract *> &map)
|
||||
{
|
||||
for (device_iterator i = m_devices.begin (); i != m_devices.end (); ++i) {
|
||||
if (i->device_abstract ()) {
|
||||
std::map<const DeviceAbstract *, DeviceAbstract *>::const_iterator m = map.find (i->device_abstract ());
|
||||
tl_assert (m != map.end ());
|
||||
i->set_device_abstract (m->second);
|
||||
}
|
||||
i->translate_device_abstracts (map);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -534,6 +530,7 @@ bool Circuit::combine_parallel_devices (const db::DeviceClass &cls)
|
|||
for (size_t i = 0; i < cl.size () - 1; ++i) {
|
||||
for (size_t j = i + 1; j < cl.size (); ) {
|
||||
if (cls.combine_devices (cl [i], cl [j])) {
|
||||
cl [i]->join_device (cl [j]);
|
||||
check_device_before_remove (this, cl [j]); // sanity check
|
||||
delete cl [j];
|
||||
cl.erase (cl.begin () + j);
|
||||
|
|
@ -623,6 +620,7 @@ bool Circuit::combine_serial_devices(const db::DeviceClass &cls)
|
|||
|
||||
// found a combination candidate
|
||||
if (cls.combine_devices (dd.first, dd.second)) {
|
||||
dd.first->join_device (dd.second);
|
||||
check_device_before_remove (this, dd.second); // sanity check
|
||||
delete dd.second;
|
||||
any = true;
|
||||
|
|
|
|||
|
|
@ -187,4 +187,96 @@ void Device::set_parameter_value (const std::string &name, double v)
|
|||
}
|
||||
}
|
||||
|
||||
void Device::add_others_terminals (unsigned int this_terminal, db::Device *other, unsigned int other_terminal)
|
||||
{
|
||||
std::map<unsigned int, std::vector<OtherTerminalRef> >::const_iterator ot = other->m_reconnected_terminals.find (other_terminal);
|
||||
if (ot == other->m_reconnected_terminals.end ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (other->m_reconnected_terminals.empty ()) {
|
||||
m_reconnected_terminals.insert (std::make_pair (this_terminal, ot->second));
|
||||
} else {
|
||||
|
||||
std::vector<OtherTerminalRef> &terminals = m_reconnected_terminals [this_terminal];
|
||||
|
||||
size_t n = terminals.size ();
|
||||
terminals.insert (terminals.end (), ot->second.begin (), ot->second.end ());
|
||||
|
||||
db::DVector d = other->position () - position ();
|
||||
while (n < terminals.size ()) {
|
||||
terminals [n].offset += d;
|
||||
++n;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Device::join_terminals (unsigned int this_terminal, db::Device *other, unsigned int other_terminal)
|
||||
{
|
||||
if (m_reconnected_terminals.empty ()) {
|
||||
m_reconnected_terminals [this_terminal].push_back (OtherTerminalRef (device_abstract (), db::DVector (), this_terminal));
|
||||
}
|
||||
|
||||
other->connect_terminal (other_terminal, 0);
|
||||
|
||||
add_others_terminals (this_terminal, other, other_terminal);
|
||||
}
|
||||
|
||||
void Device::reroute_terminal (unsigned int this_terminal, db::Device *other, unsigned int from_other_terminal, unsigned int other_terminal)
|
||||
{
|
||||
// TODO: the internal connection is not represented currently ...
|
||||
|
||||
if (! m_reconnected_terminals.empty ()) {
|
||||
m_reconnected_terminals.erase (this_terminal);
|
||||
}
|
||||
|
||||
add_others_terminals (this_terminal, other, other_terminal);
|
||||
|
||||
connect_terminal (this_terminal, other->net_for_terminal (other_terminal));
|
||||
|
||||
other->connect_terminal (from_other_terminal, 0);
|
||||
other->connect_terminal (other_terminal, 0);
|
||||
}
|
||||
|
||||
void Device::join_device (db::Device *other)
|
||||
{
|
||||
db::DVector d = other->position () - position ();
|
||||
|
||||
m_other_abstracts.reserve (m_other_abstracts.size () + 1 + other->m_other_abstracts.size ());
|
||||
|
||||
m_other_abstracts.push_back (std::make_pair (other->device_abstract (), d));
|
||||
|
||||
for (std::vector<std::pair<const db::DeviceAbstract *, db::DVector> >::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 ().second += d;
|
||||
}
|
||||
}
|
||||
|
||||
static db::DeviceAbstract *map_da (const std::map<const DeviceAbstract *, DeviceAbstract *> &map, const db::DeviceAbstract *da)
|
||||
{
|
||||
if (! da) {
|
||||
return 0;
|
||||
} else {
|
||||
std::map<const DeviceAbstract *, DeviceAbstract *>::const_iterator m = map.find (da);
|
||||
tl_assert (m != map.end ());
|
||||
return m->second;
|
||||
}
|
||||
}
|
||||
|
||||
void Device::translate_device_abstracts (const std::map<const DeviceAbstract *, DeviceAbstract *> &map)
|
||||
{
|
||||
set_device_abstract (map_da (map, device_abstract ()));
|
||||
|
||||
for (std::vector<std::pair<const db::DeviceAbstract *, db::DVector> >::iterator a = m_other_abstracts.begin (); a != m_other_abstracts.end (); ++a) {
|
||||
a->first = map_da (map, a->first);
|
||||
}
|
||||
|
||||
for (std::map<unsigned int, std::vector<OtherTerminalRef> >::iterator t = m_reconnected_terminals.begin (); t != m_reconnected_terminals.end (); ++t) {
|
||||
for (std::vector<OtherTerminalRef>::iterator r = t->second.begin (); r != t->second.end (); ++r) {
|
||||
r->device_abstract = map_da (map, r->device_abstract);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "dbCommon.h"
|
||||
#include "dbNet.h"
|
||||
#include "dbPoint.h"
|
||||
#include "dbVector.h"
|
||||
|
||||
#include "tlObject.h"
|
||||
|
||||
|
|
@ -54,6 +55,22 @@ public:
|
|||
typedef std::vector<std::pair<size_t, size_t> > global_connections;
|
||||
typedef global_connections::const_iterator global_connections_iterator;
|
||||
|
||||
/**
|
||||
* @brief A structure describing a terminal reference into another device abstract
|
||||
*/
|
||||
struct OtherTerminalRef
|
||||
{
|
||||
OtherTerminalRef (const db::DeviceAbstract *_device_abstract, const db::DVector &_offset, unsigned int _other_terminal_id)
|
||||
: device_abstract (_device_abstract), offset (_offset), other_terminal_id (_other_terminal_id)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
const db::DeviceAbstract *device_abstract;
|
||||
db::DVector offset;
|
||||
unsigned int other_terminal_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
|
|
@ -228,6 +245,52 @@ public:
|
|||
*/
|
||||
void set_parameter_value (const std::string &name, double v);
|
||||
|
||||
/**
|
||||
* @brief Used for device combination: join terminals with other device
|
||||
*/
|
||||
void join_terminals (unsigned int this_terminal, db::Device *other, unsigned int other_terminal);
|
||||
|
||||
/**
|
||||
* @brief Used for device combination: reroute terminal to other device
|
||||
*
|
||||
* This will disconnect "this_terminal" from the device and make a connection to
|
||||
* "other_terminal" of the "other" device instead.
|
||||
*
|
||||
* An internal connection between "this_terminal" and "from_other_terminal" is
|
||||
* implied.
|
||||
*/
|
||||
void reroute_terminal (unsigned int this_terminal, db::Device *other, unsigned int from_other_terminal, unsigned int other_terminal);
|
||||
|
||||
/**
|
||||
* @brief Gets the set of other terminal references
|
||||
*
|
||||
* This method will return 0 if the device isn't a combined device or the given terminal
|
||||
* is not connector to a different abstract.
|
||||
*
|
||||
* The returned vector (if any) is a complete list of terminals connected to the given
|
||||
* logical device terminal.
|
||||
*/
|
||||
const std::vector<OtherTerminalRef> *reconnected_terminals_for (unsigned int this_terminal) const
|
||||
{
|
||||
std::map<unsigned int, std::vector<OtherTerminalRef> >::const_iterator t = m_reconnected_terminals.find (this_terminal);
|
||||
if (t != m_reconnected_terminals.end ()) {
|
||||
return & t->second;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the set of other device abstracts
|
||||
*
|
||||
* This list does not include the intrinsic original abstract of the device.
|
||||
* This vector is non-empty if this device is a combined one.
|
||||
*/
|
||||
const std::vector<std::pair<const db::DeviceAbstract *, db::DVector> > &other_abstracts () const
|
||||
{
|
||||
return m_other_abstracts;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Circuit;
|
||||
friend class Net;
|
||||
|
|
@ -240,6 +303,18 @@ private:
|
|||
std::vector<double> m_parameters;
|
||||
size_t m_id;
|
||||
Circuit *mp_circuit;
|
||||
std::vector<std::pair<const db::DeviceAbstract *, db::DVector> > m_other_abstracts;
|
||||
std::map<unsigned int, std::vector<OtherTerminalRef> > m_reconnected_terminals;
|
||||
|
||||
/**
|
||||
* @brief Translates the device abstracts
|
||||
*/
|
||||
void translate_device_abstracts (const std::map<const DeviceAbstract *, DeviceAbstract *> &map);
|
||||
|
||||
/**
|
||||
* @brief Joins this device with another
|
||||
*/
|
||||
void join_device (db::Device *other);
|
||||
|
||||
/**
|
||||
* @brief Sets the terminal reference for a specific terminal
|
||||
|
|
@ -258,6 +333,8 @@ private:
|
|||
* @brief Sets the circuit
|
||||
*/
|
||||
void set_circuit (Circuit *circuit);
|
||||
|
||||
void add_others_terminals (unsigned int this_terminal, db::Device *other, unsigned int other_terminal);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,30 +46,46 @@ bool DeviceClassTwoTerminalDevice::combine_devices (Device *a, Device *b) const
|
|||
db::Net *nb1 = b->net_for_terminal (0);
|
||||
db::Net *nb2 = b->net_for_terminal (1);
|
||||
|
||||
bool res = true;
|
||||
|
||||
if ((na1 == nb1 && na2 == nb2) || (na1 == nb2 && na2 == nb1)) {
|
||||
|
||||
parallel (a, b);
|
||||
|
||||
if (na1 == nb1 && na2 == nb2) {
|
||||
a->join_terminals (0, b, 0);
|
||||
a->join_terminals (1, b, 1);
|
||||
} else {
|
||||
a->join_terminals (0, b, 1);
|
||||
a->join_terminals (1, b, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} else if ((na2 == nb1 || na2 == nb2) && na2->is_internal ()) {
|
||||
|
||||
// serial a(B) to b(A or B)
|
||||
serial (a, b);
|
||||
a->connect_terminal (1, (na2 == nb1 ? nb2 : nb1));
|
||||
|
||||
if (na2 == nb1) {
|
||||
a->reroute_terminal (1, b, 0, 1);
|
||||
} else {
|
||||
a->reroute_terminal (1, b, 1, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} else if ((na1 == nb1 || na1 == nb2) && na1->is_internal ()) {
|
||||
|
||||
// serial a(A) to b(A or B)
|
||||
serial (a, b);
|
||||
a->connect_terminal (0, (na1 == nb1 ? nb2 : nb1));
|
||||
|
||||
}
|
||||
if (na1 == nb1) {
|
||||
a->reroute_terminal (0, b, 0, 1);
|
||||
} else {
|
||||
a->reroute_terminal (0, b, 1, 0);
|
||||
}
|
||||
|
||||
if (res) {
|
||||
b->connect_terminal (0, 0);
|
||||
b->connect_terminal (1, 0);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -193,8 +209,9 @@ bool DeviceClassDiode::combine_devices (Device *a, Device *b) const
|
|||
if (na1 == nb1 && na2 == nb2) {
|
||||
|
||||
a->set_parameter_value (0, a->parameter_value (0) + b->parameter_value (0));
|
||||
b->connect_terminal (0, 0);
|
||||
b->connect_terminal (1, 0);
|
||||
|
||||
a->join_terminals (0, b, 0);
|
||||
a->join_terminals (1, b, 1);
|
||||
|
||||
return true;
|
||||
|
||||
|
|
@ -248,9 +265,15 @@ bool DeviceClassMOS3Transistor::combine_devices (Device *a, Device *b) const
|
|||
|
||||
combine_parameters (a, b);
|
||||
|
||||
b->connect_terminal (0, 0);
|
||||
b->connect_terminal (1, 0);
|
||||
b->connect_terminal (2, 0);
|
||||
if (nas == nbs && nad == nbd) {
|
||||
a->join_terminals (0, b, 0);
|
||||
a->join_terminals (2, b, 2);
|
||||
} else {
|
||||
a->join_terminals (0, b, 2);
|
||||
a->join_terminals (2, b, 0);
|
||||
}
|
||||
|
||||
a->join_terminals (1, b, 1);
|
||||
|
||||
return true;
|
||||
|
||||
|
|
@ -299,10 +322,16 @@ bool DeviceClassMOS4Transistor::combine_devices (Device *a, Device *b) const
|
|||
|
||||
combine_parameters (a, b);
|
||||
|
||||
b->connect_terminal (0, 0);
|
||||
b->connect_terminal (1, 0);
|
||||
b->connect_terminal (2, 0);
|
||||
b->connect_terminal (3, 0);
|
||||
if (nas == nbs && nad == nbd) {
|
||||
a->join_terminals (0, b, 0);
|
||||
a->join_terminals (2, b, 2);
|
||||
} else {
|
||||
a->join_terminals (0, b, 2);
|
||||
a->join_terminals (2, b, 0);
|
||||
}
|
||||
|
||||
a->join_terminals (1, b, 1);
|
||||
a->join_terminals (3, b, 3);
|
||||
|
||||
return true;
|
||||
|
||||
|
|
|
|||
|
|
@ -687,13 +687,13 @@ NetlistBrowserPage::enable_updates (bool f)
|
|||
}
|
||||
|
||||
static db::Box
|
||||
bbox_for_device (const db::Layout *layout, const db::Device *device)
|
||||
bbox_for_device_abstract (const db::Layout *layout, const db::DeviceAbstract *device_abstract, const db::DVector &offset)
|
||||
{
|
||||
if (! device->device_abstract () || ! layout->is_valid_cell_index (device->device_abstract ()->cell_index ())) {
|
||||
if (! device_abstract || ! layout->is_valid_cell_index (device_abstract->cell_index ())) {
|
||||
return db::Box ();
|
||||
}
|
||||
|
||||
return layout->cell (device->device_abstract ()->cell_index ()).bbox ();
|
||||
return layout->cell (device_abstract->cell_index ()).bbox ().moved (db::VCplxTrans (1.0 / layout->dbu ()) * offset);
|
||||
}
|
||||
|
||||
static db::Box
|
||||
|
|
@ -753,7 +753,16 @@ NetlistBrowserPage::adjust_view ()
|
|||
}
|
||||
|
||||
for (std::vector<const db::Device *>::const_iterator device = m_current_devices.begin (); device != m_current_devices.end (); ++device) {
|
||||
bbox += trans_for (*device, *mp_database->internal_layout (), *mp_database->internal_top_cell (), m_cell_context_cache) * bbox_for_device (layout, *device);
|
||||
|
||||
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 ());
|
||||
|
||||
const std::vector<std::pair<const db::DeviceAbstract *, db::DVector> > &oda = (*device)->other_abstracts ();
|
||||
for (std::vector<std::pair<const db::DeviceAbstract *, db::DVector> >::const_iterator a = oda.begin (); a != oda.end (); ++a) {
|
||||
bbox += trans * bbox_for_device_abstract (layout, a->first, a->second);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (std::vector<const db::SubCircuit *>::const_iterator subcircuit = m_current_subcircuits.begin (); subcircuit != m_current_subcircuits.end (); ++subcircuit) {
|
||||
|
|
@ -809,22 +818,44 @@ NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, siz
|
|||
db::ICplxTrans device_trans = trans_for (device, *layout, *cell, m_cell_context_cache, db::DCplxTrans (device->position () - db::DPoint ()));
|
||||
|
||||
QColor color = make_valid_color (m_colorizer.marker_color ());
|
||||
db::Box device_bbox = bbox_for_device (layout, device);
|
||||
if (device_bbox.empty ()) {
|
||||
return false;
|
||||
|
||||
db::Box device_bbox = bbox_for_device_abstract (layout, device->device_abstract (), db::DVector ());
|
||||
if (! device_bbox.empty ()) {
|
||||
|
||||
if (n_markers == m_max_shape_count) {
|
||||
return true;
|
||||
}
|
||||
|
||||
++n_markers;
|
||||
|
||||
mp_markers.push_back (new lay::Marker (mp_view, m_cv_index));
|
||||
mp_markers.back ()->set (device_bbox, device_trans, tv);
|
||||
mp_markers.back ()->set_color (color);
|
||||
mp_markers.back ()->set_frame_color (color);
|
||||
|
||||
}
|
||||
|
||||
if (n_markers == m_max_shape_count) {
|
||||
return true;
|
||||
const std::vector<std::pair<const db::DeviceAbstract *, db::DVector> > &oda = device->other_abstracts ();
|
||||
for (std::vector<std::pair<const db::DeviceAbstract *, db::DVector> >::const_iterator a = oda.begin (); a != oda.end (); ++a) {
|
||||
|
||||
db::Box da_box = bbox_for_device_abstract (layout, a->first, a->second);
|
||||
if (! da_box.empty ()) {
|
||||
|
||||
if (n_markers == m_max_shape_count) {
|
||||
return true;
|
||||
}
|
||||
|
||||
++n_markers;
|
||||
|
||||
mp_markers.push_back (new lay::Marker (mp_view, m_cv_index));
|
||||
mp_markers.back ()->set (da_box, device_trans, tv);
|
||||
mp_markers.back ()->set_color (color);
|
||||
mp_markers.back ()->set_frame_color (color);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
++n_markers;
|
||||
|
||||
mp_markers.push_back (new lay::Marker (mp_view, m_cv_index));
|
||||
mp_markers.back ()->set (device_bbox, device_trans, tv);
|
||||
mp_markers.back ()->set_color (color);
|
||||
mp_markers.back ()->set_frame_color (color);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue