Fixed #648 (join_nets should work on global nets too) (#655)

This commit is contained in:
Matthias Köfferlein 2020-10-10 23:15:36 +02:00 committed by GitHub
parent 2f0fa28e58
commit 52f54ab39e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 329 additions and 32 deletions

View File

@ -799,10 +799,18 @@ struct cluster_building_receiver
typedef std::set<size_t> global_nets;
typedef std::pair<shape_vector, global_nets> cluster_value;
cluster_building_receiver (const db::Connectivity &conn)
: mp_conn (&conn)
cluster_building_receiver (const db::Connectivity &conn, const tl::equivalence_clusters<size_t> *attr_equivalence)
: mp_conn (&conn), mp_attr_equivalence (attr_equivalence)
{
// .. nothing yet..
if (mp_attr_equivalence) {
// cache the global nets per attribute equivalence cluster
for (size_t gid = 0; gid < conn.global_nets (); ++gid) {
tl::equivalence_clusters<size_t>::cluster_id_type cl = attr_equivalence->cluster_id (global_net_id_to_attr (gid));
if (cl > 0) {
m_global_nets_by_attribute_cluster [cl].insert (gid);
}
}
}
}
void generate_clusters (local_clusters<T> &clusters)
@ -817,7 +825,32 @@ struct cluster_building_receiver
cluster->add_attr (s->second.second);
}
cluster->set_global_nets (c->second);
std::set<size_t> global_nets = c->second;
// Add the global nets we derive from the attribute equivalence (join_nets of labelled vs.
// global nets)
if (mp_attr_equivalence) {
for (typename shape_vector::const_iterator s = c->first.begin (); s != c->first.end (); ++s) {
size_t a = s->second.second;
if (a == 0) {
continue;
}
tl::equivalence_clusters<size_t>::cluster_id_type cl = mp_attr_equivalence->cluster_id (a);
if (cl > 0) {
std::map<size_t, std::set<size_t> >::const_iterator gn = m_global_nets_by_attribute_cluster.find (cl);
if (gn != m_global_nets_by_attribute_cluster.end ()) {
global_nets.insert (gn->second.begin (), gn->second.end ());
}
}
}
}
cluster->set_global_nets (global_nets);
}
}
@ -913,6 +946,8 @@ private:
std::map<const T *, typename std::list<cluster_value>::iterator> m_shape_to_clusters;
std::map<size_t, typename std::list<cluster_value>::iterator> m_global_to_clusters;
std::list<cluster_value> m_clusters;
std::map<size_t, std::set<size_t> > m_global_nets_by_attribute_cluster;
const tl::equivalence_clusters<size_t> *mp_attr_equivalence;
void join (typename std::list<cluster_value>::iterator ic1, typename std::list<cluster_value>::iterator ic2)
{
@ -1035,7 +1070,7 @@ local_clusters<T>::build_clusters (const db::Cell &cell, const db::Connectivity
}
}
cluster_building_receiver<T, box_type> rec (conn);
cluster_building_receiver<T, box_type> rec (conn, attr_equivalence);
bs.process (rec, 1 /*==touching*/, bc);
rec.generate_clusters (*this);
@ -1048,36 +1083,27 @@ template <class T>
void
local_clusters<T>::apply_attr_equivalences (const tl::equivalence_clusters<size_t> &attr_equivalence)
{
tl::equivalence_clusters<size_t> eq;
// collect all local attributes (the ones which are present in attr_equivalence) into "eq"
// and form equivalences for multi-attribute clusters.
for (const_iterator c = begin (); c != end (); ++c) {
typename local_cluster<T>::attr_iterator a0;
for (typename local_cluster<T>::attr_iterator a = c->begin_attr (); a != c->end_attr (); ++a) {
if (attr_equivalence.has_attribute (*a)) {
if (a0 == typename local_cluster<T>::attr_iterator ()) {
a0 = a;
}
eq.same (*a0, *a);
}
}
}
// apply the equivalences implied by attr_equivalence
eq.apply_equivalences (attr_equivalence);
// identify the layout clusters joined into one attribute cluster and join them
std::map<tl::equivalence_clusters<size_t>::cluster_id_type, std::set<size_t> > c2c;
for (const_iterator c = begin (); c != end (); ++c) {
for (typename local_cluster<T>::attr_iterator a = c->begin_attr (); a != c->end_attr (); ++a) {
tl::equivalence_clusters<size_t>::cluster_id_type cl = attr_equivalence.cluster_id (*a);
if (cl > 0) {
c2c [cl].insert (c->id ());
}
}
for (typename local_cluster<T>::global_nets_iterator g = c->begin_global_nets (); g != c->end_global_nets (); ++g) {
size_t a = global_net_id_to_attr (*g);
tl::equivalence_clusters<size_t>::cluster_id_type cl = attr_equivalence.cluster_id (a);
if (cl > 0) {
c2c [cl].insert (c->id ());
}
}
}
for (std::map<tl::equivalence_clusters<size_t>::cluster_id_type, std::set<size_t> >::const_iterator c = c2c.begin (); c != c2c.end (); ++c) {

View File

@ -1396,11 +1396,11 @@ private:
/**
* @brief A helper function generating an attribute ID from a property ID
* This function is used to provide a generic attribute wrapping a property ID and a text ID.
* This function is used to provide a generic attribute wrapping a property ID, text ID and global net ID
*/
inline size_t prop_id_to_attr (db::properties_id_type id)
{
return size_t (id) * 2;
return size_t (id) * 4;
}
/**
@ -1408,7 +1408,7 @@ inline size_t prop_id_to_attr (db::properties_id_type id)
*/
inline bool is_prop_id_attr (size_t attr)
{
return (attr & 1) == 0;
return (attr & 3) == 0;
}
/**
@ -1416,7 +1416,32 @@ inline bool is_prop_id_attr (size_t attr)
*/
inline db::properties_id_type prop_id_from_attr (size_t attr)
{
return attr / 2;
return attr / 4;
}
/**
* @brief A helper function generating an attribute ID from a global net ID
* This function is used to provide a generic attribute wrapping a property ID, text ID and global net ID
*/
inline size_t global_net_id_to_attr (size_t id)
{
return size_t (id) * 4 + 2;
}
/**
* @brief Gets a value indicating whether the attribute is a global net ID
*/
inline bool is_global_net_id_attr (size_t attr)
{
return (attr & 3) == 2;
}
/**
* @brief Gets the global net ID from an attribute
*/
inline size_t global_net_id_from_attr (size_t attr)
{
return attr / 4;
}
/**
@ -1424,9 +1449,18 @@ inline db::properties_id_type prop_id_from_attr (size_t attr)
*/
inline size_t text_ref_to_attr (const db::Text *tr)
{
// NOTE: pointers are 32bit aligned, hence the lower two bits are 0
return size_t (tr) + 1;
}
/**
* @brief Gets a value indicating whether the attribute is a StringRef
*/
inline bool is_text_ref_attr (size_t attr)
{
return (attr & 3) == 1;
}
/**
* @brief Gets the text value from an attribute ID
*/

View File

@ -51,7 +51,7 @@ void NetlistExtractor::set_include_floating_subcircuits (bool 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<size_t> &eq)
build_net_name_equivalence (const db::Layout *layout, const db::Connectivity &conn, db::property_names_id_type net_name_id, const std::string &joined_net_names, tl::equivalence_clusters<size_t> &eq)
{
std::map<std::string, std::set<size_t> > prop_by_name;
tl::GlobPattern jn_pattern (joined_net_names);
@ -67,6 +67,14 @@ build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type
}
}
// include pseudo-attributes for global nets to implement "join_with" for global nets
for (size_t gid = 0; gid < conn.global_nets (); ++gid) {
const std::string &gn = conn.global_net_name (gid);
if (jn_pattern.match (gn)) {
prop_by_name [gn].insert (db::global_net_id_to_attr (gid));
}
}
const db::repository<db::Text> &text_repository = layout->shape_repository ().repository (db::object_tag<db::Text> ());
for (db::repository<db::Text>::iterator t = text_repository.begin (); t != text_repository.end (); ++t) {
std::string nn = t->string ();
@ -107,12 +115,12 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
std::map<db::cell_index_type, tl::equivalence_clusters<size_t> > net_name_equivalence;
if (m_text_annot_name_id.first) {
if (! m_joined_net_names.empty ()) {
build_net_name_equivalence (mp_layout, m_text_annot_name_id.second, m_joined_net_names, net_name_equivalence [hier_clusters_type::top_cell_index]);
build_net_name_equivalence (mp_layout, conn, m_text_annot_name_id.second, m_joined_net_names, net_name_equivalence [hier_clusters_type::top_cell_index]);
}
for (std::list<std::pair<std::string, std::string> >::const_iterator m = m_joined_net_names_per_cell.begin (); m != m_joined_net_names_per_cell.end (); ++m) {
std::pair<bool, db::cell_index_type> cp = mp_layout->cell_by_name (m->first.c_str ());
if (cp.first) {
build_net_name_equivalence (mp_layout, m_text_annot_name_id.second, m->second, net_name_equivalence [cp.second]);
build_net_name_equivalence (mp_layout, conn, m_text_annot_name_id.second, m->second, net_name_equivalence [cp.second]);
}
}
}
@ -313,7 +321,7 @@ void NetlistExtractor::collect_labels (const connected_clusters_type &clusters,
}
} else {
} else if (db::is_text_ref_attr (*a)) {
net_names.insert (db::text_from_attr (*a));

View File

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

Binary file not shown.

BIN
testdata/algo/device_extract_l13.gds vendored Normal file

Binary file not shown.