From 44503faceae9080c76b46a01da84bec5044fbd01 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 29 Mar 2020 18:57:07 +0200 Subject: [PATCH] Attempt to auto-import .map files for LEF/DEF reader. Probably needs adjustment. --- .../lefdef/db_plugin/dbLEFDEFImporter.cc | 78 ++++++++--- .../lefdef/db_plugin/dbLEFDEFImporter.h | 8 ++ .../lefdef/db_plugin/dbLEFDEFPlugin.cc | 125 +++++++++++++++++- 3 files changed, 190 insertions(+), 21 deletions(-) diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index 430a31f25..d61efba16 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -147,18 +147,25 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer { if (purpose == Outline || purpose == PlacementBlockage || purpose == Region) { + // NOTE: the canonical name is independent from the tech component's settings + // as is "(name)". It's used for implementing the automatic map file import + // feature. std::string ld; + std::string canonical_name; bool produce; if (purpose == Outline) { produce = mp_tech_comp->produce_cell_outlines (); ld = mp_tech_comp->cell_outline_layer (); + canonical_name = "(OUTLINE)"; } else if (purpose == Region) { produce = mp_tech_comp->produce_regions (); ld = mp_tech_comp->region_layer (); + canonical_name = "(REGION)"; } else { produce = mp_tech_comp->produce_placement_blockages (); ld = mp_tech_comp->placement_blockage_layer (); + canonical_name = "(BLK)"; } if (! produce) { @@ -178,10 +185,9 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer if (ll.first) { - // create the layer if it is not part of the layout yet. - if (! layout.is_valid_layer (ll.second)) { - layout.insert_layer (ll.second, m_layer_map.mapping (ll.second)); - } + return ll; + + } else if ((ll = m_layer_map.logical (db::LayerProperties (canonical_name), layout)).first) { return ll; @@ -199,67 +205,99 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer } else { + if (mp_tech_comp) { + bool produce = true; + switch (purpose) { + case Routing: + default: + produce = mp_tech_comp->produce_routing (); + break; + case ViaGeometry: + produce = mp_tech_comp->produce_via_geometry (); + break; + case Label: + produce = mp_tech_comp->produce_labels (); + break; + case Pins: + produce = mp_tech_comp->produce_pins (); + break; + case Obstructions: + produce = mp_tech_comp->produce_obstructions (); + break; + case Blockage: + produce = mp_tech_comp->produce_blockages (); + break; + } + if (! produce) { + return std::make_pair (false, 0); + } + } + + // Note: "name" is the decorated name as provided by the tech component's + // x_suffix specifications. As this is a variable entity, we also provide + // a canonical name of the form "(layer,purpose)" where purpose is a + // predefined suffix. The canonical name is the last fallback. Hence this + // allows importing layer mapping files as canonical name mapping. std::string name (n); - bool produce = true; int dt = 0; + std::string canonical_purpose; + if (mp_tech_comp) { switch (purpose) { case Routing: default: - produce = mp_tech_comp->produce_routing (); name += mp_tech_comp->routing_suffix (); + canonical_purpose = "NET"; dt += mp_tech_comp->routing_datatype (); break; case ViaGeometry: - produce = mp_tech_comp->produce_via_geometry (); name += mp_tech_comp->via_geometry_suffix (); dt += mp_tech_comp->via_geometry_datatype (); + canonical_purpose = "VIA"; break; case Label: - produce = mp_tech_comp->produce_labels (); name += mp_tech_comp->labels_suffix (); dt += mp_tech_comp->labels_datatype (); + canonical_purpose = "LABEL"; break; case Pins: - produce = mp_tech_comp->produce_pins (); name += mp_tech_comp->pins_suffix (); dt += mp_tech_comp->pins_datatype (); + canonical_purpose = "PIN"; break; case Obstructions: - produce = mp_tech_comp->produce_obstructions (); name += mp_tech_comp->obstructions_suffix (); dt += mp_tech_comp->obstructions_datatype (); + canonical_purpose = "OBS"; break; case Blockage: - produce = mp_tech_comp->produce_blockages (); name += mp_tech_comp->blockages_suffix (); dt += mp_tech_comp->blockages_datatype (); + canonical_purpose = "BLK"; break; } } - if (! produce) { - return std::make_pair (false, 0); - } + std::string canonical_name = std::string ("(") + n + "," + canonical_purpose + ")"; std::pair ll = m_layer_map.logical (name, layout); if (ll.first) { - // create the layer if it is not part of the layout yet. - if (! layout.is_valid_layer (ll.second)) { - layout.insert_layer (ll.second, m_layer_map.mapping (ll.second)); - } + return ll; + } else if ((ll = m_layer_map.logical (db::LayerProperties (canonical_name), layout)).first) { + + // final fallback: try canonical name return ll; } else { - std::pair ll_raw = m_layer_map.logical (n, layout); + ll = m_layer_map.logical (n, layout); int ln = -1; - if (ll_raw.first && (ln = layout.get_properties (ll_raw.second).layer) >= 0) { + if (ll.first && (ln = layout.get_properties (ll.second).layer) >= 0) { m_layer_map.map (db::LayerProperties (name), layout.layers (), db::LayerProperties (ln, dt, name)); m_layer_map.prepare (layout); diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h index 8058accd0..0cfc38f2b 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h @@ -518,6 +518,14 @@ public: return m_layer_map; } + /** + * @brief Get the layer map (non-const version) + */ + db::LayerMap &layer_map () + { + return m_layer_map; + } + /** * @brief Create a new layer or return the index of the given layer */ diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc index d9b10b28a..fa2e9adb5 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc @@ -77,6 +77,124 @@ static bool is_def_format (const std::string &fn) return false; } +/** + * @brief Reads a map file + * + * NOTE: this is rather experimental ... no idea what is the specification of + * the map file. + */ +static void +read_map_file (const std::string &path, db::LEFDEFLayerDelegate &layers) +{ + tl::log << tl::to_string (tr ("Reading LEF/DEF map file")) << " " << path; + + db::LayerMap &lm = layers.layer_map (); + unsigned int n = lm.next_index (); + + tl::InputFile file (path); + tl::InputStream file_stream (file); + tl::TextInputStream ts (file_stream); + + std::map purpose_translation; + purpose_translation ["LEFPIN"] = "PIN"; + purpose_translation ["LEFOBS"] = "OBS"; + purpose_translation ["SPNET"] = "NET"; + purpose_translation ["NET"] = "NET"; + purpose_translation ["VIA"] = "VIA"; + + while (! ts.at_end ()) { + + const std::string &l = ts.get_line (); + + tl::Extractor ex (l.c_str ()); + if (ex.at_end () || ex.test ("#")) { + + // ignore empty of comment lines + + } else { + + std::string w1, w2; + int layer = 0, datatype = 0; + + if (ex.try_read_word (w1) && ex.try_read_word (w2, "._$,/:") && ex.try_read (layer) && ex.try_read (datatype)) { + + if (w1 == "DIEAREA") { + + std::string canonical_name = "(OUTLINE)"; + lm.map (db::LayerProperties (canonical_name), n++, db::LayerProperties (layer, datatype)); + + } else if (w1 == "NAME") { + + std::vector purposes = tl::split (w2, ","); + for (std::vector::const_iterator p = purposes.begin (); p != purposes.end (); ++p) { + std::string canonical_name = std::string ("(") + tl::split (*p, "/").front () + ",LABEL)"; + lm.map (db::LayerProperties (canonical_name), n++, db::LayerProperties (layer, datatype)); + } + + } else { + + 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 (*p); + if (i != purpose_translation.end ()) { + std::string canonical_name = std::string ("(") + w1 + "," + i->second + ")"; + lm.map (db::LayerProperties (canonical_name), n++, db::LayerProperties (layer, datatype)); + } + } + + } + + } + + } + + } +} + +/** + * @brief Imports a .map file present next to the input files + */ +static void +import_map_file_heuristics (const std::string &main_path, db::LEFDEFLayerDelegate &layers) +{ + std::string input_dir = tl::absolute_path (main_path); + if (! tl::file_exists (input_dir)) { + return; + } + + std::string bn = tl::basename (tl::filename (main_path)); + std::vector map_files; + std::string map_file_exact; + + std::vector entries = tl::dir_entries (input_dir); + for (std::vector::const_iterator e = entries.begin (); e != entries.end (); ++e) { + + if (tl::to_lower_case (tl::extension (*e)) == "map") { + + if (tl::basename (*e) == bn) { + map_file_exact = *e; + } else { + map_files.push_back (*e); + } + + } + + } + + try { + if (! map_file_exact.empty ()) { + read_map_file (tl::combine_path (input_dir, map_file_exact), layers); + tl::log << layers.layer_map ().to_string_file_format (); // @@@ + } else if (map_files.size () == 1) { + read_map_file (tl::combine_path (input_dir, map_files.front ()), layers); + tl::log << layers.layer_map ().to_string_file_format (); // @@@ + } + } catch (tl::Exception &ex) { + // ignore read errors on map file (this is a heuristics!) + tl::error << ex.msg (); + } +} + class LEFDEFReader : public db::ReaderBase { @@ -125,6 +243,9 @@ private: // Take the layer map and the "read all layers" flag from the reader options - hence we override the db::LEFDEFLayerDelegate layers (lefdef_options); + + import_map_file_heuristics (m_stream.absolute_path (), layers); + layers.prepare (layout); layout.dbu (lefdef_options->dbu ()); @@ -163,9 +284,11 @@ private: } - // Additionally read all LEF files next to the DEF file + // Additionally read all LEF files next to the DEF file and if there is a single .map file + // or one with the same name than the input file with ".map" suffix, try to read this one too. std::string input_dir = tl::absolute_path (m_stream.absolute_path ()); + if (tl::file_exists (input_dir)) { std::vector entries = tl::dir_entries (input_dir);