mirror of https://github.com/KLayout/klayout.git
Implemented #444 (double-height standard-cell support).
This commit is contained in:
parent
412fe2bbf9
commit
d0e6efa484
|
|
@ -1103,6 +1103,9 @@ private:
|
||||||
// ------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------
|
||||||
// hier_clusters implementation
|
// hier_clusters implementation
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
const db::cell_index_type hier_clusters<T>::top_cell_index = std::numeric_limits<db::cell_index_type>::max ();
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
hier_clusters<T>::hier_clusters ()
|
hier_clusters<T>::hier_clusters ()
|
||||||
: m_base_verbosity (20)
|
: m_base_verbosity (20)
|
||||||
|
|
@ -1124,7 +1127,7 @@ void hier_clusters<T>::clear ()
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void
|
void
|
||||||
hier_clusters<T>::build (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters<unsigned int> *attr_equivalence, const std::set<db::cell_index_type> *breakout_cells)
|
hier_clusters<T>::build (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> > *attr_equivalence, const std::set<db::cell_index_type> *breakout_cells)
|
||||||
{
|
{
|
||||||
clear ();
|
clear ();
|
||||||
cell_clusters_box_converter<T> cbc (layout, *this);
|
cell_clusters_box_converter<T> cbc (layout, *this);
|
||||||
|
|
@ -1903,7 +1906,7 @@ hier_clusters<T>::propagate_cluster_inst (const db::Layout &layout, const db::Ce
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void
|
void
|
||||||
hier_clusters<T>::do_build (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters<unsigned int> *attr_equivalence, const std::set<db::cell_index_type> *breakout_cells)
|
hier_clusters<T>::do_build (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> > *attr_equivalence, const std::set<db::cell_index_type> *breakout_cells)
|
||||||
{
|
{
|
||||||
tl::SelfTimer timer (tl::verbosity () > m_base_verbosity, tl::to_string (tr ("Computing shape clusters")));
|
tl::SelfTimer timer (tl::verbosity () > m_base_verbosity, tl::to_string (tr ("Computing shape clusters")));
|
||||||
|
|
||||||
|
|
@ -1918,8 +1921,30 @@ hier_clusters<T>::do_build (cell_clusters_box_converter<T> &cbc, const db::Layou
|
||||||
tl::RelativeProgress progress (tl::to_string (tr ("Computing local clusters")), called.size (), 1);
|
tl::RelativeProgress progress (tl::to_string (tr ("Computing local clusters")), called.size (), 1);
|
||||||
|
|
||||||
for (std::set<db::cell_index_type>::const_iterator c = called.begin (); c != called.end (); ++c) {
|
for (std::set<db::cell_index_type>::const_iterator c = called.begin (); c != called.end (); ++c) {
|
||||||
build_local_cluster (layout, layout.cell (*c), shape_flags, conn, *c == cell.cell_index () ? attr_equivalence : 0);
|
|
||||||
|
// look for the net label joining spec - for the top cell the "top_cell_index" entry is looked for.
|
||||||
|
// If there is no such entry or the cell is not the top cell, look for the entry by cell index.
|
||||||
|
std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> >::const_iterator ae;
|
||||||
|
const tl::equivalence_clusters<unsigned int> *ec = 0;
|
||||||
|
if (attr_equivalence) {
|
||||||
|
if (*c == cell.cell_index ()) {
|
||||||
|
ae = attr_equivalence->find (top_cell_index);
|
||||||
|
if (ae != attr_equivalence->end ()) {
|
||||||
|
ec = &ae->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (! ec) {
|
||||||
|
ae = attr_equivalence->find (*c);
|
||||||
|
if (ae != attr_equivalence->end ()) {
|
||||||
|
ec = &ae->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
build_local_cluster (layout, layout.cell (*c), shape_flags, conn, ec);
|
||||||
|
|
||||||
++progress;
|
++progress;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -986,10 +986,15 @@ public:
|
||||||
*/
|
*/
|
||||||
void set_base_verbosity (int bv);
|
void set_base_verbosity (int bv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A constant indicating the top cell for the equivalence cluster key
|
||||||
|
*/
|
||||||
|
static const db::cell_index_type top_cell_index;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Builds a hierarchy of clusters from a cell hierarchy and given connectivity
|
* @brief Builds a hierarchy of clusters from a cell hierarchy and given connectivity
|
||||||
*/
|
*/
|
||||||
void build (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters<unsigned int> *attr_equivalence = 0, const std::set<cell_index_type> *breakout_cells = 0);
|
void build (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> > *attr_equivalence = 0, const std::set<cell_index_type> *breakout_cells = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the connected clusters for a given cell
|
* @brief Gets the connected clusters for a given cell
|
||||||
|
|
@ -1030,7 +1035,7 @@ private:
|
||||||
void build_local_cluster (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters<unsigned int> *attr_equivalence);
|
void build_local_cluster (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters<unsigned int> *attr_equivalence);
|
||||||
void build_hier_connections (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::set<cell_index_type> *breakout_cells, instance_interaction_cache_type &instance_interaction_cache);
|
void build_hier_connections (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::set<cell_index_type> *breakout_cells, instance_interaction_cache_type &instance_interaction_cache);
|
||||||
void build_hier_connections_for_cells (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const std::vector<db::cell_index_type> &cells, const db::Connectivity &conn, const std::set<cell_index_type> *breakout_cells, tl::RelativeProgress &progress, instance_interaction_cache_type &instance_interaction_cache);
|
void build_hier_connections_for_cells (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const std::vector<db::cell_index_type> &cells, const db::Connectivity &conn, const std::set<cell_index_type> *breakout_cells, tl::RelativeProgress &progress, instance_interaction_cache_type &instance_interaction_cache);
|
||||||
void do_build (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters<unsigned int> *attr_equivalence, const std::set<cell_index_type> *breakout_cells);
|
void do_build (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> > *attr_equivalence, const std::set<cell_index_type> *breakout_cells);
|
||||||
|
|
||||||
std::map<db::cell_index_type, connected_clusters<T> > m_per_cell_clusters;
|
std::map<db::cell_index_type, connected_clusters<T> > m_per_cell_clusters;
|
||||||
int m_base_verbosity;
|
int m_base_verbosity;
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include "dbLayoutVsSchematic.h"
|
#include "dbLayoutVsSchematic.h"
|
||||||
#include "dbLayoutToNetlistFormatDefs.h"
|
#include "dbLayoutToNetlistFormatDefs.h"
|
||||||
#include "dbLayoutVsSchematicFormatDefs.h"
|
#include "dbLayoutVsSchematicFormatDefs.h"
|
||||||
|
#include "tlGlobPattern.h"
|
||||||
|
|
||||||
namespace db
|
namespace db
|
||||||
{
|
{
|
||||||
|
|
@ -295,6 +296,11 @@ size_t LayoutToNetlist::global_net_id (const std::string &name)
|
||||||
}
|
}
|
||||||
|
|
||||||
void LayoutToNetlist::extract_netlist (const std::string &joined_net_names, bool include_floating_subcircuits)
|
void LayoutToNetlist::extract_netlist (const std::string &joined_net_names, bool include_floating_subcircuits)
|
||||||
|
{
|
||||||
|
extract_netlist (joined_net_names, std::map<std::string, std::string> (), include_floating_subcircuits);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutToNetlist::extract_netlist (const std::string &joined_net_names, const std::map<std::string, std::string> &joined_net_names_per_cell, bool include_floating_subcircuits)
|
||||||
{
|
{
|
||||||
if (m_netlist_extracted) {
|
if (m_netlist_extracted) {
|
||||||
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
||||||
|
|
@ -302,7 +308,23 @@ void LayoutToNetlist::extract_netlist (const std::string &joined_net_names, bool
|
||||||
ensure_netlist ();
|
ensure_netlist ();
|
||||||
|
|
||||||
db::NetlistExtractor netex;
|
db::NetlistExtractor netex;
|
||||||
|
|
||||||
netex.set_joined_net_names (joined_net_names);
|
netex.set_joined_net_names (joined_net_names);
|
||||||
|
|
||||||
|
const db::Layout &layout = dss ().layout (m_layout_index);
|
||||||
|
for (std::map<std::string, std::string>::const_iterator j = joined_net_names_per_cell.begin (); j != joined_net_names_per_cell.end (); ++j) {
|
||||||
|
tl::GlobPattern pat (j->first);
|
||||||
|
if (pat.is_const ()) {
|
||||||
|
netex.set_joined_net_names (j->first, j->second);
|
||||||
|
} else {
|
||||||
|
for (db::Layout::const_iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||||
|
if (pat.match (layout.cell_name (c->cell_index ()))) {
|
||||||
|
netex.set_joined_net_names (layout.cell_name (c->cell_index ()), j->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
netex.set_include_floating_subcircuits (include_floating_subcircuits);
|
netex.set_include_floating_subcircuits (include_floating_subcircuits);
|
||||||
netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters);
|
netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -391,6 +391,16 @@ public:
|
||||||
*/
|
*/
|
||||||
void extract_netlist (const std::string &joined_net_names = std::string (), bool include_floating_subcircuits = false);
|
void extract_netlist (const std::string &joined_net_names = std::string (), bool include_floating_subcircuits = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Runs the netlist extraction
|
||||||
|
* In addition to the previous version, this extraction method allows specification of a per-cell list of
|
||||||
|
* joined (labelled) net names.
|
||||||
|
* The key of the "joined_net_names_per_cell" is a cell name or a glob expression for cells. On all matching cells,
|
||||||
|
* the value is applied as a label selector for labels that are joined together. The "joined_net_names" expressions
|
||||||
|
* is only applied to the top cell.
|
||||||
|
*/
|
||||||
|
void extract_netlist (const std::string &joined_net_names, const std::map<std::string, std::string> &joined_net_names_per_cell, bool include_floating_subcircuits = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Marks the netlist as extracted
|
* @brief Marks the netlist as extracted
|
||||||
* NOTE: this method is provided for special cases such as netlist readers. Don't
|
* NOTE: this method is provided for special cases such as netlist readers. Don't
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,11 @@ void NetlistExtractor::set_joined_net_names (const std::string &jnn)
|
||||||
m_joined_net_names = jnn;
|
m_joined_net_names = jnn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetlistExtractor::set_joined_net_names (const std::string &cellname, const std::string &jnn)
|
||||||
|
{
|
||||||
|
m_joined_net_names_per_cell.push_back (std::make_pair (cellname, jnn));
|
||||||
|
}
|
||||||
|
|
||||||
void NetlistExtractor::set_include_floating_subcircuits (bool f)
|
void NetlistExtractor::set_include_floating_subcircuits (bool f)
|
||||||
{
|
{
|
||||||
m_include_floating_subcircuits = f;
|
m_include_floating_subcircuits = f;
|
||||||
|
|
@ -90,9 +95,17 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
||||||
|
|
||||||
// the big part: actually extract the nets
|
// the big part: actually extract the nets
|
||||||
|
|
||||||
tl::equivalence_clusters<unsigned int> net_name_equivalence;
|
std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> > net_name_equivalence;
|
||||||
if (m_text_annot_name_id.first && ! m_joined_net_names.empty ()) {
|
if (m_text_annot_name_id.first) {
|
||||||
build_net_name_equivalence (mp_layout, m_text_annot_name_id.second, m_joined_net_names, net_name_equivalence);
|
if (! m_joined_net_names.empty ()) {
|
||||||
|
build_net_name_equivalence (mp_layout, m_text_annot_name_id.second, m_joined_net_names, net_name_equivalence [hier_clusters_type::top_cell_index]);
|
||||||
|
}
|
||||||
|
for (std::list<std::pair<std::string, std::string> >::const_iterator m = m_joined_net_names_per_cell.begin (); m != m_joined_net_names_per_cell.end (); ++m) {
|
||||||
|
std::pair<bool, db::cell_index_type> cp = mp_layout->cell_by_name (m->first.c_str ());
|
||||||
|
if (cp.first) {
|
||||||
|
build_net_name_equivalence (mp_layout, m_text_annot_name_id.second, m->second, net_name_equivalence [cp.second]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mp_clusters->build (*mp_layout, *mp_cell, db::ShapeIterator::Polygons, conn, &net_name_equivalence);
|
mp_clusters->build (*mp_layout, *mp_cell, db::ShapeIterator::Polygons, conn, &net_name_equivalence);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,13 @@ public:
|
||||||
*/
|
*/
|
||||||
void set_joined_net_names (const std::string &jnn);
|
void set_joined_net_names (const std::string &jnn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the joined net names attribute for a given cell name
|
||||||
|
* While the single-parameter set_joined_net_names only acts on the top cell, this
|
||||||
|
* version will act on the cell with the given name.
|
||||||
|
*/
|
||||||
|
void set_joined_net_names (const std::string &cell_name, const std::string &jnn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the joined net names expression
|
* @brief Gets the joined net names expression
|
||||||
*/
|
*/
|
||||||
|
|
@ -128,6 +135,7 @@ private:
|
||||||
std::pair<bool, db::property_names_id_type> m_device_annot_name_id;
|
std::pair<bool, db::property_names_id_type> m_device_annot_name_id;
|
||||||
std::pair<bool, db::property_names_id_type> m_terminal_annot_name_id;
|
std::pair<bool, db::property_names_id_type> m_terminal_annot_name_id;
|
||||||
std::string m_joined_net_names;
|
std::string m_joined_net_names;
|
||||||
|
std::list<std::pair<std::string, std::string> > m_joined_net_names_per_cell;
|
||||||
bool m_include_floating_subcircuits;
|
bool m_include_floating_subcircuits;
|
||||||
|
|
||||||
bool instance_is_device (db::properties_id_type prop_id) const;
|
bool instance_is_device (db::properties_id_type prop_id) const;
|
||||||
|
|
|
||||||
|
|
@ -355,6 +355,17 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
||||||
"\n"
|
"\n"
|
||||||
"The 'include_floating_subcircuits' argument has been introduced in version 0.26.2."
|
"The 'include_floating_subcircuits' argument has been introduced in version 0.26.2."
|
||||||
) +
|
) +
|
||||||
|
gsi::method ("extract_netlist", &db::LayoutToNetlist::extract_netlist, gsi::arg ("join_net_names"), gsi::arg ("join_net_names_per_cell"), gsi::arg ("include_floating_subcircuits", false),
|
||||||
|
"@brief Runs the netlist extraction\n"
|
||||||
|
"This method runs the netlist extraction like the two-parameter version. In addition to the latter, this method "
|
||||||
|
"can be given a per-cell net label joining specification in 'join_net_names_per_cell'. The keys of this array "
|
||||||
|
"are cell names or cell names or cell name match expressions (glob style). The values are lable match expressions.\n"
|
||||||
|
"\n"
|
||||||
|
"If not an empty string, the 'join_net_names' label match expression is applied to the top cell. For all non-top cells "
|
||||||
|
"the per-cell label match expression is applied and determines what labels are joined into single nets. "
|
||||||
|
"As the keys of 'join_net_names_per_cell' are glob expressions, a single cell may fall into more than one category. In this "
|
||||||
|
"case, the label match pattern are combined. In any case, the 'join_net_names' has priority for the top cell."
|
||||||
|
) +
|
||||||
gsi::method_ext ("internal_layout", &l2n_internal_layout,
|
gsi::method_ext ("internal_layout", &l2n_internal_layout,
|
||||||
"@brief Gets the internal layout\n"
|
"@brief Gets the internal layout\n"
|
||||||
"Usually it should not be required to obtain the internal layout. If you need to do so, make sure not to modify the layout as\n"
|
"Usually it should not be required to obtain the internal layout. If you need to do so, make sure not to modify the layout as\n"
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ module DRC
|
||||||
@engine = engine
|
@engine = engine
|
||||||
@netlisted = false
|
@netlisted = false
|
||||||
@connect_implicit = []
|
@connect_implicit = []
|
||||||
|
@connect_implicit_per_cell = {}
|
||||||
@l2n = nil
|
@l2n = nil
|
||||||
@lnum = 0
|
@lnum = 0
|
||||||
@device_scaling = 1.0
|
@device_scaling = 1.0
|
||||||
|
|
@ -203,6 +204,7 @@ module DRC
|
||||||
def clear_connections
|
def clear_connections
|
||||||
@netlisted = false
|
@netlisted = false
|
||||||
@connect_implicit = []
|
@connect_implicit = []
|
||||||
|
@connect_implicit_per_cell = {}
|
||||||
_clear_data
|
_clear_data
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -210,8 +212,9 @@ module DRC
|
||||||
# @name connect_implicit
|
# @name connect_implicit
|
||||||
# @brief Specifies a search pattern for labels which create implicit net connections
|
# @brief Specifies a search pattern for labels which create implicit net connections
|
||||||
# @synopsis connect_implicit(label_pattern)
|
# @synopsis connect_implicit(label_pattern)
|
||||||
|
# @synopsis connect_implicit(cell_pattern, label_pattern)
|
||||||
# Use this method to supply label strings which create implicit net connections
|
# Use this method to supply label strings which create implicit net connections
|
||||||
# on the top level circuit. This feature is useful to connect identically labelled nets
|
# on the top level circuit in the first version. This feature is useful to connect identically labelled nets
|
||||||
# while a component isn't integrated yet. If the component is integrated, nets may be connected
|
# while a component isn't integrated yet. If the component is integrated, nets may be connected
|
||||||
# on a higher hierarchy level - e.g. by a power mesh. Inside the component this net consists
|
# on a higher hierarchy level - e.g. by a power mesh. Inside the component this net consists
|
||||||
# of individual islands. To properly perform netlist extraction and comparison, these islands
|
# of individual islands. To properly perform netlist extraction and comparison, these islands
|
||||||
|
|
@ -219,12 +222,26 @@ module DRC
|
||||||
# achive this if these islands are labelled with the same text on the top level of the
|
# achive this if these islands are labelled with the same text on the top level of the
|
||||||
# component.
|
# component.
|
||||||
#
|
#
|
||||||
|
# In the second version, the pattern can be specified for a cell range (given by a cell name pattern or a
|
||||||
|
# single cell name). These pattern are applied to non-top cells. The unspecific pattern
|
||||||
|
# has priority over the cell-specific ones. As the cell selector is a pattern itself, a
|
||||||
|
# single cell may fall into more than one category. In this case, the label filters are
|
||||||
|
# combined.
|
||||||
|
#
|
||||||
# The implicit connections are applied on the next net extraction and cleared
|
# The implicit connections are applied on the next net extraction and cleared
|
||||||
# on "clear_connections".
|
# on "clear_connections".
|
||||||
|
|
||||||
def connect_implicit(arg)
|
def connect_implicit(arg1, arg2 = nil)
|
||||||
cleanup
|
cleanup
|
||||||
@connect_implicit << arg
|
if arg2
|
||||||
|
(arg2.is_a?(String) && arg2 != "") || raise("The second argument of 'connect_implicit' has to be a non-empty string")
|
||||||
|
arg1.is_a?(String) || raise("The first argument of 'connect_implicit' has to be a string")
|
||||||
|
@connect_implicit_per_cell[arg1] ||= []
|
||||||
|
@connect_implicit_per_cell[arg1] << arg2
|
||||||
|
else
|
||||||
|
arg1.is_a?(String) || raise("The argument of 'connect_implicit' has to be a string")
|
||||||
|
@connect_implicit << arg1
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# %DRC%
|
# %DRC%
|
||||||
|
|
@ -341,15 +358,19 @@ module DRC
|
||||||
|
|
||||||
# run extraction in a timed environment
|
# run extraction in a timed environment
|
||||||
if ! @netlisted
|
if ! @netlisted
|
||||||
|
|
||||||
# build a glob expression from the parts
|
# build a glob expression from the parts
|
||||||
exprs = @connect_implicit.collect { |c| c.gsub(/\?\*\[\]\{\},\(\)\\/) { |x| "\\" + x } }
|
expr = _join_glob_pattern(@connect_implicit)
|
||||||
if exprs.size > 1
|
|
||||||
expr = "{" + exprs.join(",") + "}"
|
# build cell-pattern specific glob expressions from the parts
|
||||||
else
|
per_cell_expr = {}
|
||||||
expr = exprs[0] || ""
|
@connect_implicit_per_cell.each do |cell_pattern,label_pattern|
|
||||||
|
per_cell_expr[cell_pattern] = _join_glob_pattern(label_pattern)
|
||||||
end
|
end
|
||||||
@engine._cmd(@l2n, :extract_netlist, expr)
|
|
||||||
|
@engine._cmd(@l2n, :extract_netlist, expr, per_cell_expr)
|
||||||
@netlisted = true
|
@netlisted = true
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@l2n
|
@l2n
|
||||||
|
|
@ -401,6 +422,19 @@ module DRC
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def _join_glob_pattern(pattern)
|
||||||
|
|
||||||
|
exprs = pattern.collect { |c| c.gsub(/\?\*\[\]\{\},\(\)\\/) { |x| "\\" + x } }
|
||||||
|
if exprs.size > 1
|
||||||
|
expr = "{" + exprs.join(",") + "}"
|
||||||
|
else
|
||||||
|
expr = exprs[0] || ""
|
||||||
|
end
|
||||||
|
|
||||||
|
expr
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
def _make_data
|
def _make_data
|
||||||
|
|
||||||
if @engine._dss
|
if @engine._dss
|
||||||
|
|
|
||||||
|
|
@ -184,17 +184,24 @@ to shapes belonging to tie-down diodes.
|
||||||
<a name="connect_implicit"/><p>Usage:</p>
|
<a name="connect_implicit"/><p>Usage:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><tt>connect_implicit(label_pattern)</tt></li>
|
<li><tt>connect_implicit(label_pattern)</tt></li>
|
||||||
|
<li><tt>connect_implicit(cell_pattern, label_pattern)</tt></li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>
|
<p>
|
||||||
Use this method to supply label strings which create implicit net connections
|
Use the first version of this method to supply label strings which create implicit net connections
|
||||||
on the top level circuit. This feature is useful to connect identically labelled nets
|
on the top level circuit. This feature is useful to connect identically labelled nets
|
||||||
while a component isn't integrated yet. If the component is integrated, nets may be connected
|
while a component isn't integrated yet. If the component is integrated, nets may be connected
|
||||||
on a higher hierarchy level - e.g. by a power mesh. Inside the component this net consists
|
on a higher hierarchy level - e.g. by a power mesh. Inside the component this net consists
|
||||||
of individual islands. To properly perform netlist extraction and comparison, these islands
|
of individual islands. To properly perform netlist extraction and comparison, these islands
|
||||||
need to be connected even though there isn't a physical connection. "connect_implicit" can
|
need to be connected even though there isn't a physical connection. "connect_implicit" can
|
||||||
achive this if these islands are labelled with the same text on the top level of the
|
achieve this if these islands are labelled with the same text on the top level of the
|
||||||
component.
|
component.
|
||||||
</p><p>
|
</p><p>
|
||||||
|
In the second version, the pattern can be specified for a cell range (given by a cell glob-style
|
||||||
|
name pattern or a single cell name). These pattern are applied to non-top cells. An unspecific pattern
|
||||||
|
has priority over the cell-specific ones. As the cell selector is a pattern itself, a
|
||||||
|
single cell may fall into more than one category. In this case, the label filters are
|
||||||
|
combined.
|
||||||
|
</p><p>
|
||||||
The implicit connections are applied on the next net extraction and cleared
|
The implicit connections are applied on the next net extraction and cleared
|
||||||
on "clear_connections".
|
on "clear_connections".
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
|
|
@ -165,3 +165,15 @@ TEST(18_cheats)
|
||||||
run_test (_this, "invchain_cheat", "invchain_for_cheat.gds");
|
run_test (_this, "invchain_cheat", "invchain_for_cheat.gds");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// testing cell specific net joining for VSS of the double-height inverter standard cell
|
||||||
|
TEST(19_double_height_inv)
|
||||||
|
{
|
||||||
|
run_test (_this, "double_height", "double_height_inv.gds");
|
||||||
|
}
|
||||||
|
|
||||||
|
// testing cell specific net joining for VSS of the double-height inverter standard cell
|
||||||
|
TEST(20_double_height2_inv)
|
||||||
|
{
|
||||||
|
run_test (_this, "double_height2", "double_height2_inv.gds");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
* Extracted by KLayout
|
||||||
|
|
||||||
|
.SUBCKT INVCHAIN IN OUT VSS VDD
|
||||||
|
X$1 VDD IN \$1 \$1 OUT VSS INV2
|
||||||
|
.ENDS INVCHAIN
|
||||||
|
|
||||||
|
.SUBCKT INV2 VDD A1 A2 Q1 Q2 VSS
|
||||||
|
X$1 VSS VDD A2 Q2 INV
|
||||||
|
X$2 VSS VDD A1 Q1 INV
|
||||||
|
.ENDS INV2
|
||||||
|
|
||||||
|
.SUBCKT INV \$1 \$2 \$3 \$4
|
||||||
|
M$1 \$4 \$3 \$2 \$4 PMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U
|
||||||
|
+ PD=3.45U
|
||||||
|
M$2 \$4 \$3 \$1 \$4 NMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U
|
||||||
|
+ PD=3.45U
|
||||||
|
.ENDS INV
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
|
||||||
|
source($lvs_test_source)
|
||||||
|
|
||||||
|
report_lvs($lvs_test_target_lvsdb)
|
||||||
|
|
||||||
|
writer = write_spice(true, false)
|
||||||
|
target_netlist($lvs_test_target_cir, writer, "Extracted by KLayout")
|
||||||
|
|
||||||
|
# needs this delegate because we use MOS3 which is not available in Spice
|
||||||
|
class SpiceReaderDelegate < RBA::NetlistSpiceReaderDelegate
|
||||||
|
|
||||||
|
# says we want to catch these subcircuits as devices
|
||||||
|
def wants_subcircuit(name)
|
||||||
|
name == "HVNMOS" || name == "HVPMOS"
|
||||||
|
end
|
||||||
|
|
||||||
|
# translate the element
|
||||||
|
def element(circuit, el, name, model, value, nets, params)
|
||||||
|
|
||||||
|
if el != "M"
|
||||||
|
# all other elements are left to the standard implementation
|
||||||
|
return super
|
||||||
|
end
|
||||||
|
|
||||||
|
if nets.size != 4
|
||||||
|
error("Device #{model} needs four nodes")
|
||||||
|
end
|
||||||
|
|
||||||
|
# provide a device class
|
||||||
|
cls = circuit.netlist.device_class_by_name(model)
|
||||||
|
if ! cls
|
||||||
|
cls = RBA::DeviceClassMOS3Transistor::new
|
||||||
|
cls.name = model
|
||||||
|
circuit.netlist.add(cls)
|
||||||
|
end
|
||||||
|
|
||||||
|
# create a device
|
||||||
|
device = circuit.create_device(cls, name)
|
||||||
|
|
||||||
|
# and configure the device
|
||||||
|
[ "S", "G", "D" ].each_with_index do |t,index|
|
||||||
|
device.connect_terminal(t, nets[index])
|
||||||
|
end
|
||||||
|
device.set_parameter("W", params["W"] * 1e6)
|
||||||
|
device.set_parameter("L", params["L"] * 1e6)
|
||||||
|
|
||||||
|
device
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
reader = RBA::NetlistSpiceReader::new(SpiceReaderDelegate::new)
|
||||||
|
schematic("double_height_inv.cir", reader)
|
||||||
|
|
||||||
|
deep
|
||||||
|
|
||||||
|
# Drawing layers
|
||||||
|
|
||||||
|
nwell = input(1, 0)
|
||||||
|
active = input(2, 0)
|
||||||
|
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
|
||||||
|
pgate = pactive & poly
|
||||||
|
psd = pactive - pgate
|
||||||
|
|
||||||
|
active_outside_nwell = active - nwell
|
||||||
|
nactive = active_outside_nwell
|
||||||
|
ngate = nactive & poly
|
||||||
|
nsd = nactive - ngate
|
||||||
|
|
||||||
|
# Device extraction
|
||||||
|
|
||||||
|
# PMOS transistor device extraction
|
||||||
|
extract_devices(mos3("PMOS"), { "SD" => psd, "G" => pgate,
|
||||||
|
"tS" => psd, "tD" => psd, "tG" => poly })
|
||||||
|
|
||||||
|
# NMOS transistor device extraction
|
||||||
|
extract_devices(mos3("NMOS"), { "SD" => nsd, "G" => ngate,
|
||||||
|
"tS" => nsd, "tD" => nsd, "tG" => poly })
|
||||||
|
|
||||||
|
# Define connectivity for netlist extraction
|
||||||
|
|
||||||
|
# Inter-layer
|
||||||
|
connect(psd, diff_cont)
|
||||||
|
connect(nsd, diff_cont)
|
||||||
|
connect(poly, poly_cont)
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Implicit connection of the INV2
|
||||||
|
# VSS nets
|
||||||
|
connect_implicit("INV2", "VSS")
|
||||||
|
|
||||||
|
# Compare section
|
||||||
|
|
||||||
|
netlist.simplify
|
||||||
|
align
|
||||||
|
|
||||||
|
compare
|
||||||
|
|
||||||
|
|
@ -0,0 +1,326 @@
|
||||||
|
#%lvsdb-klayout
|
||||||
|
J(
|
||||||
|
W(INVCHAIN)
|
||||||
|
U(0.001)
|
||||||
|
L(l3 '3/0')
|
||||||
|
L(l11 '3/1')
|
||||||
|
L(l6 '4/0')
|
||||||
|
L(l7 '5/0')
|
||||||
|
L(l8 '6/0')
|
||||||
|
L(l12 '6/1')
|
||||||
|
L(l9 '7/0')
|
||||||
|
L(l10 '8/0')
|
||||||
|
L(l13 '8/1')
|
||||||
|
L(l14)
|
||||||
|
L(l2)
|
||||||
|
L(l5)
|
||||||
|
C(l3 l3 l11 l7)
|
||||||
|
C(l11 l3 l11)
|
||||||
|
C(l6 l6 l8 l2 l5)
|
||||||
|
C(l7 l3 l7 l8)
|
||||||
|
C(l8 l6 l7 l8 l12 l9)
|
||||||
|
C(l12 l8 l12)
|
||||||
|
C(l9 l8 l9 l10)
|
||||||
|
C(l10 l9 l10 l13)
|
||||||
|
C(l13 l10 l13)
|
||||||
|
C(l14 l14)
|
||||||
|
C(l2 l6 l2)
|
||||||
|
C(l5 l6 l5)
|
||||||
|
G(l14 SUBSTRATE)
|
||||||
|
K(PMOS MOS3)
|
||||||
|
K(NMOS MOS3)
|
||||||
|
D(D$PMOS PMOS
|
||||||
|
T(S
|
||||||
|
R(l2 (-900 -475) (775 950))
|
||||||
|
)
|
||||||
|
T(G
|
||||||
|
R(l3 (-125 -475) (250 950))
|
||||||
|
)
|
||||||
|
T(D
|
||||||
|
R(l2 (125 -475) (775 950))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
D(D$NMOS NMOS
|
||||||
|
T(S
|
||||||
|
R(l5 (-900 -475) (775 950))
|
||||||
|
)
|
||||||
|
T(G
|
||||||
|
R(l3 (-125 -475) (250 950))
|
||||||
|
)
|
||||||
|
T(D
|
||||||
|
R(l5 (125 -475) (775 950))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
X(INV
|
||||||
|
R((-1500 -800) (3000 4600))
|
||||||
|
N(1
|
||||||
|
R(l6 (290 -310) (220 220))
|
||||||
|
R(l6 (-220 180) (220 220))
|
||||||
|
R(l8 (-290 -690) (360 760))
|
||||||
|
R(l9 (-305 -705) (250 250))
|
||||||
|
R(l9 (-250 150) (250 250))
|
||||||
|
R(l10 (-2025 -775) (3000 900))
|
||||||
|
R(l5 (-1375 -925) (775 950))
|
||||||
|
)
|
||||||
|
N(2
|
||||||
|
R(l6 (290 2490) (220 220))
|
||||||
|
R(l6 (-220 180) (220 220))
|
||||||
|
R(l8 (-290 -690) (360 760))
|
||||||
|
R(l9 (-305 -705) (250 250))
|
||||||
|
R(l9 (-250 150) (250 250))
|
||||||
|
R(l10 (-2025 -775) (3000 900))
|
||||||
|
R(l2 (-1375 -925) (775 950))
|
||||||
|
)
|
||||||
|
N(3
|
||||||
|
R(l3 (-125 -250) (250 2500))
|
||||||
|
R(l3 (-250 -3050) (250 1600))
|
||||||
|
R(l3 (-250 1200) (250 1600))
|
||||||
|
)
|
||||||
|
N(4
|
||||||
|
R(l6 (-510 -310) (220 220))
|
||||||
|
R(l6 (-220 180) (220 220))
|
||||||
|
R(l6 (-220 2180) (220 220))
|
||||||
|
R(l6 (-220 180) (220 220))
|
||||||
|
R(l8 (-290 -3530) (360 2840))
|
||||||
|
R(l8 (-360 -2800) (360 760))
|
||||||
|
R(l8 (-360 2040) (360 760))
|
||||||
|
R(l2 (-680 -855) (775 950))
|
||||||
|
R(l5 (-775 -3750) (775 950))
|
||||||
|
)
|
||||||
|
P(1)
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
X(INV2
|
||||||
|
R((0 0) (3000 9200))
|
||||||
|
N(1 I(VDD)
|
||||||
|
R(l10 (0 3150) (3000 2900))
|
||||||
|
R(l13 (-1891 -1451) (2 2))
|
||||||
|
)
|
||||||
|
N(2 I(A1)
|
||||||
|
R(l11 (1479 7109) (2 2))
|
||||||
|
)
|
||||||
|
N(3 I(A2)
|
||||||
|
R(l11 (1519 1949) (2 2))
|
||||||
|
)
|
||||||
|
N(4 I(Q1)
|
||||||
|
R(l12 (1919 7069) (2 2))
|
||||||
|
)
|
||||||
|
N(5 I(Q2)
|
||||||
|
R(l12 (1939 1949) (2 2))
|
||||||
|
)
|
||||||
|
N(6 I(VSS)
|
||||||
|
R(l13 (2679 8389) (2 2))
|
||||||
|
R(l13 (-32 -7642) (2 2))
|
||||||
|
)
|
||||||
|
P(1 I(VDD))
|
||||||
|
P(2 I(A1))
|
||||||
|
P(3 I(A2))
|
||||||
|
P(4 I(Q1))
|
||||||
|
P(5 I(Q2))
|
||||||
|
P(6 I(VSS))
|
||||||
|
X(1 INV M O(180) Y(1500 800)
|
||||||
|
P(0 6)
|
||||||
|
P(1 1)
|
||||||
|
P(2 3)
|
||||||
|
P(3 5)
|
||||||
|
)
|
||||||
|
X(2 INV O(180) Y(1500 8400)
|
||||||
|
P(0 6)
|
||||||
|
P(1 1)
|
||||||
|
P(2 2)
|
||||||
|
P(3 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
X(INVCHAIN
|
||||||
|
R((-90 0) (4475 9200))
|
||||||
|
N(1
|
||||||
|
R(l3 (1625 1835) (2160 250))
|
||||||
|
R(l3 (-250 0) (250 4990))
|
||||||
|
R(l3 (-1605 0) (1605 250))
|
||||||
|
R(l7 (-1545 -250) (240 250))
|
||||||
|
R(l8 (-560 -375) (690 510))
|
||||||
|
)
|
||||||
|
N(2 I(IN)
|
||||||
|
R(l3 (-90 6850) (1590 650))
|
||||||
|
R(l11 (-701 -351) (2 2))
|
||||||
|
)
|
||||||
|
N(3 I(OUT)
|
||||||
|
R(l8 (-90 1720) (1890 470))
|
||||||
|
R(l12 (-1171 -231) (2 2))
|
||||||
|
)
|
||||||
|
N(4 I(VSS)
|
||||||
|
R(l10 (3000 655) (1385 250))
|
||||||
|
R(l10 (-250 0) (250 7220))
|
||||||
|
R(l10 (-1385 0) (1385 250))
|
||||||
|
R(l13 (-686 -126) (2 2))
|
||||||
|
)
|
||||||
|
N(5 I(VDD)
|
||||||
|
R(l13 (2299 4599) (2 2))
|
||||||
|
)
|
||||||
|
P(2 I(IN))
|
||||||
|
P(3 I(OUT))
|
||||||
|
P(4 I(VSS))
|
||||||
|
P(5 I(VDD))
|
||||||
|
X(1 INV2 Y(0 0)
|
||||||
|
P(0 5)
|
||||||
|
P(1 2)
|
||||||
|
P(2 1)
|
||||||
|
P(3 1)
|
||||||
|
P(4 3)
|
||||||
|
P(5 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
H(
|
||||||
|
K(PMOS MOS3)
|
||||||
|
K(NMOS MOS3)
|
||||||
|
X(INV
|
||||||
|
N(1 I(VDD))
|
||||||
|
N(2 I(VSS))
|
||||||
|
N(3 I(A))
|
||||||
|
N(4 I(Q))
|
||||||
|
P(1 I(VDD))
|
||||||
|
P(2 I(VSS))
|
||||||
|
P(3 I(A))
|
||||||
|
P(4 I(Q))
|
||||||
|
D(1 PMOS
|
||||||
|
I($1)
|
||||||
|
E(L 0.25)
|
||||||
|
E(W 0.95)
|
||||||
|
E(AS 0)
|
||||||
|
E(AD 0)
|
||||||
|
E(PS 0)
|
||||||
|
E(PD 0)
|
||||||
|
T(S 1)
|
||||||
|
T(G 3)
|
||||||
|
T(D 4)
|
||||||
|
)
|
||||||
|
D(2 NMOS
|
||||||
|
I($3)
|
||||||
|
E(L 0.25)
|
||||||
|
E(W 0.95)
|
||||||
|
E(AS 0)
|
||||||
|
E(AD 0)
|
||||||
|
E(PS 0)
|
||||||
|
E(PD 0)
|
||||||
|
T(S 2)
|
||||||
|
T(G 3)
|
||||||
|
T(D 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
X(INV2
|
||||||
|
N(1 I(VDD))
|
||||||
|
N(2 I(VSS))
|
||||||
|
N(3 I(A1))
|
||||||
|
N(4 I(Q1))
|
||||||
|
N(5 I(A2))
|
||||||
|
N(6 I(Q2))
|
||||||
|
P(1 I(VDD))
|
||||||
|
P(2 I(VSS))
|
||||||
|
P(3 I(A1))
|
||||||
|
P(4 I(Q1))
|
||||||
|
P(5 I(A2))
|
||||||
|
P(6 I(Q2))
|
||||||
|
X(1 INV I($1)
|
||||||
|
P(0 1)
|
||||||
|
P(1 2)
|
||||||
|
P(2 3)
|
||||||
|
P(3 4)
|
||||||
|
)
|
||||||
|
X(2 INV I($2)
|
||||||
|
P(0 1)
|
||||||
|
P(1 2)
|
||||||
|
P(2 5)
|
||||||
|
P(3 6)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
X(INVCHAIN
|
||||||
|
N(1 I('1'))
|
||||||
|
N(2 I('2'))
|
||||||
|
N(3 I('3'))
|
||||||
|
N(4 I('4'))
|
||||||
|
N(5 I('5'))
|
||||||
|
X(1 INV2 I($2)
|
||||||
|
P(0 1)
|
||||||
|
P(1 2)
|
||||||
|
P(2 3)
|
||||||
|
P(3 4)
|
||||||
|
P(4 4)
|
||||||
|
P(5 5)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Z(
|
||||||
|
X(INV INV 1
|
||||||
|
Z(
|
||||||
|
N(3 3 1)
|
||||||
|
N(4 4 1)
|
||||||
|
N(2 1 1)
|
||||||
|
N(1 2 1)
|
||||||
|
P(2 2 1)
|
||||||
|
P(3 3 1)
|
||||||
|
P(1 0 1)
|
||||||
|
P(0 1 1)
|
||||||
|
D(2 2 1)
|
||||||
|
D(1 1 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
X(INV2 INV2 1
|
||||||
|
Z(
|
||||||
|
N(2 3 1)
|
||||||
|
N(3 5 1)
|
||||||
|
N(4 4 W)
|
||||||
|
N(5 6 W)
|
||||||
|
N(1 1 1)
|
||||||
|
N(6 2 1)
|
||||||
|
P(1 2 1)
|
||||||
|
P(2 4 1)
|
||||||
|
P(3 3 1)
|
||||||
|
P(4 5 1)
|
||||||
|
P(0 0 1)
|
||||||
|
P(5 1 1)
|
||||||
|
X(2 1 1)
|
||||||
|
X(1 2 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
X(INVCHAIN INVCHAIN 1
|
||||||
|
Z(
|
||||||
|
N(1 4 1)
|
||||||
|
N(2 3 1)
|
||||||
|
N(3 5 1)
|
||||||
|
N(5 1 1)
|
||||||
|
N(4 2 1)
|
||||||
|
P(0 () 1)
|
||||||
|
P(1 () 1)
|
||||||
|
P(3 () 1)
|
||||||
|
P(2 () 1)
|
||||||
|
X(1 1 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
* Extracted by KLayout
|
||||||
|
|
||||||
|
.SUBCKT INVCHAIN ANY R ANY$1 PWR GND
|
||||||
|
X$1 ANY R R ANY$1 PWR GND INV2
|
||||||
|
.ENDS INVCHAIN
|
||||||
|
|
||||||
|
.SUBCKT INV2 A1 A2 Q1 Q2 R VSS
|
||||||
|
X$1 VSS R A1 Q1 INV
|
||||||
|
X$2 VSS R A2 Q2 INV
|
||||||
|
.ENDS INV2
|
||||||
|
|
||||||
|
.SUBCKT INV \$1 \$2 \$3 \$4
|
||||||
|
M$1 \$4 \$3 \$2 \$4 PMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U
|
||||||
|
+ PD=3.45U
|
||||||
|
M$2 \$4 \$3 \$1 \$4 NMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U
|
||||||
|
+ PD=3.45U
|
||||||
|
.ENDS INV
|
||||||
|
|
@ -0,0 +1,135 @@
|
||||||
|
|
||||||
|
source($lvs_test_source)
|
||||||
|
|
||||||
|
report_lvs($lvs_test_target_lvsdb)
|
||||||
|
|
||||||
|
writer = write_spice(true, false)
|
||||||
|
target_netlist($lvs_test_target_cir, writer, "Extracted by KLayout")
|
||||||
|
|
||||||
|
# needs this delegate because we use MOS3 which is not available in Spice
|
||||||
|
class SpiceReaderDelegate < RBA::NetlistSpiceReaderDelegate
|
||||||
|
|
||||||
|
# says we want to catch these subcircuits as devices
|
||||||
|
def wants_subcircuit(name)
|
||||||
|
name == "HVNMOS" || name == "HVPMOS"
|
||||||
|
end
|
||||||
|
|
||||||
|
# translate the element
|
||||||
|
def element(circuit, el, name, model, value, nets, params)
|
||||||
|
|
||||||
|
if el != "M"
|
||||||
|
# all other elements are left to the standard implementation
|
||||||
|
return super
|
||||||
|
end
|
||||||
|
|
||||||
|
if nets.size != 4
|
||||||
|
error("Device #{model} needs four nodes")
|
||||||
|
end
|
||||||
|
|
||||||
|
# provide a device class
|
||||||
|
cls = circuit.netlist.device_class_by_name(model)
|
||||||
|
if ! cls
|
||||||
|
cls = RBA::DeviceClassMOS3Transistor::new
|
||||||
|
cls.name = model
|
||||||
|
circuit.netlist.add(cls)
|
||||||
|
end
|
||||||
|
|
||||||
|
# create a device
|
||||||
|
device = circuit.create_device(cls, name)
|
||||||
|
|
||||||
|
# and configure the device
|
||||||
|
[ "S", "G", "D" ].each_with_index do |t,index|
|
||||||
|
device.connect_terminal(t, nets[index])
|
||||||
|
end
|
||||||
|
device.set_parameter("W", params["W"] * 1e6)
|
||||||
|
device.set_parameter("L", params["L"] * 1e6)
|
||||||
|
|
||||||
|
device
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
reader = RBA::NetlistSpiceReader::new(SpiceReaderDelegate::new)
|
||||||
|
schematic("double_height_inv.cir", reader)
|
||||||
|
|
||||||
|
deep
|
||||||
|
|
||||||
|
# Drawing layers
|
||||||
|
|
||||||
|
nwell = input(1, 0)
|
||||||
|
active = input(2, 0)
|
||||||
|
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
|
||||||
|
pgate = pactive & poly
|
||||||
|
psd = pactive - pgate
|
||||||
|
|
||||||
|
active_outside_nwell = active - nwell
|
||||||
|
nactive = active_outside_nwell
|
||||||
|
ngate = nactive & poly
|
||||||
|
nsd = nactive - ngate
|
||||||
|
|
||||||
|
# Device extraction
|
||||||
|
|
||||||
|
# PMOS transistor device extraction
|
||||||
|
extract_devices(mos3("PMOS"), { "SD" => psd, "G" => pgate,
|
||||||
|
"tS" => psd, "tD" => psd, "tG" => poly })
|
||||||
|
|
||||||
|
# NMOS transistor device extraction
|
||||||
|
extract_devices(mos3("NMOS"), { "SD" => nsd, "G" => ngate,
|
||||||
|
"tS" => nsd, "tD" => nsd, "tG" => poly })
|
||||||
|
|
||||||
|
# Define connectivity for netlist extraction
|
||||||
|
|
||||||
|
# Inter-layer
|
||||||
|
connect(psd, diff_cont)
|
||||||
|
connect(nsd, diff_cont)
|
||||||
|
connect(poly, poly_cont)
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Implicit connection of the INV2
|
||||||
|
# VSS nets
|
||||||
|
connect_implicit("GND")
|
||||||
|
connect_implicit("?") # "R"
|
||||||
|
connect_implicit("DOESNOTEXIST")
|
||||||
|
connect_implicit("*2", "*SS")
|
||||||
|
connect_implicit("*", "R")
|
||||||
|
connect_implicit("DOESNOTEXIST", "DOESNOTEXIST")
|
||||||
|
|
||||||
|
# Compare section
|
||||||
|
|
||||||
|
netlist.simplify
|
||||||
|
align
|
||||||
|
|
||||||
|
compare
|
||||||
|
|
||||||
|
|
@ -0,0 +1,325 @@
|
||||||
|
#%lvsdb-klayout
|
||||||
|
J(
|
||||||
|
W(INVCHAIN)
|
||||||
|
U(0.001)
|
||||||
|
L(l3 '3/0')
|
||||||
|
L(l11 '3/1')
|
||||||
|
L(l6 '4/0')
|
||||||
|
L(l7 '2/0')
|
||||||
|
L(l8 '6/0')
|
||||||
|
L(l12 '6/1')
|
||||||
|
L(l9 '7/0')
|
||||||
|
L(l10 '8/0')
|
||||||
|
L(l13 '8/1')
|
||||||
|
L(l14)
|
||||||
|
L(l2)
|
||||||
|
L(l5)
|
||||||
|
C(l3 l3 l11 l7)
|
||||||
|
C(l11 l3 l11)
|
||||||
|
C(l6 l6 l8 l2 l5)
|
||||||
|
C(l7 l3 l7 l8)
|
||||||
|
C(l8 l6 l7 l8 l12 l9)
|
||||||
|
C(l12 l8 l12)
|
||||||
|
C(l9 l8 l9 l10)
|
||||||
|
C(l10 l9 l10 l13)
|
||||||
|
C(l13 l10 l13)
|
||||||
|
C(l14 l14)
|
||||||
|
C(l2 l6 l2)
|
||||||
|
C(l5 l6 l5)
|
||||||
|
G(l14 SUBSTRATE)
|
||||||
|
K(PMOS MOS3)
|
||||||
|
K(NMOS MOS3)
|
||||||
|
D(D$PMOS PMOS
|
||||||
|
T(S
|
||||||
|
R(l2 (-900 -475) (775 950))
|
||||||
|
)
|
||||||
|
T(G
|
||||||
|
R(l3 (-125 -475) (250 950))
|
||||||
|
)
|
||||||
|
T(D
|
||||||
|
R(l2 (125 -475) (775 950))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
D(D$NMOS NMOS
|
||||||
|
T(S
|
||||||
|
R(l5 (-900 -475) (775 950))
|
||||||
|
)
|
||||||
|
T(G
|
||||||
|
R(l3 (-125 -475) (250 950))
|
||||||
|
)
|
||||||
|
T(D
|
||||||
|
R(l5 (125 -475) (775 950))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
X(INV
|
||||||
|
R((-1500 -800) (3000 4600))
|
||||||
|
N(1
|
||||||
|
R(l6 (290 -310) (220 220))
|
||||||
|
R(l6 (-220 180) (220 220))
|
||||||
|
R(l8 (-290 -690) (360 760))
|
||||||
|
R(l9 (-305 -705) (250 250))
|
||||||
|
R(l9 (-250 150) (250 250))
|
||||||
|
R(l10 (-2025 -775) (3000 900))
|
||||||
|
R(l5 (-1375 -925) (775 950))
|
||||||
|
)
|
||||||
|
N(2
|
||||||
|
R(l6 (290 2490) (220 220))
|
||||||
|
R(l6 (-220 180) (220 220))
|
||||||
|
R(l8 (-290 -690) (360 760))
|
||||||
|
R(l9 (-305 -705) (250 250))
|
||||||
|
R(l9 (-250 150) (250 250))
|
||||||
|
R(l10 (-2025 -775) (3000 900))
|
||||||
|
R(l2 (-1375 -925) (775 950))
|
||||||
|
)
|
||||||
|
N(3
|
||||||
|
R(l3 (-125 -250) (250 2500))
|
||||||
|
R(l3 (-250 -3050) (250 1600))
|
||||||
|
R(l3 (-250 1200) (250 1600))
|
||||||
|
)
|
||||||
|
N(4
|
||||||
|
R(l6 (-510 -310) (220 220))
|
||||||
|
R(l6 (-220 180) (220 220))
|
||||||
|
R(l6 (-220 2180) (220 220))
|
||||||
|
R(l6 (-220 180) (220 220))
|
||||||
|
R(l8 (-290 -3530) (360 2840))
|
||||||
|
R(l8 (-360 -2800) (360 760))
|
||||||
|
R(l8 (-360 2040) (360 760))
|
||||||
|
R(l2 (-680 -855) (775 950))
|
||||||
|
R(l5 (-775 -3750) (775 950))
|
||||||
|
)
|
||||||
|
P(1)
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
X(INV2
|
||||||
|
R((0 0) (3000 9200))
|
||||||
|
N(1 I(A1)
|
||||||
|
R(l11 (1479 7109) (2 2))
|
||||||
|
)
|
||||||
|
N(2 I(A2)
|
||||||
|
R(l11 (1519 1949) (2 2))
|
||||||
|
)
|
||||||
|
N(3 I(Q1)
|
||||||
|
R(l12 (1919 7069) (2 2))
|
||||||
|
)
|
||||||
|
N(4 I(Q2)
|
||||||
|
R(l12 (1939 1949) (2 2))
|
||||||
|
)
|
||||||
|
N(5 I(R)
|
||||||
|
R(l13 (2719 5559) (2 2))
|
||||||
|
R(l13 (-92 -1942) (2 2))
|
||||||
|
)
|
||||||
|
N(6 I(VSS)
|
||||||
|
R(l13 (2679 8389) (2 2))
|
||||||
|
R(l13 (-32 -7642) (2 2))
|
||||||
|
)
|
||||||
|
P(1 I(A1))
|
||||||
|
P(2 I(A2))
|
||||||
|
P(3 I(Q1))
|
||||||
|
P(4 I(Q2))
|
||||||
|
P(5 I(R))
|
||||||
|
P(6 I(VSS))
|
||||||
|
X(1 INV O(180) Y(1500 8400)
|
||||||
|
P(0 6)
|
||||||
|
P(1 5)
|
||||||
|
P(2 1)
|
||||||
|
P(3 3)
|
||||||
|
)
|
||||||
|
X(2 INV M O(180) Y(1500 800)
|
||||||
|
P(0 6)
|
||||||
|
P(1 5)
|
||||||
|
P(2 2)
|
||||||
|
P(3 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
X(INVCHAIN
|
||||||
|
R((-90 0) (3090 9200))
|
||||||
|
N(1 I(ANY)
|
||||||
|
R(l3 (-90 6850) (1590 650))
|
||||||
|
R(l11 (-701 -351) (2 2))
|
||||||
|
)
|
||||||
|
N(2 I(R)
|
||||||
|
R(l11 (1479 2369) (2 2))
|
||||||
|
R(l8 (439 4579) (690 510))
|
||||||
|
R(l12 (-301 -291) (2 2))
|
||||||
|
)
|
||||||
|
N(3 I(ANY)
|
||||||
|
R(l8 (-90 1720) (1890 470))
|
||||||
|
R(l12 (-1171 -231) (2 2))
|
||||||
|
)
|
||||||
|
N(4 I(PWR)
|
||||||
|
R(l13 (299 5549) (2 2))
|
||||||
|
R(l13 (-12 -1992) (2 2))
|
||||||
|
)
|
||||||
|
N(5 I(GND)
|
||||||
|
R(l13 (319 8399) (2 2))
|
||||||
|
R(l13 (-52 -7602) (2 2))
|
||||||
|
)
|
||||||
|
P(1 I(ANY))
|
||||||
|
P(2 I(R))
|
||||||
|
P(3 I(ANY))
|
||||||
|
P(4 I(PWR))
|
||||||
|
P(5 I(GND))
|
||||||
|
X(1 INV2 Y(0 0)
|
||||||
|
P(0 1)
|
||||||
|
P(1 2)
|
||||||
|
P(2 2)
|
||||||
|
P(3 3)
|
||||||
|
P(4 4)
|
||||||
|
P(5 5)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
H(
|
||||||
|
K(PMOS MOS3)
|
||||||
|
K(NMOS MOS3)
|
||||||
|
X(INV
|
||||||
|
N(1 I(VDD))
|
||||||
|
N(2 I(VSS))
|
||||||
|
N(3 I(A))
|
||||||
|
N(4 I(Q))
|
||||||
|
P(1 I(VDD))
|
||||||
|
P(2 I(VSS))
|
||||||
|
P(3 I(A))
|
||||||
|
P(4 I(Q))
|
||||||
|
D(1 PMOS
|
||||||
|
I($1)
|
||||||
|
E(L 0.25)
|
||||||
|
E(W 0.95)
|
||||||
|
E(AS 0)
|
||||||
|
E(AD 0)
|
||||||
|
E(PS 0)
|
||||||
|
E(PD 0)
|
||||||
|
T(S 1)
|
||||||
|
T(G 3)
|
||||||
|
T(D 4)
|
||||||
|
)
|
||||||
|
D(2 NMOS
|
||||||
|
I($3)
|
||||||
|
E(L 0.25)
|
||||||
|
E(W 0.95)
|
||||||
|
E(AS 0)
|
||||||
|
E(AD 0)
|
||||||
|
E(PS 0)
|
||||||
|
E(PD 0)
|
||||||
|
T(S 2)
|
||||||
|
T(G 3)
|
||||||
|
T(D 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
X(INV2
|
||||||
|
N(1 I(VDD))
|
||||||
|
N(2 I(VSS))
|
||||||
|
N(3 I(A1))
|
||||||
|
N(4 I(Q1))
|
||||||
|
N(5 I(A2))
|
||||||
|
N(6 I(Q2))
|
||||||
|
P(1 I(VDD))
|
||||||
|
P(2 I(VSS))
|
||||||
|
P(3 I(A1))
|
||||||
|
P(4 I(Q1))
|
||||||
|
P(5 I(A2))
|
||||||
|
P(6 I(Q2))
|
||||||
|
X(1 INV I($1)
|
||||||
|
P(0 1)
|
||||||
|
P(1 2)
|
||||||
|
P(2 3)
|
||||||
|
P(3 4)
|
||||||
|
)
|
||||||
|
X(2 INV I($2)
|
||||||
|
P(0 1)
|
||||||
|
P(1 2)
|
||||||
|
P(2 5)
|
||||||
|
P(3 6)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
X(INVCHAIN
|
||||||
|
N(1 I('1'))
|
||||||
|
N(2 I('2'))
|
||||||
|
N(3 I('3'))
|
||||||
|
N(4 I('4'))
|
||||||
|
N(5 I('5'))
|
||||||
|
X(1 INV2 I($2)
|
||||||
|
P(0 1)
|
||||||
|
P(1 2)
|
||||||
|
P(2 3)
|
||||||
|
P(3 4)
|
||||||
|
P(4 4)
|
||||||
|
P(5 5)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Z(
|
||||||
|
X(INV INV 1
|
||||||
|
Z(
|
||||||
|
N(3 3 1)
|
||||||
|
N(4 4 1)
|
||||||
|
N(2 1 1)
|
||||||
|
N(1 2 1)
|
||||||
|
P(2 2 1)
|
||||||
|
P(3 3 1)
|
||||||
|
P(1 0 1)
|
||||||
|
P(0 1 1)
|
||||||
|
D(2 2 1)
|
||||||
|
D(1 1 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
X(INV2 INV2 1
|
||||||
|
Z(
|
||||||
|
N(1 3 1)
|
||||||
|
N(2 5 1)
|
||||||
|
N(3 4 W)
|
||||||
|
N(4 6 W)
|
||||||
|
N(5 1 1)
|
||||||
|
N(6 2 1)
|
||||||
|
P(0 2 1)
|
||||||
|
P(1 4 1)
|
||||||
|
P(2 3 1)
|
||||||
|
P(3 5 1)
|
||||||
|
P(4 0 1)
|
||||||
|
P(5 1 1)
|
||||||
|
X(1 1 1)
|
||||||
|
X(2 2 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
X(INVCHAIN INVCHAIN 1
|
||||||
|
Z(
|
||||||
|
N(1 3 1)
|
||||||
|
N(3 5 1)
|
||||||
|
N(5 2 1)
|
||||||
|
N(4 1 1)
|
||||||
|
N(2 4 1)
|
||||||
|
P(2 () 1)
|
||||||
|
P(0 () 1)
|
||||||
|
P(4 () 1)
|
||||||
|
P(3 () 1)
|
||||||
|
P(1 () 1)
|
||||||
|
X(1 1 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
* cell INVCHAIN
|
||||||
|
.SUBCKT INVCHAIN
|
||||||
|
X$2 1 2 3 4 4 5 INV2
|
||||||
|
.ENDS INVCHAIN
|
||||||
|
|
||||||
|
* cell INV2
|
||||||
|
.SUBCKT INV2 VDD VSS A1 Q1 A2 Q2
|
||||||
|
X$1 VDD VSS A1 Q1 INV
|
||||||
|
X$2 VDD VSS A2 Q2 INV
|
||||||
|
.ENDS INV2
|
||||||
|
|
||||||
|
* cell INV
|
||||||
|
.SUBCKT INV VDD VSS A Q
|
||||||
|
M$1 VDD A Q VDD PMOS L=0.25U W=0.95U
|
||||||
|
M$3 VSS A Q VSS NMOS L=0.25U W=0.95U
|
||||||
|
.ENDS INV
|
||||||
|
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
* cell INVCHAIN
|
||||||
|
.SUBCKT INVCHAIN
|
||||||
|
X$2 1 2 3 4 4 5 INV2
|
||||||
|
.ENDS INVCHAIN
|
||||||
|
|
||||||
|
* cell INV2
|
||||||
|
.SUBCKT INV2 VDD VSS A1 Q1 A2 Q2
|
||||||
|
X$1 VDD VSS A1 Q1 INV
|
||||||
|
X$2 VDD VSS A2 Q2 INV
|
||||||
|
.ENDS INV2
|
||||||
|
|
||||||
|
* cell INV
|
||||||
|
.SUBCKT INV VDD VSS A Q
|
||||||
|
M$1 VDD A Q VDD PMOS L=0.25U W=0.95U
|
||||||
|
M$3 VSS A Q VSS NMOS L=0.25U W=0.95U
|
||||||
|
.ENDS INV
|
||||||
|
|
||||||
Binary file not shown.
Loading…
Reference in New Issue