WIP: Support for combined devices

This commit is contained in:
Matthias Koefferlein 2019-05-08 00:14:08 +02:00
parent 8aeab5f131
commit 9a361ee234
5 changed files with 265 additions and 38 deletions

View File

@ -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;

View File

@ -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);
}
}
}
}

View File

@ -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);
};
}

View File

@ -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;

View File

@ -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;
}