diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index f396b50d7..6e6963f7b 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -176,6 +176,7 @@ void Device::set_parameter_value (const std::string &name, double v) // SubCircuit class implementation SubCircuit::SubCircuit () + : m_id (0) { // .. nothing yet .. } @@ -190,12 +191,13 @@ SubCircuit::~SubCircuit() } SubCircuit::SubCircuit (Circuit *circuit, const std::string &name) - : m_circuit (circuit), m_name (name) + : m_circuit (circuit), m_name (name), m_id (0) { // .. nothing yet .. } SubCircuit::SubCircuit (const SubCircuit &other) + : m_id (0) { operator= (other); } @@ -472,13 +474,13 @@ void Net::set_circuit (Circuit *circuit) // Circuit class implementation Circuit::Circuit () - : mp_netlist (0), m_valid_device_id_table (false) + : mp_netlist (0), m_valid_device_id_table (false), m_valid_subcircuit_id_table (false) { // .. nothing yet .. } Circuit::Circuit (const Circuit &other) - : mp_netlist (0), m_valid_device_id_table (false) + : mp_netlist (0), m_valid_device_id_table (false), m_valid_subcircuit_id_table (false) { operator= (other); } @@ -489,6 +491,7 @@ Circuit &Circuit::operator= (const Circuit &other) m_name = other.m_name; invalidate_device_id_table (); + invalidate_subcircuit_id_table (); for (const_pin_iterator i = other.begin_pins (); i != other.end_pins (); ++i) { add_pin (*i); @@ -560,6 +563,10 @@ void Circuit::clear () m_devices.clear (); m_nets.clear (); m_sub_circuits.clear (); + m_device_id_table.clear (); + m_subcircuit_id_table.clear (); + m_valid_device_id_table = false; + m_valid_subcircuit_id_table = false; } void Circuit::set_name (const std::string &name) @@ -637,12 +644,47 @@ Device *Circuit::device_by_id (size_t id) void Circuit::add_sub_circuit (SubCircuit *sub_circuit) { + size_t id = 0; + if (! m_sub_circuits.empty ()) { + tl_assert (m_sub_circuits.back () != 0); + id = m_sub_circuits.back ()->id (); + } + sub_circuit->set_id (id + 1); + m_sub_circuits.push_back (sub_circuit); + invalidate_subcircuit_id_table (); } void Circuit::remove_sub_circuit (SubCircuit *sub_circuit) { m_sub_circuits.erase (sub_circuit); + invalidate_subcircuit_id_table (); +} + +void Circuit::validate_subcircuit_id_table () +{ + m_subcircuit_id_table.clear (); + for (sub_circuit_iterator d = begin_sub_circuits (); d != end_sub_circuits (); ++d) { + m_subcircuit_id_table.insert (std::make_pair (d->id (), d.operator-> ())); + } + + m_valid_subcircuit_id_table = true; +} + +void Circuit::invalidate_subcircuit_id_table () +{ + m_valid_subcircuit_id_table = false; + m_subcircuit_id_table.clear (); +} + +SubCircuit *Circuit::subcircuit_by_id (size_t id) +{ + if (! m_valid_subcircuit_id_table) { + validate_subcircuit_id_table (); + } + + std::map::const_iterator d = m_subcircuit_id_table.find (id); + return d != m_subcircuit_id_table.end () ? d->second : 0; } void Circuit::translate_circuits (const std::map &map) diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index e9ceec255..39523f936 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -726,6 +726,17 @@ public: */ ~SubCircuit (); + /** + * @brief Gets the subcircuit ID + * The ID is a unique integer which identifies the subcircuit. + * It can be used to retrieve the subcircuit from the circuit using Circuit::subcircuit_by_id. + * When assigned, the subcircuit ID is not 0. + */ + size_t id () const + { + return m_id; + } + /** * @brief Gets the circuit the reference points to (const version) */ @@ -805,6 +816,7 @@ private: std::string m_name; db::DCplxTrans m_trans; std::vector m_pin_refs; + size_t m_id; /** * @brief Sets the pin reference for a specific pin @@ -818,6 +830,14 @@ private: { m_circuit.reset (c); } + + /** + * @brief Sets the device ID + */ + void set_id (size_t id) + { + m_id = id; + } }; /** @@ -1080,6 +1100,23 @@ public: */ void remove_sub_circuit (SubCircuit *sub_circuit); + /** + * @brief Gets the subcircuit from a given ID (const version) + * + * If the ID is not valid, null is returned. + */ + const SubCircuit *subcircuit_by_id (size_t id) const + { + return (const_cast (this)->subcircuit_by_id (id)); + } + + /** + * @brief Gets the subcircuit from a given ID (const version) + * + * If the ID is not valid, null is returned. + */ + SubCircuit *subcircuit_by_id (size_t id); + /** * @brief Begin iterator for the subcircuits of the circuit (non-const version) */ @@ -1166,6 +1203,8 @@ private: std::vector m_pin_refs; bool m_valid_device_id_table; std::map m_device_id_table; + bool m_valid_subcircuit_id_table; + std::map m_subcircuit_id_table; /** * @brief Sets the pin reference for a specific pin @@ -1180,6 +1219,8 @@ private: void validate_device_id_table (); void invalidate_device_id_table (); + void validate_subcircuit_id_table (); + void invalidate_subcircuit_id_table (); }; /** diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index cd52b6ee8..d647b9cae 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -128,6 +128,12 @@ Class decl_dbSubCircuit ("db", "SubCircuit", gsi::method ("circuit", (db::Circuit *(db::SubCircuit::*) ()) &db::SubCircuit::circuit, "@brief Gets the circuit referenced by the subcircuit.\n" ) + + gsi::method ("id", &db::SubCircuit::id, + "@brief Gets the subcircuit ID.\n" + "The ID is a unique integer which identifies the subcircuit.\n" + "It can be used to retrieve the subcircuit from the circuit using \\Circuit#subcircuit_by_id.\n" + "When assigned, the subcircuit ID is not 0.\n" + ) + gsi::method ("name=", &db::SubCircuit::set_name, gsi::arg ("name"), "@brief Sets the name of the subcircuit.\n" "SubCircuit names are used to name a subcircuits inside a netlist file. " @@ -617,6 +623,10 @@ Class decl_dbCircuit ("db", "Circuit", "@brief Gets the device object for a given ID.\n" "If the ID is not a valid device ID, nil is returned." ) + + gsi::method ("subcircuit_by_id", (db::SubCircuit *(db::Circuit::*) (size_t)) &db::Circuit::subcircuit_by_id, gsi::arg ("id"), + "@brief Gets the subcircuit object for a given ID.\n" + "If the ID is not a valid subcircuit ID, nil is returned." + ) + gsi::method ("pin_by_id", &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." diff --git a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc index d0cb30f19..33dd87329 100644 --- a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc @@ -279,10 +279,12 @@ public: m_net_clusters.build (*layout, cell, db::ShapeIterator::Polygons, conn); + // reverse lookup for Circuit vs. cell index std::map circuits; + // some circuits may be there because of device extraction for (db::Netlist::circuit_iterator c = nl->begin_circuits (); c != nl->end_circuits (); ++c) { - // @@@ TODO: what if the circuits don't have a cell index? + tl_assert (layout->is_valid_cell_index (c->cell_index ())); circuits.insert (std::make_pair (c->cell_index (), c.operator-> ())); } @@ -345,7 +347,6 @@ public: std::map::const_iterator k = circuits.find (ccid); tl_assert (k != circuits.end ()); // because we walk bottom-up - // @@@ name? subcircuit = new db::SubCircuit (k->second); db::CplxTrans dbu_trans (layout->dbu ()); subcircuit->set_trans (dbu_trans * i->inst ().complex_trans () * dbu_trans.inverted ()); @@ -440,14 +441,10 @@ static std::string device_name (const db::Device &device) } } -// @@@ TODO: refactor. This is inefficient. Give an ID automatically. -static std::string subcircuit_name (const db::SubCircuit &subcircuit, const db::Circuit &circuit) +static std::string subcircuit_name (const db::SubCircuit &subcircuit) { if (subcircuit.name ().empty ()) { - int id = 1; - for (db::Circuit::const_sub_circuit_iterator d = circuit.begin_sub_circuits (); d != circuit.end_sub_circuits () && d.operator-> () != &subcircuit; ++d, ++id) - ; - return "$" + tl::to_string (id); + return "$" + tl::to_string (subcircuit.id ()); } else { return subcircuit.name (); } @@ -543,7 +540,7 @@ static std::string netlist2string (const db::Netlist &nl) const db::Pin &pin = *p; ps += pin_name (pin) + "=" + net_name (subcircuit.net_for_pin (pin.id ())); } - res += std::string (" X") + sc->circuit ()->name () + " " + subcircuit_name (*sc, *c) + " (" + ps + ")\n"; + res += std::string (" X") + sc->circuit ()->name () + " " + subcircuit_name (*sc) + " (" + ps + ")\n"; } } diff --git a/src/db/unit_tests/dbNetlistTests.cc b/src/db/unit_tests/dbNetlistTests.cc index 1f7a9009e..ac4c95ac0 100644 --- a/src/db/unit_tests/dbNetlistTests.cc +++ b/src/db/unit_tests/dbNetlistTests.cc @@ -269,16 +269,16 @@ TEST(4_CircuitDevices) db::Device *d2a = new db::Device (&dc2, "d2a"); db::Device *d2b = new db::Device (&dc2, "d2b"); c->add_device (d1); - EXPECT_EQ (d1->id (), 1); + EXPECT_EQ (d1->id (), size_t (1)); EXPECT_EQ (c->device_by_id (d1->id ()) == d1, true); c->add_device (dd); - EXPECT_EQ (dd->id (), 2); + EXPECT_EQ (dd->id (), size_t (2)); EXPECT_EQ (c->device_by_id (dd->id ()) == dd, true); c->add_device (d2a); - EXPECT_EQ (d2a->id (), 3); + EXPECT_EQ (d2a->id (), size_t (3)); EXPECT_EQ (c->device_by_id (d2a->id ()) == d2a, true); c->add_device (d2b); - EXPECT_EQ (d2b->id (), 4); + EXPECT_EQ (d2b->id (), size_t (4)); EXPECT_EQ (c->device_by_id (d2b->id ()) == d2b, true); c->remove_device (dd); dd = 0; @@ -416,10 +416,14 @@ TEST(4_NetlistSubcircuits) db::SubCircuit *sc1 = new db::SubCircuit (c2); sc1->set_name ("sc1"); c1->add_sub_circuit (sc1); + EXPECT_EQ (sc1->id (), size_t (1)); + EXPECT_EQ (c1->subcircuit_by_id (sc1->id ()) == sc1, true); db::SubCircuit *sc2 = new db::SubCircuit (c2); sc2->set_name ("sc2"); c1->add_sub_circuit (sc2); + EXPECT_EQ (sc2->id (), size_t (2)); + EXPECT_EQ (c1->subcircuit_by_id (sc2->id ()) == sc2, true); db::Net *n2a = new db::Net (); c2->add_net (n2a); diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb index aad2539e3..bcd6314bc 100644 --- a/testdata/ruby/dbNetlist.rb +++ b/testdata/ruby/dbNetlist.rb @@ -260,6 +260,8 @@ class DBNetlist_TestClass < TestBase sc1.name = "SC1" assert_equal(sc1.name, "SC1") assert_equal(sc1.circuit.name, "CC") + assert_equal(c.subcircuit_by_id(sc1.id).id, 1) + assert_equal(c.subcircuit_by_id(2).inspect, "nil") sc2 = c.create_subcircuit(cc) sc2.name = "SC2"