From dbe5e19017cf7926d3471f2f8f04f9da0042400c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 25 Jul 2020 22:15:09 +0200 Subject: [PATCH] First implementation of masks for vias. Needs debugging. --- .../lefdef/db_plugin/dbDEFImporter.cc | 192 +++++--- .../lefdef/db_plugin/dbLEFDEFImporter.cc | 433 +++++++++++------- .../lefdef/db_plugin/dbLEFDEFImporter.h | 155 ++++++- .../lefdef/db_plugin/dbLEFImporter.cc | 178 ++++--- .../lefdef/db_plugin/dbLEFImporter.h | 16 +- 5 files changed, 670 insertions(+), 304 deletions(-) diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc index 51c4c3767..149bb8b05 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc @@ -517,13 +517,19 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C double x = 0.0, y = 0.0; unsigned int mask = 0; + bool read_mask = true; while (true) { - if (test ("MASK")) { - mask = get_mask (get_long ()); + if (read_mask) { + mask = 0; + if (test ("MASK")) { + mask = get_mask (get_long ()); + } } + read_mask = true; + if (test ("RECT")) { if (! test ("(")) { @@ -567,12 +573,18 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C while (peek ("(") || peek ("MASK")) { if (test ("MASK")) { - mask = get_mask (get_long ()); + unsigned int m = get_mask (get_long ()); + if (m != mask) { + // stop here with the segments and use the mask value for the next iteration + mask = m; + read_mask = false; + break; + } } if (! test ("(")) { - // We could have a via here: in that case we have swallowed MASK already, but - // since we don't do anything with that, this does not hurt for now. + // We have a via here. MASK is already read, but the value did not change. + read_mask = false; break; } @@ -632,16 +644,27 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C std::map::const_iterator vd = m_via_desc.find (vn); if (vd != m_via_desc.end () && ! pts.empty ()) { - if (nx <= 1 && ny <= 1) { - design.insert (db::CellInstArray (db::CellInst (vd->second.cell->cell_index ()), db::Trans (ft.rot (), db::Vector (pts.back ())))); - } else { - design.insert (db::CellInstArray (db::CellInst (vd->second.cell->cell_index ()), db::Trans (ft.rot (), db::Vector (pts.back ())), db::Vector (dx, 0), db::Vector (0, dy), (unsigned long) nx, (unsigned long) ny)); + + // For the via, the masks are encoded in a three-digit number ( ) + unsigned int mask_top = (mask / 100) % 10; + unsigned int mask_cut = (mask / 10) % 10; + unsigned int mask_bottom = mask % 10; + + db::Cell *cell = reader_state ()->via_cell (vn, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer); + if (cell) { + if (nx <= 1 && ny <= 1) { + design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (ft.rot (), db::Vector (pts.back ())))); + } else { + design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (ft.rot (), db::Vector (pts.back ())), db::Vector (dx, 0), db::Vector (0, dy), (unsigned long) nx, (unsigned long) ny)); + } } + if (ln == vd->second.m1) { ln = vd->second.m2; } else if (ln == vd->second.m2) { ln = vd->second.m1; } + } if (! specialnets) { @@ -799,7 +822,11 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool std::map::const_iterator vd = m_via_desc.find (vn); if (vd != m_via_desc.end ()) { - design.insert (db::CellInstArray (db::CellInst (vd->second.cell->cell_index ()), db::Trans (ft.rot (), pt))); + // TODO: no mask specification here? + db::Cell *cell = reader_state ()->via_cell (vn, layout, 0, 0, 0, &m_lef_importer); + if (cell) { + design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (ft.rot (), pt))); + } } else { error (tl::to_string (tr ("Invalid via name: ")) + vn); } @@ -844,7 +871,7 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool } void -DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale) +DEFImporter::read_vias (db::Layout & /*layout*/, db::Cell & /*design*/, double scale) { while (test ("-")) { @@ -852,100 +879,144 @@ DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale) ViaDesc &vd = m_via_desc.insert (std::make_pair (n, ViaDesc ())).first->second; // produce a cell for vias - std::string cellname = options ().via_cellname_prefix () + n; - db::Cell &cell = layout.cell (layout.add_cell (cellname.c_str ())); - reader_state ()->register_via_cell (n, &cell); - vd.cell = &cell; + std::auto_ptr rule_based_vg; + std::auto_ptr geo_based_vg; - bool has_via_rule = false; - - db::Vector cutsize, cutspacing; - db::Vector be, te; - db::Vector bo, to; - db::Point offset; - int rows = 1, columns = 1; - std::string pattern; unsigned int mask = 0; - std::map > geometry; - std::vector *top = 0, *cut = 0, *bottom = 0; + std::auto_ptr via_generator; + std::set seen_layers; + std::vector routing_layers; while (test ("+")) { if (test ("VIARULE")) { - has_via_rule = true; + if (! rule_based_vg.get ()) { + rule_based_vg.reset (new RuleBasedViaGenerator ()); + } + take (); } else if (test ("CUTSIZE")) { - cutsize = get_vector (scale); + if (! rule_based_vg.get ()) { + rule_based_vg.reset (new RuleBasedViaGenerator ()); + } + + rule_based_vg->set_cutsize (get_vector (scale)); } else if (test ("CUTSPACING")) { - cutspacing = get_vector (scale); + if (! rule_based_vg.get ()) { + rule_based_vg.reset (new RuleBasedViaGenerator ()); + } + + rule_based_vg->set_cutspacing (get_vector (scale)); } else if (test ("ORIGIN")) { - offset = get_point (scale); + if (! rule_based_vg.get ()) { + rule_based_vg.reset (new RuleBasedViaGenerator ()); + } + + rule_based_vg->set_offset (get_point (scale)); } else if (test ("ENCLOSURE")) { - be = get_vector (scale); - te = get_vector (scale); + if (! rule_based_vg.get ()) { + rule_based_vg.reset (new RuleBasedViaGenerator ()); + } + + rule_based_vg->set_be (get_vector (scale)); + rule_based_vg->set_te (get_vector (scale)); } else if (test ("OFFSET")) { - bo = get_vector (scale); - to = get_vector (scale); + if (! rule_based_vg.get ()) { + rule_based_vg.reset (new RuleBasedViaGenerator ()); + } + + rule_based_vg->set_bo (get_vector (scale)); + rule_based_vg->set_to (get_vector (scale)); } else if (test ("ROWCOL")) { - rows = get_long (); - columns = get_long (); + if (! rule_based_vg.get ()) { + rule_based_vg.reset (new RuleBasedViaGenerator ()); + } + + rule_based_vg->set_rows (get_long ()); + rule_based_vg->set_columns (get_long ()); } else if (test ("PATTERN")) { - pattern = get (); + if (! rule_based_vg.get ()) { + rule_based_vg.reset (new RuleBasedViaGenerator ()); + } + + rule_based_vg->set_pattern (get ()); } else if (test ("LAYERS")) { + if (! rule_based_vg.get ()) { + rule_based_vg.reset (new RuleBasedViaGenerator ()); + } + std::string bn = get (); std::string cn = get (); std::string tn = get (); - bottom = &geometry.insert (std::make_pair (bn, std::vector ())).first->second; - cut = &geometry.insert (std::make_pair (cn, std::vector ())).first->second; - top = &geometry.insert (std::make_pair (tn, std::vector ())).first->second; + rule_based_vg->set_bottom_layer (bn); + rule_based_vg->set_cut_layer (cn); + rule_based_vg->set_top_layer (tn); vd.m1 = bn; vd.m2 = tn; } else if (test ("POLYGON")) { + if (! geo_based_vg.get ()) { + geo_based_vg.reset (new GeometryBasedViaGenerator ()); + } + std::string ln = get (); + if (m_lef_importer.is_routing_layer (ln) && seen_layers.find (ln) != seen_layers.end ()) { + seen_layers.insert (ln); + routing_layers.push_back (ln); + } + if (test ("+")) { expect ("MASK"); mask = get_mask (get_long ()); } - std::vector &polygons = geometry.insert (std::make_pair (ln, std::vector ())).first->second; - polygons.push_back (db::Polygon ()); - read_polygon (polygons.back (), scale); + db::Polygon poly; + read_polygon (poly, scale); + geo_based_vg->add_polygon (ln, poly, mask); } else if (test ("RECT")) { + if (! geo_based_vg.get ()) { + geo_based_vg.reset (new GeometryBasedViaGenerator ()); + } + std::string ln = get (); + if (m_lef_importer.is_routing_layer (ln) && seen_layers.find (ln) != seen_layers.end ()) { + seen_layers.insert (ln); + routing_layers.push_back (ln); + } + if (test ("+")) { expect ("MASK"); mask = get_mask (get_long ()); } - std::vector &polygons = geometry.insert (std::make_pair (ln, std::vector ())).first->second; - polygons.push_back (db::Polygon ()); - read_rect (polygons.back (), scale); + db::Polygon poly; + read_polygon (poly, scale); + geo_based_vg->add_polygon (ln, poly, mask); } @@ -954,13 +1025,6 @@ DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale) if (vd.m1.empty () && vd.m2.empty ()) { // analyze the layers to find the metals - std::vector routing_layers; - for (std::map >::const_iterator b = geometry.begin (); b != geometry.end (); ++b) { - if (m_lef_importer.is_routing_layer (b->first)) { - routing_layers.push_back (b->first); - } - } - if (routing_layers.size () == 2) { vd.m1 = routing_layers[0]; vd.m2 = routing_layers[1]; @@ -970,22 +1034,18 @@ DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale) } + if (rule_based_vg.get () && geo_based_vg.get ()) { + error (tl::to_string (tr ("A via can only be defined through a VIARULE or geometry, not both ways"))); + } else if (rule_based_vg.get ()) { + reader_state ()->register_via_cell (n, rule_based_vg.release ()); + } else if (geo_based_vg.get ()) { + reader_state ()->register_via_cell (n, geo_based_vg.release ()); + } else { + error (tl::to_string (tr ("Too little information to generate a via"))); + } + test (";"); - if (has_via_rule && top && cut && bottom) { - create_generated_via (*bottom, *cut, *top, - cutsize, cutspacing, be, te, bo, to, offset, rows, columns, pattern); - } - - for (std::map >::const_iterator g = geometry.begin (); g != geometry.end (); ++g) { - std::pair dl = open_layer (layout, g->first, ViaGeometry, mask); - if (dl.first) { - for (std::vector::const_iterator p = g->second.begin (); p != g->second.end (); ++p) { - cell.shapes (dl.second).insert (*p); - } - } - } - } } diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index a65b769e9..431a002ce 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -67,6 +67,206 @@ std::string correct_path (const std::string &fn, const db::Layout &layout, const } } +// ----------------------------------------------------------------------------------- +// Utilities + +static bool is_hex_digit (char c) +{ + char cup = toupper (c); + return (cup >= 'A' && cup <= 'F') || (c >= '0' && c <= '9'); +} + +static int hex_value (char c) +{ + char cup = toupper (c); + if (cup >= 'A' && cup <= 'F') { + return (cup - 'A') + 10; + } else if (c >= '0' && c <= '9') { + return c - '0'; + } else { + return 0; + } +} + +// ----------------------------------------------------------------------------------- +// RuleBasedViaGenerator implementation + +RuleBasedViaGenerator::RuleBasedViaGenerator () + : LEFDEFViaGenerator (), m_bottom_mask (0), m_cut_mask (0), m_top_mask (0), m_rows (1), m_columns (1) +{ } + +void +RuleBasedViaGenerator::create_cell (LEFDEFReaderState &reader, Layout &layout, db::Cell &cell, unsigned int mask_bottom, unsigned int mask_cut, unsigned int mask_top, const LEFDEFNumberOfMasks *nm) +{ + if (mask_bottom == 0) { + mask_bottom = m_bottom_mask; + } + if (mask_cut == 0) { + mask_cut = m_cut_mask; + } + if (mask_top == 0) { + mask_top = m_top_mask; + } + + unsigned int num_cut_masks = nm ? nm->number_of_masks (m_cut_layer) : 1; + + // NOTE: missing cuts due to pattern holes don't change mask assignment + + db::Vector vs ((m_cutsize.x () * m_columns + m_cutspacing.x () * (m_columns - 1)) / 2, (m_cutsize.y () * m_rows + m_cutspacing.y () * (m_rows - 1)) / 2); + db::Box via_box (m_offset - vs, m_offset + vs); + + std::pair dl (false, 0); + + dl = reader.open_layer (layout, m_bottom_layer, ViaGeometry, mask_bottom); + if (dl.first) { + cell.shapes (dl.second).insert (db::Polygon (via_box.enlarged (m_be).moved (m_bo))); + } + + dl = reader.open_layer (layout, m_top_layer, ViaGeometry, mask_top); + if (dl.first) { + cell.shapes (dl.second).insert (db::Polygon (via_box.enlarged (m_te).moved (m_bo))); + } + + const char *p = m_pattern.c_str (); + int rp = m_pattern.empty () ? -1 : 0; + const char *p0 = p, *p1 = p; + + for (int r = 0; r < m_rows; ++r) { + + if (rp == 0) { + + if (*p) { + + // read a new row specification + rp = 0; + while (*p && is_hex_digit (*p)) { + rp = (rp * 16) + hex_value (*p++); + } + if (*p == '_') { + ++p; + } + + p0 = p; + if (*p) { + while (*p && (is_hex_digit (*p) || toupper (*p) == 'R')) { + ++p; + } + } + p1 = p; + if (*p == '_') { + ++p; + } + + } + + } + + if (rp != 0) { + + if (rp > 0) { + --rp; + } + + const char *pp = p0; + unsigned int d = 0; + int cp = (p == p0 ? -1 : 0); + int bit = 0; + + for (int c = 0; c < m_columns; ++c) { + + if (cp == 0) { + + d = 0; + cp = 4; + bit = 0; + + if (*pp && pp < p1 && toupper (*pp) == 'R') { + + ++pp; + if (*pp && pp < p1) { + cp = 4 * hex_value (*pp++); + if (*pp && pp < p1) { + d = (unsigned int) hex_value (*pp++); + } + } + + } else if (*pp && pp < p1) { + + d = (unsigned int) hex_value (*pp++); + + } + + if (cp > 0) { + --cp; + } + + } else if (cp > 0) { + + --cp; + + } else { + + d = 0xf; + + } + + if ((d & (0x8 >> (bit++ % 4))) != 0) { + + db::Vector vbl ((m_cutsize + m_cutspacing).x () * c, (m_cutsize + m_cutspacing).y () * r); + db::Box vb (via_box.lower_left () + vbl, via_box.lower_left () + vbl + m_cutsize); + + unsigned int cm = 0; + if (mask_cut > 0) { + // This is the core algorithm for mask assignment in patterned vias + cm = (mask_cut + r + c - 1) % num_cut_masks + 1; + } + + dl = reader.open_layer (layout, m_cut_layer, ViaGeometry, cm); + if (dl.first) { + cell.shapes (dl.second).insert (db::Polygon (vb)); + } + + } + + } + + } + + } +} + +// ----------------------------------------------------------------------------------- +// GeometryBasedViaGenerator implementation + +GeometryBasedViaGenerator::GeometryBasedViaGenerator () + : LEFDEFViaGenerator () +{ } + +void +GeometryBasedViaGenerator::create_cell (LEFDEFReaderState &reader, Layout &layout, db::Cell &cell, unsigned int /*mask_bottom*/, unsigned int /*mask_cut*/, unsigned int /*mask_top*/, const LEFDEFNumberOfMasks * /*nm*/) +{ + for (std::map > >::const_iterator g = m_geometries.begin (); g != m_geometries.end (); ++g) { + + for (std::list >::const_iterator i = g->second.begin (); i != g->second.end (); ++i) { + + std::pair dl (false, 0); + + dl = reader.open_layer (layout, g->first, ViaGeometry, i->first); + if (dl.first) { + cell.shapes (dl.second).insert (i->second); + } + + } + + } +} + +void +GeometryBasedViaGenerator::add_polygon (const std::string &ln, const db::Polygon &poly, unsigned int mask) +{ + m_geometries [ln].push_back (std::make_pair (mask, poly)); +} + // ----------------------------------------------------------------------------------- // LEFDEFTechnologyComponent implementation @@ -449,6 +649,15 @@ LEFDEFReaderState::LEFDEFReaderState (const LEFDEFReaderOptions *tc, db::Layout } } +LEFDEFReaderState::~LEFDEFReaderState () +{ + for (std::map::const_iterator i = m_via_generators.begin (); i != m_via_generators.end (); ++i) { + delete i->second; + } + + m_via_generators.clear (); +} + void LEFDEFReaderState::register_layer (const std::string &ln) { @@ -484,7 +693,7 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) purpose_translation ["VIA"] = ViaGeometry; purpose_translation ["BLOCKAGE"] = Blockage; - std::map, db::LayerProperties> layer_map; + std::map >, db::LayerProperties> layer_map; while (! ts.at_end ()) { @@ -504,15 +713,15 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) if (w1 == "DIEAREA") { - layer_map [std::make_pair (std::string (), Outline)] = db::LayerProperties (layer, datatype, "OUTLINE"); + layer_map [std::make_pair (std::string (), std::make_pair (Outline, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "OUTLINE"); } else if (w1 == "REGIONS") { - layer_map [std::make_pair (std::string (), Regions)] = db::LayerProperties (layer, datatype, "REGIONS"); + layer_map [std::make_pair (std::string (), std::make_pair (Regions, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "REGIONS"); } else if (w1 == "BLOCKAGE") { - layer_map [std::make_pair (std::string (), PlacementBlockage)] = db::LayerProperties (layer, datatype, "PLACEMENT_BLK"); + layer_map [std::make_pair (std::string (), std::make_pair (PlacementBlockage, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "PLACEMENT_BLK"); } else if (w1 == "NAME") { @@ -530,7 +739,7 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) std::string final_name = tl::join (layers, "/") + ".LABEL"; for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { - layer_map [std::make_pair (*l, Label)] = db::LayerProperties (layer, datatype, final_name); + layer_map [std::make_pair (*l, std::make_pair (Label, (unsigned int) 0))] = db::LayerProperties (layer, datatype, final_name); } } else { @@ -542,15 +751,30 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) // "(M1,PINS): M1.NET/PINS" // (separating, translating and recombing the purposes) - std::set translated_purposes; + std::set > translated_purposes; std::string purpose_str; + std::vector purposes = tl::split (w2, ","); for (std::vector::const_iterator p = purposes.begin (); p != purposes.end (); ++p) { - std::map::const_iterator i = purpose_translation.find (tl::to_upper_case (*p)); + std::string p_uc = tl::to_upper_case (*p); + tl::Extractor ex (p_uc.c_str ()); + + std::string ps; + ex.read (ps); + + unsigned int mask = 0; + + if (ex.test (":")) { + if (ex.test ("MASK") && ex.test (":")) { + ex.read (mask); + } + } + + std::map::const_iterator i = purpose_translation.find (ps); if (i != purpose_translation.end ()) { - translated_purposes.insert (i->second); + translated_purposes.insert (std::make_pair (i->second, mask)); if (! purpose_str.empty ()) { purpose_str += "/"; @@ -558,11 +782,12 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) purpose_str += i->first; } + } std::string final_name = w1 + "." + purpose_str; - for (std::set::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) { + for (std::set >::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) { layer_map [std::make_pair (w1, *p)] = db::LayerProperties (layer, datatype, final_name); } @@ -575,8 +800,8 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) } db::DirectLayerMapping lm (&layout); - for (std::map, db::LayerProperties>::const_iterator i = layer_map.begin (); i != layer_map.end (); ++i) { - map_layer_explicit (i->first.first, i->first.second, i->second, lm.map_layer (i->second).second); + for (std::map >, db::LayerProperties>::const_iterator i = layer_map.begin (); i != layer_map.end (); ++i) { + map_layer_explicit (i->first.first, i->first.second.first, i->second, lm.map_layer (i->second).second, i->first.second.second); } } @@ -840,16 +1065,52 @@ LEFDEFReaderState::finish (db::Layout &layout) } void -LEFDEFReaderState::register_via_cell (const std::string &vn, db::Cell *cell) +LEFDEFReaderState::register_via_cell (const std::string &vn, LEFDEFViaGenerator *generator) { - m_via_cells [vn] = cell; + if (m_via_generators.find (vn) != m_via_generators.end ()) { + delete m_via_generators [vn]; + } + m_via_generators [vn] = generator; } db::Cell * -LEFDEFReaderState::via_cell (const std::string &vn) +LEFDEFReaderState::via_cell (const std::string &vn, db::Layout &layout, unsigned int mask_bottom, unsigned int mask_cut, unsigned int mask_top, const LEFDEFNumberOfMasks *nm) { - std::map::const_iterator i = m_via_cells.find (vn); - return i != m_via_cells.end () ? i->second : 0; + ViaKey vk (vn, mask_bottom, mask_cut, mask_top); + std::map::const_iterator i = m_via_cells.find (vk); + if (i == m_via_cells.end ()) { + + db::Cell *cell = 0; + + std::map::const_iterator g = m_via_generators.find (vn); + if (g != m_via_generators.end ()) { + + LEFDEFViaGenerator *vg = g->second; + + std::string mask_suffix; + if (mask_bottom > 0 || mask_cut > 0 || mask_top > 0) { + mask_suffix += "_"; + mask_suffix += tl::to_string (mask_bottom); + mask_suffix += "_"; + mask_suffix += tl::to_string (mask_cut); + mask_suffix += "_"; + mask_suffix += tl::to_string (mask_top); + } + + std::string cn = mp_tech_comp->via_cellname_prefix () + vn + mask_suffix; + cell = &layout.cell (layout.add_cell (cn.c_str ())); + + vg->create_cell (*this, layout, *cell, mask_bottom, mask_cut, mask_bottom, nm); + + } + + m_via_cells[vk] = cell; + return cell; + + } else { + tl_assert (! i->second || i->second->layout () == &layout); + return i->second; + } } // ----------------------------------------------------------------------------------- @@ -872,10 +1133,7 @@ LEFDEFImporter::~LEFDEFImporter () unsigned int LEFDEFImporter::get_mask (long m) { - if (m < 1 || m > 16) { - error (tl::to_string (tr ("Invalid mask number: ")) + tl::to_string (m)); - } - return (unsigned int) (m - 1); + return (unsigned int) m; } void @@ -1146,141 +1404,6 @@ LEFDEFImporter::next () return m_last_token; } -static bool is_hex_digit (char c) -{ - char cup = toupper (c); - return (cup >= 'A' && cup <= 'F') || (c >= '0' && c <= '9'); -} - -static int hex_value (char c) -{ - char cup = toupper (c); - if (cup >= 'A' && cup <= 'F') { - return (cup - 'A') + 10; - } else if (c >= '0' && c <= '9') { - return c - '0'; - } else { - return 0; - } -} - -void -LEFDEFImporter::create_generated_via (std::vector &bottom, - std::vector &cut, - std::vector &top, - const db::Vector &cutsize, - const db::Vector &cutspacing, - const db::Vector &be, const db::Vector &te, - const db::Vector &bo, const db::Vector &to, - const db::Point &o, - int rows, int columns, - const std::string &pattern) -{ - db::Vector vs ((cutsize.x () * columns + cutspacing.x () * (columns - 1)) / 2, (cutsize.y () * rows + cutspacing.y () * (rows - 1)) / 2); - db::Box via_box (o - vs, o + vs); - - bottom.push_back (db::Polygon (via_box.enlarged (be).moved (bo))); - top.push_back (db::Polygon (via_box.enlarged (te).moved (to))); - - const char *p = pattern.c_str (); - int rp = pattern.empty () ? -1 : 0; - const char *p0 = p, *p1 = p; - - for (int r = 0; r < rows; ++r) { - - if (rp == 0) { - - if (*p) { - - // read a new row specification - rp = 0; - while (*p && is_hex_digit (*p)) { - rp = (rp * 16) + hex_value (*p++); - } - if (*p == '_') { - ++p; - } - - p0 = p; - if (*p) { - while (*p && (is_hex_digit (*p) || toupper (*p) == 'R')) { - ++p; - } - } - p1 = p; - if (*p == '_') { - ++p; - } - - } - - } - - if (rp != 0) { - - if (rp > 0) { - --rp; - } - - const char *pp = p0; - unsigned int d = 0; - int cp = (p == p0 ? -1 : 0); - int bit = 0; - - for (int c = 0; c < columns; ++c) { - - if (cp == 0) { - - d = 0; - cp = 4; - bit = 0; - - if (*pp && pp < p1 && toupper (*pp) == 'R') { - - ++pp; - if (*pp && pp < p1) { - cp = 4 * hex_value (*pp++); - if (*pp && pp < p1) { - d = (unsigned int) hex_value (*pp++); - } - } - - } else if (*pp && pp < p1) { - - d = (unsigned int) hex_value (*pp++); - - } - - if (cp > 0) { - --cp; - } - - } else if (cp > 0) { - - --cp; - - } else { - - d = 0xf; - - } - - if ((d & (0x8 >> (bit++ % 4))) != 0) { - - db::Vector vbl ((cutsize + cutspacing).x () * c, (cutsize + cutspacing).y () * r); - db::Box vb (via_box.lower_left () + vbl, via_box.lower_left () + vbl + cutsize); - cut.push_back (db::Polygon (vb)); - - } - - } - - } - - } - -} - db::FTrans LEFDEFImporter::get_orient (bool optional) { diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h index 03aa9e635..d0c298328 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h @@ -43,6 +43,8 @@ namespace tl namespace db { +class LEFDEFReaderState; + /** * @brief Correct a path relative to the stream and technology */ @@ -848,6 +850,86 @@ enum LayerPurpose Regions, // from DEF only }; +/** + * @brief An interface for resolving the number of masks from a layer name + */ +class DB_PLUGIN_PUBLIC LEFDEFNumberOfMasks +{ +public: + LEFDEFNumberOfMasks () { } + virtual ~LEFDEFNumberOfMasks () { } + + virtual unsigned int number_of_masks (const std::string &layer_name) const = 0; +}; + +/** + * @brief Provides a via generator base class + */ +class DB_PLUGIN_PUBLIC LEFDEFViaGenerator +{ +public: + LEFDEFViaGenerator () { } + virtual ~LEFDEFViaGenerator () { } + + virtual void create_cell (LEFDEFReaderState &reader, db::Layout &layout, db::Cell &cell, unsigned int mask_bottom, unsigned int mask_cut, unsigned int mask_top, const LEFDEFNumberOfMasks *nm) = 0; +}; + +/** + * @brief Provides a via generator implementation for rule-based vias + */ +class DB_PLUGIN_PUBLIC RuleBasedViaGenerator + : public LEFDEFViaGenerator +{ +public: + RuleBasedViaGenerator (); + + virtual void create_cell (LEFDEFReaderState &reader, Layout &layout, db::Cell &cell, unsigned int mask_bottom, unsigned int mask_cut, unsigned int mask_top, const LEFDEFNumberOfMasks *nm); + + void set_cutsize (const db::Vector &cutsize) { m_cutsize = cutsize; } + void set_cutspacing (const db::Vector &cutspacing) { m_cutspacing = cutspacing; } + void set_offset (const db::Point &offset) { m_offset = offset; } + void set_be (const db::Vector &be) { m_be = be; } + void set_te (const db::Vector &te) { m_te = te; } + void set_bo (const db::Vector &bo) { m_bo = bo; } + void set_to (const db::Vector &to) { m_to = to; } + void set_rows (int rows) { m_rows = rows; } + void set_columns (int columns) { m_columns = columns; } + void set_pattern (const std::string &pattern) { m_pattern = pattern; } + void set_bottom_layer (const std::string &ln) { m_bottom_layer = ln; } + void set_cut_layer (const std::string &ln) { m_cut_layer = ln; } + void set_top_layer (const std::string &ln) { m_top_layer = ln; } + void set_bottom_mask (unsigned int m) { m_bottom_mask = m; } + void set_cut_mask (unsigned int m) { m_cut_mask = m; } + void set_top_mask (unsigned int m) { m_top_mask = m; } + +private: + std::string m_bottom_layer, m_cut_layer, m_top_layer; + unsigned int m_bottom_mask, m_cut_mask, m_top_mask; + db::Vector m_cutsize, m_cutspacing; + db::Vector m_be, m_te; + db::Vector m_bo, m_to; + db::Point m_offset; + int m_rows, m_columns; + std::string m_pattern; +}; + +/** + * @brief Provides a geometry-based via generator implementation + */ +class DB_PLUGIN_PUBLIC GeometryBasedViaGenerator + : public LEFDEFViaGenerator +{ +public: + GeometryBasedViaGenerator (); + + virtual void create_cell (LEFDEFReaderState &reader, Layout &layout, db::Cell &cell, unsigned int mask_bottom, unsigned int mask_cut, unsigned int mask_top, const LEFDEFNumberOfMasks *num_cut_masks); + + void add_polygon (const std::string &ln, const db::Polygon &poly, unsigned int mask); + +private: + std::map > > m_geometries; +}; + /** * @brief Layer handler delegate * @@ -861,6 +943,11 @@ public: */ LEFDEFReaderState (const LEFDEFReaderOptions *tc, db::Layout &layout, const std::string &base_path = std::string ()); + /** + * @brief Destructor + */ + ~LEFDEFReaderState (); + /** * @brief Reads the given map file * @@ -892,14 +979,16 @@ public: void finish (db::Layout &layout); /** - * @brief Registers a via cell for the via with the given name + * @brief Registers a via generator for the via with the given name + * + * The generator is capable of creating a via for a specific mask configuration */ - void register_via_cell (const std::string &vn, db::Cell *cell); + void register_via_cell (const std::string &vn, LEFDEFViaGenerator *generator); /** * @brief Gets the via cell for the given via name or 0 if no such via is registered */ - db::Cell *via_cell (const std::string &vn); + db::Cell *via_cell (const std::string &vn, Layout &layout, unsigned int mask_bottom, unsigned int mask_cut, unsigned int mask_top, const LEFDEFNumberOfMasks *nm); /** * @brief Get the technology component pointer @@ -910,6 +999,45 @@ public: } private: + /** + * @brief A key for the via cache + */ + struct ViaKey + { + ViaKey (const std::string &n, unsigned int mb, unsigned int mc, unsigned int mt) + : name (n), mask_bottom (mb), mask_cut (mc), mask_top (mt) + { } + + bool operator== (const ViaKey &other) const + { + return name == other.name && mask_bottom == other.mask_bottom && mask_cut == other.mask_cut && mask_top == other.mask_top; + } + + bool operator< (const ViaKey &other) const + { + if (name != other.name) { + return name < other.name; + } + if (mask_bottom != other.mask_bottom) { + return mask_bottom < other.mask_bottom; + } + if (mask_cut != other.mask_cut) { + return mask_cut < other.mask_cut; + } + if (mask_top != other.mask_top) { + return mask_top < other.mask_top; + } + return false; + } + + std::string name; + unsigned int mask_bottom, mask_cut, mask_top; + }; + + // no copying + LEFDEFReaderState (const LEFDEFReaderState &); + LEFDEFReaderState &operator= (const LEFDEFReaderState &); + std::map >, std::pair > m_layers; std::map >, unsigned int> m_unassigned_layers; db::LayerMap m_layer_map; @@ -917,8 +1045,9 @@ private: bool m_has_explicit_layer_mapping; int m_laynum; std::map m_default_number; - std::map m_via_cells; + std::map m_via_cells; const LEFDEFReaderOptions *mp_tech_comp; + std::map m_via_generators; std::pair open_layer_uncached (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask); void map_layer_explicit (const std::string &n, LayerPurpose purpose, const LayerProperties &lp, unsigned int layer, unsigned int mask); @@ -929,12 +1058,7 @@ private: */ struct DB_PLUGIN_PUBLIC ViaDesc { - ViaDesc () : cell (0) { } - - /** - * @brief The cell representing the via - */ - db::Cell *cell; + ViaDesc () { } /** * @brief The names of bottom and top metal respectively @@ -1152,17 +1276,6 @@ protected: return mp_reader_state; } - void create_generated_via (std::vector &bottom, - std::vector &cut, - std::vector &top, - const db::Vector &cutsize, - const db::Vector &cutspacing, - const db::Vector &be, const db::Vector &te, - const db::Vector &bo, const db::Vector &to, - const db::Point &o, - int rows, int columns, - const std::string &pattern); - private: tl::AbsoluteProgress *mp_progress; tl::TextInputStream *mp_stream; diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc index 205359c8d..003826ccb 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc @@ -163,7 +163,6 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p std::string layer_name; double dbu = layout.dbu (); double w = 0.0; - unsigned int mask = 0; while (true) { @@ -197,6 +196,7 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p std::vector points; + unsigned int mask = 0; if (test ("MASK")) { mask = get_mask (get_long ()); } @@ -243,6 +243,7 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p std::vector points; + unsigned int mask = 0; if (test ("MASK")) { mask = get_mask (get_long ()); } @@ -289,6 +290,7 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p std::vector points; + unsigned int mask = 0; if (test ("MASK")) { mask = get_mask (get_long ()); } @@ -337,10 +339,15 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p // note: the 5.8 spec says ITERATE comes before MASK for VIA bool iterate = test ("ITERATE"); + unsigned int mask = 0; if (test ("MASK")) { mask = get_mask (get_long ()); } + unsigned int mask_bottom = mask % 10; + unsigned int mask_cut = (mask / 10) % 10; + unsigned int mask_top = (mask / 100) % 10; + int layer_id = -1; std::pair dl = open_layer (layout, layer_name, purpose, mask); if (dl.first) { @@ -359,7 +366,7 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p points.push_back (db::Vector (db::DVector (x / dbu, y / dbu))); std::string vn = get (); - db::Cell *vc = reader_state ()->via_cell (vn); + db::Cell *vc = reader_state ()->via_cell (vn, layout, mask_bottom, mask_cut, mask_top, this); if (! vc) { warn (tl::to_string (tr ("Unknown via: ")) + vn); } @@ -437,21 +444,8 @@ LEFImporter::read_nondefaultrule (db::Layout & /*layout*/) } void -LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_desc, const std::string & /*n*/) +LEFImporter::read_viadef_by_rule (RuleBasedViaGenerator *vg, ViaDesc &via_desc, const std::string & /*n*/, double dbu) { - db::Vector cutsize, cutspacing; - db::Vector be, te; - db::Vector bo, to; - db::Point offset; - int rows = 1, columns = 1; - std::string pattern; - - // @@@ there is something with masks here ... - std::vector, std::vector > > geometry; - geometry.push_back (std::pair, std::vector > ()); - geometry.push_back (std::pair, std::vector > ()); - geometry.push_back (std::pair, std::vector > ()); - while (! test ("END")) { double x, y; @@ -460,7 +454,7 @@ LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_d x = get_double (); y = get_double (); - cutsize = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ())); + vg->set_cutsize (db::Vector (db::DVector (x / dbu, y / dbu))); test (";"); @@ -468,7 +462,7 @@ LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_d x = get_double (); y = get_double (); - cutspacing = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ())); + vg->set_cutspacing (db::Vector (db::DVector (x / dbu, y / dbu))); test (";"); @@ -476,7 +470,7 @@ LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_d x = get_double (); y = get_double (); - offset = db::Point (db::DPoint (x / layout.dbu (), y / layout.dbu ())); + vg->set_offset (db::Point (db::DPoint (x / dbu, y / dbu))); test (";"); @@ -484,11 +478,11 @@ LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_d x = get_double (); y = get_double (); - be = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ())); + vg->set_be (db::Vector (db::DVector (x / dbu, y / dbu))); x = get_double (); y = get_double (); - te = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ())); + vg->set_te (db::Vector (db::DVector (x / dbu, y / dbu))); test (";"); @@ -496,32 +490,39 @@ LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_d x = get_double (); y = get_double (); - bo = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ())); + vg->set_bo (db::Vector (db::DVector (x / dbu, y / dbu))); x = get_double (); y = get_double (); - to = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ())); + vg->set_to (db::Vector (db::DVector (x / dbu, y / dbu))); test (";"); } else if (test ("ROWCOL")) { - rows = get_long (); - columns = get_long (); + vg->set_rows (get_long ()); + vg->set_columns (get_long ()); test (";"); } else if (test ("PATTERN")) { - pattern = get (); + vg->set_pattern (get ()); test (";"); } else if (test ("LAYERS")) { - via_desc.m1 = geometry[0].first.first = get (); - geometry[1].first.first = get (); - via_desc.m2 = geometry[2].first.first = get (); + std::string lb, lc, lt; + lb = get (); + lc = get (); + lt = get (); + via_desc.m1 = lb; + via_desc.m2 = lt; + + vg->set_bottom_layer (lb); + vg->set_cut_layer (lc); + vg->set_top_layer (lt); test (";"); @@ -534,22 +535,10 @@ LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_d } } - - create_generated_via (geometry [0].second, geometry [1].second, geometry [2].second, - cutsize, cutspacing, be, te, bo, to, offset, rows, columns, pattern); - - for (std::vector, std::vector > >::const_iterator g = geometry.begin (); g != geometry.end (); ++g) { - std::pair dl = open_layer (layout, g->first.first, ViaGeometry, g->first.second); - if (dl.first) { - for (std::vector::const_iterator p = g->second.begin (); p != g->second.end (); ++p) { - cell.shapes (dl.second).insert (*p); - } - } - } } void -LEFImporter::read_viadef_by_geometry (Layout &layout, db::Cell &cell, ViaDesc &via_desc, const std::string &n) +LEFImporter::read_viadef_by_geometry (GeometryBasedViaGenerator *vg, ViaDesc &via_desc, const std::string &n, double dbu) { // ignore resistance spec if (test ("RESISTANCE")) { @@ -557,18 +546,80 @@ LEFImporter::read_viadef_by_geometry (Layout &layout, db::Cell &cell, ViaDesc &v test (";"); } - std::map bboxes; - read_geometries (layout, cell, ViaGeometry, &bboxes); + std::string layer_name; + std::set seen_layers; + std::vector routing_layers; + + while (true) { + + if (test ("LAYER")) { + + layer_name = get (); + + if (m_routing_layers.find (layer_name) != m_routing_layers.end () && seen_layers.find (layer_name) == seen_layers.end ()) { + seen_layers.insert (layer_name); + routing_layers.push_back (layer_name); + } + + while (! test (";")) { + take (); + } + + } else if (test ("POLYGON")) { + + std::vector points; + + unsigned int mask = 0; + if (test ("MASK")) { + mask = get_mask (get_long ()); + } + + while (! peek (";")) { + test ("("); + double x = get_double (); + double y = get_double (); + points.push_back (db::Point (db::DPoint (x / dbu, y / dbu))); + test (")"); + } + + db::Polygon p; + p.assign_hull (points.begin (), points.end ()); + + vg->add_polygon (layer_name, p, mask); + + expect (";"); + + } else if (test ("RECT")) { + + std::vector points; + + unsigned int mask = 0; + if (test ("MASK")) { + mask = get_mask (get_long ()); + } + + for (int i = 0; i < 2; ++i) { + test ("("); + double x = get_double (); + double y = get_double (); + points.push_back (db::Point (db::DPoint (x / dbu, y / dbu))); + test (")"); + } + + db::Box b (points [0], points [1]); + vg->add_polygon (layer_name, db::Polygon (b), mask); + + expect (";"); + + } else { + // stop at unknown token + break; + } + + } // determine m1 and m2 layers - std::vector routing_layers; - for (std::map::const_iterator b = bboxes.begin (); b != bboxes.end (); ++b) { - if (m_routing_layers.find (b->first) != m_routing_layers.end ()) { - routing_layers.push_back (b->first); - } - } - if (routing_layers.size () == 2) { via_desc.m1 = routing_layers[0]; via_desc.m2 = routing_layers[1]; @@ -586,22 +637,20 @@ LEFImporter::read_viadef (Layout &layout) { std::string n = get (); - // produce a cell for vias - std::string cellname = options ().via_cellname_prefix () + n; - db::Cell &cell = layout.cell (layout.add_cell (cellname.c_str ())); - reader_state ()->register_via_cell (n, &cell); - ViaDesc &via_desc = m_vias[n]; - via_desc.cell = &cell; while (test ("DEFAULT") || test ("TOPOFSTACKONLY")) ; test (";"); if (test ("VIARULE")) { - read_viadef_by_rule (layout, cell, via_desc, n); + std::auto_ptr vg (new RuleBasedViaGenerator ()); + read_viadef_by_rule (vg.get (), via_desc, n, layout.dbu ()); + reader_state ()->register_via_cell (n, vg.release ()); } else { - read_viadef_by_geometry (layout, cell, via_desc, n); + std::auto_ptr vg (new GeometryBasedViaGenerator ()); + read_viadef_by_geometry (vg.get (), via_desc, n, layout.dbu ()); + reader_state ()->register_via_cell (n, vg.release ()); } test ("VIA"); @@ -637,6 +686,12 @@ LEFImporter::read_layer (Layout & /*layout*/) } expect (";"); + } else if (test ("MASK")) { + + unsigned int num = (unsigned int) std::max (1l, get_long ()); + test (";"); + m_num_masks [ln] = num; + } else if (test ("WIDTH")) { w = get_double (); @@ -880,6 +935,11 @@ LEFImporter::read_macro (Layout &layout) read_geometries (layout, cell, Obstructions); expect ("END"); + } else if (test ("FIXEDMASK")) { + + // we do actually expect FIXEDMASK to be the case always. + expect (";"); + } else { while (! test (";")) { take (); diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h index 859ceef54..b1f75eb60 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h @@ -44,7 +44,7 @@ namespace db * @brief The LEF importer object */ class DB_PLUGIN_PUBLIC LEFImporter - : public LEFDEFImporter + : public LEFDEFImporter, public LEFDEFNumberOfMasks { public: /** @@ -107,6 +107,15 @@ public: return m_cut_layers.find (layer) != m_cut_layers.end (); } + /** + * @brief Returns the number of masks for the given layer + */ + virtual unsigned int number_of_masks (const std::string &layer) const + { + std::map::const_iterator nm = m_num_masks.find (layer); + return nm != m_num_masks.end () ? nm->second : 1; + } + /** * @brief Gets a map of the vias defined in this LEF file * @@ -129,13 +138,14 @@ private: std::map m_macro_bboxes_by_name; std::map m_vias; std::set m_routing_layers, m_cut_layers; + std::map m_num_masks; std::vector get_iteration (db::Layout &layout); void read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose purpose, std::map *collect_bboxes = 0, properties_id_type prop_id = 0); void read_nondefaultrule (Layout &layout); void read_viadef (Layout &layout); - void read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &desc, const std::string &n); - void read_viadef_by_geometry (Layout &layout, db::Cell &cell, ViaDesc &desc, const std::string &n); + void read_viadef_by_rule (RuleBasedViaGenerator *vg, ViaDesc &desc, const std::string &n, double dbu); + void read_viadef_by_geometry (GeometryBasedViaGenerator *vg, ViaDesc &desc, const std::string &n, double dbu); void read_layer (Layout &layout); void read_macro (Layout &layout); };