Merge pull request #514 from KLayout/issue-482
Implemented #482 (split gate option aka join_symmetric_nets)
|
|
@ -342,6 +342,30 @@ void Circuit::remove_net (Net *net)
|
|||
m_nets.erase (net);
|
||||
}
|
||||
|
||||
void Circuit::join_nets (Net *net, Net *with)
|
||||
{
|
||||
while (with->begin_terminals () != with->end_terminals ()) {
|
||||
db::Device *device = const_cast<db::Device *> (with->begin_terminals ()->device ());
|
||||
device->connect_terminal (with->begin_terminals ()->terminal_id (), net);
|
||||
}
|
||||
|
||||
while (with->begin_subcircuit_pins () != with->end_subcircuit_pins ()) {
|
||||
db::SubCircuit *subcircuit = const_cast<db::SubCircuit *> (with->begin_subcircuit_pins ()->subcircuit ());
|
||||
subcircuit->connect_pin (with->begin_subcircuit_pins ()->pin_id (), net);
|
||||
}
|
||||
|
||||
while (with->begin_pins () != with->end_pins ()) {
|
||||
connect_pin (with->begin_pins ()->pin_id (), net);
|
||||
}
|
||||
|
||||
// TODO: join clusters too, join net properties(?)
|
||||
if (netlist ()->callbacks ()) {
|
||||
netlist ()->callbacks ()->link_nets (net, with);
|
||||
}
|
||||
|
||||
remove_net (with);
|
||||
}
|
||||
|
||||
void Circuit::add_device (Device *device)
|
||||
{
|
||||
device->set_circuit (this);
|
||||
|
|
|
|||
|
|
@ -416,6 +416,11 @@ public:
|
|||
*/
|
||||
void remove_net (Net *net);
|
||||
|
||||
/**
|
||||
* @brief Joins the second net with the first one and removes the second net
|
||||
*/
|
||||
void join_nets (Net *net, Net *with);
|
||||
|
||||
/**
|
||||
* @brief Gets the number of nets
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -198,9 +198,23 @@ db::Region *LayoutToNetlist::make_polygon_layer (unsigned int layer_index, const
|
|||
return region.release ();
|
||||
}
|
||||
|
||||
void LayoutToNetlist::link_nets (const db::Net *net, const db::Net *with)
|
||||
{
|
||||
if (! net->circuit () || net->circuit () != with->circuit () || ! internal_layout ()
|
||||
|| ! internal_layout ()->is_valid_cell_index (net->circuit ()->cell_index ())
|
||||
|| net->cluster_id () == 0 || with->cluster_id () == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
connected_clusters<db::PolygonRef> &clusters = m_net_clusters.clusters_per_cell (net->circuit ()->cell_index ());
|
||||
clusters.join_cluster_with (net->cluster_id (), with->cluster_id ());
|
||||
}
|
||||
|
||||
size_t LayoutToNetlist::link_net_to_parent_circuit (const Net *subcircuit_net, Circuit *parent_circuit, const DCplxTrans &dtrans)
|
||||
{
|
||||
if (! subcircuit_net->circuit () || ! has_internal_layout () || ! internal_layout ()->is_valid_cell_index (parent_circuit->cell_index ())) {
|
||||
if (! subcircuit_net->circuit () || ! has_internal_layout ()
|
||||
|| ! internal_layout ()->is_valid_cell_index (parent_circuit->cell_index ())
|
||||
|| subcircuit_net->cluster_id () == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -798,6 +798,7 @@ private:
|
|||
|
||||
// implementation of NetlistManipulationCallbacks
|
||||
virtual size_t link_net_to_parent_circuit (const Net *subcircuit_net, Circuit *parent_circuit, const DCplxTrans &trans);
|
||||
virtual void link_nets (const db::Net *net, const db::Net *with);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ public:
|
|||
virtual ~NetlistManipulationCallbacks () { }
|
||||
|
||||
virtual size_t link_net_to_parent_circuit (const db::Net *subcircuit_net, db::Circuit *parent_circuit, const db::DCplxTrans &trans) = 0;
|
||||
virtual void link_nets (const db::Net *net, const db::Net *with) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -27,20 +27,50 @@
|
|||
#include "tlTimer.h"
|
||||
#include "tlEquivalenceClusters.h"
|
||||
#include "tlLog.h"
|
||||
#include "tlEnv.h"
|
||||
#include "tlInternational.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
// verbose debug output
|
||||
// TODO: make this a feature?
|
||||
// #define PRINT_DEBUG_NETCOMPARE
|
||||
namespace {
|
||||
|
||||
// verbose net graph output
|
||||
// TODO: make this a feature?
|
||||
// #define PRINT_DEBUG_NETGRAPH
|
||||
struct GlobalCompareOptions
|
||||
{
|
||||
GlobalCompareOptions ()
|
||||
{
|
||||
m_is_initialized = false;
|
||||
}
|
||||
|
||||
// Add this define for case insensitive compare
|
||||
// (applies to circuits, device classes)
|
||||
#define COMPARE_CASE_INSENSITIVE
|
||||
void ensure_initialized ()
|
||||
{
|
||||
if (! m_is_initialized) {
|
||||
// $KLAYOUT_NETLIST_COMPARE_DEBUG_NETCOMPARE
|
||||
debug_netcompare = tl::app_flag ("netlist-compare-debug-netcompare");
|
||||
// $KLAYOUT_NETLIST_COMPARE_DEBUG_NETGRAPH
|
||||
debug_netgraph = tl::app_flag ("netlist-compare-debug-netgraph");
|
||||
// $KLAYOUT_NETLIST_COMPARE_CASE_SENSITIVE
|
||||
compare_case_sensitive = tl::app_flag ("netlist-compare-case-sensitive");
|
||||
m_is_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool debug_netcompare;
|
||||
bool debug_netgraph;
|
||||
bool compare_case_sensitive;
|
||||
|
||||
private:
|
||||
bool m_is_initialized;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static GlobalCompareOptions *options ()
|
||||
{
|
||||
// TODO: thread safe?
|
||||
static GlobalCompareOptions s_options;
|
||||
s_options.ensure_initialized ();
|
||||
return &s_options;
|
||||
}
|
||||
|
||||
// A constant indicating a failed match
|
||||
const size_t failed_match = std::numeric_limits<size_t>::max ();
|
||||
|
|
@ -63,28 +93,25 @@ namespace db
|
|||
static int name_compare (const std::string &n1, const std::string &n2)
|
||||
{
|
||||
// TODO: unicode support?
|
||||
#if defined(COMPARE_CASE_INSENSITIVE)
|
||||
if (options ()->compare_case_sensitive) {
|
||||
return strcmp (n1.c_str (), n2.c_str ());
|
||||
} else {
|
||||
#if defined(_WIN32)
|
||||
return _stricmp (n1.c_str (), n2.c_str ());
|
||||
return _stricmp (n1.c_str (), n2.c_str ());
|
||||
#else
|
||||
return strcasecmp (n1.c_str (), n2.c_str ());
|
||||
#endif
|
||||
#else
|
||||
return strcmp (n1.c_str (), n2.c_str ());
|
||||
return strcasecmp (n1.c_str (), n2.c_str ());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(COMPARE_CASE_INSENSITIVE)
|
||||
static std::string normalize_name (const std::string &n)
|
||||
static inline std::string normalize_name (const std::string &n)
|
||||
{
|
||||
return tl::to_upper_case (n);
|
||||
if (options ()->compare_case_sensitive) {
|
||||
return n;
|
||||
} else {
|
||||
return tl::to_upper_case (n);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static inline const std::string &normalize_name (const std::string &n)
|
||||
{
|
||||
return n;
|
||||
}
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// DeviceCompare definition and implementation
|
||||
|
|
@ -1515,11 +1542,12 @@ NetGraph::build (const db::Circuit *c, DeviceCategorizer &device_categorizer, Ci
|
|||
for (std::vector<NetGraphNode>::iterator i = m_nodes.begin (); i != m_nodes.end (); ++i) {
|
||||
i->apply_net_index (m_net_index);
|
||||
}
|
||||
#if defined(PRINT_DEBUG_NETGRAPH)
|
||||
for (std::vector<NetGraphNode>::iterator i = m_nodes.begin (); i != m_nodes.end (); ++i) {
|
||||
tl::info << i->to_string () << tl::noendl;
|
||||
|
||||
if (options ()->debug_netgraph) {
|
||||
for (std::vector<NetGraphNode>::iterator i = m_nodes.begin (); i != m_nodes.end (); ++i) {
|
||||
tl::info << i->to_string () << tl::noendl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// create subcircuit virtual nodes
|
||||
|
||||
|
|
@ -1543,11 +1571,12 @@ NetGraph::build (const db::Circuit *c, DeviceCategorizer &device_categorizer, Ci
|
|||
for (std::map<const db::SubCircuit *, NetGraphNode>::iterator i = m_virtual_nodes.begin (); i != m_virtual_nodes.end (); ++i) {
|
||||
i->second.apply_net_index (m_net_index);
|
||||
}
|
||||
#if defined(PRINT_DEBUG_NETGRAPH)
|
||||
for (std::map<const db::SubCircuit *, NetGraphNode>::iterator i = m_virtual_nodes.begin (); i != m_virtual_nodes.end (); ++i) {
|
||||
tl::info << i->second.to_string () << tl::noendl;
|
||||
|
||||
if (options ()->debug_netgraph) {
|
||||
for (std::map<const db::SubCircuit *, NetGraphNode>::iterator i = m_virtual_nodes.begin (); i != m_virtual_nodes.end (); ++i) {
|
||||
tl::info << i->second.to_string () << tl::noendl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t
|
||||
|
|
@ -1560,34 +1589,48 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr
|
|||
|
||||
std::vector<const NetGraphNode *> other_nodes;
|
||||
other_nodes.reserve (ee - e);
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent(depth) << "consider transitions:";
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << indent(depth) << "considering transitions:";
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
|
||||
for (NetGraphNode::edge_iterator i = e; i != ee; ++i) {
|
||||
if (i->second.first != net_index) {
|
||||
const NetGraphNode *nn = &node (i->second.first);
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent(depth) << "here: " << (nn->net() ? nn->net()->expanded_name().c_str() : "(null)") << " via";
|
||||
for (std::vector<NetGraphNode::Transition>::const_iterator t = i->first.begin (); t != i->first.end(); ++t) {
|
||||
tl::info << indent(depth) << " " << t->to_string();
|
||||
if (options ()->debug_netcompare) {
|
||||
if (first) {
|
||||
tl::info << indent (depth) << " here: " << (node (net_index).net () ? node (net_index).net ()->expanded_name ().c_str () : "(null)") << " ->";
|
||||
first = false;
|
||||
}
|
||||
tl::info << indent (depth) << " " << (nn->net () ? nn->net ()->expanded_name ().c_str() : "(null)") << " via: " << tl::noendl;
|
||||
for (std::vector<NetGraphNode::Transition>::const_iterator t = i->first.begin (); t != i->first.end(); ++t) {
|
||||
tl::info << (t != i->first.begin () ? "; " : "") << t->to_string() << tl::noendl;
|
||||
}
|
||||
tl::info << "";
|
||||
}
|
||||
#endif
|
||||
nodes.push_back (nn);
|
||||
}
|
||||
}
|
||||
|
||||
if (! nodes.empty ()) { // if non-ambiguous, non-assigned
|
||||
|
||||
first = true;
|
||||
|
||||
for (NetGraphNode::edge_iterator i = e_other; i != ee_other; ++i) {
|
||||
if (i->second.first != other_net_index) {
|
||||
const NetGraphNode *nn = &data->other->node (i->second.first);
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent(depth) << "there: " << (nn->net() ? nn->net()->expanded_name().c_str() : "(null)") << " via";
|
||||
for (std::vector<NetGraphNode::Transition>::const_iterator t = i->first.begin (); t != i->first.end(); ++t) {
|
||||
tl::info << indent(depth) << " " << t->to_string();
|
||||
if (options ()->debug_netcompare) {
|
||||
if (first) {
|
||||
tl::info << indent (depth) << " there: " << (data->other->node (other_net_index).net () ? data->other->node (other_net_index).net ()->expanded_name ().c_str () : "(null)") << " ->";
|
||||
first = false;
|
||||
}
|
||||
tl::info << indent(depth) << " " << (nn->net() ? nn->net()->expanded_name().c_str() : "(null)") << " via: " << tl::noendl;
|
||||
for (std::vector<NetGraphNode::Transition>::const_iterator t = i->first.begin (); t != i->first.end(); ++t) {
|
||||
tl::info << (t != i->first.begin () ? "; " : "") << t->to_string() << tl::noendl;
|
||||
}
|
||||
tl::info << "";
|
||||
}
|
||||
#endif
|
||||
other_nodes.push_back (nn);
|
||||
}
|
||||
}
|
||||
|
|
@ -1604,9 +1647,9 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr
|
|||
if (tentative) {
|
||||
|
||||
if (nodes.size () != other_nodes.size ()) {
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent(depth) << "! rejected branch.";
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << indent(depth) << "=> rejected branch.";
|
||||
}
|
||||
return failed_match;
|
||||
}
|
||||
|
||||
|
|
@ -1614,9 +1657,9 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr
|
|||
if (nodes.size () > 1 || other_nodes.size () > 1) {
|
||||
for (size_t i = 0; i < nodes.size (); ++i) {
|
||||
if (! (*nodes[i] == *other_nodes[i])) {
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent(depth) << "! rejected branch.";
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << indent(depth) << "=> rejected branch.";
|
||||
}
|
||||
return failed_match;
|
||||
}
|
||||
}
|
||||
|
|
@ -1631,9 +1674,9 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr
|
|||
|
||||
if (bt_count == failed_match) {
|
||||
if (tentative) {
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent(depth) << "! rejected branch.";
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << indent(depth) << "=> rejected branch.";
|
||||
}
|
||||
return bt_count;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1642,11 +1685,11 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr
|
|||
|
||||
}
|
||||
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
if (! new_nodes) {
|
||||
tl::info << indent(depth) << "! no updates.";
|
||||
if (options ()->debug_netcompare) {
|
||||
if (! new_nodes) {
|
||||
tl::info << indent(depth) << "=> no updates.";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return new_nodes;
|
||||
}
|
||||
|
||||
|
|
@ -1671,13 +1714,13 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc
|
|||
size_t other_net_index = n->other_net_index ();
|
||||
NetGraphNode *n_other = & data->other->node (other_net_index);
|
||||
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
if (! tentative) {
|
||||
tl::info << indent(depth) << "deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name ();
|
||||
} else {
|
||||
tl::info << indent(depth) << "tentatively deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name ();
|
||||
if (options ()->debug_netcompare) {
|
||||
if (! tentative) {
|
||||
tl::info << indent(depth) << "deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name ();
|
||||
} else {
|
||||
tl::info << indent(depth) << "tentatively deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name ();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t new_nodes = 0;
|
||||
|
||||
|
|
@ -1722,9 +1765,9 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc
|
|||
|
||||
size_t bt_count = derive_node_identities_for_edges (e, ee, e_other, ee_other, net_index, other_net_index, depth, n_branch, tentative, with_ambiguous, data);
|
||||
if (bt_count == failed_match) {
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent(depth) << "! rejected pair.";
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << indent(depth) << "=> rejected pair.";
|
||||
}
|
||||
return bt_count;
|
||||
} else {
|
||||
new_nodes += bt_count;
|
||||
|
|
@ -1733,9 +1776,9 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc
|
|||
} else if (tentative) {
|
||||
// in tentative mode an exact match is required: no having the same edges for a node disqualifies the node
|
||||
// as matching.
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent(depth) << "! rejected pair for missing edge.";
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << indent(depth) << "=> rejected pair for missing edge.";
|
||||
}
|
||||
return failed_match;
|
||||
}
|
||||
|
||||
|
|
@ -1758,9 +1801,9 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc
|
|||
|
||||
NetGraphNode::edge_iterator e = n->find_edge (e_other->first);
|
||||
if (e == n->end ()) {
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent(depth) << "! rejected pair for missing edge.";
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << indent(depth) << "=> rejected pair for missing edge.";
|
||||
}
|
||||
return failed_match;
|
||||
}
|
||||
|
||||
|
|
@ -1770,11 +1813,11 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc
|
|||
|
||||
}
|
||||
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
if (! tentative && new_nodes > 0) {
|
||||
tl::info << indent(depth) << "finished pair deduction: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name () << " with " << new_nodes << " new pairs";
|
||||
if (options ()->debug_netcompare) {
|
||||
if (! tentative && new_nodes > 0) {
|
||||
tl::info << indent(depth) << "=> finished pair deduction: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name () << " with " << new_nodes << " new pairs";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return new_nodes;
|
||||
}
|
||||
|
|
@ -1855,17 +1898,18 @@ static bool net_names_are_different (const db::Net *a, const db::Net *b)
|
|||
size_t
|
||||
NetGraph::derive_node_identities_from_node_set (std::vector<const NetGraphNode *> &nodes, std::vector<const NetGraphNode *> &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data)
|
||||
{
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
std::string indent_s = indent (depth);
|
||||
indent_s += "*" + tl::to_string (n_branch) + " ";
|
||||
#endif
|
||||
std::string indent_s;
|
||||
if (options ()->debug_netcompare) {
|
||||
indent_s = indent (depth);
|
||||
indent_s += "*" + tl::to_string (n_branch) + " ";
|
||||
}
|
||||
|
||||
size_t new_nodes = 0;
|
||||
|
||||
if (depth > data->max_depth) {
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent_s << "max. depth exhausted (" << depth + 1 << ">" << data->max_depth << ")";
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << indent_s << "max. depth exhausted (" << depth + 1 << ">" << data->max_depth << ")";
|
||||
}
|
||||
return failed_match;
|
||||
}
|
||||
|
||||
|
|
@ -1881,9 +1925,9 @@ NetGraph::derive_node_identities_from_node_set (std::vector<const NetGraphNode *
|
|||
|
||||
TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni);
|
||||
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent_s << "deduced match (singular): " << nodes.front ()->net ()->expanded_name () << " vs. " << other_nodes.front ()->net ()->expanded_name ();
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << indent_s << "deduced match (singular): " << nodes.front ()->net ()->expanded_name () << " vs. " << other_nodes.front ()->net ()->expanded_name ();
|
||||
}
|
||||
if (data->logger && ! tentative) {
|
||||
if (! (node (ni) == data->other->node (other_ni))) {
|
||||
// this is a mismatch but we continue, because that is the only candidate
|
||||
|
|
@ -2030,9 +2074,9 @@ NetGraph::derive_node_identities_from_node_set (std::vector<const NetGraphNode *
|
|||
// their names differ -> this favors net matching by name
|
||||
|
||||
if (tentative && ! data->dont_consider_net_names && net_names_are_different ((*nr->n1)->net (), (*nr->n2)->net ())) {
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent_s << "rejecting pair as names are not identical: " << (*nr->n1)->net ()->expanded_name () << " vs. " << (*nr->n2)->net ()->expanded_name ();
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << indent_s << "rejecting pair as names are not identical: " << (*nr->n1)->net ()->expanded_name () << " vs. " << (*nr->n2)->net ()->expanded_name ();
|
||||
}
|
||||
return failed_match;
|
||||
}
|
||||
|
||||
|
|
@ -2044,9 +2088,9 @@ NetGraph::derive_node_identities_from_node_set (std::vector<const NetGraphNode *
|
|||
|
||||
TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni);
|
||||
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent_s << "deduced match (singular): " << (*nr->n1)->net ()->expanded_name () << " vs. " << (*nr->n2)->net ()->expanded_name ();
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << indent_s << "deduced match (singular): " << (*nr->n1)->net ()->expanded_name () << " vs. " << (*nr->n2)->net ()->expanded_name ();
|
||||
}
|
||||
if (data->logger && ! tentative) {
|
||||
if (! (node (ni) == data->other->node (other_ni))) {
|
||||
// this is a mismatch, but we continue with this
|
||||
|
|
@ -2086,16 +2130,16 @@ NetGraph::derive_node_identities_from_node_set (std::vector<const NetGraphNode *
|
|||
|
||||
} else if (nr->num * n_branch > data->max_n_branch) {
|
||||
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent_s << "max. complexity exhausted (" << nr->num << "*" << n_branch << ">" << data->max_n_branch << ") - mismatch.";
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << indent_s << "max. complexity exhausted (" << nr->num << "*" << n_branch << ">" << data->max_n_branch << ") - mismatch.";
|
||||
}
|
||||
return failed_match;
|
||||
|
||||
} else {
|
||||
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent_s << "analyzing ambiguity group with " << nr->num << " members";
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << indent_s << "analyzing ambiguity group with " << nr->num << " members";
|
||||
}
|
||||
|
||||
// sort the ambiguity group such that net names match best
|
||||
|
||||
|
|
@ -2152,16 +2196,16 @@ NetGraph::derive_node_identities_from_node_set (std::vector<const NetGraphNode *
|
|||
TentativeNodeMapping::map_pair_from_unknown (&tn, this, ni, data->other, other_ni);
|
||||
|
||||
// try this candidate in tentative mode
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent_s << "trying in tentative mode: " << (*i1)->net ()->expanded_name () << " vs. " << (*i2)->net ()->expanded_name ();
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << indent_s << "trying in tentative mode: " << (*i1)->net ()->expanded_name () << " vs. " << (*i2)->net ()->expanded_name ();
|
||||
}
|
||||
size_t bt_count = derive_node_identities (ni, depth + 1, nr->num * n_branch, &tn, with_ambiguous, data);
|
||||
|
||||
if (bt_count != failed_match) {
|
||||
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent_s << "match found";
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << indent_s << "match found";
|
||||
}
|
||||
// we have a match ...
|
||||
|
||||
if (any) {
|
||||
|
|
@ -2185,9 +2229,9 @@ NetGraph::derive_node_identities_from_node_set (std::vector<const NetGraphNode *
|
|||
}
|
||||
|
||||
if (! any && tentative) {
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent_s << "mismatch.";
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << indent_s << "mismatch.";
|
||||
}
|
||||
// a mismatch - stop here.
|
||||
return failed_match;
|
||||
}
|
||||
|
|
@ -2207,13 +2251,13 @@ NetGraph::derive_node_identities_from_node_set (std::vector<const NetGraphNode *
|
|||
|
||||
TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni);
|
||||
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
if (equivalent_other_nodes.has_attribute (p->second)) {
|
||||
tl::info << indent_s << "deduced ambiguous match: " << p->first->net ()->expanded_name () << " vs. " << p->second->net ()->expanded_name ();
|
||||
} else {
|
||||
tl::info << indent_s << "deduced match: " << p->first->net ()->expanded_name () << " vs. " << p->second->net ()->expanded_name ();
|
||||
if (options ()->debug_netcompare) {
|
||||
if (equivalent_other_nodes.has_attribute (p->second)) {
|
||||
tl::info << indent_s << "deduced ambiguous match: " << p->first->net ()->expanded_name () << " vs. " << p->second->net ()->expanded_name ();
|
||||
} else {
|
||||
tl::info << indent_s << "deduced match: " << p->first->net ()->expanded_name () << " vs. " << p->second->net ()->expanded_name ();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (data->logger) {
|
||||
bool ambiguous = equivalent_other_nodes.has_attribute (p->second);
|
||||
if (ambiguous) {
|
||||
|
|
@ -2249,9 +2293,9 @@ NetGraph::derive_node_identities_from_node_set (std::vector<const NetGraphNode *
|
|||
|
||||
}
|
||||
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << indent_s << "finished analysis of ambiguity group with " << nr->num << " members";
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << indent_s << "finished analysis of ambiguity group with " << nr->num << " members";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -2516,9 +2560,9 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
|
|||
|
||||
if (all_subcircuits_verified (ca, verified_circuits_a) && all_subcircuits_verified (cb, verified_circuits_b)) {
|
||||
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << "treating circuit: " << ca->name () << " vs. " << cb->name ();
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << "treating circuit: " << ca->name () << " vs. " << cb->name ();
|
||||
}
|
||||
if (mp_logger) {
|
||||
mp_logger->begin_circuit (ca, cb);
|
||||
}
|
||||
|
|
@ -2835,9 +2879,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
g2.identify (ni2, ni1);
|
||||
}
|
||||
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
int iter = 0;
|
||||
#endif
|
||||
|
||||
// two passes: one without ambiguities, the second one with
|
||||
|
||||
|
|
@ -2845,20 +2887,20 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
|
||||
for (int pass = 0; pass < 2; ++pass) {
|
||||
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
if (pass > 0) {
|
||||
tl::info << "including ambiguous nodes now.";
|
||||
if (options ()->debug_netcompare) {
|
||||
if (pass > 0) {
|
||||
tl::info << "including ambiguous nodes now.";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
good = true;
|
||||
while (true) {
|
||||
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
++iter;
|
||||
tl::info << "new compare iteration #" << iter;
|
||||
tl::info << "deducing from present nodes ...";
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << "new compare iteration #" << iter;
|
||||
tl::info << "deducing from present nodes ...";
|
||||
}
|
||||
|
||||
size_t new_identities = 0;
|
||||
|
||||
|
|
@ -2877,18 +2919,18 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
size_t ni = g1.derive_node_identities (i1 - g1.begin (), 0, 1, 0 /*not tentative*/, pass > 0 /*with ambiguities*/, &data);
|
||||
if (ni > 0 && ni != failed_match) {
|
||||
new_identities += ni;
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << ni << " new identities.";
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << ni << " new identities.";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << "checking topological identity ...";
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << "checking topological identity ...";
|
||||
}
|
||||
|
||||
// derive new identities through topology: first collect all nets with the same topological signature
|
||||
|
||||
|
|
@ -2934,9 +2976,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
|||
size_t ni = g1.derive_node_identities_from_node_set (nodes, other_nodes, 0, 1, 0 /*not tentative*/, pass > 0 /*with ambiguities*/, &data);
|
||||
if (ni > 0 && ni != failed_match) {
|
||||
new_identities += ni;
|
||||
#if defined(PRINT_DEBUG_NETCOMPARE)
|
||||
tl::info << ni << " new identities.";
|
||||
#endif
|
||||
if (options ()->debug_netcompare) {
|
||||
tl::info << ni << " new identities.";
|
||||
}
|
||||
}
|
||||
|
||||
if (new_identities == 0) {
|
||||
|
|
@ -3585,4 +3627,171 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG
|
|||
}
|
||||
}
|
||||
|
||||
static bool derive_symmetry_groups (const db::NetGraph &graph, const tl::equivalence_clusters<const NetGraphNode *> &identical_nodes, std::set<size_t> &considered_nodes, const std::set<size_t> &symmetry_group, std::list<std::set<size_t> > &symmetry_groups)
|
||||
{
|
||||
std::set<size_t> cids;
|
||||
std::set<size_t> new_symmetry_group;
|
||||
NetGraphNode::edge_type::first_type edge;
|
||||
|
||||
std::vector<NetGraphNode::edge_type> common_nodes_first;
|
||||
|
||||
bool has_candidate = true;
|
||||
|
||||
for (std::set<size_t>::const_iterator g = symmetry_group.begin (); g != symmetry_group.end () && has_candidate; ++g) {
|
||||
|
||||
std::vector<NetGraphNode::edge_type> common_nodes;
|
||||
|
||||
const NetGraphNode &n = graph.node (*g);
|
||||
for (NetGraphNode::edge_iterator e = n.begin (); e != n.end () && has_candidate; ++e) {
|
||||
|
||||
if (considered_nodes.find (e->second.first) != considered_nodes.end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const NetGraphNode *other = &graph.node (e->second.first);
|
||||
// NOTE: nodes with pins don't go into a symmetry group as we don't know what the pins connect to
|
||||
if (other->net ()->pin_count () == 0 && identical_nodes.has_attribute (other)) {
|
||||
|
||||
if (cids.empty ()) {
|
||||
edge = e->first;
|
||||
} else if (edge != e->first) {
|
||||
has_candidate = false;
|
||||
}
|
||||
|
||||
if (has_candidate) {
|
||||
cids.insert (identical_nodes.cluster_id (other));
|
||||
if (cids.size () > 1) {
|
||||
has_candidate = false;
|
||||
} else {
|
||||
new_symmetry_group.insert (e->second.first);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
common_nodes.push_back (*e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (has_candidate) {
|
||||
|
||||
// all other edges need to have identical destinations for the symmetry group to be
|
||||
// actually symmetric
|
||||
std::sort (common_nodes.begin (), common_nodes.end ());
|
||||
if (g == symmetry_group.begin ()) {
|
||||
common_nodes_first.swap (common_nodes);
|
||||
} else if (common_nodes_first != common_nodes) {
|
||||
has_candidate = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (has_candidate && ! cids.empty () && new_symmetry_group.size () > 1) {
|
||||
|
||||
considered_nodes.insert (new_symmetry_group.begin (), new_symmetry_group.end ());
|
||||
|
||||
if (derive_symmetry_groups (graph, identical_nodes, considered_nodes, new_symmetry_group, symmetry_groups)) {
|
||||
|
||||
symmetry_groups.push_back (new_symmetry_group);
|
||||
|
||||
} else {
|
||||
|
||||
std::set<size_t> cn;
|
||||
std::set_difference (considered_nodes.begin (), considered_nodes.end (), new_symmetry_group.begin (), new_symmetry_group.end (), std::inserter (cn, cn.begin ()));
|
||||
considered_nodes.swap (cn);
|
||||
|
||||
has_candidate = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return has_candidate;
|
||||
}
|
||||
|
||||
void
|
||||
NetlistComparer::join_symmetric_nets (db::Circuit *circuit)
|
||||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Join symmetric nodes for circuit: ")) + circuit->name ());
|
||||
|
||||
db::DeviceFilter device_filter (m_cap_threshold, m_res_threshold);
|
||||
db::CircuitPinMapper circuit_pin_mapper;
|
||||
std::map<const db::Circuit *, CircuitMapper> circuit_and_pin_mapping;
|
||||
|
||||
db::NetGraph graph;
|
||||
graph.build (circuit, *mp_device_categorizer, *mp_circuit_categorizer, device_filter, &circuit_and_pin_mapping, &circuit_pin_mapper);
|
||||
|
||||
// sort the nodes so we can easily identify the identical ones (in terms of topology)
|
||||
// nodes are identical if the attached devices and circuits are of the same kind and with the same parameters
|
||||
// and connect to other nodes in identical configurations.
|
||||
|
||||
std::vector<const NetGraphNode *> nodes;
|
||||
|
||||
nodes.reserve (graph.end () - graph.begin ());
|
||||
for (db::NetGraph::node_iterator i = graph.begin (); i != graph.end (); ++i) {
|
||||
if (! i->has_other () && i->net ()) {
|
||||
nodes.push_back (i.operator-> ());
|
||||
}
|
||||
}
|
||||
|
||||
std::sort (nodes.begin (), nodes.end (), CompareNodePtr ());
|
||||
|
||||
// Identical nodes leading to the same nodes on the other side are candidates for symmetry.
|
||||
|
||||
tl::equivalence_clusters<const NetGraphNode *> identical_nodes;
|
||||
|
||||
for (std::vector<const NetGraphNode *>::const_iterator np = nodes.begin (); np + 1 != nodes.end (); ++np) {
|
||||
if (*np[0] == *np[1]) {
|
||||
identical_nodes.same (np[0], np[1]);
|
||||
}
|
||||
}
|
||||
|
||||
std::list<std::set<size_t> > symmetry_groups;
|
||||
std::set<size_t> visited;
|
||||
|
||||
for (std::vector<const NetGraphNode *>::const_iterator np = nodes.begin (); np != nodes.end (); ++np) {
|
||||
|
||||
size_t node_id = graph.node_index_for_net (np[0]->net ());
|
||||
if (visited.find (node_id) != visited.end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::set<size_t> considered_nodes;
|
||||
considered_nodes.insert (node_id);
|
||||
|
||||
std::set<size_t> symmetry_group;
|
||||
symmetry_group.insert (node_id);
|
||||
|
||||
derive_symmetry_groups (graph, identical_nodes, considered_nodes, symmetry_group, symmetry_groups);
|
||||
|
||||
visited.insert (considered_nodes.begin (), considered_nodes.end ());
|
||||
|
||||
}
|
||||
|
||||
if (! symmetry_groups.empty () && tl::verbosity () >= 30) {
|
||||
tl::info << tl::to_string (tr ("Symmetry groups:"));
|
||||
int index = 0;
|
||||
for (std::list<std::set<size_t> >::const_iterator g = symmetry_groups.begin (); g != symmetry_groups.end (); ++g) {
|
||||
tl::info << " [" << index << "] " << tl::noendl;
|
||||
for (std::set<size_t>::const_iterator i = g->begin (); i != g->end (); ++i) {
|
||||
tl::info << (i == g->begin () ? "" : ",") << (graph.node (*i).net () ? graph.node (*i).net ()->expanded_name ().c_str () : "(null)") << tl::noendl;
|
||||
}
|
||||
++index;
|
||||
tl::info << "";
|
||||
}
|
||||
}
|
||||
|
||||
// join the nets
|
||||
|
||||
for (std::list<std::set<size_t> >::const_iterator g = symmetry_groups.begin (); g != symmetry_groups.end (); ++g) {
|
||||
for (std::set<size_t>::const_iterator i = g->begin (); i != g->end (); ++i) {
|
||||
if (i != g->begin ()) {
|
||||
circuit->join_nets (const_cast<db::Net *> (graph.net_by_node_index (*g->begin ())), const_cast<db::Net *> (graph.net_by_node_index (*i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -302,6 +302,20 @@ public:
|
|||
*/
|
||||
bool compare (const db::Netlist *a, const db::Netlist *b, db::NetlistCompareLogger *logger) const;
|
||||
|
||||
/**
|
||||
* @brief Joins symmetric nodes in the given circuit
|
||||
*
|
||||
* Nodes are symmetric if their exchanging would not modify the circuit.
|
||||
* Hence they will carry the same potential and can be connected (joined).
|
||||
* This will simplify the circuit and can be applied before device combination
|
||||
* to render a schematic-equivalent netlist in some cases (split gate option).
|
||||
*
|
||||
* This algorithm will apply the comparer's settings to the symmetry
|
||||
* condition (device filtering, device compare tolerances, device class
|
||||
* equivalence etc.).
|
||||
*/
|
||||
void join_symmetric_nets (db::Circuit *circuit);
|
||||
|
||||
private:
|
||||
// No copying
|
||||
NetlistComparer (const NetlistComparer &);
|
||||
|
|
|
|||
|
|
@ -1201,6 +1201,12 @@ Class<db::Circuit> decl_dbCircuit (decl_dbNetlistObject, "db", "Circuit",
|
|||
gsi::method ("remove_net", &db::Circuit::remove_net, gsi::arg ("net"),
|
||||
"@brief Removes the given net from the circuit\n"
|
||||
) +
|
||||
gsi::method ("join_nets", &db::Circuit::join_nets, gsi::arg ("net"), gsi::arg ("with"),
|
||||
"@brief Joins (connects) two nets into one\n"
|
||||
"This method will connect the 'with' net with 'net' and remove 'with'.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.4."
|
||||
) +
|
||||
gsi::iterator ("each_net", (db::Circuit::net_iterator (db::Circuit::*) ()) &db::Circuit::begin_nets, (db::Circuit::net_iterator (db::Circuit::*) ()) &db::Circuit::end_nets,
|
||||
"@brief Iterates over the nets of the circuit"
|
||||
) +
|
||||
|
|
@ -1412,6 +1418,22 @@ static void blank_circuit_by_name (db::Netlist *nl, const std::string &name_patt
|
|||
}
|
||||
}
|
||||
|
||||
static std::vector<db::Circuit *>
|
||||
circuits_by_name (db::Netlist *netlist, const std::string &name_pattern)
|
||||
{
|
||||
std::vector<db::Circuit *> res;
|
||||
|
||||
tl::GlobPattern glob (name_pattern);
|
||||
for (db::Netlist::circuit_iterator c = netlist->begin_circuits (); c != netlist->end_circuits (); ++c) {
|
||||
db::Circuit *circuit = c.operator-> ();
|
||||
if (glob.match (circuit->name ())) {
|
||||
res.push_back (circuit);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Class<db::Netlist> decl_dbNetlist ("db", "Netlist",
|
||||
gsi::method_ext ("add", &gsi::add_circuit, gsi::arg ("circuit"),
|
||||
"@brief Adds the circuit to the netlist\n"
|
||||
|
|
@ -1469,6 +1491,12 @@ Class<db::Netlist> decl_dbNetlist ("db", "Netlist",
|
|||
"@brief Gets the circuit object for a given name.\n"
|
||||
"If the name is not a valid circuit name, nil is returned."
|
||||
) +
|
||||
gsi::method_ext ("circuits_by_name", &circuits_by_name, gsi::arg ("name_pattern"),
|
||||
"@brief Gets the circuit objects for a given name filter.\n"
|
||||
"The name filter is a glob pattern. This method will return all \\Circuit objects matching the glob pattern.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.4.\n"
|
||||
) +
|
||||
gsi::iterator ("each_circuit_top_down", (db::Netlist::top_down_circuit_iterator (db::Netlist::*) ()) &db::Netlist::begin_top_down, (db::Netlist::top_down_circuit_iterator (db::Netlist::*) ()) &db::Netlist::end_top_down,
|
||||
"@brief Iterates over the circuits top-down\n"
|
||||
"Iterating top-down means the parent circuits come before the child circuits. "
|
||||
|
|
|
|||
|
|
@ -557,6 +557,20 @@ Class<db::NetlistComparer> decl_dbNetlistComparer ("db", "NetlistComparer",
|
|||
"This method will perform the actual netlist compare using the given logger. It will return true if both netlists are identical. "
|
||||
"If the comparer has been configured with \\same_nets or similar methods, the objects given there must "
|
||||
"be located inside 'circuit_a' and 'circuit_b' respectively."
|
||||
) +
|
||||
gsi::method ("join_symmetric_nets", &db::NetlistComparer::join_symmetric_nets, gsi::arg ("circuit"),
|
||||
"@brief Joins symmetric nodes in the given circuit.\n"
|
||||
"\n"
|
||||
"Nodes are symmetrical if swapping them would not modify the circuit.\n"
|
||||
"Hence they will carry the same potential and can be connected (joined).\n"
|
||||
"This will simplify the circuit and can be applied before device combination\n"
|
||||
"to render a schematic-equivalent netlist in some cases (split gate option).\n"
|
||||
"\n"
|
||||
"This algorithm will apply the comparer's settings to the symmetry\n"
|
||||
"condition (device filtering, device compare tolerances, device class\n"
|
||||
"equivalence etc.).\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.4.\n"
|
||||
),
|
||||
"@brief Compares two netlists\n"
|
||||
"This class performs a comparison of two netlists.\n"
|
||||
|
|
|
|||
|
|
@ -584,6 +584,75 @@ TEST(1_BasicExtraction)
|
|||
|
||||
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "RINGO:$I39");
|
||||
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "RINGO:$I2");
|
||||
|
||||
// use this opportunity to check joining of nets with cluster joining
|
||||
db::Circuit *top = l2n.netlist ()->circuit_by_name ("RINGO");
|
||||
top->join_nets (top->net_by_name ("VSS"), top->net_by_name ("VDD"));
|
||||
top->join_nets (top->net_by_name ("FB"), top->net_by_name ("OSC"));
|
||||
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
"circuit RINGO (FB=FB,OSC=FB,VSS=VSS,VDD=VDD);\n"
|
||||
" subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=FB,$4=VSS,$5=VSS);\n"
|
||||
" subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VSS);\n"
|
||||
" subcircuit INV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VSS);\n"
|
||||
" subcircuit INV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VSS);\n"
|
||||
" subcircuit INV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VSS);\n"
|
||||
" subcircuit INV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VSS);\n"
|
||||
" subcircuit INV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VSS);\n"
|
||||
" subcircuit INV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VSS);\n"
|
||||
" subcircuit INV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VSS);\n"
|
||||
" subcircuit INV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VSS);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=$5,G=$2,D=OUT) (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=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// do some probing after purging
|
||||
|
||||
// top level
|
||||
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::DPoint (0.0, 1.8))), "RINGO:FB");
|
||||
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::Point (0, 1800))), "RINGO:FB");
|
||||
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::DPoint (-2.0, 1.8))), "(null)");
|
||||
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (-1.5, 1.8))), "RINGO:FB");
|
||||
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (24.5, 1.8))), "RINGO:FB");
|
||||
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "RINGO:VSS");
|
||||
|
||||
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "RINGO:$I39");
|
||||
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "RINGO:$I2");
|
||||
|
||||
// compare the collected test data
|
||||
|
||||
{
|
||||
db::Layout ly2;
|
||||
ly2.dbu (ly.dbu ());
|
||||
db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP"));
|
||||
|
||||
db::CellMapping cm = l2n.cell_mapping_into (ly2, top2, true /*with device cells*/);
|
||||
|
||||
std::map<unsigned int, const db::Region *> lmap;
|
||||
lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = &rpsd;
|
||||
lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = &rnsd;
|
||||
lmap [ly2.insert_layer (db::LayerProperties (3, 0)) ] = rpoly.get ();
|
||||
lmap [ly2.insert_layer (db::LayerProperties (4, 0)) ] = rdiff_cont.get ();
|
||||
lmap [ly2.insert_layer (db::LayerProperties (5, 0)) ] = rpoly_cont.get ();
|
||||
lmap [ly2.insert_layer (db::LayerProperties (6, 0)) ] = rmetal1.get ();
|
||||
lmap [ly2.insert_layer (db::LayerProperties (7, 0)) ] = rvia1.get ();
|
||||
lmap [ly2.insert_layer (db::LayerProperties (8, 0)) ] = rmetal2.get ();
|
||||
|
||||
l2n.build_all_nets (cm, ly2, lmap, "NET_", tl::Variant (), db::LayoutToNetlist::BNH_SubcircuitCells, "CIRCUIT_", "DEVICE_");
|
||||
|
||||
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_joined_nets.gds");
|
||||
|
||||
db::compare_layouts (_this, ly2, au);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(2_Probing)
|
||||
|
|
|
|||
|
|
@ -3703,3 +3703,204 @@ TEST(24_NodesRemovedButConnectedInOther)
|
|||
);
|
||||
EXPECT_EQ (good, true);
|
||||
}
|
||||
|
||||
TEST(25_JoinSymmetricNets)
|
||||
{
|
||||
const char *nls =
|
||||
"circuit NAND2 (A=A,B=B,OUT=OUT,VSS=VSS,VDD=VDD);\n"
|
||||
" device PMOS $1 (S=OUT,G=A,D=VDD) (L=0.25,W=1);\n"
|
||||
" device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=1);\n"
|
||||
// NOTE: $1 and $2 are separate nets, but can be joined due to symmetry
|
||||
" device NMOS $3 (S=$1,G=A,D=OUT) (L=0.25,W=1);\n"
|
||||
" device NMOS $4 (S=$2,G=A,D=OUT) (L=0.25,W=1);\n"
|
||||
" device NMOS $5 (S=$1,G=B,D=VSS) (L=0.25,W=1);\n"
|
||||
" device NMOS $6 (S=$2,G=B,D=VSS) (L=0.25,W=1);\n"
|
||||
"end;\n";
|
||||
|
||||
db::Netlist nl;
|
||||
prep_nl (nl, nls);
|
||||
|
||||
db::NetlistComparer comp;
|
||||
comp.join_symmetric_nets (nl.circuit_by_name ("NAND2"));
|
||||
|
||||
// NOTE $1 and $2 are joined because they are symmetric
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit NAND2 (A=A,B=B,OUT=OUT,VSS=VSS,VDD=VDD);\n"
|
||||
" device PMOS $1 (S=OUT,G=A,D=VDD) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $3 (S=$1,G=A,D=OUT) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $4 (S=$1,G=A,D=OUT) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $5 (S=$1,G=B,D=VSS) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $6 (S=$1,G=B,D=VSS) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
)
|
||||
}
|
||||
|
||||
TEST(25b_JoinSymmetricNetsMultiple)
|
||||
{
|
||||
const char *nls =
|
||||
"circuit NAND2 (A=A,B=B,OUT=OUT,VSS=VSS,VDD=VDD);\n"
|
||||
" device PMOS $1 (S=OUT,G=A,D=VDD) (L=0.25,W=1);\n"
|
||||
" device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=1);\n"
|
||||
" device PMOS $3 (S=VDD,G=C,D=OUT) (L=0.25,W=1);\n"
|
||||
// NOTE: $1 and $2 are separate nets, but can be joined due to symmetry
|
||||
" device NMOS $4 (S=$1,G=A,D=OUT) (L=0.25,W=1);\n"
|
||||
" device NMOS $5 (S=$2,G=A,D=OUT) (L=0.25,W=1);\n"
|
||||
" device NMOS $6 (S=$3,G=A,D=OUT) (L=0.25,W=1);\n"
|
||||
" device NMOS $7 (S=$1,G=B,D=$4) (L=0.25,W=1);\n"
|
||||
" device NMOS $8 (S=$2,G=B,D=$5) (L=0.25,W=1);\n"
|
||||
" device NMOS $9 (S=$3,G=B,D=$6) (L=0.25,W=1);\n"
|
||||
" device NMOS $10 (S=$4,G=C,D=VSS) (L=0.25,W=1);\n"
|
||||
" device NMOS $11 (S=$5,G=C,D=VSS) (L=0.25,W=1);\n"
|
||||
" device NMOS $12 (S=$6,G=C,D=VSS) (L=0.25,W=1);\n"
|
||||
"end;\n";
|
||||
|
||||
db::Netlist nl;
|
||||
prep_nl (nl, nls);
|
||||
|
||||
db::NetlistComparer comp;
|
||||
comp.join_symmetric_nets (nl.circuit_by_name ("NAND2"));
|
||||
|
||||
nl.combine_devices ();
|
||||
|
||||
// NOTE $1 and $2 are joined because they are symmetric
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit NAND2 (A=A,B=B,OUT=OUT,VSS=VSS,VDD=VDD);\n"
|
||||
" device PMOS $1 (S=OUT,G=A,D=VDD) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device PMOS $3 (S=VDD,G=C,D=OUT) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $4 (S=$1,G=A,D=OUT) (L=0.25,W=3,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $7 (S=$1,G=B,D=$4) (L=0.25,W=3,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $10 (S=$4,G=C,D=VSS) (L=0.25,W=3,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
)
|
||||
}
|
||||
|
||||
TEST(26_JoinSymmetricNets)
|
||||
{
|
||||
const char *nls =
|
||||
"circuit RESCUBE (A=A,B=B);\n"
|
||||
" device RES $1 (A=A,B=$1) (R=1000);\n"
|
||||
" device RES $2 (A=A,B=$2) (R=1000);\n"
|
||||
" device RES $3 (A=A,B=$3) (R=1000);\n"
|
||||
" device RES $4 (A=$1,B=$4) (R=1000);\n"
|
||||
" device RES $5 (A=$2,B=$4) (R=1000);\n"
|
||||
" device RES $6 (A=$2,B=$5) (R=1000);\n"
|
||||
" device RES $7 (A=$3,B=$5) (R=1000);\n"
|
||||
" device RES $8 (A=$3,B=$6) (R=1000);\n"
|
||||
" device RES $9 (A=$1,B=$6) (R=1000);\n"
|
||||
" device RES $9 (A=$4,B=B) (R=1000);\n"
|
||||
" device RES $10 (A=$5,B=B) (R=1000);\n"
|
||||
" device RES $11 (A=$6,B=B) (R=1000);\n"
|
||||
"end;\n";
|
||||
|
||||
db::Netlist nl;
|
||||
prep_nl (nl, nls);
|
||||
|
||||
db::NetlistComparer comp;
|
||||
comp.join_symmetric_nets (nl.circuit_by_name ("RESCUBE"));
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit RESCUBE (A=A,B=B);\n"
|
||||
" device RES $1 (A=A,B=$1) (R=1000,L=0,W=0,A=0,P=0);\n"
|
||||
" device RES $2 (A=A,B=$1) (R=1000,L=0,W=0,A=0,P=0);\n"
|
||||
" device RES $3 (A=A,B=$1) (R=1000,L=0,W=0,A=0,P=0);\n"
|
||||
" device RES $4 (A=$1,B=$4) (R=1000,L=0,W=0,A=0,P=0);\n"
|
||||
" device RES $5 (A=$1,B=$4) (R=1000,L=0,W=0,A=0,P=0);\n"
|
||||
" device RES $6 (A=$1,B=$4) (R=1000,L=0,W=0,A=0,P=0);\n"
|
||||
" device RES $7 (A=$1,B=$4) (R=1000,L=0,W=0,A=0,P=0);\n"
|
||||
" device RES $8 (A=$1,B=$4) (R=1000,L=0,W=0,A=0,P=0);\n"
|
||||
" device RES $9 (A=$1,B=$4) (R=1000,L=0,W=0,A=0,P=0);\n"
|
||||
" device RES $10 (A=$4,B=B) (R=1000,L=0,W=0,A=0,P=0);\n"
|
||||
" device RES $11 (A=$4,B=B) (R=1000,L=0,W=0,A=0,P=0);\n"
|
||||
" device RES $12 (A=$4,B=B) (R=1000,L=0,W=0,A=0,P=0);\n"
|
||||
"end;\n"
|
||||
)
|
||||
|
||||
nl.combine_devices ();
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit RESCUBE (A=A,B=B);\n"
|
||||
" device RES $10 (A=A,B=B) (R=833.333333333,L=0,W=0,A=0,P=0);\n"
|
||||
"end;\n"
|
||||
)
|
||||
}
|
||||
|
||||
TEST(27_DontJoinSymmetricNetsWithPins)
|
||||
{
|
||||
const char *nls =
|
||||
"circuit NAND2 (A=A,B=B,OUT=OUT,VSS=VSS,VDD=VDD,X=$1,Y=$2);\n"
|
||||
" device PMOS $1 (S=OUT,G=A,D=VDD) (L=0.25,W=1);\n"
|
||||
" device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=1);\n"
|
||||
// NOTE: $1 and $2 are separate nets, but can be joined due to symmetry
|
||||
" device NMOS $3 (S=$1,G=A,D=OUT) (L=0.25,W=1);\n"
|
||||
" device NMOS $4 (S=$2,G=A,D=OUT) (L=0.25,W=1);\n"
|
||||
" device NMOS $5 (S=$1,G=B,D=VSS) (L=0.25,W=1);\n"
|
||||
" device NMOS $6 (S=$2,G=B,D=VSS) (L=0.25,W=1);\n"
|
||||
"end;\n";
|
||||
|
||||
db::Netlist nl;
|
||||
prep_nl (nl, nls);
|
||||
|
||||
db::NetlistComparer comp;
|
||||
comp.join_symmetric_nets (nl.circuit_by_name ("NAND2"));
|
||||
|
||||
// NOTE $1 and $2 are NOT joined because they have pins
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit NAND2 (A=A,B=B,OUT=OUT,VSS=VSS,VDD=VDD,X=$1,Y=$2);\n"
|
||||
" device PMOS $1 (S=OUT,G=A,D=VDD) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $3 (S=$1,G=A,D=OUT) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $4 (S=$2,G=A,D=OUT) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $5 (S=$1,G=B,D=VSS) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $6 (S=$2,G=B,D=VSS) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
)
|
||||
}
|
||||
|
||||
TEST(28_NoSymmetryDetectionCases)
|
||||
{
|
||||
{
|
||||
const char *nls =
|
||||
"circuit NAND2 (A=A,B=B,OUT=OUT,VSS=VSS,VDD=VDD);\n"
|
||||
" device PMOS $1 (S=OUT,G=A,D=VDD) (L=0.25,W=1);\n"
|
||||
" device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=1);\n"
|
||||
// NOTE: $1 and $2 are separate nets, but cannot be joined because of different W
|
||||
" device NMOS $3 (S=$1,G=A,D=OUT) (L=0.25,W=1);\n"
|
||||
" device NMOS $4 (S=$2,G=A,D=OUT) (L=0.25,W=1.1);\n"
|
||||
" device NMOS $5 (S=$1,G=B,D=VSS) (L=0.25,W=1);\n"
|
||||
" device NMOS $6 (S=$2,G=B,D=VSS) (L=0.25,W=1);\n"
|
||||
"end;\n";
|
||||
|
||||
db::Netlist nl;
|
||||
prep_nl (nl, nls);
|
||||
|
||||
db::NetlistComparer comp;
|
||||
std::string sref = nl.to_string ();
|
||||
comp.join_symmetric_nets (nl.circuit_by_name ("NAND2"));
|
||||
|
||||
EXPECT_EQ (nl.to_string (), sref);
|
||||
}
|
||||
|
||||
{
|
||||
const char *nls =
|
||||
"circuit NAND2 (A=A,B=B,OUT=OUT,VSS=VSS,VSS2=VSS2,VDD=VDD);\n"
|
||||
" device PMOS $1 (S=OUT,G=A,D=VDD) (L=0.25,W=1);\n"
|
||||
" device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=1);\n"
|
||||
" device NMOS $3 (S=$1,G=A,D=OUT) (L=0.25,W=1);\n"
|
||||
" device NMOS $4 (S=$2,G=A,D=OUT) (L=0.25,W=1);\n"
|
||||
// NOTE: $1 and $2 are separate nets, but cannot be joined because of different D connections
|
||||
" device NMOS $5 (S=$1,G=B,D=VSS) (L=0.25,W=1);\n"
|
||||
" device NMOS $6 (S=$2,G=B,D=VSS2) (L=0.25,W=1);\n"
|
||||
"end;\n";
|
||||
|
||||
db::Netlist nl;
|
||||
prep_nl (nl, nls);
|
||||
|
||||
db::NetlistComparer comp;
|
||||
std::string sref = nl.to_string ();
|
||||
comp.join_symmetric_nets (nl.circuit_by_name ("NAND2"));
|
||||
|
||||
EXPECT_EQ (nl.to_string (), sref);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -371,15 +371,6 @@ TEST(1_DeviceAndNetExtraction)
|
|||
" device NMOS $4 (S=$4,G=$2,D=OUT) (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.gds");
|
||||
|
||||
db::compare_layouts (_this, ly, au);
|
||||
}
|
||||
|
||||
TEST(2_DeviceAndNetExtractionFlat)
|
||||
|
|
|
|||
|
|
@ -1525,3 +1525,89 @@ TEST(23_NetlistObject)
|
|||
pin3 = pin2;
|
||||
EXPECT_EQ (pin3.property (1).to_string (), "hello");
|
||||
}
|
||||
|
||||
TEST(24_JoinNets)
|
||||
{
|
||||
db::Netlist nl;
|
||||
db::Circuit *c;
|
||||
|
||||
db::DeviceClass *dc;
|
||||
|
||||
dc = new db::DeviceClassMOS3Transistor ();
|
||||
dc->set_name ("NMOS");
|
||||
nl.add_device_class (dc);
|
||||
|
||||
dc = new db::DeviceClassMOS3Transistor ();
|
||||
dc->set_name ("PMOS");
|
||||
nl.add_device_class (dc);
|
||||
|
||||
nl.from_string (
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" subcircuit PTRANS SC1 ($1=$5,$2=$2,$3=IN);\n"
|
||||
" subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN);\n"
|
||||
" subcircuit PTRANS SC3 ($1=$5,$2=OUT,$3=$2);\n"
|
||||
" subcircuit NTRANS SC4 ($1=$4,$2=OUT,$3=$2);\n"
|
||||
"end;\n"
|
||||
"circuit PTRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
" device PMOS $1 (S=$1,D=$2,G=$3) (L=0.25,W=0.95);\n"
|
||||
"end;\n"
|
||||
"circuit NTRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
" device NMOS $1 (S=$1,D=$2,G=$3) (L=0.25,W=0.95);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
c = nl.circuit_by_name ("INV2");
|
||||
c->join_nets (c->net_by_name ("IN"), c->net_by_name ("OUT"));
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=IN,$4=$4,$5=$5);\n"
|
||||
" subcircuit PTRANS SC1 ($1=$5,$2=$2,$3=IN);\n"
|
||||
" subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN);\n"
|
||||
" subcircuit PTRANS SC3 ($1=$5,$2=IN,$3=$2);\n"
|
||||
" subcircuit NTRANS SC4 ($1=$4,$2=IN,$3=$2);\n"
|
||||
"end;\n"
|
||||
"circuit PTRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
" device PMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
"circuit NTRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
" device NMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(25_JoinNets)
|
||||
{
|
||||
db::Netlist nl;
|
||||
db::Circuit *c;
|
||||
|
||||
db::DeviceClass *dc;
|
||||
|
||||
dc = new db::DeviceClassMOS3Transistor ();
|
||||
dc->set_name ("NMOS");
|
||||
nl.add_device_class (dc);
|
||||
|
||||
dc = new db::DeviceClassMOS3Transistor ();
|
||||
dc->set_name ("PMOS");
|
||||
nl.add_device_class (dc);
|
||||
|
||||
nl.from_string (
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" device PMOS $1 (S=$5,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $3 (S=$4,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
c = nl.circuit_by_name ("INV2");
|
||||
c->join_nets (c->net_by_name ("IN"), c->net_by_name ("OUT"));
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=IN,$4=$4,$5=$5);\n"
|
||||
" device PMOS $1 (S=$5,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device PMOS $2 (S=$5,G=$2,D=IN) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $3 (S=$4,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $4 (S=$4,G=$2,D=IN) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
|
||||
|
||||
<!-- generated by /home/matthias/klayout/dvb/scripts/extract_doc.rb -->
|
||||
<!-- generated by /home/matthias/klayout/master/scripts/extract_doc.rb -->
|
||||
<!-- DO NOT EDIT! -->
|
||||
|
||||
<doc>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
|
||||
|
||||
<!-- generated by /home/matthias/klayout/dvb/scripts/extract_doc.rb -->
|
||||
<!-- generated by /home/matthias/klayout/master/scripts/extract_doc.rb -->
|
||||
<!-- DO NOT EDIT! -->
|
||||
|
||||
<doc>
|
||||
|
|
@ -151,7 +151,7 @@ l1and2, l1minus2 = cheat("UNIT_CELL) do
|
|||
end
|
||||
</pre>
|
||||
</p><p>
|
||||
(Technically, the check code block is a Ruby Proc and cannot create variables
|
||||
(Technically, the cheat code block is a Ruby Proc and cannot create variables
|
||||
outside it's scope. Hence the results of this code block have to be passed
|
||||
through the "cheat" method).
|
||||
</p><p>
|
||||
|
|
@ -234,7 +234,6 @@ See <a href="/about/drc_ref_netter.xml#connect_global">Netter#connect_global</a>
|
|||
<a name="connect_implicit"/><p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>connect_implicit(label_pattern)</tt></li>
|
||||
<li><tt>connect_implicit(cell_pattern, label_pattern)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
See <a href="/about/drc_ref_netter.xml#connect_implicit">Netter#connect_implicit</a> for a description of that function.
|
||||
|
|
@ -769,7 +768,7 @@ a new target will be set up.
|
|||
</p><p>
|
||||
<ul>
|
||||
<li>A string "@n" (n is an integer) specifying output to a layout in the current panel </li>
|
||||
<li>A string "@+" specifying output to a new layout in the current panel</li>
|
||||
<li>A string "@+" specifying output to a new layout in the current panel </li>
|
||||
<li>A layout filename </li>
|
||||
<li>A <class_doc href="Layout">Layout</class_doc> object </li>
|
||||
<li>A <class_doc href="Cell">Cell</class_doc> object </li>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
|
||||
|
||||
<!-- generated by /home/matthias/klayout/dvb/scripts/extract_doc.rb -->
|
||||
<!-- generated by /home/matthias/klayout/master/scripts/extract_doc.rb -->
|
||||
<!-- DO NOT EDIT! -->
|
||||
|
||||
<doc>
|
||||
|
|
@ -751,6 +751,19 @@ The following image shows the effect of the "interacting" method (input1: red, i
|
|||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<h2>"intersections" - Returns the intersection points of intersecting edge segments for two edge collections</h2>
|
||||
<keyword name="intersections"/>
|
||||
<a name="intersections"/><p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.intersections(edges)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This operation is similar to the "&" operator, but it does also report intersection points
|
||||
between non-colinear, but intersection edges. Such points are reported as point-like,
|
||||
degenerated edge objects.
|
||||
</p><p>
|
||||
This method is available for edge layers. The argument must be an edge layer.
|
||||
</p>
|
||||
<h2>"is_box?" - Returns true, if the region contains a single box</h2>
|
||||
<keyword name="is_box?"/>
|
||||
<a name="is_box?"/><p>Usage:</p>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
|
||||
|
||||
<!-- generated by /home/matthias/klayout/dvb/scripts/extract_doc.rb -->
|
||||
<!-- generated by /home/matthias/klayout/master/scripts/extract_doc.rb -->
|
||||
<!-- DO NOT EDIT! -->
|
||||
|
||||
<doc>
|
||||
|
|
@ -187,17 +187,17 @@ to shapes belonging to tie-down diodes.
|
|||
<li><tt>connect_implicit(cell_pattern, label_pattern)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
Use the first version of this method to supply label strings which create implicit net connections
|
||||
on the top level circuit. This feature is useful to connect identically labelled nets
|
||||
Use this method to supply label strings which create implicit net connections
|
||||
on the top level circuit in the first version. This feature is useful to connect identically labelled nets
|
||||
while a component isn't integrated yet. If the component is integrated, nets may be connected
|
||||
on a higher hierarchy level - e.g. by a power mesh. Inside the component this net consists
|
||||
of individual islands. To properly perform netlist extraction and comparison, these islands
|
||||
need to be connected even though there isn't a physical connection. "connect_implicit" can
|
||||
achieve this if these islands are labelled with the same text on the top level of the
|
||||
achive this if these islands are labelled with the same text on the top level of the
|
||||
component.
|
||||
</p><p>
|
||||
In the second version, the pattern can be specified for a cell range (given by a cell glob-style
|
||||
name pattern or a single cell name). These pattern are applied to non-top cells. An unspecific pattern
|
||||
In the second version, the pattern can be specified for a cell range (given by a cell name pattern or a
|
||||
single cell name). These pattern are applied to non-top cells. The unspecific pattern
|
||||
has priority over the cell-specific ones. As the cell selector is a pattern itself, a
|
||||
single cell may fall into more than one category. In this case, the label filters are
|
||||
combined.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
|
||||
|
||||
<!-- generated by /home/matthias/klayout/dvb/scripts/extract_doc.rb -->
|
||||
<!-- generated by /home/matthias/klayout/master/scripts/extract_doc.rb -->
|
||||
<!-- DO NOT EDIT! -->
|
||||
|
||||
<doc>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
|
||||
|
||||
<!-- generated by /home/matthias/klayout/dvb/scripts/extract_doc.rb -->
|
||||
<!-- generated by /home/matthias/klayout/master/scripts/extract_doc.rb -->
|
||||
<!-- DO NOT EDIT! -->
|
||||
|
||||
<doc>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
|
||||
|
||||
<!-- generated by /home/matthias/klayout/dvb/scripts/extract_doc.rb -->
|
||||
<!-- generated by /home/matthias/klayout/master/scripts/extract_doc.rb -->
|
||||
<!-- DO NOT EDIT! -->
|
||||
|
||||
<doc>
|
||||
|
|
@ -46,6 +46,15 @@ See <a href="/about/lvs_ref_netter.xml#compare">Netter#compare</a> for a descrip
|
|||
<p>
|
||||
See <a href="/about/lvs_ref_netter.xml#equivalent_pins">Netter#equivalent_pins</a> for a description of that function.
|
||||
</p>
|
||||
<h2>"join_symmetric_nets" - Joins symmetric nets of selected circuits on the extracted netlist</h2>
|
||||
<keyword name="join_symmetric_nets"/>
|
||||
<a name="join_symmetric_nets"/><p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>join_symmetric_nets(circuit_filter)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
See <a href="/about/lvs_ref_netter.xml#join_symmetric_nets">Netter#join_symmetric_nets</a> for a description of that function.
|
||||
</p>
|
||||
<h2>"max_branch_complexity" - Configures the maximum branch complexity for ambiguous net matching</h2>
|
||||
<keyword name="max_branch_complexity"/>
|
||||
<a name="max_branch_complexity"/><p>Usage:</p>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
|
||||
|
||||
<!-- generated by /home/matthias/klayout/dvb/scripts/extract_doc.rb -->
|
||||
<!-- generated by /home/matthias/klayout/master/scripts/extract_doc.rb -->
|
||||
<!-- DO NOT EDIT! -->
|
||||
|
||||
<doc>
|
||||
|
|
@ -110,6 +110,29 @@ If the netlist provides named pins, names can be used instead of numbers.
|
|||
Before this method can be used, a schematic netlist needs to be loaded with
|
||||
<a href="#schematic">schematic</a>.
|
||||
</p>
|
||||
<h2>"join_symmetric_nets" - Joins symmetric nets of selected circuits on the extracted netlist</h2>
|
||||
<keyword name="join_symmetric_nets"/>
|
||||
<a name="join_symmetric_nets"/><p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>join_symmetric_nets(circuit_filter)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
Nets are symmetrical if swapping them would not modify the circuit.
|
||||
Hence they will carry the same potential and can be connected (joined).
|
||||
This will simplify the circuit and can be applied before device combination
|
||||
(e.g. through "netlist.simplify") to render a schematic-equivalent netlist in some
|
||||
cases where symmetric nodes are split (i.e. "split gate" configuration).
|
||||
</p><p>
|
||||
This method operates on the extracted netlist (layout). The circuit filter
|
||||
specifies the circuits to which to apply this operation. The filter is a
|
||||
glob-style pattern. Using "*" for all circuits is possible, but it's
|
||||
discouraged currenty until the reliability of the symmetry detection
|
||||
algorithm is established. Currently it is recommended to apply it only to
|
||||
those circuits for which this feature is required.
|
||||
</p><p>
|
||||
For the symmetry detection, the specified constraints (e.g. tolerances,
|
||||
device filters etc.) apply.
|
||||
</p>
|
||||
<h2>"lvs_data" - Gets the internal <class_doc href="LayoutVsSchematic">LayoutVsSchematic</class_doc> object</h2>
|
||||
<keyword name="lvs_data"/>
|
||||
<a name="lvs_data"/><p>Usage:</p>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 5.0 KiB |