diff --git a/src/db/db/dbDevice.cc b/src/db/db/dbDevice.cc index 0e41cd9a9..0dcf8410d 100644 --- a/src/db/db/dbDevice.cc +++ b/src/db/db/dbDevice.cc @@ -189,12 +189,12 @@ 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::vector &terminals = m_reconnected_terminals [this_terminal]; + std::vector &terminals = m_reconnected_terminals [this_terminal]; - std::map >::const_iterator ot = other->m_reconnected_terminals.find (other_terminal); + std::map >::const_iterator ot = other->m_reconnected_terminals.find (other_terminal); if (ot == other->m_reconnected_terminals.end ()) { - terminals.push_back (OtherTerminalRef (other_abstracts ().size (), other_terminal)); + terminals.push_back (DeviceReconnectedTerminal (other_abstracts ().size (), other_terminal)); } else { @@ -217,7 +217,7 @@ void Device::init_terminal_routes () size_t n = device_class ()->terminal_definitions ().size (); for (size_t i = 0; i < n; ++i) { - m_reconnected_terminals [i].push_back (OtherTerminalRef (0, i)); + m_reconnected_terminals [i].push_back (DeviceReconnectedTerminal (0, i)); } } @@ -258,11 +258,11 @@ void Device::join_device (db::Device *other) 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)); + m_other_abstracts.push_back (db::DeviceAbstractRef (other->device_abstract (), d)); - for (std::vector >::const_iterator a = other->m_other_abstracts.begin (); a != other->m_other_abstracts.end (); ++a) { + 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; + m_other_abstracts.back ().offset += d; } } @@ -281,8 +281,8 @@ void Device::translate_device_abstracts (const std::map >::iterator a = m_other_abstracts.begin (); a != m_other_abstracts.end (); ++a) { - a->first = map_da (map, a->first); + for (std::vector::iterator a = m_other_abstracts.begin (); a != m_other_abstracts.end (); ++a) { + a->device_abstract = map_da (map, a->device_abstract); } } diff --git a/src/db/db/dbDevice.h b/src/db/db/dbDevice.h index ffcde9ea7..de0afc06f 100644 --- a/src/db/db/dbDevice.h +++ b/src/db/db/dbDevice.h @@ -39,6 +39,51 @@ class Circuit; class DeviceClass; class DeviceAbstract; +/** + * @brief A structure describing a terminal reference into another device abstract + */ +struct DeviceReconnectedTerminal +{ + DeviceReconnectedTerminal (size_t _device_index, unsigned int _other_terminal_id) + : device_index (_device_index), other_terminal_id (_other_terminal_id) + { + // .. nothing yet .. + } + + DeviceReconnectedTerminal () + : device_index (0), other_terminal_id (0) + { + // .. nothing yet .. + } + + size_t device_index; + unsigned int other_terminal_id; +}; + +/** + * @brief A structure describing a reference to another device abstract + * + * This structure is used within Device to reference more than the standard + * device abstract. + */ +struct DeviceAbstractRef +{ + DeviceAbstractRef (const db::DeviceAbstract *_device_abstract, const db::DVector &_offset) + : device_abstract (_device_abstract), offset (_offset) + { + // .. nothing yet .. + } + + DeviceAbstractRef () + : device_abstract (0), offset () + { + // .. nothing yet .. + } + + const db::DeviceAbstract *device_abstract; + db::DVector offset; +}; + /** * @brief An actual device * @@ -55,21 +100,6 @@ 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 (size_t _device_index, unsigned int _other_terminal_id) - : device_index (_device_index), other_terminal_id (_other_terminal_id) - { - // .. nothing yet .. - } - - size_t device_index; - unsigned int other_terminal_id; - }; - /** * @brief Default constructor */ @@ -269,9 +299,9 @@ public: * 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 + const std::vector *reconnected_terminals_for (unsigned int this_terminal) const { - std::map >::const_iterator t = m_reconnected_terminals.find (this_terminal); + std::map >::const_iterator t = m_reconnected_terminals.find (this_terminal); if (t != m_reconnected_terminals.end ()) { return & t->second; } else { @@ -282,7 +312,17 @@ public: /** * @brief Gets the map of reconnected terminals */ - const std::map > &reconnected_terminals () const + const std::map > &reconnected_terminals () const + { + return m_reconnected_terminals; + } + + /** + * @brief Gets the map of reconnected terminals (non-const version) + * + * NOTE: don't use this method to modify this container! It's provided for persistence implementation only. + */ + std::map > &reconnected_terminals () { return m_reconnected_terminals; } @@ -293,27 +333,17 @@ public: * 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 + const std::vector &other_abstracts () const { return m_other_abstracts; } - /** - * @brief Gets the map of reconnected terminals (non-const version) - * - * NOTE: don't use this method to modify this container! It's provided for persistence implementation only. - */ - std::map > &reconnected_terminals () - { - return m_reconnected_terminals; - } - /** * @brief Gets the set of other device abstracts (non-const version) * * NOTE: don't use this method to modify this container! It's provided for persistence implementation only. */ - std::vector > &other_abstracts () + std::vector &other_abstracts () { return m_other_abstracts; } @@ -330,8 +360,8 @@ private: std::vector m_parameters; size_t m_id; Circuit *mp_circuit; - std::vector > m_other_abstracts; - std::map > m_reconnected_terminals; + std::vector m_other_abstracts; + std::map > m_reconnected_terminals; /** * @brief Translates the device abstracts diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc index 5c5a249ca..bb9cd39ec 100644 --- a/src/db/db/dbLayoutToNetlistReader.cc +++ b/src/db/db/dbLayoutToNetlistReader.cc @@ -556,7 +556,7 @@ LayoutToNetlistStandardReader::read_device (db::LayoutToNetlist *l2n, db::Circui db::DeviceAbstract *da = device_model_by_name (l2n->netlist (), n); - device->other_abstracts ().push_back (std::make_pair (da, db::DVector (dbu * dx, dbu * dy))); + device->other_abstracts ().push_back (db::DeviceAbstractRef (da, db::DVector (dbu * dx, dbu * dy))); } else if (test (skeys::connect_key) || test (lkeys::connect_key)) { @@ -577,7 +577,7 @@ LayoutToNetlistStandardReader::read_device (db::LayoutToNetlist *l2n, db::Circui size_t touter_id = terminal_id (dm->device_class (), touter); size_t tinner_id = terminal_id (dm->device_class (), tinner); - device->reconnected_terminals () [touter_id].push_back (db::Device::OtherTerminalRef (size_t (device_comp_index), tinner_id)); + device->reconnected_terminals () [touter_id].push_back (db::DeviceReconnectedTerminal (size_t (device_comp_index), tinner_id)); } else if (test (skeys::terminal_key) || test (lkeys::terminal_key)) { @@ -642,10 +642,10 @@ LayoutToNetlistStandardReader::read_device (db::LayoutToNetlist *l2n, db::Circui ccell.insert (inst); insts.push_back (inst); - const std::vector > &other_devices = device->other_abstracts (); - for (std::vector >::const_iterator i = other_devices.begin (); i != other_devices.end (); ++i) { + const std::vector &other_devices = device->other_abstracts (); + for (std::vector::const_iterator i = other_devices.begin (); i != other_devices.end (); ++i) { - db::CellInstArray other_inst (db::CellInst (i->first->cell_index ()), db::Trans (db::Vector (x, y) + dbu_inv * i->second)); + db::CellInstArray other_inst (db::CellInst (i->device_abstract->cell_index ()), db::Trans (db::Vector (x, y) + dbu_inv * i->offset)); ccell.insert (other_inst); insts.push_back (other_inst); @@ -662,13 +662,13 @@ LayoutToNetlistStandardReader::read_device (db::LayoutToNetlist *l2n, db::Circui if (! device->reconnected_terminals ().empty ()) { - const std::vector *tr = device->reconnected_terminals_for (tid); + const std::vector *tr = device->reconnected_terminals_for (tid); if (tr) { - for (std::vector::const_iterator i = tr->begin (); i != tr->end (); ++i) { + for (std::vector::const_iterator i = tr->begin (); i != tr->end (); ++i) { const db::DeviceAbstract *da = dm; if (i->device_index > 0) { - da = device->other_abstracts () [i->device_index - 1].first; + da = device->other_abstracts () [i->device_index - 1].device_abstract; } Connections ref (net->cluster_id (), da->cluster_id_for_terminal (i->other_terminal_id)); connections [insts [i->device_index]].push_back (ref); diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index b3ece9cfb..0febc845c 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -500,19 +500,19 @@ void std_writer_impl::write (const db::LayoutToNetlist *l2n, const db::Dev tl_assert (device.device_abstract () != 0); *mp_stream << " " << tl::to_word_or_quoted_string (device.device_abstract ()->name ()) << endl; - const std::vector > &other_abstracts = device.other_abstracts (); - for (std::vector >::const_iterator a = other_abstracts.begin (); a != other_abstracts.end (); ++a) { + const std::vector &other_abstracts = device.other_abstracts (); + for (std::vector::const_iterator a = other_abstracts.begin (); a != other_abstracts.end (); ++a) { - db::Vector pos = dbu_inv * a->second; + db::Vector pos = dbu_inv * a->offset; - *mp_stream << " " << Keys::device_key << "(" << tl::to_word_or_quoted_string (a->first->name ()) << " " << pos.x () << " " << pos.y () << ")" << endl; + *mp_stream << " " << Keys::device_key << "(" << tl::to_word_or_quoted_string (a->device_abstract->name ()) << " " << pos.x () << " " << pos.y () << ")" << endl; } - const std::map > &reconnected_terminals = device.reconnected_terminals (); - for (std::map >::const_iterator t = reconnected_terminals.begin (); t != reconnected_terminals.end (); ++t) { + const std::map > &reconnected_terminals = device.reconnected_terminals (); + for (std::map >::const_iterator t = reconnected_terminals.begin (); t != reconnected_terminals.end (); ++t) { - for (std::vector::const_iterator c = t->second.begin (); c != t->second.end (); ++c) { + for (std::vector::const_iterator c = t->second.begin (); c != t->second.end (); ++c) { *mp_stream << " " << Keys::connect_key << "(" << c->device_index << " " << tl::to_word_or_quoted_string (td [t->first].name ()) << " " << tl::to_word_or_quoted_string (td [c->other_terminal_id].name ()) << ")" << endl; } diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index 244f87168..47ec269f0 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -70,6 +70,160 @@ static void device_disconnect_terminal_by_name (db::Device *device, const std::s device_connect_terminal_by_name (device, terminal_name, 0); } +static size_t get_device_index (const db::DeviceReconnectedTerminal *obj) +{ + return obj->device_index; +} + +static void set_device_index (db::DeviceReconnectedTerminal *obj, size_t device_index) +{ + obj->device_index = device_index; +} + +static size_t get_other_terminal_id (const db::DeviceReconnectedTerminal *obj) +{ + return obj->other_terminal_id; +} + +static void set_other_terminal_id (db::DeviceReconnectedTerminal *obj, size_t other_terminal_id) +{ + obj->other_terminal_id = other_terminal_id; +} + +Class decl_dbDeviceReconnectedTerminal ("db", "DeviceReconnectedTerminal", + gsi::method_ext ("device_index=", &set_device_index, gsi::arg ("device_index"), + "@brief The device abstract index setter.\n" + "See the class description for details." + ) + + gsi::method_ext ("device_index", &get_device_index, + "@brief The device abstract index getter.\n" + "See the class description for details." + ) + + gsi::method_ext ("other_terminal_id=", &set_other_terminal_id, gsi::arg ("other_terminal_id"), + "@brief The setter for the abstract's connected terminal.\n" + "See the class description for details." + ) + + gsi::method_ext ("other_terminal_id", &get_other_terminal_id, + "@brief The getter for the abstract's connected terminal.\n" + "See the class description for details." + ), + "@brief Describes a terminal rerouting in 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. To support different combination schemes, " + "device-to-abstract routing is supported. Parallel combinations will route all outer terminals to corresponding " + "terminals of all device abstracts (because of terminal swapping these may be different ones).\n" + "\n" + "This object describes one route to an abstract's terminal. The device index is 0 for the main device abstract and " + "1 for the first combined device abstract.\n" + "\n" + "This class has been introduced in version 0.26.\n" +); + +static const db::DeviceAbstract *get_device_abstract (const db::DeviceAbstractRef *obj) +{ + return obj->device_abstract; +} + +static void set_device_abstract (db::DeviceAbstractRef *obj, const db::DeviceAbstract *device_abstract) +{ + obj->device_abstract = device_abstract; +} + +static db::DVector get_offset (const db::DeviceAbstractRef *obj) +{ + return obj->offset; +} + +static void set_offset (db::DeviceAbstractRef *obj, const db::DVector &offset) +{ + obj->offset = offset; +} + +Class decl_dbDeviceAbstractRef ("db", "DeviceAbstractRef", + gsi::method_ext ("device_abstract=", &set_device_abstract, gsi::arg ("device_abstract"), + "@brief The setter for the device abstract reference.\n" + "See the class description for details." + ) + + gsi::method_ext ("device_abstract", &get_device_abstract, + "@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" + "See the class description for details." + ) + + gsi::method_ext ("offset", &get_offset, + "@brief The getter for the offset.\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" + "\n" + "This class has been introduced in version 0.26.\n" +); + +static bool is_combined_device (const db::Device *device) +{ + return ! device->reconnected_terminals ().empty (); +} + +static std::vector::const_iterator begin_reconnected_terminals_for (const db::Device *device, size_t terminal_id) +{ + static std::vector empty; + + const std::vector *ti = device->reconnected_terminals_for (terminal_id); + if (! ti) { + return empty.begin (); + } else { + return ti->begin (); + } +} + +static std::vector::const_iterator end_reconnected_terminals_for (const db::Device *device, size_t terminal_id) +{ + static std::vector empty; + + const std::vector *ti = device->reconnected_terminals_for (terminal_id); + if (! ti) { + return empty.end (); + } else { + return ti->end (); + } +} + +static void clear_reconnected_terminals (db::Device *device) +{ + device->reconnected_terminals ().clear (); +} + +static void add_reconnected_terminals (db::Device *device, size_t outer_terminal, const db::DeviceReconnectedTerminal &t) +{ + device->reconnected_terminals () [outer_terminal].push_back (t); +} + +static std::vector::const_iterator begin_other_abstracts (const db::Device *device) +{ + return device->other_abstracts ().begin (); +} + +static std::vector::const_iterator end_other_abstracts (const db::Device *device) +{ + return device->other_abstracts ().end (); +} + +static void clear_other_abstracts (db::Device *device) +{ + device->other_abstracts ().clear (); +} + +static void add_other_abstracts (db::Device *device, const db::DeviceAbstractRef &ref) +{ + device->other_abstracts ().push_back (ref); +} + Class decl_dbDevice ("db", "Device", gsi::method ("device_class", &db::Device::device_class, "@brief Gets the device class the device belongs to.\n" @@ -78,6 +232,39 @@ Class decl_dbDevice ("db", "Device", "@brief Gets the device abstract for this device instance.\n" "See \\DeviceAbstract for more details.\n" ) + + gsi::method ("device_abstract=", &db::Device::set_device_abstract, + "@hide\n" + "Provided for test purposes mainly. Be careful with pointers!" + ) + + gsi::method_ext ("is_combined_device?", &is_combined_device, + "@brief Returns true, if the device is a combined device.\n" + "Combined devices feature multiple device abstracts and device-to-abstract terminal connections.\n" + "See \\each_reconnected_terminal and \\each_combined_abstract for more details.\n" + ) + + gsi::iterator_ext ("each_reconnected_terminal_for", &begin_reconnected_terminals_for, &end_reconnected_terminals_for, gsi::arg ("terminal_id"), + "@brief Iterates over the reconnected terminal specifications for a given outer terminal.\n" + "This feature applies to combined devices. This iterator will deliver all device-to-abstract terminal reroutings.\n" + ) + + gsi::method_ext ("clear_reconnected_terminals", &clear_reconnected_terminals, + "@hide\n" + "Provided for test purposes mainly." + ) + + gsi::method_ext ("add_reconnected_terminal_for", &add_reconnected_terminals, gsi::arg ("outer_terminal"), gsi::arg ("descriptor"), + "@hide\n" + "Provided for test purposes mainly." + ) + + gsi::iterator_ext ("each_combined_abstract", &begin_other_abstracts, &end_other_abstracts, + "@brief Iterates over the combined device specifications.\n" + "This feature applies to combined devices. This iterator will deliver all device abstracts present in addition to the default device abstract.\n" + ) + + gsi::method_ext ("clear_combined_abstracts", &clear_other_abstracts, + "@hide\n" + "Provided for test purposes mainly." + ) + + gsi::method_ext ("add_combined_abstract", &add_other_abstracts, gsi::arg ("ref"), + "@hide\n" + "Provided for test purposes mainly." + ) + gsi::method ("circuit", (db::Circuit *(db::Device::*) ()) &db::Device::circuit, "@brief Gets the circuit the device lives in." ) + diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index 9217a7acf..b7352cd2e 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -758,9 +758,9 @@ NetlistBrowserPage::adjust_view () 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); + const std::vector &oda = (*device)->other_abstracts (); + for (std::vector::const_iterator a = oda.begin (); a != oda.end (); ++a) { + bbox += trans * bbox_for_device_abstract (layout, a->device_abstract, a->offset); } } @@ -835,10 +835,10 @@ NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, siz } - const std::vector > &oda = device->other_abstracts (); - for (std::vector >::const_iterator a = oda.begin (); a != oda.end (); ++a) { + 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); + db::Box da_box = bbox_for_device_abstract (layout, a->device_abstract, a->offset); if (! da_box.empty ()) { if (n_markers == m_max_shape_count) { diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb index 0cb932001..40e66c776 100644 --- a/testdata/ruby/dbNetlist.rb +++ b/testdata/ruby/dbNetlist.rb @@ -262,7 +262,72 @@ class DBNetlist_TestClass < TestBase d2.connect_terminal(0, net) assert_equal(net.terminal_count, 1) + + assert_equal(d1.is_combined_device?, false) + + da = RBA::DeviceAbstract::new + da.name = "xyz" + d1.device_abstract = da + + a = [] + d1.each_combined_abstract { |i| a << i } + assert_equal(a.size, 0) + + t = RBA::DeviceAbstractRef::new + t.device_abstract = d1.device_abstract + t.offset = RBA::DVector::new(1, 2) + d1.add_combined_abstract(t) + + a = [] + d1.each_combined_abstract { |i| a << i } + assert_equal(a.size, 1) + assert_equal(a.collect { |i| i.device_abstract.name }.join(","), "xyz") + assert_equal(a.collect { |i| i.offset.to_s }.join(","), "1,2") + d1.clear_combined_abstracts + + a = [] + d1.each_combined_abstract { |i| a << i } + assert_equal(a.size, 0) + + a = [] + d1.each_reconnected_terminal_for(0) { |i| a << i } + assert_equal(a.size, 0) + + a = [] + d1.each_reconnected_terminal_for(1) { |i| a << i } + assert_equal(a.size, 0) + + t = RBA::DeviceReconnectedTerminal::new + t.device_index = 0 + t.other_terminal_id = 2 + d1.add_reconnected_terminal_for(1, t) + + t = RBA::DeviceReconnectedTerminal::new + t.device_index = 1 + t.other_terminal_id = 1 + d1.add_reconnected_terminal_for(1, t) + + a = [] + d1.each_reconnected_terminal_for(0) { |i| a << i } + assert_equal(a.size, 0) + + a = [] + d1.each_reconnected_terminal_for(1) { |i| a << i } + assert_equal(a.size, 2) + assert_equal(a.collect { |i| i.device_index.to_s }.join(","), "0,1") + assert_equal(a.collect { |i| i.other_terminal_id.to_s }.join(","), "2,1") + + d1.clear_reconnected_terminals + + a = [] + d1.each_reconnected_terminal_for(0) { |i| a << i } + assert_equal(a.size, 0) + + a = [] + d1.each_reconnected_terminal_for(1) { |i| a << i } + assert_equal(a.size, 0) + end def test_5_SubCircuit @@ -648,11 +713,11 @@ END names = [] nl.each_circuit_top_down { |c| names << c.name } - assert_equal(names.join(","), "C1,C2,C3") + assert_equal(names.join(","), "C3,C2,C1") names = [] nl.each_circuit_bottom_up { |c| names << c.name } - assert_equal(names.join(","), "C3,C2,C1") + assert_equal(names.join(","), "C1,C2,C3") names = [] c1.each_child { |c| names << c.name } @@ -691,11 +756,11 @@ END names = [] nl.each_circuit_top_down { |c| names << c.name } - assert_equal(names.join(","), "C1,C2,C3") + assert_equal(names.join(","), "C1,C3,C2") names = [] nl.each_circuit_bottom_up { |c| names << c.name } - assert_equal(names.join(","), "C3,C2,C1") + assert_equal(names.join(","), "C2,C3,C1") c3.create_subcircuit(c2) assert_equal(nl.top_circuit_count, 1)