mirror of https://github.com/KLayout/klayout.git
534 lines
15 KiB
C++
534 lines
15 KiB
C++
|
|
/*
|
|
|
|
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_dbNetlist
|
|
#define _HDR_dbNetlist
|
|
|
|
#include "dbCommon.h"
|
|
#include "dbCircuit.h"
|
|
#include "dbDeviceClass.h"
|
|
#include "dbDeviceAbstract.h"
|
|
|
|
#include "tlVector.h"
|
|
|
|
#include <string>
|
|
|
|
namespace db
|
|
{
|
|
|
|
/**
|
|
* @brief The netlist class
|
|
*
|
|
* This class represents a hierarchical netlist.
|
|
* The main components of a netlist are circuits and device classes.
|
|
* The circuits represent cells, the device classes type of devices.
|
|
*/
|
|
class DB_PUBLIC Netlist
|
|
: public gsi::ObjectBase, public tl::Object
|
|
{
|
|
public:
|
|
typedef tl::shared_collection<Circuit> circuit_list;
|
|
typedef circuit_list::const_iterator const_circuit_iterator;
|
|
typedef circuit_list::iterator circuit_iterator;
|
|
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::shared_collection<DeviceAbstract> device_abstract_list;
|
|
typedef device_abstract_list::const_iterator const_abstract_model_iterator;
|
|
typedef device_abstract_list::iterator device_abstract_iterator;
|
|
typedef dereferencing_iterator<tl::vector<Circuit *>::iterator, Circuit> top_down_circuit_iterator;
|
|
typedef dereferencing_iterator<tl::vector<const Circuit *>::const_iterator, const Circuit> const_top_down_circuit_iterator;
|
|
typedef dereferencing_iterator<tl::vector<Circuit *>::reverse_iterator, Circuit> bottom_up_circuit_iterator;
|
|
typedef dereferencing_iterator<tl::vector<const Circuit *>::const_reverse_iterator, const Circuit> const_bottom_up_circuit_iterator;
|
|
|
|
/**
|
|
* @brief Constructor
|
|
*
|
|
* This constructor creates an empty hierarchical netlist
|
|
*/
|
|
Netlist ();
|
|
|
|
/**
|
|
* @brief Copy constructor
|
|
*/
|
|
Netlist (const Netlist &other);
|
|
|
|
/**
|
|
* @brief Destructor
|
|
*/
|
|
~Netlist ();
|
|
|
|
/**
|
|
* @brief Assignment
|
|
*/
|
|
Netlist &operator= (const Netlist &other);
|
|
|
|
/**
|
|
* @brief Clears the netlist
|
|
*/
|
|
void clear ();
|
|
|
|
/**
|
|
* @brief Returns a parsable string representation of the netlist
|
|
*
|
|
* This method returns a string suitable for being put into from_string.
|
|
*/
|
|
std::string to_string () const;
|
|
|
|
/**
|
|
* @brief Reads a netlist from the string generated by to_parsable_string
|
|
*
|
|
* The device classes have to be installed so it's possible to identify the devices
|
|
* by their class.
|
|
*/
|
|
void from_string (const std::string &s);
|
|
|
|
/**
|
|
* @brief Starts a sequence of operations during which topology updates are not desired
|
|
*
|
|
* If the hierarchy is modified, the topology information (top-down order, children
|
|
* and parent information) may be recomputed frequently. This may cause performance issues
|
|
* and may not be desired.
|
|
*
|
|
* Calling this method will bring the netlist into a state in which updates on the
|
|
* list will not happen. Using "unlock" will end this state.
|
|
*
|
|
* "lock" and "unlock" are incremental and can be nested. Use "NetlistLocker" for safe locking
|
|
* and unlocking.
|
|
*
|
|
* Before lock, the state will be validated, so inside the locked operation, the topology
|
|
* information will be valid with respect to the initial state.
|
|
*/
|
|
void lock ();
|
|
|
|
/**
|
|
* @brief Ends a sequence of operations during which topology updates are not desired
|
|
* See "lock" for more details.
|
|
*/
|
|
void unlock ();
|
|
|
|
/**
|
|
* @brief Adds a circuit to this netlist
|
|
*
|
|
* The netlist takes over ownership of the object.
|
|
*/
|
|
void add_circuit (Circuit *circuit);
|
|
|
|
/**
|
|
* @brief Deletes a circuit from the netlist
|
|
*/
|
|
void remove_circuit (Circuit *circuit);
|
|
|
|
/**
|
|
* @brief Purges a circuit from the netlist
|
|
* In contrast to "delete", this method will
|
|
* also remove subcircuits unless called
|
|
* otherwise.
|
|
*/
|
|
void purge_circuit (Circuit *circuit);
|
|
|
|
/**
|
|
* @brief Gets the number of circuits
|
|
*/
|
|
size_t circuit_count () const
|
|
{
|
|
return m_circuits.size ();
|
|
}
|
|
|
|
/**
|
|
* @brief Flattens the given circuit
|
|
* All subcircuit references are replaced by the content of this circuit.
|
|
*/
|
|
void flatten_circuit (Circuit *circuit);
|
|
|
|
/**
|
|
* @brief Begin iterator for the circuits of the netlist (non-const version)
|
|
*/
|
|
circuit_iterator begin_circuits ()
|
|
{
|
|
return m_circuits.begin ();
|
|
}
|
|
|
|
/**
|
|
* @brief End iterator for the circuits of the netlist (non-const version)
|
|
*/
|
|
circuit_iterator end_circuits ()
|
|
{
|
|
return m_circuits.end ();
|
|
}
|
|
|
|
/**
|
|
* @brief Begin iterator for the circuits of the netlist (const version)
|
|
*/
|
|
const_circuit_iterator begin_circuits () const
|
|
{
|
|
return m_circuits.begin ();
|
|
}
|
|
|
|
/**
|
|
* @brief End iterator for the circuits of the netlist (const version)
|
|
*/
|
|
const_circuit_iterator end_circuits () const
|
|
{
|
|
return m_circuits.end ();
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the circuit with the given name
|
|
*
|
|
* If no circuit with that name exists, null is returned.
|
|
*/
|
|
Circuit *circuit_by_name (const std::string &name)
|
|
{
|
|
return m_circuit_by_name.object_by (name);
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the circuit with the given name (const version)
|
|
*
|
|
* If no circuit with that name exists, null is returned.
|
|
*/
|
|
const Circuit *circuit_by_name (const std::string &name) const
|
|
{
|
|
return m_circuit_by_name.object_by (name);
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the circuit with the given cell index
|
|
*
|
|
* If no circuit with that cell index exists, null is returned.
|
|
*/
|
|
Circuit *circuit_by_cell_index (db::cell_index_type cell_index)
|
|
{
|
|
return m_circuit_by_cell_index.object_by (cell_index);
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the circuit with the given cell index (const version)
|
|
*
|
|
* If no circuit with that cell index exists, null is returned.
|
|
*/
|
|
const Circuit *circuit_by_cell_index (db::cell_index_type cell_index) const
|
|
{
|
|
return m_circuit_by_cell_index.object_by (cell_index);
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*
|
|
* The netlist takes over ownership of the object.
|
|
*/
|
|
void add_device_class (DeviceClass *device_class);
|
|
|
|
/**
|
|
* @brief Deletes a device class from the netlist
|
|
*/
|
|
void remove_device_class (DeviceClass *device_class);
|
|
|
|
/**
|
|
* @brief Gets a device class by it's name (const version)
|
|
*
|
|
* This method returns 0 if there is no class with this name.
|
|
*/
|
|
const DeviceClass *device_class_by_name (const std::string &name) const
|
|
{
|
|
return const_cast<Netlist *> (this)->device_class_by_name (name);
|
|
}
|
|
|
|
/**
|
|
* @brief Gets a device class by it's name (non-const version)
|
|
*
|
|
* This method returns 0 if there is no class with this name.
|
|
*/
|
|
DeviceClass *device_class_by_name (const std::string &name);
|
|
|
|
/**
|
|
* @brief Begin iterator for the device classes of the netlist (non-const version)
|
|
*/
|
|
device_class_iterator begin_device_classes ()
|
|
{
|
|
return m_device_classes.begin ();
|
|
}
|
|
|
|
/**
|
|
* @brief End iterator for the device classes of the netlist (non-const version)
|
|
*/
|
|
device_class_iterator end_device_classes ()
|
|
{
|
|
return m_device_classes.end ();
|
|
}
|
|
|
|
/**
|
|
* @brief Begin iterator for the device classes of the netlist (const version)
|
|
*/
|
|
const_device_class_iterator begin_device_classes () const
|
|
{
|
|
return m_device_classes.begin ();
|
|
}
|
|
|
|
/**
|
|
* @brief End iterator for the device classes of the netlist (const version)
|
|
*/
|
|
const_device_class_iterator end_device_classes () const
|
|
{
|
|
return m_device_classes.end ();
|
|
}
|
|
|
|
/**
|
|
* @brief Adds a device abstract to this netlist
|
|
*
|
|
* The netlist takes over ownership of the object.
|
|
*/
|
|
void add_device_abstract (DeviceAbstract *device_abstract);
|
|
|
|
/**
|
|
* @brief Deletes a device abstract from the netlist
|
|
*/
|
|
void remove_device_abstract (DeviceAbstract *device_abstract);
|
|
|
|
/**
|
|
* @brief Begin iterator for the device abstracts of the netlist (non-const version)
|
|
*/
|
|
device_abstract_iterator begin_device_abstracts ()
|
|
{
|
|
return m_device_abstracts.begin ();
|
|
}
|
|
|
|
/**
|
|
* @brief End iterator for the device abstracts of the netlist (non-const version)
|
|
*/
|
|
device_abstract_iterator end_device_abstracts ()
|
|
{
|
|
return m_device_abstracts.end ();
|
|
}
|
|
|
|
/**
|
|
* @brief Begin iterator for the device abstracts of the netlist (const version)
|
|
*/
|
|
const_abstract_model_iterator begin_device_abstracts () const
|
|
{
|
|
return m_device_abstracts.begin ();
|
|
}
|
|
|
|
/**
|
|
* @brief End iterator for the device abstracts of the netlist (const version)
|
|
*/
|
|
const_abstract_model_iterator end_device_abstracts () const
|
|
{
|
|
return m_device_abstracts.end ();
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the device abstract with the given name
|
|
*
|
|
* If no device abstract with that name exists, null is returned.
|
|
*/
|
|
DeviceAbstract *device_abstract_by_name (const std::string &name)
|
|
{
|
|
return m_device_abstract_by_name.object_by (name);
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the device abstract with the given name (const version)
|
|
*
|
|
* If no device abstract with that name exists, null is returned.
|
|
*/
|
|
const DeviceAbstract *device_abstract_by_name (const std::string &name) const
|
|
{
|
|
return m_device_abstract_by_name.object_by (name);
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the device abstract with the given cell index
|
|
*
|
|
* If no device abstract with that cell index exists, null is returned.
|
|
*/
|
|
DeviceAbstract *device_abstract_by_cell_index (db::cell_index_type cell_index)
|
|
{
|
|
return m_device_abstract_by_cell_index.object_by (cell_index);
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the device abstract with the given cell index (const version)
|
|
*
|
|
* If no device abstract with that cell index exists, null is returned.
|
|
*/
|
|
const DeviceAbstract *device_abstract_by_cell_index (db::cell_index_type cell_index) const
|
|
{
|
|
return m_device_abstract_by_cell_index.object_by (cell_index);
|
|
}
|
|
|
|
/**
|
|
* @brief Purge unused nets
|
|
*
|
|
* This method will purge all nets which return "floating".
|
|
*/
|
|
void purge_nets ();
|
|
|
|
/**
|
|
* @brief Creates pins for top-level circuits
|
|
*
|
|
* This method will turn all named nets of top-level circuits (such that are not
|
|
* referenced by subcircuits) into pins. This method can be used before purge to
|
|
* avoid that purge will remove nets which are directly connecting to subcircuits.
|
|
*/
|
|
void make_top_level_pins ();
|
|
|
|
/**
|
|
* @brief Purge unused nets, circuits and subcircuits
|
|
*
|
|
* This method will purge all nets which return "floating". Circuits which don't have any
|
|
* nets (or only floating ones) and removed. Their subcircuits are disconnected.
|
|
*
|
|
* This method respects the circuit's "dont_purge" flag and will not purge them if this
|
|
* flag is set.
|
|
*/
|
|
void purge ();
|
|
|
|
/**
|
|
* @brief Convenience method: simplify (purge, combine devices, ...)
|
|
*/
|
|
void simplify ();
|
|
|
|
/**
|
|
* @brief Combine devices
|
|
*
|
|
* This method will combine devices that can be combined according
|
|
* to their device classes "combine_devices" method.
|
|
*/
|
|
void combine_devices ();
|
|
|
|
private:
|
|
friend class Circuit;
|
|
friend class DeviceAbstract;
|
|
|
|
circuit_list m_circuits;
|
|
device_class_list m_device_classes;
|
|
device_abstract_list m_device_abstracts;
|
|
bool m_valid_topology;
|
|
int m_lock_count;
|
|
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;
|
|
object_by_attr<Netlist, Netlist::circuit_iterator, name_attribute<Circuit> > m_circuit_by_name;
|
|
object_by_attr<Netlist, Netlist::circuit_iterator, cell_index_attribute<Circuit> > m_circuit_by_cell_index;
|
|
object_by_attr<Netlist, Netlist::device_abstract_iterator, name_attribute<DeviceAbstract> > m_device_abstract_by_name;
|
|
object_by_attr<Netlist, Netlist::device_abstract_iterator, cell_index_attribute<DeviceAbstract> > m_device_abstract_by_cell_index;
|
|
|
|
void invalidate_topology ();
|
|
void validate_topology ();
|
|
void circuits_changed ();
|
|
void device_abstracts_changed ();
|
|
|
|
const tl::vector<Circuit *> &child_circuits (Circuit *circuit);
|
|
const tl::vector<Circuit *> &parent_circuits (Circuit *circuit);
|
|
};
|
|
|
|
/**
|
|
* @brief A helper class using RAII for safe locking/unlocking
|
|
*/
|
|
class DB_PUBLIC NetlistLocker
|
|
{
|
|
public:
|
|
NetlistLocker (Netlist *netlist)
|
|
: mp_netlist (netlist)
|
|
{
|
|
if (mp_netlist.get ()) {
|
|
mp_netlist->lock ();
|
|
}
|
|
}
|
|
|
|
~NetlistLocker ()
|
|
{
|
|
if (mp_netlist.get ()) {
|
|
mp_netlist->unlock ();
|
|
}
|
|
}
|
|
|
|
private:
|
|
tl::weak_ptr<Netlist> mp_netlist;
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|