mirror of https://github.com/KLayout/klayout.git
explicit net joining - preparations
This commit is contained in:
parent
e0eac2147b
commit
9f295523e4
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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.
Binary file not shown.
Binary file not shown.
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue