explicit net joining - preparations

This commit is contained in:
Matthias Koefferlein 2021-03-27 21:56:53 +01:00
parent e0eac2147b
commit 9f295523e4
14 changed files with 1030 additions and 83 deletions

View File

@ -40,7 +40,7 @@ namespace db
// 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_iter (iter), m_layout_index (0), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false)
{
// check the iterator
if (iter.has_complex_region () || iter.region () != db::Box::world ()) {
@ -60,7 +60,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)
: 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)
{
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> ());
@ -68,7 +68,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_iter (), m_netlist_extracted (false), m_is_flat (true), m_device_scaling (1.0), m_include_floating_subcircuits (false)
{
mp_internal_dss.reset (new db::DeepShapeStore (topcell_name, dbu));
mp_dss.reset (mp_internal_dss.get ());
@ -79,7 +79,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_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false)
{
init ();
}
@ -310,37 +310,91 @@ size_t LayoutToNetlist::global_net_id (const std::string &name)
return m_conn.global_net_id (name);
}
void LayoutToNetlist::extract_netlist (const std::string &joined_net_names, bool include_floating_subcircuits)
void LayoutToNetlist::set_include_floating_subcircuits (bool f)
{
extract_netlist (joined_net_names, std::map<std::string, std::string> (), include_floating_subcircuits);
m_include_floating_subcircuits = f;
}
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)
void LayoutToNetlist::clear_join_net_names ()
{
m_joined_net_names.clear ();
m_joined_net_names_per_cell.clear ();
}
void LayoutToNetlist::join_net_names (const tl::GlobPattern &gp)
{
m_joined_net_names.push_back (gp);
}
void LayoutToNetlist::join_net_names (const tl::GlobPattern &cell, const tl::GlobPattern &gp)
{
m_joined_net_names_per_cell.push_back (std::make_pair (cell, gp));
}
void LayoutToNetlist::clear_join_nets ()
{
m_joined_nets.clear ();
m_joined_nets_per_cell.clear ();
}
void LayoutToNetlist::join_nets (const std::set<std::string> &jn)
{
m_joined_nets.push_back (jn);
}
void LayoutToNetlist::join_nets (const tl::GlobPattern &cell, const std::set<std::string> &gp)
{
m_joined_nets_per_cell.push_back (std::make_pair (cell, gp));
}
void LayoutToNetlist::extract_netlist ()
{
if (m_netlist_extracted) {
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
}
ensure_netlist ();
const db::Layout &layout = dss ().layout (m_layout_index);
db::NetlistExtractor netex;
netex.set_joined_net_names (joined_net_names);
netex.set_joined_net_names (m_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);
std::map<std::string, std::list<tl::GlobPattern> > jp_per_cell;
for (std::list<std::pair<tl::GlobPattern, tl::GlobPattern> >::const_iterator j = m_joined_net_names_per_cell.begin (); j != m_joined_net_names_per_cell.end (); ++j) {
if (j->first.is_const ()) {
jp_per_cell [j->first.pattern ()].push_back (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);
if (j->first.match (layout.cell_name (c->cell_index ()))) {
jp_per_cell [layout.cell_name (c->cell_index ())].push_back (j->second);
}
}
}
}
for (std::map<std::string, std::list<tl::GlobPattern> >::const_iterator i = jp_per_cell.begin (); i != jp_per_cell.end (); ++i) {
netex.set_joined_net_names (i->first, i->second);
}
netex.set_include_floating_subcircuits (include_floating_subcircuits);
netex.set_joined_nets (m_joined_nets);
std::map<std::string, std::list<std::set<std::string> > > jn_per_cell;
for (std::list<std::pair<tl::GlobPattern, std::set<std::string> > >::const_iterator j = m_joined_nets_per_cell.begin (); j != m_joined_nets_per_cell.end (); ++j) {
if (j->first.is_const ()) {
jn_per_cell [j->first.pattern ()].push_back (j->second);
} else {
for (db::Layout::const_iterator c = layout.begin (); c != layout.end (); ++c) {
if (j->first.match (layout.cell_name (c->cell_index ()))) {
jn_per_cell [layout.cell_name (c->cell_index ())].push_back (j->second);
}
}
}
}
for (std::map<std::string, std::list<std::set<std::string> > >::const_iterator i = jn_per_cell.begin (); i != jn_per_cell.end (); ++i) {
netex.set_joined_nets (i->first, i->second);
}
netex.set_include_floating_subcircuits (m_include_floating_subcircuits);
netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters);
m_netlist_extracted = true;

View File

@ -27,6 +27,7 @@
#include "dbCellMapping.h"
#include "dbNetlistExtractor.h"
#include "dbNetlistDeviceExtractor.h"
#include "tlGlobPattern.h"
namespace db
{
@ -423,20 +424,106 @@ public:
size_t global_net_id (const std::string &name);
/**
* @brief Runs the netlist extraction
* See the class description for more details.
* @brief Sets a flag indicating whether to include floating subcircuits
*/
void extract_netlist (const std::string &joined_net_names = std::string (), bool include_floating_subcircuits = false);
void set_include_floating_subcircuits (bool f);
/**
* @brief Sets a flag indicating whether to include floating subcircuits
*/
bool include_floating_subcircuits () const
{
return m_include_floating_subcircuits;
}
/**
* @brief Clears the "join net names" settings
*/
void clear_join_net_names ();
/**
* @brief Joins net names matching the given expression
*
* Using this function will *add* one more rule. To clear all registered rules, use "clear_join_net_names".
* These pattern will only act on top level cells.
*/
void join_net_names (const tl::GlobPattern &gp);
/**
* @brief Joins net names matching the given expression
*
* Using this function will *add* one more rule specific to cells matching the first glob pattern. To clear all registered rules, use "clear_join_net_names".
* Pattern registered with this function will act on the given cells, regardless of whether it's top level or not.
*/
void join_net_names (const tl::GlobPattern &cell, const tl::GlobPattern &gp);
/**
* @brief Gets the joined net names for top level
*
* This method is mainly provided to test purposes.
*/
const std::list<tl::GlobPattern> &joined_net_names () const
{
return m_joined_net_names;
}
/**
* @brief Gets the joined net names per cell
*
* This method is mainly provided to test purposes.
*/
const std::list<std::pair<tl::GlobPattern, tl::GlobPattern> > &joined_net_names_per_cell () const
{
return m_joined_net_names_per_cell;
}
/**
* @brief Clears the "join nets" settings
*/
void clear_join_nets ();
/**
* @brief Joins the given nets for the top level cell
*
* This method will make an explicit connection between the nets given in the name set.
* This applies implicit joining of different nets with the same label (intra-net joining)
* and of nets with different names (inter-net joining). Intra-net joining is implied always.
*/
void join_nets (const std::set<std::string> &jn);
/**
* @brief Joins the given nets for cells matching the given pattern
*
* Using this function will *add* one more rule specific to cells matching the first glob pattern. To clear all registered rules, use "clear_join_nets".
* Pattern registered with this function will act on the given cells, regardless of whether it's top level or not.
*/
void join_nets (const tl::GlobPattern &cell, const std::set<std::string> &gp);
/**
* @brief Gets the joined nets for top level
*
* This method is mainly provided to test purposes.
*/
const std::list<std::set<std::string> > &joined_nets () const
{
return m_joined_nets;
}
/**
* @brief Gets the joined nets per cell
*
* This method is mainly provided to test purposes.
*/
const std::list<std::pair<tl::GlobPattern, std::set<std::string> > > &joined_nets_per_cell () const
{
return m_joined_nets_per_cell;
}
/**
* @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.
* See the class description for more details.
*/
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);
void extract_netlist ();
/**
* @brief Marks the netlist as extracted
@ -830,6 +917,11 @@ private:
double m_device_scaling;
db::DeepLayer m_dummy_layer;
std::string m_generator;
bool m_include_floating_subcircuits;
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;
std::list<std::pair<tl::GlobPattern, std::set<std::string> > > m_joined_nets_per_cell;
struct CellReuseTableKey
{

View File

@ -35,33 +35,44 @@ NetlistExtractor::NetlistExtractor ()
// .. nothing yet ..
}
void NetlistExtractor::set_joined_net_names (const std::string &jnn)
void NetlistExtractor::set_joined_net_names (const std::list<tl::GlobPattern> &jnn)
{
m_joined_net_names = jnn;
}
void NetlistExtractor::set_joined_net_names (const std::string &cellname, const std::string &jnn)
void NetlistExtractor::set_joined_net_names (const std::string &cellname, const std::list<tl::GlobPattern> &jnn)
{
m_joined_net_names_per_cell.push_back (std::make_pair (cellname, jnn));
}
void NetlistExtractor::set_joined_nets (const std::list<std::set<std::string> > &jnn)
{
m_joined_nets = jnn;
}
void NetlistExtractor::set_joined_nets (const std::string &cell_name, const std::list<std::set<std::string> > &jnn)
{
m_joined_nets_per_cell.push_back (std::make_pair (cell_name, jnn));
}
void NetlistExtractor::set_include_floating_subcircuits (bool f)
{
m_include_floating_subcircuits = f;
}
static void
build_net_name_equivalence (const db::Layout *layout, const db::Connectivity &conn, db::property_names_id_type net_name_id, const std::string &joined_net_names, tl::equivalence_clusters<size_t> &eq)
build_net_name_equivalence (const db::Layout *layout, const db::Connectivity &conn, db::property_names_id_type net_name_id, const std::list<tl::GlobPattern> &jn_pattern, tl::equivalence_clusters<size_t> &eq)
{
std::map<std::string, std::set<size_t> > prop_by_name;
tl::GlobPattern jn_pattern (joined_net_names);
for (db::PropertiesRepository::iterator i = layout->properties_repository ().begin (); i != layout->properties_repository ().end (); ++i) {
for (db::PropertiesRepository::properties_set::const_iterator p = i->second.begin (); p != i->second.end (); ++p) {
if (p->first == net_name_id) {
std::string nn = p->second.to_string ();
if (jn_pattern.match (nn)) {
prop_by_name [nn].insert (db::prop_id_to_attr (i->first));
for (std::list<tl::GlobPattern>::const_iterator jp = jn_pattern.begin (); jp != jn_pattern.end (); ++jp) {
if (jp->match (nn)) {
prop_by_name [nn].insert (db::prop_id_to_attr (i->first));
}
}
}
}
@ -70,16 +81,20 @@ build_net_name_equivalence (const db::Layout *layout, const db::Connectivity &co
// include pseudo-attributes for global nets to implement "join_with" for global nets
for (size_t gid = 0; gid < conn.global_nets (); ++gid) {
const std::string &gn = conn.global_net_name (gid);
if (jn_pattern.match (gn)) {
prop_by_name [gn].insert (db::global_net_id_to_attr (gid));
for (std::list<tl::GlobPattern>::const_iterator jp = jn_pattern.begin (); jp != jn_pattern.end (); ++jp) {
if (jp->match (gn)) {
prop_by_name [gn].insert (db::global_net_id_to_attr (gid));
}
}
}
const db::repository<db::Text> &text_repository = layout->shape_repository ().repository (db::object_tag<db::Text> ());
for (db::repository<db::Text>::iterator t = text_repository.begin (); t != text_repository.end (); ++t) {
std::string nn = t->string ();
if (jn_pattern.match (nn)) {
prop_by_name [nn].insert (db::text_ref_to_attr (t.operator-> ()));
for (std::list<tl::GlobPattern>::const_iterator jp = jn_pattern.begin (); jp != jn_pattern.end (); ++jp) {
if (jp->match (nn)) {
prop_by_name [nn].insert (db::text_ref_to_attr (t.operator-> ()));
}
}
}
@ -93,6 +108,58 @@ build_net_name_equivalence (const db::Layout *layout, const db::Connectivity &co
}
}
static void
build_net_name_equivalence_for_explicit_connections (const db::Layout *layout, const db::Connectivity &conn, db::property_names_id_type net_name_id, const std::set<std::string> &nets_to_join, tl::equivalence_clusters<size_t> &eq)
{
std::map<std::string, std::set<size_t> > prop_by_name;
for (db::PropertiesRepository::iterator i = layout->properties_repository ().begin (); i != layout->properties_repository ().end (); ++i) {
for (db::PropertiesRepository::properties_set::const_iterator p = i->second.begin (); p != i->second.end (); ++p) {
if (p->first == net_name_id) {
std::string nn = p->second.to_string ();
if (nets_to_join.find (nn) != nets_to_join.end ()) {
prop_by_name [nn].insert (db::prop_id_to_attr (i->first));
}
}
}
}
// include pseudo-attributes for global nets to implement "join_with" for global nets
for (size_t gid = 0; gid < conn.global_nets (); ++gid) {
const std::string &gn = conn.global_net_name (gid);
if (nets_to_join.find (gn) != nets_to_join.end ()) {
prop_by_name [gn].insert (db::global_net_id_to_attr (gid));
}
}
const db::repository<db::Text> &text_repository = layout->shape_repository ().repository (db::object_tag<db::Text> ());
for (db::repository<db::Text>::iterator t = text_repository.begin (); t != text_repository.end (); ++t) {
std::string nn = t->string ();
if (nets_to_join.find (nn) != nets_to_join.end ()) {
prop_by_name [nn].insert (db::text_ref_to_attr (t.operator-> ()));
}
}
// first inter-name equivalence (this implies implicit connections for all n1 and n2 labels)
for (std::map<std::string, std::set<size_t> >::const_iterator pn = prop_by_name.begin (); pn != prop_by_name.end (); ++pn) {
std::set<size_t>::const_iterator p = pn->second.begin ();
std::set<size_t>::const_iterator p0 = p;
while (p != pn->second.end ()) {
eq.same (*p0, *p);
++p;
}
}
// second intra-name equivalence
for (std::map<std::string, std::set<size_t> >::const_iterator pn1 = prop_by_name.begin (); pn1 != prop_by_name.end (); ++pn1) {
std::map<std::string, std::set<size_t> >::const_iterator pn2 = pn1;
++pn2;
for ( ; pn2 != prop_by_name.end (); ++pn2) {
eq.same (*pn1->second.begin (), *pn2->second.begin ());
}
}
}
void
NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layout_index, const db::Connectivity &conn, db::Netlist &nl, hier_clusters_type &clusters)
{
@ -114,15 +181,31 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
std::map<db::cell_index_type, tl::equivalence_clusters<size_t> > net_name_equivalence;
if (m_text_annot_name_id.first) {
if (! m_joined_net_names.empty ()) {
build_net_name_equivalence (mp_layout, conn, 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) {
for (std::list<std::pair<std::string, std::list<tl::GlobPattern> > >::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, conn, m_text_annot_name_id.second, m->second, net_name_equivalence [cp.second]);
}
}
if (! m_joined_nets.empty ()) {
for (std::list<std::set<std::string> >::const_iterator n = m_joined_nets.begin (); n != m_joined_nets.end (); ++n) {
build_net_name_equivalence_for_explicit_connections (mp_layout, conn, m_text_annot_name_id.second, *n, net_name_equivalence [hier_clusters_type::top_cell_index]);
}
}
for (std::list<std::pair<std::string, std::list<std::set<std::string> > > >::const_iterator m = m_joined_nets_per_cell.begin (); m != m_joined_nets_per_cell.end (); ++m) {
std::pair<bool, db::cell_index_type> cp = mp_layout->cell_by_name (m->first.c_str ());
if (cp.first) {
for (std::list<std::set<std::string> >::const_iterator n = m->second.begin (); n != m->second.end (); ++n) {
build_net_name_equivalence_for_explicit_connections (mp_layout, conn, m_text_annot_name_id.second, *n, net_name_equivalence [cp.second]);
}
}
}
}
// the big part: actually extract the nets

View File

@ -26,6 +26,7 @@
#include "dbCommon.h"
#include "dbHierNetworkProcessor.h"
#include "dbNetShape.h"
#include "tlGlobPattern.h"
#include <map>
#include <set>
@ -104,23 +105,30 @@ public:
* @brief Sets the joined net names attribute
* This is a glob expression rendering net names where partial nets with the
* same name are joined even without explicit connection.
* The cell-less version applies to top level cells only.
*/
void set_joined_net_names (const std::string &jnn);
void set_joined_net_names (const std::list<tl::GlobPattern> &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);
void set_joined_net_names (const std::string &cell_name, const std::list<tl::GlobPattern> &jnn);
/**
* @brief Gets the joined net names expression
* @brief Sets the joined nets attribute
* This specifies a list of net names to join. Each join group is a set of names which specifies the net
* names that are to be connected. Multiple such groups can be specified. Each net name listed in a
* group implies implicit joining of the corresponding labels into one net.
* The cell-less version applies to top level cells only.
*/
const std::string &joined_net_names () const
{
return m_joined_net_names;
}
void set_joined_nets (const std::list<std::set<std::string> > &jnn);
/**
* @brief Sets the joined nets attribute per cell
*/
void set_joined_nets (const std::string &cell_name, const std::list<std::set<std::string> > &jnn);
/**
* @brief Extract the nets
@ -135,8 +143,10 @@ private:
std::pair<bool, db::property_names_id_type> m_text_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::string m_joined_net_names;
std::list<std::pair<std::string, std::string> > m_joined_net_names_per_cell;
std::list<tl::GlobPattern> m_joined_net_names;
std::list<std::pair<std::string, std::list<tl::GlobPattern> > > m_joined_net_names_per_cell;
std::list<std::set<std::string> > m_joined_nets;
std::list<std::pair<std::string, std::list<std::set<std::string> > > > m_joined_nets_per_cell;
bool m_include_floating_subcircuits;
bool instance_is_device (db::properties_id_type prop_id) const;

View File

@ -140,6 +140,68 @@ static db::Region antenna_check (db::LayoutToNetlist *l2n, const db::Region &pol
return antenna_check3 (l2n, poly, 1, 0, metal, 1, 0, ratio, diodes);
}
static void join_net_names (db::LayoutToNetlist *l2n, const std::string &s)
{
l2n->join_net_names (tl::GlobPattern (s));
}
static std::string dump_joined_net_names (const db::LayoutToNetlist *l2n)
{
const std::list<tl::GlobPattern> &jn = l2n->joined_net_names ();
std::vector<std::string> s;
for (std::list<tl::GlobPattern>::const_iterator j = jn.begin (); j != jn.end (); ++j) {
s.push_back (j->pattern ());
}
return tl::join (s, ",");
}
static void join_net_names2 (db::LayoutToNetlist *l2n, const std::string &c, const std::string &s)
{
l2n->join_net_names (tl::GlobPattern (c), tl::GlobPattern (s));
}
static std::string dump_joined_net_names_per_cell (const db::LayoutToNetlist *l2n)
{
const std::list<std::pair<tl::GlobPattern, tl::GlobPattern> > &jn = l2n->joined_net_names_per_cell ();
std::vector<std::string> s;
for (std::list<std::pair<tl::GlobPattern, tl::GlobPattern> >::const_iterator i = jn.begin (); i != jn.end (); ++i) {
s.push_back (i->first.pattern () + ":" + i->second.pattern ());
}
return tl::join (s, ",");
}
static void join_nets (db::LayoutToNetlist *l2n, const std::set<std::string> &s)
{
l2n->join_nets (s);
}
static std::string dump_joined_nets (const db::LayoutToNetlist *l2n)
{
const std::list<std::set<std::string> > &jn = l2n->joined_nets ();
std::vector<std::string> s;
for (std::list<std::set<std::string> >::const_iterator j = jn.begin (); j != jn.end (); ++j) {
std::vector<std::string> t (j->begin (), j->end ());
s.push_back (tl::join (t, "+"));
}
return tl::join (s, ",");
}
static void join_nets2 (db::LayoutToNetlist *l2n, const std::string &c, const std::set<std::string> &s)
{
l2n->join_nets (tl::GlobPattern (c), s);
}
static std::string dump_joined_nets_per_cell (const db::LayoutToNetlist *l2n)
{
const std::list<std::pair<tl::GlobPattern, std::set<std::string> > > &jn = l2n->joined_nets_per_cell ();
std::vector<std::string> s;
for (std::list<std::pair<tl::GlobPattern, std::set<std::string> > >::const_iterator i = jn.begin (); i != jn.end (); ++i) {
std::vector<std::string> t (i->second.begin (), i->second.end ());
s.push_back (i->first.pattern () + ":" + tl::join (t, "+"));
}
return tl::join (s, ",");
}
Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
gsi::constructor ("new", &make_l2n, gsi::arg ("iter"),
"@brief Creates a new extractor connected to an original layout\n"
@ -334,7 +396,7 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
) +
gsi::method ("connect", (void (db::LayoutToNetlist::*) (const db::Region &)) &db::LayoutToNetlist::connect, gsi::arg ("l"),
"@brief Defines an intra-layer connection for the given layer.\n"
"The layer is either an original layer created with \\make_layer and it's variants or\n"
"The layer is either an original layer created with \\make_incluidelayer and it's variants or\n"
"a derived layer. Certain limitations apply. It's safe to use\n"
"boolean operations for deriving layers. Other operations are applicable as long as they are\n"
"capable of delivering hierarchical layers.\n"
@ -372,13 +434,38 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
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."
) +
gsi::method ("extract_netlist", &db::LayoutToNetlist::extract_netlist, gsi::arg ("join_net_names", std::string (), "\"\""), gsi::arg ("include_floating_subcircuits", false),
"@brief Runs the netlist extraction\n"
"'join_net_names' is a glob expression for labels. Nets on top level carrying the same label which matches this glob "
"expression will be connected implicitly even if there is no physical connection. This feature is useful to simulate a connection "
"which will be made later when integrating the component.\n"
gsi::method ("include_floating_subcircuits=", &db::LayoutToNetlist::set_include_floating_subcircuits, gsi::arg ("flag"),
"@brief Sets a flag indicating whether to include floating subcircuits in the netlist.\n"
"\n"
"Valid glob expressions are:\n"
"With 'include_floating_subcircuits' set to true, subcircuits with no connection to their parent "
"circuit are still included in the circuit as floating subcircuits. Specifically on flattening this "
"means that these subcircuits are properly propagated to their parent instead of appearing as "
"additional top circuits.\n"
"\n"
"This attribute has been introduced in version 0.27 and replaces the arguments of \\extract_netlist."
) +
gsi::method ("include_floating_subcircuits", &db::LayoutToNetlist::include_floating_subcircuits,
"@brief Gets a flag indicating whether to include floating subcircuits in the netlist.\n"
"See \\include_floating_subcircuits= for details.\n"
"\n"
"This attribute has been introduced in version 0.27.\n"
) +
gsi::method ("clear_join_net_names", &db::LayoutToNetlist::clear_join_net_names,
"@brief Clears all implicit net joining expressions.\n"
"See \\extract_netlist for more details about this feature.\n"
"\n"
"This method has been introduced in version 0.27 and replaces the arguments of \\extract_netlist."
) +
gsi::method_ext ("join_net_names", &join_net_names, gsi::arg ("pattern"),
"@brief Specifies another pattern for implicit joining of nets for the top level cell.\n"
"Use this method to register a pattern for net labels considered in implicit net joining. Implicit net joining "
"allows connecting multiple parts of the same nets (e.g. supply rails) without need for a physical connection. "
"The pattern specifies labels to look for. When parts are labelled with a name matching the expression, "
"the parts carrying the same name are joined.\n"
"\n"
"This method adds a new pattern. Use \\clear_join_net_names to clear the registered pattern.\n"
"\n"
"Each pattern is a glob expression. Valid glob expressions are:\n"
"@ul\n"
"@li \"\" no implicit connections.@/li\n"
"@li \"*\" to make all labels candidates for implicit connections.@/li\n"
@ -389,27 +476,45 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
"\n"
"Label matching is case sensitive.\n"
"\n"
"With 'include_floating_subcircuits' set to true, subcircuits with no connection to their parent "
"circuit are still included in the circuit as floating subcircuits. Specifically on flattening this "
"means that these subcircuits are property propagated to their parent instead of appearing as "
"additional top circuits.\n"
"This method has been introduced in version 0.27 and replaces the arguments of \\extract_netlist."
) +
gsi::method_ext ("join_net_names", &join_net_names2, gsi::arg ("cell_pattern"), gsi::arg ("pattern"),
"@brief Specifies another pattern for implicit joining of nets for the cells from the given cell pattern.\n"
"This method allows applying implicit net joining for specific cells, not only for the top cell.\n"
"\n"
"This method adds a new pattern. Use \\clear_join_net_names to clear the registered pattern.\n"
"\n"
"This method has been introduced in version 0.27 and replaces the arguments of \\extract_netlist."
) +
gsi::method ("clear_join_nets", &db::LayoutToNetlist::clear_join_nets,
"@brief Clears all explicit net joining expressions.\n"
"See \\extract_netlist for more details about this feature.\n"
"\n"
"Explicit net joining has been introduced in version 0.27."
) +
gsi::method_ext ("join_nets", &join_nets, gsi::arg ("net_names"),
"@brief Specifies another name list for explicit joining of nets for the top level cell.\n"
"Use this method to join nets from the set of net names. All these nets will be connected together forming a single net.\n"
"Explicit joining will imply implicit joining for the involved nets - partial nets involved will be connected too (intra-net joining).\n"
"\n"
"This method adds a new name list. Use \\clear_join_nets to clear the registered pattern.\n"
"\n"
"Explicit net joining has been introduced in version 0.27."
) +
gsi::method_ext ("join_nets", &join_nets2, gsi::arg ("cell_pattern"), gsi::arg ("net_names"),
"@brief Specifies another name list for explicit joining of nets for the cells from the given cell pattern.\n"
"This method allows applying explicit net joining for specific cells, not only for the top cell.\n"
"\n"
"This method adds a new name list. Use \\clear_join_nets to clear the registered pattern.\n"
"\n"
"Explicit net joining has been introduced in version 0.27."
) +
gsi::method ("extract_netlist", &db::LayoutToNetlist::extract_netlist,
"@brief Runs the netlist extraction\n"
"\n"
"See the class description for more details.\n"
"\n"
"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 label 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.\n"
"\n"
"This variant of 'extract_netlist' has been introduced in version 0.26.2."
"This method has been made parameter-less in version 0.27. Use \\include_floating_subcircuits= and \\join_net_names as substitutes for the arguments of previous versions."
) +
gsi::method_ext ("internal_layout", &l2n_internal_layout,
"@brief Gets the internal layout\n"
@ -658,7 +763,13 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
"considered.\n"
"\n"
"This variant has been introduced in version 0.26.6.\n"
),
) +
// test API
gsi::method_ext ("dump_joined_net_names", &dump_joined_net_names, "@hide") +
gsi::method_ext ("dump_joined_net_names_per_cell", &dump_joined_net_names_per_cell, "@hide") +
gsi::method_ext ("dump_joined_nets", &dump_joined_nets, "@hide") +
gsi::method_ext ("dump_joined_nets_per_cell", &dump_joined_nets_per_cell, "@hide")
,
"@brief A generic framework for extracting netlists from layouts\n"
"\n"
"This class wraps various concepts from db::NetlistExtractor and db::NetlistDeviceExtractor\n"
@ -674,7 +785,7 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
" hierarchy and the layout taken as input.\n"
"@/li\n"
"@li Preparation\n"
" In this step, the device recognitions and extraction layers are drawn from\n"
" In this step, the device recognition and extraction layers are drawn from\n"
" the framework. Derived can now be computed using boolean operations.\n"
" Methods to use in this step are \\make_layer and it's variants.\n"
" Layer preparation is not necessarily required to happen before all\n"

View File

@ -3156,7 +3156,7 @@ TEST(12_FlattenCircuitDoesFlattenLayout)
db::compare_layouts (_this, ly, au);
}
TEST(13_JoinNets)
TEST(13_JoinNetNames)
{
db::Layout ly;
db::LayerMap lmap;
@ -3299,7 +3299,8 @@ TEST(13_JoinNets)
l2n.connect_global (*rbulk, "VSS");
// Extract with joining VSS and VDD
l2n.extract_netlist ("{VSS,VDD}");
l2n.join_net_names (tl::GlobPattern ("{VSS,VDD}"));
l2n.extract_netlist ();
// debug layers produced for nets
// 201/0 -> Well
@ -3385,3 +3386,249 @@ TEST(13_JoinNets)
db::compare_layouts (_this, ly, au);
}
TEST(14_JoinNets)
{
db::Layout ly;
db::LayerMap lmap;
unsigned int nwell = define_layer (ly, lmap, 1);
unsigned int nwell_lbl = define_layer (ly, lmap, 1, 1);
unsigned int active = define_layer (ly, lmap, 2);
unsigned int pplus = define_layer (ly, lmap, 10);
unsigned int nplus = define_layer (ly, lmap, 11);
unsigned int poly = define_layer (ly, lmap, 3);
unsigned int poly_lbl = define_layer (ly, lmap, 3, 1);
unsigned int diff_cont = define_layer (ly, lmap, 4);
unsigned int poly_cont = define_layer (ly, lmap, 5);
unsigned int metal1 = define_layer (ly, lmap, 6);
unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1);
unsigned int via1 = define_layer (ly, lmap, 7);
unsigned int metal2 = define_layer (ly, lmap, 8);
unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1);
{
db::LoadLayoutOptions options;
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
std::string fn (tl::testsrc ());
fn = tl::combine_path (fn, "testdata");
fn = tl::combine_path (fn, "algo");
fn = tl::combine_path (fn, "device_extract_l14.gds");
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly, options);
}
db::Cell &tc = ly.cell (*ly.begin_top_down ());
db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set<unsigned int> ()));
std::unique_ptr<db::Region> rbulk (l2n.make_layer ("bulk"));
std::unique_ptr<db::Region> rnwell (l2n.make_layer (nwell, "nwell"));
std::unique_ptr<db::Region> rnwell_lbl (l2n.make_layer (nwell_lbl, "nwell_lbl"));
std::unique_ptr<db::Region> ractive (l2n.make_layer (active, "active"));
std::unique_ptr<db::Region> rpplus (l2n.make_layer (pplus, "pplus"));
std::unique_ptr<db::Region> rnplus (l2n.make_layer (nplus, "nplus"));
std::unique_ptr<db::Region> rpoly (l2n.make_polygon_layer (poly, "poly"));
std::unique_ptr<db::Texts> rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl"));
std::unique_ptr<db::Region> rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont"));
std::unique_ptr<db::Region> rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont"));
std::unique_ptr<db::Region> rmetal1 (l2n.make_polygon_layer (metal1, "metal1"));
std::unique_ptr<db::Texts> rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl"));
std::unique_ptr<db::Region> rvia1 (l2n.make_polygon_layer (via1, "via1"));
std::unique_ptr<db::Region> rmetal2 (l2n.make_polygon_layer (metal2, "metal2"));
std::unique_ptr<db::Texts> rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl"));
// derived regions
db::Region ractive_in_nwell = *ractive & *rnwell;
db::Region rpactive = ractive_in_nwell & *rpplus;
db::Region rntie = ractive_in_nwell & *rnplus;
db::Region rpgate = rpactive & *rpoly;
db::Region rpsd = rpactive - rpgate;
db::Region ractive_outside_nwell = *ractive - *rnwell;
db::Region rnactive = ractive_outside_nwell & *rnplus;
db::Region rptie = ractive_outside_nwell & *rpplus;
db::Region rngate = rnactive & *rpoly;
db::Region rnsd = rnactive - rngate;
// return the computed layers into the original layout and write it for debugging purposes
unsigned int lgate = ly.insert_layer (db::LayerProperties (20, 0)); // 20/0 -> Gate
unsigned int lsd = ly.insert_layer (db::LayerProperties (21, 0)); // 21/0 -> Source/Drain
unsigned int lpdiff = ly.insert_layer (db::LayerProperties (22, 0)); // 22/0 -> P Diffusion
unsigned int lndiff = ly.insert_layer (db::LayerProperties (23, 0)); // 23/0 -> N Diffusion
unsigned int lptie = ly.insert_layer (db::LayerProperties (24, 0)); // 24/0 -> P Tie
unsigned int lntie = ly.insert_layer (db::LayerProperties (25, 0)); // 25/0 -> N Tie
rpgate.insert_into (&ly, tc.cell_index (), lgate);
rngate.insert_into (&ly, tc.cell_index (), lgate);
rpsd.insert_into (&ly, tc.cell_index (), lsd);
rnsd.insert_into (&ly, tc.cell_index (), lsd);
rpsd.insert_into (&ly, tc.cell_index (), lpdiff);
rnsd.insert_into (&ly, tc.cell_index (), lndiff);
rpsd.insert_into (&ly, tc.cell_index (), lptie);
rnsd.insert_into (&ly, tc.cell_index (), lntie);
db::NetlistDeviceExtractorMOS4Transistor pmos_ex ("PMOS");
db::NetlistDeviceExtractorMOS4Transistor nmos_ex ("NMOS");
// device extraction
db::NetlistDeviceExtractor::input_layers dl;
dl["SD"] = &rpsd;
dl["G"] = &rpgate;
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
dl["W"] = rnwell.get ();
l2n.extract_devices (pmos_ex, dl);
dl["SD"] = &rnsd;
dl["G"] = &rngate;
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
dl["W"] = rbulk.get ();
l2n.extract_devices (nmos_ex, dl);
// net extraction
l2n.register_layer (rpsd, "psd");
l2n.register_layer (rnsd, "nsd");
l2n.register_layer (rptie, "ptie");
l2n.register_layer (rntie, "ntie");
// Intra-layer
l2n.connect (rpsd);
l2n.connect (rnsd);
l2n.connect (*rnwell);
l2n.connect (*rpoly);
l2n.connect (*rdiff_cont);
l2n.connect (*rpoly_cont);
l2n.connect (*rmetal1);
l2n.connect (*rvia1);
l2n.connect (*rmetal2);
l2n.connect (rptie);
l2n.connect (rntie);
// Inter-layer
l2n.connect (rpsd, *rdiff_cont);
l2n.connect (rnsd, *rdiff_cont);
l2n.connect (rntie, *rnwell);
l2n.connect (*rpoly, *rpoly_cont);
l2n.connect (*rpoly_cont, *rmetal1);
l2n.connect (*rdiff_cont, *rmetal1);
l2n.connect (*rdiff_cont, rptie);
l2n.connect (*rdiff_cont, rntie);
l2n.connect (*rnwell, rntie);
l2n.connect (*rmetal1, *rvia1);
l2n.connect (*rvia1, *rmetal2);
l2n.connect (*rnwell, *rnwell_lbl); // attaches labels
l2n.connect (*rpoly, *rpoly_lbl); // attaches labels
l2n.connect (*rmetal1, *rmetal1_lbl); // attaches labels
l2n.connect (*rmetal2, *rmetal2_lbl); // attaches labels
// Global
l2n.connect_global (*rbulk, "BULK");
l2n.connect_global (rptie, "BULK");
// Extract while joining VSS with BULK and VDD with NWELL
std::set<std::string> jn;
jn.insert ("VDD");
jn.insert ("NWELL");
l2n.join_nets (tl::GlobPattern ("INV2"), jn);
jn.clear ();
jn.insert ("VSS");
jn.insert ("BULK");
l2n.join_nets (tl::GlobPattern ("INV2"), jn);
// This will trigger an implicit connection on top level (side effect of explicit connections)
jn.clear ();
jn.insert ("VDD");
l2n.join_nets (jn);
l2n.extract_netlist ();
// debug layers produced for nets
// 201/0 -> Well
// 203/0 -> Poly
// 204/0 -> Diffusion contacts
// 205/0 -> Poly contacts
// 206/0 -> Metal1
// 207/0 -> Via1
// 208/0 -> Metal2
// 210/0 -> N source/drain
// 211/0 -> P source/drain
// 212/0 -> N tie
// 213/0 -> P tie
std::map<const db::Region *, unsigned int> dump_map;
dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (210, 0));
dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (211, 0));
dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (212, 0));
dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (213, 0));
dump_map [rbulk.get () ] = ly.insert_layer (db::LayerProperties (214, 0));
dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (201, 0));
dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (203, 0));
dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (204, 0));
dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (205, 0));
dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (206, 0));
dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (207, 0));
dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (208, 0));
// write nets to layout
db::CellMapping cm = l2n.cell_mapping_into (ly, tc);
dump_nets_to_layout (l2n, ly, dump_map, cm);
dump_map.clear ();
dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (310, 0));
dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (311, 0));
dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (312, 0));
dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (313, 0));
dump_map [rbulk.get () ] = ly.insert_layer (db::LayerProperties (314, 0));
dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (301, 0));
dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (303, 0));
dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (304, 0));
dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (305, 0));
dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (306, 0));
dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (307, 0));
dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (308, 0));
dump_recursive_nets_to_layout (l2n, ly, dump_map, cm);
// compare netlist as string
CHECKPOINT ();
db::compare_netlist (_this, *l2n.netlist (),
"circuit RINGO ();\n"
" subcircuit INV2 $1 ('NWELL,VDD'=VDD,IN=$I15,$3=FB,OUT=OSC,VSS=VSS);\n"
" subcircuit INV2 $2 ('NWELL,VDD'=VDD,IN=FB,$3=$I26,OUT=$I25,VSS=VSS);\n"
" subcircuit INV2 $3 ('NWELL,VDD'=VDD,IN=$3,$3=$I30,OUT=$I12,VSS=VSS);\n"
" subcircuit INV2 $4 ('NWELL,VDD'=VDD,IN=$I10,$3=$I29,OUT=$3,VSS=VSS);\n"
" subcircuit INV2 $5 ('NWELL,VDD'=VDD,IN=$I12,$3=$I31,OUT=$I13,VSS=VSS);\n"
" subcircuit INV2 $6 ('NWELL,VDD'=VDD,IN=$I13,$3=$I32,OUT=$I14,VSS=VSS);\n"
" subcircuit INV2 $7 ('NWELL,VDD'=VDD,IN=$I14,$3=$I33,OUT=$I15,VSS=VSS);\n"
" subcircuit INV2 $8 ('NWELL,VDD'=VDD,IN=$I25,$3=$I27,OUT=$I9,VSS=VSS);\n"
" subcircuit INV2 $9 ('NWELL,VDD'=VDD,IN=$I9,$3=$I28,OUT=$I10,VSS=VSS);\n"
"end;\n"
"circuit INV2 ('NWELL,VDD'='NWELL,VDD',IN=IN,$3=$3,OUT=OUT,VSS=VSS);\n"
" device PMOS $1 (S=$3,G=IN,D='NWELL,VDD',B='NWELL,VDD') (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
" device PMOS $2 (S='NWELL,VDD',G=$3,D=OUT,B='NWELL,VDD') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
" device NMOS $3 (S=$3,G=IN,D=VSS,B=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
" device NMOS $4 (S=VSS,G=$3,D=OUT,B=VSS) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
" subcircuit TRANS $1 ($1=$3,$2='NWELL,VDD',$3=IN);\n"
" subcircuit TRANS $2 ($1='NWELL,VDD',$2=OUT,$3=$3);\n"
" subcircuit TRANS $3 ($1=$3,$2=VSS,$3=IN);\n"
" subcircuit TRANS $4 ($1=VSS,$2=OUT,$3=$3);\n"
"end;\n"
"circuit TRANS ($1=$1,$2=$2,$3=$3);\n"
"end;\n"
);
// compare the collected test data
std::string au = tl::testsrc ();
au = tl::combine_path (au, "testdata");
au = tl::combine_path (au, "algo");
au = tl::combine_path (au, "device_extract_au14_circuits.gds");
db::compare_layouts (_this, ly, au);
}

View File

@ -958,19 +958,38 @@ TEST(3_DeviceAndNetExtractionWithImplicitConnections)
// extract the nets
std::list<tl::GlobPattern> gp;
db::Netlist nl2 = nl;
net_ex.set_joined_net_names ("{VDDZ,VSSZ,NEXT,FB}");
gp.clear ();
gp.push_back (tl::GlobPattern ("{VDDZ,VSSZ,NEXT,FB}"));
net_ex.set_joined_net_names (gp);
net_ex.extract_nets (dss, 0, conn, nl2, cl);
EXPECT_EQ (all_net_names_unique (nl2), true);
nl2 = nl;
net_ex.set_joined_net_names ("{VDDZ,VSSZ,NEXT}");
gp.clear ();
gp.push_back (tl::GlobPattern ("VDDZ"));
gp.push_back (tl::GlobPattern ("VSSZ"));
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, nl2, cl);
EXPECT_EQ (all_net_names_unique (nl2), true);
nl2 = nl;
gp.clear ();
gp.push_back (tl::GlobPattern ("{VDDZ,VSSZ,NEXT}"));
net_ex.set_joined_net_names (gp);
net_ex.extract_nets (dss, 0, conn, nl2, cl);
EXPECT_EQ (all_net_names_unique (nl2), false);
net_ex.set_joined_net_names ("*");
gp.clear ();
gp.push_back (tl::GlobPattern ("*"));
net_ex.set_joined_net_names (gp);
net_ex.extract_nets (dss, 0, conn, nl, cl);
EXPECT_EQ (all_net_names_unique (nl), true);
@ -1233,7 +1252,9 @@ TEST(4_ResAndCapExtraction)
// extract the nets
net_ex.set_joined_net_names ("*");
std::list<tl::GlobPattern> gp;
gp.push_back (tl::GlobPattern ("*"));
net_ex.set_joined_net_names (gp);
net_ex.extract_nets (dss, 0, conn, nl, cl);
// Flatten device circuits
@ -1507,7 +1528,9 @@ TEST(5_ResAndCapWithBulkExtraction)
// extract the nets
net_ex.set_joined_net_names ("*");
std::list<tl::GlobPattern> gp;
gp.push_back (tl::GlobPattern ("*"));
net_ex.set_joined_net_names (gp);
net_ex.extract_nets (dss, 0, conn, nl, cl);
// Flatten device circuits
@ -1749,7 +1772,9 @@ TEST(6_BJT3TransistorExtraction)
// extract the nets
net_ex.set_joined_net_names ("*");
std::list<tl::GlobPattern> gp;
gp.push_back (tl::GlobPattern ("*"));
net_ex.set_joined_net_names (gp);
net_ex.extract_nets (dss, 0, conn, nl, cl);
// Flatten device circuits
@ -1915,7 +1940,9 @@ TEST(7_DiodeExtraction)
// extract the nets
net_ex.set_joined_net_names ("*");
std::list<tl::GlobPattern> gp;
gp.push_back (tl::GlobPattern ("*"));
net_ex.set_joined_net_names (gp);
net_ex.extract_nets (dss, 0, conn, nl, cl);
// cleanup + completion
@ -2048,7 +2075,9 @@ TEST(8_DiodeExtractionScaled)
// extract the nets
net_ex.set_joined_net_names ("*");
std::list<tl::GlobPattern> gp;
gp.push_back (tl::GlobPattern ("*"));
net_ex.set_joined_net_names (gp);
net_ex.extract_nets (dss, 0, conn, nl, cl);
// cleanup + completion
@ -2922,3 +2951,255 @@ TEST(13_RemoveDummyPins)
);
}
TEST(14_JoinNets)
{
db::Layout ly;
db::LayerMap lmap;
unsigned int nwell = define_layer (ly, lmap, 1);
unsigned int active = define_layer (ly, lmap, 2);
unsigned int poly = define_layer (ly, lmap, 3);
unsigned int poly_lbl = define_layer (ly, lmap, 3, 1);
unsigned int diff_cont = define_layer (ly, lmap, 4);
unsigned int poly_cont = define_layer (ly, lmap, 5);
unsigned int metal1 = define_layer (ly, lmap, 6);
unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1);
unsigned int via1 = define_layer (ly, lmap, 7);
unsigned int metal2 = define_layer (ly, lmap, 8);
unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1);
{
db::LoadLayoutOptions options;
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
std::string fn (tl::testsrc ());
fn = tl::combine_path (fn, "testdata");
fn = tl::combine_path (fn, "algo");
fn = tl::combine_path (fn, "device_extract_l1_join_nets.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 ractive (db::RecursiveShapeIterator (ly, tc, active), dss);
db::Region rpoly (db::RecursiveShapeIterator (ly, tc, poly), dss);
db::Region rpoly_lbl (db::RecursiveShapeIterator (ly, tc, poly_lbl), dss);
db::Region rdiff_cont (db::RecursiveShapeIterator (ly, tc, diff_cont), dss);
db::Region rpoly_cont (db::RecursiveShapeIterator (ly, tc, poly_cont), dss);
db::Region rmetal1 (db::RecursiveShapeIterator (ly, tc, metal1), dss);
db::Region rmetal1_lbl (db::RecursiveShapeIterator (ly, tc, metal1_lbl), dss);
db::Region rvia1 (db::RecursiveShapeIterator (ly, tc, via1), dss);
db::Region rmetal2 (db::RecursiveShapeIterator (ly, tc, metal2), dss);
db::Region rmetal2_lbl (db::RecursiveShapeIterator (ly, tc, metal2_lbl), dss);
// derived regions
db::Region rpactive = ractive & rnwell;
db::Region rpgate = rpactive & rpoly;
db::Region rpsd = rpactive - rpgate;
db::Region rnactive = ractive - rnwell;
db::Region rngate = rnactive & rpoly;
db::Region rnsd = rnactive - rngate;
// Global
db::Region bulk (dss);
// return the computed layers into the original layout and write it for debugging purposes
unsigned int lgate = ly.insert_layer (db::LayerProperties (10, 0)); // 10/0 -> Gate
unsigned int lsd = ly.insert_layer (db::LayerProperties (11, 0)); // 11/0 -> Source/Drain
unsigned int lpdiff = ly.insert_layer (db::LayerProperties (12, 0)); // 12/0 -> P Diffusion
unsigned int lndiff = ly.insert_layer (db::LayerProperties (13, 0)); // 13/0 -> N Diffusion
rpgate.insert_into (&ly, tc.cell_index (), lgate);
rngate.insert_into (&ly, tc.cell_index (), lgate);
rpsd.insert_into (&ly, tc.cell_index (), lsd);
rnsd.insert_into (&ly, tc.cell_index (), lsd);
rpsd.insert_into (&ly, tc.cell_index (), lpdiff);
rnsd.insert_into (&ly, tc.cell_index (), lndiff);
// 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.connect_global (rnwell, "NWELL");
// Intra-layer
conn.connect (rpsd);
conn.connect (rnsd);
conn.connect (rpoly);
conn.connect (rdiff_cont);
conn.connect (rpoly_cont);
conn.connect (rmetal1);
conn.connect (rvia1);
conn.connect (rmetal2);
// Inter-layer
conn.connect (rpsd, rdiff_cont);
conn.connect (rnsd, rdiff_cont);
conn.connect (rpoly, rpoly_cont);
conn.connect (rpoly_cont, rmetal1);
conn.connect (rdiff_cont, rmetal1);
conn.connect (rmetal1, rvia1);
conn.connect (rvia1, rmetal2);
conn.connect (rpoly, rpoly_lbl); // attaches labels
conn.connect (rmetal1, rmetal1_lbl); // attaches labels
conn.connect (rmetal2, rmetal2_lbl); // attaches labels
// 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);
EXPECT_EQ (all_net_names_unique (nl), true);
// debug layers produced for nets
// 202/0 -> Active
// 203/0 -> Poly
// 204/0 -> Diffusion contacts
// 205/0 -> Poly contacts
// 206/0 -> Metal1
// 207/0 -> Via1
// 208/0 -> Metal2
// 210/0 -> N source/drain
// 211/0 -> P source/drain
// 212/0 -> Bulk
// 213/0 -> NWell
std::map<unsigned int, unsigned int> dump_map;
dump_map [layer_of (bulk) ] = ly.insert_layer (db::LayerProperties (212, 0));
dump_map [layer_of (rnwell) ] = ly.insert_layer (db::LayerProperties (213, 0));
dump_map [layer_of (rpsd) ] = ly.insert_layer (db::LayerProperties (210, 0));
dump_map [layer_of (rnsd) ] = ly.insert_layer (db::LayerProperties (211, 0));
dump_map [layer_of (rpoly) ] = ly.insert_layer (db::LayerProperties (203, 0));
dump_map [layer_of (rdiff_cont)] = ly.insert_layer (db::LayerProperties (204, 0));
dump_map [layer_of (rpoly_cont)] = 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 INV2 $1 (IN=$I8,$2=FB,OUT=OSC,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $2 (IN=FB,$2=$I20,OUT=$I19,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $3 (IN=NEXT,$2=$I25,OUT=$I5,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $4 (IN=$I3,$2=$I24,OUT=NEXT,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $5 (IN=$I5,$2=$I26,OUT=$I6,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $6 (IN=$I6,$2=$I27,OUT=$I7,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $7 (IN=$I7,$2=$I28,OUT=$I8,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $8 (IN=$I19,$2=$I21,OUT=$I1,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $9 (IN=$I1,$2=$I22,OUT=$I2,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $10 (IN=$I2,$2=$I23,OUT=$I3,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
"end;\n"
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,VDD=VDD,VSS=VSS);\n"
" device PMOS $1 (S=$2,G=IN,D=VDD,B=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
" device PMOS $2 (S=VDD,G=$2,D=OUT,B=VDD) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
" device NMOS $3 (S=$2,G=IN,D=VSS,B=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
" device NMOS $4 (S=VSS,G=$2,D=OUT,B=VSS) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
" subcircuit TRANS $1 ($1=$2,$2=VSS,$3=IN);\n"
" subcircuit TRANS $2 ($1=$2,$2=VDD,$3=IN);\n"
" subcircuit TRANS $3 ($1=VDD,$2=OUT,$3=$2);\n"
" subcircuit TRANS $4 ($1=VSS,$2=OUT,$3=$2);\n"
"end;\n"
"circuit TRANS ($1=$1,$2=$2,$3=$3);\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,OSC=OSC,NEXT=NEXT,'VDD,VDDZ'='VDD,VDDZ','VSS,VSSZ'='VSS,VSSZ');\n"
" subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $2 (IN=FB,$2=$I20,OUT=$I19,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $3 (IN=NEXT,$2=$I25,OUT=$I5,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $4 (IN=$I3,$2=$I24,OUT=NEXT,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $5 (IN=$I5,$2=$I26,OUT=$I6,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $6 (IN=$I6,$2=$I27,OUT=$I7,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $7 (IN=$I7,$2=$I28,OUT=$I8,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $8 (IN=$I19,$2=$I21,OUT=$I1,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $9 (IN=$I1,$2=$I22,OUT=$I2,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
" subcircuit INV2 $10 (IN=$I2,$2=$I23,OUT=$I3,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
"end;\n"
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,VDD=VDD,VSS=VSS);\n"
" device PMOS $1 (S=$2,G=IN,D=VDD,B=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
" device PMOS $2 (S=VDD,G=$2,D=OUT,B=VDD) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
" device NMOS $3 (S=$2,G=IN,D=VSS,B=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
" device NMOS $4 (S=VSS,G=$2,D=OUT,B=VSS) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
"end;\n"
);
// compare the collected test data
std::string au = tl::testsrc ();
au = tl::combine_path (au, "testdata");
au = tl::combine_path (au, "algo");
au = tl::combine_path (au, "device_extract_au1_join_nets.gds");
db::compare_layouts (_this, ly, au);
}

View File

@ -1704,7 +1704,12 @@ NetTracerDialog::trace_all_nets (db::LayoutToNetlist *l2ndb, const lay::CellView
tracer_data.configure_l2n (*l2ndb);
l2ndb->extract_netlist (std::string (), flat /*include floating subcircuits for netlist to flatten*/);
l2ndb->clear_join_nets ();
l2ndb->clear_join_net_names ();
// include floating subcircuits for netlist to flatten
l2ndb->set_include_floating_subcircuits (flat);
l2ndb->extract_netlist ();
if (flat) {
l2ndb->netlist ()->flatten ();

View File

@ -68,6 +68,30 @@ public:
*/
GlobPattern &operator= (const std::string &s);
/**
* @brief Equality
*/
bool operator== (const tl::GlobPattern &other) const
{
return m_p == other.m_p;
}
/**
* @brief Less
*/
bool operator< (const tl::GlobPattern &other) const
{
return m_p < other.m_p;
}
/**
* @brief Pattern is empty
*/
bool empty () const
{
return m_p.empty ();
}
/**
* @brief Sets a value indicating whether to treat the match case sensitive
*/

Binary file not shown.

Binary file not shown.

BIN
testdata/algo/device_extract_l14.gds vendored Normal file

Binary file not shown.

Binary file not shown.

View File

@ -99,6 +99,46 @@ class DBLayoutToNetlist_TestClass < TestBase
end
assert_equal(map.select { |i| i }.join(","), "RINGO=>TOP,INV2=>INV2")
# extended attributes for extract_netlist
l2n = RBA::LayoutToNetlist::new
l2n.include_floating_subcircuits = true
assert_equal(l2n.include_floating_subcircuits, true)
l2n.include_floating_subcircuits = false
assert_equal(l2n.include_floating_subcircuits, false)
assert_equal(l2n.dump_joined_nets, "")
l2n.join_nets([ "VDD", "NWELL" ])
l2n.join_nets([ "VSS", "BULK" ])
assert_equal(l2n.dump_joined_nets, "NWELL+VDD,BULK+VSS")
l2n.clear_join_nets
assert_equal(l2n.dump_joined_nets, "")
assert_equal(l2n.dump_joined_nets_per_cell, "")
l2n.join_nets("INV*", [ "VDD", "NWELL" ])
l2n.join_nets("ND2*", [ "VSS", "BULK" ])
assert_equal(l2n.dump_joined_nets_per_cell, "INV*:NWELL+VDD,ND2*:BULK+VSS")
l2n.clear_join_nets
assert_equal(l2n.dump_joined_nets, "")
assert_equal(l2n.dump_joined_nets_per_cell, "")
assert_equal(l2n.dump_joined_net_names, "")
l2n.join_net_names("VDD")
l2n.join_net_names("VSS")
assert_equal(l2n.dump_joined_net_names, "VDD,VSS")
l2n.clear_join_net_names
assert_equal(l2n.dump_joined_net_names, "")
assert_equal(l2n.dump_joined_net_names_per_cell, "")
l2n.join_net_names("INV*", "VDD")
l2n.join_net_names("ND2*", "VSS")
assert_equal(l2n.dump_joined_net_names_per_cell, "INV*:VDD,ND2*:VSS")
l2n.clear_join_net_names
assert_equal(l2n.dump_joined_net_names, "")
assert_equal(l2n.dump_joined_net_names_per_cell, "")
end
def test_2_ShapesFromNet