mirror of https://github.com/KLayout/klayout.git
Fixed issue #419 (multiple top circuits after flatten of netlist)
The problem is solved by always producing subcircuits for cell instances, even if there are no connections. The netlist comparer had to be adjusted too because subcircuits without pins were used for representing "unknown" subcircuit pairing. In addition, this patch should lead to a better matching of parallel subcircuit configurations where two different subcircuits are entirely parallel.
This commit is contained in:
parent
595075a88a
commit
6648b53822
|
|
@ -294,7 +294,7 @@ 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)
|
||||
void LayoutToNetlist::extract_netlist (const std::string &joined_net_names, bool include_floating_subcircuits)
|
||||
{
|
||||
if (m_netlist_extracted) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
||||
|
|
@ -302,7 +302,9 @@ void LayoutToNetlist::extract_netlist (const std::string &joined_net_names)
|
|||
ensure_netlist ();
|
||||
|
||||
db::NetlistExtractor netex;
|
||||
netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters, joined_net_names);
|
||||
netex.set_joined_net_names (joined_net_names);
|
||||
netex.set_include_floating_subcircuits (include_floating_subcircuits);
|
||||
netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters);
|
||||
|
||||
m_netlist_extracted = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -389,7 +389,7 @@ public:
|
|||
* @brief Runs the netlist extraction
|
||||
* See the class description for more details.
|
||||
*/
|
||||
void extract_netlist (const std::string &joined_net_names = std::string ());
|
||||
void extract_netlist (const std::string &joined_net_names = std::string (), bool include_floating_subcircuits = false);
|
||||
|
||||
/**
|
||||
* @brief Marks the netlist as extracted
|
||||
|
|
|
|||
|
|
@ -2624,18 +2624,15 @@ compute_device_key (const db::Device &device, const db::NetGraph &g, bool strict
|
|||
return k;
|
||||
}
|
||||
|
||||
static std::vector<std::pair<size_t, size_t> >
|
||||
compute_subcircuit_key (const db::SubCircuit &subcircuit, const db::NetGraph &g, const std::map<const db::Circuit *, CircuitMapper> *circuit_map, const CircuitPinMapper *pin_map)
|
||||
static bool
|
||||
compute_subcircuit_key (const db::SubCircuit &subcircuit, const db::NetGraph &g, const std::map<const db::Circuit *, CircuitMapper> *circuit_map, const CircuitPinMapper *pin_map, std::vector<std::pair<size_t, size_t> > &k)
|
||||
{
|
||||
std::vector<std::pair<size_t, size_t> > k;
|
||||
|
||||
const db::Circuit *cr = subcircuit.circuit_ref ();
|
||||
|
||||
std::map<const db::Circuit *, CircuitMapper>::const_iterator icm = circuit_map->find (cr);
|
||||
if (icm == circuit_map->end ()) {
|
||||
// this can happen if the other circuit does not exist - in this case the key is an invalid one which cannot
|
||||
// be produced by a regular subcircuit.
|
||||
return k;
|
||||
// this can happen if the other circuit does not exist - report invalid mapping.
|
||||
return false;
|
||||
}
|
||||
|
||||
const CircuitMapper *cm = & icm->second;
|
||||
|
|
@ -2660,7 +2657,7 @@ compute_subcircuit_key (const db::SubCircuit &subcircuit, const db::NetGraph &g,
|
|||
|
||||
std::sort (k.begin (), k.end ());
|
||||
|
||||
return k;
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
|
@ -3349,7 +3346,8 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG
|
|||
continue;
|
||||
}
|
||||
|
||||
std::vector<std::pair<size_t, size_t> > k = compute_subcircuit_key (*sc, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper);
|
||||
std::vector<std::pair<size_t, size_t> > k;
|
||||
bool valid = compute_subcircuit_key (*sc, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper, k);
|
||||
|
||||
bool mapped = true;
|
||||
for (std::vector<std::pair<size_t, size_t> >::iterator i = k.begin (); i != k.end () && mapped; ++i) {
|
||||
|
|
@ -3363,7 +3361,7 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG
|
|||
mp_logger->subcircuit_mismatch (sc.operator-> (), 0);
|
||||
}
|
||||
good = false;
|
||||
} else if (! k.empty ()) {
|
||||
} else if (valid) {
|
||||
// TODO: report devices which cannot be distiguished topologically?
|
||||
subcircuit_map.insert (std::make_pair (k, std::make_pair (sc.operator-> (), sc_cat)));
|
||||
}
|
||||
|
|
@ -3381,7 +3379,8 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG
|
|||
continue;
|
||||
}
|
||||
|
||||
std::vector<std::pair<size_t, size_t> > k = compute_subcircuit_key (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper);
|
||||
std::vector<std::pair<size_t, size_t> > k;
|
||||
compute_subcircuit_key (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper, k);
|
||||
|
||||
bool mapped = true;
|
||||
for (std::vector<std::pair<size_t, size_t> >::iterator i = k.begin (); i != k.end (); ++i) {
|
||||
|
|
@ -3407,18 +3406,50 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG
|
|||
|
||||
db::SubCircuitCompare scc;
|
||||
|
||||
if (! scc.equals (scm->second, std::make_pair (sc.operator-> (), sc_cat))) {
|
||||
if (mp_logger) {
|
||||
mp_logger->subcircuit_mismatch (scm->second.first, sc.operator-> ());
|
||||
}
|
||||
good = false;
|
||||
} else {
|
||||
if (mp_logger) {
|
||||
mp_logger->match_subcircuits (scm->second.first, sc.operator-> ());
|
||||
std::multimap<std::vector<std::pair<size_t, size_t> >, std::pair<const db::SubCircuit *, size_t> >::iterator scm_start = scm;
|
||||
|
||||
bool found = false;
|
||||
size_t nscm = 0;
|
||||
while (! found && scm != subcircuit_map.end () && scm->first == k) {
|
||||
++nscm;
|
||||
if (scc.equals (scm->second, std::make_pair (sc.operator-> (), sc_cat))) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
subcircuit_map.erase (scm);
|
||||
if (! found) {
|
||||
|
||||
if (nscm == 1) {
|
||||
|
||||
// unique match, but doesn't fit: report this one as paired, but mismatching:
|
||||
if (mp_logger) {
|
||||
mp_logger->subcircuit_mismatch (scm_start->second.first, sc.operator-> ());
|
||||
}
|
||||
|
||||
// no longer look for this one
|
||||
subcircuit_map.erase (scm_start);
|
||||
|
||||
} else {
|
||||
|
||||
// no unqiue match
|
||||
if (mp_logger) {
|
||||
mp_logger->subcircuit_mismatch (0, sc.operator-> ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
good = false;
|
||||
|
||||
} else {
|
||||
|
||||
if (mp_logger) {
|
||||
mp_logger->match_subcircuits (scm->second.first, sc.operator-> ());
|
||||
}
|
||||
|
||||
// no longer look for this one
|
||||
subcircuit_map.erase (scm);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,11 +29,21 @@ namespace db
|
|||
{
|
||||
|
||||
NetlistExtractor::NetlistExtractor ()
|
||||
: mp_clusters (0), mp_layout (0), mp_cell (0)
|
||||
: mp_clusters (0), mp_layout (0), mp_cell (0), m_include_floating_subcircuits (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void NetlistExtractor::set_joined_net_names (const std::string &jnn)
|
||||
{
|
||||
m_joined_net_names = jnn;
|
||||
}
|
||||
|
||||
void NetlistExtractor::set_include_floating_subcircuits (bool f)
|
||||
{
|
||||
m_include_floating_subcircuits = f;
|
||||
}
|
||||
|
||||
static void
|
||||
build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type net_name_id, const std::string &joined_net_names, tl::equivalence_clusters<unsigned int> &eq)
|
||||
{
|
||||
|
|
@ -62,7 +72,7 @@ build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type
|
|||
}
|
||||
|
||||
void
|
||||
NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layout_index, const db::Connectivity &conn, db::Netlist &nl, hier_clusters_type &clusters, const std::string &joined_net_names)
|
||||
NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layout_index, const db::Connectivity &conn, db::Netlist &nl, hier_clusters_type &clusters)
|
||||
{
|
||||
mp_clusters = &clusters;
|
||||
mp_layout = &dss.const_layout (layout_index);
|
||||
|
|
@ -81,8 +91,8 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
// the big part: actually extract the nets
|
||||
|
||||
tl::equivalence_clusters<unsigned int> net_name_equivalence;
|
||||
if (m_text_annot_name_id.first && ! joined_net_names.empty ()) {
|
||||
build_net_name_equivalence (mp_layout, m_text_annot_name_id.second, joined_net_names, net_name_equivalence);
|
||||
if (m_text_annot_name_id.first && ! m_joined_net_names.empty ()) {
|
||||
build_net_name_equivalence (mp_layout, m_text_annot_name_id.second, m_joined_net_names, net_name_equivalence);
|
||||
}
|
||||
mp_clusters->build (*mp_layout, *mp_cell, db::ShapeIterator::Polygons, conn, &net_name_equivalence);
|
||||
|
||||
|
|
@ -98,9 +108,25 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
std::map<db::cell_index_type, std::map<size_t, size_t> > pins_per_cluster_per_cell;
|
||||
for (db::Layout::bottom_up_const_iterator cid = mp_layout->begin_bottom_up (); cid != mp_layout->end_bottom_up (); ++cid) {
|
||||
|
||||
const db::Cell &cell = mp_layout->cell (*cid);
|
||||
|
||||
const connected_clusters_type &clusters = mp_clusters->clusters_per_cell (*cid);
|
||||
if (clusters.empty ()) {
|
||||
continue;
|
||||
|
||||
bool any_good = false;
|
||||
|
||||
// in case of "include floating subcircuits" check whether we have a child cell which has a circuit attached in this case
|
||||
if (include_floating_subcircuits ()) {
|
||||
for (db::Cell::child_cell_iterator cc = cell.begin_child_cells (); ! any_good && ! cc.at_end (); ++cc) {
|
||||
any_good = (circuits.find (*cc) != circuits.end ());
|
||||
}
|
||||
}
|
||||
|
||||
if (! any_good) {
|
||||
// skip this cell
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
db::DeviceAbstract *dm = nl.device_abstract_by_cell_index (*cid);
|
||||
|
|
@ -128,6 +154,16 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
|
||||
std::map<std::pair<db::cell_index_type, db::ICplxTrans>, db::SubCircuit *> subcircuits;
|
||||
|
||||
if (include_floating_subcircuits ()) {
|
||||
|
||||
// Make sure we create one subcircuit for each instance of cells which do have circuits
|
||||
// associated.
|
||||
for (db::Cell::const_iterator inst = cell.begin (); ! inst.at_end (); ++inst) {
|
||||
make_subcircuit (circuit, inst->cell_index (), inst->complex_trans (), subcircuits, circuits);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (connected_clusters_type::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) {
|
||||
|
||||
const db::local_cluster<db::PolygonRef> &lc = clusters.cluster_by_id (*c);
|
||||
|
|
@ -315,6 +351,39 @@ void NetlistExtractor::connect_devices (db::Circuit *circuit,
|
|||
}
|
||||
}
|
||||
|
||||
db::SubCircuit * NetlistExtractor::make_subcircuit (db::Circuit *circuit,
|
||||
db::cell_index_type inst_cell_index,
|
||||
const db::ICplxTrans &inst_trans,
|
||||
std::map<std::pair<db::cell_index_type, db::ICplxTrans>, db::SubCircuit *> &subcircuits,
|
||||
const std::map<db::cell_index_type, db::Circuit *> &circuits)
|
||||
{
|
||||
db::SubCircuit *subcircuit = 0;
|
||||
|
||||
std::pair<db::cell_index_type, db::ICplxTrans> subcircuit_key (inst_cell_index, inst_trans);
|
||||
|
||||
std::map<std::pair<db::cell_index_type, db::ICplxTrans>, db::SubCircuit *>::const_iterator j = subcircuits.find (subcircuit_key);
|
||||
if (j == subcircuits.end ()) {
|
||||
|
||||
// make subcircuit if required
|
||||
|
||||
std::map<db::cell_index_type, db::Circuit *>::const_iterator k = circuits.find (inst_cell_index);
|
||||
if (k == circuits.end ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
subcircuit = new db::SubCircuit (k->second);
|
||||
db::CplxTrans dbu_trans (mp_layout->dbu ());
|
||||
subcircuit->set_trans (dbu_trans * inst_trans * dbu_trans.inverted ());
|
||||
circuit->add_subcircuit (subcircuit);
|
||||
subcircuits.insert (std::make_pair (subcircuit_key, subcircuit));
|
||||
|
||||
} else {
|
||||
subcircuit = j->second;
|
||||
}
|
||||
|
||||
return subcircuit;
|
||||
}
|
||||
|
||||
void NetlistExtractor::make_and_connect_subcircuits (db::Circuit *circuit,
|
||||
const connected_clusters_type &clusters,
|
||||
size_t cid,
|
||||
|
|
@ -335,27 +404,8 @@ void NetlistExtractor::make_and_connect_subcircuits (db::Circuit *circuit,
|
|||
continue;
|
||||
}
|
||||
|
||||
db::SubCircuit *subcircuit = 0;
|
||||
|
||||
std::pair<db::cell_index_type, db::ICplxTrans> subcircuit_key (inst_cell_index, inst_trans);
|
||||
|
||||
std::map<std::pair<db::cell_index_type, db::ICplxTrans>, db::SubCircuit *>::const_iterator j = subcircuits.find (subcircuit_key);
|
||||
if (j == subcircuits.end ()) {
|
||||
|
||||
// make subcircuit if required
|
||||
|
||||
std::map<db::cell_index_type, db::Circuit *>::const_iterator k = circuits.find (inst_cell_index);
|
||||
tl_assert (k != circuits.end ()); // because we walk bottom-up
|
||||
|
||||
subcircuit = new db::SubCircuit (k->second);
|
||||
db::CplxTrans dbu_trans (mp_layout->dbu ());
|
||||
subcircuit->set_trans (dbu_trans * inst_trans * dbu_trans.inverted ());
|
||||
circuit->add_subcircuit (subcircuit);
|
||||
subcircuits.insert (std::make_pair (subcircuit_key, subcircuit));
|
||||
|
||||
} else {
|
||||
subcircuit = j->second;
|
||||
}
|
||||
db::SubCircuit *subcircuit = make_subcircuit (circuit, inst_cell_index, inst_trans, subcircuits, circuits);
|
||||
tl_assert (subcircuit != 0);
|
||||
|
||||
// create the pin connection to the subcircuit
|
||||
std::map<db::cell_index_type, std::map<size_t, size_t> >::const_iterator icc2p = pins_per_cluster.find (inst_cell_index);
|
||||
|
|
|
|||
|
|
@ -80,11 +80,45 @@ public:
|
|||
*/
|
||||
NetlistExtractor ();
|
||||
|
||||
/**
|
||||
* @brief Sets a flag indicating whether floating circuits shall be included as subcircuits
|
||||
* If this attribute is set to true, disconnected subcircuits (such that do not have a pin)
|
||||
* are included per instance of a cell. Such subcircuits do not have a connection to their
|
||||
* parent circuit but reflect the hierarchy they are present it. This is useful when the
|
||||
* netlist is supposed to be flattened later, because then each subcircuit will render floating
|
||||
* nets in the parent circuit. With this flag set to false, floating circuits will always appear
|
||||
* as additional top cells.
|
||||
*/
|
||||
void set_include_floating_subcircuits (bool f);
|
||||
|
||||
/**
|
||||
* @brief Gets a flag indicating whether floating circuits shall be included as subcircuits
|
||||
*/
|
||||
bool include_floating_subcircuits () const
|
||||
{
|
||||
return m_include_floating_subcircuits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
void set_joined_net_names (const std::string &jnn);
|
||||
|
||||
/**
|
||||
* @brief Gets the joined net names expression
|
||||
*/
|
||||
const std::string &joined_net_names () const
|
||||
{
|
||||
return m_joined_net_names;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extract the nets
|
||||
* See the class description for more details.
|
||||
*/
|
||||
void extract_nets (const db::DeepShapeStore &dss, unsigned int layout_index, const db::Connectivity &conn, db::Netlist &nl, hier_clusters_type &clusters, const std::string &joined_net_names = std::string ());
|
||||
void extract_nets (const db::DeepShapeStore &dss, unsigned int layout_index, const db::Connectivity &conn, db::Netlist &nl, hier_clusters_type &clusters);
|
||||
|
||||
private:
|
||||
hier_clusters_type *mp_clusters;
|
||||
|
|
@ -93,6 +127,8 @@ 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;
|
||||
bool m_include_floating_subcircuits;
|
||||
|
||||
bool instance_is_device (db::properties_id_type prop_id) const;
|
||||
db::Device *device_from_instance (db::properties_id_type prop_id, db::Circuit *circuit) const;
|
||||
|
|
@ -106,6 +142,18 @@ private:
|
|||
*/
|
||||
size_t make_pin (db::Circuit *circuit, db::Net *net);
|
||||
|
||||
/**
|
||||
* @brief Makes a subcircuit for the given instance (by cell index and transformation)
|
||||
* This method maintains a subcircuit cache in "subcircuits" and will pull the subcircuit from there
|
||||
* if possible.
|
||||
* It returns the new or old subcircuit.
|
||||
*/
|
||||
db::SubCircuit *make_subcircuit (Circuit *circuit,
|
||||
db::cell_index_type inst_cell_index,
|
||||
const db::ICplxTrans &inst_trans,
|
||||
std::map<std::pair<db::cell_index_type, db::ICplxTrans>, db::SubCircuit *> &subcircuits,
|
||||
const std::map<db::cell_index_type, db::Circuit *> &circuits);
|
||||
|
||||
/**
|
||||
* @brief Turns the connections of a cluster into subcircuit instances
|
||||
*
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ 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::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 "
|
||||
|
|
@ -346,7 +346,14 @@ 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"
|
||||
"\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_ext ("internal_layout", &l2n_internal_layout,
|
||||
"@brief Gets the internal layout\n"
|
||||
|
|
|
|||
|
|
@ -741,16 +741,19 @@ TEST(3_DeviceAndNetExtractionWithImplicitConnections)
|
|||
// extract the nets
|
||||
|
||||
db::Netlist nl2 = nl;
|
||||
net_ex.extract_nets (dss, 0, conn, nl2, cl, "{VDDZ,VSSZ,NEXT,FB}");
|
||||
net_ex.set_joined_net_names ("{VDDZ,VSSZ,NEXT,FB}");
|
||||
net_ex.extract_nets (dss, 0, conn, nl2, cl);
|
||||
|
||||
EXPECT_EQ (all_net_names_unique (nl2), true);
|
||||
|
||||
nl2 = nl;
|
||||
net_ex.extract_nets (dss, 0, conn, nl2, cl, "{VDDZ,VSSZ,NEXT}");
|
||||
net_ex.set_joined_net_names ("{VDDZ,VSSZ,NEXT}");
|
||||
net_ex.extract_nets (dss, 0, conn, nl2, cl);
|
||||
|
||||
EXPECT_EQ (all_net_names_unique (nl2), false);
|
||||
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl, "*");
|
||||
net_ex.set_joined_net_names ("*");
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
||||
|
||||
EXPECT_EQ (all_net_names_unique (nl), true);
|
||||
|
||||
|
|
@ -1012,7 +1015,8 @@ TEST(4_ResAndCapExtraction)
|
|||
|
||||
// extract the nets
|
||||
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl, "*");
|
||||
net_ex.set_joined_net_names ("*");
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
||||
|
||||
// Flatten device circuits
|
||||
|
||||
|
|
@ -1285,7 +1289,8 @@ TEST(5_ResAndCapWithBulkExtraction)
|
|||
|
||||
// extract the nets
|
||||
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl, "*");
|
||||
net_ex.set_joined_net_names ("*");
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
||||
|
||||
// Flatten device circuits
|
||||
|
||||
|
|
@ -1526,7 +1531,8 @@ TEST(6_BJT3TransistorExtraction)
|
|||
|
||||
// extract the nets
|
||||
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl, "*");
|
||||
net_ex.set_joined_net_names ("*");
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
||||
|
||||
// Flatten device circuits
|
||||
|
||||
|
|
@ -1691,7 +1697,8 @@ TEST(7_DiodeExtraction)
|
|||
|
||||
// extract the nets
|
||||
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl, "*");
|
||||
net_ex.set_joined_net_names ("*");
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
||||
|
||||
// cleanup + completion
|
||||
nl.combine_devices ();
|
||||
|
|
@ -1823,7 +1830,8 @@ TEST(8_DiodeExtractionScaled)
|
|||
|
||||
// extract the nets
|
||||
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl, "*");
|
||||
net_ex.set_joined_net_names ("*");
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
||||
|
||||
// cleanup + completion
|
||||
nl.combine_devices ();
|
||||
|
|
@ -2303,3 +2311,158 @@ TEST(10_DeviceExtractionWithBreakoutCells)
|
|||
|
||||
db::compare_layouts (_this, ly, au);
|
||||
}
|
||||
|
||||
TEST(11_FloatingSubcircuitExtraction)
|
||||
{
|
||||
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_floating_subcircuits.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;
|
||||
|
||||
// perform the extraction
|
||||
|
||||
db::Netlist nl;
|
||||
db::hier_clusters<db::PolygonRef> cl;
|
||||
|
||||
db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS");
|
||||
db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS");
|
||||
|
||||
db::NetlistDeviceExtractor::input_layers dl;
|
||||
|
||||
dl["SD"] = &rpsd;
|
||||
dl["G"] = &rpgate;
|
||||
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["P"] = &rpoly; // not needed for extraction but to return terminal shapes
|
||||
nmos_ex.extract (dss, 0, dl, nl, cl);
|
||||
|
||||
// perform the net extraction
|
||||
|
||||
db::Connectivity conn;
|
||||
// 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
|
||||
|
||||
db::NetlistExtractor net_ex;
|
||||
net_ex.set_include_floating_subcircuits (true);
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
||||
|
||||
// compare netlist as string
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, nl,
|
||||
"circuit RINGO ();\n"
|
||||
" subcircuit INV2 $1 (IN=FB,$2=$I29,OUT=$I1,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $2 (IN=$I1,$2=$I30,OUT=$I2,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2X $3 ($1=VDD,$2=VSS,$3=$I25,$4=$I11);\n"
|
||||
" subcircuit TRANSISO $4 ();\n" // effect of "include floating subcircuits"!
|
||||
" subcircuit INV2 $5 (IN=$I9,$2=$I31,OUT=$I3,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $6 (IN=$I3,$2=$I32,OUT=$I25,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit TRANSISOB $7 ();\n" // effect of "include floating subcircuits"!
|
||||
" subcircuit INV2 $7 (IN=$I11,$2=$I33,OUT=$I5,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $8 (IN=$I5,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2X $9 ($1=VDD,$2=VSS,$3=$I2,$4=$I9);\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"
|
||||
" subcircuit TRANS $1 ($1=$2,$2=$4,$3=IN);\n"
|
||||
" subcircuit TRANS $2 ($1=$2,$2=$5,$3=IN);\n"
|
||||
" subcircuit TRANS $3 ($1=$4,$2=OUT,$3=$2);\n"
|
||||
" subcircuit TRANS $4 ($1=$5,$2=OUT,$3=$2);\n"
|
||||
"end;\n"
|
||||
"circuit TRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
"end;\n"
|
||||
"circuit INV2X ($1=$I4,$2=$I3,$3=$I2,$4=$I1);\n"
|
||||
" subcircuit INV2 $1 (IN=$I2,$2=$I6,OUT=$I5,$4=$I3,$5=$I4);\n"
|
||||
" subcircuit INV2 $2 (IN=$I5,$2=$I7,OUT=$I1,$4=$I3,$5=$I4);\n"
|
||||
" subcircuit TRANSISO $3 ();\n" // effect of "include floating subcircuits"!
|
||||
" subcircuit TRANSISO $4 ();\n" // effect of "include floating subcircuits"!
|
||||
" subcircuit TRANSISOB $5 ();\n" // effect of "include floating subcircuits"!
|
||||
"end;\n"
|
||||
"circuit TRANSISO ();\n"
|
||||
" device NMOS $1 (S=$1,G=$2,D=$1) (L=0.25,W=0.95,AS=0.49875,AD=0.49875,PS=2.95,PD=2.95);\n"
|
||||
"end;\n"
|
||||
"circuit TRANSISOB ();\n"
|
||||
" device NMOS $1 (S=$1,G=$2,D=$1) (L=0.25,W=0.95,AS=0.49875,AD=0.49875,PS=2.95,PD=2.95);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1669,7 +1669,7 @@ NetTracerDialog::trace_all_nets (db::LayoutToNetlist *l2ndb, const lay::CellView
|
|||
|
||||
tracer_data.configure_l2n (*l2ndb);
|
||||
|
||||
l2ndb->extract_netlist ();
|
||||
l2ndb->extract_netlist (std::string (), flat /*include floating subcircuits for netlist to flatten*/);
|
||||
|
||||
if (flat) {
|
||||
l2ndb->netlist ()->flatten ();
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue