WIP: netlist topology - children, parents, top-down and bottom-up iteration.

This commit is contained in:
Matthias Koefferlein 2018-12-29 00:48:28 +01:00
parent 2f48479838
commit d57ede441c
5 changed files with 655 additions and 7 deletions

View File

@ -504,13 +504,13 @@ void Net::set_circuit (Circuit *circuit)
// Circuit class implementation
Circuit::Circuit ()
: mp_netlist (0), m_valid_device_id_table (false), m_valid_subcircuit_id_table (false)
: mp_netlist (0), m_valid_device_id_table (false), m_valid_subcircuit_id_table (false), m_index (0)
{
// .. nothing yet ..
}
Circuit::Circuit (const Circuit &other)
: mp_netlist (0), m_valid_device_id_table (false), m_valid_subcircuit_id_table (false)
: mp_netlist (0), m_valid_device_id_table (false), m_valid_subcircuit_id_table (false), m_index (0)
{
operator= (other);
}
@ -609,6 +609,54 @@ void Circuit::set_cell_index (const db::cell_index_type ci)
m_cell_index = ci;
}
Circuit::child_circuit_iterator Circuit::begin_children ()
{
tl_assert (mp_netlist != 0);
return mp_netlist->child_circuits (this).begin ();
}
Circuit::child_circuit_iterator Circuit::end_children ()
{
tl_assert (mp_netlist != 0);
return mp_netlist->child_circuits (this).end ();
}
Circuit::const_child_circuit_iterator Circuit::begin_children () const
{
tl_assert (mp_netlist != 0);
return reinterpret_cast<const tl::vector<const Circuit *> &> (mp_netlist->child_circuits (const_cast <Circuit *> (this))).begin ();
}
Circuit::const_child_circuit_iterator Circuit::end_children () const
{
tl_assert (mp_netlist != 0);
return reinterpret_cast<const tl::vector<const Circuit *> &> (mp_netlist->child_circuits (const_cast <Circuit *> (this))).end ();
}
Circuit::child_circuit_iterator Circuit::begin_parents ()
{
tl_assert (mp_netlist != 0);
return mp_netlist->parent_circuits (this).begin ();
}
Circuit::child_circuit_iterator Circuit::end_parents ()
{
tl_assert (mp_netlist != 0);
return mp_netlist->parent_circuits (this).end ();
}
Circuit::const_child_circuit_iterator Circuit::begin_parents () const
{
tl_assert (mp_netlist != 0);
return reinterpret_cast<const tl::vector<const Circuit *> &> (mp_netlist->parent_circuits (const_cast <Circuit *> (this))).begin ();
}
Circuit::const_child_circuit_iterator Circuit::end_parents () const
{
tl_assert (mp_netlist != 0);
return reinterpret_cast<const tl::vector<const Circuit *> &> (mp_netlist->parent_circuits (const_cast <Circuit *> (this))).end ();
}
const Pin &Circuit::add_pin (const Pin &pin)
{
m_pins.push_back (pin);
@ -687,12 +735,20 @@ void Circuit::add_subcircuit (SubCircuit *subcircuit)
m_subcircuits.push_back (subcircuit);
invalidate_subcircuit_id_table ();
if (mp_netlist) {
mp_netlist->invalidate_topology ();
}
}
void Circuit::remove_subcircuit (SubCircuit *subcircuit)
{
m_subcircuits.erase (subcircuit);
invalidate_subcircuit_id_table ();
if (mp_netlist) {
mp_netlist->invalidate_topology ();
}
}
void Circuit::validate_subcircuit_id_table ()
@ -1073,21 +1129,25 @@ size_t DeviceClass::terminal_id_for_name (const std::string &name) const
// Netlist class implementation
Netlist::Netlist ()
: m_valid_topology (false)
{
// .. nothing yet ..
m_circuits.changed ().add (this, &Netlist::invalidate_topology);
}
Netlist::Netlist (const Netlist &other)
: m_valid_topology (false)
{
operator= (other);
m_circuits.changed ().add (this, &Netlist::invalidate_topology);
}
Netlist &Netlist::operator= (const Netlist &other)
{
if (this != &other) {
clear ();
std::map<const DeviceClass *, DeviceClass *> dct;
m_device_classes.clear ();
for (const_device_class_iterator dc = other.begin_device_classes (); dc != other.end_device_classes (); ++dc) {
DeviceClass *dc_new = dc->clone ();
dct [dc.operator-> ()] = dc_new;
@ -1110,6 +1170,223 @@ Netlist &Netlist::operator= (const Netlist &other)
return *this;
}
void Netlist::invalidate_topology ()
{
if (m_valid_topology) {
m_valid_topology = false;
m_top_circuits = 0;
m_top_down_circuits.clear ();
m_child_circuits.clear ();
m_parent_circuits.clear ();
}
}
namespace {
struct sort_by_index
{
bool operator () (const Circuit *a, const Circuit *b) const
{
return a->index () < b->index ();
}
};
}
void Netlist::validate_topology ()
{
if (m_valid_topology) {
return;
}
m_child_circuits.clear ();
m_parent_circuits.clear ();
size_t max_index = 0;
for (circuit_iterator c = begin_circuits (); c != end_circuits (); ++c) {
c->set_index (max_index);
++max_index;
}
// build the child circuit list ... needed for the topology sorting
m_child_circuits.reserve (max_index);
m_parent_circuits.reserve (max_index);
for (circuit_iterator c = begin_circuits (); c != end_circuits (); ++c) {
std::set<Circuit *> children;
for (Circuit::subcircuit_iterator sc = c->begin_subcircuits (); sc != c->end_subcircuits (); ++sc) {
if (sc->circuit_ref ()) {
children.insert (sc->circuit_ref ());
}
}
m_child_circuits.push_back (tl::vector<Circuit *> ());
tl::vector<Circuit *> &cc = m_child_circuits.back ();
cc.reserve (children.size ());
cc.insert (cc.end (), children.begin (), children.end ());
// sort by index for better reproducibility
std::sort (cc.begin (), cc.end (), sort_by_index ());
std::set<Circuit *> parents;
for (Circuit::refs_iterator sc = c->begin_refs (); sc != c->end_refs (); ++sc) {
if (sc->circuit ()) {
parents.insert (sc->circuit ());
}
}
m_parent_circuits.push_back (tl::vector<Circuit *> ());
tl::vector<Circuit *> &pc = m_parent_circuits.back ();
pc.reserve (parents.size ());
pc.insert (pc.end (), parents.begin (), parents.end ());
// sort by index for better reproducibility
std::sort (pc.begin (), pc.end (), sort_by_index ());
}
// do topology sorting
m_top_circuits = 0;
m_top_down_circuits.clear ();
m_top_down_circuits.reserve (max_index);
std::vector<size_t> num_parents (max_index, 0);
// while there are cells to treat ..
while (m_top_down_circuits.size () != max_index) {
size_t n_top_down_circuits = m_top_down_circuits.size ();
// Treat all circuits that do not have all parents reported.
// For all such a circuits, disable the parent counting,
// add the circuits's index to the top-down sorted list and
// increment the reported parent count in all the
// child circuits.
for (circuit_iterator c = begin_circuits (); c != end_circuits (); ++c) {
if (m_parent_circuits [c->index ()].size () == num_parents [c->index ()]) {
m_top_down_circuits.push_back (c.operator-> ());
num_parents [c->index ()] = std::numeric_limits<cell_index_type>::max ();
}
}
// For all these a circuits, increment the reported parent instance
// count in all the child circuits.
for (tl::vector<Circuit *>::const_iterator ii = m_top_down_circuits.begin () + n_top_down_circuits; ii != m_top_down_circuits.end (); ++ii) {
const tl::vector<Circuit *> &cc = m_child_circuits [(*ii)->index ()];
for (tl::vector<Circuit *>::const_iterator icc = cc.begin (); icc != cc.end (); ++icc) {
tl_assert (num_parents [(*icc)->index ()] != std::numeric_limits<cell_index_type>::max ());
num_parents [(*icc)->index ()] += 1;
}
}
// If no new cells have been reported this is basically a
// sign of recursion in the graph.
if (n_top_down_circuits == m_top_down_circuits.size ()) {
throw tl::Exception (tl::to_string (tr ("Recursive hierarchy detected in netlist")));
}
}
// Determine the number of top cells
for (tl::vector<Circuit *>::const_iterator e = m_top_down_circuits.begin (); e != m_top_down_circuits.end () && m_parent_circuits [(*e)->index ()].empty (); ++e) {
++m_top_circuits;
}
m_valid_topology = true;
}
const tl::vector<Circuit *> &Netlist::child_circuits (Circuit *circuit)
{
if (! m_valid_topology) {
validate_topology ();
}
tl_assert (circuit->index () < m_child_circuits.size ());
return m_child_circuits [circuit->index ()];
}
const tl::vector<Circuit *> &Netlist::parent_circuits (Circuit *circuit)
{
if (! m_valid_topology) {
validate_topology ();
}
tl_assert (circuit->index () < m_parent_circuits.size ());
return m_parent_circuits [circuit->index ()];
}
Netlist::top_down_circuit_iterator Netlist::begin_top_down ()
{
if (! m_valid_topology) {
validate_topology ();
}
return m_top_down_circuits.begin ();
}
Netlist::top_down_circuit_iterator Netlist::end_top_down ()
{
if (! m_valid_topology) {
validate_topology ();
}
return m_top_down_circuits.end ();
}
Netlist::const_top_down_circuit_iterator Netlist::begin_top_down () const
{
if (! m_valid_topology) {
const_cast<Netlist *> (this)->validate_topology ();
}
return reinterpret_cast<const tl::vector<const Circuit *> &> (m_top_down_circuits).begin ();
}
Netlist::const_top_down_circuit_iterator Netlist::end_top_down () const
{
if (! m_valid_topology) {
const_cast<Netlist *> (this)->validate_topology ();
}
return reinterpret_cast<const tl::vector<const Circuit *> &> (m_top_down_circuits).end ();
}
size_t Netlist::top_circuit_count () const
{
if (! m_valid_topology) {
const_cast<Netlist *> (this)->validate_topology ();
}
return m_top_circuits;
}
Netlist::bottom_up_circuit_iterator Netlist::begin_bottom_up ()
{
if (! m_valid_topology) {
validate_topology ();
}
return m_top_down_circuits.rbegin ();
}
Netlist::bottom_up_circuit_iterator Netlist::end_bottom_up ()
{
if (! m_valid_topology) {
validate_topology ();
}
return m_top_down_circuits.rend ();
}
Netlist::const_bottom_up_circuit_iterator Netlist::begin_bottom_up () const
{
if (! m_valid_topology) {
const_cast<Netlist *> (this)->validate_topology ();
}
return reinterpret_cast<const tl::vector<const Circuit *> &> (m_top_down_circuits).rbegin ();
}
Netlist::const_bottom_up_circuit_iterator Netlist::end_bottom_up () const
{
if (! m_valid_topology) {
const_cast<Netlist *> (this)->validate_topology ();
}
return reinterpret_cast<const tl::vector<const Circuit *> &> (m_top_down_circuits).rend ();
}
void Netlist::clear ()
{
m_device_classes.clear ();

View File

@ -920,6 +920,10 @@ public:
typedef subcircuit_list::iterator subcircuit_iterator;
typedef tl::weak_collection<SubCircuit>::const_iterator const_refs_iterator;
typedef tl::weak_collection<SubCircuit>::iterator refs_iterator;
typedef tl::vector<Circuit *>::const_iterator child_circuit_iterator;
typedef tl::vector<const Circuit *>::const_iterator const_child_circuit_iterator;
typedef tl::vector<Circuit *>::const_iterator parent_circuit_iterator;
typedef tl::vector<const Circuit *>::const_iterator const_parent_circuit_iterator;
/**
* @brief Constructor
@ -974,6 +978,15 @@ public:
return m_name;
}
/**
* @brief The index of the circuit in the netlist
* CAUTION: this attribute is used for internal purposes and may not be valid always.
*/
size_t index () const
{
return m_index;
}
/**
* @brief Sets the layout cell reference for this circuit
*
@ -1016,6 +1029,52 @@ public:
return m_refs.begin ();
}
/**
* @brief Gets the child circuits iterator (begin)
* The child circuits are the circuits referenced by all subcircuits
* in the circuit.
*/
child_circuit_iterator begin_children ();
/**
* @brief Gets the child circuits iterator (end)
*/
child_circuit_iterator end_children ();
/**
* @brief Gets the child circuits iterator (begin, const version)
* The child circuits are the circuits referenced by all subcircuits
* in the circuit.
*/
const_child_circuit_iterator begin_children () const;
/**
* @brief Gets the child circuits iterator (end, const version)
*/
const_child_circuit_iterator end_children () const;
/**
* @brief Gets the parent circuits iterator (begin)
* The parents circuits are the circuits referencing this circuit via subcircuits.
*/
parent_circuit_iterator begin_parents ();
/**
* @brief Gets the parent circuits iterator (end)
*/
parent_circuit_iterator end_parents ();
/**
* @brief Gets the parent circuits iterator (begin, const version)
* The parents circuits are the circuits referencing this circuit via subcircuits.
*/
const_parent_circuit_iterator begin_parents () const;
/**
* @brief Gets the parent circuits iterator (end, const version)
*/
const_parent_circuit_iterator end_parents () const;
/**
* @brief Gets the references to this circuit (end, const version)
* This iterator will deliver all subcircuits referencing this circuit
@ -1300,10 +1359,13 @@ private:
bool m_valid_subcircuit_id_table;
std::map<size_t, SubCircuit *> m_subcircuit_id_table;
tl::weak_collection<SubCircuit> m_refs;
size_t m_index;
void set_index (size_t index)
{
m_index = index;
}
/**
* @brief Sets the pin reference for a specific pin
*/
void set_pin_ref_for_pin (size_t ppin_id, Net::pin_iterator iter);
void register_ref (SubCircuit *sc);
@ -1717,6 +1779,10 @@ public:
typedef tl::shared_collection<DeviceClass> device_class_list;
typedef device_class_list::const_iterator const_device_class_iterator;
typedef device_class_list::iterator device_class_iterator;
typedef tl::vector<Circuit *>::const_iterator top_down_circuit_iterator;
typedef tl::vector<const Circuit *>::const_iterator const_top_down_circuit_iterator;
typedef tl::vector<Circuit *>::const_reverse_iterator bottom_up_circuit_iterator;
typedef tl::vector<const Circuit *>::const_reverse_iterator const_bottom_up_circuit_iterator;
/**
* @brief Constructor
@ -1784,6 +1850,65 @@ public:
return m_circuits.end ();
}
/**
* @brief Gets the top-down circuits iterator (begin)
* This iterator will deliver the circuits in a top-down way - i.e. child circuits
* will always come after parent circuits.
* The first "top_circuit_count" elements will be top circuits (those which are not
* referenced by other circuits).
*/
top_down_circuit_iterator begin_top_down ();
/**
* @brief Gets the top-down circuits iterator (end)
*/
top_down_circuit_iterator end_top_down ();
/**
* @brief Gets the top-down circuits iterator (begin, const version)
* This iterator will deliver the circuits in a top-down way - i.e. child circuits
* will always come after parent circuits.
* The first "top_circuit_count" elements will be top circuits (those which are not
* referenced by other circuits).
*/
const_top_down_circuit_iterator begin_top_down () const;
/**
* @brief Gets the top-down circuits iterator (end, const version)
*/
const_top_down_circuit_iterator end_top_down () const;
/**
* @brief Gets the number of top circuits
* Top circuits are those which are not referenced by other circuits.
* In a well-formed netlist there is a single top-level circuit.
*/
size_t top_circuit_count () const;
/**
* @brief Gets the bottom-up circuits iterator (begin)
* This iterator will deliver the circuits in a bottom-up way - i.e. child circuits
* will always come before parent circuits.
*/
bottom_up_circuit_iterator begin_bottom_up ();
/**
* @brief Gets the bottom-up circuits iterator (end)
*/
bottom_up_circuit_iterator end_bottom_up ();
/**
* @brief Gets the bottom-up circuits iterator (begin, const version)
* This iterator will deliver the circuits in a bottom-up way - i.e. child circuits
* will always come before parent circuits.
*/
const_bottom_up_circuit_iterator begin_bottom_up () const;
/**
* @brief Gets the bottom-up circuits iterator (end, const version)
*/
const_bottom_up_circuit_iterator end_bottom_up () const;
/**
* @brief Adds a device class to this netlist
*
@ -1844,8 +1969,21 @@ public:
void combine_devices ();
private:
friend class Circuit;
circuit_list m_circuits;
device_class_list m_device_classes;
bool m_valid_topology;
tl::vector<Circuit *> m_top_down_circuits;
tl::vector<tl::vector<Circuit *> > m_child_circuits;
tl::vector<tl::vector<Circuit *> > m_parent_circuits;
size_t m_top_circuits;
void invalidate_topology ();
void validate_topology ();
const tl::vector<Circuit *> &child_circuits (Circuit *circuit);
const tl::vector<Circuit *> &parent_circuits (Circuit *circuit);
};
}

View File

@ -627,6 +627,14 @@ Class<db::Circuit> decl_dbCircuit ("db", "Circuit",
"to the outside through such a pin. The pin is added after all existing "
"pins. For more details see the \\Pin class."
) +
gsi::iterator ("each_child", (db::Circuit::child_circuit_iterator (db::Circuit::*) ()) &db::Circuit::begin_children, (db::Circuit::child_circuit_iterator (db::Circuit::*) ()) &db::Circuit::end_children,
"@brief Iterates over the child circuits of this circuit\n"
"Child circuits are the ones that are referenced from this circuit via subcircuits."
) +
gsi::iterator ("each_parent", (db::Circuit::parent_circuit_iterator (db::Circuit::*) ()) &db::Circuit::begin_parents, (db::Circuit::parent_circuit_iterator (db::Circuit::*) ()) &db::Circuit::end_parents,
"@brief Iterates over the parent circuits of this circuit\n"
"Child circuits are the ones that are referencing this circuit via subcircuits."
) +
gsi::iterator ("each_ref", (db::Circuit::refs_iterator (db::Circuit::*) ()) &db::Circuit::begin_refs, (db::Circuit::refs_iterator (db::Circuit::*) ()) &db::Circuit::end_refs,
"@brief Iterates over the subcircuit objects referencing this circuit\n"
) +
@ -800,6 +808,21 @@ Class<db::Netlist> decl_dbNetlist ("db", "Netlist",
"@brief Removes the given circuit object from the netlist\n"
"After the object has been removed, it becomes invalid and cannot be used further."
) +
gsi::iterator ("each_circuit_top_down", (db::Netlist::top_down_circuit_iterator (db::Netlist::*) ()) &db::Netlist::begin_top_down, (db::Netlist::top_down_circuit_iterator (db::Netlist::*) ()) &db::Netlist::end_top_down,
"@brief Iterates over the circuits top-down\n"
"Iterating top-down means the parent circuits come before the child circuits. "
"The first \\top_circuit_count circuits are top circuits - i.e. those which are not referenced by other circuits."
) +
gsi::iterator ("each_circuit_bottom_up", (db::Netlist::bottom_up_circuit_iterator (db::Netlist::*) ()) &db::Netlist::begin_bottom_up, (db::Netlist::bottom_up_circuit_iterator (db::Netlist::*) ()) &db::Netlist::end_bottom_up,
"@brief Iterates over the circuits bottom-up\n"
"Iterating bottom-up means the parent circuits come after the child circuits. "
"This is the basically the reverse order as delivered by \\each_circuit_top_down."
) +
gsi::method ("top_circuit_count", &db::Netlist::top_circuit_count,
"@brief Gets the number of top circuits.\n"
"Top circuits are those which are not referenced by other circuits via subcircuits. "
"A well-formed netlist has a single top circuit."
) +
gsi::iterator ("each_circuit", (db::Netlist::circuit_iterator (db::Netlist::*) ()) &db::Netlist::begin_circuits, (db::Netlist::circuit_iterator (db::Netlist::*) ()) &db::Netlist::end_circuits,
"@brief Iterates over the circuits of the netlist"
) +

View File

@ -834,3 +834,121 @@ TEST(11_NetlistCircuitRefs)
sc3 = db::SubCircuit ();
EXPECT_EQ (refs2string (c2), "sc1,sc2");
}
static std::string children2string (const db::Circuit *c)
{
std::string res;
for (db::Circuit::const_child_circuit_iterator r = c->begin_children (); r != c->end_children (); ++r) {
if (!res.empty ()) {
res += ",";
}
res += (*r)->name ();
}
return res;
}
static std::string parents2string (const db::Circuit *c)
{
std::string res;
for (db::Circuit::const_parent_circuit_iterator r = c->begin_parents (); r != c->end_parents (); ++r) {
if (!res.empty ()) {
res += ",";
}
res += (*r)->name ();
}
return res;
}
static std::string td2string (const db::Netlist *nl)
{
std::string res;
for (db::Netlist::const_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 bu2string (const db::Netlist *nl)
{
std::string res;
for (db::Netlist::const_bottom_up_circuit_iterator r = nl->begin_bottom_up (); r != nl->end_bottom_up (); ++r) {
if (!res.empty ()) {
res += ",";
}
res += (*r)->name ();
}
return res;
}
TEST(12_NetlistTopology)
{
std::auto_ptr<db::Netlist> nl (new db::Netlist ());
EXPECT_EQ (nl->top_circuit_count (), size_t (0));
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 (bu2string (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 ()), "c1,c2");
EXPECT_EQ (bu2string (nl.get ()), "c2,c1");
db::Circuit *c3 = new db::Circuit ();
c3->set_name ("c3");
nl->add_circuit (c3);
EXPECT_EQ (nl->top_circuit_count (), size_t (3));
EXPECT_EQ (td2string (nl.get ()), "c1,c2,c3");
EXPECT_EQ (bu2string (nl.get ()), "c3,c2,c1");
db::SubCircuit *sc1 = new db::SubCircuit (c2);
sc1->set_name ("sc1");
c1->add_subcircuit (sc1);
EXPECT_EQ (children2string (c1), "c2");
EXPECT_EQ (parents2string (c2), "c1");
EXPECT_EQ (nl->top_circuit_count (), size_t (2));
EXPECT_EQ (td2string (nl.get ()), "c1,c3,c2");
EXPECT_EQ (bu2string (nl.get ()), "c2,c3,c1");
db::SubCircuit *sc2 = new db::SubCircuit (c2);
sc2->set_name ("sc2");
c1->add_subcircuit (sc2);
EXPECT_EQ (children2string (c1), "c2");
EXPECT_EQ (parents2string (c2), "c1");
EXPECT_EQ (nl->top_circuit_count (), size_t (2));
EXPECT_EQ (td2string (nl.get ()), "c1,c3,c2");
EXPECT_EQ (bu2string (nl.get ()), "c2,c3,c1");
db::SubCircuit *sc3 = new db::SubCircuit (c3);
sc3->set_name ("sc3");
c1->add_subcircuit (sc3);
EXPECT_EQ (children2string (c1), "c2,c3");
EXPECT_EQ (children2string (c2), "");
EXPECT_EQ (children2string (c3), "");
EXPECT_EQ (parents2string (c2), "c1");
EXPECT_EQ (parents2string (c3), "c1");
EXPECT_EQ (nl->top_circuit_count (), size_t (1));
EXPECT_EQ (td2string (nl.get ()), "c1,c2,c3");
EXPECT_EQ (bu2string (nl.get ()), "c3,c2,c1");
db::SubCircuit *sc4 = new db::SubCircuit (*sc2);
sc4->set_name ("sc4");
c3->add_subcircuit (sc4);
EXPECT_EQ (children2string (c1), "c2,c3");
EXPECT_EQ (children2string (c2), "");
EXPECT_EQ (children2string (c3), "c2");
EXPECT_EQ (parents2string (c2), "c1,c3");
EXPECT_EQ (parents2string (c3), "c1");
EXPECT_EQ (nl->top_circuit_count (), size_t (1));
EXPECT_EQ (td2string (nl.get ()), "c1,c3,c2");
EXPECT_EQ (bu2string (nl.get ()), "c2,c3,c1");
}

View File

@ -563,6 +563,98 @@ class DBNetlist_TestClass < TestBase
end
def test_10_NetlistTopology
nl = RBA::Netlist::new
assert_equal(nl.top_circuit_count, 0)
c1 = RBA::Circuit::new
c1.name = "C1"
nl.add(c1)
assert_equal(nl.top_circuit_count, 1)
c2 = RBA::Circuit::new
c2.name = "C2"
nl.add(c2)
assert_equal(nl.top_circuit_count, 2)
c3 = RBA::Circuit::new
c3.name = "C3"
nl.add(c3)
assert_equal(nl.top_circuit_count, 3)
names = []
nl.each_circuit_top_down { |c| names << c.name }
assert_equal(names.join(","), "C1,C2,C3")
names = []
nl.each_circuit_bottom_up { |c| names << c.name }
assert_equal(names.join(","), "C3,C2,C1")
names = []
c1.each_child { |c| names << c.name }
assert_equal(names.join(","), "")
names = []
c2.each_parent { |c| names << c.name }
assert_equal(names.join(","), "")
c1.create_subcircuit(c2)
assert_equal(nl.top_circuit_count, 2)
names = []
c1.each_child { |c| names << c.name }
assert_equal(names.join(","), "C2")
names = []
c2.each_parent { |c| names << c.name }
assert_equal(names.join(","), "C1")
c1.create_subcircuit(c2)
c1.create_subcircuit(c3)
assert_equal(nl.top_circuit_count, 1)
names = []
c1.each_child { |c| names << c.name }
assert_equal(names.join(","), "C2,C3")
names = []
c2.each_parent { |c| names << c.name }
assert_equal(names.join(","), "C1")
names = []
c3.each_parent { |c| names << c.name }
assert_equal(names.join(","), "C1")
names = []
nl.each_circuit_top_down { |c| names << c.name }
assert_equal(names.join(","), "C1,C2,C3")
names = []
nl.each_circuit_bottom_up { |c| names << c.name }
assert_equal(names.join(","), "C3,C2,C1")
c3.create_subcircuit(c2)
assert_equal(nl.top_circuit_count, 1)
names = []
c2.each_parent { |c| names << c.name }
assert_equal(names.join(","), "C1,C3")
names = []
c3.each_parent { |c| names << c.name }
assert_equal(names.join(","), "C1")
names = []
nl.each_circuit_top_down { |c| names << c.name }
assert_equal(names.join(","), "C1,C3,C2")
names = []
nl.each_circuit_bottom_up { |c| names << c.name }
assert_equal(names.join(","), "C2,C3,C1")
end
end
load("test_epilogue.rb")