mirror of https://github.com/KLayout/klayout.git
Merge pull request #1657 from KLayout/1598-support-for-soft-connections
1598 support for soft connections
This commit is contained in:
commit
4f67ae5261
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
.SUBCKT RINGO VSS VDD FB ENABLE OUT
|
||||
X$1 VDD VSS 1 FB ENABLE ND2X1
|
||||
X$2 VDD VSS 2 1 INVX1
|
||||
X$3 VDD VSS 3 2 INVX1
|
||||
X$4 VDD VSS 4 3 INVX1
|
||||
X$5 VDD VSS 5 4 INVX1
|
||||
X$6 VDD VSS 6 5 INVX1
|
||||
X$7 VDD VSS 7 6 INVX1
|
||||
X$8 VDD VSS 8 7 INVX1
|
||||
X$9 VDD VSS 9 8 INVX1
|
||||
X$10 VDD VSS 10 9 INVX1
|
||||
X$11 VDD VSS FB 10 INVX1
|
||||
X$12 VDD VSS OUT FB INVX1
|
||||
.ENDS RINGO
|
||||
|
||||
.SUBCKT ND2X1 VDD VSS OUT B A
|
||||
M$1 OUT A VDD VDD LVPMOS L=0.25U W=1.5U
|
||||
M$2 VDD B OUT VDD LVPMOS L=0.25U W=1.5U
|
||||
M$3 VSS A 1 VSS LVNMOS L=0.25U W=0.95U
|
||||
M$4 1 B OUT VSS LVNMOS L=0.25U W=0.95U
|
||||
.ENDS ND2X1
|
||||
|
||||
.SUBCKT INVX1 VDD VSS OUT IN
|
||||
M$1 VDD IN OUT VDD LVPMOS L=0.25U W=1.5U
|
||||
M$2 VSS IN OUT VSS LVNMOS L=0.25U W=0.95U
|
||||
.ENDS INVX1
|
||||
Binary file not shown.
|
|
@ -1,27 +0,0 @@
|
|||
|
||||
.SUBCKT RINGO VSS VDD FB ENABLE OUT
|
||||
X$1 VDD 1 VSS VDD FB ENABLE VSS ND2X1
|
||||
X$2 VDD 2 VSS VDD 1 VSS INVX1
|
||||
X$3 VDD 3 VSS VDD 2 VSS INVX1
|
||||
X$4 VDD 4 VSS VDD 3 VSS INVX1
|
||||
X$5 VDD 5 VSS VDD 4 VSS INVX1
|
||||
X$6 VDD 6 VSS VDD 5 VSS INVX1
|
||||
X$7 VDD 7 VSS VDD 6 VSS INVX1
|
||||
X$8 VDD 8 VSS VDD 7 VSS INVX1
|
||||
X$9 VDD 9 VSS VDD 8 VSS INVX1
|
||||
X$10 VDD 10 VSS VDD 9 VSS INVX1
|
||||
X$11 VDD FB VSS VDD 10 VSS INVX1
|
||||
X$12 VDD OUT VSS VDD FB VSS INVX1
|
||||
.ENDS RINGO
|
||||
|
||||
.SUBCKT ND2X1 VDD OUT VSS NWELL B A BULK
|
||||
M$1 OUT A VDD NWELL PMOS L=0.25U W=1.5U
|
||||
M$2 VDD B OUT NWELL PMOS L=0.25U W=1.5U
|
||||
M$3 VSS A 1 BULK NMOS L=0.25U W=0.95U
|
||||
M$4 1 B OUT BULK NMOS L=0.25U W=0.95U
|
||||
.ENDS ND2X1
|
||||
|
||||
.SUBCKT INVX1 VDD OUT VSS NWELL IN BULK
|
||||
M$1 VDD IN OUT NWELL PMOS L=0.25U W=1.5U
|
||||
M$2 VSS IN OUT BULK NMOS L=0.25U W=0.95U
|
||||
.ENDS INVX1
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
|
||||
# Hierarchical mode
|
||||
deep
|
||||
# Print details
|
||||
verbose
|
||||
|
||||
# Output generation (dialog only)
|
||||
report_lvs
|
||||
|
||||
# Enable this to produce a L2N database
|
||||
# report_netlist("extracted.l2n")
|
||||
|
||||
# True to write the extracted netlist
|
||||
if false
|
||||
|
||||
# true: use net names instead of numbers
|
||||
# false: use numbers for nets
|
||||
spice_with_net_names = true
|
||||
# true: put in comments with details
|
||||
# false: no comments
|
||||
spice_with_comments = false
|
||||
|
||||
# Extracted netlist
|
||||
target_netlist(File.join(File.dirname(File.absolute_path(source.path || ".")), source.cell_name + "_extracted.cir"), write_spice(spice_with_net_names, spice_with_comments), "Extracted by KLayout on : #{Time.now.strftime("%d/%m/%Y %H:%M")}")
|
||||
|
||||
end
|
||||
|
||||
# Specify the schematic netlist
|
||||
# (looks for a file called <cell name>.cir where <cell name>
|
||||
# is the current cell name). The file is looked up relative to
|
||||
# the layout file name.
|
||||
schematic(File.join(File.dirname(File.absolute_path(source.path || ".")), source.cell_name + ".cir"))
|
||||
|
||||
# layers definitions
|
||||
########################
|
||||
nwell = input(1, 0)
|
||||
diff = input(2, 0)
|
||||
pplus = input(3, 0)
|
||||
nplus = input(4, 0)
|
||||
poly = input(5, 0)
|
||||
thickox = input(6, 0)
|
||||
polyres = input(7, 0)
|
||||
contact = input(8, 0)
|
||||
metal1 = input(9, 0)
|
||||
via = input(10, 0)
|
||||
metal2 = input(11, 0)
|
||||
pad = input(12, 0)
|
||||
border = input(13, 0)
|
||||
|
||||
# Special layer for bulk terminals
|
||||
|
||||
bulk = make_layer
|
||||
|
||||
# Computed layers
|
||||
|
||||
diff_in_nwell = diff & nwell
|
||||
pdiff = diff_in_nwell - nplus
|
||||
ntie = diff_in_nwell & nplus
|
||||
pgate = pdiff & poly
|
||||
psd = pdiff - pgate
|
||||
hv_pgate = pgate & thickox
|
||||
lv_pgate = pgate - hv_pgate
|
||||
hv_psd = psd & thickox
|
||||
lv_psd = psd - thickox
|
||||
|
||||
diff_outside_nwell = diff - nwell
|
||||
ndiff = diff_outside_nwell - pplus
|
||||
ptie = diff_outside_nwell & pplus
|
||||
ngate = ndiff & poly
|
||||
nsd = ndiff - ngate
|
||||
hv_ngate = ngate & thickox
|
||||
lv_ngate = ngate - hv_ngate
|
||||
hv_nsd = nsd & thickox
|
||||
lv_nsd = nsd - thickox
|
||||
|
||||
# PMOS transistor device extraction
|
||||
|
||||
hvpmos_ex = RBA::DeviceExtractorMOS4Transistor::new("HVPMOS")
|
||||
extract_devices(hvpmos_ex, { "SD" => psd, "G" => hv_pgate, "P" => poly, "W" => nwell })
|
||||
|
||||
lvpmos_ex = RBA::DeviceExtractorMOS4Transistor::new("LVPMOS")
|
||||
extract_devices(lvpmos_ex, { "SD" => psd, "G" => lv_pgate, "P" => poly, "W" => nwell })
|
||||
|
||||
# NMOS transistor device extraction
|
||||
|
||||
lvnmos_ex = RBA::DeviceExtractorMOS4Transistor::new("LVNMOS")
|
||||
extract_devices(lvnmos_ex, { "SD" => nsd, "G" => lv_ngate, "P" => poly, "W" => bulk })
|
||||
|
||||
hvnmos_ex = RBA::DeviceExtractorMOS4Transistor::new("HVNMOS")
|
||||
extract_devices(hvnmos_ex, { "SD" => nsd, "G" => hv_ngate, "P" => poly, "W" => bulk })
|
||||
|
||||
# Define connectivity for netlist extraction
|
||||
|
||||
# Inter-layer
|
||||
connect(contact, ntie)
|
||||
connect(contact, ptie)
|
||||
connect(nwell, ntie)
|
||||
connect(psd, contact)
|
||||
connect(nsd, contact)
|
||||
connect(poly, contact)
|
||||
connect(contact, metal1)
|
||||
connect(metal1, via)
|
||||
connect(via, metal2)
|
||||
|
||||
# Make "must-connect" connections between NWELL and VDD and BULK and VSS
|
||||
connect_explicit(["NWELL", "VDD"])
|
||||
connect_explicit(["BULK", "VSS"])
|
||||
|
||||
# Global connections
|
||||
connect_global(ptie, "BULK")
|
||||
connect_global(bulk, "BULK")
|
||||
|
||||
# Actually performs the extraction
|
||||
netlist
|
||||
|
||||
# Flatten cells which are present in one netlist only
|
||||
align
|
||||
|
||||
# Simplication of the netlist
|
||||
netlist.simplify
|
||||
|
||||
# LVS compare
|
||||
if compare
|
||||
puts "Congratulations! Netlists match."
|
||||
else
|
||||
puts "LVS ERROR: netlists do not match!"
|
||||
end
|
||||
|
||||
|
|
@ -45,6 +45,7 @@ SOURCES = \
|
|||
dbLayoutDiff.cc \
|
||||
dbLayoutQuery.cc \
|
||||
dbLayoutStateModel.cc \
|
||||
dbLayoutToNetlistSoftConnections.cc \
|
||||
dbLayoutUtils.cc \
|
||||
dbLibrary.cc \
|
||||
dbLibraryManager.cc \
|
||||
|
|
@ -270,6 +271,7 @@ HEADERS = \
|
|||
dbLayoutQuery.h \
|
||||
dbLayoutStateModel.h \
|
||||
dbLayoutToNetlistEnums.h \
|
||||
dbLayoutToNetlistSoftConnections.h \
|
||||
dbLayoutUtils.h \
|
||||
dbLibrary.h \
|
||||
dbLibraryManager.h \
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -60,9 +60,11 @@ class DeepLayer;
|
|||
class DB_PUBLIC Connectivity
|
||||
{
|
||||
public:
|
||||
typedef std::set<unsigned int> layers_type;
|
||||
typedef std::set<unsigned int> all_layers_type;
|
||||
typedef all_layers_type::const_iterator all_layer_iterator;
|
||||
typedef std::map<unsigned int, int> layers_type;
|
||||
typedef layers_type::const_iterator layer_iterator;
|
||||
typedef std::set<size_t> global_nets_type;
|
||||
typedef std::map<unsigned int, int> global_nets_type;
|
||||
typedef global_nets_type::const_iterator global_nets_iterator;
|
||||
|
||||
/**
|
||||
|
|
@ -101,11 +103,26 @@ public:
|
|||
*/
|
||||
void connect (unsigned int la, unsigned int lb);
|
||||
|
||||
/**
|
||||
* @brief Adds inter-layer connectivity of the soft type
|
||||
*
|
||||
* Soft connections are directed and are reported during "interacts"
|
||||
* by the "soft" output argument. "la" is the "upper" layer and "lb" is the lower layer.
|
||||
*/
|
||||
void soft_connect (unsigned int la, unsigned int lb);
|
||||
|
||||
/**
|
||||
* @brief Adds a connection to a global net
|
||||
*/
|
||||
size_t connect_global (unsigned int l, const std::string &gn);
|
||||
|
||||
/**
|
||||
* @brief Adds a soft connection to a global net
|
||||
*
|
||||
* The global net is always the "lower" layer.
|
||||
*/
|
||||
size_t soft_connect_global (unsigned int l, const std::string &gn);
|
||||
|
||||
/**
|
||||
* @brief Adds intra-layer connectivity for layer l
|
||||
* This is a convenience method that takes a db::DeepLayer object.
|
||||
|
|
@ -120,11 +137,28 @@ public:
|
|||
*/
|
||||
void connect (const db::DeepLayer &la, const db::DeepLayer &lb);
|
||||
|
||||
/**
|
||||
* @brief Adds inter-layer connectivity
|
||||
* This is a convenience method that takes a db::DeepLayer object.
|
||||
* It is assumed that all those layers originate from the same deep shape store.
|
||||
*
|
||||
* Soft connections are directed and are reported during "interacts"
|
||||
* by the "soft" output argument. "la" is the "upper" layer and "lb" is the lower layer.
|
||||
*/
|
||||
void soft_connect (const db::DeepLayer &la, const db::DeepLayer &lb);
|
||||
|
||||
/**
|
||||
* @brief Adds a connection to a global net
|
||||
*/
|
||||
size_t connect_global (const db::DeepLayer &la, const std::string &gn);
|
||||
|
||||
/**
|
||||
* @brief Adds a soft connection to a global net
|
||||
*
|
||||
* The global net is always the "lower" layer.
|
||||
*/
|
||||
size_t soft_connect_global (const db::DeepLayer &la, const std::string &gn);
|
||||
|
||||
/**
|
||||
* @brief Gets the global net name per ID
|
||||
*/
|
||||
|
|
@ -143,15 +177,19 @@ public:
|
|||
/**
|
||||
* @brief Begin iterator for the layers involved
|
||||
*/
|
||||
layer_iterator begin_layers () const;
|
||||
all_layer_iterator begin_layers () const;
|
||||
|
||||
/**
|
||||
* @brief End iterator for the layers involved
|
||||
*/
|
||||
layer_iterator end_layers () const;
|
||||
all_layer_iterator end_layers () const;
|
||||
|
||||
/**
|
||||
* @brief Begin iterator for the layers connected to a specific layer
|
||||
*
|
||||
* The iterator returned is over a map of target layers and soft mode
|
||||
* (an int, being 0 for a hard connection, +1 for an upward soft connection
|
||||
* and -1 for a downward soft connection).
|
||||
*/
|
||||
layer_iterator begin_connected (unsigned int layer) const;
|
||||
|
||||
|
|
@ -162,6 +200,10 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Begin iterator for the global connections for a specific layer
|
||||
*
|
||||
* The iterator returned is over a map of global net ID and soft mode
|
||||
* (an int, being 0 for a hard connection, +1 for an upward soft connection
|
||||
* and -1 for a downward soft connection).
|
||||
*/
|
||||
global_nets_iterator begin_global_connections (unsigned int layer) const;
|
||||
|
||||
|
|
@ -175,17 +217,21 @@ public:
|
|||
*
|
||||
* This method accepts a transformation. This transformation is applied
|
||||
* to the b shape before checking against a.
|
||||
*
|
||||
* The "soft" output argument will deliver the soft mode that applies
|
||||
* to the connection - 0: hard connection, -1: a is the lower layer, +1: a is
|
||||
* the upper layer.
|
||||
*/
|
||||
template <class T, class Trans>
|
||||
bool interacts (const T &a, unsigned int la, const T &b, unsigned int lb, const Trans &trans) const;
|
||||
bool interacts (const T &a, unsigned int la, const T &b, unsigned int lb, const Trans &trans, int &soft) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the given shapes on the given layers interact
|
||||
*/
|
||||
template <class T>
|
||||
bool interacts (const T &a, unsigned int la, const T &b, unsigned int lb) const
|
||||
bool interacts (const T &a, unsigned int la, const T &b, unsigned int lb, int &soft) const
|
||||
{
|
||||
return interacts (a, la, b, lb, UnitTrans ());
|
||||
return interacts (a, la, b, lb, UnitTrans (), soft);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -195,17 +241,21 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Returns true, if two cells basically (without considering transformation) interact
|
||||
*
|
||||
* This is a pretty basic check based on the cell's bounding boxes
|
||||
*/
|
||||
bool interact (const db::Cell &a, const db::Cell &b) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true, if two cells with the given transformations interact
|
||||
*
|
||||
* This is a pretty basic check based on the cell's bounding boxes
|
||||
*/
|
||||
template <class T>
|
||||
bool interact (const db::Cell &a, const T &ta, const db::Cell &b, const T &tb) const;
|
||||
|
||||
private:
|
||||
layers_type m_all_layers;
|
||||
all_layers_type m_all_layers;
|
||||
std::map<unsigned int, layers_type> m_connected;
|
||||
std::vector<std::string> m_global_net_names;
|
||||
std::map<unsigned int, global_nets_type> m_global_connections;
|
||||
|
|
@ -277,7 +327,7 @@ public:
|
|||
* "trans" is the transformation which is applied to the other cluster before
|
||||
* the test.
|
||||
*/
|
||||
bool interacts (const local_cluster<T> &other, const db::ICplxTrans &trans, const Connectivity &conn) const;
|
||||
bool interacts (const local_cluster<T> &other, const db::ICplxTrans &trans, const Connectivity &conn, int &soft) const;
|
||||
|
||||
/**
|
||||
* @brief Tests whether this cluster interacts with the given cell
|
||||
|
|
@ -288,7 +338,7 @@ public:
|
|||
bool interacts (const db::Cell &cell, const db::ICplxTrans &trans, const Connectivity &conn) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the bounding box of this cluster
|
||||
* @brief Gets the bounding box ofF this cluster
|
||||
*/
|
||||
const box_type &bbox () const
|
||||
{
|
||||
|
|
@ -572,6 +622,21 @@ public:
|
|||
return id > m_clusters.size ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Makes a soft connection between clusters a and b (a: upper, b: lower)
|
||||
*/
|
||||
void make_soft_connection (typename local_cluster<T>::id_type a, typename local_cluster<T>::id_type b);
|
||||
|
||||
/**
|
||||
* @brief Get the downward soft connections for a given cluster
|
||||
*/
|
||||
const std::set<size_t> &downward_soft_connections (typename local_cluster<T>::id_type id) const;
|
||||
|
||||
/**
|
||||
* @brief Get the upward soft connections for a given cluster
|
||||
*/
|
||||
const std::set<size_t> &upward_soft_connections (typename local_cluster<T>::id_type id) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the number of clusters
|
||||
*/
|
||||
|
|
@ -592,8 +657,11 @@ private:
|
|||
box_type m_bbox;
|
||||
tree_type m_clusters;
|
||||
size_t m_next_dummy_id;
|
||||
std::map<size_t, std::set<size_t> > m_soft_connections;
|
||||
std::map<size_t, std::set<size_t> > m_soft_connections_rev;
|
||||
|
||||
void apply_attr_equivalences (const tl::equivalence_clusters<size_t> &attr_equivalence);
|
||||
void remove_soft_connections_for (typename local_cluster<T>::id_type id);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -794,7 +862,61 @@ private:
|
|||
size_t m_id;
|
||||
};
|
||||
|
||||
typedef std::list<std::pair<ClusterInstance, ClusterInstance> > cluster_instance_pair_list_type;
|
||||
struct ClusterInstancePair
|
||||
{
|
||||
ClusterInstancePair (const ClusterInstance &_a, const ClusterInstance &_b, int _soft)
|
||||
: a (_a), b (_b), soft (_soft)
|
||||
{ }
|
||||
|
||||
bool operator== (const ClusterInstancePair &other) const
|
||||
{
|
||||
return a == other.a && b == other.b && soft == other.soft;
|
||||
}
|
||||
|
||||
bool operator< (const ClusterInstancePair &other) const
|
||||
{
|
||||
if (!(a == other.a)) {
|
||||
return a < other.a;
|
||||
}
|
||||
if (!(b == other.b)) {
|
||||
return b < other.b;
|
||||
}
|
||||
return soft < other.soft;
|
||||
}
|
||||
|
||||
ClusterInstance a, b;
|
||||
int soft;
|
||||
};
|
||||
|
||||
typedef std::list<ClusterInstancePair> cluster_instance_pair_list_type;
|
||||
|
||||
struct ClusterIDPair
|
||||
{
|
||||
typedef size_t id_type;
|
||||
|
||||
ClusterIDPair (id_type _a, id_type _b, int _soft)
|
||||
: a (_a), b (_b), soft (_soft)
|
||||
{ }
|
||||
|
||||
bool operator== (const ClusterIDPair &other) const
|
||||
{
|
||||
return a == other.a && b == other.b && soft == other.soft;
|
||||
}
|
||||
|
||||
bool operator< (const ClusterIDPair &other) const
|
||||
{
|
||||
if (!(a == other.a)) {
|
||||
return a < other.a;
|
||||
}
|
||||
if (!(b == other.b)) {
|
||||
return b < other.b;
|
||||
}
|
||||
return soft < other.soft;
|
||||
}
|
||||
|
||||
id_type a, b;
|
||||
int soft;
|
||||
};
|
||||
|
||||
inline bool equal_array_delegates (const db::ArrayBase *a, const db::ArrayBase *b)
|
||||
{
|
||||
|
|
@ -1106,7 +1228,7 @@ public:
|
|||
* The "with_id" cluster is removed. All connections of "with_id" are transferred to the
|
||||
* first one. All shapes of "with_id" are transferred to "id".
|
||||
*/
|
||||
void join_cluster_with(typename local_cluster<T>::id_type id, typename local_cluster<T>::id_type with_id);
|
||||
void join_cluster_with (typename local_cluster<T>::id_type id, typename local_cluster<T>::id_type with_id);
|
||||
|
||||
/**
|
||||
* @brief An iterator delivering all clusters (even the connectors)
|
||||
|
|
|
|||
|
|
@ -32,7 +32,9 @@
|
|||
#include "dbLayoutVsSchematic.h"
|
||||
#include "dbLayoutToNetlistFormatDefs.h"
|
||||
#include "dbLayoutVsSchematicFormatDefs.h"
|
||||
#include "dbLayoutToNetlistSoftConnections.h"
|
||||
#include "dbShapeProcessor.h"
|
||||
#include "dbNetlistDeviceClasses.h"
|
||||
#include "dbLog.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
||||
|
|
@ -45,7 +47,7 @@ namespace db
|
|||
// Note: the iterator provides the hierarchical selection (enabling/disabling cells etc.)
|
||||
|
||||
LayoutToNetlist::LayoutToNetlist (const db::RecursiveShapeIterator &iter)
|
||||
: m_iter (iter), m_layout_index (0), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false)
|
||||
: m_iter (iter), m_layout_index (0), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false), m_make_soft_connection_diodes (false)
|
||||
{
|
||||
// check the iterator
|
||||
if (iter.has_complex_region () || iter.region () != db::Box::world ()) {
|
||||
|
|
@ -65,7 +67,7 @@ LayoutToNetlist::LayoutToNetlist (const db::RecursiveShapeIterator &iter)
|
|||
}
|
||||
|
||||
LayoutToNetlist::LayoutToNetlist (db::DeepShapeStore *dss, unsigned int layout_index)
|
||||
: mp_dss (dss), m_layout_index (layout_index), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false)
|
||||
: mp_dss (dss), m_layout_index (layout_index), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false), m_make_soft_connection_diodes (false)
|
||||
{
|
||||
if (dss->is_valid_layout_index (m_layout_index)) {
|
||||
m_iter = db::RecursiveShapeIterator (dss->layout (m_layout_index), dss->initial_cell (m_layout_index), std::set<unsigned int> ());
|
||||
|
|
@ -73,7 +75,7 @@ LayoutToNetlist::LayoutToNetlist (db::DeepShapeStore *dss, unsigned int layout_i
|
|||
}
|
||||
|
||||
LayoutToNetlist::LayoutToNetlist (const std::string &topcell_name, double dbu)
|
||||
: m_iter (), m_netlist_extracted (false), m_is_flat (true), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false)
|
||||
: m_iter (), m_netlist_extracted (false), m_is_flat (true), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false), m_make_soft_connection_diodes (false)
|
||||
{
|
||||
mp_internal_dss.reset (new db::DeepShapeStore (topcell_name, dbu));
|
||||
mp_dss.reset (mp_internal_dss.get ());
|
||||
|
|
@ -84,7 +86,7 @@ LayoutToNetlist::LayoutToNetlist (const std::string &topcell_name, double dbu)
|
|||
|
||||
LayoutToNetlist::LayoutToNetlist ()
|
||||
: m_iter (), mp_internal_dss (new db::DeepShapeStore ()), mp_dss (mp_internal_dss.get ()), m_layout_index (0),
|
||||
m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false)
|
||||
m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false), m_make_soft_connection_diodes (false)
|
||||
{
|
||||
init ();
|
||||
}
|
||||
|
|
@ -298,6 +300,26 @@ void LayoutToNetlist::connect_impl (const db::ShapeCollection &a, const db::Shap
|
|||
m_conn.connect (dla.layer (), dlb.layer ());
|
||||
}
|
||||
|
||||
void LayoutToNetlist::soft_connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b)
|
||||
{
|
||||
reset_extracted ();
|
||||
|
||||
if (! is_persisted (a)) {
|
||||
register_layer (a);
|
||||
}
|
||||
if (! is_persisted (b)) {
|
||||
register_layer (b);
|
||||
}
|
||||
|
||||
// we need to keep a reference, so we can safely delete the region
|
||||
db::DeepLayer dla = deep_layer_of (a);
|
||||
db::DeepLayer dlb = deep_layer_of (b);
|
||||
m_dlrefs.insert (dla);
|
||||
m_dlrefs.insert (dlb);
|
||||
|
||||
m_conn.soft_connect (dla.layer (), dlb.layer ());
|
||||
}
|
||||
|
||||
size_t LayoutToNetlist::connect_global_impl (const db::ShapeCollection &l, const std::string &gn)
|
||||
{
|
||||
reset_extracted ();
|
||||
|
|
@ -313,6 +335,21 @@ size_t LayoutToNetlist::connect_global_impl (const db::ShapeCollection &l, const
|
|||
return m_conn.connect_global (dl.layer (), gn);
|
||||
}
|
||||
|
||||
size_t LayoutToNetlist::soft_connect_global_impl (const db::ShapeCollection &l, const std::string &gn)
|
||||
{
|
||||
reset_extracted ();
|
||||
|
||||
if (! is_persisted (l)) {
|
||||
register_layer (l);
|
||||
}
|
||||
|
||||
// we need to keep a reference, so we can safely delete the region
|
||||
db::DeepLayer dl = deep_layer_of (l);
|
||||
m_dlrefs.insert (dl);
|
||||
|
||||
return m_conn.soft_connect_global (dl.layer (), gn);
|
||||
}
|
||||
|
||||
const std::string &LayoutToNetlist::global_net_name (size_t id) const
|
||||
{
|
||||
return m_conn.global_net_name (id);
|
||||
|
|
@ -360,6 +397,24 @@ void LayoutToNetlist::join_nets (const tl::GlobPattern &cell, const std::set<std
|
|||
m_joined_nets_per_cell.push_back (std::make_pair (cell, gp));
|
||||
}
|
||||
|
||||
#if defined(_DEBUG)
|
||||
static bool check_many_pins (const db::Netlist *netlist)
|
||||
{
|
||||
bool ok = true;
|
||||
for (auto c = netlist->begin_circuits (); c != netlist->end_circuits (); ++c) {
|
||||
const db::Circuit &circuit = *c;
|
||||
for (auto n = circuit.begin_nets (); n != circuit.end_nets (); ++n) {
|
||||
const db::Net &net = *n;
|
||||
if (net.pin_count () > 1) {
|
||||
ok = false;
|
||||
tl::error << "Many pins on net " << net.expanded_name () << " in circuit " << circuit.name ();
|
||||
}
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
#endif
|
||||
|
||||
void LayoutToNetlist::extract_netlist ()
|
||||
{
|
||||
if (m_netlist_extracted) {
|
||||
|
|
@ -371,6 +426,17 @@ void LayoutToNetlist::extract_netlist ()
|
|||
netex.set_include_floating_subcircuits (m_include_floating_subcircuits);
|
||||
netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters);
|
||||
|
||||
// treat soft connections
|
||||
do_soft_connections ();
|
||||
|
||||
// implement the "join_nets" (aka "must connect") feature
|
||||
#if defined(_DEBUG)
|
||||
// NOTE: the join_nets feature only works for "one pin per net" case
|
||||
// TODO: either fix that or make sure we do not get multiple pins per net.
|
||||
// Right now, there no known case that produces multiple pins on a net at
|
||||
// this stage.
|
||||
tl_assert (check_many_pins (mp_netlist.get ()));
|
||||
#endif
|
||||
do_join_nets ();
|
||||
|
||||
if (tl::verbosity () >= 41) {
|
||||
|
|
@ -477,7 +543,7 @@ void LayoutToNetlist::check_must_connect (const db::Circuit &c, const db::Net &a
|
|||
check_must_connect_impl (c, a, b, c, a, b, path);
|
||||
}
|
||||
|
||||
static std::string path_msg (const std::vector<const db::SubCircuit *> &path, const db::Circuit &c_org)
|
||||
static std::string path_msg (const std::vector<const db::SubCircuit *> &path)
|
||||
{
|
||||
if (path.empty ()) {
|
||||
return std::string ();
|
||||
|
|
@ -485,15 +551,13 @@ static std::string path_msg (const std::vector<const db::SubCircuit *> &path, co
|
|||
|
||||
std::string msg (".\n" + tl::to_string (tr ("Instance path: ")));
|
||||
|
||||
for (auto p = path.rbegin (); p != path.rend (); ++p) {
|
||||
if (p != path.rbegin ()) {
|
||||
msg += "/";
|
||||
}
|
||||
msg += (*p)->circuit ()->name () + ":" + (*p)->expanded_name () + "[" + (*p)->trans ().to_string () + "]";
|
||||
}
|
||||
auto p0 = path.rbegin ();
|
||||
msg += (*p0)->circuit ()->name ();
|
||||
|
||||
msg += "/";
|
||||
msg += c_org.name ();
|
||||
for (auto p = p0; p != path.rend (); ++p) {
|
||||
msg += "/";
|
||||
msg += (*p)->circuit_ref ()->name () + "[" + (*p)->trans ().to_string (true /*short*/) + "]" + ":" + (*p)->expanded_name ();
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
|
@ -519,12 +583,12 @@ void LayoutToNetlist::check_must_connect_impl (const db::Circuit &c, const db::N
|
|||
|
||||
if (a_org.expanded_name () == b_org.expanded_name ()) {
|
||||
if (path.empty ()) {
|
||||
db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s must be connected further up in the hierarchy - this is an error at chip top level")), a_org.expanded_name ()) + path_msg (path, c_org));
|
||||
db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s must be connected further up in the hierarchy - this is an error at chip top level")), a_org.expanded_name ()) + path_msg (path));
|
||||
warn.set_cell_name (c.name ());
|
||||
warn.set_category_name ("must-connect");
|
||||
log_entry (warn);
|
||||
} else {
|
||||
db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s of circuit %s must be connected further up in the hierarchy - this is an error at chip top level")), a_org.expanded_name (), c_org.name ()) + path_msg (path, c_org));
|
||||
db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s of circuit %s must be connected further up in the hierarchy - this is an error at chip top level")), a_org.expanded_name (), c_org.name ()) + path_msg (path));
|
||||
warn.set_cell_name (c.name ());
|
||||
warn.set_geometry (subcircuit_geometry (*path.back (), internal_layout ()));
|
||||
warn.set_category_name ("must-connect");
|
||||
|
|
@ -532,12 +596,12 @@ void LayoutToNetlist::check_must_connect_impl (const db::Circuit &c, const db::N
|
|||
}
|
||||
} else {
|
||||
if (path.empty ()) {
|
||||
db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s must be connected further up in the hierarchy - this is an error at chip top level")), a_org.expanded_name (), b_org.expanded_name ()) + path_msg (path, c_org));
|
||||
db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s must be connected further up in the hierarchy - this is an error at chip top level")), a_org.expanded_name (), b_org.expanded_name ()) + path_msg (path));
|
||||
warn.set_cell_name (c.name ());
|
||||
warn.set_category_name ("must-connect");
|
||||
log_entry (warn);
|
||||
} else {
|
||||
db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s of circuit %s must be connected further up in the hierarchy - this is an error at chip top level")), a_org.expanded_name (), b_org.expanded_name (), c_org.name ()) + path_msg (path, c_org));
|
||||
db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s of circuit %s must be connected further up in the hierarchy - this is an error at chip top level")), a_org.expanded_name (), b_org.expanded_name (), c_org.name ()) + path_msg (path));
|
||||
warn.set_cell_name (c.name ());
|
||||
warn.set_geometry (subcircuit_geometry (*path.back (), internal_layout ()));
|
||||
warn.set_category_name ("must-connect");
|
||||
|
|
@ -558,7 +622,7 @@ void LayoutToNetlist::check_must_connect_impl (const db::Circuit &c, const db::N
|
|||
const db::Net *net_b = sc.net_for_pin (b.begin_pins ()->pin_id ());
|
||||
|
||||
if (net_a == 0) {
|
||||
db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s of circuit %s is not connected at all%s")), a_org.expanded_name (), c_org.name (), subcircuit_to_string (sc)) + path_msg (path, c_org));
|
||||
db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s of circuit %s is not connected at all%s")), a_org.expanded_name (), c_org.name (), subcircuit_to_string (sc)) + path_msg (path));
|
||||
error.set_cell_name (sc.circuit ()->name ());
|
||||
error.set_geometry (subcircuit_geometry (sc, internal_layout ()));
|
||||
error.set_category_name ("must-connect");
|
||||
|
|
@ -566,7 +630,7 @@ void LayoutToNetlist::check_must_connect_impl (const db::Circuit &c, const db::N
|
|||
}
|
||||
|
||||
if (net_b == 0) {
|
||||
db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s of circuit %s is not connected at all%s")), b_org.expanded_name (), c_org.name (), subcircuit_to_string (sc)) + path_msg (path, c_org));
|
||||
db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s of circuit %s is not connected at all%s")), b_org.expanded_name (), c_org.name (), subcircuit_to_string (sc)) + path_msg (path));
|
||||
error.set_cell_name (sc.circuit ()->name ());
|
||||
error.set_geometry (subcircuit_geometry (sc, internal_layout ()));
|
||||
error.set_category_name ("must-connect");
|
||||
|
|
@ -584,6 +648,54 @@ void LayoutToNetlist::check_must_connect_impl (const db::Circuit &c, const db::N
|
|||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlist::place_soft_connection_diodes ()
|
||||
{
|
||||
db::DeviceClassDiode *soft_diode = 0;
|
||||
|
||||
for (auto c = mp_netlist->begin_bottom_up (); c != mp_netlist->end_bottom_up (); ++c) {
|
||||
|
||||
auto clusters = net_clusters ().clusters_per_cell (c->cell_index ());
|
||||
|
||||
for (auto n = c->begin_nets (); n != c->end_nets (); ++n) {
|
||||
|
||||
auto soft_connections = clusters.upward_soft_connections (n->cluster_id ());
|
||||
for (auto sc = soft_connections.begin (); sc != soft_connections.end (); ++sc) {
|
||||
|
||||
if (! soft_diode) {
|
||||
soft_diode = new db::DeviceClassDiode ();
|
||||
soft_diode->set_name ("SOFT");
|
||||
mp_netlist->add_device_class (soft_diode);
|
||||
}
|
||||
|
||||
db::Device *sc_device = new db::Device (soft_diode);
|
||||
c->add_device (sc_device);
|
||||
|
||||
auto nn = c->net_by_cluster_id (*sc);
|
||||
if (nn) {
|
||||
sc_device->connect_terminal (db::DeviceClassDiode::terminal_id_C, n.operator-> ());
|
||||
sc_device->connect_terminal (db::DeviceClassDiode::terminal_id_A, nn);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlist::do_soft_connections ()
|
||||
{
|
||||
SoftConnectionInfo sc_info;
|
||||
sc_info.build (*netlist (), net_clusters ());
|
||||
sc_info.report (*this);
|
||||
|
||||
if (m_make_soft_connection_diodes) {
|
||||
place_soft_connection_diodes ();
|
||||
} else {
|
||||
sc_info.join_soft_connections (*netlist ());
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlist::do_join_nets ()
|
||||
{
|
||||
if (! mp_netlist) {
|
||||
|
|
@ -915,7 +1027,7 @@ LayoutToNetlist::create_layermap (db::Layout &target_layout, int ln) const
|
|||
|
||||
std::set<unsigned int> layers_to_copy;
|
||||
const db::Connectivity &conn = connectivity ();
|
||||
for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
for (db::Connectivity::all_layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
layers_to_copy.insert (*layer);
|
||||
}
|
||||
|
||||
|
|
@ -1162,7 +1274,8 @@ size_t LayoutToNetlist::search_net (const db::ICplxTrans &trans, const db::Cell
|
|||
const db::local_clusters<db::NetShape> &lcc = net_clusters ().clusters_per_cell (cell->cell_index ());
|
||||
for (db::local_clusters<db::NetShape>::touching_iterator i = lcc.begin_touching (local_box); ! i.at_end (); ++i) {
|
||||
const db::local_cluster<db::NetShape> &lc = *i;
|
||||
if (lc.interacts (test_cluster, trans, m_conn)) {
|
||||
int soft = 0;
|
||||
if (lc.interacts (test_cluster, trans, m_conn, soft)) {
|
||||
return lc.id ();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -494,6 +494,39 @@ public:
|
|||
connect_impl (b, a);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Defines an inter-layer soft connection for the given layers.
|
||||
* The conditions mentioned with intra-layer "connect" apply for this method too.
|
||||
* The "a" layer is the "upper" and the "b" layer the "lower" layer of the
|
||||
* soft connection.
|
||||
*/
|
||||
void soft_connect (const db::Region &a, const db::Region &b)
|
||||
{
|
||||
soft_connect_impl (a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Defines an inter-layer connection for the given layers.
|
||||
* As one layer is a texts layer, this connection will basically add net labels.
|
||||
* The "a" layer is the "upper" and the "b" layer the "lower" layer of the
|
||||
* soft connection.
|
||||
*/
|
||||
void soft_connect (const db::Region &a, const db::Texts &b)
|
||||
{
|
||||
soft_connect_impl (a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Defines an inter-layer connection for the given layers.
|
||||
* As one layer is a texts layer, this connection will basically add net labels.
|
||||
* The "a" layer is the "upper" and the "b" layer the "lower" layer of the
|
||||
* soft connection.
|
||||
*/
|
||||
void soft_connect (const db::Texts &a, const db::Region &b)
|
||||
{
|
||||
soft_connect_impl (b, a);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connects the given layer with a global net with the given name
|
||||
* Returns the global net ID
|
||||
|
|
@ -512,6 +545,26 @@ public:
|
|||
return connect_global_impl (l, gn);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Soft-connects the given layer with a global net with the given name
|
||||
* Returns the global net ID.
|
||||
* The global layer is the "lower" layer of the soft connection.
|
||||
*/
|
||||
size_t soft_connect_global (const db::Region &l, const std::string &gn)
|
||||
{
|
||||
return soft_connect_global_impl (l, gn);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Soft-connects the given text layer with a global net with the given name
|
||||
* Returns the global net ID.
|
||||
* The global layer is the "lower" layer of the soft connection.
|
||||
*/
|
||||
size_t soft_connect_global (const db::Texts &l, const std::string &gn)
|
||||
{
|
||||
return soft_connect_global_impl (l, gn);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the global net name for a given global net ID
|
||||
*/
|
||||
|
|
@ -992,6 +1045,18 @@ public:
|
|||
*/
|
||||
void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const;
|
||||
|
||||
// for debugging and testing
|
||||
bool make_soft_connection_diodes () const
|
||||
{
|
||||
return m_make_soft_connection_diodes;
|
||||
}
|
||||
|
||||
// for debugging and testing
|
||||
void set_make_soft_connection_diodes (bool f)
|
||||
{
|
||||
m_make_soft_connection_diodes = f;
|
||||
}
|
||||
|
||||
private:
|
||||
// no copying
|
||||
LayoutToNetlist (const db::LayoutToNetlist &other);
|
||||
|
|
@ -1021,6 +1086,7 @@ private:
|
|||
std::string m_generator;
|
||||
bool m_include_floating_subcircuits;
|
||||
bool m_top_level_mode;
|
||||
bool m_make_soft_connection_diodes;
|
||||
std::list<tl::GlobPattern> m_joined_net_names;
|
||||
std::list<std::pair<tl::GlobPattern, tl::GlobPattern> > m_joined_net_names_per_cell;
|
||||
std::list<std::set<std::string> > m_joined_nets;
|
||||
|
|
@ -1035,14 +1101,20 @@ private:
|
|||
db::CellMapping make_cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector<const db::Net *> *nets, bool with_device_cells);
|
||||
void connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b);
|
||||
size_t connect_global_impl (const db::ShapeCollection &l, const std::string &gn);
|
||||
void soft_connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b);
|
||||
size_t soft_connect_global_impl (const db::ShapeCollection &l, const std::string &gn);
|
||||
bool is_persisted_impl (const db::ShapeCollection &coll) const;
|
||||
void do_join_nets (db::Circuit &c, const std::vector<Net *> &nets);
|
||||
void do_join_nets ();
|
||||
void do_soft_connections ();
|
||||
void join_nets_from_pattern (db::Circuit &c, const tl::GlobPattern &p);
|
||||
void join_nets_from_pattern (db::Circuit &c, const std::set<std::string> &p);
|
||||
void check_must_connect (const db::Circuit &c, const db::Net &a, const db::Net &b);
|
||||
void check_must_connect_impl (const db::Circuit &c, const db::Net &a, const db::Net &b, const db::Circuit &c_org, const db::Net &a_org, const db::Net &b_org, std::vector<const db::SubCircuit *> &path);
|
||||
|
||||
// for debugging and testing
|
||||
void place_soft_connection_diodes ();
|
||||
|
||||
// implementation of NetlistManipulationCallbacks
|
||||
virtual size_t link_net_to_parent_circuit (const Net *subcircuit_net, Circuit *parent_circuit, const DCplxTrans &trans);
|
||||
virtual void link_nets (const db::Net *net, const db::Net *with);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ namespace l2n_std_format
|
|||
DB_PUBLIC std::string LongKeys::layer_key ("layer");
|
||||
DB_PUBLIC std::string LongKeys::class_key ("class");
|
||||
DB_PUBLIC std::string LongKeys::connect_key ("connect");
|
||||
DB_PUBLIC std::string LongKeys::softconnect_key ("softconnect");
|
||||
DB_PUBLIC std::string LongKeys::global_key ("global");
|
||||
DB_PUBLIC std::string LongKeys::softglobal_key ("softglobal");
|
||||
DB_PUBLIC std::string LongKeys::circuit_key ("circuit");
|
||||
DB_PUBLIC std::string LongKeys::net_key ("net");
|
||||
DB_PUBLIC std::string LongKeys::name_key ("name");
|
||||
|
|
@ -72,7 +74,9 @@ namespace l2n_std_format
|
|||
DB_PUBLIC std::string ShortKeys::layer_key ("L");
|
||||
DB_PUBLIC std::string ShortKeys::class_key ("K");
|
||||
DB_PUBLIC std::string ShortKeys::connect_key ("C");
|
||||
DB_PUBLIC std::string ShortKeys::softconnect_key ("CS");
|
||||
DB_PUBLIC std::string ShortKeys::global_key ("G");
|
||||
DB_PUBLIC std::string ShortKeys::softglobal_key ("GS");
|
||||
DB_PUBLIC std::string ShortKeys::circuit_key ("X");
|
||||
DB_PUBLIC std::string ShortKeys::net_key ("N");
|
||||
DB_PUBLIC std::string ShortKeys::name_key ("I");
|
||||
|
|
|
|||
|
|
@ -66,11 +66,14 @@ namespace db
|
|||
*
|
||||
* [connect]:
|
||||
* connect(<layer1> <name> ...) - connects layer1 with the following layers [short key: C]
|
||||
* softconnect(<upper> <lower> ...)
|
||||
* - specifies soft connection between lower and upper layer [short key: CS]
|
||||
*
|
||||
* [global]:
|
||||
* global(<layer> <net-name> ...)
|
||||
* - connects the shapes of the layer with the given global
|
||||
* nets [short key: G]
|
||||
* - connects the shapes of the layer with the given global nets [short key: G]
|
||||
* softglobal(<layer> <net-name> ...)
|
||||
* - soft-connects the shapes of the layer with the given global net [shoft key: GS]
|
||||
*
|
||||
* [circuit]:
|
||||
* circuit(<name> [circuit-def]) - circuit (cell) [short key: X]
|
||||
|
|
@ -222,7 +225,9 @@ namespace l2n_std_format
|
|||
static std::string layer_key;
|
||||
static std::string class_key;
|
||||
static std::string connect_key;
|
||||
static std::string softconnect_key;
|
||||
static std::string global_key;
|
||||
static std::string softglobal_key;
|
||||
static std::string circuit_key;
|
||||
static std::string net_key;
|
||||
static std::string name_key;
|
||||
|
|
@ -261,7 +266,9 @@ namespace l2n_std_format
|
|||
static std::string layer_key;
|
||||
static std::string class_key;
|
||||
static std::string connect_key;
|
||||
static std::string softconnect_key;
|
||||
static std::string global_key;
|
||||
static std::string softglobal_key;
|
||||
static std::string circuit_key;
|
||||
static std::string net_key;
|
||||
static std::string name_key;
|
||||
|
|
|
|||
|
|
@ -462,12 +462,17 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo
|
|||
}
|
||||
br.done ();
|
||||
|
||||
} else if (l2n && (test (skeys::message_key) || test (lkeys::message_key))) {
|
||||
} else if (l2n && (test (skeys::softconnect_key) || test (lkeys::softconnect_key))) {
|
||||
|
||||
db::LogEntryData data;
|
||||
read_message_entry (data);
|
||||
|
||||
l2n->log_entry (data);
|
||||
Brace br (this);
|
||||
std::string l1;
|
||||
read_word_or_quoted (l1);
|
||||
while (br) {
|
||||
std::string l2;
|
||||
read_word_or_quoted (l2);
|
||||
l2n->soft_connect (layer_by_name (l2n, l1), layer_by_name (l2n, l2));
|
||||
}
|
||||
br.done ();
|
||||
|
||||
} else if (l2n && (test (skeys::global_key) || test (lkeys::global_key))) {
|
||||
|
||||
|
|
@ -481,6 +486,25 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo
|
|||
}
|
||||
br.done ();
|
||||
|
||||
} else if (l2n && (test (skeys::softglobal_key) || test (lkeys::softglobal_key))) {
|
||||
|
||||
Brace br (this);
|
||||
std::string l1;
|
||||
read_word_or_quoted (l1);
|
||||
while (br) {
|
||||
std::string g;
|
||||
read_word_or_quoted (g);
|
||||
l2n->soft_connect_global (layer_by_name (l2n, l1), g);
|
||||
}
|
||||
br.done ();
|
||||
|
||||
} else if (l2n && (test (skeys::message_key) || test (lkeys::message_key))) {
|
||||
|
||||
db::LogEntryData data;
|
||||
read_message_entry (data);
|
||||
|
||||
l2n->log_entry (data);
|
||||
|
||||
} else if (test (skeys::circuit_key) || test (lkeys::circuit_key)) {
|
||||
|
||||
Brace br (this);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,422 @@
|
|||
|
||||
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbLayoutToNetlistSoftConnections.h"
|
||||
#include "dbLayoutToNetlist.h"
|
||||
#include "dbHierNetworkProcessor.h"
|
||||
#include "dbNetlist.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// SoftConnectionNetGraph implementation
|
||||
|
||||
SoftConnectionNetGraph::SoftConnectionNetGraph ()
|
||||
: m_partial_net_count (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void SoftConnectionNetGraph::add (const db::Net *net, SoftConnectionPinDir dir, const db::Pin *pin, size_t partial_net_count)
|
||||
{
|
||||
m_partial_net_count += partial_net_count;
|
||||
|
||||
// this is where we make the decision about the partial nets ...
|
||||
if (! pin && dir == SoftConnectionPinDir::down ()) {
|
||||
m_partial_net_count += 1;
|
||||
}
|
||||
|
||||
if (pin) {
|
||||
m_pin_ids.insert (pin->id ());
|
||||
}
|
||||
|
||||
m_cluster_dir.insert (std::make_pair (net->cluster_id (), dir));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// SoftConnectionCircuitInfo implementation
|
||||
|
||||
SoftConnectionCircuitInfo::SoftConnectionCircuitInfo (const db::Circuit *circuit)
|
||||
: mp_circuit (circuit)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
SoftConnectionNetGraph &SoftConnectionCircuitInfo::make_net_graph ()
|
||||
{
|
||||
m_net_graphs.push_back (SoftConnectionNetGraph ());
|
||||
return m_net_graphs.back ();
|
||||
}
|
||||
|
||||
void SoftConnectionCircuitInfo::add_pin_info (const db::Pin *pin, SoftConnectionPinDir dir, SoftConnectionNetGraph *graph_info)
|
||||
{
|
||||
if (pin) {
|
||||
m_pin_info.insert (std::make_pair (pin->id (), std::make_pair (dir, graph_info)));
|
||||
}
|
||||
}
|
||||
|
||||
SoftConnectionPinDir SoftConnectionCircuitInfo::direction_per_pin (const db::Pin *pin) const
|
||||
{
|
||||
if (! pin) {
|
||||
return SoftConnectionPinDir ();
|
||||
}
|
||||
|
||||
auto p = m_pin_info.find (pin->id ());
|
||||
return p != m_pin_info.end () ? p->second.first : SoftConnectionPinDir ();
|
||||
}
|
||||
|
||||
const SoftConnectionNetGraph *SoftConnectionCircuitInfo::get_net_graph_per_pin (const db::Pin *pin) const
|
||||
{
|
||||
if (! pin) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto p = m_pin_info.find (pin->id ());
|
||||
return p != m_pin_info.end () ? p->second.second : 0;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// SoftConnectionInfo implementation
|
||||
|
||||
SoftConnectionInfo::SoftConnectionInfo ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void SoftConnectionInfo::build (const db::Netlist &netlist, const db::hier_clusters<db::NetShape> &shape_clusters)
|
||||
{
|
||||
for (auto c = netlist.begin_bottom_up (); c != netlist.end_bottom_up (); ++c) {
|
||||
build_graphs_for_circuit (c.operator-> (), shape_clusters.clusters_per_cell (c->cell_index ()));
|
||||
}
|
||||
}
|
||||
|
||||
void SoftConnectionInfo::join_soft_connections (db::Netlist &netlist)
|
||||
{
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::info << "Joining soft-connected net graphs ..";
|
||||
}
|
||||
|
||||
size_t nnet_graphs_tot = 0;
|
||||
size_t npartial_tot = 0;
|
||||
|
||||
for (auto c = netlist.begin_top_down (); c != netlist.end_top_down (); ++c) {
|
||||
|
||||
size_t nnet_graphs = 0;
|
||||
size_t npartial = 0;
|
||||
|
||||
auto scc = m_scc_per_circuit.find (c.operator-> ());
|
||||
if (scc == m_scc_per_circuit.end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const SoftConnectionCircuitInfo &sc_info = scc->second;
|
||||
|
||||
for (auto sc = sc_info.begin (); sc != sc_info.end (); ++sc) {
|
||||
|
||||
auto cc = sc->begin_clusters ();
|
||||
if (cc != sc->end_clusters ()) {
|
||||
db::Net *net0 = c->net_by_cluster_id (cc->first);
|
||||
tl_assert (net0 != 0);
|
||||
++nnet_graphs;
|
||||
while (++cc != sc->end_clusters ()) {
|
||||
// TODO: logging?
|
||||
c->join_nets (net0, c->net_by_cluster_id (cc->first));
|
||||
++npartial;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nnet_graphs_tot += nnet_graphs;
|
||||
npartial_tot += npartial;
|
||||
|
||||
if (nnet_graphs > 0 && tl::verbosity () >= 30) {
|
||||
tl::info << "Circuit " << c->name () << ": joined " << nnet_graphs << " soft-connected net clusters with " << npartial << " partial nets.";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::info << "Joined " << nnet_graphs_tot << " soft-connected net clusters with " << npartial_tot << " partial nets in total.";
|
||||
}
|
||||
|
||||
m_scc_per_circuit.clear ();
|
||||
}
|
||||
|
||||
db::DPolygon
|
||||
SoftConnectionInfo::representative_polygon (const db::Net *net, const db::LayoutToNetlist &l2n, const db::CplxTrans &trans)
|
||||
{
|
||||
const db::Connectivity &conn = l2n.connectivity ();
|
||||
const db::hier_clusters<db::NetShape> &net_clusters = l2n.net_clusters ();
|
||||
|
||||
db::DBox bbox;
|
||||
|
||||
for (auto l = conn.begin_layers (); l != conn.end_layers (); ++l) {
|
||||
db::recursive_cluster_shape_iterator<db::NetShape> si (net_clusters, *l, net->circuit ()->cell_index (), net->cluster_id ());
|
||||
while (! si.at_end ()) {
|
||||
if (si->type () == db::NetShape::Polygon) {
|
||||
bbox += trans * (si.trans () * si->polygon_ref ().box ());
|
||||
}
|
||||
++si;
|
||||
}
|
||||
}
|
||||
|
||||
return db::DPolygon (bbox);
|
||||
}
|
||||
|
||||
void SoftConnectionInfo::report_partial_nets (const db::Circuit *circuit, const SoftConnectionNetGraph &net_graph, db::LayoutToNetlist &l2n, const std::string &path, const db::DCplxTrans &trans, const std::string &top_cell, int &index, std::set<std::pair<const db::Net *, db::DCplxTrans> > &seen)
|
||||
{
|
||||
for (auto cc = net_graph.begin_clusters (); cc != net_graph.end_clusters (); ++cc) {
|
||||
|
||||
const db::Net *net = circuit->net_by_cluster_id (cc->first);
|
||||
|
||||
if (! seen.insert (std::make_pair (net, trans)).second) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cc->second == SoftConnectionPinDir::down () && ! net->is_floating () && net->begin_pins () == net->end_pins ()) {
|
||||
|
||||
std::string msg = tl::sprintf (tl::to_string (tr ("\tPartial net #%d: %s - %s")), ++index, path, net->expanded_name ());
|
||||
|
||||
db::LogEntryData entry (db::NoSeverity, top_cell, msg);
|
||||
entry.set_geometry (representative_polygon (net, l2n, trans * db::CplxTrans (l2n.internal_layout ()->dbu ())));
|
||||
|
||||
l2n.log_entry (entry);
|
||||
|
||||
}
|
||||
|
||||
for (auto sc = net->begin_subcircuit_pins (); sc != net->end_subcircuit_pins (); ++sc) {
|
||||
|
||||
const db::SubCircuit *subcircuit = sc->subcircuit ();
|
||||
const db::Circuit *circuit_ref = subcircuit->circuit_ref ();
|
||||
|
||||
auto scc = m_scc_per_circuit.find (circuit_ref);
|
||||
if (scc == m_scc_per_circuit.end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const SoftConnectionCircuitInfo &sci = scc->second;
|
||||
|
||||
const SoftConnectionNetGraph *scci = sci.get_net_graph_per_pin (sc->pin ());
|
||||
if (! scci || scci->partial_net_count () == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string p = path;
|
||||
p += std::string ("/") + circuit_ref->name ();
|
||||
p += std::string ("[") + subcircuit->trans ().to_string (true /*short*/) + "]:" + subcircuit->expanded_name ();
|
||||
report_partial_nets (circuit_ref, *scci, l2n, p, trans * subcircuit->trans (), top_cell, index, seen);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SoftConnectionInfo::report (db::LayoutToNetlist &l2n)
|
||||
{
|
||||
const db::Netlist *netlist = l2n.netlist ();
|
||||
if (! netlist) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto c = netlist->begin_bottom_up (); c != netlist->end_bottom_up (); ++c) {
|
||||
|
||||
auto scc = m_scc_per_circuit.find (c.operator-> ());
|
||||
if (scc == m_scc_per_circuit.end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const SoftConnectionCircuitInfo &sc_info = scc->second;
|
||||
|
||||
for (auto sc = sc_info.begin (); sc != sc_info.end (); ++sc) {
|
||||
|
||||
if (sc->partial_net_count () < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
db::LogEntryData log_entry (l2n.top_level_mode () ? db::Error : db::Warning, c->name (), tl::to_string (tr ("Net with incomplete wiring (soft-connected partial nets)")));
|
||||
log_entry.set_category_name ("soft-connection-check");
|
||||
l2n.log_entry (log_entry);
|
||||
|
||||
int index = 0;
|
||||
std::set<std::pair<const db::Net *, db::DCplxTrans> > seen;
|
||||
report_partial_nets (c.operator-> (), *sc, l2n, c->name (), db::DCplxTrans (), c->name (), index, seen);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SoftConnectionInfo::build_graphs_for_circuit (const db::Circuit *circuit, const db::connected_clusters<db::NetShape> &shape_clusters)
|
||||
{
|
||||
SoftConnectionCircuitInfo &sc_circuit_info = m_scc_per_circuit.insert (std::make_pair (circuit, SoftConnectionCircuitInfo (circuit))).first->second;
|
||||
|
||||
std::set<size_t> seen;
|
||||
for (auto c = shape_clusters.begin (); c != shape_clusters.end (); ++c) {
|
||||
|
||||
if (seen.find (c->id ()) != seen.end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// incrementally collect further connected nets (shape clusters)
|
||||
|
||||
std::set<size_t> connected;
|
||||
connected.insert (c->id ());
|
||||
seen.insert (c->id ());
|
||||
|
||||
SoftConnectionNetGraph *sc_net_graph = 0;
|
||||
|
||||
while (! connected.empty ()) {
|
||||
|
||||
std::set<size_t> next_connected;
|
||||
|
||||
for (auto cc = connected.begin (); cc != connected.end (); ++cc) {
|
||||
|
||||
const db::Net *net = circuit->net_by_cluster_id (*cc);
|
||||
if (! net) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// the direction of a net is 0 for "no connections" or "both up and down"
|
||||
// and -1 for "down-only" connections and +1 for "up-only" connections:
|
||||
|
||||
SoftConnectionPinDir dir;
|
||||
|
||||
// direct soft connections to other nets
|
||||
|
||||
for (int up = 0; up < 2; ++up) {
|
||||
std::set<size_t> next = up ? shape_clusters.upward_soft_connections (*cc) : shape_clusters.downward_soft_connections (*cc);
|
||||
if (! next.empty () || net_has_up_or_down_subcircuit_connections (net, up)) {
|
||||
dir |= up ? SoftConnectionPinDir::up () : SoftConnectionPinDir::down ();
|
||||
}
|
||||
for (auto i = next.begin (); i != next.end (); ++i) {
|
||||
if (seen.insert (*i).second) {
|
||||
next_connected.insert (*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// collect soft connections via subcircuits
|
||||
|
||||
size_t sc_partial_net_count = 0;
|
||||
std::set<size_t> next = net_connections_through_subcircuits (net, sc_partial_net_count);
|
||||
|
||||
for (auto i = next.begin (); i != next.end (); ++i) {
|
||||
if (seen.insert (*i).second) {
|
||||
next_connected.insert (*i);
|
||||
}
|
||||
}
|
||||
|
||||
// is this net associated with a pin?
|
||||
|
||||
const db::Pin *pin = 0;
|
||||
if (net->begin_pins () != net->end_pins ()) {
|
||||
// TODO: multiple pins per net need to be supported?
|
||||
tl_assert (net->pin_count () == 1);
|
||||
pin = net->begin_pins ()->pin ();
|
||||
}
|
||||
|
||||
if (! sc_net_graph) {
|
||||
sc_net_graph = &sc_circuit_info.make_net_graph ();
|
||||
}
|
||||
|
||||
// we do not count floating nets as they cannot make a functional connection
|
||||
if (! net->is_floating ()) {
|
||||
sc_net_graph->add (net, dir, pin, sc_partial_net_count);
|
||||
}
|
||||
|
||||
sc_circuit_info.add_pin_info (pin, dir, sc_net_graph);
|
||||
|
||||
}
|
||||
|
||||
connected.swap (next_connected);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool SoftConnectionInfo::net_has_up_or_down_subcircuit_connections (const db::Net *net, bool up)
|
||||
{
|
||||
SoftConnectionPinDir look_for_dir = up ? SoftConnectionPinDir::up () : SoftConnectionPinDir::down ();
|
||||
|
||||
for (auto sc = net->begin_subcircuit_pins (); sc != net->end_subcircuit_pins (); ++sc) {
|
||||
const db::Pin *pin = sc->pin ();
|
||||
const db::Circuit *ref = sc->subcircuit ()->circuit_ref ();
|
||||
auto scc_ref = m_scc_per_circuit.find (ref);
|
||||
if (scc_ref != m_scc_per_circuit.end ()) {
|
||||
SoftConnectionPinDir dir = scc_ref->second.direction_per_pin (pin);
|
||||
if (dir & look_for_dir) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SoftConnectionInfo::get_net_connections_through_subcircuit (const db::SubCircuit *subcircuit, const db::Pin *pin, std::set<size_t> &ids, size_t &partial_net_count)
|
||||
{
|
||||
auto scc = m_scc_per_circuit.find (subcircuit->circuit_ref ());
|
||||
if (scc != m_scc_per_circuit.end ()) {
|
||||
|
||||
const SoftConnectionCircuitInfo &sci = scc->second;
|
||||
|
||||
const SoftConnectionNetGraph *scci = sci.get_net_graph_per_pin (pin);
|
||||
if (scci) {
|
||||
|
||||
// NOTE: limiting the partial net count here means we do report a partially connected once in the
|
||||
// hierarchy, not on every level.
|
||||
// Say, if you have two subcircuits, one (A) having 2 partial nets and the other (B) none. Then
|
||||
// (A) would be reported to partial nets only and when combining (A) and (B) we just need to check
|
||||
// whether B would also have partial nets. By not taking 2 + 0, but 1 + 0 the combination of (A)
|
||||
// and (B) does not give an error (error = number of partial nets > 1).
|
||||
partial_net_count += std::min (size_t (1), scci->partial_net_count ());
|
||||
|
||||
for (auto p = scci->begin_pins (); p != scci->end_pins (); ++p) {
|
||||
if (*p != pin->id ()) {
|
||||
const NetSubcircuitPinRef *netref = subcircuit->netref_for_pin (*p);
|
||||
if (netref && netref->net ()) {
|
||||
ids.insert (netref->net ()->cluster_id ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::set<size_t> SoftConnectionInfo::net_connections_through_subcircuits (const db::Net *net, size_t &partial_net_count)
|
||||
{
|
||||
std::set<size_t> ids;
|
||||
for (auto sc = net->begin_subcircuit_pins (); sc != net->end_subcircuit_pins (); ++sc) {
|
||||
get_net_connections_through_subcircuit (sc->subcircuit (), sc->pin (), ids, partial_net_count);
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,353 @@
|
|||
|
||||
/*
|
||||
|
||||
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_dbLayoutToNetlistSoftConnections
|
||||
#define _HDR_dbLayoutToNetlistSoftConnections
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbPolygon.h"
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
class Net;
|
||||
class Pin;
|
||||
class Circuit;
|
||||
class Netlist;
|
||||
class SubCircuit;
|
||||
class LayoutToNetlist;
|
||||
|
||||
template <class T> class hier_clusters;
|
||||
template <class T> class connected_clusters;
|
||||
class NetShape;
|
||||
|
||||
/**
|
||||
* @brief A small struct representing a direction value for a pin
|
||||
*
|
||||
* The pin can be upward, downward connected, connected in both ways or not connected at all.
|
||||
*/
|
||||
class SoftConnectionPinDir
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs from a single direction (+1: up, -1: down)
|
||||
*/
|
||||
explicit SoftConnectionPinDir (int dir = 0)
|
||||
: m_flags (0)
|
||||
{
|
||||
if (dir > 0) {
|
||||
m_flags = 1;
|
||||
} else if (dir < 0) {
|
||||
m_flags = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Equality
|
||||
*/
|
||||
bool operator== (SoftConnectionPinDir other) const
|
||||
{
|
||||
return m_flags == other.m_flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inequality
|
||||
*/
|
||||
bool operator!= (SoftConnectionPinDir other) const
|
||||
{
|
||||
return m_flags != other.m_flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Join two value
|
||||
*/
|
||||
SoftConnectionPinDir operator| (SoftConnectionPinDir other) const
|
||||
{
|
||||
SoftConnectionPinDir res = *this;
|
||||
res.m_flags |= other.m_flags;
|
||||
return res;
|
||||
}
|
||||
|
||||
SoftConnectionPinDir &operator|= (SoftConnectionPinDir other)
|
||||
{
|
||||
m_flags |= other.m_flags;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test for one direction
|
||||
*/
|
||||
bool operator& (SoftConnectionPinDir other) const
|
||||
{
|
||||
return (m_flags & other.m_flags) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Static getters for the constants
|
||||
*/
|
||||
|
||||
inline static SoftConnectionPinDir none () { return SoftConnectionPinDir (0); }
|
||||
inline static SoftConnectionPinDir up () { return SoftConnectionPinDir (1); }
|
||||
inline static SoftConnectionPinDir down () { return SoftConnectionPinDir (-1); }
|
||||
inline static SoftConnectionPinDir both () { return up () | down (); }
|
||||
|
||||
private:
|
||||
unsigned int m_flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Describes a soft-connected net graph
|
||||
*
|
||||
* Such a graph is a collection of nets/shape clusters that are connected via
|
||||
* soft connections.
|
||||
* There is also some information about the count of "down-only" nets. With
|
||||
* this, this object can serve as a representative model for a circuit's
|
||||
* content as embedded into a larger graph through subcircuits.
|
||||
*
|
||||
* A circuit in general can be made from a number of such net graphs.
|
||||
*/
|
||||
class DB_PUBLIC SoftConnectionNetGraph
|
||||
{
|
||||
public:
|
||||
typedef std::set<size_t> pin_set;
|
||||
typedef pin_set::const_iterator pin_iterator;
|
||||
typedef std::map<size_t, SoftConnectionPinDir> dir_map;
|
||||
typedef dir_map::const_iterator dir_map_iterator;
|
||||
|
||||
SoftConnectionNetGraph ();
|
||||
|
||||
/**
|
||||
* @brief Enters information about a specific net
|
||||
*
|
||||
* @param net The Net for which we are entering information
|
||||
* @param dir The direction code of the net
|
||||
* @param pin A pin that might leading outside our current circuit from this net (0 if there is none)
|
||||
* @param partial_net_count The partial net count of nets attached to this net inside subcircuits
|
||||
*/
|
||||
void add (const db::Net *net, SoftConnectionPinDir dir, const db::Pin *pin, size_t partial_net_count);
|
||||
|
||||
/**
|
||||
* @brief Gets the partial net count
|
||||
*
|
||||
* The partial net count is the number of nets definitely isolated.
|
||||
* This is the count of "down-only" connected nets on the cluster.
|
||||
* This may also involve nets from subcircuits.
|
||||
* Only non-trivial (floating) nets are counted.
|
||||
*
|
||||
* A partial net count of more than one indicates a soft connection
|
||||
* between nets.
|
||||
*/
|
||||
size_t partial_net_count () const
|
||||
{
|
||||
return m_partial_net_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the outside pins on the net graph (begin iterator)
|
||||
*
|
||||
* The iterator delivers Pin IDs of pins leading outside the circuit this graph lives in.
|
||||
*/
|
||||
pin_iterator begin_pins () const
|
||||
{
|
||||
return m_pin_ids.begin ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the pins on the net graph (end iterator)
|
||||
*/
|
||||
pin_iterator end_pins () const
|
||||
{
|
||||
return m_pin_ids.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the shape clusters + dir information (begin iterator)
|
||||
*/
|
||||
dir_map_iterator begin_clusters () const
|
||||
{
|
||||
return m_cluster_dir.begin ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the shape clusters + dir information (end iterator)
|
||||
*/
|
||||
dir_map_iterator end_clusters () const
|
||||
{
|
||||
return m_cluster_dir.end ();
|
||||
}
|
||||
|
||||
private:
|
||||
pin_set m_pin_ids;
|
||||
size_t m_partial_net_count;
|
||||
dir_map m_cluster_dir;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Provides temporary soft connection information for a circuit
|
||||
*
|
||||
* Soft connection information is the soft-connected net graphs that are formed inside
|
||||
* the circuit and how these graphs connect to pins from the circuit leading outside.
|
||||
*/
|
||||
class DB_PUBLIC SoftConnectionCircuitInfo
|
||||
{
|
||||
public:
|
||||
typedef std::list<SoftConnectionNetGraph> net_graph_list;
|
||||
typedef net_graph_list::const_iterator net_graph_list_iterator;
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
SoftConnectionCircuitInfo (const db::Circuit *circuit);
|
||||
|
||||
/**
|
||||
* @brief Gets the circuit for this info object
|
||||
*/
|
||||
const db::Circuit *circuit () const
|
||||
{
|
||||
return mp_circuit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a new graph info object
|
||||
*/
|
||||
SoftConnectionNetGraph &make_net_graph ();
|
||||
|
||||
/**
|
||||
* @brief Adds information about a pin
|
||||
*
|
||||
* @param pin The pin
|
||||
* @param dir The direction of connections from the pin
|
||||
* @param graph_info The soft-connected net graph info object
|
||||
*/
|
||||
void add_pin_info (const db::Pin *pin, SoftConnectionPinDir dir, SoftConnectionNetGraph *graph_info);
|
||||
|
||||
/**
|
||||
* @brief Gets the direction attribute of the pin
|
||||
*/
|
||||
SoftConnectionPinDir direction_per_pin (const db::Pin *pin) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the soft-connected net graph object the pin connects to
|
||||
*/
|
||||
const SoftConnectionNetGraph *get_net_graph_per_pin (const db::Pin *pin) const;
|
||||
|
||||
/**
|
||||
* @brief List of per-circuit net graph objects, begin iterator
|
||||
*/
|
||||
net_graph_list_iterator begin () const
|
||||
{
|
||||
return m_net_graphs.begin ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief List of per-circuit net graph objects, end iterator
|
||||
*/
|
||||
net_graph_list_iterator end () const
|
||||
{
|
||||
return m_net_graphs.end ();
|
||||
}
|
||||
|
||||
private:
|
||||
const db::Circuit *mp_circuit;
|
||||
net_graph_list m_net_graphs;
|
||||
std::map<size_t, std::pair<SoftConnectionPinDir, const SoftConnectionNetGraph *> > m_pin_info;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Provides temporary soft connection information for a netlist
|
||||
*/
|
||||
class DB_PUBLIC SoftConnectionInfo
|
||||
{
|
||||
public:
|
||||
SoftConnectionInfo ();
|
||||
|
||||
/**
|
||||
* @brief Builds the soft connection information for the given netlist and shape clusters
|
||||
*/
|
||||
void build (const db::Netlist &netlist, const db::hier_clusters<db::NetShape> &shape_clusters);
|
||||
|
||||
/**
|
||||
* @brief Joins nets connected by soft connections
|
||||
*
|
||||
* This method will clear the information from this object
|
||||
* as the clusters will no longer be valid.
|
||||
*/
|
||||
void join_soft_connections (db::Netlist &netlist);
|
||||
|
||||
/**
|
||||
* @brief Create log entries
|
||||
*/
|
||||
void report (db::LayoutToNetlist &l2n);
|
||||
|
||||
private:
|
||||
std::map<const db::Circuit *, SoftConnectionCircuitInfo> m_scc_per_circuit;
|
||||
|
||||
/**
|
||||
* @brief Builds the per-circuit net graphs
|
||||
*
|
||||
* First of all, this method creates a SoftConnectionCircuitInfo object for the circuit.
|
||||
*
|
||||
* Inside this per-circuit object, it will create a number of SoftConnectionNetGraph objects - each one
|
||||
* for a cluster of soft-connected nets.
|
||||
*
|
||||
* Call this method bottom-up as it needs SoftConnectionCircuitInfo objects for called circuits.
|
||||
*/
|
||||
void build_graphs_for_circuit (const db::Circuit *circuit, const db::connected_clusters<db::NetShape> &shape_clusters);
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the given net connects to subcircuits with up or down connections inside
|
||||
*/
|
||||
bool net_has_up_or_down_subcircuit_connections (const db::Net *net, bool up);
|
||||
|
||||
/**
|
||||
* @brief Gets connections to other nets / shape clusters through the given subcircuit from the given pin
|
||||
*
|
||||
* As a side effect, this method will also collect the partial net count - that is the number
|
||||
* of defintively disconnected (down-only) nets.
|
||||
* More that one such a net will render an error.
|
||||
*/
|
||||
void get_net_connections_through_subcircuit (const db::SubCircuit *subcircuit, const db::Pin *pin, std::set<size_t> &ids, size_t &partial_net_count);
|
||||
|
||||
/**
|
||||
* @brief Gets connections to other nets / shape clusters through the subcircuits on the net
|
||||
*
|
||||
* As a side effect, this method will also collect the partial net count - that is the number
|
||||
* of defintively disconnected (down-only) nets.
|
||||
* More that one such a net will render an error.
|
||||
*
|
||||
* The return value is a set of nets shape cluster IDs.
|
||||
*/
|
||||
std::set<size_t> net_connections_through_subcircuits (const db::Net *net, size_t &partial_net_count);
|
||||
|
||||
void report_partial_nets (const db::Circuit *circuit, const SoftConnectionNetGraph &cluster_info, LayoutToNetlist &l2n, const std::string &path, const db::DCplxTrans &trans, const std::string &top_cell, int &index, std::set<std::pair<const db::Net *, db::DCplxTrans> > &seen);
|
||||
db::DPolygon representative_polygon (const db::Net *net, const db::LayoutToNetlist &l2n, const db::CplxTrans &trans);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -351,7 +351,7 @@ void std_writer_impl<Keys>::write (bool nested, TokenizedOutput &stream, std::ma
|
|||
if (! Keys::is_short ()) {
|
||||
stream << endl << "# Mask layers" << endl;
|
||||
}
|
||||
for (db::Connectivity::layer_iterator l = mp_l2n->connectivity ().begin_layers (); l != mp_l2n->connectivity ().end_layers (); ++l) {
|
||||
for (db::Connectivity::all_layer_iterator l = mp_l2n->connectivity ().begin_layers (); l != mp_l2n->connectivity ().end_layers (); ++l) {
|
||||
TokenizedOutput out (stream, Keys::layer_key);
|
||||
out << name_for_layer (mp_l2n, *l);
|
||||
db::LayerProperties lp = ly->get_properties (*l);
|
||||
|
|
@ -364,15 +364,32 @@ void std_writer_impl<Keys>::write (bool nested, TokenizedOutput &stream, std::ma
|
|||
if (! Keys::is_short ()) {
|
||||
stream << endl << "# Mask layer connectivity" << endl;
|
||||
}
|
||||
for (db::Connectivity::layer_iterator l = mp_l2n->connectivity ().begin_layers (); l != mp_l2n->connectivity ().end_layers (); ++l) {
|
||||
for (db::Connectivity::all_layer_iterator l = mp_l2n->connectivity ().begin_layers (); l != mp_l2n->connectivity ().end_layers (); ++l) {
|
||||
|
||||
db::Connectivity::layer_iterator ce = mp_l2n->connectivity ().end_connected (*l);
|
||||
db::Connectivity::layer_iterator cb = mp_l2n->connectivity ().begin_connected (*l);
|
||||
if (cb != ce) {
|
||||
TokenizedOutput out (stream, Keys::connect_key);
|
||||
out << name_for_layer (mp_l2n, *l);
|
||||
for (db::Connectivity::layer_iterator c = mp_l2n->connectivity ().begin_connected (*l); c != ce; ++c) {
|
||||
out << name_for_layer (mp_l2n, *c);
|
||||
bool any_soft = false;
|
||||
{
|
||||
TokenizedOutput out (stream, Keys::connect_key);
|
||||
out << name_for_layer (mp_l2n, *l);
|
||||
for (db::Connectivity::layer_iterator c = mp_l2n->connectivity ().begin_connected (*l); c != ce; ++c) {
|
||||
if (c->second < 0) {
|
||||
any_soft = true;
|
||||
}
|
||||
out << name_for_layer (mp_l2n, c->first);
|
||||
}
|
||||
}
|
||||
// add soft connections in addition and as overrides to stay backward compatible with older versions
|
||||
// (these will ignore these statements)
|
||||
if (any_soft) {
|
||||
TokenizedOutput out (stream, Keys::softconnect_key);
|
||||
out << name_for_layer (mp_l2n, *l);
|
||||
for (db::Connectivity::layer_iterator c = mp_l2n->connectivity ().begin_connected (*l); c != ce; ++c) {
|
||||
if (c->second < 0) {
|
||||
out << name_for_layer (mp_l2n, c->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_progress.set (mp_stream->pos ());
|
||||
}
|
||||
|
|
@ -380,7 +397,7 @@ void std_writer_impl<Keys>::write (bool nested, TokenizedOutput &stream, std::ma
|
|||
}
|
||||
|
||||
any = false;
|
||||
for (db::Connectivity::layer_iterator l = mp_l2n->connectivity ().begin_layers (); l != mp_l2n->connectivity ().end_layers (); ++l) {
|
||||
for (db::Connectivity::all_layer_iterator l = mp_l2n->connectivity ().begin_layers (); l != mp_l2n->connectivity ().end_layers (); ++l) {
|
||||
|
||||
db::Connectivity::global_nets_iterator ge = mp_l2n->connectivity ().end_global_connections (*l);
|
||||
db::Connectivity::global_nets_iterator gb = mp_l2n->connectivity ().begin_global_connections (*l);
|
||||
|
|
@ -391,10 +408,27 @@ void std_writer_impl<Keys>::write (bool nested, TokenizedOutput &stream, std::ma
|
|||
}
|
||||
any = true;
|
||||
}
|
||||
TokenizedOutput out (stream, Keys::global_key);
|
||||
out << name_for_layer (mp_l2n, *l);
|
||||
for (db::Connectivity::global_nets_iterator g = gb; g != ge; ++g) {
|
||||
out << tl::to_word_or_quoted_string (mp_l2n->connectivity ().global_net_name (*g));
|
||||
bool any_soft = false;
|
||||
{
|
||||
TokenizedOutput out (stream, Keys::global_key);
|
||||
out << name_for_layer (mp_l2n, *l);
|
||||
for (db::Connectivity::global_nets_iterator g = gb; g != ge; ++g) {
|
||||
if (g->second < 0) {
|
||||
any_soft = true;
|
||||
}
|
||||
out << tl::to_word_or_quoted_string (mp_l2n->connectivity ().global_net_name (g->first));
|
||||
}
|
||||
}
|
||||
// add soft connections in addition and as overrides to stay backward compatible with older versions
|
||||
// (these will ignore these statements)
|
||||
if (any_soft) {
|
||||
TokenizedOutput out (stream, Keys::softglobal_key);
|
||||
out << name_for_layer (mp_l2n, *l);
|
||||
for (db::Connectivity::global_nets_iterator g = gb; g != ge; ++g) {
|
||||
if (g->second < 0) {
|
||||
out << tl::to_word_or_quoted_string (mp_l2n->connectivity ().global_net_name (g->first));
|
||||
}
|
||||
}
|
||||
}
|
||||
m_progress.set (mp_stream->pos ());
|
||||
}
|
||||
|
|
@ -634,7 +668,7 @@ void std_writer_impl<Keys>::write (TokenizedOutput &stream, const db::Net &net,
|
|||
|
||||
reset_geometry_ref ();
|
||||
|
||||
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
|
||||
for (db::Connectivity::all_layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
|
||||
|
||||
db::cell_index_type cci = circuit->cell_index ();
|
||||
db::cell_index_type prev_ci = cci;
|
||||
|
|
@ -757,7 +791,7 @@ void std_writer_impl<Keys>::write (TokenizedOutput &stream, const db::DeviceAbst
|
|||
|
||||
bool any = false;
|
||||
|
||||
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
|
||||
for (db::Connectivity::all_layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
|
||||
|
||||
size_t cid = device_abstract.cluster_id_for_terminal (t->id ());
|
||||
if (cid == 0) {
|
||||
|
|
|
|||
|
|
@ -161,22 +161,33 @@ std::string
|
|||
LogEntryData::to_string (bool with_geometry) const
|
||||
{
|
||||
std::string res;
|
||||
const std::string &msg = message ();
|
||||
|
||||
if (m_category_name != 0) {
|
||||
if (m_category_description == 0) {
|
||||
res += "[" + category_name () + "] ";
|
||||
} else {
|
||||
res += "[" + category_description () + "] ";
|
||||
// a message that starts with a tab is a continuation or detail entry
|
||||
if (! msg.empty () && msg [0] == '\t') {
|
||||
|
||||
res = " ";
|
||||
res += std::string (msg, 1);
|
||||
|
||||
} else {
|
||||
|
||||
if (m_category_name != 0) {
|
||||
if (m_category_description == 0) {
|
||||
res += "[" + category_name () + "] ";
|
||||
} else {
|
||||
res += "[" + category_description () + "] ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_cell_name != 0) {
|
||||
res += tl::to_string (tr ("In cell "));
|
||||
res += cell_name ();
|
||||
res += ": ";
|
||||
}
|
||||
if (m_cell_name != 0) {
|
||||
res += tl::to_string (tr ("In cell "));
|
||||
res += cell_name ();
|
||||
res += ": ";
|
||||
}
|
||||
|
||||
res += message ();
|
||||
res += msg;
|
||||
|
||||
}
|
||||
|
||||
if (with_geometry && ! m_geometry.box ().empty ()) {
|
||||
res += tl::to_string (tr (", shape: ")) + m_geometry.to_string ();
|
||||
|
|
|
|||
|
|
@ -288,7 +288,9 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
|
||||
const db::local_cluster<db::NetShape> &lc = clusters.cluster_by_id (*c);
|
||||
const connected_clusters_type::connections_type &cc = clusters.connections_for_cluster (*c);
|
||||
if (cc.empty () && lc.empty ()) {
|
||||
const std::set<size_t> &sc_up = clusters.upward_soft_connections (*c);
|
||||
const std::set<size_t> &sc_down = clusters.downward_soft_connections (*c);
|
||||
if (cc.empty () && sc_up.empty () && sc_down.empty () && lc.empty ()) {
|
||||
// this is an entirely empty cluster so we skip it.
|
||||
// Such clusters are left over when joining clusters.
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -26,22 +26,106 @@
|
|||
namespace gsi
|
||||
{
|
||||
|
||||
static std::string
|
||||
l2s (db::Connectivity::layer_iterator b, db::Connectivity::layer_iterator e)
|
||||
{
|
||||
std::string s;
|
||||
for (db::Connectivity::layer_iterator i = b; i != e; ++i) {
|
||||
if (! s.empty ()) {
|
||||
s += ",";
|
||||
}
|
||||
s += tl::to_string (i->first);
|
||||
if (i->second < 0) {
|
||||
s += "-S";
|
||||
} else if (i->second > 0) {
|
||||
s += "+S";
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static std::string
|
||||
gn2s (db::Connectivity::global_nets_iterator b, db::Connectivity::global_nets_iterator e)
|
||||
{
|
||||
std::string s;
|
||||
for (db::Connectivity::global_nets_iterator i = b; i != e; ++i) {
|
||||
if (! s.empty ()) {
|
||||
s += ",";
|
||||
}
|
||||
s += tl::to_string (i->first);
|
||||
if (i->second < 0) {
|
||||
s += "-S";
|
||||
} else if (i->second > 0) {
|
||||
s += "+S";
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static std::string
|
||||
connectivity_to_string (const db::Connectivity *conn)
|
||||
{
|
||||
std::string res;
|
||||
|
||||
for (auto l = conn->begin_layers (); l != conn->end_layers (); ++l) {
|
||||
if (conn->begin_connected (*l) != conn->end_connected (*l)) {
|
||||
if (! res.empty ()) {
|
||||
res += "\n";
|
||||
}
|
||||
res += tl::to_string (*l) + ":" + l2s (conn->begin_connected (*l), conn->end_connected (*l));
|
||||
}
|
||||
if (conn->begin_global_connections (*l) != conn->end_global_connections (*l)) {
|
||||
if (! res.empty ()) {
|
||||
res += "\n";
|
||||
}
|
||||
res += "G" + tl::to_string (*l) + ":" + gn2s (conn->begin_global_connections (*l), conn->end_global_connections (*l));
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Class<db::Connectivity> decl_dbConnectivity ("db", "Connectivity",
|
||||
gsi::method ("connect", (void (db::Connectivity::*) (unsigned int)) &db::Connectivity::connect, gsi::arg ("layer"),
|
||||
"@brief Specifies intra-layer connectivity.\n"
|
||||
"This method specifies a hard connection between shapes on the given layer. "
|
||||
"Without specifying such a connection, shapes on that layer do not form connection regions."
|
||||
) +
|
||||
gsi::method ("connect", (void (db::Connectivity::*) (unsigned int, unsigned int)) &db::Connectivity::connect, gsi::arg ("layer_a"), gsi::arg ("layer_b"),
|
||||
"@brief Specifies inter-layer connectivity.\n"
|
||||
"This method specifies a hard connection between shapes on layer_a and layer_b."
|
||||
) +
|
||||
gsi::method ("soft_connect", (void (db::Connectivity::*) (unsigned int, unsigned int)) &db::Connectivity::soft_connect, gsi::arg ("layer_a"), gsi::arg ("layer_b"),
|
||||
"@brief Specifies a soft connection between layer_a and layer_b.\n"
|
||||
"@param layer_a The 'upper' layer\n"
|
||||
"@param layer_b The 'lower' layer\n"
|
||||
"Soft connections are made between a lower and an upper layer. The lower layer conceptually is a high-ohmic "
|
||||
"(i.e. substrate, diffusion) region that is not intended for signal wiring. The netlist extraction will check "
|
||||
"that no routing happens over such regions.\n"
|
||||
"\n"
|
||||
"Soft connections have in introduced in version 0.29."
|
||||
) +
|
||||
gsi::method ("connect_global", (size_t (db::Connectivity::*) (unsigned int, const std::string &)) &db::Connectivity::connect_global, gsi::arg ("layer"), gsi::arg ("global_net_name"),
|
||||
"@brief Connects the given layer to the global net given by name.\n"
|
||||
"Returns the ID of the global net."
|
||||
) +
|
||||
gsi::method ("soft_connect_global", (size_t (db::Connectivity::*) (unsigned int, const std::string &)) &db::Connectivity::soft_connect_global, gsi::arg ("layer"), gsi::arg ("global_net_name"),
|
||||
"@brief Soft-connects the given layer to the global net given by name.\n"
|
||||
"Returns the ID of the global net.\n"
|
||||
"See \\soft_connect for a description of the soft connection feature. The global net is always the "
|
||||
"'lower' (i.e. high-ohmic, substrate) part of the soft connection.\n"
|
||||
"\n"
|
||||
"Soft connections have in introduced in version 0.29."
|
||||
) +
|
||||
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"
|
||||
) +
|
||||
// provided for testing purposes mainly.
|
||||
gsi::method_ext ("to_s", &connectivity_to_string,
|
||||
"@hide\n"
|
||||
),
|
||||
"@brief This class specifies connections between different layers.\n"
|
||||
"Connections are build using \\connect. There are basically two flavours of connections: intra-layer and inter-layer.\n"
|
||||
|
|
@ -60,6 +144,10 @@ Class<db::Connectivity> decl_dbConnectivity ("db", "Connectivity",
|
|||
"Global nets are defined by name and are managed through IDs. To get the name for a given ID, use "
|
||||
"\\global_net_name."
|
||||
"\n"
|
||||
"Starting with version 0.29, soft connections are supported. Soft connections attach to high-ohmic substrate or diffusion "
|
||||
"layers (the 'lower' layer) are upon netlist extraction it will be checked that no wiring is routed over such connections. "
|
||||
"See \\soft_connect and \\soft_global_connect for details.\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.26.\n"
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -433,6 +433,32 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
"\n"
|
||||
"This variant has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method ("soft_connect", (void (db::LayoutToNetlist::*) (const db::Region &, const db::Region &)) &db::LayoutToNetlist::soft_connect, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief Defines an inter-layer connection for the given layers in soft mode.\n"
|
||||
"Connects two layers through a soft connection.\n"
|
||||
"Soft connections cannot make connections between two different nets.\n"
|
||||
"These are directional connections where 'b' is the 'lower' layer (typically high-ohmic substrate or diffusion).\n"
|
||||
"\n"
|
||||
"Soft connections have been introduced in version 0.29.\n"
|
||||
) +
|
||||
gsi::method ("soft_connect", (void (db::LayoutToNetlist::*) (const db::Region &, const db::Texts &)) &db::LayoutToNetlist::soft_connect, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief Defines an inter-layer connection for the given layers in soft mode.\n"
|
||||
"Connects two layers through a soft connection.\n"
|
||||
"Soft connections cannot make connections between two different nets.\n"
|
||||
"These are directional connections where 'b' is the 'lower' layer (typically high-ohmic substrate or diffusion).\n"
|
||||
"As one argument is a (hierarchical) text collection, this method is used to attach net labels to polygons.\n"
|
||||
"\n"
|
||||
"Soft connections have been introduced in version 0.29.\n"
|
||||
) +
|
||||
gsi::method ("soft_connect", (void (db::LayoutToNetlist::*) (const db::Texts &, const db::Region &)) &db::LayoutToNetlist::soft_connect, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief Defines an inter-layer connection for the given layers in soft mode.\n"
|
||||
"Connects two layers through a soft connection.\n"
|
||||
"Soft connections cannot make connections between two different nets.\n"
|
||||
"These are directional connections where 'b' is the 'lower' layer (typically high-ohmic substrate or diffusion).\n"
|
||||
"As one argument is a (hierarchical) text collection, this method is used to attach net labels to polygons.\n"
|
||||
"\n"
|
||||
"Soft connections have been introduced in version 0.29.\n"
|
||||
) +
|
||||
gsi::method ("connect_global", (size_t (db::LayoutToNetlist::*) (const db::Region &, const std::string &)) &db::LayoutToNetlist::connect_global, gsi::arg ("l"), gsi::arg ("global_net_name"),
|
||||
"@brief Defines a connection of the given layer with a global net.\n"
|
||||
"This method returns the ID of the global net. Use \\global_net_name to get "
|
||||
|
|
@ -441,10 +467,26 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
gsi::method ("connect_global", (size_t (db::LayoutToNetlist::*) (const db::Texts &, const std::string &)) &db::LayoutToNetlist::connect_global, gsi::arg ("l"), gsi::arg ("global_net_name"),
|
||||
"@brief Defines a connection of the given text layer with a global net.\n"
|
||||
"This method returns the ID of the global net. Use \\global_net_name to get "
|
||||
"the name back from the ID."
|
||||
"the name back from the ID.\n"
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method ("soft_connect_global", (size_t (db::LayoutToNetlist::*) (const db::Region &, const std::string &)) &db::LayoutToNetlist::soft_connect_global, gsi::arg ("l"), gsi::arg ("global_net_name"),
|
||||
"@brief Defines a connection of the given layer with a global net in soft mode.\n"
|
||||
"This method returns the ID of the global net. Use \\global_net_name to get "
|
||||
"the name back from the ID.\n"
|
||||
"Soft connections are directional, where the global net is the 'lower' layer (typically high-ohmic substrate or diffusion).\n"
|
||||
"\n"
|
||||
"Soft connections have been introduced in version 0.29.\n"
|
||||
) +
|
||||
gsi::method ("soft_connect_global", (size_t (db::LayoutToNetlist::*) (const db::Texts &, const std::string &)) &db::LayoutToNetlist::soft_connect_global, gsi::arg ("l"), gsi::arg ("global_net_name"),
|
||||
"@brief Defines a connection of the given text layer with a global net in soft mode.\n"
|
||||
"This method returns the ID of the global net. Use \\global_net_name to get "
|
||||
"the name back from the ID.\n"
|
||||
"Soft connections are directional, where the global net is the 'lower' layer (typically high-ohmic substrate or diffusion).\n"
|
||||
"\n"
|
||||
"Soft connections have been introduced in version 0.29.\n"
|
||||
) +
|
||||
gsi::method ("global_net_name", &db::LayoutToNetlist::global_net_name, gsi::arg ("global_net_id"),
|
||||
"@brief Gets the global net name for the given global net ID."
|
||||
) +
|
||||
|
|
@ -464,6 +506,12 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
"\n"
|
||||
"This attribute has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method ("make_soft_connection_diodes=", &db::LayoutToNetlist::set_make_soft_connection_diodes, gsi::arg ("flag"),
|
||||
"@hide"
|
||||
) +
|
||||
gsi::method ("make_soft_connection_diodes", &db::LayoutToNetlist::make_soft_connection_diodes,
|
||||
"@hide"
|
||||
) +
|
||||
gsi::method ("top_level_mode=", &db::LayoutToNetlist::set_top_level_mode, gsi::arg ("flag"),
|
||||
"@brief Sets a flag indicating whether top level mode is enabled.\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -36,6 +36,23 @@ static std::string l2s (db::Connectivity::layer_iterator b, db::Connectivity::la
|
|||
{
|
||||
std::string s;
|
||||
for (db::Connectivity::layer_iterator i = b; i != e; ++i) {
|
||||
if (! s.empty ()) {
|
||||
s += ",";
|
||||
}
|
||||
s += tl::to_string (i->first);
|
||||
if (i->second < 0) {
|
||||
s += "-S";
|
||||
} else if (i->second > 0) {
|
||||
s += "+S";
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static std::string al2s (db::Connectivity::all_layer_iterator b, db::Connectivity::all_layer_iterator e)
|
||||
{
|
||||
std::string s;
|
||||
for (db::Connectivity::all_layer_iterator i = b; i != e; ++i) {
|
||||
if (! s.empty ()) {
|
||||
s += ",";
|
||||
}
|
||||
|
|
@ -51,7 +68,12 @@ static std::string gn2s (db::Connectivity::global_nets_iterator b, db::Connectiv
|
|||
if (! s.empty ()) {
|
||||
s += ",";
|
||||
}
|
||||
s += tl::to_string (*i);
|
||||
s += tl::to_string (i->first);
|
||||
if (i->second < 0) {
|
||||
s += "-S";
|
||||
} else if (i->second > 0) {
|
||||
s += "+S";
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
|
@ -60,15 +82,15 @@ TEST(1_Connectivity)
|
|||
{
|
||||
db::Connectivity conn;
|
||||
|
||||
EXPECT_EQ (l2s (conn.begin_layers (), conn.end_layers ()), "");
|
||||
EXPECT_EQ (al2s (conn.begin_layers (), conn.end_layers ()), "");
|
||||
|
||||
conn.connect (0);
|
||||
EXPECT_EQ (l2s (conn.begin_layers (), conn.end_layers ()), "0");
|
||||
EXPECT_EQ (al2s (conn.begin_layers (), conn.end_layers ()), "0");
|
||||
EXPECT_EQ (l2s (conn.begin_connected (0), conn.end_connected (0)), "0");
|
||||
EXPECT_EQ (l2s (conn.begin_connected (1), conn.end_connected (1)), "");
|
||||
|
||||
conn.connect (0, 1);
|
||||
EXPECT_EQ (l2s (conn.begin_layers (), conn.end_layers ()), "0,1");
|
||||
EXPECT_EQ (al2s (conn.begin_layers (), conn.end_layers ()), "0,1");
|
||||
EXPECT_EQ (l2s (conn.begin_connected (0), conn.end_connected (0)), "0,1");
|
||||
EXPECT_EQ (l2s (conn.begin_connected (1), conn.end_connected (1)), "0");
|
||||
|
||||
|
|
@ -104,6 +126,60 @@ TEST(1_Connectivity)
|
|||
EXPECT_EQ (conn2.global_net_name (1), "GLOBAL2");
|
||||
}
|
||||
|
||||
TEST(1_ConnectivitySoft)
|
||||
{
|
||||
db::Connectivity conn;
|
||||
|
||||
EXPECT_EQ (al2s (conn.begin_layers (), conn.end_layers ()), "");
|
||||
|
||||
conn.connect (0);
|
||||
EXPECT_EQ (al2s (conn.begin_layers (), conn.end_layers ()), "0");
|
||||
EXPECT_EQ (l2s (conn.begin_connected (0), conn.end_connected (0)), "0");
|
||||
EXPECT_EQ (l2s (conn.begin_connected (1), conn.end_connected (1)), "");
|
||||
|
||||
conn.soft_connect (0, 1);
|
||||
EXPECT_EQ (al2s (conn.begin_layers (), conn.end_layers ()), "0,1");
|
||||
EXPECT_EQ (l2s (conn.begin_connected (0), conn.end_connected (0)), "0,1-S");
|
||||
EXPECT_EQ (l2s (conn.begin_connected (1), conn.end_connected (1)), "0+S");
|
||||
|
||||
conn.connect (1);
|
||||
EXPECT_EQ (l2s (conn.begin_connected (1), conn.end_connected (1)), "0+S,1");
|
||||
|
||||
conn.soft_connect (2, 0);
|
||||
conn.connect (2);
|
||||
|
||||
EXPECT_EQ (l2s (conn.begin_connected (0), conn.end_connected (0)), "0,1-S,2+S");
|
||||
EXPECT_EQ (l2s (conn.begin_connected (1), conn.end_connected (1)), "0+S,1");
|
||||
EXPECT_EQ (l2s (conn.begin_connected (2), conn.end_connected (2)), "0-S,2");
|
||||
|
||||
conn.connect (2, 0);
|
||||
|
||||
EXPECT_EQ (l2s (conn.begin_connected (0), conn.end_connected (0)), "0,1-S,2");
|
||||
EXPECT_EQ (l2s (conn.begin_connected (1), conn.end_connected (1)), "0+S,1");
|
||||
EXPECT_EQ (l2s (conn.begin_connected (2), conn.end_connected (2)), "0,2");
|
||||
|
||||
EXPECT_EQ (conn.soft_connect_global (0, "GLOBAL"), size_t (0));
|
||||
EXPECT_EQ (gn2s (conn.begin_global_connections (2), conn.end_global_connections (2)), "");
|
||||
EXPECT_EQ (gn2s (conn.begin_global_connections (0), conn.end_global_connections (0)), "0-S");
|
||||
EXPECT_EQ (conn.soft_connect_global (2, "GLOBAL2"), size_t (1));
|
||||
EXPECT_EQ (gn2s (conn.begin_global_connections (2), conn.end_global_connections (2)), "1-S");
|
||||
EXPECT_EQ (conn.connect_global (0, "GLOBAL2"), size_t (1));
|
||||
EXPECT_EQ (gn2s (conn.begin_global_connections (0), conn.end_global_connections (0)), "0-S,1");
|
||||
|
||||
EXPECT_EQ (conn.global_net_name (0), "GLOBAL");
|
||||
EXPECT_EQ (conn.global_net_name (1), "GLOBAL2");
|
||||
|
||||
db::Connectivity conn2 = conn;
|
||||
|
||||
EXPECT_EQ (l2s (conn2.begin_connected (0), conn2.end_connected (0)), "0,1-S,2");
|
||||
EXPECT_EQ (l2s (conn2.begin_connected (1), conn2.end_connected (1)), "0+S,1");
|
||||
EXPECT_EQ (l2s (conn2.begin_connected (2), conn2.end_connected (2)), "0,2");
|
||||
|
||||
EXPECT_EQ (gn2s (conn2.begin_global_connections (0), conn2.end_global_connections (0)), "0-S,1");
|
||||
EXPECT_EQ (conn2.global_net_name (0), "GLOBAL");
|
||||
EXPECT_EQ (conn2.global_net_name (1), "GLOBAL2");
|
||||
}
|
||||
|
||||
TEST(2_ShapeInteractions)
|
||||
{
|
||||
db::Connectivity conn;
|
||||
|
|
@ -121,18 +197,19 @@ TEST(2_ShapeInteractions)
|
|||
db::ICplxTrans t3 (db::Trans (db::Vector (0, 2000)));
|
||||
db::PolygonRef ref3 (poly.transformed (t3), repo);
|
||||
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref2, 0), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t2), true); // t2*ref1 == ref2
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref2, 1), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t2), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 1, ref2, 0), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 1, ref1, 0, t2), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref3, 0), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t3), false); // t3*ref1 == ref3
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref3, 1), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t3), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 1, ref2, 2), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 1, ref1, 2, t2), false);
|
||||
int soft = std::numeric_limits<int>::max ();
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref2, 0, soft), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t2, soft), true); // t2*ref1 == ref2
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref2, 1, soft), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t2, soft), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 1, ref2, 0, soft), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 1, ref1, 0, t2, soft), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref3, 0, soft), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t3, soft), false); // t3*ref1 == ref3
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref3, 1, soft), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t3, soft), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 1, ref2, 2, soft), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 1, ref1, 2, t2, soft), false);
|
||||
}
|
||||
|
||||
TEST(2_ShapeInteractionsRealPolygon)
|
||||
|
|
@ -154,20 +231,21 @@ TEST(2_ShapeInteractionsRealPolygon)
|
|||
db::ICplxTrans t4 (db::Trans (db::Vector (0, 1500)));
|
||||
db::PolygonRef ref4 (poly.transformed (t4), repo);
|
||||
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref2, 0), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t2), true); // t2*ref1 == ref2
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref2, 1), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t2), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 1, ref2, 0), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 1, ref1, 0, t2), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref3, 0), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t3), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref4, 0), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t4), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref3, 1), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t3), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 1, ref2, 2), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 1, ref1, 2, t2), false);
|
||||
int soft = std::numeric_limits<int>::max ();
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref2, 0, soft), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t2, soft), true); // t2*ref1 == ref2
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref2, 1, soft), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t2, soft), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 1, ref2, 0, soft), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 1, ref1, 0, t2, soft), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref3, 0, soft), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t3, soft), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref4, 0, soft), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t4, soft), true);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref3, 1, soft), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t3, soft), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 1, ref2, 2, soft), false);
|
||||
EXPECT_EQ (conn.interacts (ref1, 1, ref1, 2, t2, soft), false);
|
||||
}
|
||||
|
||||
TEST(10_LocalClusterBasic)
|
||||
|
|
@ -215,21 +293,22 @@ TEST(11_LocalClusterInteractBasic)
|
|||
|
||||
db::local_cluster<db::PolygonRef> cluster;
|
||||
db::local_cluster<db::PolygonRef> cluster2;
|
||||
int soft;
|
||||
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn), false);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn, soft), false);
|
||||
|
||||
cluster.add (db::PolygonRef (poly, repo), 0);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn), false);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn, soft), false);
|
||||
|
||||
cluster2.add (db::PolygonRef (poly, repo), 0);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn), true);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (db::Trans (db::Vector (10, 20))), conn), true);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (db::Trans (db::Vector (0, 1000))), conn), true);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (db::Trans (db::Vector (0, 1001))), conn), false);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (db::Trans (db::Vector (0, 2000))), conn), false);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn, soft), true);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (db::Trans (db::Vector (10, 20))), conn, soft), true);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (db::Trans (db::Vector (0, 1000))), conn, soft), true);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (db::Trans (db::Vector (0, 1001))), conn, soft), false);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (db::Trans (db::Vector (0, 2000))), conn, soft), false);
|
||||
|
||||
cluster.clear ();
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn), false);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn, soft), false);
|
||||
}
|
||||
|
||||
TEST(11_LocalClusterInteractDifferentLayers)
|
||||
|
|
@ -248,28 +327,29 @@ TEST(11_LocalClusterInteractDifferentLayers)
|
|||
|
||||
db::local_cluster<db::PolygonRef> cluster;
|
||||
db::local_cluster<db::PolygonRef> cluster2;
|
||||
int soft;
|
||||
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn), false);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn, soft), false);
|
||||
|
||||
cluster.add (db::PolygonRef (poly, repo), 0);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn), false);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn, soft), false);
|
||||
|
||||
cluster2.add (db::PolygonRef (poly, repo), 1);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn), true);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (db::Trans (db::Vector (10, 20))), conn), true);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (db::Trans (db::Vector (0, 1000))), conn), true);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (db::Trans (db::Vector (0, 1001))), conn), false);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (db::Trans (db::Vector (0, 2000))), conn), false);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn, soft), true);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (db::Trans (db::Vector (10, 20))), conn, soft), true);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (db::Trans (db::Vector (0, 1000))), conn, soft), true);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (db::Trans (db::Vector (0, 1001))), conn, soft), false);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (db::Trans (db::Vector (0, 2000))), conn, soft), false);
|
||||
|
||||
cluster.clear ();
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn), false);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn, soft), false);
|
||||
cluster.add (db::PolygonRef (poly, repo), 2);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn), false); // not connected
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn, soft), false); // not connected
|
||||
|
||||
cluster.clear ();
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn), false);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn, soft), false);
|
||||
cluster.add (db::PolygonRef (poly, repo), 1);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn), true);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn, soft), true);
|
||||
}
|
||||
|
||||
static std::string obj2string (const db::PolygonRef &ref)
|
||||
|
|
@ -286,7 +366,7 @@ template <class T>
|
|||
static std::string local_cluster_to_string (const db::local_cluster<T> &cluster, const db::Connectivity &conn)
|
||||
{
|
||||
std::string res;
|
||||
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
|
||||
for (db::Connectivity::all_layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
|
||||
for (typename db::local_cluster<T>::shape_iterator s = cluster.begin (*l); ! s.at_end (); ++s) {
|
||||
if (! res.empty ()) {
|
||||
res += ";";
|
||||
|
|
@ -313,6 +393,15 @@ static std::string local_clusters_to_string (const db::local_clusters<T> &cluste
|
|||
}
|
||||
s += "#" + tl::to_string (c->id ()) + ":" + local_cluster_to_string (*c, conn);
|
||||
}
|
||||
for (typename db::local_clusters<T>::const_iterator c = clusters.begin (); c != clusters.end (); ++c) {
|
||||
auto sc = clusters.upward_soft_connections (c->id ());
|
||||
for (auto i = sc.begin (); i != sc.end (); ++i) {
|
||||
if (! s.empty ()) {
|
||||
s += "\n";
|
||||
}
|
||||
s += "(#" + tl::to_string (*i) + "->#" + tl::to_string (c->id ()) + ")";
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
@ -590,6 +679,90 @@ TEST(23_LocalClustersWithEdges)
|
|||
}
|
||||
}
|
||||
|
||||
TEST(24_LocalClustersWithSoftConnections)
|
||||
{
|
||||
db::Layout layout;
|
||||
db::Cell &cell = layout.cell (layout.add_cell ("TOP"));
|
||||
db::GenericRepository &repo = layout.shape_repository ();
|
||||
|
||||
auto dbu = db::CplxTrans (layout.dbu ()).inverted ();
|
||||
|
||||
unsigned int nwell = 0;
|
||||
unsigned int ntie = 1;
|
||||
unsigned int ptie = 2;
|
||||
unsigned int contact = 3;
|
||||
unsigned int metal1 = 4;
|
||||
|
||||
cell.shapes (nwell).insert (db::PolygonRef (dbu * db::DPolygon (db::DBox (0.0, 4.0, 2.0, 8.0)), repo));
|
||||
cell.shapes (ntie).insert (db::PolygonRef (dbu * db::DPolygon (db::DBox (0.5, 5.0, 1.5, 7.0)), repo));
|
||||
cell.shapes (contact).insert (db::PolygonRef (dbu * db::DPolygon (db::DBox (0.8, 6.0, 1.2, 6.5)), repo));
|
||||
cell.shapes (metal1).insert (db::PolygonRef (dbu * db::DPolygon (db::DBox (0.0, 5.0, 2.0, 7.0)), repo));
|
||||
|
||||
cell.shapes (ptie).insert (db::PolygonRef (dbu * db::DPolygon (db::DBox (0.5, 1.0, 1.5, 3.0)), repo));
|
||||
cell.shapes (contact).insert (db::PolygonRef (dbu * db::DPolygon (db::DBox (0.8, 2.0, 1.2, 2.5)), repo));
|
||||
cell.shapes (metal1).insert (db::PolygonRef (dbu * db::DPolygon (db::DBox (0.0, 1.0, 2.0, 3.0)), repo));
|
||||
|
||||
db::Connectivity conn;
|
||||
conn.connect (nwell);
|
||||
conn.connect (ntie);
|
||||
conn.connect (ptie);
|
||||
conn.connect (contact);
|
||||
conn.connect (metal1);
|
||||
conn.soft_connect (ntie, nwell);
|
||||
conn.soft_connect (contact, ntie);
|
||||
conn.connect (metal1, contact);
|
||||
|
||||
{
|
||||
db::local_clusters<db::PolygonRef> clusters;
|
||||
clusters.build_clusters (cell, conn);
|
||||
EXPECT_EQ (local_clusters_to_string (clusters, conn),
|
||||
"#1:[0](0,4000;0,8000;2000,8000;2000,4000)\n"
|
||||
"#2:[1](500,5000;500,7000;1500,7000;1500,5000)\n"
|
||||
"#3:[3](800,6000;800,6500;1200,6500;1200,6000);[4](0,5000;0,7000;2000,7000;2000,5000)\n"
|
||||
"#4:[3](800,2000;800,2500;1200,2500;1200,2000);[4](0,1000;0,3000;2000,3000;2000,1000)\n"
|
||||
"#5:[2](500,1000;500,3000;1500,3000;1500,1000)\n"
|
||||
"(#2->#1)\n"
|
||||
"(#3->#2)"
|
||||
);
|
||||
}
|
||||
|
||||
conn.soft_connect (contact, ptie);
|
||||
|
||||
{
|
||||
db::local_clusters<db::PolygonRef> clusters;
|
||||
clusters.build_clusters (cell, conn);
|
||||
EXPECT_EQ (local_clusters_to_string (clusters, conn),
|
||||
"#1:[0](0,4000;0,8000;2000,8000;2000,4000)\n"
|
||||
"#2:[1](500,5000;500,7000;1500,7000;1500,5000)\n"
|
||||
"#3:[3](800,6000;800,6500;1200,6500;1200,6000);[4](0,5000;0,7000;2000,7000;2000,5000)\n"
|
||||
"#4:[2](500,1000;500,3000;1500,3000;1500,1000)\n"
|
||||
"#5:[3](800,2000;800,2500;1200,2500;1200,2000);[4](0,1000;0,3000;2000,3000;2000,1000)\n"
|
||||
"(#2->#1)\n"
|
||||
"(#3->#2)\n"
|
||||
"(#5->#4)"
|
||||
);
|
||||
}
|
||||
|
||||
conn.soft_connect_global (ptie, "BULK");
|
||||
|
||||
{
|
||||
db::local_clusters<db::PolygonRef> clusters;
|
||||
clusters.build_clusters (cell, conn);
|
||||
EXPECT_EQ (local_clusters_to_string (clusters, conn),
|
||||
"#1:[0](0,4000;0,8000;2000,8000;2000,4000)\n"
|
||||
"#2:[1](500,5000;500,7000;1500,7000;1500,5000)\n"
|
||||
"#3:[3](800,6000;800,6500;1200,6500;1200,6000);[4](0,5000;0,7000;2000,7000;2000,5000)\n"
|
||||
"#4:[2](500,1000;500,3000;1500,3000;1500,1000)\n"
|
||||
"#5:[3](800,2000;800,2500;1200,2500;1200,2000);[4](0,1000;0,3000;2000,3000;2000,1000)\n"
|
||||
"#6:+BULK\n"
|
||||
"(#2->#1)\n"
|
||||
"(#3->#2)\n"
|
||||
"(#5->#4)\n"
|
||||
"(#4->#6)"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(30_LocalConnectedClusters)
|
||||
{
|
||||
db::Layout layout;
|
||||
|
|
@ -920,7 +1093,7 @@ static void copy_cluster_shapes (const std::string *&attrs, db::Shapes &out, db:
|
|||
const db::local_cluster<db::PolygonRef> &lc = clusters.cluster_by_id (cluster_id);
|
||||
|
||||
// copy the shapes from this cell
|
||||
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
|
||||
for (db::Connectivity::all_layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
|
||||
for (db::local_cluster<db::PolygonRef>::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) {
|
||||
db::Polygon poly = s->obj ().transformed (trans * db::ICplxTrans (s->trans ()));
|
||||
out.insert (db::PolygonWithProperties (poly, cell_and_attr_pid > 0 ? cell_and_attr_pid : cell_pid));
|
||||
|
|
|
|||
|
|
@ -101,6 +101,11 @@ static void dump_nets_to_layout (const db::Netlist &nl, const db::hier_clusters<
|
|||
for (db::Net::const_terminal_iterator t = n->begin_terminals (); t != n->end_terminals (); ++t) {
|
||||
|
||||
const db::NetTerminalRef &tref = *t;
|
||||
|
||||
if (! tref.device ()->device_abstract ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
db::cell_index_type dci = tref.device ()->device_abstract ()->cell_index ();
|
||||
db::DCplxTrans dtr = tref.device ()->trans ();
|
||||
|
||||
|
|
@ -121,6 +126,10 @@ static void dump_nets_to_layout (const db::Netlist &nl, const db::hier_clusters<
|
|||
|
||||
for (db::Circuit::const_device_iterator d = c->begin_devices (); d != c->end_devices (); ++d) {
|
||||
|
||||
if (! d->device_abstract ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<db::cell_index_type> original_device_cells;
|
||||
|
||||
db::cell_index_type dci = d->device_abstract ()->cell_index ();
|
||||
|
|
@ -3176,6 +3185,334 @@ TEST(14_JoinNets)
|
|||
db::compare_layouts (_this, ly, au);
|
||||
}
|
||||
|
||||
static
|
||||
void annotate_soft_connections (db::Netlist &netlist, const db::hier_clusters<db::NetShape> &net_clusters)
|
||||
{
|
||||
db::DeviceClassDiode *soft_diode = new db::DeviceClassDiode ();
|
||||
soft_diode->set_name ("SOFT");
|
||||
netlist.add_device_class (soft_diode);
|
||||
|
||||
for (auto c = netlist.begin_bottom_up (); c != netlist.end_bottom_up (); ++c) {
|
||||
|
||||
auto clusters = net_clusters.clusters_per_cell (c->cell_index ());
|
||||
|
||||
for (auto n = c->begin_nets (); n != c->end_nets (); ++n) {
|
||||
|
||||
auto soft_connections = clusters.upward_soft_connections (n->cluster_id ());
|
||||
for (auto sc = soft_connections.begin (); sc != soft_connections.end (); ++sc) {
|
||||
|
||||
db::Device *sc_device = new db::Device (soft_diode);
|
||||
c->add_device (sc_device);
|
||||
|
||||
auto nn = c->net_by_cluster_id (*sc);
|
||||
if (nn) {
|
||||
sc_device->connect_terminal (db::DeviceClassDiode::terminal_id_C, n.operator-> ());
|
||||
sc_device->connect_terminal (db::DeviceClassDiode::terminal_id_A, nn);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
TEST(15_SoftConnections)
|
||||
{
|
||||
db::Layout ly;
|
||||
db::LayerMap lmap;
|
||||
|
||||
unsigned int nwell = define_layer (ly, lmap, 1);
|
||||
unsigned int diff = define_layer (ly, lmap, 2);
|
||||
unsigned int pplus = define_layer (ly, lmap, 3);
|
||||
unsigned int nplus = define_layer (ly, lmap, 4);
|
||||
unsigned int poly = define_layer (ly, lmap, 5);
|
||||
unsigned int contact = define_layer (ly, lmap, 8);
|
||||
unsigned int metal1 = define_layer (ly, lmap, 9);
|
||||
unsigned int via1 = define_layer (ly, lmap, 10);
|
||||
unsigned int metal2 = define_layer (ly, lmap, 11);
|
||||
|
||||
{
|
||||
db::LoadLayoutOptions options;
|
||||
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
|
||||
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
|
||||
|
||||
std::string fn (tl::testdata ());
|
||||
fn = tl::combine_path (fn, "algo");
|
||||
fn = tl::combine_path (fn, "soft_connections.gds");
|
||||
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly, options);
|
||||
}
|
||||
|
||||
db::Cell &tc = ly.cell (*ly.begin_top_down ());
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
dss.set_text_enlargement (1);
|
||||
dss.set_text_property_name (tl::Variant ("LABEL"));
|
||||
|
||||
// original layers
|
||||
db::Region rnwell (db::RecursiveShapeIterator (ly, tc, nwell), dss);
|
||||
db::Region rdiff (db::RecursiveShapeIterator (ly, tc, diff), dss);
|
||||
db::Region rpplus (db::RecursiveShapeIterator (ly, tc, pplus), dss);
|
||||
db::Region rnplus (db::RecursiveShapeIterator (ly, tc, nplus), dss);
|
||||
db::Region rpoly (db::RecursiveShapeIterator (ly, tc, poly), dss);
|
||||
db::Region rcontact (db::RecursiveShapeIterator (ly, tc, contact), dss);
|
||||
db::Region rmetal1 (db::RecursiveShapeIterator (ly, tc, metal1), dss);
|
||||
db::Region rvia1 (db::RecursiveShapeIterator (ly, tc, via1), dss);
|
||||
db::Region rmetal2 (db::RecursiveShapeIterator (ly, tc, metal2), dss);
|
||||
|
||||
// derived regions
|
||||
|
||||
db::Region rdiff_in_nwell = rdiff & rnwell;
|
||||
db::Region rpdiff = rdiff_in_nwell - rnplus;
|
||||
db::Region rntie = rdiff_in_nwell & rnplus;
|
||||
db::Region rpgate = rpdiff & rpoly;
|
||||
db::Region rpsd = rpdiff - rpgate;
|
||||
|
||||
db::Region rdiff_outside_nwell = rdiff - rnwell;
|
||||
db::Region rndiff = rdiff_outside_nwell - rpplus;
|
||||
db::Region rptie = rdiff_outside_nwell & rpplus;
|
||||
db::Region rngate = rndiff & rpoly;
|
||||
db::Region rnsd = rndiff - rngate;
|
||||
|
||||
// Global
|
||||
|
||||
db::Region bulk (dss);
|
||||
|
||||
// return the computed layers into the original layout and write it for debugging purposes
|
||||
|
||||
unsigned int lpgate = ly.insert_layer (db::LayerProperties (10, 0)); // 10/0 -> Gate (p)
|
||||
unsigned int lngate = ly.insert_layer (db::LayerProperties (11, 0)); // 11/0 -> Gate (n)
|
||||
unsigned int lpsd = ly.insert_layer (db::LayerProperties (12, 0)); // 12/0 -> Source/Drain (p)
|
||||
unsigned int lnsd = ly.insert_layer (db::LayerProperties (13, 0)); // 13/0 -> Source/Drain (n)
|
||||
unsigned int lpdiff = ly.insert_layer (db::LayerProperties (14, 0)); // 14/0 -> P Diffusion
|
||||
unsigned int lndiff = ly.insert_layer (db::LayerProperties (15, 0)); // 15/0 -> N Diffusion
|
||||
unsigned int lptie = ly.insert_layer (db::LayerProperties (16, 0)); // 16/0 -> P Tie
|
||||
unsigned int lntie = ly.insert_layer (db::LayerProperties (17, 0)); // 17/0 -> N Tie
|
||||
|
||||
rpgate.insert_into (&ly, tc.cell_index (), lpgate);
|
||||
rngate.insert_into (&ly, tc.cell_index (), lngate);
|
||||
rpsd.insert_into (&ly, tc.cell_index (), lpsd);
|
||||
rnsd.insert_into (&ly, tc.cell_index (), lnsd);
|
||||
rpdiff.insert_into (&ly, tc.cell_index (), lpdiff);
|
||||
rndiff.insert_into (&ly, tc.cell_index (), lndiff);
|
||||
rptie.insert_into (&ly, tc.cell_index (), lptie);
|
||||
rntie.insert_into (&ly, tc.cell_index (), lntie);
|
||||
|
||||
// perform the extraction
|
||||
|
||||
db::Netlist nl;
|
||||
db::hier_clusters<db::NetShape> cl;
|
||||
|
||||
db::NetlistDeviceExtractorMOS4Transistor pmos_ex ("PMOS");
|
||||
db::NetlistDeviceExtractorMOS4Transistor nmos_ex ("NMOS");
|
||||
|
||||
db::NetlistDeviceExtractor::input_layers dl;
|
||||
|
||||
dl["SD"] = &rpsd;
|
||||
dl["G"] = &rpgate;
|
||||
dl["W"] = &rnwell;
|
||||
dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes
|
||||
pmos_ex.extract (dss, 0, dl, nl, cl);
|
||||
|
||||
dl["SD"] = &rnsd;
|
||||
dl["G"] = &rngate;
|
||||
dl["W"] = &bulk;
|
||||
dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes
|
||||
nmos_ex.extract (dss, 0, dl, nl, cl);
|
||||
|
||||
// perform the net extraction
|
||||
|
||||
db::NetlistExtractor net_ex;
|
||||
|
||||
db::Connectivity conn;
|
||||
|
||||
// Global nets
|
||||
conn.connect_global (bulk, "BULK");
|
||||
conn.soft_connect_global (rptie, "BULK");
|
||||
|
||||
// Intra-layer
|
||||
conn.connect (rpsd);
|
||||
conn.connect (rnsd);
|
||||
conn.connect (rptie);
|
||||
conn.connect (rntie);
|
||||
conn.connect (rnwell);
|
||||
conn.connect (rpoly);
|
||||
conn.connect (rcontact);
|
||||
conn.connect (rmetal1);
|
||||
conn.connect (rvia1);
|
||||
conn.connect (rmetal2);
|
||||
// Inter-layer
|
||||
conn.soft_connect (rcontact, rpsd);
|
||||
conn.soft_connect (rcontact, rnsd);
|
||||
conn.soft_connect (rntie, rnwell);
|
||||
conn.soft_connect (rcontact, rptie);
|
||||
conn.soft_connect (rcontact, rntie);
|
||||
conn.soft_connect (rcontact, rpoly);
|
||||
conn.connect (rcontact, rmetal1);
|
||||
conn.connect (rvia1, rmetal1);
|
||||
conn.connect (rvia1, rmetal2);
|
||||
|
||||
// extract the nets
|
||||
std::list<std::set<std::string> > jn;
|
||||
|
||||
jn.push_back (std::set<std::string> ());
|
||||
jn.back ().insert ("BULK");
|
||||
jn.back ().insert ("VSS");
|
||||
|
||||
jn.push_back (std::set<std::string> ());
|
||||
jn.back ().insert ("NWELL");
|
||||
jn.back ().insert ("VDD");
|
||||
|
||||
net_ex.set_joined_nets ("INV2", jn);
|
||||
|
||||
std::list<tl::GlobPattern> gp;
|
||||
gp.push_back (tl::GlobPattern ("NEXT"));
|
||||
gp.push_back (tl::GlobPattern ("FB"));
|
||||
net_ex.set_joined_net_names (gp);
|
||||
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
||||
|
||||
annotate_soft_connections (nl, cl);
|
||||
|
||||
EXPECT_EQ (all_net_names_unique (nl), true);
|
||||
|
||||
// debug layers produced for nets
|
||||
std::map<unsigned int, unsigned int> dump_map;
|
||||
dump_map [layer_of (bulk) ] = ly.insert_layer (db::LayerProperties (200, 0));
|
||||
dump_map [layer_of (rnwell) ] = ly.insert_layer (db::LayerProperties (201, 0));
|
||||
dump_map [layer_of (rpsd) ] = ly.insert_layer (db::LayerProperties (202, 0));
|
||||
dump_map [layer_of (rnsd) ] = ly.insert_layer (db::LayerProperties (203, 0));
|
||||
dump_map [layer_of (rpoly) ] = ly.insert_layer (db::LayerProperties (204, 0));
|
||||
dump_map [layer_of (rcontact) ] = ly.insert_layer (db::LayerProperties (205, 0));
|
||||
dump_map [layer_of (rmetal1) ] = ly.insert_layer (db::LayerProperties (206, 0));
|
||||
dump_map [layer_of (rvia1) ] = ly.insert_layer (db::LayerProperties (207, 0));
|
||||
dump_map [layer_of (rmetal2) ] = ly.insert_layer (db::LayerProperties (208, 0));
|
||||
|
||||
// write nets to layout
|
||||
db::CellMapping cm = dss.cell_mapping_to_original (0, &ly, tc.cell_index ());
|
||||
dump_nets_to_layout (nl, cl, ly, dump_map, cm, true);
|
||||
|
||||
// compare netlist as string
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, nl,
|
||||
"circuit RINGO ();\n"
|
||||
" subcircuit ND2X1 $1 (NWELL=$4,B=FB,A=ENABLE,VDD=VDD,OUT=$5,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $2 (NWELL=$4,IN=$14,VDD=VDD,OUT=FB,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $3 (NWELL=$4,IN=FB,VDD=$I17,OUT=OUT,VSS=$I27,BULK=BULK);\n"
|
||||
" subcircuit TIE $4 (NWELL=$4,VSS=$I27,VDD=$I17,BULK=BULK);\n"
|
||||
" subcircuit EMPTY $5 ($1=$4,$2=$I27,$3=$I17);\n"
|
||||
" subcircuit TIE $6 (NWELL=$4,VSS=VSS,VDD=VDD,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $7 (NWELL=$4,IN=$5,VDD=VDD,OUT=$6,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit EMPTY $8 ($1=$4,$2=VSS,$3=VDD);\n"
|
||||
" subcircuit INVX1 $9 (NWELL=$4,IN=$6,VDD=VDD,OUT=$7,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $10 (NWELL=$4,IN=$7,VDD=VDD,OUT=$8,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $11 (NWELL=$4,IN=$8,VDD=VDD,OUT=$9,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $12 (NWELL=$4,IN=$9,VDD=VDD,OUT=$10,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $13 (NWELL=$4,IN=$10,VDD=VDD,OUT=$11,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $14 (NWELL=$4,IN=$11,VDD=VDD,OUT=$12,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $15 (NWELL=$4,IN=$12,VDD=VDD,OUT=$15,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $16 (NWELL=$4,IN=$15,VDD=VDD,OUT=$14,VSS=VSS,BULK=BULK);\n"
|
||||
"end;\n"
|
||||
"circuit ND2X1 (NWELL=NWELL,B=B,A=A,VDD=VDD,OUT=OUT,VSS=VSS,BULK=BULK);\n"
|
||||
" device PMOS $1 (S=$7,G=$4,D=$9,B=NWELL) (L=0.25,W=1.5,AS=0.6375,AD=0.3375,PS=3.85,PD=1.95);\n"
|
||||
" device PMOS $2 (S=$9,G=$2,D=$6,B=NWELL) (L=0.25,W=1.5,AS=0.3375,AD=0.6375,PS=1.95,PD=3.85);\n"
|
||||
" device NMOS $3 (S=$13,G=$4,D=$14,B=BULK) (L=0.25,W=0.95,AS=0.40375,AD=0.21375,PS=2.75,PD=1.4);\n"
|
||||
" device NMOS $4 (S=$14,G=$2,D=$11,B=BULK) (L=0.25,W=0.95,AS=0.21375,AD=0.40375,PS=1.4,PD=2.75);\n"
|
||||
" device SOFT $5 (A=B,C=$2) (A=0,P=0);\n"
|
||||
" device SOFT $6 (A=A,C=$4) (A=0,P=0);\n"
|
||||
" device SOFT $7 (A=OUT,C=$6) (A=0,P=0);\n"
|
||||
" device SOFT $8 (A=OUT,C=$7) (A=0,P=0);\n"
|
||||
" device SOFT $9 (A=VDD,C=$9) (A=0,P=0);\n"
|
||||
" device SOFT $10 (A=OUT,C=$11) (A=0,P=0);\n"
|
||||
" device SOFT $11 (A=VSS,C=$13) (A=0,P=0);\n"
|
||||
"end;\n"
|
||||
"circuit TIE (NWELL=NWELL,VSS=VSS,VDD=VDD,BULK=BULK);\n"
|
||||
" device SOFT $1 (A=$2,C=NWELL) (A=0,P=0);\n"
|
||||
" device SOFT $2 (A=VDD,C=$2) (A=0,P=0);\n"
|
||||
" device SOFT $3 (A=VSS,C=$3) (A=0,P=0);\n"
|
||||
" device SOFT $4 (A=$3,C=BULK) (A=0,P=0);\n"
|
||||
"end;\n"
|
||||
"circuit EMPTY ($1=$1,$2=$2,$3=$3);\n"
|
||||
"end;\n"
|
||||
"circuit INVX1 (NWELL=NWELL,IN=IN,VDD=VDD,OUT=OUT,VSS=VSS,BULK=BULK);\n"
|
||||
" device PMOS $1 (S=$5,G=$2,D=$7,B=NWELL) (L=0.25,W=1.5,AS=0.6375,AD=0.6375,PS=3.85,PD=3.85);\n"
|
||||
" device NMOS $2 (S=$10,G=$2,D=$8,B=BULK) (L=0.25,W=0.95,AS=0.40375,AD=0.40375,PS=2.75,PD=2.75);\n"
|
||||
" device SOFT $3 (A=IN,C=$2) (A=0,P=0);\n"
|
||||
" device SOFT $4 (A=VDD,C=$5) (A=0,P=0);\n"
|
||||
" device SOFT $5 (A=OUT,C=$7) (A=0,P=0);\n"
|
||||
" device SOFT $6 (A=OUT,C=$8) (A=0,P=0);\n"
|
||||
" device SOFT $7 (A=VSS,C=$10) (A=0,P=0);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// doesn't do anything here, but we test that this does not destroy anything:
|
||||
nl.combine_devices ();
|
||||
|
||||
// make pins for named nets of top-level circuits - this way they are not purged
|
||||
nl.make_top_level_pins ();
|
||||
nl.purge ();
|
||||
|
||||
// compare netlist as string
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, nl,
|
||||
"circuit RINGO (FB=FB,ENABLE=ENABLE,OUT=OUT,VDD=VDD,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit ND2X1 $1 (NWELL=$4,B=FB,A=ENABLE,VDD=VDD,OUT=$5,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $2 (NWELL=$4,IN=$14,VDD=VDD,OUT=FB,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $3 (NWELL=$4,IN=FB,VDD=$I17,OUT=OUT,VSS=$I27,BULK=BULK);\n"
|
||||
" subcircuit TIE $4 (NWELL=$4,VSS=$I27,VDD=$I17,BULK=BULK);\n"
|
||||
" subcircuit TIE $5 (NWELL=$4,VSS=VSS,VDD=VDD,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $6 (NWELL=$4,IN=$5,VDD=VDD,OUT=$6,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $7 (NWELL=$4,IN=$6,VDD=VDD,OUT=$7,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $8 (NWELL=$4,IN=$7,VDD=VDD,OUT=$8,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $9 (NWELL=$4,IN=$8,VDD=VDD,OUT=$9,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $10 (NWELL=$4,IN=$9,VDD=VDD,OUT=$10,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $11 (NWELL=$4,IN=$10,VDD=VDD,OUT=$11,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $12 (NWELL=$4,IN=$11,VDD=VDD,OUT=$12,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $13 (NWELL=$4,IN=$12,VDD=VDD,OUT=$15,VSS=VSS,BULK=BULK);\n"
|
||||
" subcircuit INVX1 $14 (NWELL=$4,IN=$15,VDD=VDD,OUT=$14,VSS=VSS,BULK=BULK);\n"
|
||||
"end;\n"
|
||||
"circuit ND2X1 (NWELL=NWELL,B=B,A=A,VDD=VDD,OUT=OUT,VSS=VSS,BULK=BULK);\n"
|
||||
" device PMOS $1 (S=$7,G=$4,D=$9,B=NWELL) (L=0.25,W=1.5,AS=0.6375,AD=0.3375,PS=3.85,PD=1.95);\n"
|
||||
" device PMOS $2 (S=$9,G=$2,D=$6,B=NWELL) (L=0.25,W=1.5,AS=0.3375,AD=0.6375,PS=1.95,PD=3.85);\n"
|
||||
" device NMOS $3 (S=$13,G=$4,D=$14,B=BULK) (L=0.25,W=0.95,AS=0.40375,AD=0.21375,PS=2.75,PD=1.4);\n"
|
||||
" device NMOS $4 (S=$14,G=$2,D=$11,B=BULK) (L=0.25,W=0.95,AS=0.21375,AD=0.40375,PS=1.4,PD=2.75);\n"
|
||||
" device SOFT $5 (A=B,C=$2) (A=0,P=0);\n"
|
||||
" device SOFT $6 (A=A,C=$4) (A=0,P=0);\n"
|
||||
" device SOFT $7 (A=OUT,C=$6) (A=0,P=0);\n"
|
||||
" device SOFT $8 (A=OUT,C=$7) (A=0,P=0);\n"
|
||||
" device SOFT $9 (A=VDD,C=$9) (A=0,P=0);\n"
|
||||
" device SOFT $10 (A=OUT,C=$11) (A=0,P=0);\n"
|
||||
" device SOFT $11 (A=VSS,C=$13) (A=0,P=0);\n"
|
||||
"end;\n"
|
||||
"circuit TIE (NWELL=NWELL,VSS=VSS,VDD=VDD,BULK=BULK);\n"
|
||||
" device SOFT $1 (A=$2,C=NWELL) (A=0,P=0);\n"
|
||||
" device SOFT $2 (A=VDD,C=$2) (A=0,P=0);\n"
|
||||
" device SOFT $3 (A=VSS,C=$3) (A=0,P=0);\n"
|
||||
" device SOFT $4 (A=$3,C=BULK) (A=0,P=0);\n"
|
||||
"end;\n"
|
||||
"circuit INVX1 (NWELL=NWELL,IN=IN,VDD=VDD,OUT=OUT,VSS=VSS,BULK=BULK);\n"
|
||||
" device PMOS $1 (S=$5,G=$2,D=$7,B=NWELL) (L=0.25,W=1.5,AS=0.6375,AD=0.6375,PS=3.85,PD=3.85);\n"
|
||||
" device NMOS $2 (S=$10,G=$2,D=$8,B=BULK) (L=0.25,W=0.95,AS=0.40375,AD=0.40375,PS=2.75,PD=2.75);\n"
|
||||
" device SOFT $3 (A=IN,C=$2) (A=0,P=0);\n"
|
||||
" device SOFT $4 (A=VDD,C=$5) (A=0,P=0);\n"
|
||||
" device SOFT $5 (A=OUT,C=$7) (A=0,P=0);\n"
|
||||
" device SOFT $6 (A=OUT,C=$8) (A=0,P=0);\n"
|
||||
" device SOFT $7 (A=VSS,C=$10) (A=0,P=0);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// compare the collected test data
|
||||
|
||||
std::string au = tl::testdata ();
|
||||
au = tl::combine_path (au, "algo");
|
||||
au = tl::combine_path (au, "soft_connections_au.gds");
|
||||
|
||||
db::compare_layouts (_this, ly, au);
|
||||
}
|
||||
|
||||
|
||||
TEST(100_issue954)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1838,6 +1838,36 @@ is equivalent to "layer.smoothed" (see <a href="/about/drc_ref_layer.xml#smoothe
|
|||
argument, "smoothed" represents the polygon smoother on primary shapes within
|
||||
<a href="/about/drc_ref_drc.xml">DRC</a> expressions (see <a href="/about/drc_ref_layer.xml#drc">Layer#drc</a> and <a href="/about/drc_ref_global.xml#smoothed">smoothed</a> for more details).
|
||||
</p>
|
||||
<a name="soft_connect"/><h2>"soft_connect" - Specifies a soft connection between two layers</h2>
|
||||
<keyword name="soft_connect"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>soft_connect(a, b)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
A "soft connection" is made between two layers and
|
||||
is a directional connection (like an ideal diode).
|
||||
Soft connections allow detecting if nets are connected
|
||||
via a high-ohmic substrate or diffusion layer (the
|
||||
"lower" layer).
|
||||
"b" is the "lower" and "a" the upper layer.
|
||||
</p><p>
|
||||
See <a href="/about/drc_ref_netter.xml#connect">Netter#connect</a> for a more detailed description of that function.
|
||||
</p>
|
||||
<a name="soft_connect_global"/><h2>"soft_connect_global" - Specifies a soft connection to a global net</h2>
|
||||
<keyword name="soft_connect_global"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>soft_connect_global(l, name)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
Like <a href="#soft_connect">soft_connect</a>, a soft connection is made between
|
||||
a layer and a global net (e.g. substrate). The global net
|
||||
is always the "lower" net of the soft connection.
|
||||
</p><p>
|
||||
See <a href="/about/drc_ref_netter.xml#soft_connect_global">Netter#soft_connect_global</a> for a more detailed
|
||||
description of that function.
|
||||
</p>
|
||||
<a name="source"/><h2>"source" - Specifies a source layout</h2>
|
||||
<keyword name="source"/>
|
||||
<p>Usage:</p>
|
||||
|
|
|
|||
|
|
@ -434,6 +434,49 @@ layout analysis. Hence, all <a href="#connect">connect</a>, <a href="#connect_gl
|
|||
calls must have been made before this method is used. Further <a href="#connect">connect</a>
|
||||
statements will clear the netlist and re-extract it again.
|
||||
</p>
|
||||
<a name="soft_connect"/><h2>"soft_connect" - Specifies a soft connection between two layers</h2>
|
||||
<keyword name="soft_connect"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>soft_connect(a, b)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
a and b must be polygon or text layers. After calling this function, the
|
||||
Netter considers shapes from layer a and b connected in "soft mode".
|
||||
Typically, b is a high-ohmic layer such as diffusion, implant for substate
|
||||
material, also called the "lower" layer.
|
||||
</p><p>
|
||||
A soft connection between shapes from layer a and b forms a directional
|
||||
connection like an ideal diode: current can flow down, but now up
|
||||
(not meant in the physical sense, this is a concept).
|
||||
</p><p>
|
||||
Hence, two nets are disconnected, if they both connect to the same lower layer,
|
||||
but do not have a connection between them.
|
||||
</p><p>
|
||||
The netlist extractor will use this scheme to identify nets that are
|
||||
connected only via such a high-ohmic region. Such a case is typically
|
||||
bad for the functionality of a device and reported as an error.
|
||||
Once, the check has been made and no error is found, soft-connected
|
||||
nets are joined the same way than hard connections are made.
|
||||
</p><p>
|
||||
Beside this, soft connections follow the same rules than hard connections
|
||||
(see <a href="#connect">connect</a>).
|
||||
</p>
|
||||
<a name="soft_connect_global"/><h2>"soft_connect_global" - Soft-connects a layer with a global net</h2>
|
||||
<keyword name="soft_connect_global"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>soft-connect_global(l, name)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
Connects the shapes from the given layer l to a global net with the given name
|
||||
in "soft mode".
|
||||
</p><p>
|
||||
See <a href="#connect_global">connect_global</a> for details about the concepts of global nets.
|
||||
See <a href="#soft_connect">soft_connect</a> for details about the concept of soft connections.
|
||||
In global net soft connections, the global net (typically a substrate)
|
||||
is always the "lower" layer.
|
||||
</p>
|
||||
<a name="top_level"/><h2>"top_level" - Specifies top level mode</h2>
|
||||
<keyword name="top_level"/>
|
||||
<p>Usage:</p>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
<h2-index/>
|
||||
|
||||
<h2>Intra- and inter-layer connections</h2>
|
||||
<keyword name="connect"/>
|
||||
|
||||
<p>
|
||||
The connectivity setup of a LVS script determines how the connections are made.
|
||||
|
|
@ -77,6 +78,7 @@ connect(metal2, metal2_labels)</pre>
|
|||
</p>
|
||||
|
||||
<h2>Global connections</h2>
|
||||
<keyword name="connect_global"/>
|
||||
|
||||
<p>
|
||||
KLayout supports implicit connections made across all polygons on
|
||||
|
|
@ -98,6 +100,7 @@ connect(metal2, metal2_labels)</pre>
|
|||
</p>
|
||||
|
||||
<h2>Implicit connections</h2>
|
||||
<keyword name="connect_implicit"/>
|
||||
|
||||
<p>
|
||||
Implicit connections can be useful to supply preliminary connections
|
||||
|
|
@ -193,6 +196,7 @@ connect(metal2, metal2_labels)</pre>
|
|||
</p>
|
||||
|
||||
<h2>Explicit connections</h2>
|
||||
<keyword name="connect_explicit"/>
|
||||
|
||||
<p>
|
||||
Explicit connections can be useful to enforce a connection in the layout
|
||||
|
|
@ -280,4 +284,219 @@ connect_explicit("INV", [ "BULK", "VSS" ])
|
|||
statements.
|
||||
</p>
|
||||
|
||||
<h2>Soft connections</h2>
|
||||
<keyword name="soft_connect"/>
|
||||
<keyword name="soft_connect_global"/>
|
||||
|
||||
<p>
|
||||
Soft connections are a way to find wiring issues where signals
|
||||
or even power is routed over high-ohmic paths.
|
||||
High-ohmic paths can be established through connections via
|
||||
poly silicon, implant, well or substrate areas. Such areas
|
||||
can easily show resistance values which are a hundred times
|
||||
higher than that of metal connections. We have to make sure
|
||||
that for routing power or critical signals, connections are
|
||||
not made through such areas, but primarily through metal
|
||||
connections.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Here is an example:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="/manual/soft_connections.png"/>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In this case, we have a standard textbook planar CMOS technology with two PMOS devices
|
||||
sitting in a n-well. These could be the two PMOS of two inverter pairs for example.
|
||||
Both PMOS need to be connected to VDD at their sources. In addition, the n-well
|
||||
area also needs to be tied to VDD in order to provide reverse bias for the p+ drain
|
||||
areas and the body potential for the transistors, forming the opposite
|
||||
electrode of the gate capacity.
|
||||
</p>
|
||||
|
||||
<p>Such a technology stack can be described by the following connectivity:</p>
|
||||
|
||||
<pre># Input layers
|
||||
|
||||
nwell = ...
|
||||
active = ...
|
||||
pplus = ...
|
||||
nplus = ...
|
||||
poly = ...
|
||||
contact = ...
|
||||
metal1 = ...
|
||||
via1 = ...
|
||||
metal2 = ...
|
||||
|
||||
# computed layers
|
||||
|
||||
(nactive, pactive) = active.and_not(nwell)
|
||||
|
||||
# PMOS and NMOS source/drain regions
|
||||
psd = (nactive & pplus) - poly
|
||||
nsd = (pactive & nplus) - poly
|
||||
|
||||
# n tie and p tie (nwell and substrate contact)
|
||||
ntie = nactive & nplus
|
||||
ptie = pactive & pplus
|
||||
|
||||
# connections
|
||||
|
||||
# nwell connections
|
||||
connect(ntie, nwell)
|
||||
connect(contact, ntie)
|
||||
|
||||
# substrate connections
|
||||
connect_global(ptie, "BULK")
|
||||
connect(contact, ptie)
|
||||
|
||||
# device connections
|
||||
connect(contact, psd)
|
||||
connect(contact, nsd)
|
||||
connect(contact, poly)
|
||||
|
||||
# metal connections
|
||||
connect(metal1, contact)
|
||||
connect(via1, metal1)
|
||||
connect(metal2, via1)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
However, there is an issue:
|
||||
As shown in the picture, the left PMOS source is properly connected to VDD.
|
||||
The right one however lacks the metal connection to VDD. From the perspective
|
||||
of pure connectivity, this transistor's source is connected to VDD, but only
|
||||
through a weak n-well connection. Such a device will not work - or at least, badly.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The solution is to introduce soft connections. Soft connections are made
|
||||
by replacing "connect" with "soft_connect" and "connect_global" with "soft_connect_global"
|
||||
(see <a href="/about/drc_ref_global.xml#soft_connect">soft_connect</a> and
|
||||
<a href="/about/drc_ref_global.xml#soft_connect_global">soft_connect_global</a>).
|
||||
The first layer is the "upper" layer while the second layer is the "lower" layer.
|
||||
The lower layer is the high-ohmic one. In global connections, the global net is
|
||||
always the high-ohmic one.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Soft connections can be visualized as directional connections: current can only flow from the
|
||||
upper to the lower layer, but not the other way. So, a real connection is only made,
|
||||
if both upper terminals of the soft connections are connected to the same physical net.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To solve the n-well issue we have to substitute the n-tie to n-well connection statement
|
||||
by a "soft_connect" statement:
|
||||
</p>
|
||||
|
||||
<pre>soft_connect(ntie, nwell)</pre>
|
||||
|
||||
<p>
|
||||
The above picture now looks like this:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="/manual/soft_connections2.png"/>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
With this definition, the netlist extractor is able to detect the fault
|
||||
and raise a warning or an error (in top level mode).
|
||||
The warning is shown on the log tab and indicates incomplete wiring plus
|
||||
details about the subnets, separated by the soft connections.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The complete the setup we also need to include other soft connections,
|
||||
such as connections via substrate (a global soft connect to the BULK net),
|
||||
via source/drain implants, via the tie implants and via poly:
|
||||
</p>
|
||||
|
||||
<pre># Input layers
|
||||
|
||||
nwell = ...
|
||||
active = ...
|
||||
pplus = ...
|
||||
nplus = ...
|
||||
poly = ...
|
||||
contact = ...
|
||||
metal1 = ...
|
||||
via1 = ...
|
||||
metal2 = ...
|
||||
|
||||
# computed layers
|
||||
|
||||
(nactive, pactive) = active.and_not(nwell)
|
||||
|
||||
# PMOS and NMOS source/drain regions
|
||||
psd = (nactive & pplus) - poly
|
||||
nsd = (pactive & nplus) - poly
|
||||
|
||||
# n tie and p tie (nwell and substrate contact)
|
||||
ntie = nactive & nplus
|
||||
ptie = pactive & pplus
|
||||
|
||||
# connections
|
||||
|
||||
# nwell connections
|
||||
soft_connect(ntie, nwell)
|
||||
soft_connect(contact, ntie)
|
||||
|
||||
# substrate connections
|
||||
soft_connect_global(ptie, "BULK")
|
||||
soft_connect(contact, ptie)
|
||||
|
||||
# device connections
|
||||
soft_connect(contact, psd)
|
||||
soft_connect(contact, nsd)
|
||||
soft_connect(contact, poly)
|
||||
|
||||
# metal connections
|
||||
connect(metal1, contact)
|
||||
connect(via1, metal1)
|
||||
connect(metal2, via1)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
As this code demonstrates, multiple soft connections can be specified.
|
||||
From the perspective of the check, all soft connections are of the same kind.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note, that two opposite soft connections cancel, so this would eventually
|
||||
make a hard connection:
|
||||
</p>
|
||||
|
||||
<pre>soft_connect(a, b)
|
||||
soft_connect(b, a)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<b>NOTE:</b> It is therefore important to observe the direction of soft connections:
|
||||
upper and high-conductive / low-ohmic layer first, and lower and low-conductive / high-ohmic
|
||||
layer second.
|
||||
</p>
|
||||
|
||||
<h3>Soft connections and "must connect" nets</h3>
|
||||
|
||||
<p>
|
||||
Soft connections and must connect nets (aka "connect_explicit" and "connect_implicit")
|
||||
serve the same purpose - to detect incomplete wiring. Typically they are used
|
||||
together, such as doing "connect_implicit" on VDD nets and "connect_explicit"
|
||||
on VDD and NWELL nets if the schematic circuits do not feature an explicit
|
||||
NWELL pin.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Soft connections are checked before connect_explicit and connect_implicit
|
||||
are executed. This means, that soft connection errors cannot be masked by
|
||||
declaring them "must connect". On the other hand, that is not a real issue
|
||||
as both checks would raise an warning or error (in the top-level case).
|
||||
It would only be a different kind of warning.
|
||||
</p>
|
||||
|
||||
</doc>
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
|
|
@ -244,6 +244,8 @@
|
|||
<file alias="drc_raw1.png">doc/images/drc_raw1.png</file>
|
||||
<file alias="drc_raw2.png">doc/images/drc_raw2.png</file>
|
||||
<file alias="drc_raw3.png">doc/images/drc_raw3.png</file>
|
||||
<file alias="soft_connections.png">doc/manual/soft_connections.png</file>
|
||||
<file alias="soft_connections2.png">doc/manual/soft_connections2.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/help/programming">
|
||||
<file alias="introduction.xml">doc/programming/introduction.xml</file>
|
||||
|
|
|
|||
|
|
@ -2284,12 +2284,36 @@ CODE
|
|||
# @synopsis connect(a, b)
|
||||
# See \Netter#connect for a description of that function.
|
||||
|
||||
# %DRC%
|
||||
# @name soft_connect
|
||||
# @brief Specifies a soft connection between two layers
|
||||
# @synopsis soft_connect(a, b)
|
||||
# A "soft connection" is made between two layers and
|
||||
# is a directional connection (like an ideal diode).
|
||||
# Soft connections allow detecting if nets are connected
|
||||
# via a high-ohmic substrate or diffusion layer (the
|
||||
# "lower" layer).
|
||||
# "b" is the "lower" and "a" the upper layer.
|
||||
#
|
||||
# See \Netter#connect for a more detailed description of that function.
|
||||
|
||||
# %DRC%
|
||||
# @name connect_global
|
||||
# @brief Specifies a connection to a global net
|
||||
# @synopsis connect_global(l, name)
|
||||
# See \Netter#connect_global for a description of that function.
|
||||
|
||||
# %DRC%
|
||||
# @name soft_connect_global
|
||||
# @brief Specifies a soft connection to a global net
|
||||
# @synopsis soft_connect_global(l, name)
|
||||
# Like \soft_connect, a soft connection is made between
|
||||
# a layer and a global net (e.g. substrate). The global net
|
||||
# is always the "lower" net of the soft connection.
|
||||
#
|
||||
# See \Netter#soft_connect_global for a more detailed
|
||||
# description of that function.
|
||||
|
||||
# %DRC%
|
||||
# @name clear_connections
|
||||
# @brief Clears all connections stored so far
|
||||
|
|
@ -2360,14 +2384,18 @@ CODE
|
|||
clear_connections
|
||||
connect
|
||||
connect_global
|
||||
soft_connect
|
||||
soft_connect_global
|
||||
connect_implicit
|
||||
connect_explicit
|
||||
device_scaling
|
||||
top_level
|
||||
ignore_extraction_errors
|
||||
extract_devices
|
||||
l2n_data
|
||||
netlist
|
||||
l2n_data
|
||||
_l2n_object
|
||||
_make_soft_connection_diodes
|
||||
).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(*args)
|
||||
|
|
|
|||
|
|
@ -116,6 +116,51 @@ module DRC
|
|||
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name soft_connect
|
||||
# @brief Specifies a soft connection between two layers
|
||||
# @synopsis soft_connect(a, b)
|
||||
# a and b must be polygon or text layers. After calling this function, the
|
||||
# Netter considers shapes from layer a and b connected in "soft mode".
|
||||
# Typically, b is a high-ohmic layer such as diffusion, implant for substate
|
||||
# material, also called the "lower" layer.
|
||||
#
|
||||
# A soft connection between shapes from layer a and b forms a directional
|
||||
# connection like an ideal diode: current can flow down, but now up
|
||||
# (not meant in the physical sense, this is a concept).
|
||||
#
|
||||
# Hence, two nets are disconnected, if they both connect to the same lower layer,
|
||||
# but do not have a connection between them.
|
||||
#
|
||||
# The netlist extractor will use this scheme to identify nets that are
|
||||
# connected only via such a high-ohmic region. Such a case is typically
|
||||
# bad for the functionality of a device and reported as an error.
|
||||
# Once, the check has been made and no error is found, soft-connected
|
||||
# nets are joined the same way than hard connections are made.
|
||||
#
|
||||
# Beside this, soft connections follow the same rules than hard connections
|
||||
# (see \connect).
|
||||
|
||||
def soft_connect(a, b)
|
||||
|
||||
@engine._context("soft_connect") do
|
||||
|
||||
a.is_a?(DRC::DRCLayer) || raise("First argument must be a layer")
|
||||
b.is_a?(DRC::DRCLayer) || raise("Second argument must be a layer")
|
||||
a.requires_texts_or_region
|
||||
b.requires_texts_or_region
|
||||
|
||||
register_layer(a.data)
|
||||
register_layer(b.data)
|
||||
# soft connections imply hard intra-layer connections
|
||||
a.data.is_a?(RBA::Region) && @l2n.connect(a.data)
|
||||
b.data.is_a?(RBA::Region) && @l2n.connect(b.data)
|
||||
@l2n.soft_connect(a.data, b.data)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name connect_global
|
||||
# @brief Connects a layer with a global net
|
||||
|
|
@ -140,6 +185,33 @@ module DRC
|
|||
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name soft_connect_global
|
||||
# @brief Soft-connects a layer with a global net
|
||||
# @synopsis soft-connect_global(l, name)
|
||||
# Connects the shapes from the given layer l to a global net with the given name
|
||||
# in "soft mode".
|
||||
#
|
||||
# See \connect_global for details about the concepts of global nets.
|
||||
# See \soft_connect for details about the concept of soft connections.
|
||||
# In global net soft connections, the global net (typically a substrate)
|
||||
# is always the "lower" layer.
|
||||
|
||||
def soft_connect_global(l, name)
|
||||
|
||||
@engine._context("soft_connect_global") do
|
||||
|
||||
l.is_a?(DRC::DRCLayer) || raise("Layer argument must be a layer")
|
||||
l.requires_texts_or_region
|
||||
|
||||
register_layer(l.data)
|
||||
l.data.is_a?(RBA::Region) && @l2n.connect(l.data)
|
||||
@l2n.soft_connect_global(l.data, name)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name extract_devices
|
||||
# @brief Extracts devices based on the given extractor class, name and device layer selection
|
||||
|
|
@ -681,6 +753,14 @@ module DRC
|
|||
@l2n && @l2n.is_extracted? && self.l2n_data
|
||||
end
|
||||
|
||||
def _l2n_object
|
||||
@l2n
|
||||
end
|
||||
|
||||
def _make_soft_connection_diodes(f)
|
||||
@l2n.make_soft_connection_diodes = f
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def cleanup
|
||||
|
|
|
|||
|
|
@ -519,7 +519,7 @@ HelpSource::get_image (const std::string &u)
|
|||
{
|
||||
QResource res (resource_url (QUrl::fromEncoded (u.c_str ()).path ()));
|
||||
if (res.size () == 0) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("ERROR: no data found for resource ")) + u);
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("No data found for resource ")) + u);
|
||||
}
|
||||
|
||||
QByteArray data;
|
||||
|
|
@ -552,7 +552,7 @@ HelpSource::get_css (const std::string &u)
|
|||
|
||||
QResource res (resource_url (QUrl::fromEncoded (u.c_str ()).path ()));
|
||||
if (res.size () == 0) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("ERROR: no data found for resource ")) + u);
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("No data found for resource ")) + u);
|
||||
}
|
||||
|
||||
QByteArray data;
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ ResourceHelpProvider::get (lay::HelpSource * /*src*/, const std::string &path) c
|
|||
QString qpath = tl::to_qstring (path);
|
||||
QResource res (resource_url (qpath));
|
||||
if (res.size () == 0) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("ERROR: no data found for resource ")) + tl::to_string (res.fileName ()));
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("No data found for resource ")) + tl::to_string (res.fileName ()));
|
||||
}
|
||||
|
||||
QByteArray data;
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@
|
|||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/run_16px.png</normaloff>:/run_16px.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
|
|
@ -576,6 +576,9 @@
|
|||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::ActionsContextMenu</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="headerHidden">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ size_t count_shapes (db::LayoutToNetlist *l2ndb, db::Net *net)
|
|||
size_t n = 0;
|
||||
|
||||
const db::Connectivity &conn = l2ndb->connectivity ();
|
||||
for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
for (db::Connectivity::all_layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
n += count_shapes (l2ndb, net, *layer);
|
||||
}
|
||||
|
||||
|
|
@ -276,7 +276,7 @@ void NetInfoDialog::update_info_text ()
|
|||
bool incomplete = false;
|
||||
|
||||
const db::Connectivity &conn = mp_l2ndb->connectivity ();
|
||||
for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
for (db::Connectivity::all_layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
|
||||
std::string l = layer_string (mp_l2ndb.get (), *layer);
|
||||
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ NetlistBrowserDialog::probe_net (const db::DPoint &p, bool trace_path)
|
|||
std::vector<db::Region *> regions;
|
||||
|
||||
const db::Connectivity &conn = l2ndb->connectivity ();
|
||||
for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
for (db::Connectivity::all_layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
db::LayerProperties lp = l2ndb->internal_layout ()->get_properties (*layer);
|
||||
if (! lp.is_null ()) {
|
||||
db::Region *region = l2ndb->layer_by_index (*layer);
|
||||
|
|
|
|||
|
|
@ -235,6 +235,8 @@ NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/)
|
|||
connect (actionExportAll, SIGNAL (triggered ()), this, SLOT (export_all ()));
|
||||
connect (actionExportSelected, SIGNAL (triggered ()), this, SLOT (export_selected ()));
|
||||
|
||||
connect (mode_tab, SIGNAL (currentChanged (int)), this, SLOT (mode_tab_changed (int)));
|
||||
|
||||
forward->setEnabled (false);
|
||||
backward->setEnabled (false);
|
||||
}
|
||||
|
|
@ -330,6 +332,13 @@ NetlistBrowserPage::eventFilter (QObject *watched, QEvent *event)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
NetlistBrowserPage::mode_tab_changed (int)
|
||||
{
|
||||
clear_highlights ();
|
||||
dm_update_highlights ();
|
||||
}
|
||||
|
||||
void
|
||||
NetlistBrowserPage::layer_list_changed (int)
|
||||
{
|
||||
|
|
@ -1072,11 +1081,10 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb)
|
|||
mode_tab->setTabEnabled (0, true);
|
||||
mode_tab->setTabEnabled (1, is_lvsdb);
|
||||
mode_tab->setTabEnabled (2, is_lvsdb);
|
||||
mode_tab->setTabEnabled (3, is_lvsdb);
|
||||
mode_tab->setTabEnabled (3, true);
|
||||
#if QT_VERSION >= 0x50F00
|
||||
mode_tab->setTabVisible (1, is_lvsdb);
|
||||
mode_tab->setTabVisible (2, is_lvsdb);
|
||||
mode_tab->setTabVisible (3, is_lvsdb);
|
||||
#endif
|
||||
|
||||
if (is_lvsdb) {
|
||||
|
|
@ -1166,7 +1174,7 @@ NetlistBrowserPage::setup_trees ()
|
|||
|
||||
if ((lvsdb && lvsdb->cross_ref ()) || (l2ndb && ! l2ndb->log_entries ().empty ())) {
|
||||
|
||||
NetlistLogModel *new_model = new NetlistLogModel (log_view, lvsdb->cross_ref (), l2ndb);
|
||||
NetlistLogModel *new_model = new NetlistLogModel (log_view, lvsdb ? lvsdb->cross_ref () : 0, l2ndb);
|
||||
delete log_view->model ();
|
||||
log_view->setModel (new_model);
|
||||
|
||||
|
|
@ -1421,7 +1429,7 @@ NetlistBrowserPage::adjust_view ()
|
|||
size_t cluster_id = net->cluster_id ();
|
||||
|
||||
const db::Connectivity &conn = mp_database->connectivity ();
|
||||
for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
for (db::Connectivity::all_layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
|
||||
db::Box layer_bbox;
|
||||
db::recursive_cluster_shape_iterator<db::NetShape> shapes (mp_database->net_clusters (), *layer, cell_index, cluster_id);
|
||||
|
|
@ -1580,7 +1588,7 @@ NetlistBrowserPage::produce_highlights_for_net (const db::Net *net, size_t &n_ma
|
|||
tl::Color fallback_color = make_valid_color (m_colorizer.marker_color ());
|
||||
|
||||
const db::Connectivity &conn = mp_database->connectivity ();
|
||||
for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
for (db::Connectivity::all_layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
|
||||
db::LayerProperties lp = layout->get_properties (*layer);
|
||||
std::map<db::LayerProperties, lay::LayerPropertiesConstIterator>::const_iterator display = display_by_lp.find (lp);
|
||||
|
|
|
|||
|
|
@ -214,6 +214,7 @@ private slots:
|
|||
void log_selection_changed ();
|
||||
void browse_color_for_net ();
|
||||
void select_color_for_net ();
|
||||
void mode_tab_changed (int);
|
||||
|
||||
protected:
|
||||
bool eventFilter (QObject *watched, QEvent *event);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ namespace lay
|
|||
|
||||
static void build_top_circuit_list (const db::NetlistCrossReference *cross_ref, std::vector<NetlistCrossReferenceModel::circuit_pair> &top_level_circuits)
|
||||
{
|
||||
if (! top_level_circuits.empty ()) {
|
||||
if (! top_level_circuits.empty () || ! cross_ref) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -139,48 +139,80 @@ size_t NetlistCrossReferenceModel::top_circuit_count () const
|
|||
|
||||
size_t NetlistCrossReferenceModel::child_circuit_count (const circuit_pair &circuits) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
build_child_circuit_map (mp_cross_ref.get (), m_child_circuits);
|
||||
return m_child_circuits [circuits].size ();
|
||||
}
|
||||
|
||||
size_t NetlistCrossReferenceModel::net_count (const circuit_pair &circuits) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
|
||||
return data ? data->nets.size () : 0;
|
||||
}
|
||||
|
||||
size_t NetlistCrossReferenceModel::net_terminal_count (const net_pair &nets) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const db::NetlistCrossReference::PerNetData *data = mp_cross_ref->per_net_data_for (nets);
|
||||
return data ? data->terminals.size () : 0;
|
||||
}
|
||||
|
||||
size_t NetlistCrossReferenceModel::net_subcircuit_pin_count (const net_pair &nets) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const db::NetlistCrossReference::PerNetData *data = mp_cross_ref->per_net_data_for (nets);
|
||||
return data ? data->subcircuit_pins.size () : 0;
|
||||
}
|
||||
|
||||
size_t NetlistCrossReferenceModel::net_pin_count (const net_pair &nets) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const db::NetlistCrossReference::PerNetData *data = mp_cross_ref->per_net_data_for (nets);
|
||||
return data ? data->pins.size () : 0;
|
||||
}
|
||||
|
||||
size_t NetlistCrossReferenceModel::device_count (const circuit_pair &circuits) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
|
||||
return data ? data->devices.size () : 0;
|
||||
}
|
||||
|
||||
size_t NetlistCrossReferenceModel::pin_count (const circuit_pair &circuits) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
|
||||
return data ? data->pins.size () : 0;
|
||||
}
|
||||
|
||||
size_t NetlistCrossReferenceModel::subcircuit_count (const circuit_pair &circuits) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
|
||||
return data ? data->subcircuits.size () : 0;
|
||||
}
|
||||
|
|
@ -218,6 +250,10 @@ struct DataGetter<const db::SubCircuit *>
|
|||
template <class Pair>
|
||||
static IndexedNetlistModel::circuit_pair get_parent_of (const Pair &pair, const db::NetlistCrossReference *cross_ref, std::map<Pair, IndexedNetlistModel::circuit_pair> &cache)
|
||||
{
|
||||
if (! cross_ref) {
|
||||
return IndexedNetlistModel::circuit_pair ((const db::Circuit *) 0, (const db::Circuit *) 0);
|
||||
}
|
||||
|
||||
typename std::map<Pair, IndexedNetlistModel::circuit_pair>::iterator i = cache.find (pair);
|
||||
if (i == cache.end ()) {
|
||||
|
||||
|
|
@ -266,6 +302,7 @@ IndexedNetlistModel::circuit_pair NetlistCrossReferenceModel::parent_of (const I
|
|||
|
||||
std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::top_circuit_from_index (size_t index) const
|
||||
{
|
||||
tl_assert (mp_cross_ref.get ());
|
||||
build_top_circuit_list (mp_cross_ref.get (), m_top_level_circuits);
|
||||
|
||||
IndexedNetlistModel::circuit_pair cp = m_top_level_circuits [index];
|
||||
|
|
@ -276,6 +313,7 @@ std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceMode
|
|||
|
||||
std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::child_circuit_from_index (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
tl_assert (mp_cross_ref.get ());
|
||||
build_child_circuit_map (mp_cross_ref.get (), m_child_circuits);
|
||||
|
||||
IndexedNetlistModel::circuit_pair cp = m_child_circuits [circuits][index];
|
||||
|
|
@ -286,6 +324,7 @@ std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceMode
|
|||
|
||||
std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::circuit_from_index (size_t index) const
|
||||
{
|
||||
tl_assert (mp_cross_ref.get ());
|
||||
IndexedNetlistModel::circuit_pair cp = mp_cross_ref->begin_circuits () [index];
|
||||
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (cp);
|
||||
tl_assert (data != 0);
|
||||
|
|
@ -294,6 +333,7 @@ std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceMode
|
|||
|
||||
std::pair<IndexedNetlistModel::net_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::net_from_index (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
tl_assert (mp_cross_ref.get ());
|
||||
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
|
||||
tl_assert (data != 0);
|
||||
return std::make_pair (data->nets [index].pair, std::make_pair (data->nets [index].status, data->nets [index].msg));
|
||||
|
|
@ -301,11 +341,13 @@ std::pair<IndexedNetlistModel::net_pair, std::pair<NetlistCrossReferenceModel::S
|
|||
|
||||
const db::Net *NetlistCrossReferenceModel::second_net_for (const db::Net *first) const
|
||||
{
|
||||
tl_assert (mp_cross_ref.get ());
|
||||
return mp_cross_ref->other_net_for (first);
|
||||
}
|
||||
|
||||
const db::Circuit *NetlistCrossReferenceModel::second_circuit_for (const db::Circuit *first) const
|
||||
{
|
||||
tl_assert (mp_cross_ref.get ());
|
||||
return mp_cross_ref->other_circuit_for (first);
|
||||
}
|
||||
|
||||
|
|
@ -382,7 +424,7 @@ namespace {
|
|||
|
||||
void NetlistCrossReferenceModel::ensure_subcircuit_data_built () const
|
||||
{
|
||||
if (! m_per_subcircuit_data.empty ()) {
|
||||
if (! m_per_subcircuit_data.empty () || ! mp_cross_ref.get ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -466,6 +508,7 @@ IndexedNetlistModel::net_subcircuit_pin_pair NetlistCrossReferenceModel::subcirc
|
|||
|
||||
IndexedNetlistModel::net_subcircuit_pin_pair NetlistCrossReferenceModel::net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const
|
||||
{
|
||||
tl_assert (mp_cross_ref.get ());
|
||||
const db::NetlistCrossReference::PerNetData *data = mp_cross_ref->per_net_data_for (nets);
|
||||
tl_assert (data != 0);
|
||||
return data->subcircuit_pins [index];
|
||||
|
|
@ -473,6 +516,7 @@ IndexedNetlistModel::net_subcircuit_pin_pair NetlistCrossReferenceModel::net_sub
|
|||
|
||||
IndexedNetlistModel::net_terminal_pair NetlistCrossReferenceModel::net_terminalref_from_index (const net_pair &nets, size_t index) const
|
||||
{
|
||||
tl_assert (mp_cross_ref.get ());
|
||||
const db::NetlistCrossReference::PerNetData *data = mp_cross_ref->per_net_data_for (nets);
|
||||
tl_assert (data != 0);
|
||||
return data->terminals [index];
|
||||
|
|
@ -480,6 +524,7 @@ IndexedNetlistModel::net_terminal_pair NetlistCrossReferenceModel::net_terminalr
|
|||
|
||||
IndexedNetlistModel::net_pin_pair NetlistCrossReferenceModel::net_pinref_from_index (const net_pair &nets, size_t index) const
|
||||
{
|
||||
tl_assert (mp_cross_ref.get ());
|
||||
const db::NetlistCrossReference::PerNetData *data = mp_cross_ref->per_net_data_for (nets);
|
||||
tl_assert (data != 0);
|
||||
return data->pins [index];
|
||||
|
|
@ -487,6 +532,7 @@ IndexedNetlistModel::net_pin_pair NetlistCrossReferenceModel::net_pinref_from_in
|
|||
|
||||
std::pair<IndexedNetlistModel::device_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::device_from_index (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
tl_assert (mp_cross_ref.get ());
|
||||
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
|
||||
tl_assert (data != 0);
|
||||
return std::make_pair (data->devices [index].pair, std::make_pair (data->devices [index].status, data->devices [index].msg));
|
||||
|
|
@ -494,6 +540,7 @@ std::pair<IndexedNetlistModel::device_pair, std::pair<NetlistCrossReferenceModel
|
|||
|
||||
std::pair<IndexedNetlistModel::pin_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::pin_from_index (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
tl_assert (mp_cross_ref.get ());
|
||||
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
|
||||
tl_assert (data != 0);
|
||||
return std::make_pair (data->pins [index].pair, std::make_pair (data->pins [index].status, data->pins [index].msg));
|
||||
|
|
@ -501,6 +548,7 @@ std::pair<IndexedNetlistModel::pin_pair, std::pair<NetlistCrossReferenceModel::S
|
|||
|
||||
std::pair<IndexedNetlistModel::subcircuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::subcircuit_from_index (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
tl_assert (mp_cross_ref.get ());
|
||||
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
|
||||
tl_assert (data != 0);
|
||||
return std::make_pair (data->subcircuits [index].pair, std::make_pair (data->subcircuits [index].status, data->subcircuits [index].msg));
|
||||
|
|
@ -536,6 +584,10 @@ static size_t get_index_of (const Pair &pair, Iter begin, Iter end, std::map<Pai
|
|||
|
||||
size_t NetlistCrossReferenceModel::circuit_index (const circuit_pair &circuits) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return lay::no_netlist_index;
|
||||
}
|
||||
|
||||
std::map<circuit_pair, size_t>::iterator i = m_index_of_circuits.find (circuits);
|
||||
if (i == m_index_of_circuits.end ()) {
|
||||
|
||||
|
|
@ -562,6 +614,10 @@ size_t NetlistCrossReferenceModel::circuit_index (const circuit_pair &circuits)
|
|||
|
||||
size_t NetlistCrossReferenceModel::net_index (const net_pair &nets) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return lay::no_netlist_index;
|
||||
}
|
||||
|
||||
circuit_pair circuits = parent_of (nets);
|
||||
|
||||
const db::NetlistCrossReference::PerCircuitData *org_data = mp_cross_ref->per_circuit_data_for (circuits);
|
||||
|
|
@ -575,6 +631,10 @@ size_t NetlistCrossReferenceModel::net_index (const net_pair &nets) const
|
|||
|
||||
size_t NetlistCrossReferenceModel::device_index (const device_pair &devices) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return lay::no_netlist_index;
|
||||
}
|
||||
|
||||
circuit_pair circuits = parent_of (devices);
|
||||
|
||||
const db::NetlistCrossReference::PerCircuitData *org_data = mp_cross_ref->per_circuit_data_for (circuits);
|
||||
|
|
@ -588,6 +648,10 @@ size_t NetlistCrossReferenceModel::device_index (const device_pair &devices) con
|
|||
|
||||
size_t NetlistCrossReferenceModel::pin_index (const pin_pair &pins, const circuit_pair &circuits) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return lay::no_netlist_index;
|
||||
}
|
||||
|
||||
const db::NetlistCrossReference::PerCircuitData *org_data = mp_cross_ref->per_circuit_data_for (circuits);
|
||||
if (! org_data) {
|
||||
return lay::no_netlist_index;
|
||||
|
|
@ -599,6 +663,10 @@ size_t NetlistCrossReferenceModel::pin_index (const pin_pair &pins, const circui
|
|||
|
||||
size_t NetlistCrossReferenceModel::subcircuit_index (const subcircuit_pair &subcircuits) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return lay::no_netlist_index;
|
||||
}
|
||||
|
||||
circuit_pair circuits = parent_of (subcircuits);
|
||||
|
||||
const db::NetlistCrossReference::PerCircuitData *org_data = mp_cross_ref->per_circuit_data_for (circuits);
|
||||
|
|
@ -612,6 +680,10 @@ size_t NetlistCrossReferenceModel::subcircuit_index (const subcircuit_pair &subc
|
|||
|
||||
std::string NetlistCrossReferenceModel::circuit_pair_status_hint (const std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > &cps) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return std::string ();
|
||||
}
|
||||
|
||||
std::string msg;
|
||||
|
||||
if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) {
|
||||
|
|
@ -655,6 +727,10 @@ std::string NetlistCrossReferenceModel::circuit_status_hint (size_t index) const
|
|||
|
||||
std::string NetlistCrossReferenceModel::child_circuit_status_hint (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return std::string ();
|
||||
}
|
||||
|
||||
std::string msg;
|
||||
|
||||
std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > cps = child_circuit_from_index (circuits, index);
|
||||
|
|
@ -685,6 +761,10 @@ std::string NetlistCrossReferenceModel::child_circuit_status_hint (const circuit
|
|||
|
||||
std::string NetlistCrossReferenceModel::net_status_hint (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return std::string ();
|
||||
}
|
||||
|
||||
std::string msg;
|
||||
|
||||
std::pair<IndexedNetlistModel::net_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > cps = net_from_index (circuits, index);
|
||||
|
|
@ -713,6 +793,10 @@ std::string NetlistCrossReferenceModel::net_status_hint (const circuit_pair &cir
|
|||
|
||||
std::string NetlistCrossReferenceModel::device_status_hint (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return std::string ();
|
||||
}
|
||||
|
||||
std::string msg;
|
||||
|
||||
std::pair<IndexedNetlistModel::device_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > cps = device_from_index (circuits, index);
|
||||
|
|
@ -748,6 +832,10 @@ std::string NetlistCrossReferenceModel::device_status_hint (const circuit_pair &
|
|||
|
||||
std::string NetlistCrossReferenceModel::pin_status_hint (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return std::string ();
|
||||
}
|
||||
|
||||
std::string msg;
|
||||
|
||||
std::pair<IndexedNetlistModel::pin_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > cps = pin_from_index (circuits, index);
|
||||
|
|
@ -772,6 +860,10 @@ std::string NetlistCrossReferenceModel::pin_status_hint (const circuit_pair &cir
|
|||
|
||||
std::string NetlistCrossReferenceModel::subcircuit_status_hint (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
if (! mp_cross_ref.get ()) {
|
||||
return std::string ();
|
||||
}
|
||||
|
||||
std::string msg;
|
||||
|
||||
std::pair<IndexedNetlistModel::subcircuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > cps = subcircuit_from_index (circuits, index);
|
||||
|
|
|
|||
|
|
@ -301,3 +301,38 @@ TEST(40_DeviceExtractorErrors)
|
|||
run_test (_this, "custom_resistors", "custom_resistors.gds", true, false /*no LVS*/);
|
||||
}
|
||||
|
||||
// Basic soft connection
|
||||
TEST(50_BasicSoftConnection)
|
||||
{
|
||||
run_test (_this, "soft_connect1", "soft_connect1.gds", true, false /*no LVS*/);
|
||||
}
|
||||
|
||||
// No errors
|
||||
TEST(51_SoftConnectionNoErrors)
|
||||
{
|
||||
run_test (_this, "soft_connect2", "soft_connect2.gds", true, false /*no LVS*/);
|
||||
}
|
||||
|
||||
// Simple hierarchy
|
||||
TEST(52_SoftConnectionSimpleHierarchy)
|
||||
{
|
||||
run_test (_this, "soft_connect3", "soft_connect3.gds", true, false /*no LVS*/);
|
||||
}
|
||||
|
||||
// Soft connected nets from different subcircuits
|
||||
TEST(53_SoftConnectionFromSubcircuits)
|
||||
{
|
||||
run_test (_this, "soft_connect4", "soft_connect4.gds", true, false /*no LVS*/);
|
||||
}
|
||||
|
||||
// Soft connected nets from different subcircuits (propagated)
|
||||
TEST(54_SoftConnectionFromSubcircuits2)
|
||||
{
|
||||
run_test (_this, "soft_connect5", "soft_connect5.gds", true, false /*no LVS*/);
|
||||
}
|
||||
|
||||
// Level 2 soft connection
|
||||
TEST(55_SoftConnectionSecondLevel)
|
||||
{
|
||||
run_test (_this, "soft_connect6", "soft_connect6.gds", true, false /*no LVS*/);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,6 +97,12 @@ TEST(2_fullWithAlign)
|
|||
run_test (_this, "vexriscv_align.lvs", "vexriscv.cir.gz", "vexriscv.oas.gz");
|
||||
}
|
||||
|
||||
TEST(3_fullSoft)
|
||||
{
|
||||
test_is_long_runner ();
|
||||
run_test (_this, "vexriscv_soft.lvs", "vexriscv.cir.gz", "vexriscv.oas.gz");
|
||||
}
|
||||
|
||||
TEST(10_private)
|
||||
{
|
||||
// test_is_long_runner ();
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ RUBYTEST (dbEdgePairTest, "dbEdgePairTest.rb")
|
|||
RUBYTEST (dbEdgesTest, "dbEdgesTest.rb")
|
||||
RUBYTEST (dbEdgeTest, "dbEdgeTest.rb")
|
||||
RUBYTEST (dbGlyphs, "dbGlyphs.rb")
|
||||
RUBYTEST (dbHierNetworkProcessorTests, "dbHierNetworkProcessorTests.rb")
|
||||
RUBYTEST (dbInstanceTest, "dbInstanceTest.rb")
|
||||
RUBYTEST (dbInstElementTest, "dbInstElementTest.rb")
|
||||
RUBYTEST (dbLayerMapping, "dbLayerMapping.rb")
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -29,7 +29,7 @@ J(
|
|||
G(l14 SUBSTRATE)
|
||||
H(W B('Must-connect nets GND must be connected further up in the hierarchy - this is an error at chip top level') C(INVCHAIN) X('must-connect'))
|
||||
H(W B('Must-connect nets R must be connected further up in the hierarchy - this is an error at chip top level') C(INVCHAIN) X('must-connect'))
|
||||
H(W B('Must-connect nets R of circuit INV2 must be connected further up in the hierarchy - this is an error at chip top level.\nInstance path: INVCHAIN:$1[r0 *1 0,0]/INV2') C(INVCHAIN) X('must-connect') Q('(0,0;0,9.2;3,9.2;3,0)'))
|
||||
H(W B('Must-connect nets R of circuit INV2 must be connected further up in the hierarchy - this is an error at chip top level.\nInstance path: INVCHAIN/INV2[r0 0,0]:$1') C(INVCHAIN) X('must-connect') Q('(0,0;0,9.2;3,9.2;3,0)'))
|
||||
K(PMOS MOS3)
|
||||
K(NMOS MOS3)
|
||||
D(D$PMOS PMOS
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ J(
|
|||
G(l14 SUBSTRATE)
|
||||
H(W B('Must-connect nets GND must be connected further up in the hierarchy - this is an error at chip top level') C(INVCHAIN) X('must-connect'))
|
||||
H(W B('Must-connect nets R must be connected further up in the hierarchy - this is an error at chip top level') C(INVCHAIN) X('must-connect'))
|
||||
H(W B('Must-connect nets R of circuit INV2 must be connected further up in the hierarchy - this is an error at chip top level.\nInstance path: INVCHAIN:$1[r0 *1 0,0]/INV2') C(INVCHAIN) X('must-connect') Q('(0,0;0,9.2;3,9.2;3,0)'))
|
||||
H(W B('Must-connect nets R of circuit INV2 must be connected further up in the hierarchy - this is an error at chip top level.\nInstance path: INVCHAIN/INV2[r0 0,0]:$1') C(INVCHAIN) X('must-connect') Q('(0,0;0,9.2;3,9.2;3,0)'))
|
||||
K(PMOS MOS3)
|
||||
K(NMOS MOS3)
|
||||
D(D$PMOS PMOS
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ J(
|
|||
G(l14 SUBSTRATE)
|
||||
H(W B('Must-connect nets VSSTOP must be connected further up in the hierarchy - this is an error at chip top level') C(TOP) X('must-connect'))
|
||||
H(W B('Must-connect nets VDD must be connected further up in the hierarchy - this is an error at chip top level') C(TOP) X('must-connect'))
|
||||
H(W B('Must-connect nets VSS of circuit INV2 must be connected further up in the hierarchy - this is an error at chip top level.\nInstance path: INVCHAIN:$2[r0 *1 0,0]/INV2') C(INVCHAIN) X('must-connect') Q('(0,0;0,9.2;3,9.2;3,0)'))
|
||||
H(W B('Must-connect nets VSS of circuit INV2 must be connected further up in the hierarchy - this is an error at chip top level.\nInstance path: INVCHAIN/INV2[r0 0,0]:$2') C(INVCHAIN) X('must-connect') Q('(0,0;0,9.2;3,9.2;3,0)'))
|
||||
K(PMOS MOS3)
|
||||
K(NMOS MOS3)
|
||||
D(D$PMOS PMOS
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
* Extracted by KLayout
|
||||
|
||||
.SUBCKT TOP A Q VDD SUBSTRATE|VSS
|
||||
X$1 SUBSTRATE|VSS VDD VDD \$1 Q SUBSTRATE|VSS INV
|
||||
X$2 SUBSTRATE|VSS VDD VDD A \$1 SUBSTRATE|VSS INV
|
||||
.ENDS TOP
|
||||
|
||||
.SUBCKT INV \$1 \$2 \$3 \$4 \$5 SUBSTRATE
|
||||
M$1 \$2 \$4 \$5 \$3 PMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U
|
||||
+ PD=3.45U
|
||||
M$2 \$1 \$4 \$5 SUBSTRATE NMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U
|
||||
+ PD=3.45U
|
||||
.ENDS INV
|
||||
Binary file not shown.
|
|
@ -0,0 +1,217 @@
|
|||
#%l2n-klayout
|
||||
W(TOP)
|
||||
U(0.001)
|
||||
L(l3 '1/0')
|
||||
L(l4 '3/0')
|
||||
L(l15 '3/1')
|
||||
L(l8 '4/0')
|
||||
L(l11 '5/0')
|
||||
L(l12 '6/0')
|
||||
L(l16 '6/1')
|
||||
L(l13 '7/0')
|
||||
L(l14 '8/0')
|
||||
L(l17 '8/1')
|
||||
L(l7)
|
||||
L(l10)
|
||||
L(l2)
|
||||
L(l9)
|
||||
L(l6)
|
||||
C(l3 l3 l10)
|
||||
C(l4 l4 l15 l11)
|
||||
C(l15 l4 l15)
|
||||
C(l8 l8 l12 l10 l2 l9 l6)
|
||||
CS(l8 l10 l2 l9 l6)
|
||||
C(l11 l4 l11 l12)
|
||||
CS(l11 l4)
|
||||
C(l12 l8 l11 l12 l16 l13)
|
||||
C(l16 l12 l16)
|
||||
C(l13 l12 l13 l14)
|
||||
C(l14 l13 l14 l17)
|
||||
C(l17 l14 l17)
|
||||
C(l7 l7)
|
||||
C(l10 l3 l8 l10)
|
||||
CS(l10 l3)
|
||||
C(l2 l8 l2)
|
||||
C(l9 l8 l9)
|
||||
C(l6 l8 l6)
|
||||
G(l7 SUBSTRATE)
|
||||
G(l9 SUBSTRATE)
|
||||
GS(l9 SUBSTRATE)
|
||||
H(W B('Net with incomplete wiring (soft-connected partial nets)') C(TOP) X('soft-connection-check'))
|
||||
H(B('\tPartial net #1: TOP - VDD') C(TOP) Q('(0.6,3.95;0.6,4.85;4.5,4.85;4.5,3.95)'))
|
||||
H(B('\tPartial net #2: TOP - $I4') C(TOP) Q('(5.1,3.95;5.1,4.85;9,4.85;9,3.95)'))
|
||||
H(W B('Net with incomplete wiring (soft-connected partial nets)') C(TOP) X('soft-connection-check'))
|
||||
H(B('\tPartial net #1: TOP - VSS') C(TOP) Q('(0.6,1.15;0.6,2.05;4.5,2.05;4.5,1.15)'))
|
||||
H(B('\tPartial net #2: TOP - $I1') C(TOP) Q('(5.1,1.15;5.1,2.05;9,2.05;9,1.15)'))
|
||||
K(PMOS MOS4)
|
||||
K(NMOS MOS4)
|
||||
D(D$PMOS PMOS
|
||||
T(S
|
||||
R(l2 (-900 -475) (775 950))
|
||||
)
|
||||
T(G
|
||||
R(l4 (-125 -475) (250 950))
|
||||
)
|
||||
T(D
|
||||
R(l2 (125 -475) (775 950))
|
||||
)
|
||||
T(B
|
||||
R(l3 (-125 -475) (250 950))
|
||||
)
|
||||
)
|
||||
D(D$NMOS NMOS
|
||||
T(S
|
||||
R(l6 (-900 -475) (775 950))
|
||||
)
|
||||
T(G
|
||||
R(l4 (-125 -475) (250 950))
|
||||
)
|
||||
T(D
|
||||
R(l6 (125 -475) (775 950))
|
||||
)
|
||||
T(B
|
||||
R(l7 (-125 -475) (250 950))
|
||||
)
|
||||
)
|
||||
X(INV
|
||||
R((-1500 -800) (3000 4600))
|
||||
N(1
|
||||
R(l8 (290 -310) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (-290 -690) (360 760))
|
||||
R(l13 (-305 -705) (250 250))
|
||||
R(l13 (-250 150) (250 250))
|
||||
R(l14 (-2025 -775) (3000 900))
|
||||
R(l6 (-1375 -925) (775 950))
|
||||
)
|
||||
N(2
|
||||
R(l8 (290 2490) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (-290 -690) (360 760))
|
||||
R(l13 (-305 -705) (250 250))
|
||||
R(l13 (-250 150) (250 250))
|
||||
R(l14 (-2025 -775) (3000 900))
|
||||
R(l2 (-1375 -925) (775 950))
|
||||
)
|
||||
N(3
|
||||
R(l3 (-1500 1800) (3000 2000))
|
||||
)
|
||||
N(4
|
||||
R(l4 (-125 -250) (250 2500))
|
||||
R(l4 (-250 -3050) (250 1600))
|
||||
R(l4 (-250 1200) (250 1600))
|
||||
)
|
||||
N(5
|
||||
R(l8 (-510 -310) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l8 (-220 2180) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (-290 -3530) (360 2840))
|
||||
R(l12 (-360 -2800) (360 760))
|
||||
R(l12 (-360 2040) (360 760))
|
||||
R(l2 (-680 -855) (775 950))
|
||||
R(l6 (-775 -3750) (775 950))
|
||||
)
|
||||
N(6 I(SUBSTRATE))
|
||||
P(1)
|
||||
P(2)
|
||||
P(3)
|
||||
P(4)
|
||||
P(5)
|
||||
P(6 I(SUBSTRATE))
|
||||
D(1 D$PMOS
|
||||
Y(0 2800)
|
||||
E(L 0.25)
|
||||
E(W 0.95)
|
||||
E(AS 0.73625)
|
||||
E(AD 0.73625)
|
||||
E(PS 3.45)
|
||||
E(PD 3.45)
|
||||
T(S 5)
|
||||
T(G 4)
|
||||
T(D 2)
|
||||
T(B 3)
|
||||
)
|
||||
D(2 D$NMOS
|
||||
Y(0 0)
|
||||
E(L 0.25)
|
||||
E(W 0.95)
|
||||
E(AS 0.73625)
|
||||
E(AD 0.73625)
|
||||
E(PS 3.45)
|
||||
E(PD 3.45)
|
||||
T(S 5)
|
||||
T(G 4)
|
||||
T(D 1)
|
||||
T(B 6)
|
||||
)
|
||||
)
|
||||
X(TOP
|
||||
R((600 800) (8880 4600))
|
||||
N(1
|
||||
R(l4 (2920 2600) (2880 400))
|
||||
R(l11 (-300 -300) (200 200))
|
||||
R(l12 (-300 -300) (690 400))
|
||||
)
|
||||
N(2 I(A)
|
||||
R(l4 (6600 2600) (2880 400))
|
||||
R(l15 (-2380 -200) (0 0))
|
||||
)
|
||||
N(3 I(Q)
|
||||
R(l12 (1810 2600) (690 400))
|
||||
R(l16 (-400 -200) (0 0))
|
||||
)
|
||||
N(4 I(VDD)
|
||||
R(l3 (4000 3400) (1600 2000))
|
||||
R(l3 (-5000 -2000) (1000 2000))
|
||||
R(l3 (6400 -2000) (1000 2000))
|
||||
R(l8 (-8000 -900) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l8 (7200 200) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l12 (-7900 -350) (800 900))
|
||||
R(l12 (6600 -900) (800 900))
|
||||
R(l13 (-7900 -350) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l13 (7200 200) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l14 (-8000 -350) (1000 900))
|
||||
R(l14 (6400 -900) (1000 900))
|
||||
R(l17 (-4800 -450) (0 0))
|
||||
)
|
||||
N(5 I('SUBSTRATE,VSS')
|
||||
R(l8 (1000 1700) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l8 (7200 200) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l12 (-7900 -350) (800 900))
|
||||
R(l12 (6600 -900) (800 900))
|
||||
R(l13 (-7900 -350) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l13 (7200 200) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l14 (-8000 -350) (1000 900))
|
||||
R(l14 (6400 -900) (1000 900))
|
||||
R(l17 (-4800 -550) (0 0))
|
||||
)
|
||||
P(2 I(A))
|
||||
P(3 I(Q))
|
||||
P(4 I(VDD))
|
||||
P(5 I('SUBSTRATE,VSS'))
|
||||
X(1 INV Y(3000 1600)
|
||||
P(0 5)
|
||||
P(1 4)
|
||||
P(2 4)
|
||||
P(3 1)
|
||||
P(4 3)
|
||||
P(5 5)
|
||||
)
|
||||
X(2 INV Y(6600 1600)
|
||||
P(0 5)
|
||||
P(1 4)
|
||||
P(2 4)
|
||||
P(3 2)
|
||||
P(4 1)
|
||||
P(5 5)
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
|
||||
$lvs_test_source && source($lvs_test_source)
|
||||
|
||||
if $lvs_test_target_l2n
|
||||
report_netlist($lvs_test_target_l2n)
|
||||
else
|
||||
report_netlist
|
||||
end
|
||||
|
||||
writer = write_spice(true, false)
|
||||
$lvs_test_target_cir && target_netlist($lvs_test_target_cir, writer, "Extracted by KLayout")
|
||||
|
||||
deep
|
||||
|
||||
# Drawing layers
|
||||
|
||||
nwell = input(1, 0)
|
||||
active = input(2, 0)
|
||||
nplus = input(2, 1)
|
||||
pplus = input(2, 2)
|
||||
poly = input(3, 0)
|
||||
poly_lbl = input(3, 1)
|
||||
diff_cont = input(4, 0)
|
||||
poly_cont = input(5, 0)
|
||||
metal1 = input(6, 0)
|
||||
metal1_lbl = input(6, 1)
|
||||
via1 = input(7, 0)
|
||||
metal2 = input(8, 0)
|
||||
metal2_lbl = input(8, 1)
|
||||
|
||||
# Bulk layer for terminal provisioning
|
||||
|
||||
bulk = polygon_layer
|
||||
|
||||
psd = nil
|
||||
nsd = nil
|
||||
|
||||
# Computed layers
|
||||
|
||||
active_in_nwell = active & nwell
|
||||
pactive = active_in_nwell & pplus
|
||||
ntie = active_in_nwell & nplus
|
||||
pgate = pactive & poly
|
||||
psd = pactive - pgate
|
||||
|
||||
active_outside_nwell = active - nwell
|
||||
nactive = active_outside_nwell & nplus
|
||||
ptie = active_outside_nwell & pplus
|
||||
ngate = nactive & poly
|
||||
nsd = nactive - ngate
|
||||
|
||||
# Device extraction
|
||||
|
||||
# PMOS transistor device extraction
|
||||
extract_devices(mos4("PMOS"), { "SD" => psd, "G" => pgate, "W" => nwell,
|
||||
"tS" => psd, "tD" => psd, "tG" => poly })
|
||||
|
||||
# NMOS transistor device extraction
|
||||
extract_devices(mos4("NMOS"), { "SD" => nsd, "G" => ngate, "W" => bulk,
|
||||
"tS" => nsd, "tD" => nsd, "tG" => poly })
|
||||
|
||||
# Define connectivity for netlist extraction
|
||||
|
||||
# Inter-layer
|
||||
|
||||
soft_connect(diff_cont, psd)
|
||||
soft_connect(diff_cont, nsd)
|
||||
soft_connect(diff_cont, ptie)
|
||||
soft_connect(diff_cont, ntie)
|
||||
soft_connect(ntie, nwell)
|
||||
soft_connect(poly_cont, poly)
|
||||
|
||||
connect(diff_cont, metal1)
|
||||
connect(poly_cont, metal1)
|
||||
connect(metal1, via1)
|
||||
connect(via1, metal2)
|
||||
|
||||
# attach labels
|
||||
connect(poly, poly_lbl)
|
||||
connect(metal1, metal1_lbl)
|
||||
connect(metal2, metal2_lbl)
|
||||
|
||||
# Global
|
||||
connect_global(bulk, "SUBSTRATE")
|
||||
soft_connect_global(ptie, "SUBSTRATE")
|
||||
|
||||
# Netlist section (NOTE: we only check log here)
|
||||
netlist
|
||||
|
||||
netlist.simplify
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
* Extracted by KLayout
|
||||
|
||||
.SUBCKT TOP A Q VDD SUBSTRATE|VSS
|
||||
X$1 SUBSTRATE|VSS VDD VDD \$1 Q SUBSTRATE|VSS INV
|
||||
X$2 SUBSTRATE|VSS VDD VDD A \$1 SUBSTRATE|VSS INV
|
||||
.ENDS TOP
|
||||
|
||||
.SUBCKT INV \$1 \$2 \$3 \$4 \$5 SUBSTRATE
|
||||
M$1 \$2 \$4 \$5 \$3 PMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U
|
||||
+ PD=3.45U
|
||||
M$2 \$1 \$4 \$5 SUBSTRATE NMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U
|
||||
+ PD=3.45U
|
||||
.ENDS INV
|
||||
Binary file not shown.
|
|
@ -0,0 +1,213 @@
|
|||
#%l2n-klayout
|
||||
W(TOP)
|
||||
U(0.001)
|
||||
L(l3 '1/0')
|
||||
L(l4 '3/0')
|
||||
L(l15 '3/1')
|
||||
L(l8 '4/0')
|
||||
L(l11 '5/0')
|
||||
L(l12 '6/0')
|
||||
L(l16 '6/1')
|
||||
L(l13 '7/0')
|
||||
L(l14 '8/0')
|
||||
L(l17 '8/1')
|
||||
L(l7)
|
||||
L(l10)
|
||||
L(l2)
|
||||
L(l9)
|
||||
L(l6)
|
||||
C(l3 l3 l10)
|
||||
C(l4 l4 l15 l11)
|
||||
C(l15 l4 l15)
|
||||
C(l8 l8 l12 l10 l2 l9 l6)
|
||||
CS(l8 l10 l2 l9 l6)
|
||||
C(l11 l4 l11 l12)
|
||||
CS(l11 l4)
|
||||
C(l12 l8 l11 l12 l16 l13)
|
||||
C(l16 l12 l16)
|
||||
C(l13 l12 l13 l14)
|
||||
C(l14 l13 l14 l17)
|
||||
C(l17 l14 l17)
|
||||
C(l7 l7)
|
||||
C(l10 l3 l8 l10)
|
||||
CS(l10 l3)
|
||||
C(l2 l8 l2)
|
||||
C(l9 l8 l9)
|
||||
C(l6 l8 l6)
|
||||
G(l7 SUBSTRATE)
|
||||
G(l9 SUBSTRATE)
|
||||
GS(l9 SUBSTRATE)
|
||||
K(PMOS MOS4)
|
||||
K(NMOS MOS4)
|
||||
D(D$PMOS PMOS
|
||||
T(S
|
||||
R(l2 (-900 -475) (775 950))
|
||||
)
|
||||
T(G
|
||||
R(l4 (-125 -475) (250 950))
|
||||
)
|
||||
T(D
|
||||
R(l2 (125 -475) (775 950))
|
||||
)
|
||||
T(B
|
||||
R(l3 (-125 -475) (250 950))
|
||||
)
|
||||
)
|
||||
D(D$NMOS NMOS
|
||||
T(S
|
||||
R(l6 (-900 -475) (775 950))
|
||||
)
|
||||
T(G
|
||||
R(l4 (-125 -475) (250 950))
|
||||
)
|
||||
T(D
|
||||
R(l6 (125 -475) (775 950))
|
||||
)
|
||||
T(B
|
||||
R(l7 (-125 -475) (250 950))
|
||||
)
|
||||
)
|
||||
X(INV
|
||||
R((-1500 -800) (3000 4600))
|
||||
N(1
|
||||
R(l8 (290 -310) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (-290 -690) (360 760))
|
||||
R(l13 (-305 -705) (250 250))
|
||||
R(l13 (-250 150) (250 250))
|
||||
R(l14 (-2025 -775) (3000 900))
|
||||
R(l6 (-1375 -925) (775 950))
|
||||
)
|
||||
N(2
|
||||
R(l8 (290 2490) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (-290 -690) (360 760))
|
||||
R(l13 (-305 -705) (250 250))
|
||||
R(l13 (-250 150) (250 250))
|
||||
R(l14 (-2025 -775) (3000 900))
|
||||
R(l2 (-1375 -925) (775 950))
|
||||
)
|
||||
N(3
|
||||
R(l3 (-1500 1800) (3000 2000))
|
||||
)
|
||||
N(4
|
||||
R(l4 (-125 -250) (250 2500))
|
||||
R(l4 (-250 -3050) (250 1600))
|
||||
R(l4 (-250 1200) (250 1600))
|
||||
)
|
||||
N(5
|
||||
R(l8 (-510 -310) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l8 (-220 2180) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (-290 -3530) (360 2840))
|
||||
R(l12 (-360 -2800) (360 760))
|
||||
R(l12 (-360 2040) (360 760))
|
||||
R(l2 (-680 -855) (775 950))
|
||||
R(l6 (-775 -3750) (775 950))
|
||||
)
|
||||
N(6 I(SUBSTRATE))
|
||||
P(1)
|
||||
P(2)
|
||||
P(3)
|
||||
P(4)
|
||||
P(5)
|
||||
P(6 I(SUBSTRATE))
|
||||
D(1 D$PMOS
|
||||
Y(0 2800)
|
||||
E(L 0.25)
|
||||
E(W 0.95)
|
||||
E(AS 0.73625)
|
||||
E(AD 0.73625)
|
||||
E(PS 3.45)
|
||||
E(PD 3.45)
|
||||
T(S 5)
|
||||
T(G 4)
|
||||
T(D 2)
|
||||
T(B 3)
|
||||
)
|
||||
D(2 D$NMOS
|
||||
Y(0 0)
|
||||
E(L 0.25)
|
||||
E(W 0.95)
|
||||
E(AS 0.73625)
|
||||
E(AD 0.73625)
|
||||
E(PS 3.45)
|
||||
E(PD 3.45)
|
||||
T(S 5)
|
||||
T(G 4)
|
||||
T(D 1)
|
||||
T(B 6)
|
||||
)
|
||||
)
|
||||
X(TOP
|
||||
R((600 800) (8880 4600))
|
||||
N(1
|
||||
R(l4 (2920 2600) (2880 400))
|
||||
R(l11 (-300 -300) (200 200))
|
||||
R(l12 (-300 -300) (690 400))
|
||||
)
|
||||
N(2 I(A)
|
||||
R(l4 (6600 2600) (2880 400))
|
||||
R(l15 (-2380 -200) (0 0))
|
||||
)
|
||||
N(3 I(Q)
|
||||
R(l12 (1810 2600) (690 400))
|
||||
R(l16 (-400 -200) (0 0))
|
||||
)
|
||||
N(4 I(VDD)
|
||||
R(l3 (4000 3400) (1600 2000))
|
||||
R(l3 (-5000 -2000) (1000 2000))
|
||||
R(l3 (6400 -2000) (1000 2000))
|
||||
R(l8 (-8000 -900) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l8 (7200 200) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l12 (-7900 -350) (800 900))
|
||||
R(l12 (6600 -900) (800 900))
|
||||
R(l13 (-7900 -350) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l13 (7200 200) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l14 (-4400 -350) (1200 900))
|
||||
R(l14 (-4800 -900) (1000 900))
|
||||
R(l14 (6400 -900) (1000 900))
|
||||
R(l17 (-4800 -450) (0 0))
|
||||
)
|
||||
N(5 I('SUBSTRATE,VSS')
|
||||
R(l8 (1000 1700) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l8 (7200 200) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l12 (-7900 -350) (800 900))
|
||||
R(l12 (6600 -900) (800 900))
|
||||
R(l13 (-7900 -350) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l13 (7200 200) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l14 (-4400 -350) (1200 900))
|
||||
R(l14 (-4800 -900) (1000 900))
|
||||
R(l14 (6400 -900) (1000 900))
|
||||
R(l17 (-4800 -550) (0 0))
|
||||
)
|
||||
P(2 I(A))
|
||||
P(3 I(Q))
|
||||
P(4 I(VDD))
|
||||
P(5 I('SUBSTRATE,VSS'))
|
||||
X(1 INV Y(3000 1600)
|
||||
P(0 5)
|
||||
P(1 4)
|
||||
P(2 4)
|
||||
P(3 1)
|
||||
P(4 3)
|
||||
P(5 5)
|
||||
)
|
||||
X(2 INV Y(6600 1600)
|
||||
P(0 5)
|
||||
P(1 4)
|
||||
P(2 4)
|
||||
P(3 2)
|
||||
P(4 1)
|
||||
P(5 5)
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
|
||||
$lvs_test_source && source($lvs_test_source)
|
||||
|
||||
if $lvs_test_target_l2n
|
||||
report_netlist($lvs_test_target_l2n)
|
||||
else
|
||||
report_netlist
|
||||
end
|
||||
|
||||
writer = write_spice(true, false)
|
||||
$lvs_test_target_cir && target_netlist($lvs_test_target_cir, writer, "Extracted by KLayout")
|
||||
|
||||
deep
|
||||
|
||||
# Drawing layers
|
||||
|
||||
nwell = input(1, 0)
|
||||
active = input(2, 0)
|
||||
nplus = input(2, 1)
|
||||
pplus = input(2, 2)
|
||||
poly = input(3, 0)
|
||||
poly_lbl = input(3, 1)
|
||||
diff_cont = input(4, 0)
|
||||
poly_cont = input(5, 0)
|
||||
metal1 = input(6, 0)
|
||||
metal1_lbl = input(6, 1)
|
||||
via1 = input(7, 0)
|
||||
metal2 = input(8, 0)
|
||||
metal2_lbl = input(8, 1)
|
||||
|
||||
# Bulk layer for terminal provisioning
|
||||
|
||||
bulk = polygon_layer
|
||||
|
||||
psd = nil
|
||||
nsd = nil
|
||||
|
||||
# Computed layers
|
||||
|
||||
active_in_nwell = active & nwell
|
||||
pactive = active_in_nwell & pplus
|
||||
ntie = active_in_nwell & nplus
|
||||
pgate = pactive & poly
|
||||
psd = pactive - pgate
|
||||
|
||||
active_outside_nwell = active - nwell
|
||||
nactive = active_outside_nwell & nplus
|
||||
ptie = active_outside_nwell & pplus
|
||||
ngate = nactive & poly
|
||||
nsd = nactive - ngate
|
||||
|
||||
# Device extraction
|
||||
|
||||
# PMOS transistor device extraction
|
||||
extract_devices(mos4("PMOS"), { "SD" => psd, "G" => pgate, "W" => nwell,
|
||||
"tS" => psd, "tD" => psd, "tG" => poly })
|
||||
|
||||
# NMOS transistor device extraction
|
||||
extract_devices(mos4("NMOS"), { "SD" => nsd, "G" => ngate, "W" => bulk,
|
||||
"tS" => nsd, "tD" => nsd, "tG" => poly })
|
||||
|
||||
# Define connectivity for netlist extraction
|
||||
|
||||
# Inter-layer
|
||||
|
||||
soft_connect(diff_cont, psd)
|
||||
soft_connect(diff_cont, nsd)
|
||||
soft_connect(diff_cont, ptie)
|
||||
soft_connect(diff_cont, ntie)
|
||||
soft_connect(ntie, nwell)
|
||||
soft_connect(poly_cont, poly)
|
||||
|
||||
connect(diff_cont, metal1)
|
||||
connect(poly_cont, metal1)
|
||||
connect(metal1, via1)
|
||||
connect(via1, metal2)
|
||||
|
||||
# attach labels
|
||||
connect(poly, poly_lbl)
|
||||
connect(metal1, metal1_lbl)
|
||||
connect(metal2, metal2_lbl)
|
||||
|
||||
# Global
|
||||
connect_global(bulk, "SUBSTRATE")
|
||||
soft_connect_global(ptie, "SUBSTRATE")
|
||||
|
||||
# Netlist section (NOTE: we only check log here)
|
||||
netlist
|
||||
|
||||
netlist.simplify
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
* Extracted by KLayout
|
||||
|
||||
.SUBCKT TOP A Q VDD SUBSTRATE|VSS
|
||||
X$1 SUBSTRATE|VSS VDD VDD \$1 Q SUBSTRATE|VSS INV
|
||||
X$2 SUBSTRATE|VSS VDD VDD A \$1 SUBSTRATE|VSS INV
|
||||
.ENDS TOP
|
||||
|
||||
.SUBCKT INV \$1 \$2 \$3 \$4 \$5 SUBSTRATE
|
||||
X$1 \$5 \$1 \$4 SUBSTRATE NTRANS
|
||||
X$2 \$5 \$2 \$4 \$3 PTRANS
|
||||
.ENDS INV
|
||||
|
||||
.SUBCKT PTRANS \$1 \$3 \$5 \$I3
|
||||
M$1 \$3 \$5 \$1 \$I3 PMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U
|
||||
+ PD=3.45U
|
||||
.ENDS PTRANS
|
||||
|
||||
.SUBCKT NTRANS \$1 \$3 \$5 SUBSTRATE
|
||||
M$1 \$3 \$5 \$1 SUBSTRATE NMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U
|
||||
+ PD=3.45U
|
||||
.ENDS NTRANS
|
||||
Binary file not shown.
|
|
@ -0,0 +1,257 @@
|
|||
#%l2n-klayout
|
||||
W(TOP)
|
||||
U(0.001)
|
||||
L(l3 '1/0')
|
||||
L(l4 '3/0')
|
||||
L(l15 '3/1')
|
||||
L(l8 '4/0')
|
||||
L(l11 '5/0')
|
||||
L(l12 '6/0')
|
||||
L(l16 '6/1')
|
||||
L(l13 '7/0')
|
||||
L(l14 '8/0')
|
||||
L(l17 '8/1')
|
||||
L(l7)
|
||||
L(l10)
|
||||
L(l2)
|
||||
L(l9)
|
||||
L(l6)
|
||||
C(l3 l3 l10)
|
||||
C(l4 l4 l15 l11)
|
||||
C(l15 l4 l15)
|
||||
C(l8 l8 l12 l10 l2 l9 l6)
|
||||
CS(l8 l10 l2 l9 l6)
|
||||
C(l11 l4 l11 l12)
|
||||
CS(l11 l4)
|
||||
C(l12 l8 l11 l12 l16 l13)
|
||||
C(l16 l12 l16)
|
||||
C(l13 l12 l13 l14)
|
||||
C(l14 l13 l14 l17)
|
||||
C(l17 l14 l17)
|
||||
C(l7 l7)
|
||||
C(l10 l3 l8 l10)
|
||||
CS(l10 l3)
|
||||
C(l2 l8 l2)
|
||||
C(l9 l8 l9)
|
||||
C(l6 l8 l6)
|
||||
G(l7 SUBSTRATE)
|
||||
G(l9 SUBSTRATE)
|
||||
GS(l9 SUBSTRATE)
|
||||
H(W B('Net with incomplete wiring (soft-connected partial nets)') C(TOP) X('soft-connection-check'))
|
||||
H(B('\tPartial net #1: TOP - VDD') C(TOP) Q('(0.6,3.95;0.6,4.85;4.5,4.85;4.5,3.95)'))
|
||||
H(B('\tPartial net #2: TOP - $I4') C(TOP) Q('(5.1,3.95;5.1,4.85;9,4.85;9,3.95)'))
|
||||
H(W B('Net with incomplete wiring (soft-connected partial nets)') C(TOP) X('soft-connection-check'))
|
||||
H(B('\tPartial net #1: TOP - VSS') C(TOP) Q('(0.6,1.15;0.6,2.05;4.5,2.05;4.5,1.15)'))
|
||||
H(B('\tPartial net #2: TOP - $I1') C(TOP) Q('(5.1,1.15;5.1,2.05;9,2.05;9,1.15)'))
|
||||
K(PMOS MOS4)
|
||||
K(NMOS MOS4)
|
||||
D(D$PMOS PMOS
|
||||
T(S
|
||||
R(l2 (-900 -475) (775 950))
|
||||
)
|
||||
T(G
|
||||
R(l4 (-125 -475) (250 950))
|
||||
)
|
||||
T(D
|
||||
R(l2 (125 -475) (775 950))
|
||||
)
|
||||
T(B
|
||||
R(l3 (-125 -475) (250 950))
|
||||
)
|
||||
)
|
||||
D(D$NMOS NMOS
|
||||
T(S
|
||||
R(l6 (-900 -475) (775 950))
|
||||
)
|
||||
T(G
|
||||
R(l4 (-125 -475) (250 950))
|
||||
)
|
||||
T(D
|
||||
R(l6 (125 -475) (775 950))
|
||||
)
|
||||
T(B
|
||||
R(l7 (-125 -475) (250 950))
|
||||
)
|
||||
)
|
||||
X(NTRANS
|
||||
R((-1000 -800) (2000 1600))
|
||||
N(1
|
||||
R(l8 (-510 -310) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (-290 -690) (360 760))
|
||||
R(l6 (-680 -855) (775 950))
|
||||
)
|
||||
N(2
|
||||
R(l8 (290 -310) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (-290 -690) (360 760))
|
||||
R(l6 (-455 -855) (775 950))
|
||||
)
|
||||
N(3
|
||||
R(l4 (-125 -800) (250 1600))
|
||||
)
|
||||
N(4 I(SUBSTRATE))
|
||||
P(1)
|
||||
P(2)
|
||||
P(3)
|
||||
P(4 I(SUBSTRATE))
|
||||
D(1 D$NMOS
|
||||
Y(0 0)
|
||||
E(L 0.25)
|
||||
E(W 0.95)
|
||||
E(AS 0.73625)
|
||||
E(AD 0.73625)
|
||||
E(PS 3.45)
|
||||
E(PD 3.45)
|
||||
T(S 1)
|
||||
T(G 3)
|
||||
T(D 2)
|
||||
T(B 4)
|
||||
)
|
||||
)
|
||||
X(PTRANS
|
||||
R((-1000 -800) (2000 1600))
|
||||
N(1
|
||||
R(l8 (-510 -310) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (-290 -690) (360 760))
|
||||
R(l2 (-680 -855) (775 950))
|
||||
)
|
||||
N(2
|
||||
R(l8 (290 -310) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (-290 -690) (360 760))
|
||||
R(l2 (-455 -855) (775 950))
|
||||
)
|
||||
N(3
|
||||
R(l4 (-125 -800) (250 1600))
|
||||
)
|
||||
N(4)
|
||||
P(1)
|
||||
P(2)
|
||||
P(3)
|
||||
P(4)
|
||||
D(1 D$PMOS
|
||||
Y(0 0)
|
||||
E(L 0.25)
|
||||
E(W 0.95)
|
||||
E(AS 0.73625)
|
||||
E(AD 0.73625)
|
||||
E(PS 3.45)
|
||||
E(PD 3.45)
|
||||
T(S 1)
|
||||
T(G 3)
|
||||
T(D 2)
|
||||
T(B 4)
|
||||
)
|
||||
)
|
||||
X(INV
|
||||
R((-1500 -800) (3000 4600))
|
||||
N(1
|
||||
R(l13 (275 -325) (250 250))
|
||||
R(l13 (-250 150) (250 250))
|
||||
R(l14 (-2025 -775) (3000 900))
|
||||
)
|
||||
N(2
|
||||
R(l13 (275 2475) (250 250))
|
||||
R(l13 (-250 150) (250 250))
|
||||
R(l14 (-2025 -775) (3000 900))
|
||||
)
|
||||
N(3
|
||||
R(l3 (-1500 1800) (3000 2000))
|
||||
)
|
||||
N(4
|
||||
R(l4 (-125 -250) (250 2500))
|
||||
)
|
||||
N(5
|
||||
R(l12 (-580 -420) (360 2840))
|
||||
)
|
||||
N(6 I(SUBSTRATE))
|
||||
P(1)
|
||||
P(2)
|
||||
P(3)
|
||||
P(4)
|
||||
P(5)
|
||||
P(6 I(SUBSTRATE))
|
||||
X(1 NTRANS Y(0 0)
|
||||
P(0 5)
|
||||
P(1 1)
|
||||
P(2 4)
|
||||
P(3 6)
|
||||
)
|
||||
X(2 PTRANS Y(0 2800)
|
||||
P(0 5)
|
||||
P(1 2)
|
||||
P(2 4)
|
||||
P(3 3)
|
||||
)
|
||||
)
|
||||
X(TOP
|
||||
R((600 800) (8880 4600))
|
||||
N(1
|
||||
R(l4 (2920 2600) (2880 400))
|
||||
R(l11 (-300 -300) (200 200))
|
||||
R(l12 (-300 -300) (690 400))
|
||||
)
|
||||
N(2 I(A)
|
||||
R(l4 (6600 2600) (2880 400))
|
||||
R(l15 (-2380 -200) (0 0))
|
||||
)
|
||||
N(3 I(Q)
|
||||
R(l12 (1810 2600) (690 400))
|
||||
R(l16 (-400 -200) (0 0))
|
||||
)
|
||||
N(4 I(VDD)
|
||||
R(l3 (4000 3400) (1600 2000))
|
||||
R(l3 (-5000 -2000) (1000 2000))
|
||||
R(l3 (6400 -2000) (1000 2000))
|
||||
R(l8 (-8000 -900) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l8 (7200 200) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l12 (-7900 -350) (800 900))
|
||||
R(l12 (6600 -900) (800 900))
|
||||
R(l13 (-7900 -350) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l13 (7200 200) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l14 (-8000 -350) (1000 900))
|
||||
R(l14 (6400 -900) (1000 900))
|
||||
R(l17 (-4800 -450) (0 0))
|
||||
)
|
||||
N(5 I('SUBSTRATE,VSS')
|
||||
R(l8 (1000 1700) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l8 (7200 200) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l12 (-7900 -350) (800 900))
|
||||
R(l12 (6600 -900) (800 900))
|
||||
R(l13 (-7900 -350) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l13 (7200 200) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l14 (-8000 -350) (1000 900))
|
||||
R(l14 (6400 -900) (1000 900))
|
||||
R(l17 (-4800 -550) (0 0))
|
||||
)
|
||||
P(2 I(A))
|
||||
P(3 I(Q))
|
||||
P(4 I(VDD))
|
||||
P(5 I('SUBSTRATE,VSS'))
|
||||
X(1 INV Y(3000 1600)
|
||||
P(0 5)
|
||||
P(1 4)
|
||||
P(2 4)
|
||||
P(3 1)
|
||||
P(4 3)
|
||||
P(5 5)
|
||||
)
|
||||
X(2 INV Y(6600 1600)
|
||||
P(0 5)
|
||||
P(1 4)
|
||||
P(2 4)
|
||||
P(3 2)
|
||||
P(4 1)
|
||||
P(5 5)
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
|
||||
$lvs_test_source && source($lvs_test_source)
|
||||
|
||||
if $lvs_test_target_l2n
|
||||
report_netlist($lvs_test_target_l2n)
|
||||
else
|
||||
report_netlist
|
||||
end
|
||||
|
||||
writer = write_spice(true, false)
|
||||
$lvs_test_target_cir && target_netlist($lvs_test_target_cir, writer, "Extracted by KLayout")
|
||||
|
||||
deep
|
||||
|
||||
# Drawing layers
|
||||
|
||||
nwell = input(1, 0)
|
||||
active = input(2, 0)
|
||||
nplus = input(2, 1)
|
||||
pplus = input(2, 2)
|
||||
poly = input(3, 0)
|
||||
poly_lbl = input(3, 1)
|
||||
diff_cont = input(4, 0)
|
||||
poly_cont = input(5, 0)
|
||||
metal1 = input(6, 0)
|
||||
metal1_lbl = input(6, 1)
|
||||
via1 = input(7, 0)
|
||||
metal2 = input(8, 0)
|
||||
metal2_lbl = input(8, 1)
|
||||
|
||||
# Bulk layer for terminal provisioning
|
||||
|
||||
bulk = polygon_layer
|
||||
|
||||
psd = nil
|
||||
nsd = nil
|
||||
|
||||
# Computed layers
|
||||
|
||||
active_in_nwell = active & nwell
|
||||
pactive = active_in_nwell & pplus
|
||||
ntie = active_in_nwell & nplus
|
||||
pgate = pactive & poly
|
||||
psd = pactive - pgate
|
||||
|
||||
active_outside_nwell = active - nwell
|
||||
nactive = active_outside_nwell & nplus
|
||||
ptie = active_outside_nwell & pplus
|
||||
ngate = nactive & poly
|
||||
nsd = nactive - ngate
|
||||
|
||||
# Device extraction
|
||||
|
||||
# PMOS transistor device extraction
|
||||
extract_devices(mos4("PMOS"), { "SD" => psd, "G" => pgate, "W" => nwell,
|
||||
"tS" => psd, "tD" => psd, "tG" => poly })
|
||||
|
||||
# NMOS transistor device extraction
|
||||
extract_devices(mos4("NMOS"), { "SD" => nsd, "G" => ngate, "W" => bulk,
|
||||
"tS" => nsd, "tD" => nsd, "tG" => poly })
|
||||
|
||||
# Define connectivity for netlist extraction
|
||||
|
||||
# Inter-layer
|
||||
|
||||
soft_connect(diff_cont, psd)
|
||||
soft_connect(diff_cont, nsd)
|
||||
soft_connect(diff_cont, ptie)
|
||||
soft_connect(diff_cont, ntie)
|
||||
soft_connect(ntie, nwell)
|
||||
soft_connect(poly_cont, poly)
|
||||
|
||||
connect(diff_cont, metal1)
|
||||
connect(poly_cont, metal1)
|
||||
connect(metal1, via1)
|
||||
connect(via1, metal2)
|
||||
|
||||
# attach labels
|
||||
connect(poly, poly_lbl)
|
||||
connect(metal1, metal1_lbl)
|
||||
connect(metal2, metal2_lbl)
|
||||
|
||||
# Global
|
||||
connect_global(bulk, "SUBSTRATE")
|
||||
soft_connect_global(ptie, "SUBSTRATE")
|
||||
|
||||
# Netlist section (NOTE: we only check log here)
|
||||
netlist
|
||||
|
||||
netlist.simplify
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
* Extracted by KLayout
|
||||
|
||||
.SUBCKT TOP A Q SUBSTRATE
|
||||
X$1 \$5 \$1 Q SUBSTRATE INV
|
||||
X$2 \$5 A \$1 SUBSTRATE INV
|
||||
.ENDS TOP
|
||||
|
||||
.SUBCKT INV \$2 \$4 \$5 SUBSTRATE
|
||||
M$1 \$2 \$4 \$5 \$2 PMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U
|
||||
+ PD=3.45U
|
||||
M$2 SUBSTRATE \$4 \$5 SUBSTRATE NMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P
|
||||
+ PS=3.45U PD=3.45U
|
||||
.ENDS INV
|
||||
Binary file not shown.
|
|
@ -0,0 +1,192 @@
|
|||
#%l2n-klayout
|
||||
W(TOP)
|
||||
U(0.001)
|
||||
L(l3 '1/0')
|
||||
L(l4 '3/0')
|
||||
L(l15 '3/1')
|
||||
L(l8 '4/0')
|
||||
L(l11 '5/0')
|
||||
L(l12 '6/0')
|
||||
L(l16 '6/1')
|
||||
L(l13 '7/0')
|
||||
L(l14 '8/0')
|
||||
L(l17)
|
||||
L(l7)
|
||||
L(l10)
|
||||
L(l2)
|
||||
L(l9)
|
||||
L(l6)
|
||||
C(l3 l3 l10)
|
||||
C(l4 l4 l15 l11)
|
||||
C(l15 l4 l15)
|
||||
C(l8 l8 l12 l10 l2 l9 l6)
|
||||
CS(l8 l10 l2 l9 l6)
|
||||
C(l11 l4 l11 l12)
|
||||
CS(l11 l4)
|
||||
C(l12 l8 l11 l12 l16 l13)
|
||||
C(l16 l12 l16)
|
||||
C(l13 l12 l13 l14)
|
||||
C(l14 l13 l14 l17)
|
||||
C(l17 l14 l17)
|
||||
C(l7 l7)
|
||||
C(l10 l3 l8 l10)
|
||||
CS(l10 l3)
|
||||
C(l2 l8 l2)
|
||||
C(l9 l8 l9)
|
||||
C(l6 l8 l6)
|
||||
G(l7 SUBSTRATE)
|
||||
G(l9 SUBSTRATE)
|
||||
GS(l9 SUBSTRATE)
|
||||
H(W B('Net with incomplete wiring (soft-connected partial nets)') C(TOP) X('soft-connection-check'))
|
||||
H(B('\tPartial net #1: TOP/INV[r0 3,1.6]:$1 - $2') C(TOP) Q('(1.5,3.95;1.5,4.85;5.3,4.85;5.3,3.95)'))
|
||||
H(B('\tPartial net #2: TOP/INV[r0 7.7,1.6]:$2 - $2') C(TOP) Q('(6.2,3.95;6.2,4.85;10,4.85;10,3.95)'))
|
||||
H(W B('Net with incomplete wiring (soft-connected partial nets)') C(TOP) X('soft-connection-check'))
|
||||
H(B('\tPartial net #1: TOP/INV[r0 3,1.6]:$1 - $1') C(TOP) Q('(1.5,1.15;1.5,2.05;5.3,2.05;5.3,1.15)'))
|
||||
H(B('\tPartial net #2: TOP/INV[r0 7.7,1.6]:$2 - $1') C(TOP) Q('(6.2,1.15;6.2,2.05;10,2.05;10,1.15)'))
|
||||
K(PMOS MOS4)
|
||||
K(NMOS MOS4)
|
||||
D(D$PMOS PMOS
|
||||
T(S
|
||||
R(l2 (-900 -475) (775 950))
|
||||
)
|
||||
T(G
|
||||
R(l4 (-125 -475) (250 950))
|
||||
)
|
||||
T(D
|
||||
R(l2 (125 -475) (775 950))
|
||||
)
|
||||
T(B
|
||||
R(l3 (-125 -475) (250 950))
|
||||
)
|
||||
)
|
||||
D(D$NMOS NMOS
|
||||
T(S
|
||||
R(l6 (-900 -475) (775 950))
|
||||
)
|
||||
T(G
|
||||
R(l4 (-125 -475) (250 950))
|
||||
)
|
||||
T(D
|
||||
R(l6 (125 -475) (775 950))
|
||||
)
|
||||
T(B
|
||||
R(l7 (-125 -475) (250 950))
|
||||
)
|
||||
)
|
||||
X(INV
|
||||
R((-1500 -800) (3800 4600))
|
||||
N(1 I(SUBSTRATE)
|
||||
R(l8 (1700 100) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l8 (-1610 -210) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (890 -760) (800 900))
|
||||
R(l12 (-1980 -830) (360 760))
|
||||
R(l13 (-305 -705) (250 250))
|
||||
R(l13 (-250 150) (250 250))
|
||||
R(l13 (1175 -225) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l14 (-3400 -350) (3000 900))
|
||||
R(l14 (-200 -900) (1000 900))
|
||||
R(l6 (-2175 -925) (775 950))
|
||||
)
|
||||
N(2
|
||||
R(l3 (-1500 1800) (3000 2000))
|
||||
R(l3 (-200 -2000) (1000 2000))
|
||||
R(l8 (-2010 -1310) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l8 (1190 -210) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l12 (-1680 -280) (360 760))
|
||||
R(l12 (820 -830) (800 900))
|
||||
R(l13 (-1925 -775) (250 250))
|
||||
R(l13 (-250 150) (250 250))
|
||||
R(l13 (1175 -225) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l14 (-3400 -350) (3000 900))
|
||||
R(l14 (-200 -900) (1000 900))
|
||||
R(l10 (-700 -950) (400 1000))
|
||||
R(l2 (-1875 -975) (775 950))
|
||||
)
|
||||
N(3
|
||||
R(l4 (-125 -250) (250 2500))
|
||||
R(l4 (-250 -3050) (250 1600))
|
||||
R(l4 (-250 1200) (250 1600))
|
||||
)
|
||||
N(4
|
||||
R(l8 (-510 -310) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l8 (-220 2180) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (-290 -3530) (360 2840))
|
||||
R(l12 (-360 -2800) (360 760))
|
||||
R(l12 (-360 2040) (360 760))
|
||||
R(l2 (-680 -855) (775 950))
|
||||
R(l6 (-775 -3750) (775 950))
|
||||
)
|
||||
P(2)
|
||||
P(3)
|
||||
P(4)
|
||||
P(1 I(SUBSTRATE))
|
||||
D(1 D$PMOS
|
||||
Y(0 2800)
|
||||
E(L 0.25)
|
||||
E(W 0.95)
|
||||
E(AS 0.73625)
|
||||
E(AD 0.73625)
|
||||
E(PS 3.45)
|
||||
E(PD 3.45)
|
||||
T(S 4)
|
||||
T(G 3)
|
||||
T(D 2)
|
||||
T(B 2)
|
||||
)
|
||||
D(2 D$NMOS
|
||||
Y(0 0)
|
||||
E(L 0.25)
|
||||
E(W 0.95)
|
||||
E(AS 0.73625)
|
||||
E(AD 0.73625)
|
||||
E(PS 3.45)
|
||||
E(PD 3.45)
|
||||
T(S 4)
|
||||
T(G 3)
|
||||
T(D 1)
|
||||
T(B 1)
|
||||
)
|
||||
)
|
||||
X(TOP
|
||||
R((1500 800) (9080 4600))
|
||||
N(1
|
||||
R(l4 (2920 2600) (3980 400))
|
||||
R(l11 (-300 -300) (200 200))
|
||||
R(l12 (-300 -300) (690 400))
|
||||
)
|
||||
N(2 I(A)
|
||||
R(l4 (7700 2600) (2880 400))
|
||||
R(l15 (-2380 -200) (0 0))
|
||||
)
|
||||
N(3 I(Q)
|
||||
R(l12 (1810 2600) (690 400))
|
||||
R(l16 (-400 -200) (0 0))
|
||||
)
|
||||
N(4
|
||||
R(l3 (4000 3400) (2700 2000))
|
||||
)
|
||||
N(5 I(SUBSTRATE))
|
||||
P(2 I(A))
|
||||
P(3 I(Q))
|
||||
P(5 I(SUBSTRATE))
|
||||
X(1 INV Y(3000 1600)
|
||||
P(0 4)
|
||||
P(1 1)
|
||||
P(2 3)
|
||||
P(3 5)
|
||||
)
|
||||
X(2 INV Y(7700 1600)
|
||||
P(0 4)
|
||||
P(1 2)
|
||||
P(2 1)
|
||||
P(3 5)
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
|
||||
$lvs_test_source && source($lvs_test_source)
|
||||
|
||||
if $lvs_test_target_l2n
|
||||
report_netlist($lvs_test_target_l2n)
|
||||
else
|
||||
report_netlist
|
||||
end
|
||||
|
||||
writer = write_spice(true, false)
|
||||
$lvs_test_target_cir && target_netlist($lvs_test_target_cir, writer, "Extracted by KLayout")
|
||||
|
||||
deep
|
||||
|
||||
# Drawing layers
|
||||
|
||||
nwell = input(1, 0)
|
||||
active = input(2, 0)
|
||||
nplus = input(2, 1)
|
||||
pplus = input(2, 2)
|
||||
poly = input(3, 0)
|
||||
poly_lbl = input(3, 1)
|
||||
diff_cont = input(4, 0)
|
||||
poly_cont = input(5, 0)
|
||||
metal1 = input(6, 0)
|
||||
metal1_lbl = input(6, 1)
|
||||
via1 = input(7, 0)
|
||||
metal2 = input(8, 0)
|
||||
metal2_lbl = input(8, 1)
|
||||
|
||||
# Bulk layer for terminal provisioning
|
||||
|
||||
bulk = polygon_layer
|
||||
|
||||
psd = nil
|
||||
nsd = nil
|
||||
|
||||
# Computed layers
|
||||
|
||||
active_in_nwell = active & nwell
|
||||
pactive = active_in_nwell & pplus
|
||||
ntie = active_in_nwell & nplus
|
||||
pgate = pactive & poly
|
||||
psd = pactive - pgate
|
||||
|
||||
active_outside_nwell = active - nwell
|
||||
nactive = active_outside_nwell & nplus
|
||||
ptie = active_outside_nwell & pplus
|
||||
ngate = nactive & poly
|
||||
nsd = nactive - ngate
|
||||
|
||||
# Device extraction
|
||||
|
||||
# PMOS transistor device extraction
|
||||
extract_devices(mos4("PMOS"), { "SD" => psd, "G" => pgate, "W" => nwell,
|
||||
"tS" => psd, "tD" => psd, "tG" => poly })
|
||||
|
||||
# NMOS transistor device extraction
|
||||
extract_devices(mos4("NMOS"), { "SD" => nsd, "G" => ngate, "W" => bulk,
|
||||
"tS" => nsd, "tD" => nsd, "tG" => poly })
|
||||
|
||||
# Define connectivity for netlist extraction
|
||||
|
||||
# Inter-layer
|
||||
|
||||
soft_connect(diff_cont, psd)
|
||||
soft_connect(diff_cont, nsd)
|
||||
soft_connect(diff_cont, ptie)
|
||||
soft_connect(diff_cont, ntie)
|
||||
soft_connect(ntie, nwell)
|
||||
soft_connect(poly_cont, poly)
|
||||
|
||||
connect(diff_cont, metal1)
|
||||
connect(poly_cont, metal1)
|
||||
connect(metal1, via1)
|
||||
connect(via1, metal2)
|
||||
|
||||
# attach labels
|
||||
connect(poly, poly_lbl)
|
||||
connect(metal1, metal1_lbl)
|
||||
connect(metal2, metal2_lbl)
|
||||
|
||||
# Global
|
||||
connect_global(bulk, "SUBSTRATE")
|
||||
soft_connect_global(ptie, "SUBSTRATE")
|
||||
|
||||
# Netlist section (NOTE: we only check log here)
|
||||
# for debugging: _make_soft_connection_diodes(true)
|
||||
netlist
|
||||
|
||||
netlist.simplify
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
* Extracted by KLayout
|
||||
|
||||
.SUBCKT TOP A Q VDD SUBSTRATE|VSS
|
||||
X$1 SUBSTRATE|VSS VDD \$1 Q INV
|
||||
X$2 SUBSTRATE|VSS VDD A \$1 INV
|
||||
.ENDS TOP
|
||||
|
||||
.SUBCKT INV SUBSTRATE \$2 \$4 \$5
|
||||
M$1 \$2 \$4 \$5 \$2 PMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U
|
||||
+ PD=3.45U
|
||||
M$2 SUBSTRATE \$4 \$5 SUBSTRATE NMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P
|
||||
+ PS=3.45U PD=3.45U
|
||||
.ENDS INV
|
||||
Binary file not shown.
|
|
@ -0,0 +1,196 @@
|
|||
#%l2n-klayout
|
||||
W(TOP)
|
||||
U(0.001)
|
||||
L(l3 '1/0')
|
||||
L(l4 '3/0')
|
||||
L(l15 '3/1')
|
||||
L(l8 '4/0')
|
||||
L(l11 '5/0')
|
||||
L(l12 '6/0')
|
||||
L(l16 '6/1')
|
||||
L(l13 '7/0')
|
||||
L(l14 '8/0')
|
||||
L(l17 '8/1')
|
||||
L(l7)
|
||||
L(l10)
|
||||
L(l2)
|
||||
L(l9)
|
||||
L(l6)
|
||||
C(l3 l3 l10)
|
||||
C(l4 l4 l15 l11)
|
||||
C(l15 l4 l15)
|
||||
C(l8 l8 l12 l10 l2 l9 l6)
|
||||
CS(l8 l10 l2 l9 l6)
|
||||
C(l11 l4 l11 l12)
|
||||
CS(l11 l4)
|
||||
C(l12 l8 l11 l12 l16 l13)
|
||||
C(l16 l12 l16)
|
||||
C(l13 l12 l13 l14)
|
||||
C(l14 l13 l14 l17)
|
||||
C(l17 l14 l17)
|
||||
C(l7 l7)
|
||||
C(l10 l3 l8 l10)
|
||||
CS(l10 l3)
|
||||
C(l2 l8 l2)
|
||||
C(l9 l8 l9)
|
||||
C(l6 l8 l6)
|
||||
G(l7 SUBSTRATE)
|
||||
G(l9 SUBSTRATE)
|
||||
GS(l9 SUBSTRATE)
|
||||
H(W B('Net with incomplete wiring (soft-connected partial nets)') C(TOP) X('soft-connection-check'))
|
||||
H(B('\tPartial net #1: TOP - VDD') C(TOP) Q('(1.5,3.95;1.5,4.85;5.3,4.85;5.3,3.95)'))
|
||||
H(B('\tPartial net #2: TOP - $I7') C(TOP) Q('(6.2,3.95;6.2,4.85;10,4.85;10,3.95)'))
|
||||
H(W B('Net with incomplete wiring (soft-connected partial nets)') C(TOP) X('soft-connection-check'))
|
||||
H(B('\tPartial net #1: TOP - VSS') C(TOP) Q('(1.5,1.15;1.5,2.05;5.3,2.05;5.3,1.15)'))
|
||||
H(B('\tPartial net #2: TOP - $I6') C(TOP) Q('(6.2,1.15;6.2,2.05;10,2.05;10,1.15)'))
|
||||
K(PMOS MOS4)
|
||||
K(NMOS MOS4)
|
||||
D(D$PMOS PMOS
|
||||
T(S
|
||||
R(l2 (-900 -475) (775 950))
|
||||
)
|
||||
T(G
|
||||
R(l4 (-125 -475) (250 950))
|
||||
)
|
||||
T(D
|
||||
R(l2 (125 -475) (775 950))
|
||||
)
|
||||
T(B
|
||||
R(l3 (-125 -475) (250 950))
|
||||
)
|
||||
)
|
||||
D(D$NMOS NMOS
|
||||
T(S
|
||||
R(l6 (-900 -475) (775 950))
|
||||
)
|
||||
T(G
|
||||
R(l4 (-125 -475) (250 950))
|
||||
)
|
||||
T(D
|
||||
R(l6 (125 -475) (775 950))
|
||||
)
|
||||
T(B
|
||||
R(l7 (-125 -475) (250 950))
|
||||
)
|
||||
)
|
||||
X(INV
|
||||
R((-1500 -800) (3800 4600))
|
||||
N(1 I(SUBSTRATE)
|
||||
R(l8 (1700 100) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l8 (-1610 -210) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (890 -760) (800 900))
|
||||
R(l12 (-1980 -830) (360 760))
|
||||
R(l13 (-305 -705) (250 250))
|
||||
R(l13 (-250 150) (250 250))
|
||||
R(l13 (1175 -225) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l14 (-3400 -350) (3000 900))
|
||||
R(l14 (-200 -900) (1000 900))
|
||||
R(l6 (-2175 -925) (775 950))
|
||||
)
|
||||
N(2
|
||||
R(l3 (-1500 1800) (3000 2000))
|
||||
R(l3 (-200 -2000) (1000 2000))
|
||||
R(l8 (-2010 -1310) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l8 (1190 -210) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l12 (-1680 -280) (360 760))
|
||||
R(l12 (820 -830) (800 900))
|
||||
R(l13 (-1925 -775) (250 250))
|
||||
R(l13 (-250 150) (250 250))
|
||||
R(l13 (1175 -225) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l14 (-3400 -350) (3000 900))
|
||||
R(l14 (-200 -900) (1000 900))
|
||||
R(l10 (-700 -950) (400 1000))
|
||||
R(l2 (-1875 -975) (775 950))
|
||||
)
|
||||
N(3
|
||||
R(l4 (-125 -250) (250 2500))
|
||||
R(l4 (-250 -3050) (250 1600))
|
||||
R(l4 (-250 1200) (250 1600))
|
||||
)
|
||||
N(4
|
||||
R(l8 (-510 -310) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l8 (-220 2180) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (-290 -3530) (360 2840))
|
||||
R(l12 (-360 -2800) (360 760))
|
||||
R(l12 (-360 2040) (360 760))
|
||||
R(l2 (-680 -855) (775 950))
|
||||
R(l6 (-775 -3750) (775 950))
|
||||
)
|
||||
P(1 I(SUBSTRATE))
|
||||
P(2)
|
||||
P(3)
|
||||
P(4)
|
||||
D(1 D$PMOS
|
||||
Y(0 2800)
|
||||
E(L 0.25)
|
||||
E(W 0.95)
|
||||
E(AS 0.73625)
|
||||
E(AD 0.73625)
|
||||
E(PS 3.45)
|
||||
E(PD 3.45)
|
||||
T(S 4)
|
||||
T(G 3)
|
||||
T(D 2)
|
||||
T(B 2)
|
||||
)
|
||||
D(2 D$NMOS
|
||||
Y(0 0)
|
||||
E(L 0.25)
|
||||
E(W 0.95)
|
||||
E(AS 0.73625)
|
||||
E(AD 0.73625)
|
||||
E(PS 3.45)
|
||||
E(PD 3.45)
|
||||
T(S 4)
|
||||
T(G 3)
|
||||
T(D 1)
|
||||
T(B 1)
|
||||
)
|
||||
)
|
||||
X(TOP
|
||||
R((1500 800) (9080 4600))
|
||||
N(1
|
||||
R(l4 (2920 2600) (3980 400))
|
||||
R(l11 (-300 -300) (200 200))
|
||||
R(l12 (-300 -300) (690 400))
|
||||
)
|
||||
N(2 I(A)
|
||||
R(l4 (7700 2600) (2880 400))
|
||||
R(l15 (-2380 -200) (0 0))
|
||||
)
|
||||
N(3 I(Q)
|
||||
R(l12 (1810 2600) (690 400))
|
||||
R(l16 (-400 -200) (0 0))
|
||||
)
|
||||
N(4 I(VDD)
|
||||
R(l3 (4000 3400) (2700 2000))
|
||||
R(l17 (-2500 -1000) (0 0))
|
||||
)
|
||||
N(5 I('SUBSTRATE,VSS')
|
||||
R(l17 (4200 1500) (0 0))
|
||||
)
|
||||
P(2 I(A))
|
||||
P(3 I(Q))
|
||||
P(4 I(VDD))
|
||||
P(5 I('SUBSTRATE,VSS'))
|
||||
X(1 INV Y(3000 1600)
|
||||
P(0 5)
|
||||
P(1 4)
|
||||
P(2 1)
|
||||
P(3 3)
|
||||
)
|
||||
X(2 INV Y(7700 1600)
|
||||
P(0 5)
|
||||
P(1 4)
|
||||
P(2 2)
|
||||
P(3 1)
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
|
||||
$lvs_test_source && source($lvs_test_source)
|
||||
|
||||
if $lvs_test_target_l2n
|
||||
report_netlist($lvs_test_target_l2n)
|
||||
else
|
||||
report_netlist
|
||||
end
|
||||
|
||||
writer = write_spice(true, false)
|
||||
$lvs_test_target_cir && target_netlist($lvs_test_target_cir, writer, "Extracted by KLayout")
|
||||
|
||||
deep
|
||||
|
||||
# Drawing layers
|
||||
|
||||
nwell = input(1, 0)
|
||||
active = input(2, 0)
|
||||
nplus = input(2, 1)
|
||||
pplus = input(2, 2)
|
||||
poly = input(3, 0)
|
||||
poly_lbl = input(3, 1)
|
||||
diff_cont = input(4, 0)
|
||||
poly_cont = input(5, 0)
|
||||
metal1 = input(6, 0)
|
||||
metal1_lbl = input(6, 1)
|
||||
via1 = input(7, 0)
|
||||
metal2 = input(8, 0)
|
||||
metal2_lbl = input(8, 1)
|
||||
|
||||
# Bulk layer for terminal provisioning
|
||||
|
||||
bulk = polygon_layer
|
||||
|
||||
psd = nil
|
||||
nsd = nil
|
||||
|
||||
# Computed layers
|
||||
|
||||
active_in_nwell = active & nwell
|
||||
pactive = active_in_nwell & pplus
|
||||
ntie = active_in_nwell & nplus
|
||||
pgate = pactive & poly
|
||||
psd = pactive - pgate
|
||||
|
||||
active_outside_nwell = active - nwell
|
||||
nactive = active_outside_nwell & nplus
|
||||
ptie = active_outside_nwell & pplus
|
||||
ngate = nactive & poly
|
||||
nsd = nactive - ngate
|
||||
|
||||
# Device extraction
|
||||
|
||||
# PMOS transistor device extraction
|
||||
extract_devices(mos4("PMOS"), { "SD" => psd, "G" => pgate, "W" => nwell,
|
||||
"tS" => psd, "tD" => psd, "tG" => poly })
|
||||
|
||||
# NMOS transistor device extraction
|
||||
extract_devices(mos4("NMOS"), { "SD" => nsd, "G" => ngate, "W" => bulk,
|
||||
"tS" => nsd, "tD" => nsd, "tG" => poly })
|
||||
|
||||
# Define connectivity for netlist extraction
|
||||
|
||||
# Inter-layer
|
||||
|
||||
soft_connect(diff_cont, psd)
|
||||
soft_connect(diff_cont, nsd)
|
||||
soft_connect(diff_cont, ptie)
|
||||
soft_connect(diff_cont, ntie)
|
||||
soft_connect(ntie, nwell)
|
||||
soft_connect(poly_cont, poly)
|
||||
|
||||
connect(diff_cont, metal1)
|
||||
connect(poly_cont, metal1)
|
||||
connect(metal1, via1)
|
||||
connect(via1, metal2)
|
||||
|
||||
# attach labels
|
||||
connect(poly, poly_lbl)
|
||||
connect(metal1, metal1_lbl)
|
||||
connect(metal2, metal2_lbl)
|
||||
|
||||
# Global
|
||||
connect_global(bulk, "SUBSTRATE")
|
||||
soft_connect_global(ptie, "SUBSTRATE")
|
||||
|
||||
# Netlist section (NOTE: we only check log here)
|
||||
# for debugging: _make_soft_connection_diodes(true)
|
||||
netlist
|
||||
|
||||
netlist.simplify
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
* Extracted by KLayout
|
||||
|
||||
.SUBCKT TOP A Q VDD SUBSTRATE|VSS
|
||||
X$1 Q SUBSTRATE|VSS VDD \$1 INV
|
||||
X$2 \$1 SUBSTRATE|VSS VDD A INV
|
||||
.ENDS TOP
|
||||
|
||||
.SUBCKT INV \$1 SUBSTRATE \$4 \$6
|
||||
M$1 \$4 \$6 \$1 \$4 PMOS L=0.25U W=0.95U AS=1.02125P AD=0.73625P PS=4.05U
|
||||
+ PD=3.45U
|
||||
M$2 SUBSTRATE \$6 \$1 SUBSTRATE NMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P
|
||||
+ PS=3.45U PD=3.45U
|
||||
.ENDS INV
|
||||
Binary file not shown.
|
|
@ -0,0 +1,201 @@
|
|||
#%l2n-klayout
|
||||
W(TOP)
|
||||
U(0.001)
|
||||
L(l3 '1/0')
|
||||
L(l4 '3/0')
|
||||
L(l15 '3/1')
|
||||
L(l8 '4/0')
|
||||
L(l11 '5/0')
|
||||
L(l12 '6/0')
|
||||
L(l16 '6/1')
|
||||
L(l13 '7/0')
|
||||
L(l14 '8/0')
|
||||
L(l17 '8/1')
|
||||
L(l7)
|
||||
L(l10)
|
||||
L(l2)
|
||||
L(l9)
|
||||
L(l6)
|
||||
C(l3 l3 l10)
|
||||
C(l4 l4 l15 l11)
|
||||
C(l15 l4 l15)
|
||||
C(l8 l8 l12 l10 l2 l9 l6)
|
||||
CS(l8 l10 l2 l9 l6)
|
||||
C(l11 l4 l11 l12)
|
||||
CS(l11 l4)
|
||||
C(l12 l8 l11 l12 l16 l13)
|
||||
C(l16 l12 l16)
|
||||
C(l13 l12 l13 l14)
|
||||
C(l14 l13 l14 l17)
|
||||
C(l17 l14 l17)
|
||||
C(l7 l7)
|
||||
C(l10 l3 l8 l10)
|
||||
CS(l10 l3)
|
||||
C(l2 l8 l2)
|
||||
C(l9 l8 l9)
|
||||
C(l6 l8 l6)
|
||||
G(l7 SUBSTRATE)
|
||||
G(l9 SUBSTRATE)
|
||||
GS(l9 SUBSTRATE)
|
||||
H(W B('Net with incomplete wiring (soft-connected partial nets)') C(TOP) X('soft-connection-check'))
|
||||
H(B('\tPartial net #1: TOP - $2') C(TOP) Q('(6.54,2.6;6.54,4.78;6.9,4.78;6.9,2.6)'))
|
||||
H(B('\tPartial net #2: TOP - $I3') C(TOP) Q('(7.12,1.18;7.12,4.78;7.48,4.78;7.48,1.18)'))
|
||||
H(W B('Net with incomplete wiring (soft-connected partial nets)') C(TOP) X('soft-connection-check'))
|
||||
H(B('\tPartial net #1: TOP - Q') C(TOP) Q('(1.81,1.18;1.81,4.78;2.78,4.78;2.78,1.18)'))
|
||||
H(B('\tPartial net #2: TOP - $I2') C(TOP) Q('(1.84,4.02;1.84,4.78;2.2,4.78;2.2,4.02)'))
|
||||
K(PMOS MOS4)
|
||||
K(NMOS MOS4)
|
||||
D(D$PMOS PMOS
|
||||
T(S
|
||||
R(l2 (-1200 -475) (1075 950))
|
||||
)
|
||||
T(G
|
||||
R(l4 (-125 -475) (250 950))
|
||||
)
|
||||
T(D
|
||||
R(l2 (125 -475) (775 950))
|
||||
)
|
||||
T(B
|
||||
R(l3 (-125 -475) (250 950))
|
||||
)
|
||||
)
|
||||
D(D$NMOS NMOS
|
||||
T(S
|
||||
R(l6 (-900 -475) (775 950))
|
||||
)
|
||||
T(G
|
||||
R(l4 (-125 -475) (250 950))
|
||||
)
|
||||
T(D
|
||||
R(l6 (125 -475) (775 950))
|
||||
)
|
||||
T(B
|
||||
R(l7 (-125 -475) (250 950))
|
||||
)
|
||||
)
|
||||
X(INV
|
||||
R((-1500 -800) (3800 4600))
|
||||
N(1
|
||||
R(l8 (-1090 2490) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l8 (360 -3420) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l8 (-220 2180) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (-870 -690) (360 760))
|
||||
R(l12 (220 -3600) (360 2840))
|
||||
R(l12 (-360 -2800) (360 760))
|
||||
R(l12 (-360 2040) (360 760))
|
||||
R(l2 (-980 -855) (1075 950))
|
||||
R(l6 (-775 -3750) (775 950))
|
||||
)
|
||||
N(2 I(SUBSTRATE)
|
||||
R(l8 (1700 100) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l8 (-1610 -210) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (890 -760) (800 900))
|
||||
R(l12 (-1980 -830) (360 760))
|
||||
R(l13 (-305 -705) (250 250))
|
||||
R(l13 (-250 150) (250 250))
|
||||
R(l13 (1175 -225) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l14 (-3400 -350) (3000 900))
|
||||
R(l14 (-200 -900) (1000 900))
|
||||
R(l6 (-2175 -925) (775 950))
|
||||
)
|
||||
N(3
|
||||
R(l3 (-1500 1800) (3000 2000))
|
||||
R(l3 (-200 -2000) (1000 2000))
|
||||
R(l8 (-2010 -1310) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l8 (1190 -210) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l12 (-1680 -280) (360 760))
|
||||
R(l12 (820 -830) (800 900))
|
||||
R(l13 (-1925 -775) (250 250))
|
||||
R(l13 (-250 150) (250 250))
|
||||
R(l13 (1175 -225) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l14 (-3400 -350) (3000 900))
|
||||
R(l14 (-200 -900) (1000 900))
|
||||
R(l10 (-700 -950) (400 1000))
|
||||
R(l2 (-1875 -975) (775 950))
|
||||
)
|
||||
N(4
|
||||
R(l4 (-125 -250) (250 2500))
|
||||
R(l4 (-250 -3050) (250 1600))
|
||||
R(l4 (-250 1200) (250 1600))
|
||||
)
|
||||
P(1)
|
||||
P(2 I(SUBSTRATE))
|
||||
P(3)
|
||||
P(4)
|
||||
D(1 D$PMOS
|
||||
Y(0 2800)
|
||||
E(L 0.25)
|
||||
E(W 0.95)
|
||||
E(AS 1.02125)
|
||||
E(AD 0.73625)
|
||||
E(PS 4.05)
|
||||
E(PD 3.45)
|
||||
T(S 1)
|
||||
T(G 4)
|
||||
T(D 3)
|
||||
T(B 3)
|
||||
)
|
||||
D(2 D$NMOS
|
||||
Y(0 0)
|
||||
E(L 0.25)
|
||||
E(W 0.95)
|
||||
E(AS 0.73625)
|
||||
E(AD 0.73625)
|
||||
E(PS 3.45)
|
||||
E(PD 3.45)
|
||||
T(S 1)
|
||||
T(G 4)
|
||||
T(D 2)
|
||||
T(B 2)
|
||||
)
|
||||
)
|
||||
X(TOP
|
||||
R((1500 800) (9080 4600))
|
||||
N(1
|
||||
R(l4 (2920 2600) (3980 400))
|
||||
R(l11 (-300 -300) (200 200))
|
||||
R(l12 (-260 -300) (360 1600))
|
||||
)
|
||||
N(2 I(A)
|
||||
R(l4 (7700 2600) (2880 400))
|
||||
R(l15 (-2380 -200) (0 0))
|
||||
)
|
||||
N(3 I(Q)
|
||||
R(l12 (1810 2600) (690 400))
|
||||
R(l16 (-400 -200) (0 0))
|
||||
)
|
||||
N(4 I(VDD)
|
||||
R(l3 (4000 3400) (2700 2000))
|
||||
R(l14 (-1500 -1450) (1200 900))
|
||||
R(l17 (-2200 -450) (0 0))
|
||||
)
|
||||
N(5 I('SUBSTRATE,VSS')
|
||||
R(l14 (5200 1150) (1200 900))
|
||||
R(l17 (-2200 -550) (0 0))
|
||||
)
|
||||
P(2 I(A))
|
||||
P(3 I(Q))
|
||||
P(4 I(VDD))
|
||||
P(5 I('SUBSTRATE,VSS'))
|
||||
X(1 INV Y(3000 1600)
|
||||
P(0 3)
|
||||
P(1 5)
|
||||
P(2 4)
|
||||
P(3 1)
|
||||
)
|
||||
X(2 INV Y(7700 1600)
|
||||
P(0 1)
|
||||
P(1 5)
|
||||
P(2 4)
|
||||
P(3 2)
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
|
||||
$lvs_test_source && source($lvs_test_source)
|
||||
|
||||
if $lvs_test_target_l2n
|
||||
report_netlist($lvs_test_target_l2n)
|
||||
else
|
||||
report_netlist
|
||||
end
|
||||
|
||||
writer = write_spice(true, false)
|
||||
$lvs_test_target_cir && target_netlist($lvs_test_target_cir, writer, "Extracted by KLayout")
|
||||
|
||||
deep
|
||||
|
||||
# Drawing layers
|
||||
|
||||
nwell = input(1, 0)
|
||||
active = input(2, 0)
|
||||
nplus = input(2, 1)
|
||||
pplus = input(2, 2)
|
||||
poly = input(3, 0)
|
||||
poly_lbl = input(3, 1)
|
||||
diff_cont = input(4, 0)
|
||||
poly_cont = input(5, 0)
|
||||
metal1 = input(6, 0)
|
||||
metal1_lbl = input(6, 1)
|
||||
via1 = input(7, 0)
|
||||
metal2 = input(8, 0)
|
||||
metal2_lbl = input(8, 1)
|
||||
|
||||
# Bulk layer for terminal provisioning
|
||||
|
||||
bulk = polygon_layer
|
||||
|
||||
psd = nil
|
||||
nsd = nil
|
||||
|
||||
# Computed layers
|
||||
|
||||
active_in_nwell = active & nwell
|
||||
pactive = active_in_nwell & pplus
|
||||
ntie = active_in_nwell & nplus
|
||||
pgate = pactive & poly
|
||||
psd = pactive - pgate
|
||||
|
||||
active_outside_nwell = active - nwell
|
||||
nactive = active_outside_nwell & nplus
|
||||
ptie = active_outside_nwell & pplus
|
||||
ngate = nactive & poly
|
||||
nsd = nactive - ngate
|
||||
|
||||
# Device extraction
|
||||
|
||||
# PMOS transistor device extraction
|
||||
extract_devices(mos4("PMOS"), { "SD" => psd, "G" => pgate, "W" => nwell,
|
||||
"tS" => psd, "tD" => psd, "tG" => poly })
|
||||
|
||||
# NMOS transistor device extraction
|
||||
extract_devices(mos4("NMOS"), { "SD" => nsd, "G" => ngate, "W" => bulk,
|
||||
"tS" => nsd, "tD" => nsd, "tG" => poly })
|
||||
|
||||
# Define connectivity for netlist extraction
|
||||
|
||||
# Inter-layer
|
||||
|
||||
soft_connect(diff_cont, psd)
|
||||
soft_connect(diff_cont, nsd)
|
||||
soft_connect(diff_cont, ptie)
|
||||
soft_connect(diff_cont, ntie)
|
||||
soft_connect(ntie, nwell)
|
||||
soft_connect(poly_cont, poly)
|
||||
|
||||
connect(diff_cont, metal1)
|
||||
connect(poly_cont, metal1)
|
||||
connect(metal1, via1)
|
||||
connect(via1, metal2)
|
||||
|
||||
# attach labels
|
||||
connect(poly, poly_lbl)
|
||||
connect(metal1, metal1_lbl)
|
||||
connect(metal2, metal2_lbl)
|
||||
|
||||
# Global
|
||||
connect_global(bulk, "SUBSTRATE")
|
||||
soft_connect_global(ptie, "SUBSTRATE")
|
||||
|
||||
# Netlist section (NOTE: we only check log here)
|
||||
# for debugging: _make_soft_connection_diodes(true)
|
||||
netlist
|
||||
|
||||
netlist.simplify
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
|
||||
source($lvs_test_source)
|
||||
|
||||
# will get pretty big:
|
||||
# report_lvs($lvs_test_target_lvsdb, true)
|
||||
|
||||
target_netlist($lvs_test_target_cir, write_spice(true), "Extracted by KLayout")
|
||||
|
||||
schematic("vexriscv_schematic.cir.gz")
|
||||
|
||||
deep
|
||||
|
||||
# Drawing layers
|
||||
|
||||
nwell = input(1, 0)
|
||||
pactive = input(4, 0)
|
||||
nactive = input(3, 0)
|
||||
ntie = input(5, 0)
|
||||
ptie = input(6, 0)
|
||||
|
||||
poly = input(7, 0)
|
||||
cont = input(10, 0)
|
||||
metal1 = input(11, 0)
|
||||
via1 = input(14, 0)
|
||||
metal2 = input(16, 0)
|
||||
via2 = input(18, 0)
|
||||
metal3 = input(19, 0)
|
||||
via3 = input(21, 0)
|
||||
metal4 = input(22, 0)
|
||||
via4 = input(25, 0)
|
||||
metal5 = input(26, 0)
|
||||
|
||||
# Bulk layer for terminal provisioning
|
||||
|
||||
bulk = polygon_layer
|
||||
|
||||
# Computed layers
|
||||
|
||||
poly_cont = cont & poly
|
||||
diff_cont = cont - poly
|
||||
|
||||
pgate = pactive & poly
|
||||
psd = pactive - pgate
|
||||
|
||||
ngate = nactive & poly
|
||||
nsd = nactive - ngate
|
||||
|
||||
# Device extraction
|
||||
|
||||
# PMOS transistor device extraction
|
||||
extract_devices(mos4("PMOS"), { "SD" => psd, "G" => pgate, "W" => nwell,
|
||||
"tS" => psd, "tD" => psd, "tG" => poly, "tW" => nwell })
|
||||
|
||||
# NMOS transistor device extraction
|
||||
extract_devices(mos4("NMOS"), { "SD" => nsd, "G" => ngate, "W" => bulk,
|
||||
"tS" => nsd, "tD" => nsd, "tG" => poly, "tW" => bulk })
|
||||
|
||||
# Define connectivity for netlist extraction
|
||||
|
||||
# Inter-layer
|
||||
soft_connect(diff_cont, psd)
|
||||
soft_connect(diff_cont, nsd)
|
||||
soft_connect(poly_cont, poly)
|
||||
connect(poly_cont, metal1)
|
||||
connect(diff_cont, metal1)
|
||||
soft_connect(diff_cont, ntie)
|
||||
soft_connect(diff_cont, ptie)
|
||||
soft_connect(ntie, nwell)
|
||||
connect(metal1, via1)
|
||||
connect(via1, metal2)
|
||||
connect(metal2, via2)
|
||||
connect(via2, metal3)
|
||||
connect(metal3, via3)
|
||||
connect(via3, metal4)
|
||||
connect(metal4, via4)
|
||||
connect(via4, metal5)
|
||||
|
||||
# Global
|
||||
soft_connect_global(ptie, "BULK")
|
||||
connect_global(bulk, "BULK")
|
||||
|
||||
# Implicit
|
||||
connect_implicit("VDD")
|
||||
connect_implicit("VSS")
|
||||
|
||||
# Compare section
|
||||
|
||||
same_device_classes("PMOS", "TP")
|
||||
same_device_classes("NMOS", "TN")
|
||||
|
||||
# Ignore all caps from the schematic
|
||||
same_device_classes(nil, "CAP")
|
||||
|
||||
# Increase the default complexity from 100 to 200
|
||||
# This is required because the clock tree is incorrect and exhibits manifold ambiguities
|
||||
# (the netlists are just samples, not necessarily functional).
|
||||
# The algorithm needs enough freedom to follow all these branches and different variants.
|
||||
max_branch_complexity(200)
|
||||
|
||||
schematic.combine_devices
|
||||
|
||||
netlist.combine_devices
|
||||
|
||||
align
|
||||
|
||||
if ! compare
|
||||
raise "Netlists don't match"
|
||||
else
|
||||
puts "Congratulations! Netlists match."
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
# encoding: UTF-8
|
||||
|
||||
# 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
|
||||
|
||||
if !$:.member?(File::dirname($0))
|
||||
$:.push(File::dirname($0))
|
||||
end
|
||||
|
||||
load("test_prologue.rb")
|
||||
|
||||
class DBHierNetworkProcessor_TestClass < TestBase
|
||||
|
||||
# Connectivity
|
||||
def test_1_Connectivity
|
||||
|
||||
conn = RBA::Connectivity::new
|
||||
|
||||
assert_equal(conn.to_s, "")
|
||||
|
||||
conn.connect(1)
|
||||
assert_equal(conn.to_s, "1:1")
|
||||
|
||||
conn.connect(0, 1)
|
||||
assert_equal(conn.to_s, "0:1\n1:0,1")
|
||||
|
||||
conn.soft_connect(0, 2)
|
||||
assert_equal(conn.to_s, "0:1,2-S\n1:0,1\n2:0+S")
|
||||
|
||||
gid1 = conn.connect_global(0, "GLOBAL1")
|
||||
assert_equal(gid1, 0)
|
||||
assert_equal(conn.global_net_name(gid1), "GLOBAL1")
|
||||
assert_equal(conn.global_net_id("GLOBAL1"), 0)
|
||||
assert_equal(conn.to_s, "0:1,2-S\nG0:0\n1:0,1\n2:0+S")
|
||||
|
||||
conn.soft_connect_global(1, "GLOBAL1")
|
||||
assert_equal(conn.to_s, "0:1,2-S\nG0:0\n1:0,1\nG1:0-S\n2:0+S")
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
Loading…
Reference in New Issue