Implemented #444 (double-height standard-cell support).

This commit is contained in:
Matthias Koefferlein 2019-12-17 00:12:20 +01:00
parent 412fe2bbf9
commit d0e6efa484
20 changed files with 1152 additions and 19 deletions

View File

@ -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;
} }
} }

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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"

View File

@ -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

View File

@ -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>

View File

@ -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");
}

17
testdata/lvs/double_height.cir vendored Normal file
View File

@ -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

130
testdata/lvs/double_height.lvs vendored Normal file
View File

@ -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

326
testdata/lvs/double_height.lvsdb vendored Normal file
View File

@ -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)
)
)
)

17
testdata/lvs/double_height2.cir vendored Normal file
View File

@ -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

135
testdata/lvs/double_height2.lvs vendored Normal file
View File

@ -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

325
testdata/lvs/double_height2.lvsdb vendored Normal file
View File

@ -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)
)
)
)

18
testdata/lvs/double_height2_inv.cir vendored Normal file
View File

@ -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

BIN
testdata/lvs/double_height2_inv.gds vendored Normal file

Binary file not shown.

18
testdata/lvs/double_height_inv.cir vendored Normal file
View File

@ -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

BIN
testdata/lvs/double_height_inv.gds vendored Normal file

Binary file not shown.