diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 770575fd7..ea36ff395 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -183,7 +183,8 @@ SOURCES = \ dbLayoutVsSchematicFormatDefs.cc \ dbLayoutVsSchematic.cc \ gsiDeclDbNetlistCrossReference.cc \ - gsiDeclDbLayoutVsSchematic.cc + gsiDeclDbLayoutVsSchematic.cc \ + dbNetlistObject.cc HEADERS = \ dbArray.h \ @@ -329,7 +330,8 @@ HEADERS = \ dbLayoutVsSchematicWriter.h \ dbLayoutVsSchematicReader.h \ dbLayoutVsSchematicFormatDefs.h \ - dbLayoutVsSchematic.h + dbLayoutVsSchematic.h \ + dbNetlistObject.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbCircuit.cc b/src/db/db/dbCircuit.cc index f608a9f77..1ca2d79c7 100644 --- a/src/db/db/dbCircuit.cc +++ b/src/db/db/dbCircuit.cc @@ -33,7 +33,7 @@ namespace db // Circuit class implementation Circuit::Circuit () - : m_dont_purge (false), m_cell_index (0), mp_netlist (0), + : db::NetlistObject (), gsi::ObjectBase (), m_dont_purge (false), m_cell_index (0), mp_netlist (0), m_device_by_id (this, &Circuit::begin_devices, &Circuit::end_devices), m_subcircuit_by_id (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits), m_net_by_cluster_id (this, &Circuit::begin_nets, &Circuit::end_nets), @@ -48,7 +48,7 @@ Circuit::Circuit () } Circuit::Circuit (const db::Layout &layout, db::cell_index_type ci) - : m_name (layout.cell_name (ci)), m_dont_purge (false), m_cell_index (ci), mp_netlist (0), + : db::NetlistObject (), gsi::ObjectBase (), m_name (layout.cell_name (ci)), m_dont_purge (false), m_cell_index (ci), mp_netlist (0), m_device_by_id (this, &Circuit::begin_devices, &Circuit::end_devices), m_subcircuit_by_id (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits), m_net_by_cluster_id (this, &Circuit::begin_nets, &Circuit::end_nets), @@ -65,7 +65,7 @@ Circuit::Circuit (const db::Layout &layout, db::cell_index_type ci) } Circuit::Circuit (const Circuit &other) - : gsi::ObjectBase (other), tl::Object (other), m_dont_purge (false), m_cell_index (0), mp_netlist (0), + : db::NetlistObject (other), gsi::ObjectBase (other), m_dont_purge (false), m_cell_index (0), mp_netlist (0), m_device_by_id (this, &Circuit::begin_devices, &Circuit::end_devices), m_subcircuit_by_id (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits), m_net_by_cluster_id (this, &Circuit::begin_nets, &Circuit::end_nets), @@ -95,6 +95,8 @@ Circuit &Circuit::operator= (const Circuit &other) { if (this != &other) { + db::NetlistObject::operator= (other); + clear (); m_name = other.m_name; @@ -290,6 +292,13 @@ void Circuit::clear_pins () m_pins.clear (); } +const Pin &Circuit::add_pin (const Pin &pin) +{ + m_pins.push_back (pin); + m_pins.back ().set_id (m_pins.size () - 1); + return m_pins.back (); +} + const Pin &Circuit::add_pin (const std::string &name) { m_pins.push_back (Pin (name)); diff --git a/src/db/db/dbCircuit.h b/src/db/db/dbCircuit.h index 3092fb6cd..c8bcac695 100644 --- a/src/db/db/dbCircuit.h +++ b/src/db/db/dbCircuit.h @@ -86,7 +86,7 @@ public: * devices. */ class DB_PUBLIC Circuit - : public gsi::ObjectBase, public tl::Object + : public db::NetlistObject, public gsi::ObjectBase { public: typedef tl::vector pin_list; @@ -324,6 +324,12 @@ public: */ const Pin &add_pin (const std::string &name); + /** + * @brief Adds a pin to this circuit + * This version uses the given pin as the template. + */ + const Pin &add_pin (const Pin &pin); + /** * @brief Begin iterator for the pins of the circuit (non-const version) */ @@ -353,6 +359,14 @@ public: */ const Pin *pin_by_id (size_t id) const; + /** + * @brief Gets the pin by ID (the ID is basically the index) - non-const version + */ + Pin *pin_by_id (size_t id) + { + return const_cast (((const db::Circuit *) this)->pin_by_id (id)); + } + /** * @brief Gets the pin by name * @@ -361,6 +375,14 @@ public: */ const Pin *pin_by_name (const std::string &name) const; + /** + * @brief Gets the pin by name - non-const version + */ + Pin *pin_by_name (const std::string &name) + { + return const_cast (((const db::Circuit *) this)->pin_by_name (name)); + } + /** * @brief Begin iterator for the pins of the circuit (const version) */ diff --git a/src/db/db/dbDevice.cc b/src/db/db/dbDevice.cc index ca950ad2e..a1c0dbf34 100644 --- a/src/db/db/dbDevice.cc +++ b/src/db/db/dbDevice.cc @@ -31,7 +31,7 @@ namespace db // Device class implementation Device::Device () - : mp_device_class (0), mp_device_abstract (0), m_id (0), mp_circuit (0) + : db::NetlistObject (), mp_device_class (0), mp_device_abstract (0), m_id (0), mp_circuit (0) { // .. nothing yet .. } @@ -46,19 +46,19 @@ Device::~Device () } Device::Device (DeviceClass *device_class, const std::string &name) - : mp_device_class (device_class), mp_device_abstract (0), m_name (name), m_id (0), mp_circuit (0) + : db::NetlistObject (), mp_device_class (device_class), mp_device_abstract (0), m_name (name), m_id (0), mp_circuit (0) { // .. nothing yet .. } Device::Device (DeviceClass *device_class, DeviceAbstract *device_abstract, const std::string &name) - : mp_device_class (device_class), mp_device_abstract (device_abstract), m_name (name), m_id (0), mp_circuit (0) + : db::NetlistObject (), mp_device_class (device_class), mp_device_abstract (device_abstract), m_name (name), m_id (0), mp_circuit (0) { // .. nothing yet .. } Device::Device (const Device &other) - : tl::Object (other), mp_device_class (0), mp_device_abstract (0), m_id (0), mp_circuit (0) + : db::NetlistObject (other), mp_device_class (0), mp_device_abstract (0), m_id (0), mp_circuit (0) { operator= (other); } @@ -66,6 +66,7 @@ Device::Device (const Device &other) Device &Device::operator= (const Device &other) { if (this != &other) { + db::NetlistObject::operator= (other); m_name = other.m_name; m_trans = other.m_trans; m_parameters = other.m_parameters; diff --git a/src/db/db/dbDevice.h b/src/db/db/dbDevice.h index 7e6b8af3e..f93058369 100644 --- a/src/db/db/dbDevice.h +++ b/src/db/db/dbDevice.h @@ -95,7 +95,7 @@ struct DeviceAbstractRef * a specific device class. */ class DB_PUBLIC Device - : public tl::Object + : public db::NetlistObject { public: typedef std::vector > global_connections; diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index b30dfb26a..f33bd4286 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -814,11 +814,20 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout & db::properties_id_type LayoutToNetlist::make_netname_propid (db::Layout &ly, const tl::Variant &netname_prop, const db::Net &net) const { - if (! netname_prop.is_nil ()) { + if (! netname_prop.is_nil () || net.begin_properties () != net.end_properties ()) { - db::property_names_id_type name_propnameid = ly.properties_repository ().prop_name_id (netname_prop); db::PropertiesRepository::properties_set propset; - propset.insert (std::make_pair (name_propnameid, tl::Variant (net.expanded_name ()))); + + // add the user properties too (TODO: make this configurable?) + for (db::Net::property_iterator p = net.begin_properties (); p != net.end_properties (); ++p) { + db::property_names_id_type key_propnameid = ly.properties_repository ().prop_name_id (p->first); + propset.insert (std::make_pair (key_propnameid, p->second)); + } + + if (! netname_prop.is_nil ()) { + db::property_names_id_type name_propnameid = ly.properties_repository ().prop_name_id (netname_prop); + propset.insert (std::make_pair (name_propnameid, tl::Variant (net.expanded_name ()))); + } return ly.properties_repository ().properties_id (propset); diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.cc b/src/db/db/dbLayoutToNetlistFormatDefs.cc index eabcaa83a..ce6532619 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.cc +++ b/src/db/db/dbLayoutToNetlistFormatDefs.cc @@ -43,6 +43,7 @@ namespace l2n_std_format DB_PUBLIC std::string LongKeys::circuit_key ("circuit"); DB_PUBLIC std::string LongKeys::net_key ("net"); DB_PUBLIC std::string LongKeys::name_key ("name"); + DB_PUBLIC std::string LongKeys::property_key ("property"); DB_PUBLIC std::string LongKeys::device_key ("device"); DB_PUBLIC std::string LongKeys::polygon_key ("polygon"); DB_PUBLIC std::string LongKeys::rect_key ("rect"); @@ -55,7 +56,7 @@ namespace l2n_std_format DB_PUBLIC std::string LongKeys::scale_key ("scale"); DB_PUBLIC std::string LongKeys::pin_key ("pin"); - // A, B, C, D, E, G, I, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y + // A, B, C, D, E, F, G, I, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y DB_PUBLIC std::string ShortKeys::version_key ("V"); DB_PUBLIC std::string ShortKeys::description_key ("B"); DB_PUBLIC std::string ShortKeys::top_key ("W"); @@ -67,6 +68,7 @@ namespace l2n_std_format DB_PUBLIC std::string ShortKeys::circuit_key ("X"); DB_PUBLIC std::string ShortKeys::net_key ("N"); DB_PUBLIC std::string ShortKeys::name_key ("I"); + DB_PUBLIC std::string ShortKeys::property_key ("F"); DB_PUBLIC std::string ShortKeys::device_key ("D"); DB_PUBLIC std::string ShortKeys::polygon_key ("Q"); DB_PUBLIC std::string ShortKeys::rect_key ("R"); diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h index 8d70abcbc..f0b595290 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.h +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -66,7 +66,9 @@ namespace db * * [boundary-def] * - * net( [name]? [geometry-def]*) + * [property-def]* + * + * net( [name]? [property-def]* [geometry-def]*) * - net geometry [short key: N] * A net declaration shall be there also if no geometry * is present. The ID is a numerical shortcut for the net. @@ -103,6 +105,14 @@ namespace db * * name() - specify net name [short key: I] * + * [property-def]: + * + * property( ) + * - specifies a property value/key pair [short key: F] + * prop-name and prop-value are variant specifications + * in klayout notation: #x is an integer, ##y a floating-point + * value, a word or quoted literal is a string. + * * [geometry-def]: * * polygon( [coord] ...) - defines a polygon [short key: Q] @@ -123,24 +133,26 @@ namespace db * * [device-def]: * - * [trans-def] - location of the device [short key Y] + * [property-def]* - user properties + * [trans-def] - location of the device * must be before terminal - * param( ) - defines a parameter [short key E] + * param( ) - defines a parameter [short key: E] * terminal( ) * - specifies connection of the terminal with * a net (short key: T) * * [subcircuit-def]: * - * [trans-def] - location of the subcircuit [short key Y] + * [property-def]* - user properties + * [trans-def] - location of the subcircuit * pin( ) - specifies connection of the pin with a net [short key: P] * * [trans-def]: * - * location( ) - location of the instance [short key Y] - * rotation() - rotation angle (in degree, default is 0) [short key O] - * mirror - if specified, the instance is mirrored before rotation [short key M] - * scale() - magnification (default is 1) [short key S] + * location( ) - location of the instance [short key: Y] + * rotation() - rotation angle (in degree, default is 0) [short key: O] + * mirror - if specified, the instance is mirrored before rotation [short key: M] + * scale() - magnification (default is 1) [short key: S] */ namespace l2n_std_format @@ -160,6 +172,7 @@ namespace l2n_std_format static std::string circuit_key; static std::string net_key; static std::string name_key; + static std::string property_key; static std::string device_key; static std::string subcircuit_key; static std::string polygon_key; @@ -191,6 +204,7 @@ namespace l2n_std_format static std::string circuit_key; static std::string net_key; static std::string name_key; + static std::string property_key; static std::string device_key; static std::string subcircuit_key; static std::string polygon_key; diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc index 5cfa6ac49..0c073aaf6 100644 --- a/src/db/db/dbLayoutToNetlistReader.cc +++ b/src/db/db/dbLayoutToNetlistReader.cc @@ -305,7 +305,9 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo while (br) { - if (test (skeys::rect_key) || test (lkeys::rect_key)) { + if (test (skeys::property_key) || test (lkeys::property_key)) { + read_property (circuit); + } else if (test (skeys::rect_key) || test (lkeys::rect_key)) { circuit->set_boundary (db::DPolygon (dbu * read_rect ())); } else if (test (skeys::polygon_key) || test (lkeys::polygon_key)) { circuit->set_boundary (read_polygon ().transformed (dbu)); @@ -423,6 +425,22 @@ LayoutToNetlistStandardReader::read_point () return m_ref; } +void +LayoutToNetlistStandardReader::read_property (db::NetlistObject *obj) +{ + Brace br (this); + + tl::Variant k, v; + m_ex.read (k); + m_ex.read (v); + + if (obj) { + obj->set_property (k, v); + } + + br.done (); +} + std::pair LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n) { @@ -502,14 +520,18 @@ LayoutToNetlistStandardReader::read_polygon () } void -LayoutToNetlistStandardReader::read_geometries (Brace &br, db::LayoutToNetlist *l2n, db::local_cluster &lc, db::Cell &cell) +LayoutToNetlistStandardReader::read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster &lc, db::Cell &cell) { m_ref = db::Point (); while (br) { - std::pair pr = read_geometry (l2n); - lc.add (pr.second, pr.first); - cell.shapes (pr.first).insert (pr.second); + if (test (skeys::property_key) || test (lkeys::property_key)) { + read_property (obj); + } else { + std::pair pr = read_geometry (l2n); + lc.add (pr.second, pr.first); + cell.shapes (pr.first).insert (pr.second); + } } } @@ -540,7 +562,7 @@ LayoutToNetlistStandardReader::read_net (db::Netlist * /*netlist*/, db::LayoutTo net->set_cluster_id (lc.id ()); db::Cell &cell = l2n->internal_layout ()->cell (circuit->cell_index ()); - read_geometries (br, l2n, lc, cell); + read_geometries (net, br, l2n, lc, cell); } @@ -552,21 +574,28 @@ LayoutToNetlistStandardReader::read_pin (db::Netlist * /*netlist*/, db::LayoutTo { Brace br (this); - std::string name; db::Net *net = 0; + db::Pin pin; + while (br) { if (test (skeys::name_key) || test (lkeys::name_key)) { - if (!name.empty ()) { + if (! pin.name ().empty ()) { throw tl::Exception (tl::to_string (tr ("Duplicate pin name"))); } Brace br_name (this); - read_word_or_quoted (name); + std::string n; + read_word_or_quoted (n); + pin.set_name (n); br_name.done (); + } else if (test (skeys::property_key) || test (lkeys::property_key)) { + + read_property (&pin); + } else { if (net) { @@ -583,9 +612,9 @@ LayoutToNetlistStandardReader::read_pin (db::Netlist * /*netlist*/, db::LayoutTo } - const db::Pin &pin = circuit->add_pin (name); + size_t pin_id = circuit->add_pin (pin).id (); if (net) { - circuit->connect_pin (pin.id (), net); + circuit->connect_pin (pin_id, net); } br.done (); @@ -657,6 +686,10 @@ LayoutToNetlistStandardReader::read_device (db::Netlist *netlist, db::LayoutToNe // .. nothing yet .. + } else if (test (skeys::property_key) || test (lkeys::property_key)) { + + read_property (device.get ()); + } else if (test (skeys::device_key) || test (lkeys::device_key)) { std::string n; @@ -900,6 +933,10 @@ LayoutToNetlistStandardReader::read_subcircuit (db::Netlist *netlist, db::Layout // .. nothing yet .. + } else if (test (skeys::property_key) || test (lkeys::property_key)) { + + read_property (subcircuit.get ()); + } else if (test (skeys::pin_key) || test (lkeys::pin_key)) { Brace br2 (this); @@ -989,7 +1026,7 @@ LayoutToNetlistStandardReader::read_abstract_terminal (db::LayoutToNetlist *l2n, dm->set_cluster_id_for_terminal (tid, lc.id ()); db::Cell &cell = l2n->internal_layout ()->cell (dm->cell_index ()); - read_geometries (br, l2n, lc, cell); + read_geometries (0, br, l2n, lc, cell); } diff --git a/src/db/db/dbLayoutToNetlistReader.h b/src/db/db/dbLayoutToNetlistReader.h index 5d256c84e..db2c9d665 100644 --- a/src/db/db/dbLayoutToNetlistReader.h +++ b/src/db/db/dbLayoutToNetlistReader.h @@ -140,9 +140,10 @@ protected: bool read_trans_part (db::DCplxTrans &tr); void read_abstract_terminal (db::LayoutToNetlist *l2n, db::DeviceAbstract *dm, db::DeviceClass *dc); std::pair read_geometry (db::LayoutToNetlist *l2n); + void read_property (db::NetlistObject *obj); db::Polygon read_polygon (); db::Box read_rect (); - void read_geometries (Brace &br, db::LayoutToNetlist *l2n, db::local_cluster &lc, db::Cell &cell); + void read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster &lc, db::Cell &cell); db::Point read_point (); private: diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index b36eaf9ba..fad0c3a9f 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -278,6 +278,13 @@ void std_writer_impl::write (const db::Netlist *netlist, const db::LayoutT } + for (db::NetlistObject::property_iterator p = circuit.begin_properties (); p != circuit.end_properties (); ++p) { + if (p == circuit.begin_properties() && ! Keys::is_short ()) { + *mp_stream << endl << indent << indent1 << "# Properties" << endl; + } + *mp_stream << indent << indent1 << Keys::property_key << "(" << p->first.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl; + } + std::map net2id_local; std::map *net2id = &net2id_local; if (net2id_per_circuit) { @@ -416,12 +423,19 @@ void std_writer_impl::write (const db::Netlist *netlist, const db::LayoutT } else { if (! any) { + *mp_stream << indent << indent1 << Keys::net_key << "(" << id; if (! net.name ().empty ()) { *mp_stream << " " << Keys::name_key << "(" << tl::to_word_or_quoted_string (net.name ()) << ")"; } *mp_stream << endl; + + for (db::NetlistObject::property_iterator p = net.begin_properties (); p != net.end_properties (); ++p) { + *mp_stream << indent << indent2 << Keys::property_key << "(" << p->first.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl; + } + any = true; + } *mp_stream << indent << indent2; @@ -449,7 +463,15 @@ void std_writer_impl::write (const db::Netlist *netlist, const db::LayoutT if (! net.name ().empty ()) { *mp_stream << " " << Keys::name_key << "(" << tl::to_word_or_quoted_string (net.name ()) << ")"; } - *mp_stream << ")" << endl; + if (net.begin_properties () != net.end_properties ()) { + *mp_stream << endl; + for (db::NetlistObject::property_iterator p = net.begin_properties (); p != net.end_properties (); ++p) { + *mp_stream << indent << indent2 << Keys::property_key << "(" << p->first.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl; + } + *mp_stream << indent << ")" << endl; + } else { + *mp_stream << ")" << endl; + } } } @@ -470,12 +492,16 @@ void std_writer_impl::write (const db::LayoutToNetlist *l2n, const db::Sub } // each pin in one line for more than a few pins - bool separate_lines = (subcircuit.circuit_ref ()->pin_count () > 1); + bool separate_lines = (subcircuit.circuit_ref ()->pin_count () > 1) || subcircuit.begin_properties () != subcircuit.end_properties (); if (separate_lines) { *mp_stream << endl; } + for (db::NetlistObject::property_iterator p = subcircuit.begin_properties (); p != subcircuit.end_properties (); ++p) { + *mp_stream << indent << indent2 << Keys::property_key << "(" << p->first.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl; + } + for (db::Circuit::const_pin_iterator p = subcircuit.circuit_ref ()->begin_pins (); p != subcircuit.circuit_ref ()->end_pins (); ++p) { const db::Net *net = subcircuit.net_for_pin (p->id ()); if (net) { @@ -614,6 +640,10 @@ void std_writer_impl::write (const db::LayoutToNetlist * /*l2n*/, const db *mp_stream << indent << indent2 << Keys::name_key << "(" << tl::to_word_or_quoted_string (device.name ()) << ")" << endl; } + for (db::NetlistObject::property_iterator p = device.begin_properties (); p != device.end_properties (); ++p) { + *mp_stream << indent << indent2 << Keys::property_key << "(" << p->first.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl; + } + for (std::vector::const_iterator i = pd.begin (); i != pd.end (); ++i) { *mp_stream << indent << indent2 << Keys::param_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << tl::sprintf ("%.12g", device.parameter_value (i->id ())) << ")" << endl; } diff --git a/src/db/db/dbNet.cc b/src/db/db/dbNet.cc index 69f085817..b4e14b59d 100644 --- a/src/db/db/dbNet.cc +++ b/src/db/db/dbNet.cc @@ -155,19 +155,19 @@ const Pin *NetSubcircuitPinRef::pin () const // Net class implementation Net::Net () - : m_cluster_id (0), mp_circuit (0) + : NetlistObject (), m_cluster_id (0), mp_circuit (0) { // .. nothing yet .. } Net::Net (const std::string &name) - : m_cluster_id (0), mp_circuit (0) + : NetlistObject (), m_cluster_id (0), mp_circuit (0) { m_name = name; } Net::Net (const Net &other) - : tl::Object (other), m_cluster_id (0), mp_circuit (0) + : NetlistObject (other), m_cluster_id (0), mp_circuit (0) { operator= (other); } @@ -176,6 +176,8 @@ Net &Net::operator= (const Net &other) { if (this != &other) { + db::NetlistObject::operator= (other); + clear (); m_name = other.m_name; diff --git a/src/db/db/dbNet.h b/src/db/db/dbNet.h index 25e19324f..532b2f9a3 100644 --- a/src/db/db/dbNet.h +++ b/src/db/db/dbNet.h @@ -24,6 +24,7 @@ #define _HDR_dbNet #include "dbCommon.h" +#include "dbNetlistObject.h" #include "tlObject.h" @@ -360,7 +361,7 @@ private: * A net connects terminals of devices and pins or circuits */ class DB_PUBLIC Net - : public tl::Object + : public db::NetlistObject { public: typedef std::list terminal_list; diff --git a/src/db/db/dbNetlistObject.cc b/src/db/db/dbNetlistObject.cc new file mode 100644 index 000000000..522417b0d --- /dev/null +++ b/src/db/db/dbNetlistObject.cc @@ -0,0 +1,114 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "dbNetlistObject.h" + +namespace db +{ + +NetlistObject::NetlistObject () + : tl::Object (), mp_properties (0) +{ + // .. nothing yet .. +} + +NetlistObject::NetlistObject (const db::NetlistObject &other) + : tl::Object (other), mp_properties (0) +{ + if (other.mp_properties) { + mp_properties = new std::map (*other.mp_properties); + } +} + +NetlistObject::~NetlistObject () +{ + delete mp_properties; + mp_properties = 0; +} + +NetlistObject &NetlistObject::operator= (const NetlistObject &other) +{ + if (this != &other) { + + tl::Object::operator= (other); + + delete mp_properties; + mp_properties = 0; + + if (other.mp_properties) { + mp_properties = new std::map (*other.mp_properties); + } + + } + return *this; +} + +tl::Variant NetlistObject::property (const tl::Variant &key) const +{ + if (! mp_properties) { + return tl::Variant (); + } + + std::map::const_iterator i = mp_properties->find (key); + if (i == mp_properties->end ()) { + return tl::Variant (); + } else { + return i->second; + } +} + +void +NetlistObject::set_property (const tl::Variant &key, const tl::Variant &value) +{ + if (value.is_nil ()) { + + if (mp_properties) { + mp_properties->erase (key); + if (mp_properties->empty ()) { + delete mp_properties; + mp_properties = 0; + } + } + + } else { + if (! mp_properties) { + mp_properties = new std::map (); + } + (*mp_properties) [key] = value; + } +} + +static NetlistObject::property_table empty_properties; + +NetlistObject::property_iterator +NetlistObject::begin_properties () const +{ + return mp_properties ? mp_properties->begin () : empty_properties.begin (); +} + +NetlistObject::property_iterator +NetlistObject::end_properties () const +{ + return mp_properties ? mp_properties->end () : empty_properties.end (); +} + +} diff --git a/src/db/db/dbNetlistObject.h b/src/db/db/dbNetlistObject.h new file mode 100644 index 000000000..d1dac4891 --- /dev/null +++ b/src/db/db/dbNetlistObject.h @@ -0,0 +1,94 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef _HDR_dbNetlistObject +#define _HDR_dbNetlistObject + +#include "dbCommon.h" +#include "tlObject.h" +#include "tlVariant.h" + +#include +#include + +namespace db +{ + +/** + * @brief A base class for a objects in the netlist + */ +class DB_PUBLIC NetlistObject + : public tl::Object +{ +public: + typedef std::map property_table; + typedef property_table::const_iterator property_iterator; + + /** + * @brief Default constructor + */ + NetlistObject (); + + /** + * @brief Copy constructor + */ + NetlistObject (const db::NetlistObject &object); + + /** + * @brief Destructor + */ + ~NetlistObject (); + + /** + * @brief Assignment + */ + NetlistObject &operator= (const NetlistObject &other); + + /** + * @brief Gets the property value for a given key + * Returns nil if there is no property for the given key. + */ + tl::Variant property (const tl::Variant &key) const; + + /** + * @brief Sets the property value for a given key + * Set the value to nil to clear a specific key + */ + void set_property (const tl::Variant &key, const tl::Variant &value); + + /** + * @brief Iterator for the netlist properties (begin) + */ + property_iterator begin_properties () const; + + /** + * @brief Iterator for the netlist properties (end) + */ + property_iterator end_properties () const; + +private: + property_table *mp_properties; +}; + +} + +#endif diff --git a/src/db/db/dbPin.cc b/src/db/db/dbPin.cc index e223ec8ae..0e1a0e3d8 100644 --- a/src/db/db/dbPin.cc +++ b/src/db/db/dbPin.cc @@ -30,13 +30,13 @@ namespace db // Pin class implementation Pin::Pin () - : m_id (0) + : db::NetlistObject (), m_id (0) { // .. nothing yet .. } Pin::Pin (const std::string &name) - : m_name (name), m_id (0) + : db::NetlistObject (), m_name (name), m_id (0) { // .. nothing yet .. } diff --git a/src/db/db/dbPin.h b/src/db/db/dbPin.h index 1c9dd9714..ed77d701f 100644 --- a/src/db/db/dbPin.h +++ b/src/db/db/dbPin.h @@ -24,6 +24,7 @@ #define _HDR_dbPin #include "dbCommon.h" +#include "dbNetlistObject.h" #include @@ -36,6 +37,7 @@ namespace db * A pin is some place other nets can connect to a circuit. */ class DB_PUBLIC Pin + : public db::NetlistObject { public: /** @@ -70,6 +72,15 @@ public: return m_id; } + /** + * @brief Sets the name of the pin + * CAUTION: don't use this method on pins stored inside a netlist. + */ + void set_name (const std::string &name) + { + m_name = name; + } + private: friend class Circuit; @@ -80,11 +91,6 @@ private: { m_id = id; } - - void set_name (const std::string &name) - { - m_name = name; - } }; } diff --git a/src/db/db/dbSubCircuit.cc b/src/db/db/dbSubCircuit.cc index 4db7dfa6c..78c123992 100644 --- a/src/db/db/dbSubCircuit.cc +++ b/src/db/db/dbSubCircuit.cc @@ -30,7 +30,7 @@ namespace db // SubCircuit class implementation SubCircuit::SubCircuit () - : m_id (0), mp_circuit (0) + : db::NetlistObject (), m_id (0), mp_circuit (0) { // .. nothing yet .. } @@ -45,13 +45,13 @@ SubCircuit::~SubCircuit() } SubCircuit::SubCircuit (Circuit *circuit, const std::string &name) - : m_circuit_ref (0), m_name (name), m_id (0), mp_circuit (0) + : db::NetlistObject (), m_circuit_ref (0), m_name (name), m_id (0), mp_circuit (0) { set_circuit_ref (circuit); } SubCircuit::SubCircuit (const SubCircuit &other) - : tl::Object (other), m_id (0), mp_circuit (0) + : db::NetlistObject (other), m_id (0), mp_circuit (0) { operator= (other); } @@ -59,6 +59,7 @@ SubCircuit::SubCircuit (const SubCircuit &other) SubCircuit &SubCircuit::operator= (const SubCircuit &other) { if (this != &other) { + db::NetlistObject::operator= (other); m_name = other.m_name; m_trans = other.m_trans; set_circuit_ref (const_cast (other.circuit_ref ())); diff --git a/src/db/db/dbSubCircuit.h b/src/db/db/dbSubCircuit.h index 6a25001c0..970581fa5 100644 --- a/src/db/db/dbSubCircuit.h +++ b/src/db/db/dbSubCircuit.h @@ -43,7 +43,7 @@ class Circuit; * This class essentially is a reference to another circuit */ class DB_PUBLIC SubCircuit - : public tl::Object + : public db::NetlistObject { public: typedef tl::vector connected_net_list; diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index 85f985571..6d2ca28cd 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -34,7 +34,33 @@ namespace gsi { -Class decl_dbPin ("db", "Pin", +static std::vector property_keys (const db::NetlistObject *object) +{ + std::vector v; + for (db::NetlistObject::property_iterator p = object->begin_properties (); p != object->end_properties (); ++p) { + v.push_back (p->first); + } + return v; +} + +Class decl_dbNetlistObject ("db", "NetlistObject", + gsi::method ("property", &db::NetlistObject::property, gsi::arg ("key"), + "@brief Gets the property value for the given key or nil if there is no value with this key." + ) + + gsi::method ("set_property", &db::NetlistObject::set_property, gsi::arg ("key"), gsi::arg ("value"), + "@brief Sets the property value for the given key.\n" + "Use a nil value to erase the property with this key." + ) + + gsi::method_ext ("property_keys", &property_keys, + "@brief Gets the keys for the properties stored in this object." + ), + "@brief The base class for some netlist objects.\n" + "The main purpose of this class is to supply user properties for netlist objects.\n" + "\n" + "This class has been introduced in version 0.26.2" +); + +Class decl_dbPin (decl_dbNetlistObject, "db", "Pin", gsi::method ("id", &db::Pin::id, "@brief Gets the ID of the pin.\n" ) + @@ -225,7 +251,7 @@ static void add_other_abstracts (db::Device *device, const db::DeviceAbstractRef device->other_abstracts ().push_back (ref); } -Class decl_dbDevice ("db", "Device", +Class decl_dbDevice (decl_dbNetlistObject, "db", "Device", gsi::method ("device_class", &db::Device::device_class, "@brief Gets the device class the device belongs to.\n" ) + @@ -397,7 +423,7 @@ static void subcircuit_disconnect_pin1 (db::SubCircuit *subcircuit, const db::Pi } } -Class decl_dbSubCircuit ("db", "SubCircuit", +Class decl_dbSubCircuit (decl_dbNetlistObject, "db", "SubCircuit", gsi::method ("circuit_ref", (const db::Circuit *(db::SubCircuit::*) () const) &db::SubCircuit::circuit_ref, "@brief Gets the circuit referenced by the subcircuit.\n" ) + @@ -516,7 +542,7 @@ Class decl_dbNetSubcircuitPinRef ("db", "NetSubcircuitP "This class has been added in version 0.26." ); -Class decl_dbNet ("db", "Net", +Class decl_dbNet (decl_dbNetlistObject, "db", "Net", gsi::method ("circuit", (db::Circuit *(db::Net::*) ()) &db::Net::circuit, "@brief Gets the circuit the net lives in." ) + @@ -1098,8 +1124,8 @@ static void circuit_disconnect_pin1 (db::Circuit *c, const db::Pin *pin) } } -Class decl_dbCircuit ("db", "Circuit", - gsi::method ("create_pin", &db::Circuit::add_pin, gsi::arg ("name"), +Class decl_dbCircuit (decl_dbNetlistObject, "db", "Circuit", + gsi::method ("create_pin", (const db::Pin &(db::Circuit::*) (const std::string &)) &db::Circuit::add_pin, gsi::arg ("name"), "@brief Creates a new \\Pin object inside the circuit\n" "This object will describe a pin of the circuit. A circuit connects " "to the outside through such a pin. The pin is added after all existing " @@ -1147,11 +1173,11 @@ Class decl_dbCircuit ("db", "Circuit", "@brief Gets the net object for a given name.\n" "If the ID is not a valid net name, nil is returned." ) + - gsi::method ("pin_by_id", &db::Circuit::pin_by_id, gsi::arg ("id"), + gsi::method ("pin_by_id", (db::Pin *(db::Circuit::*) (size_t)) &db::Circuit::pin_by_id, gsi::arg ("id"), "@brief Gets the \\Pin object corresponding to a specific ID\n" "If the ID is not a valid pin ID, nil is returned." ) + - gsi::method ("pin_by_name", &db::Circuit::pin_by_name, gsi::arg ("name"), + gsi::method ("pin_by_name", (db::Pin *(db::Circuit::*) (const std::string &)) &db::Circuit::pin_by_name, gsi::arg ("name"), "@brief Gets the \\Pin object corresponding to a specific name\n" "If the ID is not a valid pin name, nil is returned." ) + diff --git a/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc index 5f637911d..cc3c0fb90 100644 --- a/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc @@ -254,7 +254,7 @@ TEST(1b_ReaderBasicShort) // verify against the input - std::string path = tmp_file ("tmp_l2nreader_2.txt"); + std::string path = tmp_file ("tmp.txt"); { tl::OutputStream stream (path); db::LayoutToNetlistStandardWriter writer (stream, true); @@ -266,6 +266,60 @@ TEST(1b_ReaderBasicShort) compare_text_files (path, au_path); } +TEST(1c_ReaderBasicShortWithProps) +{ + db::LayoutToNetlist l2n; + + std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_p.txt"); + tl::InputStream is_in (in_path); + + db::LayoutToNetlistStandardReader reader (is_in); + reader.read (&l2n); + + // verify against the input + + std::string path = tmp_file ("tmp.txt"); + { + tl::OutputStream stream (path); + db::LayoutToNetlistStandardWriter writer (stream, true); + writer.write (&l2n); + } + + std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_p.txt"); + + compare_text_files (path, au_path); + + { + db::Layout ly2; + ly2.dbu (l2n.internal_layout ()->dbu ()); + db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP")); + + std::map lmap; + lmap [ly2.insert_layer (db::LayerProperties (3, 0))] = l2n.layer_by_name ("poly"); + lmap [ly2.insert_layer (db::LayerProperties (3, 1))] = l2n.layer_by_name ("poly_lbl"); + lmap [ly2.insert_layer (db::LayerProperties (4, 0))] = l2n.layer_by_name ("diff_cont"); + lmap [ly2.insert_layer (db::LayerProperties (5, 0))] = l2n.layer_by_name ("poly_cont"); + lmap [ly2.insert_layer (db::LayerProperties (6, 0))] = l2n.layer_by_name ("metal1"); + lmap [ly2.insert_layer (db::LayerProperties (6, 1))] = l2n.layer_by_name ("metal1_lbl"); + lmap [ly2.insert_layer (db::LayerProperties (7, 0))] = l2n.layer_by_name ("via1"); + lmap [ly2.insert_layer (db::LayerProperties (8, 0))] = l2n.layer_by_name ("metal2"); + lmap [ly2.insert_layer (db::LayerProperties (8, 1))] = l2n.layer_by_name ("metal2_lbl"); + lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = l2n.layer_by_name ("psd"); + lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = l2n.layer_by_name ("nsd"); + + db::CellMapping cm = l2n.cell_mapping_into (ly2, top2); + + l2n.build_all_nets (cm, ly2, lmap, "NET_", tl::Variant (), db::LayoutToNetlist::BNH_Disconnected, 0, "DEVICE_"); + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "l2n_writer_au_p.oas"); + + db::compare_layouts (_this, ly2, au, db::WriteOAS); + } +} + TEST(2_ReaderWithGlobalNets) { db::LayoutToNetlist l2n; @@ -278,7 +332,7 @@ TEST(2_ReaderWithGlobalNets) // verify against the input - std::string path = tmp_file ("tmp_l2nreader_2.txt"); + std::string path = tmp_file ("tmp.txt"); { tl::OutputStream stream (path); db::LayoutToNetlistStandardWriter writer (stream, false); @@ -335,7 +389,7 @@ TEST(3_ReaderAbsoluteCoordinates) // verify against the input - std::string path = tmp_file ("tmp_l2nreader_2.txt"); + std::string path = tmp_file ("tmp.txt"); { tl::OutputStream stream (path); db::LayoutToNetlistStandardWriter writer (stream, false); @@ -394,7 +448,7 @@ TEST(4_ReaderCombinedDevices) // verify against the input - std::string path = tmp_file ("tmp_l2nreader_4.txt"); + std::string path = tmp_file ("tmp.txt"); { tl::OutputStream stream (path); db::LayoutToNetlistStandardWriter writer (stream, false); diff --git a/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc b/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc index 2db34248d..9fca0b5fd 100644 --- a/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc @@ -217,6 +217,33 @@ TEST(1_WriterBasic) db::compare_layouts (_this, ly2, au); } + + l2n.netlist ()->begin_circuits ()->set_property (17, 42); + l2n.netlist ()->begin_circuits ()->set_property ("a_float", 0.5); + l2n.netlist ()->begin_circuits ()->set_property ("a_\"non_quoted\"_string", "s"); + + l2n.netlist ()->begin_circuits ()->begin_nets ()->set_property (17, 142); + l2n.netlist ()->begin_circuits ()->begin_nets ()->set_property ("a_float", 10.5); + l2n.netlist ()->begin_circuits ()->begin_nets ()->set_property ("a_\"non_quoted\"_string", "1s"); + + l2n.netlist ()->circuit_by_name ("INV2")->begin_devices ()->set_property (17, 242); + l2n.netlist ()->circuit_by_name ("INV2")->begin_devices ()->set_property ("a_float", 20.5); + l2n.netlist ()->circuit_by_name ("INV2")->begin_devices ()->set_property ("a_\"non_quoted\"_string", "2s"); + + l2n.netlist ()->circuit_by_name ("RINGO")->begin_subcircuits ()->set_property (17, 342); + l2n.netlist ()->circuit_by_name ("RINGO")->begin_subcircuits ()->set_property ("a_float", 30.5); + l2n.netlist ()->circuit_by_name ("RINGO")->begin_subcircuits ()->set_property ("a_\"non_quoted\"_string", "3s"); + + path = tmp_file ("tmp_l2nwriter_1p.txt"); + { + tl::OutputStream stream (path); + db::LayoutToNetlistStandardWriter writer (stream, true); + writer.write (&l2n); + } + + au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_p.txt"); + + compare_text_files (path, au_path); } TEST(2_WriterWithGlobalNets) diff --git a/src/db/unit_tests/dbNetlistTests.cc b/src/db/unit_tests/dbNetlistTests.cc index 1dc2f196f..c3056e4aa 100644 --- a/src/db/unit_tests/dbNetlistTests.cc +++ b/src/db/unit_tests/dbNetlistTests.cc @@ -344,8 +344,16 @@ TEST(3_CircuitBasic) EXPECT_EQ (c.pin_by_name ("p1")->name (), "p1"); EXPECT_EQ (c.pin_by_name ("doesnt_exist") == 0, true); EXPECT_EQ (c.pin_by_name ("p2")->name (), "p2"); + EXPECT_EQ (c.pin_by_id (0)->begin_properties () == c.pin_by_id (0)->end_properties (), true); + + EXPECT_EQ (c.pin_by_id (0)->property (17).to_string (), "nil"); + c.pin_by_id (0)->set_property (17, 42); + EXPECT_EQ (c.pin_by_id (0)->begin_properties () == c.pin_by_id (0)->end_properties (), false); + EXPECT_EQ (c.pin_by_id (0)->begin_properties ()->second.to_string (), "42"); + EXPECT_EQ (c.pin_by_id (0)->property (17).to_string (), "42"); db::Circuit c2 = c; + EXPECT_EQ (c2.pin_by_id (0)->property (17).to_string (), "42"); EXPECT_EQ (c2.name (), "name"); EXPECT_EQ (pins2string (c), "p1#0,p2#1"); @@ -1419,3 +1427,90 @@ TEST(22_BlankCircuit) "end;\n" ); } + +TEST(23_NetlistObject) +{ + db::NetlistObject nlo; + nlo.set_property (1, "hello"); + EXPECT_EQ (nlo.property ("key").to_string (), "nil"); + EXPECT_EQ (nlo.property (1).to_string (), "hello"); + nlo.set_property ("key", 42); + EXPECT_EQ (nlo.property ("key").to_string (), "42"); + nlo.set_property ("key", tl::Variant ()); + EXPECT_EQ (nlo.property ("key").to_string (), "nil"); + + db::Net net ("net_name"); + net.set_property (1, "hello"); + EXPECT_EQ (net.property ("key").to_string (), "nil"); + EXPECT_EQ (net.property (1).to_string (), "hello"); + + db::Net net2 (net); + EXPECT_EQ (net.property ("key").to_string (), "nil"); + EXPECT_EQ (net.property (1).to_string (), "hello"); + + db::Net net3; + EXPECT_EQ (net3.property ("key").to_string (), "nil"); + EXPECT_EQ (net3.property (1).to_string (), "nil"); + net3 = net2; + EXPECT_EQ (net3.property (1).to_string (), "hello"); + + db::SubCircuit sc; + sc.set_property (1, "hello"); + EXPECT_EQ (sc.property ("key").to_string (), "nil"); + EXPECT_EQ (sc.property (1).to_string (), "hello"); + + db::SubCircuit sc2 (sc); + EXPECT_EQ (sc.property ("key").to_string (), "nil"); + EXPECT_EQ (sc.property (1).to_string (), "hello"); + + db::SubCircuit sc3; + EXPECT_EQ (sc3.property ("key").to_string (), "nil"); + EXPECT_EQ (sc3.property (1).to_string (), "nil"); + sc3 = sc2; + EXPECT_EQ (sc3.property (1).to_string (), "hello"); + + db::Device dev; + dev.set_property (1, "hello"); + EXPECT_EQ (dev.property ("key").to_string (), "nil"); + EXPECT_EQ (dev.property (1).to_string (), "hello"); + + db::Device dev2 (dev); + EXPECT_EQ (dev.property ("key").to_string (), "nil"); + EXPECT_EQ (dev.property (1).to_string (), "hello"); + + db::Device dev3; + EXPECT_EQ (dev3.property ("key").to_string (), "nil"); + EXPECT_EQ (dev3.property (1).to_string (), "nil"); + dev3 = dev2; + EXPECT_EQ (dev3.property (1).to_string (), "hello"); + + db::Circuit circuit; + circuit.set_property (1, "hello"); + EXPECT_EQ (circuit.property ("key").to_string (), "nil"); + EXPECT_EQ (circuit.property (1).to_string (), "hello"); + + db::Circuit circuit2 (circuit); + EXPECT_EQ (circuit.property ("key").to_string (), "nil"); + EXPECT_EQ (circuit.property (1).to_string (), "hello"); + + db::Circuit circuit3; + EXPECT_EQ (circuit3.property ("key").to_string (), "nil"); + EXPECT_EQ (circuit3.property (1).to_string (), "nil"); + circuit3 = circuit2; + EXPECT_EQ (circuit3.property (1).to_string (), "hello"); + + db::Pin pin ("pin_name"); + pin.set_property (1, "hello"); + EXPECT_EQ (pin.property ("key").to_string (), "nil"); + EXPECT_EQ (pin.property (1).to_string (), "hello"); + + db::Pin pin2 (pin); + EXPECT_EQ (pin.property ("key").to_string (), "nil"); + EXPECT_EQ (pin.property (1).to_string (), "hello"); + + db::Pin pin3; + EXPECT_EQ (pin3.property ("key").to_string (), "nil"); + EXPECT_EQ (pin3.property (1).to_string (), "nil"); + pin3 = pin2; + EXPECT_EQ (pin3.property (1).to_string (), "hello"); +} diff --git a/testdata/algo/l2n_writer_au_p.oas b/testdata/algo/l2n_writer_au_p.oas new file mode 100644 index 000000000..4db585331 Binary files /dev/null and b/testdata/algo/l2n_writer_au_p.oas differ diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb index 1a391a0ba..695eb4e38 100644 --- a/testdata/ruby/dbNetlist.rb +++ b/testdata/ruby/dbNetlist.rb @@ -25,6 +25,24 @@ load("test_prologue.rb") class DBNetlist_TestClass < TestBase + def test_0_NetlistObject + + nlo = RBA::NetlistObject::new + assert_equal(nlo.property(17), nil) + assert_equal(nlo.property_keys.inspect, "[]") + nlo.set_property(17, 42) + assert_equal(nlo.property_keys.inspect, "[17]") + assert_equal(nlo.property(17), 42) + + nlo2 = nlo.dup + assert_equal(nlo2.property(17), 42) + nlo.set_property(17, nil) + assert_equal(nlo.property_keys.inspect, "[]") + assert_equal(nlo.property(17), nil) + assert_equal(nlo2.property(17), 42) + + end + def test_1_NetlistBasicCircuit nl = RBA::Netlist::new @@ -141,6 +159,10 @@ class DBNetlist_TestClass < TestBase p1 = c.create_pin("A") p2 = c.create_pin("B") + assert_equal(p1.property(17), nil) + p1.set_property(17, 42) + assert_equal(p1.property(17), 42) + assert_equal(p1.id, 0) assert_equal(p2.id, 1) @@ -188,6 +210,10 @@ class DBNetlist_TestClass < TestBase assert_equal(c.device_by_id(2).inspect, "nil") assert_equal(c.device_by_name("doesnt_exist").inspect, "nil") + assert_equal(d1.property(17), nil) + d1.set_property(17, 42) + assert_equal(d1.property(17), 42) + d2 = c.create_device(dc) assert_equal(d2.device_class.id, dc.id) assert_equal(d2.device_class.object_id, dc.object_id) # by virtue of Ruby-to-C++ object mapping @@ -215,6 +241,10 @@ class DBNetlist_TestClass < TestBase net = c.create_net("NET") + assert_equal(net.property(17), nil) + net.set_property(17, 42) + assert_equal(net.property(17), 42) + assert_equal(net.is_floating?, true) assert_equal(net.is_internal?, false) assert_equal(net.terminal_count, 0) @@ -370,6 +400,10 @@ class DBNetlist_TestClass < TestBase assert_equal(c.subcircuit_by_id(2).inspect, "nil") assert_equal(c.subcircuit_by_name("doesnt_exist").inspect, "nil") + assert_equal(sc1.property(17), nil) + sc1.set_property(17, 42) + assert_equal(sc1.property(17), 42) + refs = [] cc.each_ref { |r| refs << r.name } assert_equal(refs.join(","), "SC1") @@ -564,6 +598,10 @@ class DBNetlist_TestClass < TestBase c.cell_index = 42 assert_equal(c.cell_index, 42) + assert_equal(c.property(17), nil) + c.set_property(17, 42) + assert_equal(c.property(17), 42) + pina1 = c.create_pin("A1") pina2 = c.create_pin("A2") pinb1 = c.create_pin("B1") @@ -581,6 +619,11 @@ class DBNetlist_TestClass < TestBase assert_equal(c.pin_by_id(17).inspect, "nil") assert_equal(c.pin_by_name("DOESNOTEXIST").inspect, "nil") + assert_equal(c.pin_by_id(0).property(17), nil) + c.pin_by_id(0).set_property(17, 42) + assert_equal(c.pin_by_id(0).property(17), 42) + assert_equal(c.pin_by_name("A1").property(17), 42) + names = [] c.each_pin { |p| names << p.name } assert_equal(names, [ "A1", "A2", "B1", "B2" ])