From 6baabc30bb794f6967edc2ba12b4d8bba9351471 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 24 Jul 2024 20:57:17 +0200 Subject: [PATCH] Added Netlist#top_circuit and Netlist#top_circuits convenience methods --- src/db/db/dbNetlist.cc | 41 +++++++++++++ src/db/db/dbNetlist.h | 26 ++++++++ src/db/db/gsiDeclDbNetlist.cc | 26 ++++++++ src/db/unit_tests/dbNetlistTests.cc | 94 +++++++++++++++++++++++++++++ testdata/ruby/dbNetlist.rb | 11 ++++ 5 files changed, 198 insertions(+) diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index f0f8d177c..e5e801863 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -366,6 +366,47 @@ size_t Netlist::top_circuit_count () const return m_top_circuits; } +Circuit *Netlist::top_circuit () +{ + size_t ntop = top_circuit_count (); + if (ntop == 0) { + return 0; + } else if (ntop > 1) { + throw tl::Exception (tl::to_string (tr ("Netlist contains more than a single top circuit"))); + } else { + return begin_top_down ().operator-> (); + } +} + +const Circuit *Netlist::top_circuit () const +{ + return const_cast (this)->top_circuit (); +} + +std::vector Netlist::top_circuits () +{ + size_t ntop = top_circuit_count (); + std::vector result; + result.reserve (ntop); + for (auto c = begin_top_down (); ntop > 0 && c != end_top_down (); ++c) { + result.push_back (c.operator-> ()); + --ntop; + } + return result; +} + +std::vector Netlist::top_circuits () const +{ + size_t ntop = top_circuit_count (); + std::vector result; + result.reserve (ntop); + for (auto c = begin_top_down (); ntop > 0 && c != end_top_down (); ++c) { + result.push_back (c.operator-> ()); + --ntop; + } + return result; +} + Netlist::bottom_up_circuit_iterator Netlist::begin_bottom_up () { if (! m_valid_topology) { diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index 9e5221796..0bff649e1 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -271,6 +271,32 @@ public: return m_circuit_by_cell_index.object_by (cell_index); } + /** + * @brief Gets the top circuit if there is one + * This method will assert if there is more than a single top circuit. + * It will return 0 if there is no top circuit. + */ + Circuit *top_circuit (); + + /** + * @brief Gets the top circuit if there is one (const version) + * This method will assert if there is more than a single top circuit. + * It will return 0 if there is no top circuit. + */ + const Circuit *top_circuit () const; + + /** + * @brief Gets the top circuits + * This convenience method will return a list of top circuits. + */ + std::vector top_circuits (); + + /** + * @brief Gets the top circuits (const version) + * This convenience method will return a list of top circuits. + */ + std::vector top_circuits () const; + /** * @brief Gets the top-down circuits iterator (begin) * This iterator will deliver the circuits in a top-down way - i.e. child circuits diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index f84294c9f..1573631dc 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -2044,6 +2044,32 @@ Class decl_dbNetlist ("db", "Netlist", "\n" "This method has been introduced in version 0.28.4.\n" ) + + gsi::method ("top_circuit", static_cast (&db::Netlist::top_circuit), + "@brief Gets the top circuit.\n" + "This method will return nil, if there is no top circuit. It will raise an error, if there is more than " + "a single top circuit.\n" + "\n" + "This convenience method has been added in version 0.29.5." + ) + + gsi::method ("top_circuit", static_cast (&db::Netlist::top_circuit), + "@brief Gets the top circuit (const version).\n" + "This method will return nil, if there is no top circuit. It will raise an error, if there is more than " + "a single top circuit.\n" + "\n" + "This convenience method has been added in version 0.29.5." + ) + + gsi::method ("top_circuits", static_cast (db::Netlist::*) ()> (&db::Netlist::top_circuits), + "@brief Gets the top circuits.\n" + "Returns a list of top circuits.\n" + "\n" + "This convenience method has been added in version 0.29.5." + ) + + gsi::method ("top_circuits", static_cast (db::Netlist::*) () const> (&db::Netlist::top_circuits), + "@brief Gets the top circuits.\n" + "Returns a list of top circuits.\n" + "\n" + "This convenience method has been added in version 0.29.5." + ) + gsi::method_ext ("nets_by_name", &nets_by_name_const_from_netlist, gsi::arg ("name_pattern"), "@brief Gets the net objects for a given name filter (const version).\n" "The name filter is a glob pattern. This method will return all \\Net objects matching the glob pattern.\n" diff --git a/src/db/unit_tests/dbNetlistTests.cc b/src/db/unit_tests/dbNetlistTests.cc index dbc8b8e9a..6cb051c86 100644 --- a/src/db/unit_tests/dbNetlistTests.cc +++ b/src/db/unit_tests/dbNetlistTests.cc @@ -208,6 +208,18 @@ static std::string parents2string (const db::Circuit *c) return res; } +static std::string td2string_nc (db::Netlist *nl) +{ + std::string res; + for (db::Netlist::top_down_circuit_iterator r = nl->begin_top_down (); r != nl->end_top_down (); ++r) { + if (!res.empty ()) { + res += ","; + } + res += r->name (); + } + return res; +} + static std::string td2string (const db::Netlist *nl) { std::string res; @@ -220,6 +232,64 @@ static std::string td2string (const db::Netlist *nl) return res; } +static std::string tcs2string_nc (db::Netlist *nl) +{ + std::string res; + std::vector tops = nl->top_circuits (); + for (auto i = tops.begin (); i != tops.end (); ++i) { + if (!res.empty ()) { + res += ","; + } + res += (*i)->name (); + } + return res; +} + +static std::string tcs2string (const db::Netlist *nl) +{ + std::string res; + std::vector tops = nl->top_circuits (); + for (auto i = tops.begin (); i != tops.end (); ++i) { + if (!res.empty ()) { + res += ","; + } + res += (*i)->name (); + } + return res; +} + +static std::string tc2string_nc (db::Netlist *nl) +{ + const db::Circuit *tc = nl->top_circuit (); + if (!tc) { + return "(nil)"; + } else { + return tc->name (); + } +} + +static std::string tc2string (const db::Netlist *nl) +{ + const db::Circuit *tc = nl->top_circuit (); + if (!tc) { + return "(nil)"; + } else { + return tc->name (); + } +} + +static std::string bu2string_nc (db::Netlist *nl) +{ + std::string res; + for (db::Netlist::bottom_up_circuit_iterator r = nl->begin_bottom_up (); r != nl->end_bottom_up (); ++r) { + if (!res.empty ()) { + res += ","; + } + res += r->name (); + } + return res; +} + static std::string bu2string (const db::Netlist *nl) { std::string res; @@ -1038,20 +1108,44 @@ TEST(12_NetlistTopology) { std::unique_ptr nl (new db::Netlist ()); EXPECT_EQ (nl->top_circuit_count (), size_t (0)); + EXPECT_EQ (tcs2string (nl.get ()), ""); + EXPECT_EQ (tcs2string_nc (nl.get ()), ""); + EXPECT_EQ (tc2string (nl.get ()), "(nil)"); + EXPECT_EQ (tc2string_nc (nl.get ()), "(nil)"); db::Circuit *c1 = new db::Circuit (); c1->set_name ("c1"); nl->add_circuit (c1); EXPECT_EQ (nl->top_circuit_count (), size_t (1)); EXPECT_EQ (td2string (nl.get ()), "c1"); + EXPECT_EQ (td2string_nc (nl.get ()), "c1"); + EXPECT_EQ (tcs2string (nl.get ()), "c1"); + EXPECT_EQ (tcs2string_nc (nl.get ()), "c1"); + EXPECT_EQ (tc2string (nl.get ()), "c1"); + EXPECT_EQ (tc2string_nc (nl.get ()), "c1"); EXPECT_EQ (bu2string (nl.get ()), "c1"); + EXPECT_EQ (bu2string_nc (nl.get ()), "c1"); db::Circuit *c2 = new db::Circuit (); c2->set_name ("c2"); nl->add_circuit (c2); EXPECT_EQ (nl->top_circuit_count (), size_t (2)); EXPECT_EQ (td2string (nl.get ()), "c2,c1"); + EXPECT_EQ (td2string_nc (nl.get ()), "c2,c1"); + EXPECT_EQ (tcs2string (nl.get ()), "c2,c1"); + EXPECT_EQ (tcs2string_nc (nl.get ()), "c2,c1"); + try { + tc2string (nl.get ()); + EXPECT_EQ (true, false); + } catch (...) { + } + try { + tc2string_nc (nl.get ()); + EXPECT_EQ (true, false); + } catch (...) { + } EXPECT_EQ (bu2string (nl.get ()), "c1,c2"); + EXPECT_EQ (bu2string_nc (nl.get ()), "c1,c2"); std::unique_ptr locker (new db::NetlistLocker (nl.get ())); diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb index 1ceb1331c..07b8bfa5c 100644 --- a/testdata/ruby/dbNetlist.rb +++ b/testdata/ruby/dbNetlist.rb @@ -832,18 +832,25 @@ END nl = RBA::Netlist::new assert_equal(nl.top_circuit_count, 0) + assert_equal(nl.top_circuit == nil, true) c1 = RBA::Circuit::new c1.name = "C1" c1.cell_index = 17 nl.add(c1) assert_equal(nl.top_circuit_count, 1) + assert_equal(nl.top_circuit.name, "C1") c2 = RBA::Circuit::new c2.name = "C2" c1.cell_index = 42 nl.add(c2) assert_equal(nl.top_circuit_count, 2) + begin + nl.top_circuit + assert_equal(true, false) + rescue + end c3 = RBA::Circuit::new c3.name = "C3" @@ -854,6 +861,10 @@ END nl.each_circuit_top_down { |c| names << c.name } assert_equal(names.join(","), "C3,C2,C1") + names = [] + nl.top_circuits.each { |c| names << c.name } + assert_equal(names.join(","), "C3,C2,C1") + names = [] nl.each_circuit_bottom_up { |c| names << c.name } assert_equal(names.join(","), "C1,C2,C3")