WIP: global nets integration in cluster builder.

This commit is contained in:
Matthias Koefferlein 2019-01-07 02:08:59 +01:00
parent a4f0fd665e
commit c80e335cd6
21 changed files with 749 additions and 411 deletions

View File

@ -104,17 +104,8 @@ Connectivity::end_global_connections (unsigned int l) const
size_t
Connectivity::connect_global (unsigned int l, const std::string &gn)
{
for (std::vector<std::string>::const_iterator i = m_global_net_names.begin (); i != m_global_net_names.end (); ++i) {
if (*i == gn) {
size_t id = i - m_global_net_names.begin ();
m_global_connections [l].insert (id);
return id;
}
}
size_t id = m_global_net_names.size ();
size_t id = global_net_id (gn);
m_global_connections [l].insert (id);
m_global_net_names.push_back (gn);
return id;
}
@ -131,6 +122,21 @@ Connectivity::global_net_name (size_t id) const
return m_global_net_names [id];
}
size_t
Connectivity::global_net_id (const std::string &gn)
{
for (std::vector<std::string>::const_iterator i = m_global_net_names.begin (); i != m_global_net_names.end (); ++i) {
if (*i == gn) {
size_t id = i - m_global_net_names.begin ();
return id;
}
}
size_t id = m_global_net_names.size ();
m_global_net_names.push_back (gn);
return id;
}
Connectivity::layer_iterator
Connectivity::begin_layers () const
{
@ -225,6 +231,7 @@ local_cluster<T>::clear ()
m_size = 0;
m_bbox = box_type ();
m_attrs.clear ();
m_global_nets.clear ();
}
template <class T>
@ -262,6 +269,7 @@ local_cluster<T>::join_with (const local_cluster<T> &other)
}
m_attrs.insert (other.m_attrs.begin (), other.m_attrs.end ());
m_global_nets.insert (other.m_global_nets.begin (), other.m_global_nets.end ());
m_size += other.size ();
m_needs_update = true;
@ -1450,95 +1458,7 @@ private:
*/
ClusterInstance make_path (id_type id, const std::vector<db::InstElement> &path) const
{
std::vector<db::InstElement>::const_iterator p = path.end ();
tl_assert (p != path.begin ());
while (true) {
--p;
ClusterInstance ci (id, *p);
if (p == path.begin ()) {
// if we're attaching to a child which is root yet, we need to promote the
// cluster to the parent in all places
connected_clusters<T> &child_cc = mp_tree->clusters_per_cell (p->inst_ptr.cell_index ());
if (child_cc.is_root (id)) {
const db::Cell &child_cell = mp_layout->cell (p->inst_ptr.cell_index ());
for (db::Cell::parent_inst_iterator pi = child_cell.begin_parent_insts (); ! pi.at_end (); ++pi) {
connected_clusters<T> &parent_cc = mp_tree->clusters_per_cell (pi->parent_cell_index ());
for (db::CellInstArray::iterator pii = pi->child_inst ().begin (); ! pii.at_end (); ++pii) {
ClusterInstance ci2 (id, db::InstElement (pi->child_inst (), pii));
if (mp_cell->cell_index () != pi->parent_cell_index () || ci != ci2) {
id_type id_dummy = parent_cc.insert_dummy ();
parent_cc.add_connection (id_dummy, ci2);
}
}
}
child_cc.reset_root (id);
}
return ci;
}
db::cell_index_type pci = p [-1].inst_ptr.cell_index ();
connected_clusters<T> &target_cc = mp_tree->clusters_per_cell (pci);
id_type parent_cluster = target_cc.find_cluster_with_connection (ci);
if (parent_cluster > 0) {
// taken parent
id = parent_cluster;
} else {
id_type id_new = 0;
// if we're attaching to a child which is root yet, we need to promote the
// cluster to the parent in all places
connected_clusters<T> &child_cc = mp_tree->clusters_per_cell (p->inst_ptr.cell_index ());
if (child_cc.is_root (id)) {
const db::Cell &child_cell = mp_layout->cell (p->inst_ptr.cell_index ());
for (db::Cell::parent_inst_iterator pi = child_cell.begin_parent_insts (); ! pi.at_end (); ++pi) {
connected_clusters<T> &parent_cc = mp_tree->clusters_per_cell (pi->parent_cell_index ());
for (db::CellInstArray::iterator pii = pi->child_inst ().begin (); ! pii.at_end (); ++pii) {
id_type id_dummy = parent_cc.insert_dummy ();
ClusterInstance ci2 (id, db::InstElement (pi->child_inst (), pii));
parent_cc.add_connection (id_dummy, ci2);
if (pci == pi->parent_cell_index () && ci == ci2) {
id_new = id_dummy;
}
}
}
child_cc.reset_root (id);
}
// no parent -> create vertical connector
id = id_new;
tl_assert (id != 0);
}
}
return mp_tree->make_path (*mp_layout, *mp_cell, id, path);
}
};
@ -1565,6 +1485,120 @@ private:
}
template <class T>
ClusterInstance
hier_clusters<T>::make_path (const db::Layout &layout, const db::Cell &cell, size_t id, const std::vector<db::InstElement> &path)
{
std::vector<db::InstElement>::const_iterator p = path.end ();
tl_assert (p != path.begin ());
while (true) {
--p;
ClusterInstance ci (id, *p);
if (p == path.begin ()) {
// if we're attaching to a child which is root yet, we need to promote the
// cluster to the parent in all places
connected_clusters<T> &child_cc = clusters_per_cell (p->inst_ptr.cell_index ());
if (child_cc.is_root (id)) {
const db::Cell &child_cell = layout.cell (p->inst_ptr.cell_index ());
for (db::Cell::parent_inst_iterator pi = child_cell.begin_parent_insts (); ! pi.at_end (); ++pi) {
connected_clusters<T> &parent_cc = clusters_per_cell (pi->parent_cell_index ());
for (db::CellInstArray::iterator pii = pi->child_inst ().begin (); ! pii.at_end (); ++pii) {
ClusterInstance ci2 (id, db::InstElement (pi->child_inst (), pii));
if (cell.cell_index () != pi->parent_cell_index () || ci != ci2) {
size_t id_dummy;
const typename db::local_cluster<T>::global_nets &gn = child_cc.cluster_by_id (id).get_global_nets ();
if (gn.empty ()) {
id_dummy = parent_cc.insert_dummy ();
} else {
local_cluster<T> *lc = parent_cc.insert ();
lc->set_global_nets (gn);
id_dummy = lc->id ();
}
parent_cc.add_connection (id_dummy, ci2);
}
}
}
child_cc.reset_root (id);
}
return ci;
}
db::cell_index_type pci = p [-1].inst_ptr.cell_index ();
connected_clusters<T> &target_cc = clusters_per_cell (pci);
size_t parent_cluster = target_cc.find_cluster_with_connection (ci);
if (parent_cluster > 0) {
// taken parent
id = parent_cluster;
} else {
size_t id_new = 0;
// if we're attaching to a child which is root yet, we need to promote the
// cluster to the parent in all places
connected_clusters<T> &child_cc = clusters_per_cell (p->inst_ptr.cell_index ());
if (child_cc.is_root (id)) {
const db::Cell &child_cell = layout.cell (p->inst_ptr.cell_index ());
for (db::Cell::parent_inst_iterator pi = child_cell.begin_parent_insts (); ! pi.at_end (); ++pi) {
connected_clusters<T> &parent_cc = clusters_per_cell (pi->parent_cell_index ());
for (db::CellInstArray::iterator pii = pi->child_inst ().begin (); ! pii.at_end (); ++pii) {
size_t id_dummy;
const typename db::local_cluster<T>::global_nets &gn = child_cc.cluster_by_id (id).get_global_nets ();
if (gn.empty ()) {
id_dummy = parent_cc.insert_dummy ();
} else {
local_cluster<T> *lc = parent_cc.insert ();
lc->set_global_nets (gn);
id_dummy = lc->id ();
}
ClusterInstance ci2 (id, db::InstElement (pi->child_inst (), pii));
parent_cc.add_connection (id_dummy, ci2);
if (pci == pi->parent_cell_index () && ci == ci2) {
id_new = id_dummy;
}
}
}
child_cc.reset_root (id);
}
// no parent -> create vertical connector
id = id_new;
tl_assert (id != 0);
}
}
}
template <class T>
void
hier_clusters<T>::do_build (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn)
@ -1648,6 +1682,83 @@ hier_clusters<T>::build_hier_connections_for_cells (cell_clusters_box_converter<
}
}
namespace {
class GlobalNetClusterMaker
{
public:
typedef std::pair<std::set<size_t>, std::set<ClusterInstance> > entry_type;
typedef std::list<entry_type> entry_list;
typedef entry_list::const_iterator entry_iterator;
void
add (const std::set<size_t> &global_nets, size_t cluster_id)
{
add (global_nets, ClusterInstance (cluster_id, db::InstElement ()));
}
void
add (const std::set<size_t> &global_nets, const ClusterInstance &inst)
{
if (global_nets.empty ()) {
return;
}
std::set<size_t>::const_iterator g0 = global_nets.begin ();
std::map<size_t, entry_list::iterator>::iterator k = m_global_net_to_entries.find (*g0);
if (k == m_global_net_to_entries.end ()) {
m_entries.push_back (entry_type ());
m_entries.back ().first.insert (*g0);
k = m_global_net_to_entries.insert (std::make_pair (*g0, --m_entries.end ())).first;
}
k->second->second.insert (inst);
for (std::set<size_t>::const_iterator g = ++g0; g != global_nets.end (); ++g) {
std::map<size_t, entry_list::iterator>::iterator j = m_global_net_to_entries.find (*g);
if (j == m_global_net_to_entries.end ()) {
k->second->first.insert (*g);
k->second->second.insert (inst);
m_global_net_to_entries.insert (std::make_pair (*g, k->second));
} else if (k->second != j->second) {
// joining required
k->second->first.insert (j->second->first.begin (), j->second->first.end ());
k->second->second.insert (j->second->second.begin (), j->second->second.end ());
m_entries.erase (j->second);
j->second = k->second;
}
}
}
entry_iterator begin () const
{
return m_entries.begin ();
}
entry_iterator end () const
{
return m_entries.end ();
}
private:
entry_list m_entries;
std::map<size_t, entry_list::iterator> m_global_net_to_entries;
};
}
template <class T>
void
hier_clusters<T>::build_hier_connections (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn)
@ -1662,7 +1773,7 @@ hier_clusters<T>::build_hier_connections (cell_clusters_box_converter<T> &cbc, c
// NOTE: this is a receiver for both the child-to-child and
// local to child interactions.
hc_receiver<T> rec (layout, cell, local, *this, cbc, conn);
std::auto_ptr<hc_receiver<T> > rec (new hc_receiver<T> (layout, cell, local, *this, cbc, conn));
cell_inst_clusters_box_converter<T> cibc (cbc);
// The box scanner needs pointers so we have to first store the instances
@ -1694,7 +1805,7 @@ hier_clusters<T>::build_hier_connections (cell_clusters_box_converter<T> &cbc, c
bs.insert (inst.operator-> (), 0);
}
bs.process (rec, 1 /*touching*/, cibc);
bs.process (*rec, 1 /*touching*/, cibc);
}
// handle local to instance connections
@ -1729,11 +1840,79 @@ hier_clusters<T>::build_hier_connections (cell_clusters_box_converter<T> &cbc, c
bs2.insert2 (inst.operator-> (), 0);
}
bs2.process (rec, 1 /*touching*/, local_cluster_box_convert<T> (), cibc);
bs2.process (*rec, 1 /*touching*/, local_cluster_box_convert<T> (), cibc);
}
// finally join local clusters which got connected by child clusters
rec.join_superclusters ();
// join local clusters which got connected by child clusters
rec->join_superclusters ();
rec.reset (0);
// finally connect global nets
{
static std::string desc = tl::to_string (tr ("Global net treatment"));
tl::SelfTimer timer (tl::verbosity () >= 51, desc);
GlobalNetClusterMaker global_net_clusters;
// insert the global nets from the subcircuits which need connection
for (std::vector<db::Instance>::const_iterator inst = inst_storage.begin (); inst != inst_storage.end (); ++inst) {
const db::connected_clusters<T> &cc = m_per_cell_clusters [inst->cell_index ()];
for (typename db::connected_clusters<T>::const_iterator cl = cc.begin (); cl != cc.end (); ++cl) {
if (! cl->get_global_nets ().empty () && cc.is_root (cl->id ())) {
for (db::Instance::cell_inst_array_type::iterator i = inst->begin (); !i.at_end (); ++i) {
global_net_clusters.add (cl->get_global_nets (), db::ClusterInstance (cl->id (), db::InstElement (*inst, i)));
}
}
}
}
// insert the global nets from here
for (typename db::connected_clusters<T>::const_iterator cl = local.begin (); cl != local.end (); ++cl) {
if (! cl->get_global_nets ().empty ()) {
global_net_clusters.add (cl->get_global_nets (), db::ClusterInstance (cl->id (), db::InstElement ()));
}
}
// now global_net_clusters knows what clusters need to be made for the global nets
for (GlobalNetClusterMaker::entry_iterator ge = global_net_clusters.begin (); ge != global_net_clusters.end (); ++ge) {
db::local_cluster<T> *gc = local.insert ();
gc->set_global_nets (ge->first);
for (std::set<ClusterInstance>::const_iterator ci = ge->second.begin (); ci != ge->second.end (); ++ci) {
if (ci->inst ().array_inst.at_end ()) {
local.join_cluster_with (gc->id (), ci->id ());
local.remove_cluster (ci->id ());
} else {
std::vector<db::InstElement> p;
p.push_back (ci->inst ());
ClusterInstance k = make_path (layout, cell, ci->id (), p);
size_t other_id = local.find_cluster_with_connection (k);
if (other_id) {
local.join_cluster_with (gc->id (), other_id);
local.remove_cluster (other_id);
} else {
local.add_connection (gc->id (), k);
}
}
}
}
}
}
template <class T>

View File

@ -99,6 +99,11 @@ public:
*/
const std::string &global_net_name (size_t id) const;
/**
* @brief Gets the global net ID for the given name
*/
size_t global_net_id (const std::string &gn);
/**
* @brief Begin iterator for the layers involved
*/
@ -306,6 +311,14 @@ public:
return m_global_nets.end ();
}
/**
* @brief Gets the global nets set
*/
const global_nets &get_global_nets () const
{
return m_global_nets;
}
/**
* @brief Sets the global nets
*/
@ -767,6 +780,14 @@ public:
*/
void clear ();
/**
* @brief Makes a valid path to a child cluster
*
* Cluster connections can only cross one level of hierarchy. This method
* creates necessary dummy entries for the given path.
*/
ClusterInstance make_path (const db::Layout &layout, const db::Cell &cell, size_t id, const std::vector<db::InstElement> &path);
private:
void build_local_cluster (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn);
void build_hier_connections (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn);

View File

@ -170,6 +170,11 @@ const std::string &LayoutToNetlist::global_net_name (size_t id) const
return m_conn.global_net_name (id);
}
size_t LayoutToNetlist::global_net_id (const std::string &name)
{
return m_conn.global_net_id (name);
}
void LayoutToNetlist::extract_netlist ()
{
if (m_netlist_extracted) {
@ -275,7 +280,6 @@ static void deliver_shapes_of_net_nonrecursive (const db::NetlistExtractor &nete
tl_assert (circuit != 0);
db::cell_index_type ci = circuit->cell_index ();
const db::local_cluster<db::PolygonRef> &lc = netex.clusters ().clusters_per_cell (ci).cluster_by_id (net.cluster_id ());
for (db::local_cluster<db::PolygonRef>::shape_iterator s = lc.begin (layer_id); !s.at_end (); ++s) {

View File

@ -176,6 +176,11 @@ public:
*/
const std::string &global_net_name (size_t id) const;
/**
* @brief Gets the global net ID for a given name name
*/
size_t global_net_id (const std::string &name);
/**
* @brief Runs the netlist extraction
* See the class description for more details.

View File

@ -113,22 +113,8 @@ const Net *Device::net_for_terminal (size_t terminal_id) const
return 0;
}
void Device::connect_terminal_global (size_t terminal_id, size_t global_net_id)
{
connect_terminal (terminal_id, 0);
m_global_connections.push_back (std::make_pair (terminal_id, global_net_id));
}
void Device::connect_terminal (size_t terminal_id, Net *net)
{
for (size_t i = 0; i < m_global_connections.size (); ) {
if (m_global_connections [i].first == terminal_id) {
m_global_connections.erase (m_global_connections.begin () + i);
} else {
++i;
}
}
if (net_for_terminal (terminal_id) == net) {
return;
}

View File

@ -884,31 +884,6 @@ public:
return m_name;
}
/**
* @brief Gets the global connections iterator (begin)
* Global connections are terminals attached to a global net.
* This iterator delivers a pair of terminal ID (first)
* and global net ID (second).
* See Connectivity for the definition of the global net ID.
*/
global_connections_iterator begin_global_connections () const
{
return m_global_connections.begin ();
}
/**
* @brief Gets the global connections iterator (end)
*/
global_connections_iterator end_global_connections () const
{
return m_global_connections.end ();
}
/**
* @brief Connects the given terminal to the given global net
*/
void connect_terminal_global (size_t terminal_id, size_t global_net_id);
/**
* @brief Gets the net attached to a specific terminal
* Returns 0 if no net is attached.
@ -966,7 +941,6 @@ private:
std::vector<double> m_parameters;
size_t m_id;
Circuit *mp_circuit;
global_connections m_global_connections;
/**
* @brief Sets the terminal reference for a specific terminal

View File

@ -250,27 +250,11 @@ bool DeviceClassMOS3Transistor::combine_devices (Device *a, Device *b) const
// ------------------------------------------------------------------------------------
// DeviceClassMOS4Transistor implementation
DB_PUBLIC size_t DeviceClassMOS4Transistor::param_id_L = 0;
DB_PUBLIC size_t DeviceClassMOS4Transistor::param_id_W = 1;
DB_PUBLIC size_t DeviceClassMOS4Transistor::param_id_AS = 2;
DB_PUBLIC size_t DeviceClassMOS4Transistor::param_id_AD = 3;
DB_PUBLIC size_t DeviceClassMOS4Transistor::terminal_id_S = 0;
DB_PUBLIC size_t DeviceClassMOS4Transistor::terminal_id_G = 1;
DB_PUBLIC size_t DeviceClassMOS4Transistor::terminal_id_D = 2;
DB_PUBLIC size_t DeviceClassMOS4Transistor::terminal_id_B = 3;
DeviceClassMOS4Transistor::DeviceClassMOS4Transistor ()
{
add_terminal_definition (db::DeviceTerminalDefinition ("S", "Source"));
add_terminal_definition (db::DeviceTerminalDefinition ("G", "Gate"));
add_terminal_definition (db::DeviceTerminalDefinition ("D", "Drain"));
add_terminal_definition (db::DeviceTerminalDefinition ("B", "Bulk"));
add_parameter_definition (db::DeviceParameterDefinition ("L", "Gate length (micrometer)", 0.0));
add_parameter_definition (db::DeviceParameterDefinition ("W", "Gate width (micrometer)", 0.0));
add_parameter_definition (db::DeviceParameterDefinition ("AS", "Source area (square micrometer)", 0.0));
add_parameter_definition (db::DeviceParameterDefinition ("AD", "Drain area (square micrometer)", 0.0));
}
bool DeviceClassMOS4Transistor::combine_devices (Device *a, Device *b) const

View File

@ -181,19 +181,11 @@ public:
* terminal for the bulk.
*/
class DB_PUBLIC DeviceClassMOS4Transistor
: public db::DeviceClass
: public DeviceClassMOS3Transistor
{
public:
DeviceClassMOS4Transistor ();
static size_t param_id_L;
static size_t param_id_W;
static size_t param_id_AS;
static size_t param_id_AD;
static size_t terminal_id_S;
static size_t terminal_id_G;
static size_t terminal_id_D;
static size_t terminal_id_B;
virtual db::DeviceClass *clone () const
@ -202,7 +194,6 @@ public:
}
virtual bool combine_devices (Device *a, Device *b) const;
virtual bool supports_parallel_combination () const { return true; }
};
}

View File

@ -24,12 +24,12 @@
#include "dbNetlistDeviceExtractorClasses.h"
#include "dbNetlistDeviceClasses.h"
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorMOS3Transistor implementation
namespace db
{
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorMOS3Transistor implementation
NetlistDeviceExtractorMOS3Transistor::NetlistDeviceExtractorMOS3Transistor (const std::string &name)
: db::NetlistDeviceExtractor (name)
{
@ -47,7 +47,7 @@ void NetlistDeviceExtractorMOS3Transistor::setup ()
db::Connectivity NetlistDeviceExtractorMOS3Transistor::get_connectivity (const db::Layout & /*layout*/, const std::vector<unsigned int> &layers) const
{
tl_assert (layers.size () == 3);
tl_assert (layers.size () >= 3);
unsigned int diff = layers [0];
unsigned int gate = layers [1];
@ -117,6 +117,9 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector<db
define_terminal (device, db::DeviceClassMOS3Transistor::terminal_id_G, gate_geometry_index, *p);
// allow derived classes to modify the device
modify_device (*p, layer_geometry, device);
// output the device for debugging
device_out (device, rdiff2gate, rgate);
@ -125,4 +128,29 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector<db
}
}
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorMOS4Transistor implementation
NetlistDeviceExtractorMOS4Transistor::NetlistDeviceExtractorMOS4Transistor (const std::string &name)
: NetlistDeviceExtractorMOS3Transistor (name)
{
// .. nothing yet ..
}
void NetlistDeviceExtractorMOS4Transistor::setup ()
{
define_layer ("SD", "Source/drain diffusion");
define_layer ("G", "Gate");
define_layer ("P", "Poly");
define_layer ("W", "Well");
register_device_class (new db::DeviceClassMOS4Transistor ());
}
void NetlistDeviceExtractorMOS4Transistor::modify_device (const db::Polygon &rgate, const std::vector<db::Region> & /*layer_geometry*/, db::Device *device)
{
unsigned int well_geometry_index = 3;
define_terminal (device, db::DeviceClassMOS4Transistor::terminal_id_B, well_geometry_index, rgate);
}
}

View File

@ -35,7 +35,7 @@ namespace db
* The device is defined by two basic input layers: the diffusion area
* (source and drain) and the gate area. It requires a third layer
* (poly) to put the gate terminals on. The separation between poly
* and allows separating the device recognition layer (gate) from the
* and gate allows separating the device recognition layer (gate) from the
* conductive layer.
*
* The device class produced by this extractor is DeviceClassMOS3Transistor.
@ -56,13 +56,43 @@ public:
protected:
/**
* @brief A cappback when the device is produced
* @brief A callback when the device is produced
* This callback is provided as a debugging port
*/
virtual void device_out (const db::Device * /*device*/, const db::Region & /*diff*/, const db::Region & /*gate*/)
{
// .. no specific implementation ..
}
/**
* @brief Allow derived classes to modify the device
*/
virtual void modify_device (const db::Polygon & /*rgate*/, const std::vector<db::Region> & /*layer_geometry*/, db::Device * /*device*/)
{
// .. no specific implementation ..
}
};
/**
* @brief A device extractor for a four-terminal MOS transistor
*
* This class is like the MOS3Transistor extractor, but requires a forth
* input layer (Well). This layer will be used to output the bulk terminal.
*
* The device class produced by this extractor is DeviceClassMOS4Transistor.
* The extractor extracts the four parameters of this class: L, W, AS and AD.
*/
class DB_PUBLIC NetlistDeviceExtractorMOS4Transistor
: public NetlistDeviceExtractorMOS3Transistor
{
public:
NetlistDeviceExtractorMOS4Transistor (const std::string &name);
virtual void setup ();
private:
virtual void modify_device (const db::Polygon &rgate, const std::vector<db::Region> &layer_geometry, db::Device *device);
};
}

View File

@ -65,8 +65,6 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect
}
std::map<db::cell_index_type, std::map<size_t, size_t> > pins_per_cluster_per_cell;
std::map<db::cell_index_type, std::map<size_t, db::Net *> > global_nets_per_cell;
for (db::Layout::bottom_up_const_iterator cid = layout.begin_bottom_up (); cid != layout.end_bottom_up (); ++cid) {
const connected_clusters_type &clusters = m_net_clusters.clusters_per_cell (*cid);
@ -89,7 +87,6 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect
circuit = k->second;
}
std::map<size_t, db::Net *> &global_nets = global_nets_per_cell [*cid];
std::map<size_t, size_t> &c2p = pins_per_cluster_per_cell [*cid];
std::map<db::InstElement, db::SubCircuit *> subcircuits;
@ -100,12 +97,8 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect
net->set_cluster_id (*c);
circuit->add_net (net);
const db::local_cluster<db::PolygonRef> &cluster = clusters.cluster_by_id (*c);
// collect global net assignments from clusters
for (std::set<size_t>::const_iterator g = cluster.begin_global_nets (); g != cluster.end_global_nets (); ++g) {
tl_assert (global_nets.find (*g) == global_nets.end ());
global_nets.insert (std::make_pair (*g, net));
const db::local_cluster<db::PolygonRef>::global_nets &gn = clusters.cluster_by_id (*c).get_global_nets ();
for (db::local_cluster<db::PolygonRef>::global_nets::const_iterator g = gn.begin (); g != gn.end (); ++g) {
assign_net_name (conn.global_net_name (*g), net);
}
@ -134,73 +127,6 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect
}
// make global net connections for devices
for (db::Circuit::device_iterator d = circuit->begin_devices (); d != circuit->end_devices (); ++d) {
for (db::Device::global_connections_iterator g = d->begin_global_connections (); g != d->end_global_connections (); ++g) {
db::Net *&net = global_nets [g->second];
if (! net) {
net = new db::Net (conn.global_net_name (g->second));
circuit->add_net (net);
}
net->add_terminal (db::NetTerminalRef (d.operator-> (), g->first));
}
}
// if any of the subcircuits has global nets which this circuit doesn't have, propagate them
std::set<db::Circuit *> seen;
std::set<size_t> global_nets_of_subcircuits;
for (db::Circuit::subcircuit_iterator sc = circuit->begin_subcircuits (); sc != circuit->end_subcircuits (); ++sc) {
db::Circuit *subcircuit = sc->circuit_ref ();
if (seen.find (subcircuit) == seen.end ()) {
seen.insert (subcircuit);
const std::map<size_t, db::Net *> &sc_gn = global_nets_per_cell [subcircuit->cell_index ()];
for (std::map<size_t, db::Net *>::const_iterator g = sc_gn.begin (); g != sc_gn.end (); ++g) {
global_nets_of_subcircuits.insert (g->first);
}
}
}
for (std::set<size_t>::const_iterator g = global_nets_of_subcircuits.begin (); g != global_nets_of_subcircuits.end (); ++g) {
}
// make the global net connections into subcircuits - if necessary by creating pins into the subcircuit
for (db::Circuit::subcircuit_iterator sc = circuit->begin_subcircuits (); sc != circuit->end_subcircuits (); ++sc) {
db::Circuit *subcircuit = sc->circuit_ref ();
const std::map<size_t, db::Net *> &sc_gn = global_nets_per_cell [subcircuit->cell_index ()];
for (std::map<size_t, db::Net *>::const_iterator g = global_nets.begin (); g != global_nets.end (); ++g) {
std::map<size_t, db::Net *>::const_iterator gg = sc_gn.find (g->first);
if (gg != sc_gn.end ()) {
size_t pin_id = 0;
if (gg->second->pin_count () > 0) {
pin_id = gg->second->begin_pins ()->pin_id ();
} else {
pin_id = subcircuit->add_pin (conn.global_net_name (gg->first)).id ();
subcircuit->connect_pin (pin_id, gg->second);
}
g->second->add_subcircuit_pin (db::NetSubcircuitPinRef (sc.operator-> (), pin_id));
}
}
}
}
}

View File

@ -37,8 +37,11 @@ Class<db::Connectivity> decl_dbConnectivity ("db", "Connectivity",
"@brief Connects the given layer to the global net given by name.\n"
"Returns the ID of the global net."
) +
gsi::method ("global", &db::Connectivity::global_net_name, gsi::arg ("global_net_id"),
gsi::method ("global_net_name", &db::Connectivity::global_net_name, gsi::arg ("global_net_id"),
"@brief Gets the name for a given global net ID.\n"
) +
gsi::method ("global_net_id", &db::Connectivity::global_net_id, gsi::arg ("global_net_name"),
"@brief Gets the ID for a given global net name.\n"
),
"@brief This class specifies connections between different layers."
"Connections are build using \\connect. There are basically two flavours of connections: intra-layer and inter-layer.\n"

View File

@ -61,44 +61,6 @@ static void device_disconnect_terminal_by_name (db::Device *device, const std::s
device_connect_terminal_by_name (device, terminal_name, 0);
}
static tl::Variant device_terminal_for_global_net (const db::Device *device, size_t global_net)
{
for (db::Device::global_connections_iterator g = device->begin_global_connections (); g != device->end_global_connections (); ++g) {
if (g->second == global_net) {
return tl::Variant (g->first);
}
}
return tl::Variant ();
}
static tl::Variant device_global_net_for_terminal (const db::Device *device, size_t terminal_id)
{
for (db::Device::global_connections_iterator g = device->begin_global_connections (); g != device->end_global_connections (); ++g) {
if (g->first == terminal_id) {
return tl::Variant (g->second);
}
}
return tl::Variant ();
}
static tl::Variant device_global_net_for_terminal_name (const db::Device *device, const std::string &terminal_name)
{
if (! device->device_class ()) {
throw tl::Exception (tl::to_string (tr ("Device does not have a device class")));
}
size_t terminal_id = device->device_class ()->terminal_id_for_name (terminal_name);
return device_global_net_for_terminal (device, terminal_id);
}
static void device_connect_terminal_global_by_name (db::Device *device, const std::string &terminal_name, size_t global_net)
{
if (! device->device_class ()) {
throw tl::Exception (tl::to_string (tr ("Device does not have a device class")));
}
size_t terminal_id = device->device_class ()->terminal_id_for_name (terminal_name);
device->connect_terminal_global (terminal_id, global_net);
}
Class<db::Device> decl_dbDevice ("db", "Device",
gsi::method ("device_class", &db::Device::device_class,
"@brief Gets the device class the device belongs to.\n"
@ -140,26 +102,6 @@ Class<db::Device> decl_dbDevice ("db", "Device",
"@brief Disconnects the given terminal from any net.\n"
"This version accepts a terminal name. If the name is not a valid terminal name, an exception is raised."
) +
gsi::method ("connect_terminal_global", &db::Device::connect_terminal_global, gsi::arg ("terminal_id"), gsi::arg ("global_net_id"),
"@brief Connects the given terminal to the given global net.\n"
"The global net ID is taken from \\Connectivity (connect_global, etc.).\n"
"If the terminal was already connected to another net, it will be disconnected from there."
) +
gsi::method_ext ("connect_terminal_global", &device_connect_terminal_global_by_name, gsi::arg ("terminal_name"), gsi::arg ("global_net_id"),
"@brief Connects the given terminal to the given global net.\n"
"This version accepts a terminal name. If the name is not a valid terminal name, an exception is raised."
) +
gsi::method_ext ("terminal_on_global_net", &device_terminal_for_global_net, gsi::arg ("global_net_id"),
"@brief Gets the terminal ID for the given global net or nil if no terminal is not that global net.\n"
"The global net ID is managed by the \\Connectivity object."
) +
gsi::method_ext ("global_net_on_terminal", &device_global_net_for_terminal, gsi::arg ("terminal_id"),
"@brief Gets the global net ID for the given terminal ID or nil if the terminal is not connected to a global net.\n"
) +
gsi::method_ext ("global_net_on_terminal", &device_global_net_for_terminal_name, gsi::arg ("terminal_name"),
"@brief Gets the global net ID for the given terminal name or nil if the terminal is not connected to a global net.\n"
"If the name is not a valid terminal name, an exception is raised."
) +
gsi::method ("parameter", (double (db::Device::*) (size_t) const) &db::Device::parameter_value, gsi::arg ("param_id"),
"@brief Gets the parameter value for the given parameter ID."
) +

View File

@ -877,17 +877,12 @@ static void copy_cluster_shapes (const std::string *&attrs, db::Shapes &out, db:
static void run_hc_test (tl::TestBase *_this, const std::string &file, const std::string &au_file)
{
db::Layout ly;
unsigned int l0 = 0, l1 = 0, l2 = 0, l3 = 0;
unsigned int l1 = 0, l2 = 0, l3 = 0, l4 = 0;
{
db::LayerProperties p;
db::LayerMap lmap;
p.layer = 0;
p.datatype = 0;
lmap.map (db::LDPair (p.layer, p.datatype), l0 = ly.insert_layer ());
ly.set_properties (l0, p);
p.layer = 1;
p.datatype = 0;
lmap.map (db::LDPair (p.layer, p.datatype), l1 = ly.insert_layer ());
@ -903,6 +898,11 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std
lmap.map (db::LDPair (p.layer, p.datatype), l3 = ly.insert_layer ());
ly.set_properties (l3, p);
p.layer = 4;
p.datatype = 0;
lmap.map (db::LDPair (p.layer, p.datatype), l4 = ly.insert_layer ());
ly.set_properties (l4, p);
db::LoadLayoutOptions options;
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
@ -919,6 +919,7 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std
normalize_layer (ly, strings, l1);
normalize_layer (ly, strings, l2);
normalize_layer (ly, strings, l3);
normalize_layer (ly, strings, l4);
// connect 1 to 1, 1 to 2 and 1 to 3, but *not* 2 to 3
db::Connectivity conn;
@ -927,6 +928,9 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std
conn.connect (l3, l3);
conn.connect (l1, l2);
conn.connect (l1, l3);
conn.connect (l1, l4);
conn.connect_global (l4, "BULK");
db::hier_clusters<db::PolygonRef> hc;
hc.build (ly, ly.cell (*ly.begin_top_down ()), db::ShapeIterator::Polygons, conn);
@ -989,7 +993,7 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std
static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::string &file, const std::string &au_file)
{
db::Layout ly;
unsigned int l1 = 0, l2 = 0, l3 = 0;
unsigned int l1 = 0, l2 = 0, l3 = 0, l4 = 0;
{
db::LayerProperties p;
@ -1010,6 +1014,11 @@ static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::str
lmap.map (db::LDPair (p.layer, p.datatype), l3 = ly.insert_layer ());
ly.set_properties (l3, p);
p.layer = 4;
p.datatype = 0;
lmap.map (db::LDPair (p.layer, p.datatype), l4 = ly.insert_layer ());
ly.set_properties (l4, p);
db::LoadLayoutOptions options;
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
@ -1026,6 +1035,7 @@ static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::str
normalize_layer (ly, strings, l1);
normalize_layer (ly, strings, l2);
normalize_layer (ly, strings, l3);
normalize_layer (ly, strings, l4);
// connect 1 to 1, 1 to 2 and 1 to 3, but *not* 2 to 3
db::Connectivity conn;
@ -1034,6 +1044,9 @@ static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::str
conn.connect (l3, l3);
conn.connect (l1, l2);
conn.connect (l1, l3);
conn.connect (l1, l4);
conn.connect_global (l4, "BULK");
db::hier_clusters<db::PolygonRef> hc;
hc.build (ly, ly.cell (*ly.begin_top_down ()), db::ShapeIterator::Polygons, conn);
@ -1042,6 +1055,7 @@ static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::str
lm[l1] = ly.insert_layer (db::LayerProperties (101, 0));
lm[l2] = ly.insert_layer (db::LayerProperties (102, 0));
lm[l3] = ly.insert_layer (db::LayerProperties (103, 0));
lm[l4] = ly.insert_layer (db::LayerProperties (104, 0));
hc.return_to_hierarchy (ly, lm);
CHECKPOINT();
@ -1138,3 +1152,9 @@ TEST(115_HierClusters)
run_hc_test_with_backannotation (_this, "hc_test_l15.gds", "hc_test_au15b.gds");
}
TEST(116_HierClusters)
{
run_hc_test (_this, "hc_test_l16.gds", "hc_test_au16.gds");
run_hc_test_with_backannotation (_this, "hc_test_l16.gds", "hc_test_au16b.gds");
}

View File

@ -49,11 +49,39 @@ static std::string device_name (const db::Device &device)
}
}
class MOSFETExtractor
static void mos2layout (const db::Layout *layout, db::cell_index_type cell_index, db::Layout *debug_out, const db::Device *device, unsigned int ldiff, const db::Region &diff, unsigned int lgate, const db::Region &gate)
{
std::string cn = layout->cell_name (cell_index);
std::pair<bool, db::cell_index_type> target_cp = debug_out->cell_by_name (cn.c_str ());
tl_assert (target_cp.first);
db::cell_index_type dci = debug_out->add_cell ((device->device_class ()->name () + "_" + device->circuit ()->name () + "_" + device_name (*device)).c_str ());
debug_out->cell (target_cp.second).insert (db::CellInstArray (db::CellInst (dci), db::Trans ()));
db::Cell &device_cell = debug_out->cell (dci);
for (db::Region::const_iterator p = diff.begin (); ! p.at_end (); ++p) {
device_cell.shapes (ldiff).insert (*p);
}
for (db::Region::const_iterator p = gate.begin (); ! p.at_end (); ++p) {
device_cell.shapes (lgate).insert (*p);
}
std::string ps;
const std::vector<db::DeviceParameterDefinition> &pd = device->device_class ()->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
if (! ps.empty ()) {
ps += ",";
}
ps += i->name () + "=" + tl::to_string (device->parameter_value (i->id ()));
}
device_cell.shapes (ldiff).insert (db::Text (ps, db::Trans (diff.bbox ().center () - db::Point ())));
}
class MOSFET3Extractor
: public db::NetlistDeviceExtractorMOS3Transistor
{
public:
MOSFETExtractor (const std::string &name, db::Layout *debug_out)
MOSFET3Extractor (const std::string &name, db::Layout *debug_out)
: db::NetlistDeviceExtractorMOS3Transistor (name), mp_debug_out (debug_out), m_ldiff (0), m_lgate (0)
{
if (mp_debug_out) {
@ -68,34 +96,34 @@ private:
void device_out (const db::Device *device, const db::Region &diff, const db::Region &gate)
{
if (! mp_debug_out) {
return;
if (mp_debug_out) {
mos2layout (layout (), cell_index (), mp_debug_out, device, m_ldiff, diff, m_lgate, gate);
}
}
};
std::string cn = layout ()->cell_name (cell_index ());
std::pair<bool, db::cell_index_type> target_cp = mp_debug_out->cell_by_name (cn.c_str ());
tl_assert (target_cp.first);
db::cell_index_type dci = mp_debug_out->add_cell ((device->device_class ()->name () + "_" + device->circuit ()->name () + "_" + device_name (*device)).c_str ());
mp_debug_out->cell (target_cp.second).insert (db::CellInstArray (db::CellInst (dci), db::Trans ()));
db::Cell &device_cell = mp_debug_out->cell (dci);
for (db::Region::const_iterator p = diff.begin (); ! p.at_end (); ++p) {
device_cell.shapes (m_ldiff).insert (*p);
}
for (db::Region::const_iterator p = gate.begin (); ! p.at_end (); ++p) {
device_cell.shapes (m_lgate).insert (*p);
class MOSFET4Extractor
: public db::NetlistDeviceExtractorMOS4Transistor
{
public:
MOSFET4Extractor (const std::string &name, db::Layout *debug_out)
: db::NetlistDeviceExtractorMOS4Transistor (name), mp_debug_out (debug_out), m_ldiff (0), m_lgate (0)
{
if (mp_debug_out) {
m_ldiff = mp_debug_out->insert_layer (db::LayerProperties (100, 0));
m_lgate = mp_debug_out->insert_layer (db::LayerProperties (101, 0));
}
}
std::string ps;
const std::vector<db::DeviceParameterDefinition> &pd = device->device_class ()->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
if (! ps.empty ()) {
ps += ",";
}
ps += i->name () + "=" + tl::to_string (device->parameter_value (i->id ()));
private:
db::Layout *mp_debug_out;
unsigned int m_ldiff, m_lgate;
void device_out (const db::Device *device, const db::Region &diff, const db::Region &gate)
{
if (mp_debug_out) {
mos2layout (layout (), cell_index (), mp_debug_out, device, m_ldiff, diff, m_lgate, gate);
}
device_cell.shapes (m_ldiff).insert (db::Text (ps, db::Trans (diff.bbox ().center () - db::Point ())));
}
};
@ -261,8 +289,8 @@ TEST(1_Basic)
// NOTE: the device extractor will add more debug layers for the transistors:
// 20/0 -> Diffusion
// 21/0 -> Gate
MOSFETExtractor pmos_ex ("PMOS", &ly);
MOSFETExtractor nmos_ex ("NMOS", &ly);
MOSFET3Extractor pmos_ex ("PMOS", &ly);
MOSFET3Extractor nmos_ex ("NMOS", &ly);
// device extraction
@ -617,8 +645,8 @@ TEST(2_Probing)
// NOTE: the device extractor will add more debug layers for the transistors:
// 20/0 -> Diffusion
// 21/0 -> Gate
MOSFETExtractor pmos_ex ("PMOS", &ly);
MOSFETExtractor nmos_ex ("NMOS", &ly);
MOSFET3Extractor pmos_ex ("PMOS", &ly);
MOSFET3Extractor nmos_ex ("NMOS", &ly);
// device extraction
@ -871,8 +899,8 @@ TEST(3_GlobalNetConnections)
// NOTE: the device extractor will add more debug layers for the transistors:
// 20/0 -> Diffusion
// 21/0 -> Gate
MOSFETExtractor pmos_ex ("PMOS", &ly);
MOSFETExtractor nmos_ex ("NMOS", &ly);
MOSFET3Extractor pmos_ex ("PMOS", &ly);
MOSFET3Extractor nmos_ex ("NMOS", &ly);
// device extraction
@ -1054,3 +1082,277 @@ TEST(3_GlobalNetConnections)
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "INV2PAIR:$I8");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "INV2PAIR:$I4");
}
TEST(4_GlobalNetDeviceExtraction)
{
db::Layout ly;
db::LayerMap lmap;
unsigned int nwell = define_layer (ly, lmap, 1);
unsigned int active = define_layer (ly, lmap, 2);
unsigned int pplus = define_layer (ly, lmap, 10);
unsigned int nplus = define_layer (ly, lmap, 11);
unsigned int poly = define_layer (ly, lmap, 3);
unsigned int poly_lbl = define_layer (ly, lmap, 3, 1);
unsigned int diff_cont = define_layer (ly, lmap, 4);
unsigned int poly_cont = define_layer (ly, lmap, 5);
unsigned int metal1 = define_layer (ly, lmap, 6);
unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1);
unsigned int via1 = define_layer (ly, lmap, 7);
unsigned int metal2 = define_layer (ly, lmap, 8);
unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1);
{
db::LoadLayoutOptions options;
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
std::string fn (tl::testsrc ());
fn = tl::combine_path (fn, "testdata");
fn = tl::combine_path (fn, "algo");
fn = tl::combine_path (fn, "device_extract_l3.gds");
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly, options);
}
db::Cell &tc = ly.cell (*ly.begin_top_down ());
db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set<unsigned int> ()));
std::auto_ptr<db::Region> rbulk (l2n.make_layer (ly.insert_layer ()));
std::auto_ptr<db::Region> rnwell (l2n.make_layer (nwell));
std::auto_ptr<db::Region> ractive (l2n.make_layer (active));
std::auto_ptr<db::Region> rpplus (l2n.make_layer (pplus));
std::auto_ptr<db::Region> rnplus (l2n.make_layer (nplus));
std::auto_ptr<db::Region> rpoly (l2n.make_polygon_layer (poly));
std::auto_ptr<db::Region> rpoly_lbl (l2n.make_text_layer (poly_lbl));
std::auto_ptr<db::Region> rdiff_cont (l2n.make_polygon_layer (diff_cont));
std::auto_ptr<db::Region> rpoly_cont (l2n.make_polygon_layer (poly_cont));
std::auto_ptr<db::Region> rmetal1 (l2n.make_polygon_layer (metal1));
std::auto_ptr<db::Region> rmetal1_lbl (l2n.make_text_layer (metal1_lbl));
std::auto_ptr<db::Region> rvia1 (l2n.make_polygon_layer (via1));
std::auto_ptr<db::Region> rmetal2 (l2n.make_polygon_layer (metal2));
std::auto_ptr<db::Region> rmetal2_lbl (l2n.make_text_layer (metal2_lbl));
// derived regions
db::Region ractive_in_nwell = *ractive & *rnwell;
db::Region rpactive = ractive_in_nwell & *rpplus;
db::Region rntie = ractive_in_nwell & *rnplus;
db::Region rpgate = rpactive & *rpoly;
db::Region rpsd = rpactive - rpgate;
db::Region ractive_outside_nwell = *ractive - *rnwell;
db::Region rnactive = ractive_outside_nwell & *rnplus;
db::Region rptie = ractive_outside_nwell & *rpplus;
db::Region rngate = rnactive & *rpoly;
db::Region rnsd = rnactive - rngate;
// return the computed layers into the original layout and write it for debugging purposes
unsigned int lgate = ly.insert_layer (db::LayerProperties (20, 0)); // 20/0 -> Gate
unsigned int lsd = ly.insert_layer (db::LayerProperties (21, 0)); // 21/0 -> Source/Drain
unsigned int lpdiff = ly.insert_layer (db::LayerProperties (22, 0)); // 22/0 -> P Diffusion
unsigned int lndiff = ly.insert_layer (db::LayerProperties (23, 0)); // 23/0 -> N Diffusion
unsigned int lptie = ly.insert_layer (db::LayerProperties (24, 0)); // 24/0 -> P Tie
unsigned int lntie = ly.insert_layer (db::LayerProperties (25, 0)); // 25/0 -> N Tie
rpgate.insert_into (&ly, tc.cell_index (), lgate);
rngate.insert_into (&ly, tc.cell_index (), lgate);
rpsd.insert_into (&ly, tc.cell_index (), lsd);
rnsd.insert_into (&ly, tc.cell_index (), lsd);
rpsd.insert_into (&ly, tc.cell_index (), lpdiff);
rnsd.insert_into (&ly, tc.cell_index (), lndiff);
rpsd.insert_into (&ly, tc.cell_index (), lptie);
rnsd.insert_into (&ly, tc.cell_index (), lntie);
// NOTE: the device extractor will add more debug layers for the transistors:
// 20/0 -> Diffusion
// 21/0 -> Gate
MOSFET4Extractor pmos_ex ("PMOS", &ly);
MOSFET4Extractor nmos_ex ("NMOS", &ly);
// device extraction
db::NetlistDeviceExtractor::input_layers dl;
dl["SD"] = &rpsd;
dl["G"] = &rpgate;
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
dl["W"] = rnwell.get ();
l2n.extract_devices (pmos_ex, dl);
dl["SD"] = &rnsd;
dl["G"] = &rngate;
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
dl["W"] = rbulk.get ();
l2n.extract_devices (nmos_ex, dl);
// net extraction
// Intra-layer
l2n.connect (rpsd);
l2n.connect (rnsd);
l2n.connect (*rnwell);
l2n.connect (*rpoly);
l2n.connect (*rdiff_cont);
l2n.connect (*rpoly_cont);
l2n.connect (*rmetal1);
l2n.connect (*rvia1);
l2n.connect (*rmetal2);
l2n.connect (rptie);
l2n.connect (rntie);
// Inter-layer
l2n.connect (rpsd, *rdiff_cont);
l2n.connect (rnsd, *rdiff_cont);
l2n.connect (*rpoly, *rpoly_cont);
l2n.connect (*rpoly_cont, *rmetal1);
l2n.connect (*rdiff_cont, *rmetal1);
l2n.connect (*rdiff_cont, rptie);
l2n.connect (*rdiff_cont, rntie);
l2n.connect (*rnwell, rntie);
l2n.connect (*rmetal1, *rvia1);
l2n.connect (*rvia1, *rmetal2);
l2n.connect (*rpoly, *rpoly_lbl); // attaches labels
l2n.connect (*rmetal1, *rmetal1_lbl); // attaches labels
l2n.connect (*rmetal2, *rmetal2_lbl); // attaches labels
// Global
l2n.connect_global (rptie, "BULK");
l2n.connect_global (*rbulk, "BULK");
// create some mess - we have to keep references to the layers to make them not disappear
rmetal1_lbl.reset (0);
rmetal2_lbl.reset (0);
rpoly_lbl.reset (0);
l2n.extract_netlist ();
// debug layers produced for nets
// 201/0 -> Well
// 203/0 -> Poly
// 204/0 -> Diffusion contacts
// 205/0 -> Poly contacts
// 206/0 -> Metal1
// 207/0 -> Via1
// 208/0 -> Metal2
// 210/0 -> N source/drain
// 211/0 -> P source/drain
// 212/0 -> N tie
// 213/0 -> P tie
std::map<const db::Region *, unsigned int> dump_map;
dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (210, 0));
dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (211, 0));
dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (212, 0));
dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (213, 0));
dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (201, 0));
dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (203, 0));
dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (204, 0));
dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (205, 0));
dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (206, 0));
dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (207, 0));
dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (208, 0));
// write nets to layout
db::CellMapping cm = l2n.cell_mapping_into (ly, tc);
dump_nets_to_layout (l2n, ly, dump_map, cm);
dump_map.clear ();
dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (310, 0));
dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (311, 0));
dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (312, 0));
dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (313, 0));
dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (301, 0));
dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (303, 0));
dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (304, 0));
dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (305, 0));
dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (306, 0));
dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (307, 0));
dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (308, 0));
dump_recursive_nets_to_layout (l2n, ly, dump_map, cm);
// compare netlist as string
EXPECT_EQ (l2n.netlist ()->to_string (),
"Circuit RINGO ():\n"
" XINV2PAIR $1 ($1=VSS,$2=VSS,$3=FB,$4=VDD,$5=VSS,$6=$I7,$7=OSC,$8=VDD)\n"
" XINV2PAIR $2 ($1=VSS,$2=VSS,$3=$I22,$4=VDD,$5=VSS,$6=FB,$7=$I13,$8=VDD)\n"
" XINV2PAIR $3 ($1=VSS,$2=VSS,$3=$I23,$4=VDD,$5=VSS,$6=$I13,$7=$I5,$8=VDD)\n"
" XINV2PAIR $4 ($1=VSS,$2=VSS,$3=$I24,$4=VDD,$5=VSS,$6=$I5,$7=$I6,$8=VDD)\n"
" XINV2PAIR $5 ($1=VSS,$2=VSS,$3=$I25,$4=VDD,$5=VSS,$6=$I6,$7=$I7,$8=VDD)\n"
"Circuit INV2PAIR ($1=$I10,$2=$I9,$3=$I8,$4=$I6,$5=$I5,$6=$I3,$7=$I2,$8=$I1):\n"
" XINV2 $1 ($1=$I1,IN=$I4,$3=$I8,BULK=$I10,OUT=$I2,VSS=$I5,VDD=$I6)\n"
" XINV2 $2 ($1=$I1,IN=$I3,$3=$I7,BULK=$I9,OUT=$I4,VSS=$I5,VDD=$I6)\n"
"Circuit INV2 ($1=$1,IN=IN,$3=$3,BULK=BULK,OUT=OUT,VSS=VSS,VDD=VDD):\n"
" DPMOS $1 (S=$3,G=IN,D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n"
" DPMOS $2 (S=VDD,G=$3,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n"
" DNMOS $3 (S=$3,G=IN,D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n"
" DNMOS $4 (S=VSS,G=$3,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n"
" XTRANS $1 ($1=$3,$2=VSS,$3=IN)\n"
" XTRANS $2 ($1=$3,$2=VDD,$3=IN)\n"
" XTRANS $3 ($1=VDD,$2=OUT,$3=$3)\n"
" XTRANS $4 ($1=VSS,$2=OUT,$3=$3)\n"
"Circuit TRANS ($1=$1,$2=$2,$3=$3):\n"
);
// compare the collected test data
std::string au = tl::testsrc ();
au = tl::combine_path (au, "testdata");
au = tl::combine_path (au, "algo");
au = tl::combine_path (au, "device_extract_au3_with_rec_nets.gds");
db::compare_layouts (_this, ly, au);
// do some probing before purging
// top level
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::DPoint (0.0, 1.8))), "RINGO:FB");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::Point (0, 1800))), "RINGO:FB");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::DPoint (-2.0, 1.8))), "(null)");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (-1.5, 1.8))), "RINGO:FB");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (24.5, 1.8))), "RINGO:OSC");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "RINGO:VSS");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "RINGO:$I22");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "INV2PAIR:$I4");
// doesn't do anything here, but we test that this does not destroy anything:
l2n.netlist ()->combine_devices ();
// make pins for named nets of top-level circuits - this way they are not purged
l2n.netlist ()->make_top_level_pins ();
l2n.netlist ()->purge ();
// compare netlist as string
EXPECT_EQ (l2n.netlist ()->to_string (),
"Circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,VSS=VSS):\n"
" XINV2PAIR $1 ($1=VSS,$2=VSS,$3=FB,$4=VDD,$5=VSS,$6=$I7,$7=OSC,$8=VDD)\n"
" XINV2PAIR $2 ($1=VSS,$2=VSS,$3=(null),$4=VDD,$5=VSS,$6=FB,$7=$I13,$8=VDD)\n"
" XINV2PAIR $3 ($1=VSS,$2=VSS,$3=(null),$4=VDD,$5=VSS,$6=$I13,$7=$I5,$8=VDD)\n"
" XINV2PAIR $4 ($1=VSS,$2=VSS,$3=(null),$4=VDD,$5=VSS,$6=$I5,$7=$I6,$8=VDD)\n"
" XINV2PAIR $5 ($1=VSS,$2=VSS,$3=(null),$4=VDD,$5=VSS,$6=$I6,$7=$I7,$8=VDD)\n"
"Circuit INV2PAIR ($1=$I10,$2=$I9,$3=$I8,$4=$I6,$5=$I5,$6=$I3,$7=$I2,$8=$I1):\n"
" XINV2 $1 ($1=$I1,IN=$I4,$3=$I8,BULK=$I10,OUT=$I2,VSS=$I5,VDD=$I6)\n"
" XINV2 $2 ($1=$I1,IN=$I3,$3=(null),BULK=$I9,OUT=$I4,VSS=$I5,VDD=$I6)\n"
"Circuit INV2 ($1=(null),IN=IN,$3=$3,BULK=(null),OUT=OUT,VSS=VSS,VDD=VDD):\n"
" DPMOS $1 (S=$3,G=IN,D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n"
" DPMOS $2 (S=VDD,G=$3,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n"
" DNMOS $3 (S=$3,G=IN,D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n"
" DNMOS $4 (S=VSS,G=$3,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n"
);
// do some probing after purging
// top level
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::DPoint (0.0, 1.8))), "RINGO:FB");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::Point (0, 1800))), "RINGO:FB");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::DPoint (-2.0, 1.8))), "(null)");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (-1.5, 1.8))), "RINGO:FB");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (24.5, 1.8))), "RINGO:OSC");
// the transistor which supplies this probe target has been optimized away by "purge".
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "(null)");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "INV2PAIR:$I8");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "INV2PAIR:$I4");
}

View File

@ -63,11 +63,11 @@ static std::string device_name (const db::Device &device)
namespace
{
class MOSFETExtractor
class MOSFET3Extractor
: public db::NetlistDeviceExtractorMOS3Transistor
{
public:
MOSFETExtractor (const std::string &name, db::Layout *debug_out)
MOSFET3Extractor (const std::string &name, db::Layout *debug_out)
: db::NetlistDeviceExtractorMOS3Transistor (name), mp_debug_out (debug_out), m_ldiff (0), m_lgate (0)
{
if (mp_debug_out) {
@ -239,8 +239,8 @@ TEST(1_DeviceAndNetExtraction)
// NOTE: the device extractor will add more debug layers for the transistors:
// 20/0 -> Diffusion
// 21/0 -> Gate
MOSFETExtractor pmos_ex ("PMOS", &ly);
MOSFETExtractor nmos_ex ("NMOS", &ly);
MOSFET3Extractor pmos_ex ("PMOS", &ly);
MOSFET3Extractor nmos_ex ("NMOS", &ly);
db::NetlistDeviceExtractor::input_layers dl;

View File

@ -1024,53 +1024,3 @@ TEST(12_NetlistTopology)
EXPECT_EQ (td2string (nl.get ()), "c1,c3,c2");
EXPECT_EQ (bu2string (nl.get ()), "c2,c3,c1");
}
TEST(13_DeviceGlobalNets)
{
db::DeviceTerminalDefinition pd;
pd.set_name ("name");
pd.set_description ("nothing yet");
db::DeviceTerminalDefinition pd2;
pd2.set_name ("name2");
pd2.set_description ("now it has something");
db::DeviceClass dc;
dc.set_name ("devname");
dc.set_description ("devdesc");
dc.add_terminal_definition (pd);
dc.add_terminal_definition (pd2);
db::Device d (&dc);
db::Net n;
d.connect_terminal_global (0, 17);
db::Device::global_connections_iterator g;
g = d.begin_global_connections ();
EXPECT_EQ (g != d.end_global_connections (), true);
EXPECT_EQ (g->first, size_t (0));
EXPECT_EQ (g->second, size_t (17));
++g;
EXPECT_EQ (g == d.end_global_connections (), true);
d.connect_terminal (0, &n);
g = d.begin_global_connections ();
EXPECT_EQ (g == d.end_global_connections (), true);
EXPECT_EQ (d.net_for_terminal (0) == &n, true);
d.connect_terminal_global (0, 17);
EXPECT_EQ (d.net_for_terminal (0) == 0, true);
g = d.begin_global_connections ();
EXPECT_EQ (g != d.end_global_connections (), true);
EXPECT_EQ (g->first, size_t (0));
EXPECT_EQ (g->second, size_t (17));
d.connect_terminal (0, 0);
g = d.begin_global_connections ();
EXPECT_EQ (g == d.end_global_connections (), true);
EXPECT_EQ (d.net_for_terminal (0) == 0, true);
}

BIN
testdata/algo/hc_test_au16.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/hc_test_au16b.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/hc_test_l16.gds vendored Normal file

Binary file not shown.

View File

@ -259,13 +259,6 @@ class DBNetlist_TestClass < TestBase
d2.connect_terminal(0, net)
assert_equal(net.terminal_count, 1)
d2.connect_terminal_global(0, 1)
assert_equal(net.terminal_count, 0)
assert_equal(d2.terminal_on_global_net(1), 0)
assert_equal(d2.terminal_on_global_net(17).inspect, "nil")
assert_equal(d2.global_net_on_terminal(0), 1)
assert_equal(d2.global_net_on_terminal(1).inspect, "nil")
end