This commit is contained in:
Matthias Koefferlein 2023-09-22 23:35:09 +02:00
parent e56cdaeaab
commit 4f3522961e
1 changed files with 267 additions and 175 deletions

View File

@ -3359,91 +3359,86 @@ TEST(13_JoinNetNames)
db::compare_layouts (_this, ly, au); db::compare_layouts (_this, ly, au);
} }
namespace
TEST(14_JoinNets)
{ {
db::Layout ly;
db::LayerMap lmap;
unsigned int nwell = define_layer (ly, lmap, 1);
unsigned int nwell_lbl = define_layer (ly, lmap, 1, 1);
unsigned int active = define_layer (ly, lmap, 2);
unsigned int pplus = define_layer (ly, lmap, 10);
unsigned int nplus = define_layer (ly, lmap, 11);
unsigned int poly = define_layer (ly, lmap, 3);
unsigned int poly_lbl = define_layer (ly, lmap, 3, 1);
unsigned int diff_cont = define_layer (ly, lmap, 4);
unsigned int poly_cont = define_layer (ly, lmap, 5);
unsigned int metal1 = define_layer (ly, lmap, 6);
unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1);
unsigned int via1 = define_layer (ly, lmap, 7);
unsigned int metal2 = define_layer (ly, lmap, 8);
unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1);
class TestRig
{ {
db::LoadLayoutOptions options; public:
options.get_options<db::CommonReaderOptions> ().layer_map = lmap; TestRig (db::Layout &ly)
options.get_options<db::CommonReaderOptions> ().create_other_layers = false; : m_ly (ly)
{
std::string fn (tl::testdata ()); nwell = define_layer (m_ly, m_lmap, 1);
fn = tl::combine_path (fn, "algo"); nwell_lbl = define_layer (m_ly, m_lmap, 1, 1);
fn = tl::combine_path (fn, "device_extract_l14.gds"); active = define_layer (m_ly, m_lmap, 2);
pplus = define_layer (m_ly, m_lmap, 10);
tl::InputStream stream (fn); nplus = define_layer (m_ly, m_lmap, 11);
db::Reader reader (stream); poly = define_layer (m_ly, m_lmap, 3);
reader.read (ly, options); poly_lbl = define_layer (m_ly, m_lmap, 3, 1);
diff_cont = define_layer (m_ly, m_lmap, 4);
poly_cont = define_layer (m_ly, m_lmap, 5);
metal1 = define_layer (m_ly, m_lmap, 6);
metal1_lbl = define_layer (m_ly, m_lmap, 6, 1);
via1 = define_layer (m_ly, m_lmap, 7);
metal2 = define_layer (m_ly, m_lmap, 8);
metal2_lbl = define_layer (m_ly, m_lmap, 8, 1);
} }
db::Cell &tc = ly.cell (*ly.begin_top_down ()); db::LayoutToNetlist *
db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set<unsigned int> ())); make_l2n ()
{
db::Cell &tc = m_ly.cell (*m_ly.begin_top_down ());
std::unique_ptr<db::Region> rbulk (l2n.make_layer ("bulk")); std::unique_ptr<db::LayoutToNetlist> l2n_p (new db::LayoutToNetlist (db::RecursiveShapeIterator (m_ly, tc, std::set<unsigned int> ())));
std::unique_ptr<db::Region> rnwell (l2n.make_layer (nwell, "nwell")); db::LayoutToNetlist &l2n = *l2n_p;
std::unique_ptr<db::Region> rnwell_lbl (l2n.make_layer (nwell_lbl, "nwell_lbl"));
std::unique_ptr<db::Region> ractive (l2n.make_layer (active, "active")); rbulk.reset (l2n.make_layer ("bulk"));
std::unique_ptr<db::Region> rpplus (l2n.make_layer (pplus, "pplus")); rnwell.reset (l2n.make_layer (nwell, "nwell"));
std::unique_ptr<db::Region> rnplus (l2n.make_layer (nplus, "nplus")); rnwell_lbl.reset (l2n.make_layer (nwell_lbl, "nwell_lbl"));
std::unique_ptr<db::Region> rpoly (l2n.make_polygon_layer (poly, "poly")); ractive.reset (l2n.make_layer (active, "active"));
std::unique_ptr<db::Texts> rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); rpplus.reset (l2n.make_layer (pplus, "pplus"));
std::unique_ptr<db::Region> rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); rnplus.reset (l2n.make_layer (nplus, "nplus"));
std::unique_ptr<db::Region> rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont")); rpoly.reset (l2n.make_polygon_layer (poly, "poly"));
std::unique_ptr<db::Region> rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); rpoly_lbl.reset (l2n.make_text_layer (poly_lbl, "poly_lbl"));
std::unique_ptr<db::Texts> rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); rdiff_cont.reset (l2n.make_polygon_layer (diff_cont, "diff_cont"));
std::unique_ptr<db::Region> rvia1 (l2n.make_polygon_layer (via1, "via1")); rpoly_cont.reset (l2n.make_polygon_layer (poly_cont, "poly_cont"));
std::unique_ptr<db::Region> rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); rmetal1.reset (l2n.make_polygon_layer (metal1, "metal1"));
std::unique_ptr<db::Texts> rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); rmetal1_lbl.reset (l2n.make_text_layer (metal1_lbl, "metal1_lbl"));
rvia1.reset (l2n.make_polygon_layer (via1, "via1"));
rmetal2.reset (l2n.make_polygon_layer (metal2, "metal2"));
rmetal2_lbl.reset (l2n.make_text_layer (metal2_lbl, "metal2_lbl"));
// derived regions // derived regions
db::Region ractive_in_nwell = *ractive & *rnwell; ractive_in_nwell = *ractive & *rnwell;
db::Region rpactive = ractive_in_nwell & *rpplus; rpactive = ractive_in_nwell & *rpplus;
db::Region rntie = ractive_in_nwell & *rnplus; rntie = ractive_in_nwell & *rnplus;
db::Region rpgate = rpactive & *rpoly; rpgate = rpactive & *rpoly;
db::Region rpsd = rpactive - rpgate; rpsd = rpactive - rpgate;
db::Region ractive_outside_nwell = *ractive - *rnwell; ractive_outside_nwell = *ractive - *rnwell;
db::Region rnactive = ractive_outside_nwell & *rnplus; rnactive = ractive_outside_nwell & *rnplus;
db::Region rptie = ractive_outside_nwell & *rpplus; rptie = ractive_outside_nwell & *rpplus;
db::Region rngate = rnactive & *rpoly; rngate = rnactive & *rpoly;
db::Region rnsd = rnactive - rngate; rnsd = rnactive - rngate;
// return the computed layers into the original layout and write it for debugging purposes // 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 lgate = m_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 lsd = m_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 lpdiff = m_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 lndiff = m_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 lptie = m_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 unsigned int lntie = m_ly.insert_layer (db::LayerProperties (25, 0)); // 25/0 -> N Tie
rpgate.insert_into (&ly, tc.cell_index (), lgate); rpgate.insert_into (&m_ly, tc.cell_index (), lgate);
rngate.insert_into (&ly, tc.cell_index (), lgate); rngate.insert_into (&m_ly, tc.cell_index (), lgate);
rpsd.insert_into (&ly, tc.cell_index (), lsd); rpsd.insert_into (&m_ly, tc.cell_index (), lsd);
rnsd.insert_into (&ly, tc.cell_index (), lsd); rnsd.insert_into (&m_ly, tc.cell_index (), lsd);
rpsd.insert_into (&ly, tc.cell_index (), lpdiff); rpsd.insert_into (&m_ly, tc.cell_index (), lpdiff);
rnsd.insert_into (&ly, tc.cell_index (), lndiff); rnsd.insert_into (&m_ly, tc.cell_index (), lndiff);
rpsd.insert_into (&ly, tc.cell_index (), lptie); rpsd.insert_into (&m_ly, tc.cell_index (), lptie);
rnsd.insert_into (&ly, tc.cell_index (), lntie); rnsd.insert_into (&m_ly, tc.cell_index (), lntie);
db::NetlistDeviceExtractorMOS4Transistor pmos_ex ("PMOS"); db::NetlistDeviceExtractorMOS4Transistor pmos_ex ("PMOS");
db::NetlistDeviceExtractorMOS4Transistor nmos_ex ("NMOS"); db::NetlistDeviceExtractorMOS4Transistor nmos_ex ("NMOS");
@ -3503,23 +3498,11 @@ TEST(14_JoinNets)
l2n.connect_global (*rbulk, "BULK"); l2n.connect_global (*rbulk, "BULK");
l2n.connect_global (rptie, "BULK"); l2n.connect_global (rptie, "BULK");
// Extract while joining VSS with BULK and VDD with NWELL return l2n_p.release ();
std::set<std::string> jn; }
jn.insert ("VDD");
jn.insert ("NWELL");
l2n.join_nets (tl::GlobPattern ("INV2"), jn);
jn.clear ();
jn.insert ("VSS");
jn.insert ("BULK");
l2n.join_nets (tl::GlobPattern ("INV2"), jn);
// This will trigger an implicit connection on top level (side effect of explicit connections)
jn.clear ();
jn.insert ("VDD");
l2n.join_nets (jn);
l2n.extract_netlist ();
void dump_nets (db::LayoutToNetlist &l2n)
{
// debug layers produced for nets // debug layers produced for nets
// 201/0 -> Well // 201/0 -> Well
// 203/0 -> Poly // 203/0 -> Poly
@ -3533,42 +3516,151 @@ TEST(14_JoinNets)
// 212/0 -> N tie // 212/0 -> N tie
// 213/0 -> P tie // 213/0 -> P tie
std::map<const db::Region *, unsigned int> dump_map; std::map<const db::Region *, unsigned int> dump_map;
dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (210, 0)); dump_map [&rpsd ] = m_ly.insert_layer (db::LayerProperties (210, 0));
dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (211, 0)); dump_map [&rnsd ] = m_ly.insert_layer (db::LayerProperties (211, 0));
dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (212, 0)); dump_map [&rptie ] = m_ly.insert_layer (db::LayerProperties (212, 0));
dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (213, 0)); dump_map [&rntie ] = m_ly.insert_layer (db::LayerProperties (213, 0));
dump_map [rbulk.get () ] = ly.insert_layer (db::LayerProperties (214, 0)); dump_map [rbulk.get () ] = m_ly.insert_layer (db::LayerProperties (214, 0));
dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (201, 0)); dump_map [rnwell.get () ] = m_ly.insert_layer (db::LayerProperties (201, 0));
dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (203, 0)); dump_map [rpoly.get () ] = m_ly.insert_layer (db::LayerProperties (203, 0));
dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (204, 0)); dump_map [rdiff_cont.get ()] = m_ly.insert_layer (db::LayerProperties (204, 0));
dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (205, 0)); dump_map [rpoly_cont.get ()] = m_ly.insert_layer (db::LayerProperties (205, 0));
dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (206, 0)); dump_map [rmetal1.get () ] = m_ly.insert_layer (db::LayerProperties (206, 0));
dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (207, 0)); dump_map [rvia1.get () ] = m_ly.insert_layer (db::LayerProperties (207, 0));
dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (208, 0)); dump_map [rmetal2.get () ] = m_ly.insert_layer (db::LayerProperties (208, 0));
// write nets to layout // write nets to layout
db::CellMapping cm = l2n.cell_mapping_into (ly, tc); db::Cell &tc = m_ly.cell (*m_ly.begin_top_down ());
dump_nets_to_layout (l2n, ly, dump_map, cm); db::CellMapping cm = l2n.cell_mapping_into (m_ly, tc);
dump_nets_to_layout (l2n, m_ly, dump_map, cm);
}
dump_map.clear (); void dump_nets_recursive (db::LayoutToNetlist &l2n)
dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (310, 0)); {
dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (311, 0)); // debug layers produced for nets
dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (312, 0)); // 301/0 -> Well
dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (313, 0)); // 303/0 -> Poly
dump_map [rbulk.get () ] = ly.insert_layer (db::LayerProperties (314, 0)); // 304/0 -> Diffusion contacts
dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (301, 0)); // 305/0 -> Poly contacts
dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (303, 0)); // 306/0 -> Metal1
dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (304, 0)); // 307/0 -> Via1
dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (305, 0)); // 308/0 -> Metal2
dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (306, 0)); // 310/0 -> N source/drain
dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (307, 0)); // 311/0 -> P source/drain
dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (308, 0)); // 312/0 -> N tie
// 313/0 -> P tie
std::map<const db::Region *, unsigned int> dump_map;
dump_map [&rpsd ] = m_ly.insert_layer (db::LayerProperties (310, 0));
dump_map [&rnsd ] = m_ly.insert_layer (db::LayerProperties (311, 0));
dump_map [&rptie ] = m_ly.insert_layer (db::LayerProperties (312, 0));
dump_map [&rntie ] = m_ly.insert_layer (db::LayerProperties (313, 0));
dump_map [rbulk.get () ] = m_ly.insert_layer (db::LayerProperties (314, 0));
dump_map [rnwell.get () ] = m_ly.insert_layer (db::LayerProperties (301, 0));
dump_map [rpoly.get () ] = m_ly.insert_layer (db::LayerProperties (303, 0));
dump_map [rdiff_cont.get ()] = m_ly.insert_layer (db::LayerProperties (304, 0));
dump_map [rpoly_cont.get ()] = m_ly.insert_layer (db::LayerProperties (305, 0));
dump_map [rmetal1.get () ] = m_ly.insert_layer (db::LayerProperties (306, 0));
dump_map [rvia1.get () ] = m_ly.insert_layer (db::LayerProperties (307, 0));
dump_map [rmetal2.get () ] = m_ly.insert_layer (db::LayerProperties (308, 0));
dump_recursive_nets_to_layout (l2n, ly, dump_map, cm); // write nets to layout
db::Cell &tc = m_ly.cell (*m_ly.begin_top_down ());
db::CellMapping cm = l2n.cell_mapping_into (m_ly, tc);
dump_recursive_nets_to_layout (l2n, m_ly, dump_map, cm);
}
const db::LayerMap &lmap () const { return m_lmap; }
private:
db::Layout &m_ly;
db::LayerMap m_lmap;
unsigned int nwell;
unsigned int nwell_lbl;
unsigned int active;
unsigned int pplus;
unsigned int nplus;
unsigned int poly;
unsigned int poly_lbl;
unsigned int diff_cont;
unsigned int poly_cont;
unsigned int metal1;
unsigned int metal1_lbl;
unsigned int via1;
unsigned int metal2;
unsigned int metal2_lbl;
std::unique_ptr<db::Region> rbulk;
std::unique_ptr<db::Region> rnwell;
std::unique_ptr<db::Region> rnwell_lbl;
std::unique_ptr<db::Region> ractive;
std::unique_ptr<db::Region> rpplus;
std::unique_ptr<db::Region> rnplus;
std::unique_ptr<db::Region> rpoly;
std::unique_ptr<db::Texts> rpoly_lbl;
std::unique_ptr<db::Region> rdiff_cont;
std::unique_ptr<db::Region> rpoly_cont;
std::unique_ptr<db::Region> rmetal1;
std::unique_ptr<db::Texts> rmetal1_lbl;
std::unique_ptr<db::Region> rvia1;
std::unique_ptr<db::Region> rmetal2;
std::unique_ptr<db::Texts> rmetal2_lbl;
db::Region ractive_in_nwell;
db::Region rpactive;
db::Region rntie;
db::Region rpgate;
db::Region rpsd;
db::Region ractive_outside_nwell;
db::Region rnactive;
db::Region rptie;
db::Region rngate;
db::Region rnsd;
};
}
TEST(14_JoinNets)
{
db::Layout ly;
TestRig test_rig (ly);
{
db::LoadLayoutOptions options;
options.get_options<db::CommonReaderOptions> ().layer_map = test_rig.lmap ();
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
std::string fn (tl::testdata ());
fn = tl::combine_path (fn, "algo");
fn = tl::combine_path (fn, "device_extract_l14.gds");
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly, options);
}
std::unique_ptr<db::LayoutToNetlist> l2n (test_rig.make_l2n ());
// Extract while joining VSS with BULK and VDD with NWELL
std::set<std::string> jn;
jn.insert ("VDD");
jn.insert ("NWELL");
l2n->join_nets (tl::GlobPattern ("INV2"), jn);
jn.clear ();
jn.insert ("VSS");
jn.insert ("BULK");
l2n->join_nets (tl::GlobPattern ("INV2"), jn);
// This will trigger an implicit connection on top level (side effect of explicit connections)
jn.clear ();
jn.insert ("VDD");
l2n->join_nets (jn);
l2n->extract_netlist ();
test_rig.dump_nets (*l2n);
test_rig.dump_nets_recursive (*l2n);
// compare netlist as string // compare netlist as string
CHECKPOINT (); CHECKPOINT ();
db::compare_netlist (_this, *l2n.netlist (), db::compare_netlist (_this, *l2n->netlist (),
"circuit RINGO ();\n" "circuit RINGO ();\n"
" subcircuit INV2 $1 ('NWELL,VDD'=VDD,IN=$I15,$3=FB,OUT=OSC,VSS=VSS);\n" " subcircuit INV2 $1 ('NWELL,VDD'=VDD,IN=$I15,$3=FB,OUT=OSC,VSS=VSS);\n"
" subcircuit INV2 $2 ('NWELL,VDD'=VDD,IN=FB,$3=$I26,OUT=$I25,VSS=VSS);\n" " subcircuit INV2 $2 ('NWELL,VDD'=VDD,IN=FB,$3=$I26,OUT=$I25,VSS=VSS);\n"