mirror of https://github.com/KLayout/klayout.git
Resolved conflicts for issue-419 merge
This commit is contained in:
commit
2757b22da6
|
|
@ -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 ();
|
||||
|
|
@ -2410,3 +2418,158 @@ TEST(11_DeviceExtractionWithSameClass)
|
|||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, nl, nl_au_string_post);
|
||||
}
|
||||
|
||||
TEST(12_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