mirror of https://github.com/KLayout/klayout.git
WIP: netlist topology - children, parents, top-down and bottom-up iteration.
This commit is contained in:
parent
2f48479838
commit
d57ede441c
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Reference in New Issue