From 9a361ee234e9d7b495ad230a84e226b99b42fa62 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 8 May 2019 00:14:08 +0200 Subject: [PATCH] WIP: Support for combined devices --- src/db/db/dbCircuit.cc | 8 +- src/db/db/dbDevice.cc | 92 +++++++++++++++++++ src/db/db/dbDevice.h | 77 ++++++++++++++++ src/db/db/dbNetlistDeviceClasses.cc | 63 +++++++++---- .../laybasic/layNetlistBrowserPage.cc | 63 +++++++++---- 5 files changed, 265 insertions(+), 38 deletions(-) diff --git a/src/db/db/dbCircuit.cc b/src/db/db/dbCircuit.cc index 2b5b6a09d..f72b68a5c 100644 --- a/src/db/db/dbCircuit.cc +++ b/src/db/db/dbCircuit.cc @@ -422,11 +422,7 @@ void Circuit::translate_device_classes (const std::map &map) { for (device_iterator i = m_devices.begin (); i != m_devices.end (); ++i) { - if (i->device_abstract ()) { - std::map::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; diff --git a/src/db/db/dbDevice.cc b/src/db/db/dbDevice.cc index e803cec08..da17710cf 100644 --- a/src/db/db/dbDevice.cc +++ b/src/db/db/dbDevice.cc @@ -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 >::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 &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 >::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 &map, const db::DeviceAbstract *da) +{ + if (! da) { + return 0; + } else { + std::map::const_iterator m = map.find (da); + tl_assert (m != map.end ()); + return m->second; + } +} + +void Device::translate_device_abstracts (const std::map &map) +{ + set_device_abstract (map_da (map, device_abstract ())); + + for (std::vector >::iterator a = m_other_abstracts.begin (); a != m_other_abstracts.end (); ++a) { + a->first = map_da (map, a->first); + } + + for (std::map >::iterator t = m_reconnected_terminals.begin (); t != m_reconnected_terminals.end (); ++t) { + for (std::vector::iterator r = t->second.begin (); r != t->second.end (); ++r) { + r->device_abstract = map_da (map, r->device_abstract); + } + } +} + } diff --git a/src/db/db/dbDevice.h b/src/db/db/dbDevice.h index 5b12d25d5..c71fa3ac7 100644 --- a/src/db/db/dbDevice.h +++ b/src/db/db/dbDevice.h @@ -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 > 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 *reconnected_terminals_for (unsigned int this_terminal) const + { + std::map >::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 > &other_abstracts () const + { + return m_other_abstracts; + } + private: friend class Circuit; friend class Net; @@ -240,6 +303,18 @@ private: std::vector m_parameters; size_t m_id; Circuit *mp_circuit; + std::vector > m_other_abstracts; + std::map > m_reconnected_terminals; + + /** + * @brief Translates the device abstracts + */ + void translate_device_abstracts (const std::map &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); }; } diff --git a/src/db/db/dbNetlistDeviceClasses.cc b/src/db/db/dbNetlistDeviceClasses.cc index 180d40ee2..09378dfdf 100644 --- a/src/db/db/dbNetlistDeviceClasses.cc +++ b/src/db/db/dbNetlistDeviceClasses.cc @@ -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; diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index 5d486d704..9217a7acf 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -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_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 > &oda = (*device)->other_abstracts (); + for (std::vector >::const_iterator a = oda.begin (); a != oda.end (); ++a) { + bbox += trans * bbox_for_device_abstract (layout, a->first, a->second); + } + } for (std::vector::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 > &oda = device->other_abstracts (); + for (std::vector >::const_iterator a = oda.begin (); a != oda.end (); ++a) { + + db::Box da_box = bbox_for_device_abstract (layout, a->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; }