klayout/src/db/db/dbCircuit.h

861 lines
22 KiB
C++

/*
KLayout Layout Viewer
Copyright (C) 2006-2024 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_dbCircuit
#define _HDR_dbCircuit
#include "dbCommon.h"
#include "dbTypes.h"
#include "dbNet.h"
#include "dbDevice.h"
#include "dbPin.h"
#include "dbSubCircuit.h"
#include "dbNetlistUtils.h"
#include "dbPolygon.h"
#include "dbMemStatistics.h"
#include "tlObject.h"
#include "tlObjectCollection.h"
#include "tlVector.h"
#include "gsiObject.h"
namespace db
{
class Netlist;
class Layout;
/**
* @brief An iterator wrapper for the child and parent circuit iterator
*/
template <class Iter, class Value>
struct DB_PUBLIC_TEMPLATE dereferencing_iterator
: public Iter
{
public:
typedef Value *pointer;
typedef Value &reference;
typedef typename Iter::difference_type difference_type;
dereferencing_iterator () { }
dereferencing_iterator (const dereferencing_iterator &d) : Iter (d) { }
dereferencing_iterator (const Iter &d) : Iter (d) { }
dereferencing_iterator &operator= (const dereferencing_iterator &d)
{
Iter::operator= (d);
return *this;
}
dereferencing_iterator operator+ (difference_type offset) const
{
return dereferencing_iterator (Iter::operator+ (offset));
}
dereferencing_iterator &operator+= (difference_type offset)
{
Iter::operator+= (offset);
return *this;
}
pointer operator-> () const { return Iter::operator* (); }
reference operator* () const { return *Iter::operator* (); }
};
/**
* @brief A circuit
*
* A circuit is a list of nets, of subcircuit references and actual
* devices.
*/
class DB_PUBLIC Circuit
: public db::NetlistObject, public gsi::ObjectBase
{
public:
typedef std::list<Pin> pin_list;
typedef pin_list::const_iterator const_pin_iterator;
typedef pin_list::iterator pin_iterator;
typedef tl::shared_collection<Device> device_list;
typedef device_list::const_iterator const_device_iterator;
typedef device_list::iterator device_iterator;
typedef tl::shared_collection<Net> net_list;
typedef net_list::const_iterator const_net_iterator;
typedef net_list::iterator net_iterator;
typedef tl::shared_collection<SubCircuit> subcircuit_list;
typedef subcircuit_list::const_iterator const_subcircuit_iterator;
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 dereferencing_iterator<tl::vector<Circuit *>::const_iterator, Circuit> child_circuit_iterator;
typedef dereferencing_iterator<tl::vector<const Circuit *>::const_iterator, const Circuit> const_child_circuit_iterator;
typedef dereferencing_iterator<tl::vector<Circuit *>::const_iterator, Circuit> parent_circuit_iterator;
typedef dereferencing_iterator<tl::vector<const Circuit *>::const_iterator, const Circuit> const_parent_circuit_iterator;
/**
* @brief Constructor
*
* Creates an empty circuit.
*/
Circuit ();
/**
* @brief Constructor
*
* Creates a circuit corresponding to a layout cell
*/
Circuit (const db::Layout &layout, db::cell_index_type ci);
/**
* @brief Copy constructor
*/
Circuit (const Circuit &other);
/**
* @brief Destructor
*/
~Circuit ();
/**
* @brief Assignment
*/
Circuit &operator= (const Circuit &other);
/**
* @brief Gets the netlist the circuit lives in
* This pointer is 0 if the circuit is not part of a netlist.
*/
Netlist *netlist ()
{
return mp_netlist;
}
/**
* @brief Gets the netlist the circuit lives in (const version)
* This pointer is 0 if the circuit is not part of a netlist.
*/
const Netlist *netlist () const
{
return mp_netlist;
}
/**
* @brief Clears the circuit
*/
void clear ();
/**
* @brief Sets the name of the circuit
*/
void set_name (const std::string &name);
/**
* @brief Gets the name of the circuit
*/
const std::string &name () const
{
return m_name;
}
/**
* @brief Sets the boundary
*/
void set_boundary (const db::DPolygon &boundary);
/**
* @brief Gets the boundary
*/
const db::DPolygon &boundary () const
{
return m_boundary;
}
/**
* @brief Sets or resets the "don't purge" flag
* This flag will prevent "purge" from deleting this circuit. It is set by "blank".
*/
void set_dont_purge (bool dp);
/**
* @brief Gets or resets the "don't purge" flag
*/
bool dont_purge () const
{
return m_dont_purge;
}
/**
* @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
*
* The layout cell reference links a circuit to a layout cell.
*/
void set_cell_index (const db::cell_index_type ci);
/**
* @brief Gets the layout cell index
*/
db::cell_index_type cell_index () const
{
return m_cell_index;
}
/**
* @brief Gets the references to this circuit (begin, non-const version)
* This iterator will deliver all subcircuits referencing this circuit
*/
refs_iterator begin_refs ()
{
return m_refs.begin ();
}
/**
* @brief Gets the references to this circuit (end, non-const version)
* This iterator will deliver all subcircuits referencing this circuit
*/
refs_iterator end_refs ()
{
return m_refs.end ();
}
/**
* @brief Gets the references to this circuit (begin, const version)
* This iterator will deliver all subcircuits referencing this circuit
*/
const_refs_iterator begin_refs () const
{
return m_refs.begin ();
}
/**
* @brief Gets the references to this circuit (end, const version)
* This iterator will deliver all subcircuits referencing this circuit
*/
const_refs_iterator end_refs () const
{
return m_refs.end ();
}
/**
* @brief Returns a value indicating whether the circuit has references
*/
bool has_refs () const
{
return begin_refs () != end_refs ();
}
/**
* @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 Clears the pins
*/
void clear_pins ();
/**
* @brief Adds a pin to this circuit
*/
Pin &add_pin (const std::string &name);
/**
* @brief Adds a pin to this circuit
* This version uses the given pin as the template.
*/
Pin &add_pin (const Pin &pin);
/**
* @brief Removes the pin with the given ID
*/
void remove_pin (size_t id);
/**
* @brief Begin iterator for the pins of the circuit (non-const version)
*/
pin_iterator begin_pins ()
{
return m_pins.begin ();
}
/**
* @brief End iterator for the pins of the circuit (non-const version)
*/
pin_iterator end_pins ()
{
return m_pins.end ();
}
/**
* @brief Gets the pin count
*/
size_t pin_count () const
{
return m_pins.size ();
}
/**
* @brief Gets the pin by ID (the ID is basically the index)
*/
const Pin *pin_by_id (size_t id) const;
/**
* @brief Gets the pin by ID (the ID is basically the index) - non-const version
*/
Pin *pin_by_id (size_t id)
{
return const_cast<Pin *> (((const db::Circuit *) this)->pin_by_id (id));
}
/**
* @brief Gets the pin by name
*
* If there is no pin with that name, null is returned.
* NOTE: this is a linear search, so it's performance may not be good for many pins.
*/
const Pin *pin_by_name (const std::string &name) const;
/**
* @brief Gets the pin by name - non-const version
*/
Pin *pin_by_name (const std::string &name)
{
return const_cast<Pin *> (((const db::Circuit *) this)->pin_by_name (name));
}
/**
* @brief Begin iterator for the pins of the circuit (const version)
*/
const_pin_iterator begin_pins () const
{
return m_pins.begin ();
}
/**
* @brief End iterator for the pins of the circuit (const version)
*/
const_pin_iterator end_pins () const
{
return m_pins.end ();
}
/**
* @brief Adds a net to this circuit
*
* The circuit takes over ownership of the object.
*/
void add_net (Net *net);
/**
* @brief Deletes a net from the circuit
*/
void remove_net (Net *net);
/**
* @brief Joins the second net with the first one and removes the second net
*/
void join_nets (Net *net, Net *with);
/**
* @brief Gets the number of nets
*/
size_t net_count () const
{
return m_nets.size ();
}
/**
* @brief Begin iterator for the nets of the circuit (non-const version)
*/
net_iterator begin_nets ()
{
return m_nets.begin ();
}
/**
* @brief End iterator for the nets of the circuit (non-const version)
*/
net_iterator end_nets ()
{
return m_nets.end ();
}
/**
* @brief Begin iterator for the nets of the circuit (const version)
*/
const_net_iterator begin_nets () const
{
return m_nets.begin ();
}
/**
* @brief End iterator for the nets of the circuit (const version)
*/
const_net_iterator end_nets () const
{
return m_nets.end ();
}
/**
* @brief Gets the net from a given cluster ID (const version)
*
* If the cluster ID is not valid, null is returned.
*/
const Net *net_by_cluster_id (size_t cluster_id) const
{
return (const_cast<Circuit *> (this)->net_by_cluster_id (cluster_id));
}
/**
* @brief Gets the net from a given cluster ID (non-const version)
*
* If the cluster ID is not valid, null is returned.
*/
Net *net_by_cluster_id (size_t cluster_id)
{
return m_net_by_cluster_id.object_by (cluster_id);
}
/**
* @brief Gets the net from a given name (const version)
*
* If the name is not valid, null is returned.
*/
const Net *net_by_name (const std::string &name) const
{
return (const_cast<Circuit *> (this)->net_by_name (name));
}
/**
* @brief Gets the net from a given name (non-const version)
*
* If the name is not valid, null is returned.
*/
Net *net_by_name (const std::string &name);
/**
* @brief Adds a device to this circuit
*
* The circuit takes over ownership of the object.
*/
void add_device (Device *device);
/**
* @brief Deletes a device from the circuit
*/
void remove_device (Device *device);
/**
* @brief Gets the number of devices
*/
size_t device_count () const
{
return m_devices.size ();
}
/**
* @brief Gets the device from a given ID (const version)
*
* If the ID is not valid, null is returned.
*/
const Device *device_by_id (size_t id) const
{
return (const_cast<Circuit *> (this)->device_by_id (id));
}
/**
* @brief Gets the device from a given ID (non-const version)
*
* If the ID is not valid, null is returned.
*/
Device *device_by_id (size_t id)
{
return m_device_by_id.object_by (id);
}
/**
* @brief Gets the device from a given name (const version)
*
* If the name is not valid, null is returned.
*/
const Device *device_by_name (const std::string &name) const
{
return (const_cast<Circuit *> (this)->device_by_name (name));
}
/**
* @brief Gets the device from a given name (non-const version)
*
* If the name is not valid, null is returned.
*/
Device *device_by_name (const std::string &name);
/**
* @brief Begin iterator for the devices of the circuit (non-const version)
*/
device_iterator begin_devices ()
{
return m_devices.begin ();
}
/**
* @brief End iterator for the devices of the circuit (non-const version)
*/
device_iterator end_devices ()
{
return m_devices.end ();
}
/**
* @brief Begin iterator for the devices of the circuit (const version)
*/
const_device_iterator begin_devices () const
{
return m_devices.begin ();
}
/**
* @brief End iterator for the devices of the circuit (const version)
*/
const_device_iterator end_devices () const
{
return m_devices.end ();
}
/**
* @brief Adds a subcircuit to this circuit
*
* The circuit takes over ownership of the object.
*/
void add_subcircuit (SubCircuit *subcircuit);
/**
* @brief Deletes a subcircuit from the circuit
*/
void remove_subcircuit (SubCircuit *subcircuit);
/**
* @brief Gets the number of subcircuits
*/
size_t subcircuit_count () const
{
return m_subcircuits.size ();
}
/**
* @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<Circuit *> (this)->subcircuit_by_id (id));
}
/**
* @brief Gets the subcircuit from a given ID (non-const version)
*
* If the ID is not valid, null is returned.
*/
SubCircuit *subcircuit_by_id (size_t id)
{
return m_subcircuit_by_id.object_by (id);
}
/**
* @brief Gets the subcircuit from a given name (const version)
*
* If the name is not valid, null is returned.
*/
const SubCircuit *subcircuit_by_name (const std::string &name) const
{
return (const_cast<Circuit *> (this)->subcircuit_by_name (name));
}
/**
* @brief Gets the subcircuit from a given name (non-const version)
*
* If the name is not valid, null is returned.
*/
SubCircuit *subcircuit_by_name (const std::string &name);
/**
* @brief Begin iterator for the subcircuits of the circuit (non-const version)
*/
subcircuit_iterator begin_subcircuits ()
{
return m_subcircuits.begin ();
}
/**
* @brief End iterator for the subcircuits of the circuit (non-const version)
*/
subcircuit_iterator end_subcircuits ()
{
return m_subcircuits.end ();
}
/**
* @brief Begin iterator for the subcircuits of the circuit (const version)
*/
const_subcircuit_iterator begin_subcircuits () const
{
return m_subcircuits.begin ();
}
/**
* @brief End iterator for the subcircuits of the circuit (const version)
*/
const_subcircuit_iterator end_subcircuits () const
{
return m_subcircuits.end ();
}
/**
* @brief Gets the connected net for a pin with the given id
*
* Returns 0 if the pin is not connected to a net.
*/
const Net *net_for_pin (size_t pin_id) const;
/**
* @brief Gets the connected net for a pin with the given id (non-const version)
*
* Returns 0 if the pin is not connected to a net.
*/
Net *net_for_pin (size_t pin_id)
{
return const_cast<Net *> (((const Circuit *) this)->net_for_pin (pin_id));
}
/**
* @brief Connects the given pin to the given net
* If the net is 0 the pin is disconnected.
* If non-null, a NetPinRef object will be inserted into the
* net and connected with the given pin.
*/
void connect_pin (size_t pin_id, Net *net);
/**
* @brief Adds a pin to the given net
* The pin will be added to the net. If there is already a pin
* on the net, the existing and new pin will be joined.
* This usually implies that nets further up in the hierarchy
* are joined too.
*/
void join_pin_with_net (size_t pin_id, Net *net);
/**
* @brief Renames the pin with the given ID
*/
void rename_pin (size_t pin_id, const std::string &name);
/**
* @brief Purge unused nets
*
* This method will purge all nets which return "is_passive".
* Pins on these nets will also be removed.
*/
void purge_nets ();
/**
* @brief Purge unused nets but
*
* This method will purge all nets which return "is_passive".
* Pins on these nets will be kept but their net will be 0.
*/
void purge_nets_keep_pins ();
/**
* @brief Purges invalid devices
*
* This method will purge all invalid devices, i.e. those
* whose terminals are all connected to the same net.
*/
void purge_devices ();
/**
* @brief Combine devices
*
* This method will combine devices that can be combined according
* to their device classes "combine_devices" method.
*/
void combine_devices ();
/**
* @brief Flattens the given subcircuit
*
* The subcircuit is resolved into the parent circuit and finally removed.
* Net, device and subcircuit names are decorated with the subcircuit's name
* if required.
*/
void flatten_subcircuit (SubCircuit *subcircuit);
/**
* @brief Blanks out the circuit
*
* This will remove all innards of the circuit (nets, devices, subcircuits)
* and circuits which will itself are not longer be called after this.
* This operation will eventually leave a blackbox model of the circuit
* containing only pins.
*/
void blank ();
/**
* @brief Gets a value indicating whether the circuit is empty
*/
bool is_empty () const;
/**
* @brief Generate memory statistics
*/
void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const
{
if (! no_self) {
stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat);
}
db::mem_stat (stat, purpose, cat, m_name, true, (void *) this);
db::mem_stat (stat, purpose, cat, m_boundary, true, (void *) this);
db::mem_stat (stat, purpose, cat, m_nets, true, (void *) this);
db::mem_stat (stat, purpose, cat, m_pins, true, (void *) this);
db::mem_stat (stat, purpose, cat, m_pin_by_id, true, (void *) this);
db::mem_stat (stat, purpose, cat, m_devices, true, (void *) this);
db::mem_stat (stat, purpose, cat, m_subcircuits, true, (void *) this);
db::mem_stat (stat, purpose, cat, m_pin_refs, true, (void *) this);
db::mem_stat (stat, purpose, cat, m_device_by_id, true, (void *) this);
db::mem_stat (stat, purpose, cat, m_subcircuit_by_id, true, (void *) this);
db::mem_stat (stat, purpose, cat, m_net_by_cluster_id, true, (void *) this);
db::mem_stat (stat, purpose, cat, m_device_by_name, true, (void *) this);
db::mem_stat (stat, purpose, cat, m_subcircuit_by_name, true, (void *) this);
db::mem_stat (stat, purpose, cat, m_net_by_name, true, (void *) this);
db::mem_stat (stat, purpose, cat, m_refs, true, (void *) this);
}
private:
friend class Netlist;
friend class Net;
friend class SubCircuit;
friend class Device;
std::string m_name;
db::DPolygon m_boundary;
bool m_dont_purge;
db::cell_index_type m_cell_index;
net_list m_nets;
pin_list m_pins;
std::vector<pin_list::iterator> m_pin_by_id;
device_list m_devices;
subcircuit_list m_subcircuits;
Netlist *mp_netlist;
std::vector<Net::pin_iterator> m_pin_refs;
object_by_attr<Circuit, Circuit::device_iterator, id_attribute<Device> > m_device_by_id;
object_by_attr<Circuit, Circuit::subcircuit_iterator, id_attribute<SubCircuit> > m_subcircuit_by_id;
object_by_attr<Circuit, Circuit::net_iterator, cluster_id_attribute<Net> > m_net_by_cluster_id;
object_by_attr<Circuit, Circuit::device_iterator, name_attribute<Device> > m_device_by_name;
object_by_attr<Circuit, Circuit::subcircuit_iterator, name_attribute<SubCircuit> > m_subcircuit_by_name;
object_by_attr<Circuit, Circuit::net_iterator, name_attribute<Net> > m_net_by_name;
tl::weak_collection<SubCircuit> m_refs;
size_t m_index;
void set_index (size_t index)
{
m_index = index;
}
void set_pin_ref_for_pin (size_t ppin_id, Net::pin_iterator iter);
void register_ref (SubCircuit *sc);
void unregister_ref (SubCircuit *sc);
void translate_circuits (const std::map<const Circuit *, Circuit *> &map);
void translate_device_classes (const std::map<const DeviceClass *, DeviceClass *> &map);
void translate_device_abstracts (const std::map<const DeviceAbstract *, DeviceAbstract *> &map);
void set_netlist (Netlist *netlist);
bool combine_parallel_devices (const db::DeviceClass &cls);
bool combine_serial_devices (const db::DeviceClass &cls);
void do_purge_nets (bool keep_pins);
void join_pins (size_t pin_id, size_t with);
void devices_changed ();
void subcircuits_changed ();
void nets_changed ();
};
/**
* @brief Memory statistics for Circuit
*/
inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const Circuit &x, bool no_self, void *parent)
{
x.mem_stat (stat, purpose, cat, no_self, parent);
}
}
#endif