From 2300c391ae6da1272b544daa8e16b9953a51e9ae Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 21 Nov 2020 00:38:25 +0100 Subject: [PATCH 01/44] Better alignment DEF layer map reader with specification (still some options are ignore). --- .../lefdef/db_plugin/dbLEFDEFImporter.cc | 197 ++++++++++++------ .../lefdef/db_plugin/dbLEFDEFImporter.h | 1 + 2 files changed, 131 insertions(+), 67 deletions(-) diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index c4628b38c..647dd099a 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -813,6 +813,26 @@ LEFDEFReaderState::map_layer_explicit (const std::string &n, LayerPurpose purpos m_layer_map.map (lp, layer); } +static bool try_read_layers (tl::Extractor &ex, std::vector &layers) +{ + int l = 0; + if (! ex.try_read (l)) { + return false; + } + layers.push_back (l); + + if (ex.test (",")) { + do { + if (! ex.try_read (l)) { + return false; + } + layers.push_back (l); + } while (ex.test (",")); + } + + return true; +} + void LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) { @@ -832,6 +852,7 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) purpose_translation ["NET"] = Routing; purpose_translation ["VIA"] = ViaGeometry; purpose_translation ["BLOCKAGE"] = Blockage; + purpose_translation ["ALL"] = All; std::map purpose_translation_rev; for (std::map::const_iterator i = purpose_translation.begin (); i != purpose_translation.end (); ++i) { @@ -853,112 +874,154 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) std::string w1, w2; int layer = 0, datatype = 0; + std::vector layers; size_t max_purpose_str = 10; - if (ex.try_read_word (w1) && ex.try_read_word (w2, "._$,/:") && ex.try_read (layer) && ex.try_read (datatype)) { + if (! ex.try_read_word (w1) || ! ex.try_read_word (w2, "._$,/:") || ! try_read_layers (ex, layers) || ! ex.try_read (datatype)) { + tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d not understood - skipped")), path, ts.line_number ()); + continue; + } - if (w1 == "DIEAREA") { + if (layers.size () > 1) { + tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: mapping to multiple layers not supported currently - first one taken")), path, ts.line_number ()); + } + layer = layers.front (); - layer_map [std::make_pair (std::string (), std::make_pair (Outline, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "OUTLINE"); + if (w1 == "DIEAREA") { - } else if (w1 == "REGIONS") { + layer_map [std::make_pair (std::string (), std::make_pair (Outline, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "OUTLINE"); - layer_map [std::make_pair (std::string (), std::make_pair (Regions, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "REGIONS"); + } else if (w1 == "REGIONS") { - } else if (w1 == "BLOCKAGE") { + layer_map [std::make_pair (std::string (), std::make_pair (Regions, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "REGIONS"); - layer_map [std::make_pair (std::string (), std::make_pair (PlacementBlockage, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "PLACEMENT_BLK"); + } else if (w1 == "BLOCKAGE") { - } else if (w1 == "NAME") { + layer_map [std::make_pair (std::string (), std::make_pair (PlacementBlockage, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "PLACEMENT_BLK"); - // converts a line like - // "NAME M1/PINS,M2/PINS ..." - // into a canonical name mapping like - // "(M1/LABELS): M1.LABEL" - // "(M2/LABELS): M2.LABEL" + } else if (w1 == "NAME") { - std::vector layers; - std::vector purposes = tl::split (w2, ","); - for (std::vector::const_iterator p = purposes.begin (); p != purposes.end (); ++p) { + // converts a line like + // "NAME M1/PINS,M2/PINS ..." + // into a canonical name mapping like + // "(M1/LABELS): M1.LABEL" + // "(M2/LABELS): M2.LABEL" + + std::vector layers; + std::vector purposes = tl::split (w2, ","); + for (std::vector::const_iterator p = purposes.begin (); p != purposes.end (); ++p) { + if (*p == "DIEAREA" || *p == "ALL" || *p == "COMP") { + tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: NAME record ignored for entity: %s")), path, ts.line_number (), *p); + } else { layers.push_back (tl::split (*p, "/").front ()); } + } - 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, std::make_pair (Label, (unsigned int) 0))] = db::LayerProperties (layer, datatype, final_name); - } + 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, std::make_pair (Label, (unsigned int) 0))] = db::LayerProperties (layer, datatype, final_name); + } - } else if (w1 == "COMP") { + } else if (w1 == "COMP") { - // ignore "COMP (ALL) ..." + // ignore "COMP (ALL) ..." + tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: COMP entry ignored")), path, ts.line_number ()); - } else { + } else { - // converts a line like - // "M1 SPNET,NET,PINS,LEFPINS ..." - // into a canonical name mapping like - // "(M1,NET): M1.NET/PINS" - // "(M1,PINS): M1.NET/PINS" - // (separating, translating and recombing the purposes) + // converts a line like + // "M1 SPNET,NET,PINS,LEFPINS ..." + // into a canonical name mapping like + // "(M1,NET): M1.NET/PINS" + // "(M1,PINS): M1.NET/PINS" + // (separating, translating and recombing the purposes) - std::set > translated_purposes; + std::set > translated_purposes; - std::vector purposes = tl::split (w2, ","); - std::reverse (purposes.begin (), purposes.end ()); + std::vector purposes = tl::split (w2, ","); + std::reverse (purposes.begin (), purposes.end ()); - unsigned int mask = 0; + unsigned int mask = 0; - for (std::vector::const_iterator p = purposes.begin (); p != purposes.end (); ++p) { + for (std::vector::const_iterator p = purposes.begin (); p != purposes.end (); ++p) { - std::string p_uc = tl::to_upper_case (*p); - tl::Extractor ex (p_uc.c_str ()); + std::string p_uc = tl::to_upper_case (*p); + tl::Extractor ex (p_uc.c_str ()); - std::string ps; - ex.read_word_or_quoted (ps); + std::string ps; + ex.read_word_or_quoted (ps); - if (ex.test (":")) { + std::map::const_iterator i = purpose_translation.find (ps); + if (i != purpose_translation.end ()) { + + if (i->second == All) { + for (std::map::const_iterator p = purpose_translation.begin (); p != purpose_translation.end (); ++p) { + if (p->second != All) { + translated_purposes.insert (std::make_pair (p->second, mask)); + } + } + } else { + translated_purposes.insert (std::make_pair (i->second, mask)); + } + + if (i->second == Routing) { + + if (ex.test (":VOLTAGE:")) { + double f = 0.0; + ex.read (f); + tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: NET voltage constraint ignored for layer %s")), path, ts.line_number (), w1); + } + + } else if (i->second == ViaGeometry) { + + if (ex.test (":SIZE:")) { + std::string sz; + ex.read_word (sz); + tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: VIA size constraint ignored for layer %s")), path, ts.line_number (), w1); + } + + } + + if (ex.test (":MASK:")) { 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 (std::make_pair (i->second, mask)); - } - + } else { + tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: purpose %s ignored for layer %s")), path, ts.line_number (), ps, w1); } - // create a visual description string for the combined purposes - std::string purpose_str; + } - for (std::set >::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) { + // create a visual description string for the combined purposes + std::string purpose_str; - if (p != translated_purposes.begin ()) { - purpose_str += "/"; - } - - std::string ps = purpose_translation_rev [p->first]; - if (p->second > 0) { - ps += ":"; - ps += tl::to_string (p->second); - } - - if ((purpose_str + ps).size () > max_purpose_str) { - purpose_str += "..."; - break; - } else { - purpose_str += ps; - } + for (std::set >::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) { + if (p != translated_purposes.begin ()) { + purpose_str += "/"; } - std::string final_name = w1 + "." + purpose_str; - - 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); + std::string ps = purpose_translation_rev [p->first]; + if (p->second > 0) { + ps += ":"; + ps += tl::to_string (p->second); } + if ((purpose_str + ps).size () > max_purpose_str) { + purpose_str += "..."; + break; + } else { + purpose_str += ps; + } + + } + + std::string final_name = w1 + "." + purpose_str; + + 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); } } diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h index f29326547..ec1da4076 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h @@ -884,6 +884,7 @@ enum LayerPurpose Blockage, // from DEF only PlacementBlockage, // from DEF only Regions, // from DEF only + All // from DEF only }; /** From 6eac98907f9152eeac488a1340b56ea53a3f6351 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 21 Nov 2020 01:00:28 +0100 Subject: [PATCH 02/44] WIP: bugfix. --- .../lefdef/db_plugin/dbLEFDEFImporter.cc | 32 +++++++++++-------- .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 12 +++++++ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index 647dd099a..e0f573282 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -954,16 +954,6 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) std::map::const_iterator i = purpose_translation.find (ps); if (i != purpose_translation.end ()) { - if (i->second == All) { - for (std::map::const_iterator p = purpose_translation.begin (); p != purpose_translation.end (); ++p) { - if (p->second != All) { - translated_purposes.insert (std::make_pair (p->second, mask)); - } - } - } else { - translated_purposes.insert (std::make_pair (i->second, mask)); - } - if (i->second == Routing) { if (ex.test (":VOLTAGE:")) { @@ -982,14 +972,28 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) } - if (ex.test (":MASK:")) { - if (ex.test ("MASK") && ex.test (":")) { - ex.read (mask); + } + + if (ex.test (":MASK:")) { + ex.read (mask); + } + + if (i == purpose_translation.end ()) { + + tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: purpose %s ignored for layer %s")), path, ts.line_number (), ps, w1); + + } else if (i->second == All) { + + for (std::map::const_iterator p = purpose_translation.begin (); p != purpose_translation.end (); ++p) { + if (p->second != All) { + translated_purposes.insert (std::make_pair (p->second, mask)); } } } else { - tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: purpose %s ignored for layer %s")), path, ts.line_number (), ps, w1); + + translated_purposes.insert (std::make_pair (i->second, mask)); + } } diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index 93921cac8..72332bedf 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -549,6 +549,18 @@ TEST(115_componentmaskshift) run_test (_this, "masks-2", "lef:in_tech.lef+lef:in.lef+def:in.def", "au.oas.gz", options, false); } +TEST(116_name_to_ld_target_mapping) +{ + db::LEFDEFReaderOptions options = default_options (); + db::LayerMap lm = db::LayerMap::from_string_file_format ("metal1: 1\nvia1: 2\nmetal2: 3\nOUTLINE: 42/17"); + options.set_layer_map (lm); + + db::LayerMap lm_read = run_test (_this, "via_properties", "lef:in.lef+def:in.def", "au.oas.gz", options, false); + EXPECT_EQ (lm_read.to_string (), + "layer_map('OUTLINE : OUTLINE (4/0)';'metal1.VIA : metal1 (1/0)';'metal2.VIA : metal2 (3/0)';'via1.VIA : via1 (2/0)')" + ) +} + TEST(200_lefdef_plugin) { db::Layout ly; From b0f25dd61e0bd2a5ad92755d67f8cb40626e3a6c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 21 Nov 2020 20:39:31 +0100 Subject: [PATCH 03/44] Fixed DEF layer mapping for compatibility with 0.26 Problem was: general layers (e.g. OUTLINE) were not routed through the layer map. --- .../lefdef/db_plugin/dbLEFDEFImporter.cc | 170 +++++++++++++----- .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 162 +++++++++++++++-- 2 files changed, 277 insertions(+), 55 deletions(-) diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index e0f573282..4cc77b69d 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -1060,14 +1060,85 @@ LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPu } } +static std::string purpose_to_name (LayerPurpose purpose) +{ + switch (purpose) { + case Outline: + return "OUTLINE"; + case Regions: + return "REGION"; + case PlacementBlockage: + return "BLOCKAGE"; + case Routing: + return "NET"; + case SpecialRouting: + return "SPNET"; + case ViaGeometry: + return "VIA"; + case Label: + return "LABEL"; + case Pins: + return "PIN"; + case LEFPins: + return "LEFPIN"; + case Obstructions: + return "LEFOBS"; + case Blockage: + return "BLK"; + case All: + return "ALL"; + } + + return std::string (); +} + +/** + * @brief Implements implicit layer mapping + * + * This is how Implicit layer mapping works: + * + * 1. For named layers (e.g. routing, pin, etc. + * + * A decorated name is formed from the basic name and the purpose string (e.g. "M1" -> "M1.PIN"). + * With the example of "M1" and purpose Pin (decorated name "M1.PIN") and with a tech component datatype specification + * of "5" for "Pin", the layer map entries have the following effect: + * + * Layer map Result + * + * (nothing) M1.PIN (default/5) (only if "create_all_layers" is ON, "default" is a default number assigned by the reader) + * M1.PIN : 1/0 M1.PIN (1/0) + * M1.PIN : 1/17 M1.PIN (1/17) + * M1 : 1/0 M1.PIN (1/5) + * M1 : 1/2 M1.PIN (1/7) (datatypes will add) + * M1 M1.PIN (default/5) + * M1 : METAL1 METAL1.PIN (default/5) (name is taken from layer map and decorated) + * M1 : METAL1 (1/2) METAL1.PIN (1/7) + * M1.PIN : METAL1_PIN METAL1_PIN (default/5) (specific name is used without decoration) + * M1.PIN : METAL1_PIN (1/17) METAL1_PIN (1/17) (full and specific mapping) + * + * 2. For general layers (e.g. outline) + * + * By default, the name, layer and datatype are taken from the tech component's specification. The specification may + * lack the layer and datatype and even the name. If the name is missing, it is generated from the purpose. + * + * Here are some examples for the mapping of "OUTLINE": + * + * Tech component Layer map Result + * + * (nothing) (nothing) OUTLINE (only if "create_all_layers" is ON) + * OUTL (nothing) OUTL (default/0) ("default" is a default number assigned by the reader) + * OUTL (4/17) (nothing) OUTL (4/17) + * OUTL OUTL : 5/1 OUTL (5/1) + * OUTL (4/17) OUTL : 4/11 OUTL 4/11 + * OUTL (4/17) 4/17 : 4/11 OUTL 4/11 + * 4/17 4/17 : 4/11 OUTLINE 4/11 + */ + std::pair LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n, LayerPurpose purpose, unsigned int mask) { if (n.empty ()) { - // 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; bool produce = false; @@ -1095,6 +1166,42 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n lp.datatype = 0; } + // if no name is given, derive one from the purpose + if (lp.name.empty ()) { + lp.name = purpose_to_name (purpose); + } + + if (lp.layer < 0) { + std::map::const_iterator ldef = m_default_number.find (lp.name); + if (ldef != m_default_number.end ()) { + lp.layer = ldef->second; + lp.datatype = 0; + } + } + + // employ the layer map to find the target layer + std::pair ll = m_layer_map.logical (lp, layout); + + if (ll.first) { + + // If the layer map provides a target, use that one for the layer + const db::LayerProperties *lpp = m_layer_map.target (ll.second); + if (lpp) { + if (! lpp->name.empty ()) { + lp.name = lpp->name; + } + if (lpp->datatype >= 0) { + lp.datatype = lpp->datatype; + } + if (lpp->layer >= 0) { + lp.layer = lpp->layer; + } + } + + } else if (! m_create_layers) { + return std::make_pair (false, 0); + } + for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) { if ((*l).second->log_equal (lp)) { return std::make_pair (true, (*l).first); @@ -1139,8 +1246,6 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n } } - // Note: "name" is the decorated name as provided by the tech component's - // x_suffix specifications. std::string name_suffix; int dt = 0; @@ -1182,8 +1287,10 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n } } + // "name" is the decorated name as provided by the tech component's x_suffix specifications. std::string name = n + name_suffix; + // Assign a layer number (a default one for now) and the datatype from the tech component's x_datatype specification. db::LayerProperties lp (name); lp.datatype = dt; std::map::const_iterator ldef = m_default_number.find (n); @@ -1191,21 +1298,31 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n lp.layer = ldef->second; } + // Route the layer through the layer map, first the decorated name and if there is no mapping, the + // undecorated one. std::pair ll = m_layer_map.logical (name, layout); + bool generic_match = false; if (! ll.first) { ll = m_layer_map.logical (n, layout); + generic_match = true; } if (ll.first) { + // If the layer map provides a target, use that one for the layer + // Datatypes from the target and the tech component's x_datatype specification are additive const db::LayerProperties *lpp = m_layer_map.target (ll.second); if (lpp) { lp = *lpp; - if (lp.datatype >= 0) { + if (lp.datatype < 0) { + lp.datatype = dt; + } else if (generic_match) { lp.datatype += dt; } if (lp.name.empty ()) { lp.name = name; + } else if (generic_match) { + lp.name += name_suffix; } } @@ -1254,44 +1371,7 @@ LEFDEFReaderState::finish (db::Layout &layout) continue; } - std::string ps; - - switch (l->first.second.first) { - case Outline: - ps = "OUTLINE"; - break; - case Regions: - ps = "REGION"; - break; - case PlacementBlockage: - ps = "PLACEMENT_BLK"; - break; - case Routing: - default: - ps = "NET"; - break; - case SpecialRouting: - ps = "SPNET"; - break; - case ViaGeometry: - ps = "VIA"; - break; - case Label: - ps = "LABEL"; - break; - case Pins: - ps = "PIN"; - break; - case LEFPins: - ps = "LEFPIN"; - break; - case Obstructions: - ps = "OBS"; - break; - case Blockage: - ps = "BLK"; - break; - } + std::string ps = purpose_to_name (l->first.second.first); unsigned int layer_index = l->second.second; db::LayerProperties lp = layout.get_properties (layer_index); @@ -1336,7 +1416,7 @@ LEFDEFReaderState::finish (db::Layout &layout) } - // On return we deliver the "canonical" map + // On return we deliver the "canonical" map which lists the decorated name vs. the real ones. m_layer_map = lm; } diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index 72332bedf..fa446436a 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -50,16 +50,13 @@ static db::LEFDEFReaderOptions default_options () return tc; } -static db::LayerMap run_test (tl::TestBase *_this, const char *lef_dir, const char *filename, const char *au, const db::LEFDEFReaderOptions &options, bool priv = true) +static db::LayerMap read (db::Layout &layout, const char *lef_dir, const char *filename, const db::LEFDEFReaderOptions &options, bool priv = true) { std::string fn_path (priv ? tl::testsrc_private () : tl::testsrc ()); fn_path += "/testdata/lefdef/"; fn_path += lef_dir; fn_path += "/"; - db::Manager m (false); - db::Layout layout (&m), layout2 (&m), layout_au (&m); - tl::Extractor ex (filename); db::LEFDEFReaderState ld (&options, layout, fn_path); @@ -142,6 +139,16 @@ static db::LayerMap run_test (tl::TestBase *_this, const char *lef_dir, const ch ld.finish (layout); + return ld.layer_map (); +} + +static db::LayerMap run_test (tl::TestBase *_this, const char *lef_dir, const char *filename, const char *au, const db::LEFDEFReaderOptions &options, bool priv = true) +{ + db::Manager m (false); + db::Layout layout (&m), layout2 (&m), layout_au (&m); + + db::LayerMap lm = read (layout, lef_dir, filename, options, priv); + // normalize the layout by writing to OASIS and reading from .. // generate a "unique" name ... @@ -200,7 +207,7 @@ static db::LayerMap run_test (tl::TestBase *_this, const char *lef_dir, const ch } - return ld.layer_map (); + return lm; } TEST(1) @@ -549,16 +556,151 @@ TEST(115_componentmaskshift) run_test (_this, "masks-2", "lef:in_tech.lef+lef:in.lef+def:in.def", "au.oas.gz", options, false); } -TEST(116_name_to_ld_target_mapping) +TEST(116_layer_mapping) { db::LEFDEFReaderOptions options = default_options (); db::LayerMap lm = db::LayerMap::from_string_file_format ("metal1: 1\nvia1: 2\nmetal2: 3\nOUTLINE: 42/17"); options.set_layer_map (lm); - db::LayerMap lm_read = run_test (_this, "via_properties", "lef:in.lef+def:in.def", "au.oas.gz", options, false); - EXPECT_EQ (lm_read.to_string (), - "layer_map('OUTLINE : OUTLINE (4/0)';'metal1.VIA : metal1 (1/0)';'metal2.VIA : metal2 (3/0)';'via1.VIA : via1 (2/0)')" - ) + { + db::Layout layout; + db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false); + EXPECT_EQ (lm_read.to_string (), + "layer_map('OUTLINE : OUTLINE (42/17)';'metal1.VIA : metal1 (1/0)';'metal2.VIA : metal2 (3/0)';'via1.VIA : via1 (2/0)')" + ) + } + + options.set_layer_map (db::LayerMap ()); + + { + db::Layout layout; + db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false); + EXPECT_EQ (lm_read.to_string (), + "layer_map('OUTLINE : OUTLINE (4/0)';'metal1.VIA : metal1 (1/0)';'metal2.VIA : metal2 (3/0)';'via1.VIA : via1 (2/0)')" + ) + } + + lm = db::LayerMap::from_string_file_format ("metal1: M1\nmetal1.V: M1_V\nvia1: V1\nmetal2: M2\nOUTLINE: OUTL"); + options.set_layer_map (lm); + options.set_via_geometry_suffix ("V"); + options.set_via_geometry_datatype (42); + + { + db::Layout layout; + db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false); + EXPECT_EQ (lm_read.to_string (), + "layer_map('OUTLINE : OUTL (4/0)';'metal1.VIA : M1V (1/42)';'metal2.VIA : M2V (3/42)';'via1.VIA : V1V (2/42)')" + ) + } + + lm = db::LayerMap::from_string_file_format ("metal1: M1\nmetal1.V: M1_V\nvia1: V1\nmetal2: M2"); + options.set_layer_map (lm); + options.set_via_geometry_suffix ("V"); + options.set_via_geometry_datatype (42); + options.set_read_all_layers (false); + + { + db::Layout layout; + db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false); + EXPECT_EQ (lm_read.to_string (), + "layer_map('metal1.VIA : M1V (1/42)';'metal2.VIA : M2V (3/42)';'via1.VIA : V1V (2/42)')" + ) + } + + lm = db::LayerMap::from_string_file_format ("metal2: M2 (17/1)"); + options.set_layer_map (lm); + + { + db::Layout layout; + db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false); + EXPECT_EQ (lm_read.to_string (), + "layer_map('metal2.VIA : M2V (17/43)')" + ) + } + + options.set_produce_via_geometry (false); + + { + db::Layout layout; + db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false); + EXPECT_EQ (lm_read.to_string (), + "layer_map()" + ) + } + + options.set_produce_via_geometry (true); + options.set_via_geometry_suffix (".V"); + lm = db::LayerMap::from_string_file_format ("metal2.V: 17/1"); + options.set_layer_map (lm); + + { + db::Layout layout; + db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false); + EXPECT_EQ (lm_read.to_string (), + "layer_map('metal2.VIA : metal2.V (17/1)')" + ) + } + + lm = db::LayerMap::from_string_file_format ("metal2.V: m2v (17/5)"); + options.set_layer_map (lm); + + { + db::Layout layout; + db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false); + EXPECT_EQ (lm_read.to_string (), + "layer_map('metal2.VIA : m2v (17/5)')" + ) + } + + lm = db::LayerMap::from_string_file_format ("OUTLINE: OUTL"); + options.set_layer_map (lm); + options.set_cell_outline_layer ("OUTLINE (42/17)"); + + { + db::Layout layout; + db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false); + EXPECT_EQ (lm_read.to_string (), + "layer_map('OUTLINE : OUTL (42/17)')" + ) + } + + lm = db::LayerMap::from_string_file_format ("OUTLINE: OUTL (18/1)"); + options.set_layer_map (lm); + options.set_cell_outline_layer ("OUTLINE (42/17)"); + + { + db::Layout layout; + db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false); + EXPECT_EQ (lm_read.to_string (), + "layer_map('OUTLINE : OUTL (18/1)')" + ) + } + + options.set_cell_outline_layer ("OUTLINE (42/17)"); + lm = db::LayerMap::from_string_file_format ("42/17: OUTL (18/1)"); + options.set_layer_map (lm); + + { + db::Layout layout; + db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false); + EXPECT_EQ (lm_read.to_string (), + "layer_map('OUTLINE : OUTL (18/1)')" + ) + } + + options.set_cell_outline_layer ("42/17"); + lm = db::LayerMap::from_string_file_format ("42/17: 18/1"); + options.set_layer_map (lm); + + { + db::Layout layout; + db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false); + EXPECT_EQ (lm_read.to_string (), + "layer_map('OUTLINE : OUTLINE (18/1)')" + ) + } + + } TEST(200_lefdef_plugin) From 3b61255d9b718fefdcc0b58735022a34d4ac219e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 21 Nov 2020 21:06:05 +0100 Subject: [PATCH 04/44] Bugfix, restore previous behavior for empty tech component suffix --- src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index 4cc77b69d..2c47e2984 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -1305,6 +1305,9 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n if (! ll.first) { ll = m_layer_map.logical (n, layout); generic_match = true; + } else if (n == name) { + // no suffix defined in tech component -> treat as generic match and combine datatypes + generic_match = true; } if (ll.first) { From 96898d31d76ef6fc9244b2b8e65e8db547cfcc6f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 21 Nov 2020 21:58:34 +0100 Subject: [PATCH 05/44] LEF/DEF layer map reader test case added. --- .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 16 ++++++++++ testdata/lefdef/mapfile/all.map | 29 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 testdata/lefdef/mapfile/all.map diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index fa446436a..4e71f6032 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -699,8 +699,24 @@ TEST(116_layer_mapping) "layer_map('OUTLINE : OUTLINE (18/1)')" ) } +} +TEST(117_mapfile_all) +{ + db::LEFDEFReaderOptions options = default_options (); + db::Layout layout; + db::LayerMap lm_read = read (layout, "mapfile", "lef:in.lef+def:in.def+map:all.map", options, false); + EXPECT_EQ (lm_read.to_string (), + "layer_map(" + "'OUTLINE : OUTLINE (1/0)';" + "'M1.BLK;M1.LEFOBS;M1.LEFPIN;M1.NET;M1.PIN;M1.SPNET;M1.VIA : \\'M1.NET/PIN/...\\' (22/2)';" + "'\\'M1.NET:1\\' : \\'M1.NET:1\\' (7/0)';" + "'\\'M1.PIN:1\\';\\'M1.SPNET:1\\';\\'M1.VIA:1\\' : \\'M1.NET:1/...\\' (6/0)';" + "'M1.LABEL : M1.LABEL (28/1)';" + "'M1_TEXT.LABEL : M1_TEXT.LABEL (29/0)'" + ")" + ) } TEST(200_lefdef_plugin) diff --git a/testdata/lefdef/mapfile/all.map b/testdata/lefdef/mapfile/all.map new file mode 100644 index 000000000..3a12f0952 --- /dev/null +++ b/testdata/lefdef/mapfile/all.map @@ -0,0 +1,29 @@ +# some variations of map file entries +DIEAREA ALL 1 0 +COMP ALL 2 0 +M1 PIN 3,4 0 +M1 LEFPIN,LEFOBS,PIN,NET,SPNET,VIA1 5 +M1 NET,SPNET,PIN,VIA:MASK:1 6 0 +M1 NET:MASK:1 7 0 +M1 TEXT 8 0 +M1 FILLOPC 9 0 +M1 FILLOPC:MASK:1 10 0 +M1 FILLOPC:MASK:2 11 0 +M1 BLOCKAGEFILL 12 0 +M1 BLOCKAGE 13 0 +M1 FILL 14 0 +M1 VIAFILL,FILL 15 0 +M1 NET,SPNET,CUSTOM 16 0 +M1 VIAFILL:FLOATING,FILL:FLOATING 17 0 +M1 NET:VOLTAGE:0.8 18 0 +M1 VIAFILL 19 0 +M1 VIA:SIZE:0.05x0.05 20 0 +M1 VIA:SIZE:3x3 21 0 +M1 ALL 22 2 +NAME DIEAREA 23 0 +NAME ALL 24 0 +NAME COMP 25 0 +NAME M1/PIN 26 0 +NAME M1/NET 27 0 +NAME M1/SPNET 28 1 +NAME M1_TEXT 29 0 From 363c437d0737d2b73ce73ee8b361f2c38a330865 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 21 Nov 2020 22:05:10 +0100 Subject: [PATCH 06/44] Updated testcase for LEF/DEF map file reader --- testdata/lefdef/mapfile/all.map | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testdata/lefdef/mapfile/all.map b/testdata/lefdef/mapfile/all.map index 3a12f0952..462c62ea3 100644 --- a/testdata/lefdef/mapfile/all.map +++ b/testdata/lefdef/mapfile/all.map @@ -2,7 +2,8 @@ DIEAREA ALL 1 0 COMP ALL 2 0 M1 PIN 3,4 0 -M1 LEFPIN,LEFOBS,PIN,NET,SPNET,VIA1 5 +M1 LEFPIN,LEFOBS,PIN,NET,SPNET,VIA 1 5 +DOES NOT MEAN ANYTHING M1 NET,SPNET,PIN,VIA:MASK:1 6 0 M1 NET:MASK:1 7 0 M1 TEXT 8 0 From 78695f9c233686d25558b53ee60a43ac2c50d6ee Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Dec 2020 12:13:21 +0100 Subject: [PATCH 07/44] WIP: new technology management scheme, libraries can be tech specific, update of technology in layout updates library references --- src/db/db/dbLayout.cc | 151 +++++++++++- src/db/db/dbLayout.h | 23 +- src/db/db/dbLayoutContextHandler.cc | 2 +- src/db/db/dbLibrary.cc | 3 + src/db/db/dbLibraryManager.cc | 46 +++- src/db/db/dbLibraryManager.h | 67 ++++- src/db/db/dbPCellDeclaration.h | 4 +- src/db/db/gsiDeclDbLayout.cc | 20 +- src/db/db/gsiDeclDbLibrary.cc | 45 +++- src/db/unit_tests/dbLibrariesTests.cc | 40 +++ src/edt/edt/edtEditorOptionsPages.cc | 78 +++--- src/edt/edt/edtEditorOptionsPages.h | 15 +- src/edt/edt/edtPCellParametersPage.cc | 231 +++++++++--------- src/edt/edt/edtPCellParametersPage.h | 4 +- src/edt/edt/edtPlugin.cc | 12 +- src/edt/edt/edtRecentConfigurationPage.cc | 26 +- src/edt/edt/edtRecentConfigurationPage.h | 7 +- src/edt/edt/edtServiceImpl.cc | 4 +- src/lay/lay/layLibraryController.cc | 35 ++- src/lay/lay/layLibraryController.h | 10 +- src/lay/lay/layMainWindow.cc | 2 +- src/laybasic/laybasic/layCellView.cc | 26 +- src/laybasic/laybasic/layCellView.h | 6 +- src/laybasic/laybasic/layEditorOptionsPage.cc | 31 ++- src/laybasic/laybasic/layEditorOptionsPage.h | 21 +- .../lefdef/db_plugin/dbLEFDEFImporter.cc | 6 +- .../streamers/magic/db_plugin/dbMAGReader.cc | 6 +- .../streamers/magic/db_plugin/dbMAGReader.h | 2 +- .../streamers/magic/db_plugin/dbMAGWriter.cc | 4 +- 29 files changed, 682 insertions(+), 245 deletions(-) diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 2e767684e..e73be99d4 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -24,6 +24,7 @@ #include "dbLayout.h" #include "dbMemStatistics.h" #include "dbTrans.h" +#include "dbTechnology.h" #include "dbShapeRepository.h" #include "dbPCellHeader.h" #include "dbPCellVariant.h" @@ -442,6 +443,152 @@ Layout::operator= (const Layout &d) return *this; } +const db::Technology * +Layout::technology () const +{ + return db::Technologies::instance ()->technology_by_name (m_tech_name); +} + +void +Layout::set_technology_name (const std::string &tech) +{ + if (tech == m_tech_name) { + return; + } + + // determine which library to map to what + std::map mapping; + std::set seen; + + for (db::Layout::iterator c = begin (); c != end (); ++c) { + + db::LibraryProxy *lib_proxy = dynamic_cast (&*c); + if (lib_proxy && seen.find (lib_proxy->lib_id ()) == seen.end ()) { + + seen.insert (lib_proxy->lib_id ()); + + std::pair new_id (false, 0); + const db::Library *l = db::LibraryManager::instance ().lib (lib_proxy->lib_id ()); + if (l) { + new_id = db::LibraryManager::instance ().lib_by_name (l->get_name (), tech); + } + + if (new_id.first && new_id.second != l->get_id ()) { + mapping.insert (std::make_pair (l->get_id (), new_id.second)); + } + + } + + } + + if (mapping.empty ()) { + + bool needs_cleanup = false; + + std::vector > pcells_to_map; + std::vector lib_cells_to_map; + + for (db::Layout::iterator c = begin (); c != end (); ++c) { + + std::map::const_iterator m; + + db::LibraryProxy *lib_proxy = dynamic_cast (&*c); + if (lib_proxy && (m = mapping.find (lib_proxy->lib_id ())) != mapping.end ()) { + + db::Cell *lib_cell = &cell (lib_proxy->library_cell_index ()); + db::PCellVariant *lib_pcell = dynamic_cast (lib_cell); + if (lib_pcell) { + pcells_to_map.push_back (std::make_pair (lib_proxy, lib_pcell)); + } else { + lib_cells_to_map.push_back (lib_proxy); + } + + needs_cleanup = true; + + } + + } + + // We do PCell resolution before the library proxy resolution. The reason is that + // PCells may generate library proxies in their instantiation. Hence we must instantiate + // the PCells before we can resolve them. + for (std::vector >::const_iterator lp = pcells_to_map.begin (); lp != pcells_to_map.end (); ++lp) { + + db::cell_index_type ci = lp->first->Cell::cell_index (); + db::PCellVariant *lib_pcell = lp->second; + + std::pair pn = lib_pcell->layout ()->pcell_by_name (lp->first->get_basic_name ().c_str ()); + + if (! pn.first) { + + // substitute by static layout cell + // @@@ TODO: keep reference so we don't loose the connection immediately. + std::string name = cell_name (ci); + db::Cell *old_cell = take_cell (ci); + insert_cell (ci, name, new db::Cell (*old_cell)); + delete old_cell; + + } else { + + db::Library *new_lib = db::LibraryManager::instance ().lib (mapping [lp->first->lib_id ()]); + + const db::PCellDeclaration *old_pcell_decl = lib_pcell->layout ()->pcell_declaration (lib_pcell->pcell_id ()); + const db::PCellDeclaration *new_pcell_decl = new_lib->layout ().pcell_declaration (pn.second); + if (! old_pcell_decl || ! new_pcell_decl) { + + // substitute by static layout cell + // @@@ TODO: keep reference so we don't loose the connection immediately. + std::string name = cell_name (ci); + db::Cell *old_cell = take_cell (ci); + insert_cell (ci, name, new db::Cell (*old_cell)); + delete old_cell; + + } else { + + // map pcell parameters by name + std::map param_by_name = lib_pcell->parameters_by_name (); + lp->first->remap (new_lib->get_id (), new_lib->layout ().get_pcell_variant (pn.second, new_pcell_decl->map_parameters (param_by_name))); + + } + + } + + } + + for (std::vector::const_iterator lp = lib_cells_to_map.begin (); lp != lib_cells_to_map.end (); ++lp) { + + db::Library *new_lib = db::LibraryManager::instance ().lib (mapping [(*lp)->lib_id ()]); + + db::cell_index_type ci = (*lp)->Cell::cell_index (); + + std::pair cn = new_lib->layout ().cell_by_name ((*lp)->get_basic_name ().c_str ()); + + if (! cn.first) { + + // unlink this proxy: substitute by static layout cell + // @@@ TODO: keep reference so we don't loose the connection immediately. + std::string name = cell_name (ci); + db::Cell *old_cell = take_cell (ci); + insert_cell (ci, name, new db::Cell (*old_cell)); + delete old_cell; + + } else { + + (*lp)->remap (new_lib->get_id (), cn.second); + + } + + } + + if (needs_cleanup) { + cleanup (); + } + + } + + m_tech_name = tech; +} + void Layout::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const { @@ -2224,7 +2371,7 @@ Layout::recover_proxy_as (cell_index_type cell_index, std::vector : if (ex.test ("LIB=")) { std::string lib_name = ex.skip (); - Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name); + Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name, m_tech_name); if (! lib) { return false; } @@ -2284,7 +2431,7 @@ Layout::recover_proxy (std::vector ::const_iterator from, std::vect if (ex.test ("LIB=")) { std::string lib_name = ex.skip (); - Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name); + Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name, m_tech_name); if (! lib) { return 0; } diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index f1555cb61..c79629567 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -67,6 +67,7 @@ class Region; class Edges; class EdgePairs; class Texts; +class Technology; class CellMapping; class LayerMapping; @@ -555,10 +556,29 @@ public: } /** - * @brief Clear the layout + * @brief Clears the layout */ void clear (); + /** + * @brief Gets the technology name the layout is associated with + */ + const std::string &technology_name () const + { + return m_tech_name; + } + + /** + * @brief Gets the technology object the layout is associated with or null if no valid technology is associated + */ + const db::Technology *technology () const; + + /** + * @brief Changes the technology, the layout is associated with + * Changing the layout may re-assess all the library references as libraries can be technology specific + */ + void set_technology_name (const std::string &tech); + /** * @brief Accessor to the array repository */ @@ -1779,6 +1799,7 @@ private: bool m_do_cleanup; bool m_editable; meta_info m_meta_info; + std::string m_tech_name; tl::Mutex m_lock; /** diff --git a/src/db/db/dbLayoutContextHandler.cc b/src/db/db/dbLayoutContextHandler.cc index 5c6bf49fb..90cff6c50 100644 --- a/src/db/db/dbLayoutContextHandler.cc +++ b/src/db/db/dbLayoutContextHandler.cc @@ -80,7 +80,7 @@ tl::Variant LayoutContextHandler::eval_double_bracket (const std::string &s) con std::string tail = cp + 1; - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname, mp_layout->technology_name ()); if (! lib) { throw tl::Exception (tl::to_string (tr ("Not a valid library name: ")) + libname); } diff --git a/src/db/db/dbLibrary.cc b/src/db/db/dbLibrary.cc index 0e10fe3e9..3103f0c56 100644 --- a/src/db/db/dbLibrary.cc +++ b/src/db/db/dbLibrary.cc @@ -192,6 +192,7 @@ Library::remap_to (db::Library *other) if (! pn.first) { // substitute by static layout cell + // @@@ TODO: keep reference so we don't loose the connection immediately. std::string name = r->first->cell_name (ci); db::Cell *old_cell = r->first->take_cell (ci); r->first->insert_cell (ci, name, new db::Cell (*old_cell)); @@ -204,6 +205,7 @@ Library::remap_to (db::Library *other) if (! old_pcell_decl || ! new_pcell_decl) { // substitute by static layout cell + // @@@ TODO: keep reference so we don't loose the connection immediately. std::string name = r->first->cell_name (ci); db::Cell *old_cell = r->first->take_cell (ci); r->first->insert_cell (ci, name, new db::Cell (*old_cell)); @@ -233,6 +235,7 @@ Library::remap_to (db::Library *other) if (! cn.first) { // unlink this proxy: substitute by static layout cell + // @@@ TODO: keep reference so we don't loose the connection immediately. std::string name = r->first->cell_name (ci); db::Cell *old_cell = r->first->take_cell (ci); r->first->insert_cell (ci, name, new db::Cell (*old_cell)); diff --git a/src/db/db/dbLibraryManager.cc b/src/db/db/dbLibraryManager.cc index ba8f2b685..8a8a0ff9e 100644 --- a/src/db/db/dbLibraryManager.cc +++ b/src/db/db/dbLibraryManager.cc @@ -66,14 +66,24 @@ LibraryManager::~LibraryManager () } std::pair -LibraryManager::lib_by_name (const std::string &name) const +LibraryManager::lib_by_name (const std::string &name, const std::set &for_technologies) const { iterator l = m_lib_by_name.find (name); - if (l == m_lib_by_name.end ()) { - return std::make_pair (false, lib_id_type (0)); - } else { - return std::make_pair (true, l->second); + while (l != m_lib_by_name.end () && l->first == name) { + bool found = true; + for (std::set::const_iterator t = for_technologies.begin (); t != for_technologies.end (); ++t) { + if (! lib (l->second)->is_for_technology (*t)) { + found = false; + break; + } + } + if (found) { + return std::make_pair (true, l->second); + } + ++l; } + + return std::make_pair (false, lib_id_type (0)); } void @@ -116,14 +126,28 @@ LibraryManager::register_lib (Library *library) library->set_id (id); // if the new library replaces the old one, remap existing library proxies before deleting the library - lib_name_map::iterator ln = m_lib_by_name.find (library->get_name ()); - if (ln != m_lib_by_name.end () && m_libs [ln->second]) { - m_libs [ln->second]->remap_to (library); - delete m_libs [ln->second]; - m_libs [ln->second] = 0; + // (replacement is done only when all technologies are substituted) + lib_name_map::iterator l = m_lib_by_name.find (library->get_name ()); + bool found = false; + while (l != m_lib_by_name.end () && l->first == library->get_name ()) { + if (m_libs [l->second] && m_libs [l->second]->get_technologies () == library->get_technologies ()) { + found = true; + break; + } + ++l; } - m_lib_by_name.insert (std::make_pair (library->get_name (), id)).first->second = id; + if (found) { + // substitute + m_libs [l->second]->remap_to (library); + delete m_libs [l->second]; + m_libs [l->second] = 0; + m_lib_by_name.erase (l); + } + + // insert new lib as first of this name + l = m_lib_by_name.find (library->get_name ()); + m_lib_by_name.insert (l, std::make_pair (library->get_name (), id)); changed_event (); diff --git a/src/db/db/dbLibraryManager.h b/src/db/db/dbLibraryManager.h index 48cf5e0a1..34d9e4428 100644 --- a/src/db/db/dbLibraryManager.h +++ b/src/db/db/dbLibraryManager.h @@ -33,6 +33,7 @@ #include #include #include +#include namespace db { @@ -50,7 +51,7 @@ class Library; class DB_PUBLIC LibraryManager { public: - typedef std::map lib_name_map; + typedef std::multimap lib_name_map; typedef lib_name_map::const_iterator iterator; /** @@ -90,11 +91,41 @@ public: } /** - * @brief Get the library by name + * @brief Get the library by name which is valid for all given technologies + * + * This method looks up a library which is valid for all technologies listed in "for_technologies". It may be + * responsible for more than that too. * * @return A pair, the boolean is true, if the name is valid. The second member is the library id. */ - std::pair lib_by_name (const std::string &name) const; + std::pair lib_by_name (const std::string &name, const std::set &for_technologies) const; + + /** + * @brief Get the library by name which is valid for the given technology + * + * This method looks up a library which is valid for the given technology. It may be + * responsible for more than that too. + * + * @return A pair, the boolean is true, if the name is valid. The second member is the library id. + */ + std::pair lib_by_name (const std::string &name, const std::string &for_technology) const + { + std::set techs; + if (! for_technology.empty ()) { + techs.insert (for_technology); + } + return lib_by_name (name, techs); + } + + /** + * @brief Get the library by name for any technology + * + * @return A pair, the boolean is true, if the name is valid. The second member is the library id. + */ + std::pair lib_by_name (const std::string &name) const + { + return lib_by_name (name, std::set ()); + } /** * @brief Get the library by name @@ -111,6 +142,36 @@ public: } } + /** + * @brief Get the library by name and technology + * + * @return The pointer to the library or 0, if there is no library with that name. + */ + Library *lib_ptr_by_name (const std::string &name, const std::string &for_technology) const + { + std::pair ll = lib_by_name (name, for_technology); + if (ll.first) { + return lib (ll.second); + } else { + return 0; + } + } + + /** + * @brief Get the library by name and technology + * + * @return The pointer to the library or 0, if there is no library with that name. + */ + Library *lib_ptr_by_name (const std::string &name, const std::set &for_technologies) const + { + std::pair ll = lib_by_name (name, for_technologies); + if (ll.first) { + return lib (ll.second); + } else { + return 0; + } + } + /** * @brief Register a library under the given name and associate a id * diff --git a/src/db/db/dbPCellDeclaration.h b/src/db/db/dbPCellDeclaration.h index 540efa369..e27ad00b0 100644 --- a/src/db/db/dbPCellDeclaration.h +++ b/src/db/db/dbPCellDeclaration.h @@ -29,6 +29,7 @@ #include "gsiObject.h" #include "dbLayout.h" #include "tlVariant.h" +#include "tlObject.h" namespace db { @@ -327,7 +328,8 @@ public: * @brief A declaration for a PCell */ class DB_PUBLIC PCellDeclaration - : public gsi::ObjectBase + : public gsi::ObjectBase, + public tl::Object { public: /** diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index 2e85264b4..e9539343d 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -39,6 +39,7 @@ #include "dbLayoutUtils.h" #include "dbLayerMapping.h" #include "dbCellMapping.h" +#include "dbTechnology.h" #include "tlStream.h" namespace gsi @@ -750,7 +751,7 @@ static db::Cell *create_cell2 (db::Layout *layout, const std::string &name, cons static db::Cell *create_cell3 (db::Layout *layout, const std::string &name, const std::string &libname) { - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname, layout->technology_name ()); if (! lib) { return 0; } @@ -765,7 +766,7 @@ static db::Cell *create_cell3 (db::Layout *layout, const std::string &name, cons static db::Cell *create_cell4 (db::Layout *layout, const std::string &name, const std::string &libname, const std::map ¶ms) { - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname, layout->technology_name ()); if (! lib) { return 0; } @@ -988,6 +989,21 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been introduced in version 0.25." ) + + gsi::method ("technology_name", &db::Layout::technology_name, + "@brief Gets the name of the technology this layout is associated with\n" + "This method has been introduced in version 0.27. Before that, the technology has been kept in the 'technology' meta data element." + ) + + gsi::method ("technology", &db::Layout::technology, + "@brief Gets the \\Technology object of the technology this layout is associated with or nil if the layout is not associated with a technology\n" + "This method has been introduced in version 0.27. Before that, the technology has been kept in the 'technology' meta data element." + ) + + gsi::method ("technology_name=", &db::Layout::set_technology_name, gsi::arg ("name"), + "@brief Sets the name of the technology this layout is associated with\n" + "Changing the technology name will re-assess all library references because libraries can be technology specified. " + "Cell layouts may be substituted during this re-assessment.\n" + "\n" + "This method has been introduced in version 0.27." + ) + gsi::method ("is_editable?", &db::Layout::is_editable, "@brief Returns a value indicating whether the layout is editable.\n" "@return True, if the layout is editable.\n" diff --git a/src/db/db/gsiDeclDbLibrary.cc b/src/db/db/gsiDeclDbLibrary.cc index 0476a5087..a156b6375 100644 --- a/src/db/db/gsiDeclDbLibrary.cc +++ b/src/db/db/gsiDeclDbLibrary.cc @@ -43,9 +43,14 @@ static db::Library *new_lib () return new db::Library (); } -static db::Library *library_by_name (const std::string &name) +static db::Library *library_by_name (const std::string &name, const std::string &for_technology) { - return db::LibraryManager::instance ().lib_ptr_by_name (name); + return db::LibraryManager::instance ().lib_ptr_by_name (name, for_technology); +} + +static db::Library *library_by_id (db::lib_id_type id) +{ + return db::LibraryManager::instance ().lib (id); } static std::vector library_names () @@ -57,6 +62,15 @@ static std::vector library_names () return r; } +static std::vector library_ids () +{ + std::vector r; + for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) { + r.push_back (l->second); + } + return r; +} + static void register_lib (db::Library *lib, const std::string &name) { lib->set_name (name); @@ -110,22 +124,45 @@ LibraryClass decl_Library ("db", "Library", gsi::constructor ("new", &new_lib, "@brief Creates a new, empty library" ) + - gsi::method ("library_by_name", &library_by_name, gsi::arg ("name"), + gsi::method ("library_by_name", &library_by_name, gsi::arg ("name"), gsi::arg ("for_technology", std::string (), "unspecific"), "@brief Gets a library by name\n" "Returns the library object for the given name. If the name is not a valid\n" "library name, nil is returned.\n" + "\n" + "Different libraries can be registered under the same names for different technologies. When a technology name is given in 'for_technologies', " + "the first library matching this technology is returned. If no technology is given, the first library is returned.\n" + "\n" + "The technology selector has been introduced in version 0.27." + ) + + gsi::method ("library_by_id", &library_by_id, gsi::arg ("id"), + "@brief Gets the library object for the given ID\n" + "If the ID is not valid, nil is returned.\n" + "\n" + "This method has been introduced in version 0.27." ) + gsi::method ("library_names", &library_names, "@brief Returns a list of the names of all libraries registered in the system.\n" + "\n" + "NOTE: starting with version 0.27, the name of a library does not need to be unique if libraries are associated with specific technologies. " + "This method will only return the names and it's not possible not unambiguously derive the library object. It is recommended to use " + "\\library_ids and \\library_by_id to obtain the library unambiguously." + ) + + gsi::method ("library_ids", &library_ids, + "@brief Returns a list of valid library IDs.\n" + "See \\library_names for the reasoning behind this method." + "\n" + "This method has been introduced in version 0.27." ) + gsi::method_ext ("register", ®ister_lib, gsi::arg ("name"), "@brief Registers the library with the given name\n" "\n" "This method can be called in the constructor to register the library after \n" "the layout object has been filled with content. If a library with that name\n" - "already exists, it will be replaced with this library. \n" + "already exists for the same technologies, it will be replaced with this library. \n" "\n" "This method will set the libraries' name.\n" + "\n" + "The technology specific bahvior has been introduced in version 0.27." ) + gsi::method_ext ("delete", &delete_lib, "@brief Deletes the library\n" diff --git a/src/db/unit_tests/dbLibrariesTests.cc b/src/db/unit_tests/dbLibrariesTests.cc index 1be0d58f6..5e81a819c 100644 --- a/src/db/unit_tests/dbLibrariesTests.cc +++ b/src/db/unit_tests/dbLibrariesTests.cc @@ -617,3 +617,43 @@ TEST(3) } } +TEST(4) +{ + LIBT_A *lib_a1 = new LIBT_A (); + lib_a1->add_technology ("X"); + db::LibraryManager::instance ().register_lib (lib_a1); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a1->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ()); + + LIBT_A *lib_a2 = new LIBT_A (); + lib_a2->add_technology ("Y"); + db::LibraryManager::instance ().register_lib (lib_a2); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a2->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); + + LIBT_A *lib_a3 = new LIBT_A (); + lib_a3->add_technology ("X"); + db::LibraryManager::instance ().register_lib (lib_a3); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a3->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); +} + diff --git a/src/edt/edt/edtEditorOptionsPages.cc b/src/edt/edt/edtEditorOptionsPages.cc index 5cf86b819..b8c944587 100644 --- a/src/edt/edt/edtEditorOptionsPages.cc +++ b/src/edt/edt/edtEditorOptionsPages.cc @@ -69,8 +69,8 @@ static void configure_from_line_edit (lay::Dispatcher *dispatcher, QLineEdit *le // ------------------------------------------------------------------ // EditorOptionsGeneric implementation -EditorOptionsGeneric::EditorOptionsGeneric (lay::Dispatcher *dispatcher) - : EditorOptionsPage (dispatcher) +EditorOptionsGeneric::EditorOptionsGeneric (lay::LayoutView *view, lay::Dispatcher *dispatcher) + : EditorOptionsPage (view, dispatcher) { mp_ui = new Ui::EditorOptionsGeneric (); mp_ui->setupUi (this); @@ -206,8 +206,8 @@ EditorOptionsGeneric::setup (lay::Dispatcher *root) // ------------------------------------------------------------------ // EditorOptionsText implementation -EditorOptionsText::EditorOptionsText (lay::Dispatcher *dispatcher) - : lay::EditorOptionsPage (dispatcher) +EditorOptionsText::EditorOptionsText (lay::LayoutView *view, lay::Dispatcher *dispatcher) + : lay::EditorOptionsPage (view, dispatcher) { mp_ui = new Ui::EditorOptionsText (); mp_ui->setupUi (this); @@ -284,8 +284,8 @@ EditorOptionsText::setup (lay::Dispatcher *root) // ------------------------------------------------------------------ // EditorOptionsPath implementation -EditorOptionsPath::EditorOptionsPath (lay::Dispatcher *dispatcher) - : lay::EditorOptionsPage (dispatcher) +EditorOptionsPath::EditorOptionsPath (lay::LayoutView *view, lay::Dispatcher *dispatcher) + : lay::EditorOptionsPage (view, dispatcher) { mp_ui = new Ui::EditorOptionsPath (); mp_ui->setupUi (this); @@ -385,8 +385,8 @@ EditorOptionsPath::setup (lay::Dispatcher *root) // ------------------------------------------------------------------ // EditorOptionsInst implementation -EditorOptionsInst::EditorOptionsInst (lay::Dispatcher *dispatcher) - : lay::EditorOptionsPage (dispatcher) +EditorOptionsInst::EditorOptionsInst (lay::LayoutView *view, lay::Dispatcher *dispatcher) + : lay::EditorOptionsPage (view, dispatcher) { mp_ui = new Ui::EditorOptionsInst (); mp_ui->setupUi (this); @@ -579,21 +579,35 @@ EditorOptionsInst::apply (lay::Dispatcher *root) root->config_set (cfg_edit_inst_place_origin, tl::to_string (place_origin)); } -void +void +EditorOptionsInst::technology_changed (const std::string &) +{ + // The layout's technology has changed + setup (dispatcher ()); +} + +void +EditorOptionsInst::active_cellview_changed () +{ + // The active cellview has changed + setup (dispatcher ()); +} + +void EditorOptionsInst::setup (lay::Dispatcher *root) { - m_cv_index = -1; - if (lay::LayoutView::current ()) { - m_cv_index = lay::LayoutView::current ()->active_cellview_index (); - } + m_cv_index = view ()->active_cellview_index (); try { mp_ui->lib_cbx->blockSignals (true); + std::string techname; + mp_ui->lib_cbx->update_list (); if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) { - mp_ui->lib_cbx->set_technology_filter (lay::LayoutView::current ()->cellview (m_cv_index)->tech_name (), true); + techname = lay::LayoutView::current ()->cellview (m_cv_index)->tech_name (); + mp_ui->lib_cbx->set_technology_filter (techname, true); } else { mp_ui->lib_cbx->set_technology_filter (std::string (), false); } @@ -606,7 +620,7 @@ EditorOptionsInst::setup (lay::Dispatcher *root) // library std::string l; root->config_get (cfg_edit_inst_lib_name, l); - mp_ui->lib_cbx->set_current_library (db::LibraryManager::instance ().lib_ptr_by_name (l)); + mp_ui->lib_cbx->set_current_library (db::LibraryManager::instance ().lib_ptr_by_name (l, techname)); mp_ui->lib_cbx->blockSignals (false); update_cell_edits (); @@ -667,8 +681,8 @@ EditorOptionsInst::setup (lay::Dispatcher *root) // ------------------------------------------------------------------ // EditorOptionsInstPCellParam implementation -EditorOptionsInstPCellParam::EditorOptionsInstPCellParam (lay::Dispatcher *dispatcher) - : lay::EditorOptionsPage (dispatcher), mp_pcell_parameters (0), mp_placeholder_label (0) +EditorOptionsInstPCellParam::EditorOptionsInstPCellParam (lay::LayoutView *view, lay::Dispatcher *dispatcher) + : lay::EditorOptionsPage (view, dispatcher), mp_pcell_parameters (0), mp_placeholder_label (0) { mp_ui = new Ui::EditorOptionsInstPCellParam (); mp_ui->setupUi (this); @@ -693,7 +707,7 @@ EditorOptionsInstPCellParam::apply (lay::Dispatcher *root) std::string param; db::Layout *layout = 0; - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview_ref ()->tech_name ()); if (lib) { layout = &lib->layout (); } else if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) { @@ -717,13 +731,16 @@ EditorOptionsInstPCellParam::apply (lay::Dispatcher *root) } } +void +EditorOptionsInstPCellParam::technology_changed (const std::string &) +{ + setup (dispatcher ()); +} + void EditorOptionsInstPCellParam::setup (lay::Dispatcher *root) { - m_cv_index = -1; - if (lay::LayoutView::current ()) { - m_cv_index = lay::LayoutView::current ()->active_cellview_index (); - } + m_cv_index = view ()->active_cellview_index (); bool needs_update = (mp_pcell_parameters == 0); @@ -743,7 +760,7 @@ EditorOptionsInstPCellParam::setup (lay::Dispatcher *root) needs_update = true; } - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview_ref ()->tech_name ()); // pcell parameters std::string param; @@ -752,8 +769,8 @@ EditorOptionsInstPCellParam::setup (lay::Dispatcher *root) db::Layout *layout = 0; if (lib) { layout = &lib->layout (); - } else if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) { - layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout (); + } else if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) { + layout = &view ()->cellview (m_cv_index)->layout (); } std::vector pv; @@ -820,15 +837,14 @@ void EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector ¶meters) { db::Layout *layout = 0; - lay::LayoutView *view = lay::LayoutView::current (); // find the layout the cell has to be looked up: that is either the layout of the current instance or // the library selected - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview_ref ()->tech_name ()); if (lib) { layout = &lib->layout (); - } else if (view) { - const lay::CellView &cv = view->cellview (m_cv_index); + } else { + const lay::CellView &cv = view ()->cellview (m_cv_index); if (cv.is_valid ()) { layout = &cv->layout (); } @@ -856,10 +872,10 @@ EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector pcell_declaration (pc.second) && view && view->cellview (m_cv_index).is_valid ()) { + if (pc.first && layout->pcell_declaration (pc.second) && view ()->cellview (m_cv_index).is_valid ()) { mp_pcell_parameters = new PCellParametersPage (this, true /*dense*/); - mp_pcell_parameters->setup (&view->cellview (m_cv_index)->layout (), view, m_cv_index, layout->pcell_declaration (pc.second), parameters); + mp_pcell_parameters->setup (&view ()->cellview (m_cv_index)->layout (), view (), m_cv_index, layout->pcell_declaration (pc.second), parameters); this->layout ()->addWidget (mp_pcell_parameters); mp_pcell_parameters->set_state (pcp_state); diff --git a/src/edt/edt/edtEditorOptionsPages.h b/src/edt/edt/edtEditorOptionsPages.h index 3b639c5d8..92b697198 100644 --- a/src/edt/edt/edtEditorOptionsPages.h +++ b/src/edt/edt/edtEditorOptionsPages.h @@ -51,6 +51,7 @@ namespace lay { class PluginDeclaration; class Dispatcher; + class LayoutView; class Plugin; } @@ -68,7 +69,7 @@ class EditorOptionsGeneric Q_OBJECT public: - EditorOptionsGeneric (lay::Dispatcher *dispatcher); + EditorOptionsGeneric (lay::LayoutView *view, lay::Dispatcher *dispatcher); ~EditorOptionsGeneric (); virtual std::string title () const; @@ -91,7 +92,7 @@ class EditorOptionsText : public lay::EditorOptionsPage { public: - EditorOptionsText (lay::Dispatcher *dispatcher); + EditorOptionsText (lay::LayoutView *view, lay::Dispatcher *dispatcher); ~EditorOptionsText (); virtual std::string title () const; @@ -112,7 +113,7 @@ class EditorOptionsPath Q_OBJECT public: - EditorOptionsPath (lay::Dispatcher *dispatcher); + EditorOptionsPath (lay::LayoutView *view, lay::Dispatcher *dispatcher); ~EditorOptionsPath (); virtual std::string title () const; @@ -136,7 +137,7 @@ class EditorOptionsInst Q_OBJECT public: - EditorOptionsInst (lay::Dispatcher *root); + EditorOptionsInst (lay::LayoutView *view, lay::Dispatcher *root); ~EditorOptionsInst (); virtual std::string title () const; @@ -154,6 +155,9 @@ private: Ui::EditorOptionsInst *mp_ui; edt::PCellParametersPage *mp_pcell_parameters; int m_cv_index; + + virtual void technology_changed (const std::string &); + virtual void active_cellview_changed (); }; /** @@ -165,7 +169,7 @@ class EditorOptionsInstPCellParam Q_OBJECT public: - EditorOptionsInstPCellParam (lay::Dispatcher *root); + EditorOptionsInstPCellParam (lay::LayoutView *view, lay::Dispatcher *root); ~EditorOptionsInstPCellParam (); virtual std::string title () const; @@ -184,6 +188,7 @@ private: std::string m_lib_name, m_cell_name; void update_pcell_parameters (const std::vector ¶meters); + virtual void technology_changed (const std::string &); }; } diff --git a/src/edt/edt/edtPCellParametersPage.cc b/src/edt/edt/edtPCellParametersPage.cc index 01b667002..5908c8d36 100644 --- a/src/edt/edt/edtPCellParametersPage.cc +++ b/src/edt/edt/edtPCellParametersPage.cc @@ -153,7 +153,7 @@ PCellParametersPage::PCellParametersPage (QWidget *parent, bool dense) void PCellParametersPage::init () { - mp_pcell_decl = 0; + mp_pcell_decl.reset (0); mp_layout = 0; mp_view = 0; m_cv_index = 0; @@ -185,7 +185,7 @@ PCellParametersPage::init () void PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters) { - mp_pcell_decl = pcell_decl; + mp_pcell_decl.reset (const_cast (pcell_decl)); // no const weak_ptr ... mp_layout = layout; mp_view = view; m_cv_index = cv_index; @@ -457,131 +457,136 @@ std::vector PCellParametersPage::get_parameters (bool *ok) { std::vector parameters; - bool edit_error = true; - int r = 0; - const std::vector &pcp = mp_pcell_decl->parameter_declarations (); - for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) { + try { - if (p->is_hidden () || p->get_type () == db::PCellParameterDeclaration::t_shape) { + if (! mp_pcell_decl) { + throw tl::Exception (tl::to_string (tr ("PCell no longer valid."))); + } - if (r < (int) m_parameters.size ()) { - parameters.push_back (m_parameters [r]); - } else { - parameters.push_back (p->get_default ()); - } + bool edit_error = true; - } else { + int r = 0; + const std::vector &pcp = mp_pcell_decl->parameter_declarations (); + for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) { - parameters.push_back (tl::Variant ()); + if (p->is_hidden () || p->get_type () == db::PCellParameterDeclaration::t_shape) { - if (p->get_choices ().empty ()) { - - switch (p->get_type ()) { - - case db::PCellParameterDeclaration::t_int: - { - QLineEdit *le = dynamic_cast (m_widgets [r]); - if (le) { - - try { - - int v = 0; - tl::from_string (tl::to_string (le->text ()), v); - - parameters.back () = tl::Variant (v); - lay::indicate_error (le, 0); - - } catch (tl::Exception &ex) { - - lay::indicate_error (le, &ex); - edit_error = false; - - } - - } - } - break; - - case db::PCellParameterDeclaration::t_double: - { - QLineEdit *le = dynamic_cast (m_widgets [r]); - if (le) { - - try { - - double v = 0; - tl::from_string (tl::to_string (le->text ()), v); - - parameters.back () = tl::Variant (v); - lay::indicate_error (le, 0); - - } catch (tl::Exception &ex) { - - lay::indicate_error (le, &ex); - edit_error = false; - - } - - } - } - break; - - case db::PCellParameterDeclaration::t_string: - { - QLineEdit *le = dynamic_cast (m_widgets [r]); - if (le) { - parameters.back () = tl::Variant (tl::to_string (le->text ())); - } - } - break; - - case db::PCellParameterDeclaration::t_list: - { - QLineEdit *le = dynamic_cast (m_widgets [r]); - if (le) { - std::vector values = tl::split (tl::to_string (le->text ()), ","); - parameters.back () = tl::Variant (values.begin (), values.end ()); - } - } - break; - - case db::PCellParameterDeclaration::t_layer: - { - lay::LayerSelectionComboBox *ly = dynamic_cast (m_widgets [r]); - if (ly) { - parameters.back () = tl::Variant (ly->current_layer_props ()); - } - } - break; - case db::PCellParameterDeclaration::t_boolean: - { - QCheckBox *cbx = dynamic_cast (m_widgets [r]); - if (cbx) { - parameters.back () = tl::Variant (cbx->isChecked ()); - } - } - break; - - default: - break; + if (r < (int) m_parameters.size ()) { + parameters.push_back (m_parameters [r]); + } else { + parameters.push_back (p->get_default ()); } } else { - QComboBox *cb = dynamic_cast (m_widgets [r]); - if (cb && cb->currentIndex () >= 0 && cb->currentIndex () < int (p->get_choices ().size ())) { - parameters.back () = p->get_choices () [cb->currentIndex ()]; + parameters.push_back (tl::Variant ()); + + if (p->get_choices ().empty ()) { + + switch (p->get_type ()) { + + case db::PCellParameterDeclaration::t_int: + { + QLineEdit *le = dynamic_cast (m_widgets [r]); + if (le) { + + try { + + int v = 0; + tl::from_string (tl::to_string (le->text ()), v); + + parameters.back () = tl::Variant (v); + lay::indicate_error (le, 0); + + } catch (tl::Exception &ex) { + + lay::indicate_error (le, &ex); + edit_error = false; + + } + + } + } + break; + + case db::PCellParameterDeclaration::t_double: + { + QLineEdit *le = dynamic_cast (m_widgets [r]); + if (le) { + + try { + + double v = 0; + tl::from_string (tl::to_string (le->text ()), v); + + parameters.back () = tl::Variant (v); + lay::indicate_error (le, 0); + + } catch (tl::Exception &ex) { + + lay::indicate_error (le, &ex); + edit_error = false; + + } + + } + } + break; + + case db::PCellParameterDeclaration::t_string: + { + QLineEdit *le = dynamic_cast (m_widgets [r]); + if (le) { + parameters.back () = tl::Variant (tl::to_string (le->text ())); + } + } + break; + + case db::PCellParameterDeclaration::t_list: + { + QLineEdit *le = dynamic_cast (m_widgets [r]); + if (le) { + std::vector values = tl::split (tl::to_string (le->text ()), ","); + parameters.back () = tl::Variant (values.begin (), values.end ()); + } + } + break; + + case db::PCellParameterDeclaration::t_layer: + { + lay::LayerSelectionComboBox *ly = dynamic_cast (m_widgets [r]); + if (ly) { + parameters.back () = tl::Variant (ly->current_layer_props ()); + } + } + break; + case db::PCellParameterDeclaration::t_boolean: + { + QCheckBox *cbx = dynamic_cast (m_widgets [r]); + if (cbx) { + parameters.back () = tl::Variant (cbx->isChecked ()); + } + } + break; + + default: + break; + } + + } else { + + QComboBox *cb = dynamic_cast (m_widgets [r]); + if (cb && cb->currentIndex () >= 0 && cb->currentIndex () < int (p->get_choices ().size ())) { + parameters.back () = p->get_choices () [cb->currentIndex ()]; + } + } } } - } - - try { - if (! edit_error) { throw tl::Exception (tl::to_string (tr ("There are errors. See the highlighted edit fields for details."))); } @@ -628,6 +633,10 @@ PCellParametersPage::get_parameters (bool *ok) void PCellParametersPage::set_parameters (const std::vector ¶meters) { + if (! mp_pcell_decl) { + return; + } + // write the changed value back size_t r = 0; const std::vector &pcp = mp_pcell_decl->parameter_declarations (); diff --git a/src/edt/edt/edtPCellParametersPage.h b/src/edt/edt/edtPCellParametersPage.h index 9786a2c8b..158a3cb07 100644 --- a/src/edt/edt/edtPCellParametersPage.h +++ b/src/edt/edt/edtPCellParametersPage.h @@ -104,7 +104,7 @@ public: */ const db::PCellDeclaration *pcell_decl () const { - return mp_pcell_decl; + return mp_pcell_decl.get (); } /** @@ -122,7 +122,7 @@ private: QScrollArea *mp_parameters_area; QLabel *mp_error_label; QLabel *mp_error_icon; - const db::PCellDeclaration *mp_pcell_decl; + tl::weak_ptr mp_pcell_decl; std::vector m_widgets; const db::Layout *mp_layout; lay::LayoutView *mp_view; diff --git a/src/edt/edt/edtPlugin.cc b/src/edt/edt/edtPlugin.cc index 1cf07b535..8f7aa14c2 100644 --- a/src/edt/edt/edtPlugin.cc +++ b/src/edt/edt/edtPlugin.cc @@ -75,7 +75,7 @@ void get_text_editor_options_pages (std::vector &ret, ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-text-param", &text_cfg_descriptors[0], &text_cfg_descriptors[sizeof (text_cfg_descriptors) / sizeof (text_cfg_descriptors[0])])); - ret.push_back (new edt::EditorOptionsText (dispatcher)); + ret.push_back (new edt::EditorOptionsText (view, dispatcher)); } static @@ -101,7 +101,7 @@ void get_path_editor_options_pages (std::vector &ret, ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-path-param", &path_cfg_descriptors[0], &path_cfg_descriptors[sizeof (path_cfg_descriptors) / sizeof (path_cfg_descriptors[0])])); - ret.push_back (new EditorOptionsPath (dispatcher)); + ret.push_back (new EditorOptionsPath (view, dispatcher)); } static @@ -145,8 +145,8 @@ void get_inst_editor_options_pages (std::vector &ret, ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-inst-param", &inst_cfg_descriptors[0], &inst_cfg_descriptors[sizeof (inst_cfg_descriptors) / sizeof (inst_cfg_descriptors[0])])); - ret.push_back (new EditorOptionsInstPCellParam (dispatcher)); - ret.push_back (new EditorOptionsInst (dispatcher)); + ret.push_back (new EditorOptionsInstPCellParam (view, dispatcher)); + ret.push_back (new EditorOptionsInst (view, dispatcher)); } template @@ -327,10 +327,10 @@ public: return false; } - virtual void get_editor_options_pages (std::vector &pages, lay::LayoutView * /*view*/, lay::Dispatcher *dispatcher) const + virtual void get_editor_options_pages (std::vector &pages, lay::LayoutView *view, lay::Dispatcher *dispatcher) const { // NOTE: we do not set plugin_declaration which makes the page unspecific - EditorOptionsGeneric *generic_opt = new EditorOptionsGeneric (dispatcher); + EditorOptionsGeneric *generic_opt = new EditorOptionsGeneric (view, dispatcher); pages.push_back (generic_opt); } diff --git a/src/edt/edt/edtRecentConfigurationPage.cc b/src/edt/edt/edtRecentConfigurationPage.cc index 554f85be0..4c5726b8f 100644 --- a/src/edt/edt/edtRecentConfigurationPage.cc +++ b/src/edt/edt/edtRecentConfigurationPage.cc @@ -55,7 +55,7 @@ RecentConfigurationPage::init () ly->addWidget (mp_tree_widget); connect (mp_tree_widget, SIGNAL (itemClicked (QTreeWidgetItem *, int)), this, SLOT (item_clicked (QTreeWidgetItem *))); - mp_view->layer_list_changed_event.add (this, &RecentConfigurationPage::layers_changed); + view ()->layer_list_changed_event.add (this, &RecentConfigurationPage::layers_changed); mp_tree_widget->setColumnCount (int (m_cfg.size ())); @@ -166,10 +166,10 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std case RecentConfigurationPage::Layer: { - int icon_size = mp_view->style ()->pixelMetric (QStyle::PM_ButtonIconSize); - lay::LayerPropertiesConstIterator l = lp_iter_from_string (mp_view, values [column]); + int icon_size = view ()->style ()->pixelMetric (QStyle::PM_ButtonIconSize); + lay::LayerPropertiesConstIterator l = lp_iter_from_string (view (), values [column]); if (! l.is_null () && ! l.at_end ()) { - item->setIcon (column, lay::LayerTreeModel::icon_for_layer (l, mp_view, icon_size, icon_size, 0, true)); + item->setIcon (column, lay::LayerTreeModel::icon_for_layer (l, view (), icon_size, icon_size, 0, true)); item->setText (column, tl::to_qstring (values [column])); } else { item->setIcon (column, QIcon ()); @@ -219,7 +219,7 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std const db::Library *lib = 0; for (std::list::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++libname_column) { if (c->rendering == RecentConfigurationPage::CellLibraryName) { - lib = db::LibraryManager::instance ().lib_ptr_by_name (values [libname_column]); + lib = db::LibraryManager::instance ().lib_ptr_by_name (values [libname_column], view ()->active_cellview_ref ()->tech_name ()); break; } } @@ -278,6 +278,12 @@ RecentConfigurationPage::layers_changed (int) update_list (get_stored_values ()); } +void +RecentConfigurationPage::technology_changed (const std::string &) +{ + update_list (get_stored_values ()); +} + void RecentConfigurationPage::update_list (const std::list > &stored_values) { @@ -327,7 +333,7 @@ RecentConfigurationPage::item_clicked (QTreeWidgetItem *item) ex.read (cv_index); } - mp_view->set_or_request_current_layer (cv_index, lp); + view ()->set_or_request_current_layer (cv_index, lp); } else { dispatcher ()->config_set (c->cfg_name, v); @@ -349,11 +355,11 @@ RecentConfigurationPage::commit_recent (lay::Dispatcher *root) std::string s; - if (!(mp_view->current_layer ().is_null () || mp_view->current_layer ().at_end ()) && mp_view->current_layer ()->is_visual ()) { + if (!(view ()->current_layer ().is_null () || view ()->current_layer ().at_end ()) && view ()->current_layer ()->is_visual ()) { - int cv_index = mp_view->current_layer ()->cellview_index (); - const lay::CellView &cv = mp_view->cellview (cv_index); - int li = mp_view->current_layer ()->layer_index (); + int cv_index = view ()->current_layer ()->cellview_index (); + const lay::CellView &cv = view ()->cellview (cv_index); + int li = view ()->current_layer ()->layer_index (); if (cv.is_valid () && cv->layout ().is_valid_layer (li)) { s = cv->layout ().get_properties (li).to_string (); if (cv_index > 0) { diff --git a/src/edt/edt/edtRecentConfigurationPage.h b/src/edt/edt/edtRecentConfigurationPage.h index a177be7fb..56b542950 100644 --- a/src/edt/edt/edtRecentConfigurationPage.h +++ b/src/edt/edt/edtRecentConfigurationPage.h @@ -46,8 +46,7 @@ class EditorOptionsPages; * @brief The base class for a object properties page */ class RecentConfigurationPage - : public lay::EditorOptionsPage, - public tl::Object + : public lay::EditorOptionsPage { Q_OBJECT @@ -79,7 +78,7 @@ public: template RecentConfigurationPage (lay::LayoutView *view, lay::Dispatcher *dispatcher, const std::string &recent_cfg_name, Iter begin_cfg, Iter end_cfg) - : EditorOptionsPage (dispatcher), mp_view (view), m_recent_cfg_name (recent_cfg_name), m_cfg (begin_cfg, end_cfg) + : EditorOptionsPage (view, dispatcher), m_recent_cfg_name (recent_cfg_name), m_cfg (begin_cfg, end_cfg) { init (); } @@ -96,7 +95,6 @@ private slots: void item_clicked (QTreeWidgetItem *item); private: - lay::LayoutView *mp_view; std::string m_recent_cfg_name; std::list m_cfg; QTreeWidget *mp_tree_widget; @@ -107,6 +105,7 @@ private: void set_stored_values (const std::list > &values) const; void render_to (QTreeWidgetItem *item, int column, const std::vector &values, RecentConfigurationPage::ConfigurationRendering rendering); void layers_changed (int); + virtual void technology_changed (const std::string &); }; } diff --git a/src/edt/edt/edtServiceImpl.cc b/src/edt/edt/edtServiceImpl.cc index c15bc6106..8f9e048be 100644 --- a/src/edt/edt/edtServiceImpl.cc +++ b/src/edt/edt/edtServiceImpl.cc @@ -1414,7 +1414,7 @@ InstService::make_cell (const lay::CellView &cv) lay::LayerState layer_state = view ()->layer_snapshot (); - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, cv->tech_name ()); // find the layout the cell has to be looked up: that is either the layout of the current instance or // the library selected @@ -1853,8 +1853,8 @@ InstService::switch_cell_or_pcell (bool switch_parameters) } - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name); const lay::CellView &cv = view ()->cellview (m_cv_index); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, cv->tech_name ()); // find the layout the cell has to be looked up: that is either the layout of the current instance or // the library selected diff --git a/src/lay/lay/layLibraryController.cc b/src/lay/lay/layLibraryController.cc index c76f13667..8b4dff669 100644 --- a/src/lay/lay/layLibraryController.cc +++ b/src/lay/lay/layLibraryController.cc @@ -122,7 +122,7 @@ LibraryController::sync_files () m_file_watcher->enable (false); } - std::map > new_lib_files; + std::map new_lib_files; // build a list of paths vs. technology std::vector > paths; @@ -174,11 +174,11 @@ LibraryController::sync_files () QFileInfo fi (tl::to_qstring (lib_path)); bool needs_load = false; - std::map >::iterator ll = m_lib_files.find (lib_path); + std::map::iterator ll = m_lib_files.find (lib_path); if (ll == m_lib_files.end ()) { needs_load = true; } else { - if (fi.lastModified () > ll->second.second) { + if (fi.lastModified () > ll->second.time) { needs_load = true; } else { new_lib_files.insert (*ll); @@ -189,7 +189,9 @@ LibraryController::sync_files () std::auto_ptr lib (new db::Library ()); lib->set_description (filename); - lib->set_technology (p->second); + if (! p->second.empty ()) { + lib->set_technology (p->second); + } lib->set_name (tl::to_string (QFileInfo (*im).baseName ())); tl::log << "Reading library '" << lib_path << "'"; @@ -205,8 +207,19 @@ LibraryController::sync_files () } } - tl::log << "Registering as '" << lib->get_name () << "' for tech '" << p->second << "'"; - new_lib_files.insert (std::make_pair (lib_path, std::make_pair (lib->get_name (), fi.lastModified ()))); + if (! p->second.empty ()) { + tl::log << "Registering as '" << lib->get_name () << "' for tech '" << p->second << "'"; + } else { + tl::log << "Registering as '" << lib->get_name () << "'"; + } + + LibInfo li; + li.name = lib->get_name (); + li.time = fi.lastModified (); + if (! p->second.empty ()) { + li.tech.insert (p->second); + } + new_lib_files.insert (std::make_pair (lib_path, li)); db::LibraryManager::instance ().register_lib (lib.release ()); @@ -230,14 +243,14 @@ LibraryController::sync_files () std::set new_names; - for (std::map >::const_iterator lf = new_lib_files.begin (); lf != new_lib_files.end (); ++lf) { - new_names.insert (lf->second.first); + for (std::map::const_iterator lf = new_lib_files.begin (); lf != new_lib_files.end (); ++lf) { + new_names.insert (lf->second.name); } - for (std::map >::const_iterator lf = m_lib_files.begin (); lf != m_lib_files.end (); ++lf) { - if (new_names.find (lf->second.first) == new_names.end ()) { + for (std::map::const_iterator lf = m_lib_files.begin (); lf != m_lib_files.end (); ++lf) { + if (new_names.find (lf->second.name) == new_names.end ()) { try { - std::pair li = db::LibraryManager::instance ().lib_by_name (lf->second.first); + std::pair li = db::LibraryManager::instance ().lib_by_name (lf->second.name, lf->second.tech); if (li.first) { db::LibraryManager::instance ().delete_lib (db::LibraryManager::instance ().lib (li.second)); } diff --git a/src/lay/lay/layLibraryController.h b/src/lay/lay/layLibraryController.h index 86c0bfdcd..e07f50ade 100644 --- a/src/lay/lay/layLibraryController.h +++ b/src/lay/lay/layLibraryController.h @@ -119,9 +119,17 @@ private slots: void sync_with_external_sources (); private: + struct LibInfo + { + LibInfo () : name (), time (), tech () { } + std::string name; + QDateTime time; + std::set tech; + }; + tl::FileSystemWatcher *m_file_watcher; tl::DeferredMethod dm_sync_files; - std::map > m_lib_files; + std::map m_lib_files; void sync_files (); }; diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index 425f8485f..c0770ab1b 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -2506,7 +2506,7 @@ void MainWindow::cm_new_layout () { std::string technology = m_initial_technology; - static std::string s_new_cell_cell_name; + static std::string s_new_cell_cell_name ("TOP"); static double s_new_cell_window_size = 2.0; double dbu = 0.0; diff --git a/src/laybasic/laybasic/layCellView.cc b/src/laybasic/laybasic/layCellView.cc index 0b28e12d0..e42317c43 100644 --- a/src/laybasic/laybasic/layCellView.cc +++ b/src/laybasic/laybasic/layCellView.cc @@ -206,13 +206,20 @@ LayoutHandle::remove_ref () } } +const std::string & +LayoutHandle::tech_name () const +{ + static std::string s_empty; + return mp_layout ? mp_layout->technology_name () : s_empty; +} + const db::Technology * LayoutHandle::technology () const { - return db::Technologies::instance ()->technology_by_name (m_tech_name); + return mp_layout ? mp_layout->technology () : 0; } -void +void LayoutHandle::apply_technology (const std::string &tn) { set_tech_name (tn); @@ -223,15 +230,8 @@ LayoutHandle::apply_technology (const std::string &tn) void LayoutHandle::set_tech_name (const std::string &tn) { - if (tn != m_tech_name) { - if (db::Technologies::instance ()->has_technology (tn)) { - m_tech_name = tn; - } else { - m_tech_name = std::string (); - } - if (mp_layout) { - mp_layout->add_meta_info (db::MetaInfo ("technology", tl::to_string (tr ("Technology name")), tn)); - } + if (mp_layout && tn != tech_name ()) { + mp_layout->set_technology_name (tn); technology_changed_event (); } } @@ -347,7 +347,7 @@ LayoutHandle::load (const db::LoadLayoutOptions &options, const std::string &tec // If there is no technology given and the reader reports one, use this one if (technology.empty ()) { - std::string tech_from_reader = layout ().meta_info_value ("technology"); + std::string tech_from_reader = layout ().technology_name (); if (! tech_from_reader.empty ()) { set_tech_name (tech_from_reader); } @@ -373,7 +373,7 @@ LayoutHandle::load () db::LayerMap new_lmap = reader.read (layout (), m_load_options); // Attach the technology from the reader if it reports one - std::string tech_from_reader = layout ().meta_info_value ("technology"); + std::string tech_from_reader = layout ().technology_name (); if (! tech_from_reader.empty ()) { set_tech_name (tech_from_reader); } diff --git a/src/laybasic/laybasic/layCellView.h b/src/laybasic/laybasic/layCellView.h index a1040dc6c..5f036b728 100644 --- a/src/laybasic/laybasic/layCellView.h +++ b/src/laybasic/laybasic/layCellView.h @@ -115,10 +115,7 @@ public: * * An empty name indicates the default technology should be used. */ - const std::string &tech_name () const - { - return m_tech_name; - } + const std::string &tech_name () const; /** * @brief Applies the given technology @@ -300,7 +297,6 @@ private: int m_ref_count; std::string m_name; std::string m_filename; - std::string m_tech_name; bool m_dirty; db::SaveLayoutOptions m_save_options; bool m_save_options_valid; diff --git a/src/laybasic/laybasic/layEditorOptionsPage.cc b/src/laybasic/laybasic/layEditorOptionsPage.cc index cc4a92d91..1d90960c6 100644 --- a/src/laybasic/laybasic/layEditorOptionsPage.cc +++ b/src/laybasic/laybasic/layEditorOptionsPage.cc @@ -24,6 +24,7 @@ #include "tlInternational.h" #include "layEditorOptionsPage.h" #include "layEditorOptionsPages.h" +#include "layLayoutView.h" namespace lay { @@ -31,10 +32,10 @@ namespace lay // ------------------------------------------------------------------ // EditorOptionsPage implementation -EditorOptionsPage::EditorOptionsPage (lay::Dispatcher *dispatcher) - : QWidget (0), mp_owner (0), m_active (true), mp_plugin_declaration (0), mp_dispatcher (dispatcher) +EditorOptionsPage::EditorOptionsPage (lay::LayoutView *view, lay::Dispatcher *dispatcher) + : QWidget (0), mp_owner (0), m_active (true), mp_plugin_declaration (0), mp_dispatcher (dispatcher), mp_view (view) { - // nothing yet .. + attach_events (); } EditorOptionsPage::~EditorOptionsPage () @@ -42,6 +43,30 @@ EditorOptionsPage::~EditorOptionsPage () set_owner (0); } +void +EditorOptionsPage::attach_events () +{ + detach_from_all_events (); + view ()->active_cellview_changed_event.add (this, &EditorOptionsPage::on_active_cellview_changed); + int cv_index = view ()->active_cellview_index (); + if (cv_index >= 0) { + view ()->cellview (cv_index)->technology_changed_event.add (this, &EditorOptionsPage::on_technology_changed); + } +} + +void +EditorOptionsPage::on_active_cellview_changed () +{ + active_cellview_changed (); + attach_events (); +} + +void +EditorOptionsPage::on_technology_changed () +{ + technology_changed (view ()->active_cellview_ref ()->tech_name ()); +} + void EditorOptionsPage::set_owner (EditorOptionsPages *owner) { diff --git a/src/laybasic/laybasic/layEditorOptionsPage.h b/src/laybasic/laybasic/layEditorOptionsPage.h index 3ee70b1a0..d6a6dad84 100644 --- a/src/laybasic/laybasic/layEditorOptionsPage.h +++ b/src/laybasic/laybasic/layEditorOptionsPage.h @@ -25,6 +25,8 @@ #include "laybasicCommon.h" +#include "tlObject.h" + #include namespace lay @@ -32,19 +34,21 @@ namespace lay class PluginDeclaration; class Dispatcher; +class LayoutView; class Plugin; +class CellView; class EditorOptionsPages; /** * @brief The base class for a object properties page */ class LAYBASIC_PUBLIC EditorOptionsPage - : public QWidget + : public QWidget, public tl::Object { Q_OBJECT public: - EditorOptionsPage (lay::Dispatcher *dispatcher); + EditorOptionsPage (lay::LayoutView *view, lay::Dispatcher *dispatcher); virtual ~EditorOptionsPage (); virtual std::string title () const = 0; @@ -72,11 +76,24 @@ protected: return mp_dispatcher; } + lay::LayoutView *view () const + { + return mp_view; + } + + virtual void active_cellview_changed () { } + virtual void technology_changed (const std::string & /*tech*/) { } + private: EditorOptionsPages *mp_owner; bool m_active; const lay::PluginDeclaration *mp_plugin_declaration; lay::Dispatcher *mp_dispatcher; + lay::LayoutView *mp_view; + + void on_active_cellview_changed (); + void on_technology_changed (); + void attach_events (); }; } diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index c4628b38c..f8780418a 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -43,11 +43,7 @@ std::string correct_path (const std::string &fn, const db::Layout &layout, const // if a technology is given and the file can be found in the technology's base path, take it // from there. - std::string tn = layout.meta_info_value ("technology"); - const db::Technology *tech = 0; - if (! tn.empty ()) { - tech = db::Technologies::instance ()->technology_by_name (tn); - } + const db::Technology *tech = layout.technology (); if (tech && ! tech->base_path ().empty ()) { std::string new_fn = tl::combine_path (tech->base_path (), fn); diff --git a/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc b/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc index f60be213e..fe7af4cb7 100644 --- a/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc +++ b/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc @@ -74,11 +74,7 @@ MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) { prepare_layers (); - mp_klayout_tech = 0; - std::string klayout_tech_name = layout.meta_info_value ("technology"); - if (! klayout_tech_name.empty () && db::Technologies::instance ()->has_technology (klayout_tech_name)) { - mp_klayout_tech = db::Technologies::instance ()->technology_by_name (klayout_tech_name); - } + mp_klayout_tech = layout.technology (); const db::MAGReaderOptions &specific_options = options.get_options (); m_lambda = specific_options.lambda; diff --git a/src/plugins/streamers/magic/db_plugin/dbMAGReader.h b/src/plugins/streamers/magic/db_plugin/dbMAGReader.h index 8a5fb31a6..3d9d4ecf2 100644 --- a/src/plugins/streamers/magic/db_plugin/dbMAGReader.h +++ b/src/plugins/streamers/magic/db_plugin/dbMAGReader.h @@ -145,7 +145,7 @@ private: std::map m_use_lib_paths; db::VCplxTrans m_dbu_trans_inv; std::string m_tech; - db::Technology *mp_klayout_tech; + const db::Technology *mp_klayout_tech; void do_read (db::Layout &layout, db::cell_index_type to_cell, tl::TextInputStream &stream); void do_read_part (db::Layout &layout, db::cell_index_type cell_index, tl::TextInputStream &stream); diff --git a/src/plugins/streamers/magic/db_plugin/dbMAGWriter.cc b/src/plugins/streamers/magic/db_plugin/dbMAGWriter.cc index 8c54b9f01..eb4b6a743 100644 --- a/src/plugins/streamers/magic/db_plugin/dbMAGWriter.cc +++ b/src/plugins/streamers/magic/db_plugin/dbMAGWriter.cc @@ -122,7 +122,7 @@ MAGWriter::write_dummmy_top (const std::set &cell_set, cons std::string tech = m_options.tech; if (tech.empty ()) { - tech = layout.meta_info_value ("technology"); + tech = layout.technology_name (); } if (! tech.empty ()) { os << "tech " << make_string (tl::to_lower_case (tech)) << "\n"; @@ -177,7 +177,7 @@ MAGWriter::do_write_cell (db::cell_index_type ci, const std::vector Date: Sun, 13 Dec 2020 14:13:59 +0100 Subject: [PATCH 08/44] WIP: bugfixing. --- src/db/db/dbLayout.cc | 5 +++-- src/db/db/dbLibraryManager.cc | 17 ++++++++++---- src/db/unit_tests/dbLibrariesTests.cc | 24 +++++++++++++++++--- src/edt/edt/edtEditorOptionsPages.cc | 27 ++++++++++------------- src/edt/edt/edtRecentConfigurationPage.cc | 6 ++++- src/edt/edt/edtServiceImpl.cc | 7 +++++- src/laybasic/laybasic/layWidgets.cc | 17 +++++++++++--- src/laybasic/laybasic/layWidgets.h | 5 ++++- 8 files changed, 78 insertions(+), 30 deletions(-) diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index e73be99d4..4aa45d4b4 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -481,7 +481,7 @@ Layout::set_technology_name (const std::string &tech) } - if (mapping.empty ()) { + if (! mapping.empty ()) { bool needs_cleanup = false; @@ -495,7 +495,8 @@ Layout::set_technology_name (const std::string &tech) db::LibraryProxy *lib_proxy = dynamic_cast (&*c); if (lib_proxy && (m = mapping.find (lib_proxy->lib_id ())) != mapping.end ()) { - db::Cell *lib_cell = &cell (lib_proxy->library_cell_index ()); + db::Library *lib = db::LibraryManager::instance ().lib (lib_proxy->lib_id ()); + db::Cell *lib_cell = &lib->layout ().cell (lib_proxy->library_cell_index ()); db::PCellVariant *lib_pcell = dynamic_cast (lib_cell); if (lib_pcell) { pcells_to_map.push_back (std::make_pair (lib_proxy, lib_pcell)); diff --git a/src/db/db/dbLibraryManager.cc b/src/db/db/dbLibraryManager.cc index 8a8a0ff9e..2e5e7df86 100644 --- a/src/db/db/dbLibraryManager.cc +++ b/src/db/db/dbLibraryManager.cc @@ -70,11 +70,11 @@ LibraryManager::lib_by_name (const std::string &name, const std::setfirst == name) { - bool found = true; - for (std::set::const_iterator t = for_technologies.begin (); t != for_technologies.end (); ++t) { - if (! lib (l->second)->is_for_technology (*t)) { + const db::Library *lptr = lib (l->second); + bool found = lptr->for_technologies (); + for (std::set::const_iterator t = for_technologies.begin (); t != for_technologies.end () && found; ++t) { + if (! lptr->is_for_technology (*t)) { found = false; - break; } } if (found) { @@ -83,6 +83,15 @@ LibraryManager::lib_by_name (const std::string &name, const std::setfirst == name) { + if (! lib (l->second)->for_technologies ()) { + return std::make_pair (true, l->second); + } + ++l; + } + return std::make_pair (false, lib_id_type (0)); } diff --git a/src/db/unit_tests/dbLibrariesTests.cc b/src/db/unit_tests/dbLibrariesTests.cc index 5e81a819c..971f0df6f 100644 --- a/src/db/unit_tests/dbLibrariesTests.cc +++ b/src/db/unit_tests/dbLibrariesTests.cc @@ -626,7 +626,8 @@ TEST(4) EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a1->get_id ()); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a1->get_id ()); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ()); @@ -637,7 +638,8 @@ TEST(4) EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a2->get_id ()); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a2->get_id ()); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ()); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); @@ -650,7 +652,23 @@ TEST(4) EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a3->get_id ()); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a3->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); + + + LIBT_A *lib_a4 = new LIBT_A (); + db::LibraryManager::instance ().register_lib (lib_a4); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a3->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").second, lib_a4->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a3->get_id ()); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ()); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); diff --git a/src/edt/edt/edtEditorOptionsPages.cc b/src/edt/edt/edtEditorOptionsPages.cc index b8c944587..779398f97 100644 --- a/src/edt/edt/edtEditorOptionsPages.cc +++ b/src/edt/edt/edtEditorOptionsPages.cc @@ -440,14 +440,13 @@ EditorOptionsInst::update_cell_edits () } db::Layout *layout = 0; - lay::LayoutView *view = lay::LayoutView::current (); // find the layout the cell has to be looked up: that is either the layout of the current instance or // the library selected if (mp_ui->lib_cbx->current_library ()) { layout = &mp_ui->lib_cbx->current_library ()->layout (); - } else if (view && view->cellview (m_cv_index).is_valid ()) { - layout = &view->cellview (m_cv_index)->layout (); + } else if (view ()->cellview (m_cv_index).is_valid ()) { + layout = &view ()->cellview (m_cv_index)->layout (); } if (! layout) { @@ -485,7 +484,7 @@ EditorOptionsInst::browse_cell () { BEGIN_PROTECTED - if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) { + if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) { // find the layout the cell has to be looked up: that is either the layout of the current instance or // the library selected @@ -495,7 +494,7 @@ BEGIN_PROTECTED lib = mp_ui->lib_cbx->current_library (); layout = &lib->layout (); } else { - layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout (); + layout = &view ()->cellview (m_cv_index)->layout (); } bool all_cells = (mp_ui->lib_cbx->current_library () != 0 ? false : true); @@ -605,12 +604,10 @@ EditorOptionsInst::setup (lay::Dispatcher *root) std::string techname; mp_ui->lib_cbx->update_list (); - if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) { - techname = lay::LayoutView::current ()->cellview (m_cv_index)->tech_name (); - mp_ui->lib_cbx->set_technology_filter (techname, true); - } else { - mp_ui->lib_cbx->set_technology_filter (std::string (), false); + if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) { + techname = view ()->cellview (m_cv_index)->tech_name (); } + mp_ui->lib_cbx->set_technology_filter (techname, ! techname.empty ()); // cell name std::string s; @@ -707,11 +704,11 @@ EditorOptionsInstPCellParam::apply (lay::Dispatcher *root) std::string param; db::Layout *layout = 0; - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview_ref ()->tech_name ()); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview ().is_valid () ? view ()->active_cellview ()->tech_name () : std::string ()); if (lib) { layout = &lib->layout (); - } else if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) { - layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout (); + } else if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) { + layout = &view ()->cellview (m_cv_index)->layout (); } bool ok = true; @@ -760,7 +757,7 @@ EditorOptionsInstPCellParam::setup (lay::Dispatcher *root) needs_update = true; } - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview_ref ()->tech_name ()); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview ().is_valid () ? view ()->active_cellview ()->tech_name () : std::string ()); // pcell parameters std::string param; @@ -840,7 +837,7 @@ EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector active_cellview_ref ()->tech_name ()); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview ().is_valid () ? view ()->active_cellview ()->tech_name () : std::string ()); if (lib) { layout = &lib->layout (); } else { diff --git a/src/edt/edt/edtRecentConfigurationPage.cc b/src/edt/edt/edtRecentConfigurationPage.cc index 4c5726b8f..41d7728d2 100644 --- a/src/edt/edt/edtRecentConfigurationPage.cc +++ b/src/edt/edt/edtRecentConfigurationPage.cc @@ -219,7 +219,11 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std const db::Library *lib = 0; for (std::list::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++libname_column) { if (c->rendering == RecentConfigurationPage::CellLibraryName) { - lib = db::LibraryManager::instance ().lib_ptr_by_name (values [libname_column], view ()->active_cellview_ref ()->tech_name ()); + if (view ()->active_cellview ().is_valid ()) { + lib = db::LibraryManager::instance ().lib_ptr_by_name (values [libname_column], view ()->active_cellview ()->tech_name ()); + } else { + lib = db::LibraryManager::instance ().lib_ptr_by_name (values [libname_column]); + } break; } } diff --git a/src/edt/edt/edtServiceImpl.cc b/src/edt/edt/edtServiceImpl.cc index 8f9e048be..f2a627842 100644 --- a/src/edt/edt/edtServiceImpl.cc +++ b/src/edt/edt/edtServiceImpl.cc @@ -1854,7 +1854,12 @@ InstService::switch_cell_or_pcell (bool switch_parameters) } const lay::CellView &cv = view ()->cellview (m_cv_index); - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, cv->tech_name ()); + db::Library *lib = 0; + if (cv.is_valid ()) { + lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, cv->tech_name ()); + } else { + lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name); + } // find the layout the cell has to be looked up: that is either the layout of the current instance or // the library selected diff --git a/src/laybasic/laybasic/layWidgets.cc b/src/laybasic/laybasic/layWidgets.cc index 6ea947b02..a84b96601 100644 --- a/src/laybasic/laybasic/layWidgets.cc +++ b/src/laybasic/laybasic/layWidgets.cc @@ -298,6 +298,7 @@ struct LayerSelectionComboBoxPrivateData const db::Layout *layout; lay::LayoutView *view; int cv_index; + db::LayerProperties last_props; }; LayerSelectionComboBox::LayerSelectionComboBox (QWidget *parent) @@ -424,6 +425,14 @@ LayerSelectionComboBox::set_view (lay::LayoutView *view, int cv_index, bool all_ mp_private->cv_index = cv_index; mp_private->all_layers = all_layers; + view->layer_list_changed_event.add (this, &LayerSelectionComboBox::on_layer_list_changed); + + update_layer_list (); +} + +void +LayerSelectionComboBox::on_layer_list_changed (int) +{ update_layer_list (); } @@ -442,7 +451,7 @@ void LayerSelectionComboBox::update_layer_list () { int i = currentIndex (); - db::LayerProperties props; + db::LayerProperties props = mp_private->last_props; if (i >= 0 && i < int (mp_private->layers.size ())) { props = mp_private->layers [i].first; } @@ -522,6 +531,8 @@ LayerSelectionComboBox::update_layer_list () void LayerSelectionComboBox::set_current_layer (const db::LayerProperties &props) { + mp_private->last_props = props; + for (std::vector >::iterator ll = mp_private->layers.begin (); ll != mp_private->layers.end (); ++ll) { if (ll->first.log_equal (props)) { setCurrentIndex (std::distance (mp_private->layers.begin (), ll)); @@ -562,7 +573,7 @@ LayerSelectionComboBox::current_layer_props () const { int i = currentIndex (); if (i < 0 || i > int (mp_private->layers.size ())) { - return db::LayerProperties (); + return mp_private->last_props; } else { return mp_private->layers [i].first; } @@ -600,7 +611,7 @@ LibrarySelectionComboBox::update_list () for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) { db::Library *lib = db::LibraryManager::instance ().lib (l->second); - if (! m_tech_set || !lib->for_technologies ()|| lib->is_for_technology (m_tech)) { + if (! m_tech_set || !lib->for_technologies () || lib->is_for_technology (m_tech)) { std::string item_text = lib->get_name (); if (! lib->get_description ().empty ()) { diff --git a/src/laybasic/laybasic/layWidgets.h b/src/laybasic/laybasic/layWidgets.h index 7de0fa33d..3f2002fb5 100644 --- a/src/laybasic/laybasic/layWidgets.h +++ b/src/laybasic/laybasic/layWidgets.h @@ -26,6 +26,8 @@ #include "laybasicCommon.h" +#include "tlObject.h" + #include #include #include @@ -170,7 +172,7 @@ private: * This combo box allows selecting a (physical) layer from a layout */ class LAYBASIC_PUBLIC LayerSelectionComboBox - : public QComboBox + : public QComboBox, public tl::Object { Q_OBJECT @@ -249,6 +251,7 @@ protected slots: private: LayerSelectionComboBoxPrivateData *mp_private; + void on_layer_list_changed (int); void update_layer_list (); }; From ab36a660fb1291cd9a2878be62de44c5756c4fab Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Dec 2020 19:11:12 +0100 Subject: [PATCH 09/44] WIP: cold references - keep reference information while libraries are not there or cells are missing. --- src/db/db/db.pro | 2 + src/db/db/dbColdProxy.cc | 128 +++++++ src/db/db/dbColdProxy.h | 111 ++++++ src/db/db/dbLayout.cc | 340 ++++++++++++------ src/db/db/dbLayout.h | 69 +++- src/db/db/dbLibrary.cc | 30 +- src/db/db/dbLibraryManager.cc | 16 + src/db/db/dbLibraryProxy.cc | 2 - .../gds2/db_plugin/dbGDS2ReaderBase.cc | 10 +- 9 files changed, 578 insertions(+), 130 deletions(-) create mode 100644 src/db/db/dbColdProxy.cc create mode 100644 src/db/db/dbColdProxy.h diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 94c5d291b..82c60a7bb 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -19,6 +19,7 @@ SOURCES = \ dbClipboard.cc \ dbClipboardData.cc \ dbClip.cc \ + dbColdProxy.cc \ dbCommonReader.cc \ dbEdge.cc \ dbEdgePair.cc \ @@ -214,6 +215,7 @@ HEADERS = \ dbClipboardData.h \ dbClipboard.h \ dbClip.h \ + dbColdProxy.h \ dbCommonReader.h \ dbEdge.h \ dbEdgePair.h \ diff --git a/src/db/db/dbColdProxy.cc b/src/db/db/dbColdProxy.cc new file mode 100644 index 000000000..a387f2838 --- /dev/null +++ b/src/db/db/dbColdProxy.cc @@ -0,0 +1,128 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "dbColdProxy.h" +#include "dbLibraryManager.h" +#include "dbLibrary.h" +#include "dbLayout.h" +#include "dbLayoutUtils.h" + +#include "tlThreads.h" + +namespace db +{ + +static tl::Mutex s_map_mutex; +static std::map > s_proxies_per_library_name; + +const tl::weak_collection & +ColdProxy::cold_proxies_per_lib_name (const std::string &libname) +{ + tl::MutexLocker locker (&s_map_mutex); + + std::map >::const_iterator i = s_proxies_per_library_name.find (libname); + if (i != s_proxies_per_library_name.end ()) { + return i->second; + } else { + static tl::weak_collection s_empty; + return s_empty; + } +} + +ColdProxy::ColdProxy (db::cell_index_type ci, db::Layout &layout, const ProxyContextInfo &info) + : Cell (ci, layout), mp_context_info (new ProxyContextInfo (info)) +{ + if (! info.lib_name.empty ()) { + tl::MutexLocker locker (&s_map_mutex); + s_proxies_per_library_name [info.lib_name].push_back (this); + } +} + +ColdProxy::~ColdProxy () +{ + delete mp_context_info; + mp_context_info = 0; +} + +Cell * +ColdProxy::clone (Layout &layout) const +{ + Cell *cell = new ColdProxy (db::Cell::cell_index (), layout, *mp_context_info); + // copy the cell content + *cell = *this; + return cell; +} + +std::string +ColdProxy::get_basic_name () const +{ + if (! mp_context_info->pcell_name.empty ()) { + return "" + mp_context_info->pcell_name; + } else if (! mp_context_info->cell_name.empty ()) { + return "" + mp_context_info->cell_name; + } else { + return Cell::get_basic_name (); + } +} + +std::string +ColdProxy::get_display_name () const +{ + if (! mp_context_info->lib_name.empty ()) { + std::string stem = "" + mp_context_info->lib_name + "."; + if (! mp_context_info->pcell_name.empty ()) { + return stem + mp_context_info->pcell_name; + } else if (! mp_context_info->cell_name.empty ()) { + return stem + mp_context_info->cell_name; + } else { + return stem + ""; + } + } else { + return Cell::get_display_name (); + } +} + +std::string +ColdProxy::get_qualified_name () const +{ + if (! mp_context_info->lib_name.empty ()) { + std::string stem = "" + mp_context_info->lib_name + "."; + if (! mp_context_info->pcell_name.empty ()) { + if (mp_context_info->pcell_parameters.empty ()) { + return stem + mp_context_info->pcell_name; + } else { + // TODO: list parameters? Might be long. + return stem + mp_context_info->pcell_name + "(...)"; + } + } else if (! mp_context_info->cell_name.empty ()) { + return stem + mp_context_info->cell_name; + } else { + return stem + ""; + } + } else { + return Cell::get_qualified_name (); + } +} + +} + diff --git a/src/db/db/dbColdProxy.h b/src/db/db/dbColdProxy.h new file mode 100644 index 000000000..13a586c1c --- /dev/null +++ b/src/db/db/dbColdProxy.h @@ -0,0 +1,111 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_dbColdProxy +#define HDR_dbColdProxy + +#include "dbCommon.h" + +#include "dbTypes.h" +#include "dbCell.h" + +#include "tlObject.h" + +namespace db +{ + +struct ProxyContextInfo; + +/** + * @brief A cell specialization: a cold proxy representing a library or PCell which has gone out of scope + * + * If a PCell or library cell gets disconnected - for example, because the technology has changed or during + * development of PCell code - this proxy replaces the original one. It stores the connection information, so + * it can be regenerated when it becomes valid again. + */ +class DB_PUBLIC ColdProxy + : public Cell, public tl::Object +{ +public: + /** + * @brief The constructor + * + * Creates a cold proxy represented by the ProxyContextInfo data. + */ + ColdProxy (db::cell_index_type ci, db::Layout &layout, const ProxyContextInfo &info); + + /** + * @brief The destructor + */ + ~ColdProxy (); + + /** + * @brief Cloning + */ + virtual Cell *clone (Layout &layout) const; + + /** + * @brief Get the library id + */ + const ProxyContextInfo &context_info () const + { + return *mp_context_info; + } + + /** + * @brief Indicates that this cell is a proxy cell + */ + virtual bool is_proxy () const + { + return true; + } + + /** + * @brief Gets a list of cold proxies for a given library name + */ + static const tl::weak_collection &cold_proxies_per_lib_name (const std::string &libname); + + /** + * @brief Gets the basic name + */ + virtual std::string get_basic_name () const; + + /** + * @brief Gets the display name + */ + virtual std::string get_display_name () const; + + /** + * @brief Gets the qualified name + */ + virtual std::string get_qualified_name () const; + +private: + ProxyContextInfo *mp_context_info; +}; + +} + +#endif + + diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 4aa45d4b4..a9c94c2ad 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -30,6 +30,7 @@ #include "dbPCellVariant.h" #include "dbPCellDeclaration.h" #include "dbLibraryProxy.h" +#include "dbColdProxy.h" #include "dbLibraryManager.h" #include "dbLibrary.h" #include "dbRegion.h" @@ -260,6 +261,65 @@ LayerIterator::operator*() const return std::pair (m_layer_index, &m_layout.get_properties (m_layer_index)); } +// ----------------------------------------------------------------- +// Implementation of the ProxyContextInfo class + +ProxyContextInfo +ProxyContextInfo::deserialize (std::vector::const_iterator from, std::vector::const_iterator to) +{ + ProxyContextInfo info; + + for (std::vector::const_iterator i = from; i != to; ++i) { + + tl::Extractor ex (i->c_str ()); + + if (ex.test ("LIB=")) { + + info.lib_name = ex.skip (); + + } else if (ex.test ("P(")) { + + std::pair vv; + + ex.read_word_or_quoted (vv.first); + ex.test (")"); + ex.test ("="); + ex.read (vv.second); + + info.pcell_parameters.insert (vv); + + } else if (ex.test ("PCELL=")) { + + info.pcell_name = ex.skip (); + + } else if (ex.test ("CELL=")) { + + info.cell_name = ex.skip (); + + } + + } + + return info; +} + +void +ProxyContextInfo::serialize (std::vector &strings) +{ + if (! lib_name.empty ()) { + strings.push_back ("LIB=" + lib_name); + } + for (std::map ::const_iterator p = pcell_parameters.begin (); p != pcell_parameters.end (); ++p) { + strings.push_back ("P(" + tl::to_word_or_quoted_string (p->first) + ")=" + p->second.to_parsable_string ()); + } + if (! pcell_name.empty ()) { + strings.push_back ("PCELL=" + pcell_name); + } + if (! cell_name.empty ()) { + strings.push_back ("CELL=" + cell_name); + } +} + // ----------------------------------------------------------------- // Implementation of the Layout class @@ -522,12 +582,10 @@ Layout::set_technology_name (const std::string &tech) if (! pn.first) { - // substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = cell_name (ci); - db::Cell *old_cell = take_cell (ci); - insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // substitute by a cold proxy + db::ProxyContextInfo info; + get_context_info (ci, info); + create_cold_proxy_as (info, ci); } else { @@ -537,12 +595,10 @@ Layout::set_technology_name (const std::string &tech) const db::PCellDeclaration *new_pcell_decl = new_lib->layout ().pcell_declaration (pn.second); if (! old_pcell_decl || ! new_pcell_decl) { - // substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = cell_name (ci); - db::Cell *old_cell = take_cell (ci); - insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // substitute by a cold proxy + db::ProxyContextInfo info; + get_context_info (ci, info); + create_cold_proxy_as (info, ci); } else { @@ -566,12 +622,10 @@ Layout::set_technology_name (const std::string &tech) if (! cn.first) { - // unlink this proxy: substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = cell_name (ci); - db::Cell *old_cell = take_cell (ci); - insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // unlink this proxy: substitute by a cold proxy + db::ProxyContextInfo info; + get_context_info (ci, info); + create_cold_proxy_as (info, ci); } else { @@ -588,6 +642,9 @@ Layout::set_technology_name (const std::string &tech) } m_tech_name = tech; + + // we may have re-established a connection for pending ("cold") proxies so we can try to restore them + restore_proxies (); } void @@ -1948,8 +2005,26 @@ static const std::vector &gauge_parameters (const std::vectorunregister (); + if (retain_layout) { + new_cell->Cell::operator= (*old_cell); + } + } + + m_cells.erase (iterator (old_cell)); + m_cells.push_back_ptr (new_cell); + m_cell_ptrs [target_cell_index] = new_cell; +} + void -Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vector &p, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping) +Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vector &p, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping, bool retain_layout) { pcell_header_type *header = pcell_header (pcell_id); tl_assert (header != 0); @@ -1963,16 +2038,13 @@ Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vectortransacting ())); tl_assert (m_cell_ptrs [target_cell_index] != 0); - invalidate_hier (); - - m_cells.erase (iterator (m_cell_ptrs [target_cell_index])); - pcell_variant_type *variant = new pcell_variant_type (target_cell_index, *this, pcell_id, parameters); - m_cells.push_back_ptr (variant); - m_cell_ptrs [target_cell_index] = variant; + replace_cell (target_cell_index, variant, retain_layout); - // produce the layout - variant->update (layer_mapping); + if (! retain_layout) { + // produce the layout unless we retained it + variant->update (layer_mapping); + } } cell_index_type @@ -2316,8 +2388,20 @@ Layout::get_pcell_variant_cell (cell_index_type cell_index, const std::vector &context_info) const +bool +Layout::get_context_info (cell_index_type cell_index, std::vector &strings) const +{ + ProxyContextInfo info; + if (! get_context_info (cell_index, info)) { + return false; + } else { + info.serialize (strings); + return true; + } +} + +bool +Layout::get_context_info (cell_index_type cell_index, ProxyContextInfo &info) const { const db::Cell *cptr = &cell (cell_index); const db::Layout *ly = this; @@ -2333,7 +2417,7 @@ Layout::get_context_info (cell_index_type cell_index, std::vector // one level of library indirection ly = &lib->layout (); cptr = &ly->cell (lib_proxy->library_cell_index ()); - context_info.push_back ("LIB=" + lib->get_name ()); + info.lib_name = lib->get_name (); } @@ -2347,19 +2431,36 @@ Layout::get_context_info (cell_index_type cell_index, std::vector const std::vector &pcp = pcell_decl->parameter_declarations (); std::vector::const_iterator pd = pcp.begin (); for (std::vector::const_iterator p = pcell_variant->parameters ().begin (); p != pcell_variant->parameters ().end () && pd != pcp.end (); ++p, ++pd) { - context_info.push_back ("P(" + tl::to_word_or_quoted_string (pd->get_name ()) + ")=" + p->to_parsable_string ()); + info.pcell_parameters.insert (std::make_pair (pd->get_name (), *p)); } const db::PCellHeader *header = ly->pcell_header (pcell_variant->pcell_id ()); - context_info.push_back ("PCELL=" + header->get_name ()); + info.pcell_name = header->get_name (); } else { - context_info.push_back ("CELL=" + std::string (ly->cell_name (cptr->cell_index ()))); + info.cell_name = ly->cell_name (cptr->cell_index ()); } return true; } +void +Layout::restore_proxies (ImportLayerMapping *layer_mapping) +{ + std::vector cold_proxies; + + for (iterator c = begin (); c != end (); ++c) { + db::ColdProxy *proxy = dynamic_cast (c.operator-> ()); + if (proxy) { + cold_proxies.push_back (proxy); + } + } + + for (std::vector::const_iterator p = cold_proxies.begin (); p != cold_proxies.end (); ++p) { + recover_proxy_as ((*p)->cell_index (), (*p)->context_info (), layer_mapping); + } +} + bool Layout::recover_proxy_as (cell_index_type cell_index, std::vector ::const_iterator from, std::vector ::const_iterator to, ImportLayerMapping *layer_mapping) { @@ -2367,17 +2468,21 @@ Layout::recover_proxy_as (cell_index_type cell_index, std::vector : return false; } - tl::Extractor ex (from->c_str ()); + return recover_proxy_as (cell_index, ProxyContextInfo::deserialize (from, to), layer_mapping); +} - if (ex.test ("LIB=")) { +bool +Layout::recover_proxy_as (cell_index_type cell_index, const ProxyContextInfo &info, ImportLayerMapping *layer_mapping) +{ + if (! info.lib_name.empty ()) { - std::string lib_name = ex.skip (); - Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name, m_tech_name); - if (! lib) { - return false; + db::Cell *lib_cell = 0; + + Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (info.lib_name, m_tech_name); + if (lib) { + lib_cell = lib->layout ().recover_proxy_no_lib (info); } - db::Cell *lib_cell = lib->layout ().recover_proxy (from + 1, to); if (lib_cell) { get_lib_proxy_as (lib, lib_cell->cell_index (), cell_index, layer_mapping); return true; @@ -2385,38 +2490,28 @@ Layout::recover_proxy_as (cell_index_type cell_index, std::vector : } else { - std::map parameters; + if (! info.pcell_name.empty ()) { - while (from != to && (ex = tl::Extractor (from->c_str ())).test ("P(")) { - - std::string name; - ex.read_word_or_quoted (name); - ex.test (")"); - ex.test ("="); - - ex.read (parameters.insert (std::make_pair (name, tl::Variant ())).first->second); - - ++from; - - } - - if (ex.test ("PCELL=")) { - - std::pair pc = pcell_by_name (ex.skip ()); + std::pair pc = pcell_by_name (info.pcell_name.c_str ()); if (pc.first) { - get_pcell_variant_as (pc.second, pcell_declaration (pc.second)->map_parameters (parameters), cell_index, layer_mapping); + get_pcell_variant_as (pc.second, pcell_declaration (pc.second)->map_parameters (info.pcell_parameters), cell_index, layer_mapping); return true; } - } else if (ex.test ("CELL=")) { + } else if (! info.cell_name.empty ()) { - // This should not happen. A cell (given by the cell index) cannot be proxy to another cell in the same layout. + // This should not happen. A cell (given by the cell name) cannot be proxy to another cell in the same layout. tl_assert (false); } } + if (! dynamic_cast (m_cell_ptrs [cell_index])) { + // create a cold proxy representing the context information so we can restore it + create_cold_proxy_as (info, cell_index); + } + return false; } @@ -2427,55 +2522,54 @@ Layout::recover_proxy (std::vector ::const_iterator from, std::vect return 0; } - tl::Extractor ex (from->c_str ()); + return recover_proxy (ProxyContextInfo::deserialize (from, to)); +} - if (ex.test ("LIB=")) { +db::Cell * +Layout::recover_proxy (const ProxyContextInfo &info) +{ + if (! info.lib_name.empty ()) { - std::string lib_name = ex.skip (); - Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name, m_tech_name); - if (! lib) { - return 0; + Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (info.lib_name, m_tech_name); + + db::Cell *lib_cell = 0; + if (lib) { + lib_cell = lib->layout ().recover_proxy_no_lib (info); } - db::Cell *lib_cell = lib->layout ().recover_proxy (from + 1, to); if (lib_cell) { - cell_index_type cell_index = get_lib_proxy (lib, lib_cell->cell_index ()); - return &cell (cell_index); + return m_cell_ptrs [get_lib_proxy (lib, lib_cell->cell_index ())]; } } else { - std::map parameters; - - while (from != to && (ex = tl::Extractor (from->c_str ())).test ("P(")) { - - std::string name; - ex.read_word_or_quoted (name); - ex.test (")"); - ex.test ("="); - - ex.read (parameters.insert (std::make_pair (name, tl::Variant ())).first->second); - - ++from; - + db::Cell *proxy = recover_proxy_no_lib (info); + if (proxy) { + return proxy; } - if (ex.test ("PCELL=")) { + } - std::pair pc = pcell_by_name (ex.skip ()); - if (pc.first) { - cell_index_type cell_index = get_pcell_variant (pc.second, pcell_declaration (pc.second)->map_parameters (parameters)); - return &cell (cell_index); - } + return m_cell_ptrs [create_cold_proxy (info)]; +} - } else if (ex.test ("CELL=")) { +db::Cell * +Layout::recover_proxy_no_lib (const ProxyContextInfo &info) +{ + if (! info.pcell_name.empty ()) { - std::pair cc = cell_by_name (ex.skip ()); - if (cc.first) { - return &cell (cc.second); - } + std::pair pc = pcell_by_name (info.pcell_name.c_str ()); + if (pc.first) { + cell_index_type cell_index = get_pcell_variant (pc.second, pcell_declaration (pc.second)->map_parameters (info.pcell_parameters)); + return m_cell_ptrs [cell_index]; + } - } + } else if (! info.cell_name.empty ()) { + + std::pair cc = cell_by_name (info.cell_name.c_str ()); + if (cc.first) { + return m_cell_ptrs [cc.second]; + } } @@ -2507,21 +2601,18 @@ Layout::unregister_lib_proxy (db::LibraryProxy *lib_proxy) } void -Layout::get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping) +Layout::get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping, bool retain_layout) { tl_assert (! (manager () && manager ()->transacting ())); tl_assert (m_cell_ptrs [target_cell_index] != 0); - invalidate_hier (); - - m_cells.erase (iterator (m_cell_ptrs [target_cell_index])); - LibraryProxy *proxy = new LibraryProxy (target_cell_index, *this, lib->get_id (), cell_index); - m_cells.push_back_ptr (proxy); - m_cell_ptrs [target_cell_index] = proxy; + replace_cell (target_cell_index, proxy, retain_layout); - // produce the layout - proxy->update (layer_mapping); + if (! retain_layout) { + // produce the layout unless we retained it + proxy->update (layer_mapping); + } } cell_index_type @@ -2552,7 +2643,7 @@ Layout::get_lib_proxy (Library *lib, cell_index_type cell_index) manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0)); } - // produce the layout + // produce the layout proxy->update (); return new_index; @@ -2560,6 +2651,47 @@ Layout::get_lib_proxy (Library *lib, cell_index_type cell_index) } } +cell_index_type +Layout::create_cold_proxy (const db::ProxyContextInfo &info) +{ + // create a new unique name + std::string b; + if (! info.cell_name.empty ()) { + b = info.cell_name; + } else if (! info.pcell_name.empty ()) { + b = info.pcell_name; + } + if (m_cell_map.find (b.c_str ()) != m_cell_map.end ()) { + b = uniquify_cell_name (b.c_str ()); + } + + // create a new cell (a LibraryProxy) + cell_index_type new_index = allocate_new_cell (); + + ColdProxy *proxy = new ColdProxy (new_index, *this, info); + m_cells.push_back_ptr (proxy); + m_cell_ptrs [new_index] = proxy; + + // enter it's index and cell_name + register_cell_name (b.c_str (), new_index); + + if (manager () && manager ()->transacting ()) { + manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0)); + } + + return new_index; +} + +void +Layout::create_cold_proxy_as (const db::ProxyContextInfo &info, cell_index_type target_cell_index) +{ + tl_assert (! (manager () && manager ()->transacting ())); + tl_assert (m_cell_ptrs [target_cell_index] != 0); + + ColdProxy *proxy = new ColdProxy (target_cell_index, *this, info); + replace_cell (target_cell_index, proxy, true); +} + void Layout::redo (db::Op *op) { diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index c79629567..779a1ee2f 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -457,6 +457,20 @@ public: virtual std::pair map_layer (const LayerProperties &lprops) = 0; }; +/** + * @brief A binary object representing context information for regenerating library proxies and PCells + */ +struct DB_PUBLIC ProxyContextInfo +{ + std::string lib_name; + std::string cell_name; + std::string pcell_name; + std::map pcell_parameters; + + static ProxyContextInfo deserialize (std::vector::const_iterator from, std::vector::const_iterator to); + void serialize (std::vector &strings); +}; + /** * @brief The layout object * @@ -863,8 +877,9 @@ public: * @param parameters The PCell parameters * @param cell_index The cell index which is to be replaced by the PCell variant proxy * @param layer_mapping The optional layer mapping object that maps the PCell layers to the layout's layers + * @param retain_layout Set to true for not using update() on the PCell but to retain existing layout (conservative approach) */ - void get_pcell_variant_as (pcell_id_type pcell_id, const std::vector ¶meters, cell_index_type cell_index, ImportLayerMapping *layer_mapping = 0); + void get_pcell_variant_as (pcell_id_type pcell_id, const std::vector ¶meters, cell_index_type cell_index, ImportLayerMapping *layer_mapping = 0, bool retain_layout = false); /** * @brief Get the PCell variant cell of a existing cell with new parameters @@ -1010,9 +1025,21 @@ public: /** * @brief Get the proxy cell (index) for a given library an cell index (inside that library) * - * This method replaces the cell with the given target cell index by a library. + * @param retain_layout Set to true for not using update() on the PCell but to retain existing layout (conservative approach) + * + * This method replaces the cell with the given target cell index by a library. */ - void get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping = 0); + void get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping = 0, bool retain_layout = false); + + /** + * @brief Creates a cold proxy representing the given context information + */ + cell_index_type create_cold_proxy (const db::ProxyContextInfo &info); + + /** + * @brief Subsitutes the given cell by a cold proxy representing the given context information + */ + void create_cold_proxy_as (const db::ProxyContextInfo &info, cell_index_type cell_index); /** * @brief Get the context information for a given cell (for writing into a file) @@ -1024,6 +1051,11 @@ public: */ bool get_context_info (cell_index_type cell_index, std::vector &context_info) const; + /** + * @brief Gets the context information as a binary object + */ + bool get_context_info (cell_index_type cell_index, ProxyContextInfo &context_info) const; + /** * @brief Recover a proxy cell from the given context info. * @@ -1035,6 +1067,11 @@ public: */ db::Cell *recover_proxy (std::vector ::const_iterator from, std::vector ::const_iterator to); + /** + * @brief Recover a proxy cell from the given binary context info object. + */ + db::Cell *recover_proxy (const ProxyContextInfo &context_info); + /** * @brief Recover a proxy cell from the given context info. * @@ -1050,6 +1087,27 @@ public: */ bool recover_proxy_as (cell_index_type cell_index, std::vector ::const_iterator from, std::vector ::const_iterator to, ImportLayerMapping *layer_mapping = 0); + /** + * @brief Recover a proxy cell from the given binary context info object + * + * See the string-based version of "recover_proxy_as" for details. + */ + bool recover_proxy_as (cell_index_type cell_index, const ProxyContextInfo &context_info, ImportLayerMapping *layer_mapping = 0); + + /** + * @brief Restores proxies as far as possible + * + * This feature can be used after a library update to make sure that proxies are updated. + * Library updates may enabled lost connections which are help in cold proxies. This method will recover + * these connections. + */ + void restore_proxies(ImportLayerMapping *layer_mapping = 0); + + /** + * @brief Replaces the given cell index with the new cell + */ + void replace_cell (cell_index_type target_cell_index, db::Cell *new_cell, bool retain_layout); + /** * @brief Delete a cell plus the subcells not used otherwise * @@ -1853,6 +1911,11 @@ private: * @brief Implementation of prune_cells and some prune_subcells variants */ void do_prune_cells_or_subcells (const std::set &ids, int levels, bool subcells); + + /** + * @brief Recovers a proxy without considering the library from context_info + */ + db::Cell *recover_proxy_no_lib (const ProxyContextInfo &context_info); }; /** diff --git a/src/db/db/dbLibrary.cc b/src/db/db/dbLibrary.cc index 3103f0c56..c22dff473 100644 --- a/src/db/db/dbLibrary.cc +++ b/src/db/db/dbLibrary.cc @@ -191,12 +191,10 @@ Library::remap_to (db::Library *other) if (! pn.first) { - // substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = r->first->cell_name (ci); - db::Cell *old_cell = r->first->take_cell (ci); - r->first->insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // substitute by a cold proxy + db::ProxyContextInfo info; + r->first->get_context_info (ci, info); + r->first->create_cold_proxy_as (info, ci); } else { @@ -204,12 +202,10 @@ Library::remap_to (db::Library *other) const db::PCellDeclaration *new_pcell_decl = other->layout ().pcell_declaration (pn.second); if (! old_pcell_decl || ! new_pcell_decl) { - // substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = r->first->cell_name (ci); - db::Cell *old_cell = r->first->take_cell (ci); - r->first->insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // substitute by a cold proxy + db::ProxyContextInfo info; + r->first->get_context_info (ci, info); + r->first->create_cold_proxy_as (info, ci); } else { @@ -234,12 +230,10 @@ Library::remap_to (db::Library *other) if (! cn.first) { - // unlink this proxy: substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = r->first->cell_name (ci); - db::Cell *old_cell = r->first->take_cell (ci); - r->first->insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // substitute by a cold proxy + db::ProxyContextInfo info; + r->first->get_context_info (ci, info); + r->first->create_cold_proxy_as (info, ci); } else { diff --git a/src/db/db/dbLibraryManager.cc b/src/db/db/dbLibraryManager.cc index 2e5e7df86..88e526c7c 100644 --- a/src/db/db/dbLibraryManager.cc +++ b/src/db/db/dbLibraryManager.cc @@ -24,6 +24,7 @@ #include "dbLibraryManager.h" #include "dbLibrary.h" #include "dbCommon.h" +#include "dbColdProxy.h" #include "tlAssert.h" #include "tlStaticObjects.h" @@ -158,6 +159,21 @@ LibraryManager::register_lib (Library *library) l = m_lib_by_name.find (library->get_name ()); m_lib_by_name.insert (l, std::make_pair (library->get_name (), id)); + // take care of cold referrers - these may not get valid + // NOTE: this will try to substitute the cold proxies we may have generated during "remap_to" above, but + // "restore_proxies" takes care not to re-substitute cold proxies. + + const tl::weak_collection &cold_proxies = db::ColdProxy::cold_proxies_per_lib_name (library->get_name ()); + std::set to_refresh; + for (tl::weak_collection::const_iterator p = cold_proxies.begin (); p != cold_proxies.end (); ++p) { + to_refresh.insert (const_cast (p->layout ())); + } + + for (std::set::const_iterator l = to_refresh.begin (); l != to_refresh.end (); ++l) { + (*l)->restore_proxies (0); + } + + // issue the change notification changed_event (); return id; diff --git a/src/db/db/dbLibraryProxy.cc b/src/db/db/dbLibraryProxy.cc index 195c82b99..241df85ad 100644 --- a/src/db/db/dbLibraryProxy.cc +++ b/src/db/db/dbLibraryProxy.cc @@ -99,8 +99,6 @@ LibraryProxy::remap (lib_id_type lib_id, cell_index_type lib_cell_index) m_lib_id = lib_id; m_library_cell_index = lib_cell_index; - // It's important to register at the new library, but the old library is about to the deleted, so we don't unregister. - // That does not disturb the old library iterating over the layouts. db::Library *lib = db::LibraryManager::instance ().lib (m_lib_id); if (lib) { lib->register_proxy (this, layout ()); diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc index d79793638..71b6561fc 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc @@ -358,17 +358,21 @@ GDS2ReaderBase::do_read (db::Layout &layout) db::cell_index_type cell_index = make_cell (layout, m_cellname); - db::Cell *cell = &layout.cell (cell_index); - + bool ignore_cell = false; std::map >::const_iterator ctx = m_context_info.find (m_cellname); if (ctx != m_context_info.end ()) { GDS2ReaderLayerMapping layer_mapping (this, &layout, m_create_layers); if (layout.recover_proxy_as (cell_index, ctx->second.begin (), ctx->second.end (), &layer_mapping)) { // ignore everything in that cell since it is created by the import: - cell = 0; + ignore_cell = true; } } + db::Cell *cell = 0; + if (! ignore_cell) { + cell = &layout.cell (cell_index); + } + long attr = 0; db::PropertiesRepository::properties_set cell_properties; From 0fc4caace0373927b872373d7eaac23647b5dece Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Dec 2020 19:39:45 +0100 Subject: [PATCH 10/44] WIP: Libraries View follows technology now. --- src/laybasic/laybasic/layLibrariesView.cc | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/laybasic/laybasic/layLibrariesView.cc b/src/laybasic/laybasic/layLibrariesView.cc index 5209b6f68..ec18a07c5 100644 --- a/src/laybasic/laybasic/layLibrariesView.cc +++ b/src/laybasic/laybasic/layLibrariesView.cc @@ -530,16 +530,28 @@ LibrariesView::do_update_content (int lib_index) size_t imin = (lib_index < 0 ? 0 : (size_t) lib_index); size_t imax = (lib_index < 0 ? std::numeric_limits ::max () : (size_t) lib_index); + std::string tech_name; // rebuild all events detach_from_all_events (); + + mp_view->active_cellview_changed_event.add (this, &LibrariesView::update_required); + lay::CellViewRef cv = mp_view->active_cellview_ref (); + if (cv.is_valid ()) { + cv->technology_changed_event.add (this, &LibrariesView::update_required); + tech_name = cv->tech_name (); + } + db::LibraryManager::instance ().changed_event.add (this, &LibrariesView::update_required); std::vector libraries; for (db::LibraryManager::iterator lib = db::LibraryManager::instance ().begin (); lib != db::LibraryManager::instance ().end (); ++lib) { - libraries.push_back (db::LibraryManager::instance ().lib (lib->second)); - libraries.back ()->layout ().hier_changed_event.add (this, &LibrariesView::update_required); - libraries.back ()->retired_state_changed_event.add (this, &LibrariesView::update_required); + db::Library *lib_ptr = db::LibraryManager::instance ().lib (lib->second); + if (! lib_ptr->for_technologies () || lib_ptr->is_for_technology (tech_name)) { + libraries.push_back (lib_ptr); + libraries.back ()->layout ().hier_changed_event.add (this, &LibrariesView::update_required); + libraries.back ()->retired_state_changed_event.add (this, &LibrariesView::update_required); + } } for (size_t i = imin; i < libraries.size () && i <= imax; ++i) { From 740f5509647f33deaa43cdd1b780e898fe5035e4 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Dec 2020 19:54:23 +0100 Subject: [PATCH 11/44] WIP: handling the case of entirely lost libraries. --- src/db/db/dbLayout.cc | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index a9c94c2ad..d627ac812 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -519,6 +519,7 @@ Layout::set_technology_name (const std::string &tech) // determine which library to map to what std::map mapping; std::set seen; + std::set lost; for (db::Layout::iterator c = begin (); c != end (); ++c) { @@ -535,25 +536,32 @@ Layout::set_technology_name (const std::string &tech) if (new_id.first && new_id.second != l->get_id ()) { mapping.insert (std::make_pair (l->get_id (), new_id.second)); + } else if (! new_id.first) { + lost.insert (lib_proxy->lib_id ()); } } } - if (! mapping.empty ()) { + if (! mapping.empty () || ! lost.empty ()) { bool needs_cleanup = false; std::vector > pcells_to_map; std::vector lib_cells_to_map; + std::vector lib_cells_lost; for (db::Layout::iterator c = begin (); c != end (); ++c) { std::map::const_iterator m; db::LibraryProxy *lib_proxy = dynamic_cast (&*c); - if (lib_proxy && (m = mapping.find (lib_proxy->lib_id ())) != mapping.end ()) { + if (! lib_proxy) { + continue; + } + + if ((m = mapping.find (lib_proxy->lib_id ())) != mapping.end ()) { db::Library *lib = db::LibraryManager::instance ().lib (lib_proxy->lib_id ()); db::Cell *lib_cell = &lib->layout ().cell (lib_proxy->library_cell_index ()); @@ -566,6 +574,12 @@ Layout::set_technology_name (const std::string &tech) needs_cleanup = true; + } else if (lost.find (lib_proxy->lib_id ()) != lost.end ()) { + + lib_cells_lost.push_back (lib_proxy); + + needs_cleanup = true; + } } @@ -635,6 +649,17 @@ Layout::set_technology_name (const std::string &tech) } + for (std::vector::const_iterator lp = lib_cells_lost.begin (); lp != lib_cells_lost.end (); ++lp) { + + db::cell_index_type ci = (*lp)->Cell::cell_index (); + + // substitute by a cold proxy + db::ProxyContextInfo info; + get_context_info (ci, info); + create_cold_proxy_as (info, ci); + + } + if (needs_cleanup) { cleanup (); } From 86e7fa56f02f9001d58b2ef4d2f361c3685c4cfa Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Dec 2020 22:02:19 +0100 Subject: [PATCH 12/44] WIP: undo/redo for applying a technology. --- src/db/db/dbColdProxy.cc | 4 +- src/db/db/dbLayout.cc | 51 +++++++- src/db/db/dbLayout.h | 12 ++ src/db/db/dbLibraryManager.cc | 28 ++-- src/db/unit_tests/dbLayoutTests.cc | 174 ++++++++++++++++++++++++- src/lay/lay/layTechnologyController.cc | 24 +++- src/laybasic/laybasic/layCellView.cc | 9 +- src/laybasic/laybasic/layCellView.h | 2 + 8 files changed, 280 insertions(+), 24 deletions(-) diff --git a/src/db/db/dbColdProxy.cc b/src/db/db/dbColdProxy.cc index a387f2838..33346ef91 100644 --- a/src/db/db/dbColdProxy.cc +++ b/src/db/db/dbColdProxy.cc @@ -77,9 +77,9 @@ std::string ColdProxy::get_basic_name () const { if (! mp_context_info->pcell_name.empty ()) { - return "" + mp_context_info->pcell_name; + return "" + mp_context_info->pcell_name; } else if (! mp_context_info->cell_name.empty ()) { - return "" + mp_context_info->cell_name; + return "" + mp_context_info->cell_name; } else { return Cell::get_basic_name (); } diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index d627ac812..6ff5baecf 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -86,6 +86,27 @@ private: db::properties_id_type m_from, m_to; }; +struct SetLayoutTechName + : public LayoutOp +{ + SetLayoutTechName (const std::string &from, const std::string &to) + : m_from (from), m_to (to) + { } + + virtual void redo (db::Layout *layout) const + { + layout->set_technology_name_without_update (m_to); + } + + virtual void undo (db::Layout *layout) const + { + layout->set_technology_name_without_update (m_from); + } + +private: + std::string m_from, m_to; +}; + struct SetLayoutDBU : public LayoutOp { @@ -509,6 +530,18 @@ Layout::technology () const return db::Technologies::instance ()->technology_by_name (m_tech_name); } +void +Layout::set_technology_name_without_update (const std::string &tech) +{ + if (tech != m_tech_name) { + if (manager () && manager ()->transacting ()) { + manager ()->queue (this, new SetLayoutTechName (m_tech_name, tech)); + } + m_tech_name = tech; + technology_changed_event (); + } +} + void Layout::set_technology_name (const std::string &tech) { @@ -666,7 +699,7 @@ Layout::set_technology_name (const std::string &tech) } - m_tech_name = tech; + set_technology_name_without_update (tech); // we may have re-established a connection for pending ("cold") proxies so we can try to restore them restore_proxies (); @@ -2043,9 +2076,20 @@ Layout::replace_cell (cell_index_type target_cell_index, db::Cell *new_cell, boo } } - m_cells.erase (iterator (old_cell)); + if (manager () && manager ()->transacting ()) { + // note the "take" method - this takes out the cell but does not delete it (we need it inside undo) + m_cells.take (iterator (old_cell)); + manager ()->queue (this, new NewRemoveCellOp (target_cell_index, cell_name (target_cell_index), true /*remove*/, old_cell)); + } else { + m_cells.erase (iterator (old_cell)); + } + m_cells.push_back_ptr (new_cell); m_cell_ptrs [target_cell_index] = new_cell; + + if (manager () && manager ()->transacting ()) { + manager ()->queue (this, new NewRemoveCellOp (target_cell_index, m_cell_names [target_cell_index], false /*new*/, 0)); + } } void @@ -2060,7 +2104,6 @@ Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vectorget_variant (*this, parameters) == 0); - tl_assert (! (manager () && manager ()->transacting ())); tl_assert (m_cell_ptrs [target_cell_index] != 0); pcell_variant_type *variant = new pcell_variant_type (target_cell_index, *this, pcell_id, parameters); @@ -2628,7 +2671,6 @@ Layout::unregister_lib_proxy (db::LibraryProxy *lib_proxy) void Layout::get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping, bool retain_layout) { - tl_assert (! (manager () && manager ()->transacting ())); tl_assert (m_cell_ptrs [target_cell_index] != 0); LibraryProxy *proxy = new LibraryProxy (target_cell_index, *this, lib->get_id (), cell_index); @@ -2710,7 +2752,6 @@ Layout::create_cold_proxy (const db::ProxyContextInfo &info) void Layout::create_cold_proxy_as (const db::ProxyContextInfo &info, cell_index_type target_cell_index) { - tl_assert (! (manager () && manager ()->transacting ())); tl_assert (m_cell_ptrs [target_cell_index] != 0); ColdProxy *proxy = new ColdProxy (target_cell_index, *this, info); diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 779a1ee2f..d9c78019e 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -593,6 +593,13 @@ public: */ void set_technology_name (const std::string &tech); + /** + * @brief Changes the technology name + * This method will only change the technology name, but does not re-assess the library links. + * It's provided mainly to support undo/redo and testing. + */ + void set_technology_name_without_update (const std::string &tech); + /** * @brief Accessor to the array repository */ @@ -1816,6 +1823,11 @@ public: */ const std::string &meta_info_value (const std::string &name) const; + /** + * @brief This event is triggered when the technology changes + */ + tl::Event technology_changed_event; + protected: /** * @brief Establish the graph's internals according to the dirty flags diff --git a/src/db/db/dbLibraryManager.cc b/src/db/db/dbLibraryManager.cc index 88e526c7c..2404f1217 100644 --- a/src/db/db/dbLibraryManager.cc +++ b/src/db/db/dbLibraryManager.cc @@ -69,19 +69,25 @@ LibraryManager::~LibraryManager () std::pair LibraryManager::lib_by_name (const std::string &name, const std::set &for_technologies) const { - iterator l = m_lib_by_name.find (name); - while (l != m_lib_by_name.end () && l->first == name) { - const db::Library *lptr = lib (l->second); - bool found = lptr->for_technologies (); - for (std::set::const_iterator t = for_technologies.begin (); t != for_technologies.end () && found; ++t) { - if (! lptr->is_for_technology (*t)) { - found = false; + iterator l; + + if (! for_technologies.empty ()) { + + l = m_lib_by_name.find (name); + while (l != m_lib_by_name.end () && l->first == name) { + const db::Library *lptr = lib (l->second); + bool found = lptr->for_technologies (); + for (std::set::const_iterator t = for_technologies.begin (); t != for_technologies.end () && found; ++t) { + if (! lptr->is_for_technology (*t)) { + found = false; + } } + if (found) { + return std::make_pair (true, l->second); + } + ++l; } - if (found) { - return std::make_pair (true, l->second); - } - ++l; + } // fallback: technology-unspecific libs diff --git a/src/db/unit_tests/dbLayoutTests.cc b/src/db/unit_tests/dbLayoutTests.cc index addce4eff..49a44f837 100644 --- a/src/db/unit_tests/dbLayoutTests.cc +++ b/src/db/unit_tests/dbLayoutTests.cc @@ -20,9 +20,12 @@ */ - - #include "dbLayout.h" +#include "dbLibraryManager.h" +#include "dbLibrary.h" +#include "dbColdProxy.h" +#include "dbLibraryProxy.h" +#include "dbTextWriter.h" #include "tlString.h" #include "tlUnitTest.h" @@ -464,3 +467,170 @@ TEST(4) prop_id = g.properties_repository ().properties_id (ps); EXPECT_EQ (el.property_ids_dirty, true); } + +static std::string l2s (const db::Layout &layout) +{ + tl::OutputStringStream os; + tl::OutputStream ostream (os); + db::TextWriter writer (ostream); + writer.write (layout); + return os.string (); +} + +TEST(5) +{ + // Technology management and library substitution + + db::cell_index_type ci; + unsigned int li; + db::Cell *cell; + + db::Library *lib_a = new db::Library (); + lib_a->set_name ("LIB"); + ci = lib_a->layout ().add_cell ("LIBCELL"); + li = lib_a->layout ().insert_layer (db::LayerProperties (1, 0)); + lib_a->layout ().cell (ci).shapes (li).insert (db::Box (0, 0, 100, 200)); + lib_a->add_technology ("A"); + db::LibraryManager::instance ().register_lib (lib_a); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "A").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "A").second, lib_a->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_ptr_by_name ("LIB", "A") == lib_a, true); + + db::Library *lib_b = new db::Library (); + lib_b->set_name ("LIB"); + ci = lib_b->layout ().add_cell ("LIBCELL"); + li = lib_b->layout ().insert_layer (db::LayerProperties (2, 0)); + lib_b->layout ().cell (ci).shapes (li).insert (db::Box (0, 0, 200, 100)); + lib_b->add_technology ("B"); + db::LibraryManager::instance ().register_lib (lib_b); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "B").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "B").second, lib_b->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_ptr_by_name ("LIB", "B") == lib_b, true); + + db::Library *lib_c = new db::Library (); + lib_c->set_name ("LIB"); + ci = lib_c->layout ().add_cell ("LIBCELL2"); + li = lib_c->layout ().insert_layer (db::LayerProperties (2, 0)); + lib_c->layout ().cell (ci).shapes (li).insert (db::Box (0, 0, 200, 100)); + lib_c->add_technology ("C"); + db::LibraryManager::instance ().register_lib (lib_c); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "C").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "C").second, lib_c->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_ptr_by_name ("LIB", "C") == lib_c, true); + + db::Manager m; + db::Layout l (&m); + EXPECT_EQ (l.technology_name (), ""); + + db::ProxyContextInfo info; + info.lib_name = "LIB"; + info.cell_name = "LIBCELL"; + + cell = l.recover_proxy (info); + EXPECT_EQ (dynamic_cast (cell) != 0, true); + EXPECT_EQ (cell->get_qualified_name (), "LIB.LIBCELL"); + EXPECT_EQ (cell->get_basic_name (), "LIBCELL"); + EXPECT_EQ (cell->get_display_name (), "LIB.LIBCELL"); + + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nend_cell\nend_lib\n"); + + // now restore the proxies + l.set_technology_name ("A"); + EXPECT_EQ (l.technology_name (), "A"); + + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 1 0 {0 0} {100 200}\nend_cell\nend_lib\n"); + + // now switch to cold proxies again as the technology does not have "LIBCELL" (but rather LIBCELL2) + l.set_technology_name ("C"); + EXPECT_EQ (l.technology_name (), "C"); + + cell = &l.cell (l.cell_by_name ("LIBCELL").second); + EXPECT_EQ (dynamic_cast (cell) != 0, true); + EXPECT_EQ (cell->get_qualified_name (), "LIB.LIBCELL"); + EXPECT_EQ (cell->get_basic_name (), "LIBCELL"); + EXPECT_EQ (cell->get_display_name (), "LIB.LIBCELL"); + + // NOTE: the box on 1/0 retained + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 1 0 {0 0} {100 200}\nend_cell\nend_lib\n"); + + // switch to another LIBCELL, this time using layer 2/0 + m.transaction ("switch_to_b"); + l.set_technology_name ("B"); + m.commit (); + + EXPECT_EQ (l.technology_name (), "B"); + cell = &l.cell (l.cell_by_name ("LIBCELL").second); + EXPECT_EQ (dynamic_cast (cell) != 0, true); + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 2 0 {0 0} {200 100}\nend_cell\nend_lib\n"); + + m.undo (); + EXPECT_EQ (l.technology_name (), "C"); + + cell = &l.cell (l.cell_by_name ("LIBCELL").second); + EXPECT_EQ (dynamic_cast (cell) != 0, true); + EXPECT_EQ (cell->get_qualified_name (), "LIB.LIBCELL"); + EXPECT_EQ (cell->get_basic_name (), "LIBCELL"); + EXPECT_EQ (cell->get_display_name (), "LIB.LIBCELL"); + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 1 0 {0 0} {100 200}\nend_cell\nend_lib\n"); + + m.redo (); + + EXPECT_EQ (l.technology_name (), "B"); + cell = &l.cell (l.cell_by_name ("LIBCELL").second); + EXPECT_EQ (dynamic_cast (cell) != 0, true); + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 2 0 {0 0} {200 100}\nend_cell\nend_lib\n"); + + db::LibraryManager::instance ().delete_lib (lib_a); + db::LibraryManager::instance ().delete_lib (lib_b); + db::LibraryManager::instance ().delete_lib (lib_c); +} + +TEST(6) +{ + // Cold proxies and context serialization + db::Cell *cell; + + db::Manager m; + db::Layout l (&m); + + EXPECT_EQ (l.technology_name (), ""); + + db::ProxyContextInfo info; + info.lib_name = "Basic"; + info.pcell_name = "CIRCLE"; + info.pcell_parameters ["actual_radius"] = tl::Variant (10.0); + info.pcell_parameters ["npoints"] = tl::Variant (8); + info.pcell_parameters ["layer"] = tl::Variant (db::LayerProperties (1, 0)); + + m.transaction ("import"); + cell = l.recover_proxy (info); + m.commit (); + EXPECT_EQ (cell->get_qualified_name (), "Basic.CIRCLE"); + EXPECT_EQ (cell->get_basic_name (), "CIRCLE"); + EXPECT_EQ (cell->get_display_name (), "Basic.CIRCLE(l=1/0,r=10,n=8)"); + + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-4142 -10000} {-10000 -4142} {-10000 4142} {-4142 10000} {4142 10000} {10000 4142} {10000 -4142} {4142 -10000} {-4142 -10000}\nend_cell\nend_lib\n"); + + db::ProxyContextInfo info2; + l.get_context_info (cell->cell_index (), info2); + info2.pcell_parameters ["actual_radius"] = tl::Variant (5.0); + + m.transaction ("modify"); + db::cell_index_type ci = cell->cell_index (); + l.recover_proxy_as (ci, info2); + m.commit (); + cell = &l.cell (ci); + EXPECT_EQ (cell->get_qualified_name (), "Basic.CIRCLE"); + EXPECT_EQ (cell->get_basic_name (), "CIRCLE"); + EXPECT_EQ (cell->get_display_name (), "Basic.CIRCLE(l=1/0,r=5,n=8)"); + + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-2071 -5000} {-5000 -2071} {-5000 2071} {-2071 5000} {2071 5000} {5000 2071} {5000 -2071} {2071 -5000} {-2071 -5000}\nend_cell\nend_lib\n"); + + m.undo (); + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-4142 -10000} {-10000 -4142} {-10000 4142} {-4142 10000} {4142 10000} {10000 4142} {10000 -4142} {4142 -10000} {-4142 -10000}\nend_cell\nend_lib\n"); + m.redo (); + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-2071 -5000} {-5000 -2071} {-5000 2071} {-2071 5000} {2071 5000} {5000 2071} {5000 -2071} {2071 -5000} {-2071 -5000}\nend_cell\nend_lib\n"); +} diff --git a/src/lay/lay/layTechnologyController.cc b/src/lay/lay/layTechnologyController.cc index d84876401..53f85f05a 100644 --- a/src/lay/lay/layTechnologyController.cc +++ b/src/lay/lay/layTechnologyController.cc @@ -285,15 +285,33 @@ bool TechnologyController::menu_activated (const std::string &symbol) const { if (symbol == "technology_selector:apply_technology") { + if (lay::LayoutView::current () && lay::LayoutView::current ()->active_cellview ().is_valid ()) { - // Cancels the current modes - changing the technology may make libraries unavailable - // for example. + if (mp_mw) { + + // Cancels the current modes - changing the technology may make libraries unavailable + // for example. mp_mw->cancel (); + + // apply technology with undo + mp_mw->manager ().transaction (tl::sprintf (tl::to_string (tr ("Apply technology '%s'")), m_current_technology)); + try { + lay::LayoutView::current ()->active_cellview ()->apply_technology (m_current_technology); + mp_mw->manager ().commit (); + } catch (...) { + mp_mw->manager ().cancel (); + throw; + } + + } else { + lay::LayoutView::current ()->active_cellview ()->apply_technology (m_current_technology); } - lay::LayoutView::current ()->active_cellview ()->apply_technology (m_current_technology); + } + return true; + } else { return lay::PluginDeclaration::menu_activated (symbol); } diff --git a/src/laybasic/laybasic/layCellView.cc b/src/laybasic/laybasic/layCellView.cc index e42317c43..1aacc1c67 100644 --- a/src/laybasic/laybasic/layCellView.cc +++ b/src/laybasic/laybasic/layCellView.cc @@ -59,6 +59,8 @@ LayoutHandle::LayoutHandle (db::Layout *layout, const std::string &filename) m_dirty (false), m_save_options_valid (false) { + layout->technology_changed_event.add (this, &LayoutHandle::on_technology_changed); + // layouts in the managed layouts space participate in spare proxy cleanup layout->do_cleanup (true); @@ -108,6 +110,12 @@ LayoutHandle::~LayoutHandle () file_watcher ().remove_file (filename ()); } +void +LayoutHandle::on_technology_changed () +{ + technology_changed_event (); +} + void LayoutHandle::layout_changed () { @@ -232,7 +240,6 @@ LayoutHandle::set_tech_name (const std::string &tn) { if (mp_layout && tn != tech_name ()) { mp_layout->set_technology_name (tn); - technology_changed_event (); } } diff --git a/src/laybasic/laybasic/layCellView.h b/src/laybasic/laybasic/layCellView.h index 5f036b728..7d2ac54e4 100644 --- a/src/laybasic/laybasic/layCellView.h +++ b/src/laybasic/laybasic/layCellView.h @@ -302,6 +302,8 @@ private: bool m_save_options_valid; db::LoadLayoutOptions m_load_options; + void on_technology_changed (); + static std::map ms_dict; static tl::FileSystemWatcher *mp_file_watcher; }; From 92d81c58443e7c7a1b025229227f752747015a41 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Dec 2020 22:09:21 +0100 Subject: [PATCH 13/44] WIP: cold proxies are written to GDS2 and OASIS too. This means we keep the library references even if we load and save with the wrong libraries or technology. --- src/db/db/dbLayout.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 6ff5baecf..ad60aad38 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -2472,6 +2472,13 @@ bool Layout::get_context_info (cell_index_type cell_index, ProxyContextInfo &info) const { const db::Cell *cptr = &cell (cell_index); + + const db::ColdProxy *cold_proxy = dynamic_cast (cptr); + if (cold_proxy) { + info = cold_proxy->context_info (); + return true; + } + const db::Layout *ly = this; const db::LibraryProxy *lib_proxy; From 11bf413cb81481bebbeb37fda84538d41746d290 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Dec 2020 22:13:51 +0100 Subject: [PATCH 14/44] Fixed the manager's 'cancel' implementation: with this, redo of a cancelled operation isn't possible any more --- src/db/db/dbManager.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/db/db/dbManager.cc b/src/db/db/dbManager.cc index 5e53b1a83..0a9e24016 100644 --- a/src/db/db/dbManager.cc +++ b/src/db/db/dbManager.cc @@ -156,16 +156,14 @@ Manager::cancel () m_opened = false; if (m_current->first.begin () != m_current->first.end ()) { - ++m_current; undo (); - - } else { - // empty transactions .. just delete - erase_transactions (m_current, m_transactions.end ()); - m_current = m_transactions.end (); } + // wipe following history as we don't want the cancelled operation to be redoable + erase_transactions (m_current, m_transactions.end ()); + m_current = m_transactions.end (); + } } From 85311d414c99865e3b0e570b15566d2bda0d8764 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 14 Dec 2020 22:20:29 +0100 Subject: [PATCH 15/44] Implemented LEF DENSITY statement properly --- .../lefdef/db_plugin/dbLEFImporter.cc | 18 ++++++++++++ .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 6 ++++ testdata/lefdef/density/.in.lef.swp | Bin 0 -> 12288 bytes testdata/lefdef/density/au.oas.gz | Bin 0 -> 493 bytes testdata/lefdef/density/in.lef | 27 ++++++++++++++++++ 5 files changed, 51 insertions(+) create mode 100644 testdata/lefdef/density/.in.lef.swp create mode 100644 testdata/lefdef/density/au.oas.gz create mode 100644 testdata/lefdef/density/in.lef diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc index c1a6caa1c..00be1e947 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc @@ -937,6 +937,24 @@ LEFImporter::read_macro (Layout &layout) expect ("END"); + } else if (test ("DENSITY")) { + + // read over DENSITY statements + while (! test ("END")) { + if (test ("LAYER")) { + get (); + expect (";"); + } else { + expect ("RECT"); + for (int i = 0; i < 5; ++i) { + get_double (); + } + expect (";"); + } + } + + expect ("END"); + } else if (test ("FIXEDMASK")) { mg->set_fixedmask (true); diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index 4e71f6032..c46067119 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -719,6 +719,11 @@ TEST(117_mapfile_all) ) } +TEST(118_density) +{ + run_test (_this, "density", "read:in.lef", "au.oas.gz", default_options (), false); +} + TEST(200_lefdef_plugin) { db::Layout ly; @@ -764,3 +769,4 @@ TEST(201_lefdef_plugin_explicit_lef) db::compare_layouts (_this, ly, fn_path + "au_plugin_alt_lef.oas.gz", db::WriteOAS); } + diff --git a/testdata/lefdef/density/.in.lef.swp b/testdata/lefdef/density/.in.lef.swp new file mode 100644 index 0000000000000000000000000000000000000000..b3c13c94dad2bd3db908b980f22d02d0971a1a55 GIT binary patch literal 12288 zcmeI2O=}ZD9L6Vl@F1PPUd+o97xJRJn@U8Gt=Z6E(u8DkD2n|E zdhrW*@$Aiu9=!A>2x2|y&95MM@|oRDv=Ne%g7P1DW_D+ud1mIfdkNWHv13?N-p%TfzRQBMzJ{I!sWeOkh`>SuW7*!!EwPko2<2T{z05COXe^vY z1|mQNhyW2F0z`la5CI}U1pXfaa*$w$IL@i~NSER^G1JDk)DQt8Km>>Y5g-CYfCvx) zB0vO)01+Sp{~!Us#n`na#@<5e|NqJF|8M8;EdcZd`T!k4Z=l!EOXxZD1bPUKp<9p! ztw7(G89RpFLr2gn=qYpv8PI2}^$B_xuloY+Bgli2&>Y5g-CYfCvx) zBJfuUShW(b*aau=G#RdEZn^qQIbfWlAGIouRrI*{1HL(tbB0*Bsc2V*5L|E*wYo~1 zn#s5M+Az2;d3)IJ@pW`3#Rivsz7AJX**22l8SyDL@3+G_SALCDfhsHv%xIaJz-gRH z{yhy7qO?lBX*qny&KrFDM7$=_TxenoRW_@tTt=;>iP#rStVYxDbX?nOB4GA$XeQKE_pZL6rhAX)(b9b z*S=$+?{@wh!N?Dtm# literal 0 HcmV?d00001 diff --git a/testdata/lefdef/density/au.oas.gz b/testdata/lefdef/density/au.oas.gz new file mode 100644 index 0000000000000000000000000000000000000000..c24d3412bf8b64b14b65e78f20b85a8b7fc7e7ac GIT binary patch literal 493 zcmY!lcJ=kt^>+;R4CduxWH!_@V0gjKfDB|rrGn#q9V6m{J>C6WUE)3cLR{TlgW|(I zT|zuKSY&u*Akv|J*c8Z!as|hS_y@#0yZZR>u%@Ku6{j*oC~kKD&=4O_KUZdEW(FQ) z4mX>xp`O1}Ff$`FGY=A*n Date: Mon, 14 Dec 2020 22:46:07 +0100 Subject: [PATCH 16/44] LEF/DEF reader: Macro resolution mode is only effective now when reading DEF. Not when reading LEF. --- .../lefdef/db_plugin/dbLEFDEFImporter.h | 2 +- .../lefdef/db_plugin/dbLEFDEFPlugin.cc | 21 ++++++++++-------- .../lefdef/db_plugin/gsiDeclDbLEFDEF.cc | 6 ++--- .../LEFDEFTechnologyComponentEditor.ui | 4 +++- testdata/lefdef/density/.in.lef.swp | Bin 12288 -> 0 bytes testdata/lefdef/density/in.lef | 1 + 6 files changed, 20 insertions(+), 14 deletions(-) delete mode 100644 testdata/lefdef/density/.in.lef.swp diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h index ec1da4076..078361d33 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h @@ -775,7 +775,7 @@ public: } /** - * @brief Specify the LEF macro resolution strategy + * @brief Specify the LEF macro resolution strategy when reading DEF files * Values are: * 0: propduce LEF geometry unless a FOREIGN cell is specified (default) * 1: produce LEF geometry always and ignore FOREIGN diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc index c874ab814..470e87d19 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc @@ -113,22 +113,25 @@ private: const db::LayerMap &read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &options, bool import_lef) { const db::LEFDEFReaderOptions *lefdef_options = dynamic_cast (options.get_options (format ())); - static db::LEFDEFReaderOptions default_options; - if (! lefdef_options) { - lefdef_options = &default_options; + db::LEFDEFReaderOptions effective_options; + if (lefdef_options) { + effective_options = *lefdef_options; } - db::LEFDEFReaderState state (lefdef_options, layout, tl::dirname (m_stream.absolute_path ())); + db::LEFDEFReaderState state (&effective_options, layout, tl::dirname (m_stream.absolute_path ())); - layout.dbu (lefdef_options->dbu ()); + layout.dbu (effective_options.dbu ()); if (import_lef) { + // Always produce LEF geometry when reading LEF + effective_options.set_macro_resolution_mode (1); + tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF file"))); db::LEFImporter importer; - for (std::vector::const_iterator l = lefdef_options->begin_lef_files (); l != lefdef_options->end_lef_files (); ++l) { + for (std::vector::const_iterator l = effective_options.begin_lef_files (); l != effective_options.end_lef_files (); ++l) { std::string lp = correct_path (*l, layout, tl::dirname (m_stream.absolute_path ())); @@ -149,7 +152,7 @@ private: DEFImporter importer; - for (std::vector::const_iterator l = lefdef_options->begin_lef_files (); l != lefdef_options->end_lef_files (); ++l) { + for (std::vector::const_iterator l = effective_options.begin_lef_files (); l != effective_options.end_lef_files (); ++l) { std::string lp = correct_path (*l, layout, tl::dirname (m_stream.absolute_path ())); @@ -163,7 +166,7 @@ private: // Additionally read all LEF files next to the DEF file - if (lefdef_options->read_lef_with_def ()) { + if (effective_options.read_lef_with_def ()) { std::string input_dir = tl::absolute_path (m_stream.absolute_path ()); @@ -198,7 +201,7 @@ private: std::map foreign_cells = state.foreign_cells (); db::cell_index_type seen = std::numeric_limits::max (); - std::vector macro_layouts = lefdef_options->macro_layouts (); + std::vector macro_layouts = effective_options.macro_layouts (); for (std::vector::const_iterator m = macro_layouts.begin (); m != macro_layouts.end (); ++m) { std::vector target_cells, source_cells; diff --git a/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc b/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc index b86a4fd21..2643028f6 100644 --- a/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc +++ b/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc @@ -770,8 +770,8 @@ gsi::Class decl_lefdef_config ("db", "LEFDEFReaderConfi "This property has been added in version 0.27.\n" ) + gsi::method ("macro_resolution_mode", &db::LEFDEFReaderOptions::macro_resolution_mode, - "@brief Gets the macro resolution mode.\n" - "This property describes the way LEF macros are turned into GDS cells. There " + "@brief Gets the macro resolution mode (LEF macros into DEF).\n" + "This property describes the way LEF macros are turned into layout cells when reading DEF. There " "are three modes available:\n" "\n" "@ul\n" @@ -786,7 +786,7 @@ gsi::Class decl_lefdef_config ("db", "LEFDEFReaderConfi "This property has been added in version 0.27.\n" ) + gsi::method ("macro_resolution_mode=", &db::LEFDEFReaderOptions::set_macro_resolution_mode, gsi::arg ("mode"), - "@brief Sets the macro resolution mode.\n" + "@brief Sets the macro resolution mode (LEF macros into DEF).\n" "See \\macro_resolution_mode for details about this property.\n" "\n" "This property has been added in version 0.27.\n" diff --git a/src/plugins/streamers/lefdef/lay_plugin/LEFDEFTechnologyComponentEditor.ui b/src/plugins/streamers/lefdef/lay_plugin/LEFDEFTechnologyComponentEditor.ui index 18825ffa5..73212cb25 100644 --- a/src/plugins/streamers/lefdef/lay_plugin/LEFDEFTechnologyComponentEditor.ui +++ b/src/plugins/streamers/lefdef/lay_plugin/LEFDEFTechnologyComponentEditor.ui @@ -294,7 +294,7 @@ - LEF import + LEF import into DEF @@ -708,6 +708,8 @@ If a layer map file is given, pattern based rules are ignored. If used inside a technology, the file will be looked up relative to the technology's base path. +Otherwise it's looked up relative to the LEF or DEF file. + (2*) Die area, Blockage and Region layers in map file will have priority over global production rules above. diff --git a/testdata/lefdef/density/.in.lef.swp b/testdata/lefdef/density/.in.lef.swp deleted file mode 100644 index b3c13c94dad2bd3db908b980f22d02d0971a1a55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2O=}ZD9L6Vl@F1PPUd+o97xJRJn@U8Gt=Z6E(u8DkD2n|E zdhrW*@$Aiu9=!A>2x2|y&95MM@|oRDv=Ne%g7P1DW_D+ud1mIfdkNWHv13?N-p%TfzRQBMzJ{I!sWeOkh`>SuW7*!!EwPko2<2T{z05COXe^vY z1|mQNhyW2F0z`la5CI}U1pXfaa*$w$IL@i~NSER^G1JDk)DQt8Km>>Y5g-CYfCvx) zB0vO)01+Sp{~!Us#n`na#@<5e|NqJF|8M8;EdcZd`T!k4Z=l!EOXxZD1bPUKp<9p! ztw7(G89RpFLr2gn=qYpv8PI2}^$B_xuloY+Bgli2&>Y5g-CYfCvx) zBJfuUShW(b*aau=G#RdEZn^qQIbfWlAGIouRrI*{1HL(tbB0*Bsc2V*5L|E*wYo~1 zn#s5M+Az2;d3)IJ@pW`3#Rivsz7AJX**22l8SyDL@3+G_SALCDfhsHv%xIaJz-gRH z{yhy7qO?lBX*qny&KrFDM7$=_TxenoRW_@tTt=;>iP#rStVYxDbX?nOB4GA$XeQKE_pZL6rhAX)(b9b z*S=$+?{@wh!N?Dtm# diff --git a/testdata/lefdef/density/in.lef b/testdata/lefdef/density/in.lef index 889d5763d..abc0ccbf6 100644 --- a/testdata/lefdef/density/in.lef +++ b/testdata/lefdef/density/in.lef @@ -8,6 +8,7 @@ END VIA1 MACRO dense CLASS CORE ; ORIGIN 0.0 0.0 ; + FOREIGN dense ; SIZE 0.7 BY 0.9 ; OBS LAYER M1 DESIGNRULEWIDTH 0.05 ; From 1106a52688b22b1207379503cf96818423a31d97 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 14 Dec 2020 23:55:04 +0100 Subject: [PATCH 17/44] WIP: first draft of implementation --- src/db/db/dbStreamLayers.cc | 268 +++++++++++++++++++++++++++--------- src/db/db/dbStreamLayers.h | 69 ++++++++-- 2 files changed, 262 insertions(+), 75 deletions(-) diff --git a/src/db/db/dbStreamLayers.cc b/src/db/db/dbStreamLayers.cc index fb33f3ac7..f73d3dc11 100644 --- a/src/db/db/dbStreamLayers.cc +++ b/src/db/db/dbStreamLayers.cc @@ -40,10 +40,9 @@ namespace db /// A helper class to join two datatype map members struct LmapJoinOp1 { - void operator() (unsigned int &a, unsigned int b) + void operator() (std::set &a, const std::set &b) { - // TODO: could also do?: throw an exception .. - a = b; + a.insert (b.begin (), b.end ()); } }; @@ -58,7 +57,27 @@ struct LmapJoinOp2 } }; -/// Utility typedefs for the expression parser +/// A helper class to implement the unmap operation +struct LmapEraseDatatypeInterval +{ + LmapEraseDatatypeInterval (unsigned int dfrom, unsigned int dto) + : m_dfrom (dfrom), m_dto (dto) + { } + + void operator() (LayerMap::datatype_map &a, const LayerMap::datatype_map &) + { + if (is_static_ld (m_dfrom) && is_static_ld (m_dto)) { + a.erase (m_dfrom, m_dto); + } else { + a.clear (); + } + } + +private: + unsigned int m_dfrom, m_dto; +}; + +/// Utility typedefs for the expression parser typedef std::pair ld_interval; /// Utility typedefs for the expression parser @@ -71,70 +90,70 @@ LayerMap::LayerMap () // .. nothing yet .. } -std::pair +std::set LayerMap::logical (const LDPair &p) const { return logical_internal (p, false); } -std::pair +std::set LayerMap::logical (const std::string &n) const { return logical_internal (n, false); } -std::pair +std::set LayerMap::logical (const db::LayerProperties &p) const { return logical_internal (p, false); } -std::pair +std::set LayerMap::logical_internal (const LDPair &p, bool allow_placeholder) const { const datatype_map *dm = m_ld_map.mapped (p.layer); if (dm) { - const unsigned int *l = dm->mapped (p.datatype); + const std::set *l = dm->mapped (p.datatype); if (l && (allow_placeholder || ! is_placeholder (*l))) { - return std::make_pair (true, *l); + return *l; } } - return std::make_pair (false, 0); + return std::set (); } -std::pair +std::set LayerMap::logical_internal (const std::string &n, bool allow_placeholder) const { - std::map::const_iterator m = m_name_map.find (n); + std::map >::const_iterator m = m_name_map.find (n); if (m != m_name_map.end () && (allow_placeholder || ! is_placeholder (m->second))) { - return std::make_pair (true, m->second); + return m->second; } else { - return std::make_pair (false, 0); + return std::set (); } } -std::pair +std::set LayerMap::logical_internal (const db::LayerProperties &p, bool allow_placeholder) const { + std::set m; if (p.layer >= 0 && p.datatype >= 0) { - std::pair m = logical_internal (db::LDPair (p.layer, p.datatype), allow_placeholder); - if (m.first) { - return m; - } + m = logical_internal (db::LDPair (p.layer, p.datatype), allow_placeholder); } - if (! p.name.empty ()) { - std::pair m = logical_internal (p.name, allow_placeholder); - if (m.first) { - return m; - } + if (m.empty () && ! p.name.empty ()) { + m = logical_internal (p.name, allow_placeholder); } - return std::make_pair (false, 0); + return m; } bool -LayerMap::is_placeholder (unsigned int l) const +LayerMap::is_placeholder (const std::set &m) const { - return (m_placeholders.size () > std::numeric_limits::max () - l); + for (std::set::const_iterator i = m.begin (); i != m.end (); ++i) { + if (m_placeholders.size () > std::numeric_limits::max () - *i) { + return true; + } + } + return false; } const db::LayerProperties * @@ -148,39 +167,52 @@ LayerMap::target (unsigned int l) const } } -std::pair +std::set LayerMap::logical (const db::LayerProperties &p, db::Layout &layout) const { - std::pair l = logical_internal (p, true); - if (l.first && is_placeholder (l.second)) { - return const_cast (this)->substitute_placeholder (p, l.second, layout); + std::set l = logical_internal (p, true); + if (is_placeholder (l)) { + return const_cast (this)->substitute_placeholder (p, l, layout); } else { return l; } } -std::pair +std::set LayerMap::logical (const db::LDPair &p, db::Layout &layout) const { - std::pair l = logical_internal (p, true); - if (l.first && is_placeholder (l.second)) { - return const_cast (this)->substitute_placeholder (db::LayerProperties (p.layer, p.datatype), l.second, layout); + std::set l = logical_internal (p, true); + if (is_placeholder (l)) { + return const_cast (this)->substitute_placeholder (db::LayerProperties (p.layer, p.datatype), l, layout); } else { return l; } } -std::pair -LayerMap::substitute_placeholder (const db::LayerProperties &p, unsigned int ph, db::Layout &layout) +std::set +LayerMap::substitute_placeholder (const db::LayerProperties &p, const std::set &m, db::Layout &layout) { - const db::LayerProperties &lp_ph = m_placeholders [std::numeric_limits::max () - ph]; - db::LayerProperties lp_new = p; - lp_new.layer = db::ld_combine (p.layer, lp_ph.layer); - lp_new.datatype = db::ld_combine (p.datatype, lp_ph.datatype); + std::set res; + for (std::set::const_iterator i = m.begin (); i != m.end (); ++i) { - unsigned int l_new = layout.insert_layer (lp_new); - map (p, l_new, lp_new); - return std::make_pair (true, l_new); + if (m_placeholders.size () > std::numeric_limits::max () - *i) { + + const db::LayerProperties &lp_ph = m_placeholders [std::numeric_limits::max () - *i]; + db::LayerProperties lp_new = p; + lp_new.layer = db::ld_combine (p.layer, lp_ph.layer); + lp_new.datatype = db::ld_combine (p.datatype, lp_ph.datatype); + + unsigned int l_new = layout.insert_layer (lp_new); + map (p, l_new, lp_new); + res.insert (l_new); + + } else { + res.insert (*i); + } + + } + + return res; } static std::string format_interval (ld_type l1, ld_type l2) @@ -206,7 +238,7 @@ LayerMap::mapping_str (unsigned int ll) const bool f2 = true; for (datatype_map::const_iterator d = l->second.begin (); d != l->second.end (); ++d) { - if (d->second == ll) { + if (d->second.find (ll) != d->second.end ()) { // create a string representation if (!f2) { @@ -232,8 +264,9 @@ LayerMap::mapping_str (unsigned int ll) const } - for (std::map ::const_iterator l = m_name_map.begin (); l != m_name_map.end (); ++l) { - if (l->second == ll) { + for (std::map >::const_iterator l = m_name_map.begin (); l != m_name_map.end (); ++l) { + + if (l->second.find (ll) != l->second.end ()) { if (!f1) { s += ";"; @@ -243,6 +276,7 @@ LayerMap::mapping_str (unsigned int ll) const s += tl::to_word_or_quoted_string (l->first); } + } std::map::const_iterator t = m_target_layers.find (ll); @@ -300,11 +334,19 @@ LayerMap::prepare (db::Layout &layout) // Now remap the indexes for (ld_map::iterator l = m_ld_map.begin (); l != m_ld_map.end (); ++l) { for (datatype_map::iterator d = l->second.begin (); d != l->second.end (); ++d) { - d->second = real_layers [d->second]; + std::set dn; + for (std::set::const_iterator i = d->second.begin (); i != d->second.end (); ++i) { + dn.insert (real_layers [*i]); + } + d->second = dn; } } - for (std::map::iterator n = m_name_map.begin (); n != m_name_map.end (); ++n) { - n->second = real_layers [n->second]; + for (std::map >::iterator n = m_name_map.begin (); n != m_name_map.end (); ++n) { + std::set dn; + for (std::set::const_iterator i = n->second.begin (); i != n->second.end (); ++i) { + dn.insert (real_layers [*i]); + } + n->second = dn; } std::map old_target_layers; @@ -329,11 +371,11 @@ LayerMap::get_layers () const for (ld_map::const_iterator l = m_ld_map.begin (); l != m_ld_map.end (); ++l) { for (datatype_map::const_iterator d = l->second.begin (); d != l->second.end (); ++d) { - layers.insert (d->second); + layers.insert (d->second.begin (), d->second.end ()); } } for (const_iterator_names n = m_name_map.begin (); n != m_name_map.end (); ++n) { - layers.insert(n->second); + layers.insert(n->second.begin (), n->second.end ()); } return std::vector (layers.begin (), layers.end ()); @@ -358,7 +400,7 @@ LayerMap::mapping (unsigned int ll) const // no mapping is given. Use the lowest layer and datatype for (ld_map::const_iterator l = m_ld_map.begin (); l != m_ld_map.end (); ++l) { for (datatype_map::const_iterator d = l->second.begin (); d != l->second.end (); ++d) { - if (d->second == ll) { + if (d->second.find (ll) != d->second.end ()) { p.layer = l->first.first; p.datatype = d->first.first; break; @@ -373,7 +415,7 @@ LayerMap::mapping (unsigned int ll) const // no mapping is given. Use the lowest layer and datatype for (ld_map::const_iterator l = m_ld_map.begin (); l != m_ld_map.end (); ++l) { for (datatype_map::const_iterator d = l->second.begin (); d != l->second.end (); ++d) { - if (d->second == ll) { + if (d->second.find (ll) != d->second.end ()) { p.layer = l->first.first; p.datatype = d->first.first; break; @@ -384,8 +426,8 @@ LayerMap::mapping (unsigned int ll) const } if (p.name.empty ()) { - for (std::map ::const_iterator l = m_name_map.begin (); l != m_name_map.end (); ++l) { - if (l->second == ll) { + for (std::map >::const_iterator l = m_name_map.begin (); l != m_name_map.end (); ++l) { + if (l->second.find (ll) != l->second.end ()) { p.name = l->first; break; } @@ -515,7 +557,7 @@ LayerMap::map_expr (tl::Extractor &ex, unsigned int l) ld_type n; if (! ex.try_read (n) && ex.try_read_word_or_quoted (name)) { - m_name_map.insert (std::make_pair (name, l)); + m_name_map [name].insert (l); } else { @@ -533,7 +575,9 @@ LayerMap::map_expr (tl::Extractor &ex, unsigned int l) datatype_map dm; for (ld_interval_vector::const_iterator di = vd.begin (); di != vd.end (); ++di) { LmapJoinOp1 op1; - dm.add (di->first, di->second + 1, l, op1); + std::set single; + single.insert (l); + dm.add (di->first, di->second + 1, single, op1); } for (ld_interval_vector::const_iterator li = vl.begin (); li != vl.end (); ++li) { LmapJoinOp2 op2; @@ -566,7 +610,7 @@ LayerMap::insert (const std::string &name, unsigned int l, const LayerProperties m_target_layers[l] = *target; } - m_name_map.insert (std::make_pair (name, l)); + m_name_map [name].insert (l); if (l >= m_next_index) { m_next_index = l + 1; @@ -580,13 +624,16 @@ LayerMap::insert (const LDPair &p1, const LDPair &p2, unsigned int l, const Laye m_target_layers[l] = *target; } + std::set single; + single.insert (l); + // create a single-interval list for the datatype range LayerMap::datatype_map dt; LmapJoinOp1 op1; if (db::is_static_ld (p1.datatype) && db::is_static_ld (p2.datatype)) { - dt.add (p1.datatype, p2.datatype + 1, l, op1); + dt.add (p1.datatype, p2.datatype + 1, single, op1); } else { - dt.add (0, std::numeric_limits::max (), l, op1); + dt.add (0, std::numeric_limits::max (), single, op1); } // add this to the layers using the special join operator that @@ -603,6 +650,103 @@ LayerMap::insert (const LDPair &p1, const LDPair &p2, unsigned int l, const Laye } } +void +LayerMap::unmap (const LDPair &f) +{ + unmap (f, f); +} + +void +LayerMap::unmap (const std::string &name) +{ + m_name_map.erase (name); +} + +void +LayerMap::unmap (const LayerProperties &f) +{ + if (f.name.empty () || is_static_ld (f.layer) || is_static_ld (f.datatype)) { + unmap (db::LDPair (f.layer, f.datatype)); + } + if (! f.name.empty ()) { + unmap (f.name); + } +} + + + +void +LayerMap::unmap (const LDPair &p1, const LDPair &p2) +{ + if (m_ld_map.begin () == m_ld_map.end ()) { + return; + } + + LmapEraseDatatypeInterval op (p1.datatype, p2.datatype); + if (db::is_static_ld (p1.layer) && db::is_static_ld (p2.layer)) { + m_ld_map.add (p1.layer, p1.layer + 1, LayerMap::datatype_map (), op); + } else { + m_ld_map.add (m_ld_map.begin ()->first.first, m_ld_map.end ()->first.second, LayerMap::datatype_map (), op); + } +} + +void +LayerMap::unmap_expr (const std::string &expr) +{ + tl::Extractor ex (expr.c_str ()); + unmap_expr (ex); + ex.expect_end (); +} + +void +LayerMap::unmap_expr (tl::Extractor &ex) +{ + try { + + do { + + tl::Extractor ex_saved = ex; + + std::string name; + ld_type n; + if (! ex.try_read (n) && ex.try_read_word_or_quoted (name)) { + + m_name_map.erase (name); + + } else { + + ex = ex_saved; + ld_interval_vector vl, vd; + + parse_intervals (ex, vl); + + if (ex.test ("/")) { + parse_intervals (ex, vd); + } else { + vd.push_back (ld_interval (0, 0)); + } + + for (ld_interval_vector::const_iterator li = vl.begin (); li != vl.end (); ++li) { + for (ld_interval_vector::const_iterator di = vd.begin (); di != vd.end (); ++di) { + unmap (LDPair (li->first, di->first), LDPair (li->second, di->second)); + } + } + + } + + } while (ex.test (";") || ex.test (",")); + + if (ex.test (":")) { + // ignore target layers + LayerProperties lp; + lp.read (ex, true); + } + + } catch (...) { + throw LayerSpecFormatException (ex.skip ()); + } +} + void LayerMap::clear () { diff --git a/src/db/db/dbStreamLayers.h b/src/db/db/dbStreamLayers.h index b142d7d95..8ea0d78b5 100644 --- a/src/db/db/dbStreamLayers.h +++ b/src/db/db/dbStreamLayers.h @@ -35,6 +35,7 @@ #include #include +#include namespace db { @@ -161,6 +162,15 @@ struct DB_PUBLIC LDPair * and effectively rename a layer or add layer name information to * a GDS layer/datatype layer. * + * "Unmapping" can be used to create "holes" in ranges of layers. + * For example, by first mapping layers 1 to 100, datatype 0 and then + * unmapping layer 50, datatype 0, the layers 1 to 49 and 51 to 100, datatype 0 + * are mapped. + * + * The layer map supports multi-mapping. That is, one input layer is + * mapped to multiple target layers. It also supports merging but + * mapping different input layers to a single target layer. + * * A layer map object can be used as a standalone object or in * conjunction with a layout object. As a standalone object, the * logical layers (indexes) are simply consecutive numbers. @@ -178,11 +188,11 @@ class DB_PUBLIC LayerMap : public gsi::ObjectBase { public: - typedef tl::interval_map datatype_map; + typedef tl::interval_map > datatype_map; typedef tl::interval_map ld_map; typedef ld_map::const_iterator const_iterator_layers; typedef datatype_map::const_iterator const_iterator_datatypes; - typedef std::map::const_iterator const_iterator_names; + typedef std::map >::const_iterator const_iterator_names; /** * @brief The constructor for an empty map @@ -195,7 +205,7 @@ public: * @return A pair telling if the layer is mapped (first=true) and * the logical layer mapped (second) if this is the case. */ - std::pair logical (const LDPair &p) const; + std::set logical (const LDPair &p) const; /** * @brief Query a layer mapping from a name @@ -203,7 +213,7 @@ public: * @return A pair telling if the layer is mapped (first=true) and * the logical layer mapped (second) if this is the case. */ - std::pair logical (const std::string &name) const; + std::set logical (const std::string &name) const; /** * @brief Query a layer mapping from a name or LDPair @@ -213,7 +223,7 @@ public: * * @param p The layer that is looked for */ - std::pair logical (const db::LayerProperties &p) const; + std::set logical (const db::LayerProperties &p) const; /** * @brief Query or install a layer mapping from a name or LDPair @@ -227,14 +237,14 @@ public: * the logical layers are placeholder values which will be replaced by * true layers during this method if a new layer is requested. */ - std::pair logical (const db::LayerProperties &p, db::Layout &layout) const; + std::set logical (const db::LayerProperties &p, db::Layout &layout) const; /** * @brief Query or install a layer mapping from a LDPair * * See the version for LayerProperties about details. */ - std::pair logical (const db::LDPair &p, db::Layout &layout) const; + std::set logical (const db::LDPair &p, db::Layout &layout) const; /** * @brief Gets the target layer for a given logical layer @@ -371,6 +381,39 @@ public: */ void map_expr (tl::Extractor &ex, unsigned int l); + /** + * @brief Unmaps a LDPair + */ + void unmap (const LDPair &f); + + /** + * @brief Unmaps the layer with the given name + */ + void unmap (const std::string &name); + + /** + * @brief Unmaps a layer with the given layer properties + */ + void unmap (const LayerProperties &f); + + /** + * @brief Removes any mapping for a range of ldpair's + * + * The range is given by two pairs p1,p2. The layers + * between [p1.l,p2.l] and with datatypes between [p1.d,p2.d] are unmapped. + */ + void unmap (const LDPair &p1, const LDPair &p2); + + /** + * @brief Removes any mapping for the layers given by the expression + */ + void unmap_expr (const std::string &expr); + + /** + * @brief Removes any mapping for the layers given by the expression + */ + void unmap_expr (tl::Extractor &ex); + /** * @brief Prepares a layer mapping object for reading * @@ -454,7 +497,7 @@ public: private: ld_map m_ld_map; - std::map m_name_map; + std::map > m_name_map; std::map m_target_layers; std::vector m_placeholders; unsigned int m_next_index; @@ -462,12 +505,12 @@ private: void insert (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties *t); void insert (const std::string &name, unsigned int l, const LayerProperties *t); - std::pair logical_internal (const LDPair &p, bool allow_placeholder) const; - std::pair logical_internal (const std::string &name, bool allow_placeholder) const; - std::pair logical_internal (const db::LayerProperties &p, bool allow_placeholder) const; + std::set logical_internal (const LDPair &p, bool allow_placeholder) const; + std::set logical_internal (const std::string &name, bool allow_placeholder) const; + std::set logical_internal (const db::LayerProperties &p, bool allow_placeholder) const; - std::pair substitute_placeholder (const db::LayerProperties &p, unsigned int ph, db::Layout &layout); - bool is_placeholder (unsigned int l) const; + std::set substitute_placeholder (const db::LayerProperties &p, const std::set &ph, db::Layout &layout); + bool is_placeholder (const std::set &l) const; }; } From 7852568284cf477fd06e64577b34d061fa69ec6e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 15 Dec 2020 18:42:43 +0100 Subject: [PATCH 18/44] WIP --- src/db/db/gsiDeclDbReader.cc | 98 +++++++++++++++++++++++++++++++++--- 1 file changed, 90 insertions(+), 8 deletions(-) diff --git a/src/db/db/gsiDeclDbReader.cc b/src/db/db/gsiDeclDbReader.cc index 24b4e5b2e..16ab5bf71 100644 --- a/src/db/db/gsiDeclDbReader.cc +++ b/src/db/db/gsiDeclDbReader.cc @@ -36,17 +36,23 @@ namespace gsi static bool lm_is_mapped (const db::LayerMap *layer_map, const db::LayerProperties &lp) { - return layer_map->logical (lp).first; + return !layer_map->logical (lp).empty (); } static int lm_logical (const db::LayerMap *layer_map, const db::LayerProperties &lp) { - std::pair lm = layer_map->logical (lp); - return lm.first ? int (lm.second) : -1; + std::set lm = layer_map->logical (lp); + return lm.empty () ? -1 : int (*lm.begin ()); } - static db::LayerProperties + static std::set + lm_logicals (const db::LayerMap *layer_map, const db::LayerProperties &lp) + { + return layer_map->logical (lp); + } + + static db::LayerProperties lm_mapping (const db::LayerMap *layer_map, unsigned int l) { return layer_map->mapping (l); @@ -82,16 +88,44 @@ namespace gsi layer_map->map_expr (s, l); } + static void + lm_unmap (db::LayerMap *layer_map, const db::LayerProperties &lp) + { + layer_map->unmap (lp); + } + + static void + lm_unmap_interval (db::LayerMap *layer_map, const db::LayerProperties &lp1, const db::LayerProperties &lp2) + { + layer_map->unmap (ldpair_from_lp (lp1), ldpair_from_lp (lp2)); + } + + static void + lm_unmap_string (db::LayerMap *layer_map, std::string &s) + { + layer_map->unmap_expr (s); + } + Class decl_LayerMap ("db", "LayerMap", gsi::method_ext ("is_mapped?", &lm_is_mapped, gsi::arg ("layer"), "@brief Check, if a given physical layer is mapped\n" "@param layer The physical layer specified with an \\LayerInfo object.\n" "@return True, if the layer is mapped." ) + - gsi::method_ext ("logical", &lm_logical, gsi::arg ("layer"), + gsi::method_ext ("#logical", &lm_logical, gsi::arg ("layer"), "@brief Returns the logical layer (the layer index in the layout object) for a given physical layer.n" "@param layer The physical layer specified with an \\LayerInfo object.\n" "@return The logical layer index or -1 if the layer is not mapped." + "\n" + "This method is deprecated with version 0.27 as in this version, layers can be mapped to multiple targets which " + "this method can't capture. Use \\logicals instead.\n" + ) + + gsi::method_ext ("logicals", &lm_logicals, gsi::arg ("layer"), + "@brief Returns the logical layers for a given physical layer.n" + "@param layer The physical layer specified with an \\LayerInfo object.\n" + "@return This list of logical layers this physical layer as mapped to or empty if there is no mapping." + "\n" + "This method has been introduced in version 0.27.\n" ) + gsi::method ("mapping_str", &db::LayerMap::mapping_str, gsi::arg ("log_layer"), "@brief Returns the mapping string for a given logical layer\n" @@ -162,11 +196,39 @@ namespace gsi "separated by a hyphen. Examples are: \"1/2\", \"1-5/0\", \"1,2,5/0\",\n" "\"1/5;5/6\".\n" "\n" - "A target layer can be specified with the \":\" notation where " - "the target is a valid layer specification string (i.e. \"1/0\").\n" + "layer/datatype wildcards can be specified with \"*\". When \"*\" is used\n" + "for the upper limit, it is equivalent to \"all layer above\". When used\n" + "alone, it is equivalent to \"all layers\". Examples: \"1 / *\", \"* / 10-*\"\n" + "\n" + "Named layers are specified simply by specifying the name, if\n" + "necessary in single or double quotes (if the name begins with a digit or\n" + "contains non-word characters). layer/datatype and name descriptions can\n" + "be mixed, i.e. \"AA;1/5\" (meaning: name \"AA\" or layer 1/datatype 5).\n" + "\n" + "A target layer can be specified with the \":\" notation, where\n" + "target is a valid string for a LayerProperties() object.\n" + "\n" + "A target can include relative layer/datatype specifications and wildcards.\n" + "For example, \"1-10/0: *+1/0\" will add 1 to the original layer number.\n" + "\"1-10/0-50: * / *\" will use the original layers.\n" "\n" "Target mapping has been added in version 0.20.\n" ) + + gsi::method_ext ("unmap", &lm_unmap, gsi::arg ("phys_layer"), + "@brief Unmaps the given layer\n" + "Unmapping will remove the specific layer from the mapping. This method allows generating " + "'mapping holes' by first mapping a range and then unmapping parts of it.\n" + "\n" + "This method has been introduced in version 0.27." + ) + + gsi::method_ext ("unmap", &lm_unmap_interval, gsi::arg ("pl_start"), gsi::arg ("pl_stop"), + "@brief Unmaps the layers from the given interval\n" + "This method has been introduced in version 0.27." + ) + + gsi::method_ext ("unmap", &lm_unmap_string, gsi::arg ("expr"), + "@brief Unmaps the layers from the given expression\n" + "This method has been introduced in version 0.27." + ) + gsi::method ("clear", &db::LayerMap::clear, "@brief Clears the map\n" ) + @@ -221,7 +283,27 @@ namespace gsi "ly.read(\"input.gds\", lo)\n" "@/code\n" "\n" - "The LayerMap class has been introduced in version 0.18." + "1:n mapping is possible: a physical layer can be mapped to multiple logical layers. For this, mapping acts additive. " + "The following example will map layer 1, datatypes 0 to 255 to logical layer 0, and layer 1, datatype 17 to logical layers " + "0 plus 1:" + "\n" + "@code" + "lm = RBA::LayerMap::new\n" + "lm.map(\"1/0-255\", 0)\n" + "lm.map(\"1/17\", 1)\n" + "@/code\n" + "\n" + "'unmapping' allows to remove a mapping. This allows creating 'holes' in mapping ranges. The followin example maps " + "layer 1, datatypes 0 to 16 and 18 to 255 to logical layer 0:" + "\n" + "@code" + "lm = RBA::LayerMap::new\n" + "lm.map(\"1/0-255\", 0)\n" + "lm.unmap(\"1/17\")\n" + "@/code\n" + "\n" + "The LayerMap class has been introduced in version 0.18. Target layer have been introduced in version 0.20. " + "1:n mapping and unmapping has been introduced in version 0.27." ); // NOTE: the contribution comes from format specific extensions. From 1f635015ce65b143741bde51e2c1b3ae3ef632cc Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 15 Dec 2020 23:05:34 +0100 Subject: [PATCH 19/44] WIP: backward compatible implementation of multi-map capability of layer mapping. --- src/db/db/dbGlyphs.cc | 12 +- src/db/db/dbLayoutQuery.cc | 2 +- src/db/db/dbNamedLayerReader.cc | 6 +- src/db/db/dbStreamLayers.cc | 84 ++++++++-- src/db/db/dbStreamLayers.h | 145 +++++++++++++++--- src/db/db/gsiDeclDbReader.cc | 86 ++++++++++- src/db/unit_tests/dbStreamLayerTests.cc | 126 +++++++++++---- src/lay/lay/laySearchReplaceDialog.cc | 2 +- .../streamers/dxf/db_plugin/dbDXFReader.cc | 2 +- .../gds2/db_plugin/dbGDS2ReaderBase.cc | 2 +- .../streamers/gds2/unit_tests/dbGDS2Reader.cc | 2 +- .../lefdef/db_plugin/dbLEFDEFImporter.cc | 6 +- .../oasis/db_plugin/dbOASISReader.cc | 2 +- 13 files changed, 393 insertions(+), 84 deletions(-) diff --git a/src/db/db/dbGlyphs.cc b/src/db/db/dbGlyphs.cc index ecea36e12..9cefc8b5e 100644 --- a/src/db/db/dbGlyphs.cc +++ b/src/db/db/dbGlyphs.cc @@ -174,9 +174,9 @@ TextGenerator::load_from_data (const char *data, size_t ndata, const std::string m_description = description; m_name = name; - std::pair l1 = map.logical (db::LDPair (1, 0)); - std::pair l2 = map.logical (db::LDPair (2, 0)); - std::pair l3 = map.logical (db::LDPair (3, 0)); + std::pair l1 = map.first_logical (db::LDPair (1, 0)); + std::pair l2 = map.first_logical (db::LDPair (2, 0)); + std::pair l3 = map.first_logical (db::LDPair (3, 0)); if (l1.first && l2.first) { read_from_layout (layout, l1.second, l2.second, l3.second); @@ -193,9 +193,9 @@ TextGenerator::load_from_file (const std::string &filename) m_description = filename; - std::pair l1 = map.logical (db::LDPair (1, 0)); - std::pair l2 = map.logical (db::LDPair (2, 0)); - std::pair l3 = map.logical (db::LDPair (3, 0)); + std::pair l1 = map.first_logical (db::LDPair (1, 0)); + std::pair l2 = map.first_logical (db::LDPair (2, 0)); + std::pair l3 = map.first_logical (db::LDPair (3, 0)); if (l1.first && l2.first) { read_from_layout (layout, l1.second, l2.second, l3.second); diff --git a/src/db/db/dbLayoutQuery.cc b/src/db/db/dbLayoutQuery.cc index 27ed3d8ad..3cf34a18e 100644 --- a/src/db/db/dbLayoutQuery.cc +++ b/src/db/db/dbLayoutQuery.cc @@ -228,7 +228,7 @@ public: { // get the layers which we have to look for for (db::Layout::layer_iterator l = layout->begin_layers (); l != layout->end_layers (); ++l) { - if (layers.is_empty () || layers.logical (*(*l).second).first) { + if (layers.is_empty () || layers.is_mapped (*(*l).second)) { m_layers.push_back ((*l).first); } } diff --git a/src/db/db/dbNamedLayerReader.cc b/src/db/db/dbNamedLayerReader.cc index 497fad153..adff2797f 100644 --- a/src/db/db/dbNamedLayerReader.cc +++ b/src/db/db/dbNamedLayerReader.cc @@ -128,7 +128,7 @@ NamedLayerReader::open_layer (db::Layout &layout, const std::string &n) std::pair ll (false, 0); - ll = m_layer_map.logical (n, layout); + ll = m_layer_map.first_logical (n, layout); if (! ll.first && !m_keep_layer_names) { if (extract_plain_layer (n.c_str (), l)) { @@ -136,7 +136,7 @@ NamedLayerReader::open_layer (db::Layout &layout, const std::string &n) db::LayerProperties lp; lp.layer = l; lp.datatype = 0; - ll = m_layer_map.logical (lp, layout); + ll = m_layer_map.first_logical (lp, layout); } else if (extract_ld (n.c_str (), l, d, on)) { @@ -144,7 +144,7 @@ NamedLayerReader::open_layer (db::Layout &layout, const std::string &n) lp.layer = l; lp.datatype = d; lp.name = on; - ll = m_layer_map.logical (lp, layout); + ll = m_layer_map.first_logical (lp, layout); } diff --git a/src/db/db/dbStreamLayers.cc b/src/db/db/dbStreamLayers.cc index f73d3dc11..e507ddea9 100644 --- a/src/db/db/dbStreamLayers.cc +++ b/src/db/db/dbStreamLayers.cc @@ -67,7 +67,7 @@ struct LmapEraseDatatypeInterval void operator() (LayerMap::datatype_map &a, const LayerMap::datatype_map &) { if (is_static_ld (m_dfrom) && is_static_ld (m_dto)) { - a.erase (m_dfrom, m_dto); + a.erase (m_dfrom, m_dto + 1); } else { a.clear (); } @@ -90,6 +90,40 @@ LayerMap::LayerMap () // .. nothing yet .. } +bool +LayerMap::is_mapped (const LDPair &p) const +{ + const datatype_map *dm = m_ld_map.mapped (p.layer); + if (!dm) { + return false; + } + const std::set *l = dm->mapped (p.datatype); + return (l && ! l->empty ()); +} + +bool +LayerMap::is_mapped (const std::string &n) const +{ + std::map >::const_iterator m = m_name_map.find (n); + return m != m_name_map.end () && ! m->second.empty (); +} + +bool +LayerMap::is_mapped (const db::LayerProperties &p) const +{ + std::set m; + if (p.layer >= 0 && p.datatype >= 0) { + if (is_mapped (db::LDPair (p.layer, p.datatype))) { + return true; + } + } + if (! p.name.empty ()) { + return is_mapped (p.name); + } else { + return false; + } +} + std::set LayerMap::logical (const LDPair &p) const { @@ -233,13 +267,19 @@ LayerMap::mapping_str (unsigned int ll) const { std::string s; bool f1 = true; + bool is_mmap = false; for (ld_map::const_iterator l = m_ld_map.begin (); l != m_ld_map.end (); ++l) { bool f2 = true; for (datatype_map::const_iterator d = l->second.begin (); d != l->second.end (); ++d) { + if (d->second.find (ll) != d->second.end ()) { + if (d->second.size () > 1) { + is_mmap = true; + } + // create a string representation if (!f2) { s += ","; @@ -268,6 +308,10 @@ LayerMap::mapping_str (unsigned int ll) const if (l->second.find (ll) != l->second.end ()) { + if (l->second.size () > 1) { + is_mmap = true; + } + if (!f1) { s += ";"; } @@ -285,7 +329,11 @@ LayerMap::mapping_str (unsigned int ll) const s += t->second.to_string (true); } - return s; + if (is_mmap) { + return "+" + s; + } else { + return s; + } } void @@ -439,19 +487,19 @@ LayerMap::mapping (unsigned int ll) const } void -LayerMap::map (const LDPair &p, unsigned int l) +LayerMap::mmap (const LDPair &p, unsigned int l) { insert (p, p, l, (const LayerProperties *) 0); } void -LayerMap::map (const std::string &name, unsigned int l) +LayerMap::mmap (const std::string &name, unsigned int l) { insert (name, l, (const LayerProperties *) 0); } void -LayerMap::map (const LayerProperties &f, unsigned int l) +LayerMap::mmap (const LayerProperties &f, unsigned int l) { if (f.name.empty () || is_static_ld (f.layer) || is_static_ld (f.datatype)) { map (db::LDPair (f.layer, f.datatype), l); @@ -462,19 +510,19 @@ LayerMap::map (const LayerProperties &f, unsigned int l) } void -LayerMap::map (const LDPair &p, unsigned int l, const LayerProperties &t) +LayerMap::mmap (const LDPair &p, unsigned int l, const LayerProperties &t) { insert (p, p, l, &t); } void -LayerMap::map (const std::string &name, unsigned int l, const LayerProperties &t) +LayerMap::mmap (const std::string &name, unsigned int l, const LayerProperties &t) { insert (name, l, &t); } void -LayerMap::map (const LayerProperties &f, unsigned int l, const LayerProperties &t) +LayerMap::mmap (const LayerProperties &f, unsigned int l, const LayerProperties &t) { if (f.name.empty () || is_static_ld (f.layer) || is_static_ld (f.datatype)) { map (db::LDPair (f.layer, f.datatype), l, t); @@ -485,13 +533,13 @@ LayerMap::map (const LayerProperties &f, unsigned int l, const LayerProperties & } void -LayerMap::map (const LDPair &p1, const LDPair &p2, unsigned int l) +LayerMap::mmap (const LDPair &p1, const LDPair &p2, unsigned int l) { insert (p1, p2, l, (const LayerProperties *) 0); } void -LayerMap::map (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties &lp) +LayerMap::mmap (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties &lp) { insert (p1, p2, l, &lp); } @@ -537,15 +585,15 @@ parse_intervals (tl::Extractor &ex, ld_interval_vector &v) } void -LayerMap::map_expr (const std::string &expr, unsigned int l) +LayerMap::mmap_expr (const std::string &expr, unsigned int l) { tl::Extractor ex (expr.c_str ()); - map_expr (ex, l); + mmap_expr (ex, l); ex.expect_end (); } void -LayerMap::map_expr (tl::Extractor &ex, unsigned int l) +LayerMap::mmap_expr (tl::Extractor &ex, unsigned int l) { try { @@ -684,7 +732,7 @@ LayerMap::unmap (const LDPair &p1, const LDPair &p2) LmapEraseDatatypeInterval op (p1.datatype, p2.datatype); if (db::is_static_ld (p1.layer) && db::is_static_ld (p2.layer)) { - m_ld_map.add (p1.layer, p1.layer + 1, LayerMap::datatype_map (), op); + m_ld_map.add (p1.layer, p2.layer + 1, LayerMap::datatype_map (), op); } else { m_ld_map.add (m_ld_map.begin ()->first.first, m_ld_map.end ()->first.second, LayerMap::datatype_map (), op); } @@ -812,7 +860,13 @@ LayerMap::from_string_file_format (const std::string &s) } else { if (! ex.at_end ()) { - lm.map_expr (ex, l); + if (ex.test ("+")) { + lm.mmap_expr (ex, l); + } else if (ex.test ("-")) { + lm.unmap_expr (ex); + } else { + lm.map_expr (ex, l); + } if (ex.test ("#") || ex.test ("//")) { // ignore comments } else { diff --git a/src/db/db/dbStreamLayers.h b/src/db/db/dbStreamLayers.h index 8ea0d78b5..26c15804a 100644 --- a/src/db/db/dbStreamLayers.h +++ b/src/db/db/dbStreamLayers.h @@ -199,7 +199,35 @@ public: */ LayerMap (); - /** + /** + * @brief Returns the first logical layer for a given layer specification + */ + template + std::pair first_logical (const L &p) const + { + std::set r = logical (p); + if (r.empty ()) { + return std::make_pair (false, 0); + } else { + return std::make_pair (true, *r.begin ()); + } + } + + /** + * @brief Returns the first logical layer for a given layer specification + */ + template + std::pair first_logical (const L &p, db::Layout &layout) const + { + std::set r = logical (p, layout); + if (r.empty ()) { + return std::make_pair (false, 0); + } else { + return std::make_pair (true, *r.begin ()); + } + } + + /** * @brief Query a layer mapping * * @return A pair telling if the layer is mapped (first=true) and @@ -246,6 +274,21 @@ public: */ std::set logical (const db::LDPair &p, db::Layout &layout) const; + /** + * @brief Returns a value indicating whether a layer (given by layer/datatype) is mapped + */ + bool is_mapped (const LDPair &p) const; + + /** + * @brief Returns a value indicating whether the given named layer is mapped + */ + bool is_mapped (const std::string &name) const; + + /** + * @brief Returns a value indicating whether a layer is mapped + */ + bool is_mapped (const db::LayerProperties &p) const; + /** * @brief Gets the target layer for a given logical layer * @@ -280,17 +323,81 @@ public: std::vector get_layers () const; /** - * @brief Map a ldpair to a logical layer + * @brief Single-map a physical to a logical layer + * + * "Single-mapping" substitutes a layer mapping. "Multimapping" (mmap_..) + * adds to a given mapping and allows generating 1:n mappings (m:n in fact). */ - void map (const LDPair &p, unsigned int l); + template + void map (const S &p, unsigned int l) + { + unmap (p); + mmap (p, l); + } /** - * @brief Map a name to a logical layer + * @brief Single-map a physical to a logical layer with a target layer */ - void map (const std::string &name, unsigned int l); + template + void map (const S &p, unsigned int l, const LayerProperties &t) + { + unmap (p); + mmap (p, l, t); + } /** - * @brief Map a name or LDPair to a logical layer + * @brief Single-map a physical layer interval with a target layer + */ + void map (const LDPair &p1, const LDPair &p2, unsigned int l) + { + unmap (p1, p2); + mmap (p1, p2, l); + } + + /** + * @brief Single-map a physical layer interval with a target layer + */ + void map (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties &t) + { + unmap (p1, p2); + mmap (p1, p2, l, t); + } + + /** + * @brief Single-map a physical layer interval (given by an expression) + */ + void map_expr (const std::string &expr, unsigned int l) + { + unmap_expr (expr); + mmap_expr (expr, l); + } + + /** + * @brief Same a map_expr with a string argument but taking the expression for a tl::Extractor + */ + void map_expr (tl::Extractor &ex, unsigned int l) + { + tl::Extractor ex1 = ex; + unmap_expr (ex1); + mmap_expr (ex, l); + } + + /** + * @brief Multi-map a ldpair to a logical layer + * + * "Multimapping" will not substitute but add to the mapping. + */ + void mmap (const LDPair &p, unsigned int l); + + /** + * @brief Multi-map a name to a logical layer + * + * "Multimapping" will not substitute but add to the mapping. + */ + void mmap (const std::string &name, unsigned int l); + + /** + * @brief Multi-map a name or LDPair to a logical layer * * The algorithm chooses the LDPair from the LayerProperties structure and/or * the name if no LDPair is given. If the source LayerProperties structure does @@ -299,26 +406,26 @@ public: * @param f The source (where to derive the match expression from) * @param l The logical layer to map to the match expression */ - void map (const LayerProperties &f, unsigned int l); + void mmap (const LayerProperties &f, unsigned int l); /** - * @brief Map a ldpair to a logical layer with a target layer + * @brief Multi-map a ldpair to a logical layer with a target layer * * The target layer specifies which layer to create for the * corresponding input. */ - void map (const LDPair &p, unsigned int l, const LayerProperties &t); + void mmap (const LDPair &p, unsigned int l, const LayerProperties &t); /** - * @brief Map a name to a logical layer with a target layer + * @brief Multi-map a name to a logical layer with a target layer * * The target layer specifies which layer to create for the * corresponding input. */ - void map (const std::string &name, unsigned int l, const LayerProperties &t); + void mmap (const std::string &name, unsigned int l, const LayerProperties &t); /** - * @brief Map a name or LDPair to a logical layer with a target layer + * @brief Multi-map a name or LDPair to a logical layer with a target layer * * The algorithm chooses the LDPair from the LayerProperties structure or * the name if no LDPair is given. If the source LayerProperties structure does @@ -328,23 +435,23 @@ public: * @param l The logical layer to map to the match expression * @param t The target layer to use for the mapped layer */ - void map (const LayerProperties &f, unsigned int l, const LayerProperties &t); + void mmap (const LayerProperties &f, unsigned int l, const LayerProperties &t); /** - * @brief Map a range of ldpair's to a logical layer + * @brief Multi-map a range of ldpair's to a logical layer * * The range is given by two pairs p1,p2. The layers * mapped are [p1.l,p2.l], the datatypes mapped are [p1.d,p2.d]. */ - void map (const LDPair &p1, const LDPair &p2, unsigned int l); + void mmap (const LDPair &p1, const LDPair &p2, unsigned int l); /** - * @brief Map a range of ldpair's to a logical layer with a target layer + * @brief Multi-map a range of ldpair's to a logical layer with a target layer * * The range is given by two pairs p1,p2. The layers * mapped are [p1.l,p2.l], the datatypes mapped are [p1.d,p2.d]. */ - void map (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties &t); + void mmap (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties &t); /** * @brief Map a range given by a string expression to a logical layer @@ -374,12 +481,12 @@ public: * This method will throw a LayerSpecFormatException if * something is wrong with the format string */ - void map_expr (const std::string &expr, unsigned int l); + void mmap_expr (const std::string &expr, unsigned int l); /** * @brief Same a map_expr with a string argument but taking the expression for a tl::Extractor */ - void map_expr (tl::Extractor &ex, unsigned int l); + void mmap_expr (tl::Extractor &ex, unsigned int l); /** * @brief Unmaps a LDPair diff --git a/src/db/db/gsiDeclDbReader.cc b/src/db/db/gsiDeclDbReader.cc index 16ab5bf71..19b82c6d3 100644 --- a/src/db/db/gsiDeclDbReader.cc +++ b/src/db/db/gsiDeclDbReader.cc @@ -36,7 +36,7 @@ namespace gsi static bool lm_is_mapped (const db::LayerMap *layer_map, const db::LayerProperties &lp) { - return !layer_map->logical (lp).empty (); + return layer_map->is_mapped (lp); } static int @@ -88,6 +88,36 @@ namespace gsi layer_map->map_expr (s, l); } + static void + lm_mmap (db::LayerMap *layer_map, const db::LayerProperties &lp, unsigned int l) + { + layer_map->mmap (lp, l); + } + + static void + lm_mmap_with_target (db::LayerMap *layer_map, const db::LayerProperties &lp, unsigned int l, const db::LayerProperties &t) + { + layer_map->mmap (lp, l, t); + } + + static void + lm_mmap_interval (db::LayerMap *layer_map, const db::LayerProperties &lp1, const db::LayerProperties &lp2, unsigned int l) + { + layer_map->mmap (ldpair_from_lp (lp1), ldpair_from_lp (lp2), l); + } + + static void + lm_mmap_interval_with_target (db::LayerMap *layer_map, const db::LayerProperties &lp1, const db::LayerProperties &lp2, unsigned int l, const db::LayerProperties &t) + { + layer_map->mmap (ldpair_from_lp (lp1), ldpair_from_lp (lp2), l, t); + } + + static void + lm_mmap_string (db::LayerMap *layer_map, std::string &s, unsigned int l) + { + layer_map->mmap_expr (s, l); + } + static void lm_unmap (db::LayerMap *layer_map, const db::LayerProperties &lp) { @@ -214,6 +244,51 @@ namespace gsi "\n" "Target mapping has been added in version 0.20.\n" ) + + gsi::method_ext ("mmap", &lm_mmap, gsi::arg ("phys_layer"), gsi::arg ("log_layer"), + "@brief Maps a physical layer to a logical one and adds to existing mappings\n" + "\n" + "This method acts like the corresponding 'map' method, but adds the logical layer to the receivers of the " + "given physical one. Hence this method implements 1:n mapping capabilities.\n" + "For backward compatibility, 'map' still substitutes mapping.\n" + "\n" + "Multi-mapping has been added in version 0.27.\n" + ) + + gsi::method_ext ("mmap", &lm_mmap_with_target, gsi::arg ("phys_layer"), gsi::arg ("log_layer"), gsi::arg ("target_layer"), + "@brief Maps a physical layer to a logical one, adds to existing mappings and specifies a target layer\n" + "\n" + "This method acts like the corresponding 'map' method, but adds the logical layer to the receivers of the " + "given physical one. Hence this method implements 1:n mapping capabilities.\n" + "For backward compatibility, 'map' still substitutes mapping.\n" + "\n" + "Multi-mapping has been added in version 0.27.\n" + ) + + gsi::method_ext ("mmap", &lm_mmap_interval, gsi::arg ("pl_start"), gsi::arg ("pl_stop"), gsi::arg ("log_layer"), + "@brief Maps a physical layer from the given interval to a logical one and adds to existing mappings\n" + "\n" + "This method acts like the corresponding 'map' method, but adds the logical layer to the receivers of the " + "given physical one. Hence this method implements 1:n mapping capabilities.\n" + "For backward compatibility, 'map' still substitutes mapping.\n" + "\n" + "Multi-mapping has been added in version 0.27.\n" + ) + + gsi::method_ext ("mmap", &lm_mmap_interval_with_target, gsi::arg ("pl_start"), gsi::arg ("pl_stop"), gsi::arg ("log_layer"), gsi::arg ("layer_properties"), + "@brief Maps a physical layer from the given interval to a logical one, adds to existing mappings and specifies a target layer\n" + "\n" + "This method acts like the corresponding 'map' method, but adds the logical layer to the receivers of the " + "given physical one. Hence this method implements 1:n mapping capabilities.\n" + "For backward compatibility, 'map' still substitutes mapping.\n" + "\n" + "Multi-mapping has been added in version 0.27.\n" + ) + + gsi::method_ext ("mmap", &lm_mmap_string, gsi::arg ("map_expr"), gsi::arg ("log_layer"), + "@brief Maps a physical layer given by an expression to a logical one and adds to existing mappings\n" + "\n" + "This method acts like the corresponding 'map' method, but adds the logical layer to the receivers of the " + "given physical one. Hence this method implements 1:n mapping capabilities.\n" + "For backward compatibility, 'map' still substitutes mapping.\n" + "\n" + "Multi-mapping has been added in version 0.27.\n" + ) + gsi::method_ext ("unmap", &lm_unmap, gsi::arg ("phys_layer"), "@brief Unmaps the given layer\n" "Unmapping will remove the specific layer from the mapping. This method allows generating " @@ -283,17 +358,18 @@ namespace gsi "ly.read(\"input.gds\", lo)\n" "@/code\n" "\n" - "1:n mapping is possible: a physical layer can be mapped to multiple logical layers. For this, mapping acts additive. " + "1:n mapping is supported: a physical layer can be mapped to multiple logical layers using 'mmap' instead of 'map'. When using this variant, " + "mapping acts additive.\n" "The following example will map layer 1, datatypes 0 to 255 to logical layer 0, and layer 1, datatype 17 to logical layers " "0 plus 1:" "\n" "@code" "lm = RBA::LayerMap::new\n" - "lm.map(\"1/0-255\", 0)\n" - "lm.map(\"1/17\", 1)\n" + "lm.map(\"1/0-255\", 0) # (can be 'mmap' too)\n" + "lm.mmap(\"1/17\", 1)\n" "@/code\n" "\n" - "'unmapping' allows to remove a mapping. This allows creating 'holes' in mapping ranges. The followin example maps " + "'unmapping' allows removing a mapping. This allows creating 'holes' in mapping ranges. The followin example maps " "layer 1, datatypes 0 to 16 and 18 to 255 to logical layer 0:" "\n" "@code" diff --git a/src/db/unit_tests/dbStreamLayerTests.cc b/src/db/unit_tests/dbStreamLayerTests.cc index b0ccf4f10..353e31693 100644 --- a/src/db/unit_tests/dbStreamLayerTests.cc +++ b/src/db/unit_tests/dbStreamLayerTests.cc @@ -29,14 +29,14 @@ TEST(1) db::LayerMap lm; lm.map (db::LDPair (1, 5), 17); - EXPECT_EQ (lm.logical (db::LDPair (1, 6)).first, false); - EXPECT_EQ (lm.logical (db::LDPair (1, 5)).first, true); - EXPECT_EQ (lm.logical (db::LDPair (1, 5)).second, (unsigned int) 17); + EXPECT_EQ (lm.first_logical (db::LDPair (1, 6)).first, false); + EXPECT_EQ (lm.first_logical (db::LDPair (1, 5)).first, true); + EXPECT_EQ (lm.first_logical (db::LDPair (1, 5)).second, (unsigned int) 17); lm.map (db::LDPair (1, 0), db::LDPair (5,0), 18); - EXPECT_EQ (lm.logical (db::LDPair (2, 0)).first, true); - EXPECT_EQ (lm.logical (db::LDPair (2, 0)).second, (unsigned int) 18); - EXPECT_EQ (lm.logical (db::LDPair (0, 0)).first, false); + EXPECT_EQ (lm.first_logical (db::LDPair (2, 0)).first, true); + EXPECT_EQ (lm.first_logical (db::LDPair (2, 0)).second, (unsigned int) 18); + EXPECT_EQ (lm.first_logical (db::LDPair (0, 0)).first, false); EXPECT_EQ (lm.mapping_str (18), "1/0;2-5/0"); EXPECT_EQ (lm.mapping_str (17), "1/5"); @@ -62,16 +62,16 @@ TEST(1) lm.map_expr ("XP;10/7-8 : XN", 13); EXPECT_EQ (lm.mapping_str (13), "10/7-8;XP : XN"); - EXPECT_EQ (lm.logical ("XP").second, (unsigned int) 13); - EXPECT_EQ (lm.logical ("XP").first, true); - EXPECT_EQ (lm.logical (db::LDPair(10, 6)).first, false); - EXPECT_EQ (lm.logical (db::LDPair(10, 7)).first, true); - EXPECT_EQ (lm.logical (db::LDPair(10, 7)).second, (unsigned int) 13); + EXPECT_EQ (lm.first_logical ("XP").second, (unsigned int) 13); + EXPECT_EQ (lm.first_logical ("XP").first, true); + EXPECT_EQ (lm.first_logical (db::LDPair(10, 6)).first, false); + EXPECT_EQ (lm.first_logical (db::LDPair(10, 7)).first, true); + EXPECT_EQ (lm.first_logical (db::LDPair(10, 7)).second, (unsigned int) 13); EXPECT_EQ (lm.mapping (13).to_string (), "XN (10/7)"); lm.clear (); - EXPECT_EQ (lm.logical (db::LDPair(10, 7)).first, false); + EXPECT_EQ (lm.first_logical (db::LDPair(10, 7)).first, false); lm.map_expr ("'XP';10/7-8 : XN", 13); EXPECT_EQ (lm.mapping_str (13), "10/7-8;XP : XN"); } @@ -349,55 +349,55 @@ TEST(6) EXPECT_EQ (layers_to_string (ly), "1/0,3/10"); std::pair p; - p = lm.logical (db::LayerProperties (1, 0)); + p = lm.first_logical (db::LayerProperties (1, 0)); EXPECT_EQ (p.first, true); EXPECT_EQ (p.second, (unsigned int) 0); - p = lm.logical (db::LayerProperties (2, 0)); + p = lm.first_logical (db::LayerProperties (2, 0)); EXPECT_EQ (p.first, false); - p = lm.logical (db::LayerProperties (3, 0)); + p = lm.first_logical (db::LayerProperties (3, 0)); EXPECT_EQ (p.first, false); - p = lm.logical (db::LayerProperties (3, 10)); + p = lm.first_logical (db::LayerProperties (3, 10)); EXPECT_EQ (p.first, true); EXPECT_EQ (p.second, (unsigned int) 1); - p = lm.logical (db::LayerProperties (3, 99)); + p = lm.first_logical (db::LayerProperties (3, 99)); EXPECT_EQ (p.first, true); EXPECT_EQ (p.second, (unsigned int) 1); EXPECT_EQ (layers_to_string (ly), "1/0,3/10"); // this will create layer 2/0 in the layout - p = lm.logical (db::LayerProperties (2, 0), ly); + p = lm.first_logical (db::LayerProperties (2, 0), ly); EXPECT_EQ (p.first, true); EXPECT_EQ (p.second, (unsigned int) 2); EXPECT_EQ (layers_to_string (ly), "1/0,3/10,2/0"); - p = lm.logical (db::LayerProperties (2, 0)); + p = lm.first_logical (db::LayerProperties (2, 0)); EXPECT_EQ (p.first, true); EXPECT_EQ (p.second, (unsigned int) 2); - p = lm.logical (db::LayerProperties (2, 0), ly); + p = lm.first_logical (db::LayerProperties (2, 0), ly); EXPECT_EQ (p.first, true); EXPECT_EQ (p.second, (unsigned int) 2); EXPECT_EQ (layers_to_string (ly), "1/0,3/10,2/0"); // this will create layer 2/42 in the layout - p = lm.logical (db::LayerProperties (2, 42), ly); + p = lm.first_logical (db::LayerProperties (2, 42), ly); EXPECT_EQ (p.first, true); EXPECT_EQ (p.second, (unsigned int) 3); EXPECT_EQ (layers_to_string (ly), "1/0,3/10,2/0,2/42"); - p = lm.logical (db::LayerProperties (2, 42)); + p = lm.first_logical (db::LayerProperties (2, 42)); EXPECT_EQ (p.first, true); EXPECT_EQ (p.second, (unsigned int) 3); - p = lm.logical (db::LayerProperties (2, 42), ly); + p = lm.first_logical (db::LayerProperties (2, 42), ly); EXPECT_EQ (p.first, true); EXPECT_EQ (p.second, (unsigned int) 3); @@ -429,19 +429,91 @@ TEST(7) EXPECT_EQ (layers_to_string (ly), "85/0,185/0,,"); std::pair p; - p = lm.logical (db::LayerProperties (85, 0)); + p = lm.first_logical (db::LayerProperties (85, 0)); EXPECT_EQ (p.first, false); EXPECT_EQ (p.second, (unsigned int) 0); - p = lm.logical (db::LayerProperties (185, 0)); + p = lm.first_logical (db::LayerProperties (185, 0)); EXPECT_EQ (p.first, false); EXPECT_EQ (p.second, (unsigned int) 0); - p = lm.logical (db::LayerProperties (10000, 0)); + p = lm.first_logical (db::LayerProperties (10000, 0)); EXPECT_EQ (p.first, true); EXPECT_EQ (p.second, (unsigned int) 1); - p = lm.logical (db::LayerProperties (10001, 0)); + p = lm.first_logical (db::LayerProperties (10001, 0)); EXPECT_EQ (p.first, true); EXPECT_EQ (p.second, (unsigned int) 0); } + +// multi-mapping, unmapping +TEST(8) +{ + db::LayerMap lm; + + unsigned int n = 0; + + // refinement + // all + lm.mmap_expr ("*/*", n++); + EXPECT_EQ (lm.mapping_str (0), "*/*"); + EXPECT_EQ (lm.to_string (), + "layer_map('*/*')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + // some + lm.mmap_expr ("*/1-10", n++); + EXPECT_EQ (lm.to_string (), + "layer_map('+*/0,1-10,11-*';'+*/1-10')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + // others + lm.mmap_expr ("*/5,15", n++); + + EXPECT_EQ (lm.to_string (), + "layer_map('+*/0,1-4,5,6-10,11-14,15,16-*';'+*/1-4,5,6-10';'+*/5,15')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + // NOTE: the leading "+" indicates that the listed layers may go somewhere else, so we can't plainly map them + EXPECT_EQ (lm.mapping_str (0), "+*/0,1-4,5,6-10,11-14,15,16-*"); + EXPECT_EQ (lm.mapping_str (1), "+*/1-4,5,6-10"); + EXPECT_EQ (lm.mapping_str (2), "+*/5,15"); + EXPECT_EQ (lm.mapping_str (3), ""); + + lm = db::LayerMap (); + n = 0; + + // refinement + // all + lm.mmap_expr ("*/*", n++); + EXPECT_EQ (lm.mapping_str (0), "*/*"); + EXPECT_EQ (lm.to_string (), + "layer_map('*/*')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + // some + lm.mmap_expr ("1-10/*", n++); + EXPECT_EQ (lm.to_string (), + "layer_map('+0/*;1-10/*;11-*/*';'+1-10/*')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + // others + lm.mmap_expr ("5,15/*", n++); + + EXPECT_EQ (lm.to_string (), + "layer_map('+0/*;1-4/*;5/*;6-10/*;11-14/*;15/*;16-*/*';'+1-4/*;5/*;6-10/*';'+5/*;15/*')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + // NOTE: the leading "+" indicates that the listed layers may go somewhere else, so we can't plainly map them + EXPECT_EQ (lm.mapping_str (0), "+0/*;1-4/*;5/*;6-10/*;11-14/*;15/*;16-*/*"); + EXPECT_EQ (lm.mapping_str (1), "+1-4/*;5/*;6-10/*"); + EXPECT_EQ (lm.mapping_str (2), "+5/*;15/*"); + EXPECT_EQ (lm.mapping_str (3), ""); +} + diff --git a/src/lay/lay/laySearchReplaceDialog.cc b/src/lay/lay/laySearchReplaceDialog.cc index 41b591104..e9ef8b94f 100644 --- a/src/lay/lay/laySearchReplaceDialog.cc +++ b/src/lay/lay/laySearchReplaceDialog.cc @@ -504,7 +504,7 @@ SearchReplaceResults::export_layout (db::Layout &layout) std::map::const_iterator lm = m_lp_map.find (layer); if (lm != m_lp_map.end ()) { - std::pair ll = insert_lm.logical (lm->second); + std::pair ll = insert_lm.first_logical (lm->second); if (! ll.first) { layer = layout.insert_layer (lm->second); insert_lm.map (lm->second, layer, lm->second); diff --git a/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc b/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc index cb023d887..5517001d8 100644 --- a/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc +++ b/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc @@ -381,7 +381,7 @@ DXFReader::do_read (db::Layout &layout, db::cell_index_type top) { // create the zero layer - this is not mapped to GDS but can be specified in the layer mapping as // a layer named "0". - std::pair ll = layer_map ().logical (zero_layer_name, layout); + std::pair ll = layer_map ().first_logical (zero_layer_name, layout); if (ll.first) { // create the layer if it is not part of the layout yet. diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc index d79793638..7111089d9 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc @@ -184,7 +184,7 @@ GDS2ReaderBase::finish_element (db::PropertiesRepository &rep) std::pair GDS2ReaderBase::open_dl (db::Layout &layout, const LDPair &dl, bool create) { - std::pair ll = m_layer_map.logical (dl, layout); + std::pair ll = m_layer_map.first_logical (dl, layout); if (ll.first) { return ll; diff --git a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc b/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc index 838260bf3..7361c67a2 100644 --- a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc +++ b/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc @@ -332,7 +332,7 @@ TEST(2) db::Layout layout_piece (&m); layout_piece = layout; - std::pair jj = map_full.logical (pairs[i]); + std::pair jj = map_full.first_logical (pairs[i]); EXPECT_EQ (jj.first, true); for (unsigned int j = 0; j < layout_piece.layers(); ++j) { diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index 2c47e2984..f68700609 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -1180,7 +1180,7 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n } // employ the layer map to find the target layer - std::pair ll = m_layer_map.logical (lp, layout); + std::pair ll = m_layer_map.first_logical (lp, layout); if (ll.first) { @@ -1300,10 +1300,10 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n // Route the layer through the layer map, first the decorated name and if there is no mapping, the // undecorated one. - std::pair ll = m_layer_map.logical (name, layout); + std::pair ll = m_layer_map.first_logical (name, layout); bool generic_match = false; if (! ll.first) { - ll = m_layer_map.logical (n, layout); + ll = m_layer_map.first_logical (n, layout); generic_match = true; } else if (n == name) { // no suffix defined in tech component -> treat as generic match and combine datatypes diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc index 3bf5485a5..131fb3e9a 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc @@ -557,7 +557,7 @@ OASISReader::warn (const std::string &msg) std::pair OASISReader::open_dl (db::Layout &layout, const LDPair &dl, bool create) { - std::pair ll = m_layer_map.logical (dl, layout); + std::pair ll = m_layer_map.first_logical (dl, layout); if (ll.first) { return ll; From 3e249b0b54f31e6b9b075e3eaa7453e90e7cbe8a Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 15 Dec 2020 23:51:01 +0100 Subject: [PATCH 20/44] WIP: More tests for layer multi-mapping --- src/db/unit_tests/dbStreamLayerTests.cc | 41 +++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/db/unit_tests/dbStreamLayerTests.cc b/src/db/unit_tests/dbStreamLayerTests.cc index 353e31693..6b0b478b0 100644 --- a/src/db/unit_tests/dbStreamLayerTests.cc +++ b/src/db/unit_tests/dbStreamLayerTests.cc @@ -446,6 +446,18 @@ TEST(7) EXPECT_EQ (p.second, (unsigned int) 0); } +static std::string set2string (const std::set &set) +{ + std::string s; + for (std::set::const_iterator i = set.begin (); i != set.end (); ++i) { + if (i != set.begin ()) { + s += ","; + } + s += tl::to_string (*i); + } + return s; +} + // multi-mapping, unmapping TEST(8) { @@ -477,6 +489,12 @@ TEST(8) ); EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + EXPECT_EQ (set2string (lm.logical (db::LDPair (0, 1000))), "0"); + EXPECT_EQ (set2string (lm.logical (db::LDPair (1, 1000))), "0"); + EXPECT_EQ (set2string (lm.logical (db::LDPair (0, 5))), "0,1,2"); + EXPECT_EQ (set2string (lm.logical (db::LDPair (0, 15))), "0,2"); + EXPECT_EQ (set2string (lm.logical (db::LDPair (0, 10))), "0,1"); + // NOTE: the leading "+" indicates that the listed layers may go somewhere else, so we can't plainly map them EXPECT_EQ (lm.mapping_str (0), "+*/0,1-4,5,6-10,11-14,15,16-*"); EXPECT_EQ (lm.mapping_str (1), "+*/1-4,5,6-10"); @@ -510,10 +528,33 @@ TEST(8) ); EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + EXPECT_EQ (set2string (lm.logical (db::LDPair (1000, 0))), "0"); + EXPECT_EQ (set2string (lm.logical (db::LDPair (1000, 1))), "0"); + EXPECT_EQ (set2string (lm.logical (db::LDPair (5, 0))), "0,1,2"); + EXPECT_EQ (set2string (lm.logical (db::LDPair (15, 0))), "0,2"); + EXPECT_EQ (set2string (lm.logical (db::LDPair (10, 0))), "0,1"); + // NOTE: the leading "+" indicates that the listed layers may go somewhere else, so we can't plainly map them EXPECT_EQ (lm.mapping_str (0), "+0/*;1-4/*;5/*;6-10/*;11-14/*;15/*;16-*/*"); EXPECT_EQ (lm.mapping_str (1), "+1-4/*;5/*;6-10/*"); EXPECT_EQ (lm.mapping_str (2), "+5/*;15/*"); EXPECT_EQ (lm.mapping_str (3), ""); + + lm = db::LayerMap (); + n = 0; + + lm.mmap_expr ("*/*", n++); + EXPECT_EQ (lm.mapping_str (0), "*/*"); + EXPECT_EQ (lm.to_string (), + "layer_map('*/*')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + // some + lm.mmap_expr ("1-10/0-20", n++); + EXPECT_EQ (lm.to_string (), + "layer_map('+0/*;1-10/0-20,21-*;11-*/*';'+1-10/0-20')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); } From 91de3709015e583eb83a2cd294c5a13a7537f39c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 16 Dec 2020 23:02:01 +0100 Subject: [PATCH 21/44] WIP: bugfix, RBA tests. --- src/db/db/dbStreamLayers.cc | 8 +++--- testdata/ruby/dbLayout.rb | 53 +++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/db/db/dbStreamLayers.cc b/src/db/db/dbStreamLayers.cc index e507ddea9..f86db8273 100644 --- a/src/db/db/dbStreamLayers.cc +++ b/src/db/db/dbStreamLayers.cc @@ -502,10 +502,10 @@ void LayerMap::mmap (const LayerProperties &f, unsigned int l) { if (f.name.empty () || is_static_ld (f.layer) || is_static_ld (f.datatype)) { - map (db::LDPair (f.layer, f.datatype), l); + mmap (db::LDPair (f.layer, f.datatype), l); } if (! f.name.empty ()) { - map (f.name, l); + mmap (f.name, l); } } @@ -525,10 +525,10 @@ void LayerMap::mmap (const LayerProperties &f, unsigned int l, const LayerProperties &t) { if (f.name.empty () || is_static_ld (f.layer) || is_static_ld (f.datatype)) { - map (db::LDPair (f.layer, f.datatype), l, t); + mmap (db::LDPair (f.layer, f.datatype), l, t); } if (! f.name.empty ()) { - map (f.name, l, t); + mmap (f.name, l, t); } } diff --git a/testdata/ruby/dbLayout.rb b/testdata/ruby/dbLayout.rb index e5ff45791..33a1decae 100644 --- a/testdata/ruby/dbLayout.rb +++ b/testdata/ruby/dbLayout.rb @@ -30,7 +30,11 @@ class DBLayout_TestClass < TestBase lmap = RBA::LayerMap::new lmap.map( "1/0", 0 ) + assert_equal(lmap.is_mapped(RBA::LayerInfo::new(1, 0)), true) + assert_equal(lmap.is_mapped(RBA::LayerInfo::new(1, 1)), false) + assert_equal(lmap.is_mapped(RBA::LayerInfo::new(2, 2)), false) lmap.map( "2/2", 0 ) + assert_equal(lmap.is_mapped(RBA::LayerInfo::new(2, 2)), true) lmap.map( "10/2", 0 ) assert_equal( lmap.mapping_str(0), "1/0;2/2;10/2" ) @@ -85,6 +89,55 @@ class DBLayout_TestClass < TestBase assert_equal( lmap.mapping_str(0), "2/2 : 4/4" ) assert_equal( lmap.mapping(0).to_s, "4/4" ) assert_equal( lmap.mapping(2).to_s, "5/5" ) + + lmap = RBA::LayerMap::new + + lmap.map("*/*", 0) + lmap.unmap(RBA::LayerInfo::new(5, 10)) + assert_equal(lmap.mapping_str(0), "0-4/*;5/0-9,11-*;6-*/*") + + lmap.clear + lmap.map("*/*", 0) + lmap.unmap(RBA::LayerInfo::new(5, 10), RBA::LayerInfo::new(16, 21)) + assert_equal(lmap.mapping_str(0), "0-4/*;5-16/0-9,22-*;17-*/*") + + lmap.clear + lmap.map("*/*", 0) + lmap.unmap("5-16/10-21") + assert_equal(lmap.mapping_str(0), "0-4/*;5-16/0-9,22-*;17-*/*") + + lmap.clear + lmap.map("*/*", 0) + lmap.mmap(RBA::LayerInfo::new(5, 10), 1) + assert_equal(lmap.mapping_str(0), "+0-4/*;5/0-9,10,11-*;6-*/*") + assert_equal(lmap.mapping_str(1), "+5/10") + + lmap.clear + lmap.map("*/*", 0) + lmap.mmap(RBA::LayerInfo::new(5, 10), 1, RBA::LayerInfo::new(100, 0)) + assert_equal(lmap.mapping_str(0), "+0-4/*;5/0-9,10,11-*;6-*/*") + assert_equal(lmap.mapping_str(1), "+5/10 : 100/0") + + lmap.clear + lmap.map("*/*", 0) + lmap.mmap(RBA::LayerInfo::new(5, 10), RBA::LayerInfo::new(16, 21), 1) + assert_equal(lmap.mapping_str(0), "+0-4/*;5-16/0-9,10-21,22-*;17-*/*") + assert_equal(lmap.mapping_str(1), "+5-16/10-21") + + lmap.clear + lmap.map("*/*", 0) + lmap.mmap(RBA::LayerInfo::new(5, 10), RBA::LayerInfo::new(16, 21), 1, RBA::LayerInfo::new(100, 0)) + assert_equal(lmap.mapping_str(0), "+0-4/*;5-16/0-9,10-21,22-*;17-*/*") + assert_equal(lmap.mapping_str(1), "+5-16/10-21 : 100/0") + + lmap.clear + lmap.map("*/*", 0) + lmap.mmap("5-16/10-21", 1) + assert_equal(lmap.mapping_str(0), "+0-4/*;5-16/0-9,10-21,22-*;17-*/*") + assert_equal(lmap.mapping_str(1), "+5-16/10-21") + + assert_equal(lmap.logicals(RBA::LayerInfo::new(5, 10)), [ 0, 1 ]) + assert_equal(lmap.logicals(RBA::LayerInfo::new(0, 10)), [ 0 ]) end From 0fddf7f389cb2de7a837ca1d4d2c2c7d10e14878 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 16 Dec 2020 23:52:58 +0100 Subject: [PATCH 22/44] WIP: text edit feature for layer mapping edit widget. --- src/buddies/src/bd/bdReaderOptions.cc | 2 +- src/db/db/dbStreamLayers.cc | 33 ++- src/db/db/dbStreamLayers.h | 16 ++ src/laybasic/laybasic/LayerMappingWidget.ui | 210 ++++++++++-------- .../laybasic/layLayerMappingWidget.cc | 49 +++- src/laybasic/laybasic/layLayerMappingWidget.h | 3 + 6 files changed, 199 insertions(+), 114 deletions(-) diff --git a/src/buddies/src/bd/bdReaderOptions.cc b/src/buddies/src/bd/bdReaderOptions.cc index 8a331dda6..dec684c29 100644 --- a/src/buddies/src/bd/bdReaderOptions.cc +++ b/src/buddies/src/bd/bdReaderOptions.cc @@ -604,7 +604,7 @@ void GenericReaderOptions::set_layer_map (const std::string &lm) int l = 0; while (! ex.at_end ()) { - m_layer_map.map_expr (ex, l); + m_layer_map.add_expr (ex, l); ex.test ("//"); ++l; } diff --git a/src/db/db/dbStreamLayers.cc b/src/db/db/dbStreamLayers.cc index f86db8273..eb1260601 100644 --- a/src/db/db/dbStreamLayers.cc +++ b/src/db/db/dbStreamLayers.cc @@ -738,6 +738,7 @@ LayerMap::unmap (const LDPair &p1, const LDPair &p2) } } + void LayerMap::unmap_expr (const std::string &expr) { @@ -838,6 +839,26 @@ LayerMap::to_string_file_format () const return os.str (); } +void +LayerMap::add_expr (const std::string &expr, unsigned int l) +{ + tl::Extractor ex (expr.c_str ()); + add_expr (ex, l); + ex.expect_end (); +} + +void +LayerMap::add_expr (tl::Extractor &ex, unsigned int l) +{ + if (ex.test ("+")) { + mmap_expr (ex, l); + } else if (ex.test ("-")) { + unmap_expr (ex); + } else { + map_expr (ex, l); + } +} + db::LayerMap LayerMap::from_string_file_format (const std::string &s) { @@ -860,13 +881,7 @@ LayerMap::from_string_file_format (const std::string &s) } else { if (! ex.at_end ()) { - if (ex.test ("+")) { - lm.mmap_expr (ex, l); - } else if (ex.test ("-")) { - lm.unmap_expr (ex); - } else { - lm.map_expr (ex, l); - } + lm.add_expr (ex, l); if (ex.test ("#") || ex.test ("//")) { // ignore comments } else { @@ -901,7 +916,7 @@ namespace tl while (! ex.test (")") && ! ex.at_end ()) { std::string m; ex.read_word_or_quoted (m); - t.map_expr (m, l); + t.add_expr (m, l); ++l; ex.test (";"); } @@ -921,7 +936,7 @@ namespace tl while (! ex.test (")") && ! ex.at_end ()) { std::string m; ex.read_word_or_quoted (m); - t.map_expr (m, l); + t.add_expr (m, l); ++l; ex.test (";"); } diff --git a/src/db/db/dbStreamLayers.h b/src/db/db/dbStreamLayers.h index 26c15804a..61eaad77a 100644 --- a/src/db/db/dbStreamLayers.h +++ b/src/db/db/dbStreamLayers.h @@ -521,6 +521,22 @@ public: */ void unmap_expr (tl::Extractor &ex); + /** + * @brief Generic expression mapping + * + * This generic mapping function takes a mapping expression. If it starts with "+", + * "mmap" is used, if it starts with "-", "unmap" is used. Otherwise, "map" is used. + */ + void add_expr (const std::string &expr, unsigned int l); + + /** + * @brief Generic expression mapping + * + * This generic mapping function takes a mapping expression. If it starts with "+", + * "mmap" is used, if it starts with "-", "unmap" is used. Otherwise, "map" is used. + */ + void add_expr (tl::Extractor &ex, unsigned int l); + /** * @brief Prepares a layer mapping object for reading * diff --git a/src/laybasic/laybasic/LayerMappingWidget.ui b/src/laybasic/laybasic/LayerMappingWidget.ui index a343b33ce..5fd4d65d7 100644 --- a/src/laybasic/laybasic/LayerMappingWidget.ui +++ b/src/laybasic/laybasic/LayerMappingWidget.ui @@ -6,8 +6,8 @@ 0 0 - 446 - 205 + 536 + 290 @@ -29,6 +29,19 @@ 6 + + + + + 0 + 0 + + + + Load File + + + @@ -45,103 +58,114 @@ - - - - - 0 - 0 - - - - Load File - - - - - - - - 0 - 0 - - - - true - - - QAbstractItemView::InternalMove - - - QAbstractItemView::ExtendedSelection - - - true - - - false - - - - - - - Add a new layer to the list - - - Add - - - - :/add.png:/add.png - - - - - - - Delete the selected layers from the list - - - Delete - - - - :/clear.png:/clear.png - - - - - - - Qt::Vertical - - - - 20 - 5 - - - - - - - - Edit the current layer - - - Edit - - - - :/edit.png:/edit.png + + + + 1 + + + List + + + + + + + 0 + 0 + + + + true + + + QAbstractItemView::InternalMove + + + QAbstractItemView::ExtendedSelection + + + true + + + false + + + + + + + Add a new layer to the list + + + Add + + + + :/add.png:/add.png + + + + + + + Delete the selected layers from the list + + + Delete + + + + :/clear.png:/clear.png + + + + + + + Edit the current layer + + + Edit + + + + :/edit.png:/edit.png + + + + + + + Qt::Vertical + + + + 20 + 5 + + + + + + + + + Text + + + + + + + - + diff --git a/src/laybasic/laybasic/layLayerMappingWidget.cc b/src/laybasic/laybasic/layLayerMappingWidget.cc index c5c243e77..e14dadcc7 100644 --- a/src/laybasic/laybasic/layLayerMappingWidget.cc +++ b/src/laybasic/laybasic/layLayerMappingWidget.cc @@ -53,6 +53,8 @@ LayerMappingWidget::LayerMappingWidget (QWidget *parent) mp_ui->layer_lv->viewport ()->acceptDrops (); + connect (mp_ui->tabs, SIGNAL (currentChanged (int)), this, SLOT (current_tab_changed (int))); + mp_layer_table_file_dialog = new lay::FileDialog (this, tl::to_string (QObject::tr ("Load Layer Table")), tl::to_string (QObject::tr ("Layer properties and text files (*.lyp *.txt);;Layer properties files (*.lyp);;Text files (*.txt);;All files (*)"))); @@ -72,6 +74,8 @@ LayerMappingWidget::set_layer_map (const db::LayerMap &lm) { std::vector layer_ids = lm.get_layers (); + mp_ui->text_edit->setPlainText (tl::to_qstring (lm.to_string_file_format ())); + mp_ui->layer_lv->reset (); mp_ui->layer_lv->clear (); @@ -88,16 +92,31 @@ LayerMappingWidget::set_layer_map (const db::LayerMap &lm) db::LayerMap LayerMappingWidget::get_layer_map () const +{ + return get_layer_map_from_tab (mp_ui->tabs->currentIndex ()); +} + +db::LayerMap +LayerMappingWidget::get_layer_map_from_tab (int tab) const { db::LayerMap lm; - for (int i = 0; i < mp_ui->layer_lv->count (); ++i) { - std::string t = tl::to_string (mp_ui->layer_lv->item (i)->data (Qt::DisplayRole).toString ()); - try { - lm.map_expr (t, (unsigned int) i); - } catch (...) { - mp_ui->layer_lv->setCurrentItem (mp_ui->layer_lv->item (i)); - throw; + + if (tab == 0) { + + for (int i = 0; i < mp_ui->layer_lv->count (); ++i) { + std::string t = tl::to_string (mp_ui->layer_lv->item (i)->data (Qt::DisplayRole).toString ()); + try { + lm.add_expr (t, (unsigned int) i); + } catch (...) { + mp_ui->layer_lv->setCurrentItem (mp_ui->layer_lv->item (i)); + throw; + } } + + } else { + + lm = db::LayerMap::from_string_file_format (tl::to_string (mp_ui->text_edit->toPlainText ())); + } return lm; @@ -128,17 +147,19 @@ LayerMappingWidget::load_button_pressed () mp_ui->layer_lv->reset (); mp_ui->layer_lv->clear (); + db::LayerMap lm; + // use those layers which have cellview index 0 + unsigned int n = 0; for (LayerPropertiesConstIterator lay_iter = props.begin_const_recursive (); ! lay_iter.at_end (); ++lay_iter) { if (! lay_iter->has_children () && lay_iter->source (true /*=real*/).cv_index () == 0) { db::LayerProperties db_lp = lay_iter->source (true /*=real*/).layer_props (); - QListWidgetItem *item = new QListWidgetItem (mp_ui->layer_lv); - item->setData (Qt::DisplayRole, tl::to_qstring (db_lp.to_string ())); - item->setFlags (item->flags () | Qt::ItemIsEditable); - mp_ui->layer_lv->addItem (item); + lm.map (db_lp, (unsigned int) n++); } } + set_layer_map (lm); + // if successful, stop now. success = true; @@ -230,5 +251,11 @@ LayerMappingWidget::edit_button_pressed () END_PROTECTED } +void +LayerMappingWidget::current_tab_changed (int index) +{ + set_layer_map (get_layer_map_from_tab (1 - index)); +} + } diff --git a/src/laybasic/laybasic/layLayerMappingWidget.h b/src/laybasic/laybasic/layLayerMappingWidget.h index 9252e8bb7..4c0bac3a4 100644 --- a/src/laybasic/laybasic/layLayerMappingWidget.h +++ b/src/laybasic/laybasic/layLayerMappingWidget.h @@ -84,11 +84,14 @@ private slots: void add_button_pressed (); void delete_button_pressed (); void edit_button_pressed (); + void current_tab_changed (int tab); private: lay::FileDialog *mp_layer_table_file_dialog; std::string m_layer_table_file; Ui::LayerMappingWidget *mp_ui; + + db::LayerMap get_layer_map_from_tab (int tab) const; }; } // namespace lay From 5bd1cb8bd72fb83c988868d687c3d99904c44d75 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 16 Dec 2020 23:54:57 +0100 Subject: [PATCH 23/44] WIP: making list the default for layer mapping edit widget --- src/laybasic/laybasic/LayerMappingWidget.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/laybasic/laybasic/LayerMappingWidget.ui b/src/laybasic/laybasic/LayerMappingWidget.ui index 5fd4d65d7..03855fa9a 100644 --- a/src/laybasic/laybasic/LayerMappingWidget.ui +++ b/src/laybasic/laybasic/LayerMappingWidget.ui @@ -61,7 +61,7 @@ - 1 + 0 From 3fbfb2072766efcb4d3778d143dbc263c0ae838f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 19 Dec 2020 00:56:45 +0100 Subject: [PATCH 24/44] WIP: shorter mapping strings. --- src/db/db/dbStreamLayers.cc | 82 ++++++++++++++++++------- src/db/unit_tests/dbStreamLayerTests.cc | 20 +++--- src/lay/lay/doc/about/layer_mapping.xml | 28 +++++++++ 3 files changed, 98 insertions(+), 32 deletions(-) diff --git a/src/db/db/dbStreamLayers.cc b/src/db/db/dbStreamLayers.cc index eb1260601..ac2cc9819 100644 --- a/src/db/db/dbStreamLayers.cc +++ b/src/db/db/dbStreamLayers.cc @@ -262,6 +262,43 @@ static std::string format_interval (ld_type l1, ld_type l2) } } +static std::vector > +extract_dt_intervals (const LayerMap::datatype_map &dt_map, int ll, bool &has_others) +{ + std::vector > res; + + for (LayerMap::datatype_map::const_iterator d = dt_map.begin (); d != dt_map.end (); ) { + + if (d->second.find (ll) != d->second.end ()) { + + std::pair dpi = d->first; + + if (d->second.size () > 1) { + has_others = true; + } + + LayerMap::datatype_map::const_iterator dd = d; + ++dd; + while (dd != dt_map.end () && dd->first.first == dpi.second && dd->second.find (ll) != dd->second.end ()) { + if (dd->second.size () > 1) { + has_others = true; + } + dpi.second = dd->first.second; + ++dd; + } + + d = dd; + + res.push_back (dpi); + + } else { + ++d; + } + + } + return res; +} + std::string LayerMap::mapping_str (unsigned int ll) const { @@ -269,36 +306,37 @@ LayerMap::mapping_str (unsigned int ll) const bool f1 = true; bool is_mmap = false; - for (ld_map::const_iterator l = m_ld_map.begin (); l != m_ld_map.end (); ++l) { + for (ld_map::const_iterator l = m_ld_map.begin (); l != m_ld_map.end (); ) { + + std::pair lti = l->first; + + std::vector > dti = extract_dt_intervals (l->second, ll, is_mmap); + ++l; + while (l != m_ld_map.end () && lti.second == l->first.first && extract_dt_intervals (l->second, ll, is_mmap) == dti) { + lti.second = l->first.second; + ++l; + } bool f2 = true; - for (datatype_map::const_iterator d = l->second.begin (); d != l->second.end (); ++d) { + for (std::vector >::const_iterator d = dti.begin (); d != dti.end (); ++d) { - if (d->second.find (ll) != d->second.end ()) { + // create a string representation + if (!f2) { + s += ","; + } else { - if (d->second.size () > 1) { - is_mmap = true; + if (!f1) { + s += ";"; } + f1 = false; - // create a string representation - if (!f2) { - s += ","; - } else { - - if (!f1) { - s += ";"; - } - f1 = false; - - s += format_interval (l->first.first, l->first.second); - s += "/"; - - } - f2 = false; - - s += format_interval (d->first.first, d->first.second); + s += format_interval (lti.first, lti.second); + s += "/"; } + f2 = false; + + s += format_interval (d->first, d->second); } diff --git a/src/db/unit_tests/dbStreamLayerTests.cc b/src/db/unit_tests/dbStreamLayerTests.cc index 6b0b478b0..f031de1f3 100644 --- a/src/db/unit_tests/dbStreamLayerTests.cc +++ b/src/db/unit_tests/dbStreamLayerTests.cc @@ -38,7 +38,7 @@ TEST(1) EXPECT_EQ (lm.first_logical (db::LDPair (2, 0)).second, (unsigned int) 18); EXPECT_EQ (lm.first_logical (db::LDPair (0, 0)).first, false); - EXPECT_EQ (lm.mapping_str (18), "1/0;2-5/0"); + EXPECT_EQ (lm.mapping_str (18), "1-5/0"); EXPECT_EQ (lm.mapping_str (17), "1/5"); lm.map (db::LDPair (2, 2), 18); @@ -477,7 +477,7 @@ TEST(8) // some lm.mmap_expr ("*/1-10", n++); EXPECT_EQ (lm.to_string (), - "layer_map('+*/0,1-10,11-*';'+*/1-10')" + "layer_map('+*/*';'+*/1-10')" ); EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); @@ -485,7 +485,7 @@ TEST(8) lm.mmap_expr ("*/5,15", n++); EXPECT_EQ (lm.to_string (), - "layer_map('+*/0,1-4,5,6-10,11-14,15,16-*';'+*/1-4,5,6-10';'+*/5,15')" + "layer_map('+*/*';'+*/1-10';'+*/5,15')" ); EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); @@ -496,8 +496,8 @@ TEST(8) EXPECT_EQ (set2string (lm.logical (db::LDPair (0, 10))), "0,1"); // NOTE: the leading "+" indicates that the listed layers may go somewhere else, so we can't plainly map them - EXPECT_EQ (lm.mapping_str (0), "+*/0,1-4,5,6-10,11-14,15,16-*"); - EXPECT_EQ (lm.mapping_str (1), "+*/1-4,5,6-10"); + EXPECT_EQ (lm.mapping_str (0), "+*/*"); + EXPECT_EQ (lm.mapping_str (1), "+*/1-10"); EXPECT_EQ (lm.mapping_str (2), "+*/5,15"); EXPECT_EQ (lm.mapping_str (3), ""); @@ -516,7 +516,7 @@ TEST(8) // some lm.mmap_expr ("1-10/*", n++); EXPECT_EQ (lm.to_string (), - "layer_map('+0/*;1-10/*;11-*/*';'+1-10/*')" + "layer_map('+*/*';'+1-10/*')" ); EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); @@ -524,7 +524,7 @@ TEST(8) lm.mmap_expr ("5,15/*", n++); EXPECT_EQ (lm.to_string (), - "layer_map('+0/*;1-4/*;5/*;6-10/*;11-14/*;15/*;16-*/*';'+1-4/*;5/*;6-10/*';'+5/*;15/*')" + "layer_map('+*/*';'+1-10/*';'+5/*;15/*')" ); EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); @@ -535,8 +535,8 @@ TEST(8) EXPECT_EQ (set2string (lm.logical (db::LDPair (10, 0))), "0,1"); // NOTE: the leading "+" indicates that the listed layers may go somewhere else, so we can't plainly map them - EXPECT_EQ (lm.mapping_str (0), "+0/*;1-4/*;5/*;6-10/*;11-14/*;15/*;16-*/*"); - EXPECT_EQ (lm.mapping_str (1), "+1-4/*;5/*;6-10/*"); + EXPECT_EQ (lm.mapping_str (0), "+*/*"); + EXPECT_EQ (lm.mapping_str (1), "+1-10/*"); EXPECT_EQ (lm.mapping_str (2), "+5/*;15/*"); EXPECT_EQ (lm.mapping_str (3), ""); @@ -553,7 +553,7 @@ TEST(8) // some lm.mmap_expr ("1-10/0-20", n++); EXPECT_EQ (lm.to_string (), - "layer_map('+0/*;1-10/0-20,21-*;11-*/*';'+1-10/0-20')" + "layer_map('+*/*';'+1-10/0-20')" ); EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); } diff --git a/src/lay/lay/doc/about/layer_mapping.xml b/src/lay/lay/doc/about/layer_mapping.xml index 81d6205db..2f3ea4c82 100644 --- a/src/lay/lay/doc/about/layer_mapping.xml +++ b/src/lay/lay/doc/about/layer_mapping.xml @@ -173,5 +173,33 @@ +

Multi-mapping and unmapping

+ +

+ Layer mapping table support an advanced feature which is to duplicate input layers to + a number of output layers (1:n) mapping. + The feature is enabled by prepending a "+" to the mapping statement. The following + statement will first select layer 5/0 and additionally copy it to layer 1000/0: +

+ +
5/0
++5/0: 1000/0
+
+ +

+ Unmapping removes the mapping for a specific layer or range. It is specified by prepending "-" + to the mapping expression. The following statement will map all datatypes of layer 5 to 0 except + for datatype 10 which is not considered. +

+ +
5/*: 5/0
+-5/10
+
+ +

+ Unmapping cancels the mappings specified previously, so the order of statements becomes important + when using unmapping and multi-mapping. +

+ From dda2724d0c59dbffe7b08c87b2d6d1350cd5c63b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 19 Dec 2020 01:37:38 +0100 Subject: [PATCH 25/44] WIP: Documentation, mapping file option for buddy scripts. --- src/buddies/src/bd/bdReaderOptions.cc | 28 +++++++++++++++++++++++++++ src/buddies/src/bd/bdReaderOptions.h | 1 + 2 files changed, 29 insertions(+) diff --git a/src/buddies/src/bd/bdReaderOptions.cc b/src/buddies/src/bd/bdReaderOptions.cc index dec684c29..156e06048 100644 --- a/src/buddies/src/bd/bdReaderOptions.cc +++ b/src/buddies/src/bd/bdReaderOptions.cc @@ -24,6 +24,8 @@ #include "dbLoadLayoutOptions.h" #include "tlCommandLineParser.h" +#include "tlStream.h" + namespace bd { @@ -153,6 +155,13 @@ GenericReaderOptions::add_options (tl::CommandLineOptions &cmd) "layer is specified, all source layers addressed with the source specification are " "combined into this target layer.\n" "\n" + "To clone layers, add a mapping statement beginning with a '+' character. While other mapping statements " + "redefine mappings established before, mapping statement starting with '+' will clone the layer (1:m mapping).\n" + "\n" + "It's also possible to cancel mappings established before by using an 'unmap' statement. Such a statement " + "begins with a '-' and lists the layers whose mapping is to be removed. This is useful for creating " + "'mapping holes' in sequences.\n" + "\n" "Examples:\n" "\n" "* 1/0 2/0 3/0-255:17/0\n" @@ -160,6 +169,18 @@ GenericReaderOptions::add_options (tl::CommandLineOptions &cmd) "\n" "* A:1/0 B:2/0\n" " Maps named layer A to 1/0 and named layer B to 2/0" + "\n" + "* */*:*/* +10/*:1000/*" + " Includes all layers, but in addition copy all layers 10 to 1000 while keeping the datatype\n" + "\n" + "* */*:*/* -10/*" + " Includes all layers, but drops layer 10, all datatypes." + ) + << tl::arg (group + + "--" + m_long_prefix + "layer-map-file=map", this, &GenericReaderOptions::set_layer_map_file, "Specifies the layer mapping for the input as a file", + "This option specifies the layer selection or mapping like + -" + m_prefix + ", but takes the mapping for the given file. " + "Each line in this file is read as one layer mapping expression. Empty lines or lines starting with a hash (#) character are " + "ignored." ) ; } @@ -610,6 +631,13 @@ void GenericReaderOptions::set_layer_map (const std::string &lm) } } +void GenericReaderOptions::set_layer_map_file (const std::string &lm) +{ + tl::InputStream file (lm); + tl::TextInputStream text (file); + m_layer_map = db::LayerMap::from_string_file_format (text.read_all ()); +} + void GenericReaderOptions::set_read_named_layers (bool f) { m_keep_layer_names = f; diff --git a/src/buddies/src/bd/bdReaderOptions.h b/src/buddies/src/bd/bdReaderOptions.h index 7a0408ead..9caa9496c 100644 --- a/src/buddies/src/bd/bdReaderOptions.h +++ b/src/buddies/src/bd/bdReaderOptions.h @@ -134,6 +134,7 @@ private: std::vector m_magic_lib_path; void set_layer_map (const std::string &lm); + void set_layer_map_file (const std::string &lm); void set_dbu (double dbu); void set_read_named_layers (bool f); From f86c13689b530b572e007bf957613f8075a1e465 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 19 Dec 2020 13:21:33 +0100 Subject: [PATCH 26/44] WIP: some refactoring to simplify multi-mapping implementation --- src/db/db/dbCommonReader.cc | 80 +++++- src/db/db/dbCommonReader.h | 264 +++++++++++------- src/db/db/gsiDeclDbCommonStreamOptions.cc | 14 +- .../db_plugin/contrib/dbGDS2TextReader.cc | 18 +- .../gds2/db_plugin/contrib/dbGDS2TextReader.h | 35 +-- .../streamers/gds2/db_plugin/dbGDS2Reader.cc | 20 +- .../streamers/gds2/db_plugin/dbGDS2Reader.h | 38 +-- .../gds2/db_plugin/dbGDS2ReaderBase.cc | 98 +------ .../gds2/db_plugin/dbGDS2ReaderBase.h | 31 +- .../streamers/gds2/unit_tests/dbGDS2Reader.cc | 8 +- .../oasis/db_plugin/dbOASISReader.cc | 128 ++------- .../streamers/oasis/db_plugin/dbOASISReader.h | 42 +-- 12 files changed, 308 insertions(+), 468 deletions(-) diff --git a/src/db/db/dbCommonReader.cc b/src/db/db/dbCommonReader.cc index 2d4afc86d..f53db049b 100644 --- a/src/db/db/dbCommonReader.cc +++ b/src/db/db/dbCommonReader.cc @@ -35,7 +35,7 @@ namespace db static const size_t null_id = std::numeric_limits::max (); CommonReader::CommonReader () - : m_cc_resolution (AddToCell) + : m_cc_resolution (AddToCell), m_create_layers (false) { // .. nothing yet .. } @@ -275,6 +275,44 @@ CommonReader::merge_cell_without_instances (db::Layout &layout, db::cell_index_t layout.delete_cell (src_cell.cell_index ()); } +const db::LayerMap & +CommonReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) +{ + init (options); + + m_layer_map.prepare (layout); + + layout.start_changes (); + try { + do_read (layout); + finish (layout); + layout.end_changes (); + } catch (...) { + layout.end_changes (); + throw; + } + + return m_layer_map; +} + +const db::LayerMap & +CommonReader::read (db::Layout &layout) +{ + return read (layout, db::LoadLayoutOptions ()); +} + +void +CommonReader::init (const LoadLayoutOptions &options) +{ + m_common_options = options.get_options (); + m_layer_map = m_common_options.layer_map; + m_cc_resolution = m_common_options.cell_conflict_resolution; + m_create_layers = m_common_options.create_other_layers; + + m_layers_created.clear (); + m_layer_names.clear (); +} + void CommonReader::finish (db::Layout &layout) { @@ -384,6 +422,46 @@ CommonReader::finish (db::Layout &layout) } } +std::pair +CommonReader::open_dl (db::Layout &layout, const LDPair &dl) +{ + std::pair ll = m_layer_map.first_logical (dl, layout); + if (ll.first) { + + return ll; + + } else if (! m_create_layers) { + + return ll; + + } else { + + // and create the layer + db::LayerProperties lp; + lp.layer = dl.layer; + lp.datatype = dl.datatype; + + // resolve OASIS name if possible + const tl::interval_map *names_dmap = m_layer_names.mapped (dl.layer); + if (names_dmap != 0) { + const std::string *name = names_dmap->mapped (dl.datatype); + if (name != 0) { + lp.name = *name; + } + } + + unsigned int ll = layout.insert_layer (lp); + m_layer_map.map (dl, ll, lp); + + m_layers_created.insert (ll); + + return std::make_pair (true, ll); + + } +} + + + // --------------------------------------------------------------- // Common format declaration diff --git a/src/db/db/dbCommonReader.h b/src/db/db/dbCommonReader.h index f0ed56bcf..66b784972 100644 --- a/src/db/db/dbCommonReader.h +++ b/src/db/db/dbCommonReader.h @@ -31,6 +31,104 @@ namespace db { +/** + * @brief The CellConflictResolution enum + */ +enum CellConflictResolution +{ + AddToCell = 0, + OverwriteCell = 1, + SkipNewCell = 2, + RenameCell = 3 +}; + +/** + * @brief Structure that holds the GDS2 and OASIS specific options for the reader + */ +class DB_PUBLIC CommonReaderOptions + : public FormatSpecificReaderOptions +{ +public: + /** + * @brief The constructor + */ + CommonReaderOptions () + : create_other_layers (true), + enable_text_objects (true), + enable_properties (true), + cell_conflict_resolution (CellConflictResolution::AddToCell) + { + // .. nothing yet .. + } + + /** + * @brief Specifies a layer mapping + * + * If a layer mapping is specified, only the given layers are read. + * Otherwise, all layers are read. + * Setting "create_other_layers" to true will make the reader + * create other layers for all layers not given in the layer map. + * Setting an empty layer map and create_other_layers to true effectively + * enables all layers for reading. + */ + db::LayerMap layer_map; + + /** + * @brief A flag indicating that a new layers shall be created + * + * If this flag is set to true, layers not listed in the layer map a created + * too. + */ + bool create_other_layers; + + /** + * @brief A flag indicating whether to read text objects + * + * If this flag is set to true, text objects are read. Otherwise they are ignored. + */ + bool enable_text_objects; + + /** + * @brief A flag indicating whether to read user properties + * + * If this flag is set to true, user properties are read. Otherwise they are ignored. + */ + bool enable_properties; + + /** + * @brief Specifies the cell merge behavior + * + * This enum controls how cells are read if a cell with the requested name already + * exists. + * + * AddToCell In this mode, instances or shapes are added to any existing cell + * OverwriteCell Overwrite existing cell. If the existing cell has children, those are removed unless used otherwise + * SkipNewCell Ignore the new cell and it's children + * RenameCell Rename the new cell + * + * If the existing opr the new cell is a ghost cell, AddToCell is applied always. In other words, + * ghost cells are always merged. + */ + CellConflictResolution cell_conflict_resolution; + + /** + * @brief Implementation of FormatSpecificReaderOptions + */ + virtual FormatSpecificReaderOptions *clone () const + { + return new CommonReaderOptions (*this); + } + + /** + * @brief Implementation of FormatSpecificReaderOptions + */ + virtual const std::string &format_name () const + { + static const std::string n ("Common"); + return n; + } +}; + /** * @brief A common reader base for GDS2 and OASIS providing common services for both readers */ @@ -38,38 +136,13 @@ class DB_PUBLIC CommonReader : public ReaderBase { public: - /** - * @brief The CellConflictResolution enum - */ - enum CellConflictResolution - { - AddToCell = 0, - OverwriteCell = 1, - SkipNewCell = 2, - RenameCell = 3 - }; + typedef tl::interval_map > layer_name_map; /** * @brief Constructor */ CommonReader (); - /** - * @brief Sets the cell name conflict resolution mode - */ - void set_cell_conflict_resolution (CellConflictResolution cc_resolution) - { - m_cc_resolution = cc_resolution; - } - - /** - * @brief Sets the cell name conflict resolution mode - */ - CellConflictResolution cell_conflict_resolution () const - { - return m_cc_resolution; - } - /** * @brief Make a cell from a name */ @@ -132,9 +205,17 @@ public: */ void finish (db::Layout &layout); + // Reimplementation of the ReaderBase interace + virtual const db::LayerMap &read (db::Layout &layout, const db::LoadLayoutOptions &options); + virtual const db::LayerMap &read (db::Layout &layout); + protected: + friend class CommonReaderLayerMapping; + virtual void common_reader_error (const std::string &msg) = 0; virtual void common_reader_warn (const std::string &msg) = 0; + virtual void do_read (db::Layout &layout) = 0; + virtual void init (const LoadLayoutOptions &options); /** * @brief Merge (and delete) the src_cell into target_cell @@ -146,98 +227,81 @@ protected: */ void merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const; + /** + * @brief Gets the common options + */ + db::CommonReaderOptions &common_options () + { + return m_common_options; + } + + /** + * @brief Gets the layer map + */ + db::LayerMap &layer_map () + { + return m_layer_map; + } + + /** + * @brief Gets the layer name map + */ + layer_name_map &layer_names () + { + return m_layer_names; + } + + /** + * @brief Gets the list of layers which have been created + */ + std::set &layers_created () + { + return m_layers_created; + } + + /** + * @brief Enters the a layer with a given layer/datatype + */ + std::pair open_dl (db::Layout &layout, const LDPair &dl); + private: std::map > m_id_map; std::map > m_name_map; std::map m_name_for_id; CellConflictResolution m_cc_resolution; + bool m_create_layers; + db::CommonReaderOptions m_common_options; + db::LayerMap m_layer_map; + tl::interval_map > m_layer_names; + std::set m_layers_created; }; /** - * @brief Structure that holds the GDS2 and OASIS specific options for the reader + * @brief A utility class that maps the layers for the proxy cell recovery */ -class DB_PUBLIC CommonReaderOptions - : public FormatSpecificReaderOptions +class CommonReaderLayerMapping + : public db::ImportLayerMapping { public: - /** - * @brief The constructor - */ - CommonReaderOptions () - : create_other_layers (true), - enable_text_objects (true), - enable_properties (true), - cell_conflict_resolution (CommonReader::AddToCell) + CommonReaderLayerMapping (db::CommonReader *reader, db::Layout *layout) + : mp_reader (reader), mp_layout (layout) { // .. nothing yet .. } - /** - * @brief Specifies a layer mapping - * - * If a layer mapping is specified, only the given layers are read. - * Otherwise, all layers are read. - * Setting "create_other_layers" to true will make the reader - * create other layers for all layers not given in the layer map. - * Setting an empty layer map and create_other_layers to true effectively - * enables all layers for reading. - */ - db::LayerMap layer_map; - - /** - * @brief A flag indicating that a new layers shall be created - * - * If this flag is set to true, layers not listed in the layer map a created - * too. - */ - bool create_other_layers; - - /** - * @brief A flag indicating whether to read text objects - * - * If this flag is set to true, text objects are read. Otherwise they are ignored. - */ - bool enable_text_objects; - - /** - * @brief A flag indicating whether to read user properties - * - * If this flag is set to true, user properties are read. Otherwise they are ignored. - */ - bool enable_properties; - - /** - * @brief Specifies the cell merge behavior - * - * This enum controls how cells are read if a cell with the requested name already - * exists. - * - * AddToCell In this mode, instances or shapes are added to any existing cell - * OverwriteCell Overwrite existing cell. If the existing cell has children, those are removed unless used otherwise - * SkipNewCell Ignore the new cell and it's children - * RenameCell Rename the new cell - * - * If the existing opr the new cell is a ghost cell, AddToCell is applied always. In other words, - * ghost cells are always merged. - */ - CommonReader::CellConflictResolution cell_conflict_resolution; - - /** - * @brief Implementation of FormatSpecificReaderOptions - */ - virtual FormatSpecificReaderOptions *clone () const + std::pair map_layer (const db::LayerProperties &lprops) { - return new CommonReaderOptions (*this); + // named layers that are imported from a library are ignored + if (lprops.is_named ()) { + return std::make_pair (false, 0); + } else { + return mp_reader->open_dl (*mp_layout, LDPair (lprops.layer, lprops.datatype)); + } } - /** - * @brief Implementation of FormatSpecificReaderOptions - */ - virtual const std::string &format_name () const - { - static const std::string n ("Common"); - return n; - } +private: + db::CommonReader *mp_reader; + db::Layout *mp_layout; }; } diff --git a/src/db/db/gsiDeclDbCommonStreamOptions.cc b/src/db/db/gsiDeclDbCommonStreamOptions.cc index 32b8ede8c..31245a050 100644 --- a/src/db/db/gsiDeclDbCommonStreamOptions.cc +++ b/src/db/db/gsiDeclDbCommonStreamOptions.cc @@ -85,12 +85,12 @@ static void set_properties_enabled (db::LoadLayoutOptions *options, bool l) options->get_options ().enable_properties = l; } -static db::CommonReader::CellConflictResolution get_cell_conflict_resolution (const db::LoadLayoutOptions *options) +static db::CellConflictResolution get_cell_conflict_resolution (const db::LoadLayoutOptions *options) { return options->get_options ().cell_conflict_resolution; } -static void set_cell_conflict_resolution (db::LoadLayoutOptions *options, db::CommonReader::CellConflictResolution cc) +static void set_cell_conflict_resolution (db::LoadLayoutOptions *options, db::CellConflictResolution cc) { options->get_options ().cell_conflict_resolution = cc; } @@ -188,18 +188,18 @@ gsi::ClassExt common_reader_options ( ); -gsi::EnumIn decl_dbCommonReader_CellConflictResolution ("db", "CellConflictResolution", - gsi::enum_const ("AddToCell", db::CommonReader::AddToCell, +gsi::EnumIn decl_dbCommonReader_CellConflictResolution ("db", "CellConflictResolution", + gsi::enum_const ("AddToCell", db::AddToCell, "@brief Add content to existing cell\n" "This is the mode use in before version 0.27. Content of new cells is simply added to existing cells with the same name." ) + - gsi::enum_const ("OverwriteCell", db::CommonReader::OverwriteCell, + gsi::enum_const ("OverwriteCell", db::OverwriteCell, "@brief The old cell is overwritten entirely (including child cells which are not used otherwise)\n" ) + - gsi::enum_const ("SkipNewCell", db::CommonReader::SkipNewCell, + gsi::enum_const ("SkipNewCell", db::SkipNewCell, "@brief The new cell is skipped entirely (including child cells which are not used otherwise)\n" ) + - gsi::enum_const ("RenameCell", db::CommonReader::RenameCell, + gsi::enum_const ("RenameCell", db::RenameCell, "@brief The new cell will be renamed to become unique\n" ), "@brief This enum specifies how cell conflicts are handled if a layout read into another layout and a cell name conflict arises. " diff --git a/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.cc b/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.cc index ee363ed67..d25c92bfc 100644 --- a/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.cc +++ b/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.cc @@ -51,23 +51,11 @@ GDS2ReaderText::~GDS2ReaderText() // .. nothing yet .. } -const LayerMap & -GDS2ReaderText::read (db::Layout &layout, const db::LoadLayoutOptions &options) +void +GDS2ReaderText::init (const db::LoadLayoutOptions &options) { + GDS2ReaderBase::init (options); storedRecId = 0; - - // HINT: reuse the standard GDS2 reader options for the text reader. - // However, the allow_big_records and allow_multi_xy_records options are ignored. - db::GDS2ReaderOptions gds2_options = options.get_options (); - db::CommonReaderOptions common_options = options.get_options (); - - return basic_read (layout, common_options.layer_map, common_options.create_other_layers, common_options.enable_text_objects, common_options.enable_properties, false, gds2_options.box_mode, common_options.cell_conflict_resolution); -} - -const LayerMap & -GDS2ReaderText::read (db::Layout &layout) -{ - return read (layout, db::LoadLayoutOptions ()); } void diff --git a/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.h b/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.h index 56de72863..2ec5b278a 100644 --- a/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.h +++ b/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.h @@ -64,43 +64,14 @@ public: */ ~GDS2ReaderText(); - /** - * @brief The basic read method - * - * This method will read the stream data and translate this to - * insert calls into the layout object. This will not do much - * on the layout object beside inserting the objects. - * It can be given a couple of options specified with the - * LoadLayoutOptions object. - * The returned map will contain all layers, the passed - * ones and the newly created ones. - * - * @param layout The layout object to write to - * @param options The generic reader options - * @return The LayerMap object that tells where which layer was loaded - */ - virtual const LayerMap &read (db::Layout &layout, const LoadLayoutOptions &options); - - /** - * @brief The basic read method (without mapping) - * - * This method will read the stream data and translate this to - * insert calls into the layout object. This will not do much - * on the layout object beside inserting the objects. - * This version will read all input layers and return a map - * which tells which GDS2 layer has been read into which logical - * layer. - * - * @param layout The layout object to write to - * @return The LayerMap object - */ - virtual const LayerMap &read (db::Layout &layout); - /** * @brief Format */ const char *format () const { return "GDS2Text"; } +protected: + virtual void init (const LoadLayoutOptions &options); + private: tl::TextInputStream sStream; std::string sExtractedValue; diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.cc index 772da9429..8838dafa9 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.cc @@ -43,6 +43,7 @@ GDS2Reader::GDS2Reader (tl::InputStream &s) m_recptr (0), mp_rec_buf (0), m_stored_rec (0), + m_allow_big_records (true), m_progress (tl::to_string (tr ("Reading GDS2 file")), 10000) { m_progress.set_format (tl::to_string (tr ("%.0f MB"))); @@ -54,23 +55,16 @@ GDS2Reader::~GDS2Reader () // .. nothing yet .. } -const LayerMap & -GDS2Reader::read (db::Layout &layout, const db::LoadLayoutOptions &options) +void +GDS2Reader::init (const db::LoadLayoutOptions &options) { - m_options = options.get_options (); - m_common_options = options.get_options (); + GDS2ReaderBase::init (options); + + m_allow_big_records = options.get_options ().allow_big_records; m_recnum = 0; --m_recnum; m_reclen = 0; - - return basic_read (layout, m_common_options.layer_map, m_common_options.create_other_layers, m_common_options.enable_text_objects, m_common_options.enable_properties, m_options.allow_multi_xy_records, m_options.box_mode, m_common_options.cell_conflict_resolution); -} - -const LayerMap & -GDS2Reader::read (db::Layout &layout) -{ - return read (layout, db::LoadLayoutOptions ()); } void @@ -108,7 +102,7 @@ GDS2Reader::get_record () error (tl::to_string (tr ("Invalid record length (less than 4)"))); } if (m_reclen >= 0x8000) { - if (m_options.allow_big_records) { + if (m_allow_big_records) { warn (tl::to_string (tr ("Record length larger than 0x8000 encountered: interpreting as unsigned"))); } else { error (tl::to_string (tr ("Record length larger than 0x8000 encountered (reader is configured not to allow such records)"))); diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.h b/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.h index 2b51144dd..21d1b5b05 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.h +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.h @@ -72,43 +72,14 @@ public: */ ~GDS2Reader (); - /** - * @brief The basic read method - * - * This method will read the stream data and translate this to - * insert calls into the layout object. This will not do much - * on the layout object beside inserting the objects. - * It can be given a couple of options specified with the - * LoadLayoutOptions object. - * The returned map will contain all layers, the passed - * ones and the newly created ones. - * - * @param layout The layout object to write to - * @param options The generic reader options - * @return The LayerMap object that tells where which layer was loaded - */ - virtual const LayerMap &read (db::Layout &layout, const LoadLayoutOptions &options); - - /** - * @brief The basic read method (without mapping) - * - * This method will read the stream data and translate this to - * insert calls into the layout object. This will not do much - * on the layout object beside inserting the objects. - * This version will read all input layers and return a map - * which tells which GDS2 layer has been read into which logical - * layer. - * - * @param layout The layout object to write to - * @return The LayerMap object - */ - virtual const LayerMap &read (db::Layout &layout); - /** * @brief Format */ virtual const char *format () const { return "GDS2"; } +protected: + virtual void init (const LoadLayoutOptions &options); + private: tl::InputStream &m_stream; size_t m_recnum; @@ -117,8 +88,7 @@ private: unsigned char *mp_rec_buf; tl::string m_string_buf; short m_stored_rec; - db::GDS2ReaderOptions m_options; - db::CommonReaderOptions m_common_options; + bool m_allow_big_records; tl::AbsoluteProgress m_progress; virtual void error (const std::string &txt); diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc index 7111089d9..d55020fa5 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc @@ -22,6 +22,7 @@ #include "dbGDS2ReaderBase.h" +#include "dbGDS2Format.h" #include "dbGDS2.h" #include "dbArray.h" @@ -34,42 +35,12 @@ namespace db // --------------------------------------------------------------- -/** - * @brief A utility class that maps the layers for the proxy cell recovery - */ -class GDS2ReaderLayerMapping - : public db::ImportLayerMapping -{ -public: - GDS2ReaderLayerMapping (db::GDS2ReaderBase *reader, db::Layout *layout, bool create) - : mp_reader (reader), mp_layout (layout), m_create (create) - { - // .. nothing yet .. - } - - std::pair map_layer (const db::LayerProperties &lprops) - { - // named layers that are imported from a library are ignored - if (lprops.is_named ()) { - return std::make_pair (false, 0); - } else { - return mp_reader->open_dl (*mp_layout, LDPair (lprops.layer, lprops.datatype), m_create); - } - } - -private: - db::GDS2ReaderBase *mp_reader; - db::Layout *mp_layout; - bool m_create; -}; - // --------------------------------------------------------------- // GDS2ReaderBase GDS2ReaderBase::GDS2ReaderBase () : m_dbu (0.001), m_dbuu (1.0), - m_create_layers (true), m_read_texts (true), m_read_properties (true), m_allow_multi_xy_records (false), @@ -83,31 +54,18 @@ GDS2ReaderBase::~GDS2ReaderBase () // .. nothing yet .. } -const LayerMap & -GDS2ReaderBase::basic_read (db::Layout &layout, const LayerMap &layer_map, bool create_other_layers, bool enable_text_objects, bool enable_properties, bool allow_multi_xy_records, unsigned int box_mode, db::CommonReader::CellConflictResolution cc_resolution) +void +GDS2ReaderBase::init (const db::LoadLayoutOptions &options) { - m_layer_map = layer_map; - m_layer_map.prepare (layout); - m_read_texts = enable_text_objects; - m_read_properties = enable_properties; + CommonReader::init (options); - m_allow_multi_xy_records = allow_multi_xy_records; - m_box_mode = box_mode; - m_create_layers = create_other_layers; + db::GDS2ReaderOptions gds2_options = options.get_options (); - set_cell_conflict_resolution (cc_resolution); + m_read_texts = common_options ().enable_text_objects; + m_read_properties = common_options ().enable_properties; - layout.start_changes (); - try { - do_read (layout); - finish (layout); - layout.end_changes (); - } catch (...) { - layout.end_changes (); - throw; - } - - return m_layer_map; + m_allow_multi_xy_records = gds2_options.allow_multi_xy_records; + m_box_mode = gds2_options.box_mode; } void @@ -181,34 +139,6 @@ GDS2ReaderBase::finish_element (db::PropertiesRepository &rep) } -std::pair -GDS2ReaderBase::open_dl (db::Layout &layout, const LDPair &dl, bool create) -{ - std::pair ll = m_layer_map.first_logical (dl, layout); - if (ll.first) { - - return ll; - - } else if (! create) { - - // layer not mapped and no layer create is requested - return ll; - - } else { - - // and create the layer - db::LayerProperties lp; - lp.layer = dl.layer; - lp.datatype = dl.datatype; - - unsigned int ll = layout.insert_layer (lp); - m_layer_map.map (dl, ll, lp); - - return std::make_pair (true, ll); - - } -} - inline db::Point pt_conv (const GDS2XY &p) { @@ -362,7 +292,7 @@ GDS2ReaderBase::do_read (db::Layout &layout) std::map >::const_iterator ctx = m_context_info.find (m_cellname); if (ctx != m_context_info.end ()) { - GDS2ReaderLayerMapping layer_mapping (this, &layout, m_create_layers); + CommonReaderLayerMapping layer_mapping (this, &layout); if (layout.recover_proxy_as (cell_index, ctx->second.begin (), ctx->second.end (), &layer_mapping)) { // ignore everything in that cell since it is created by the import: cell = 0; @@ -553,7 +483,7 @@ GDS2ReaderBase::read_boundary (db::Layout &layout, db::Cell &cell, bool from_box unsigned int xy_length = 0; GDS2XY *xy_data = get_xy_data (xy_length); - std::pair ll = open_dl (layout, ld, m_create_layers); + std::pair ll = open_dl (layout, ld); if (ll.first) { // create a box object if possible @@ -734,7 +664,7 @@ GDS2ReaderBase::read_path (db::Layout &layout, db::Cell &cell) unsigned int xy_length = 0; GDS2XY *xy_data = get_xy_data (xy_length); - std::pair ll = open_dl (layout, ld, m_create_layers); + std::pair ll = open_dl (layout, ld); if (ll.first) { // this will copy the path: @@ -825,7 +755,7 @@ GDS2ReaderBase::read_text (db::Layout &layout, db::Cell &cell) std::pair ll (false, 0); if (m_read_texts) { - ll = open_dl (layout, ld, m_create_layers); + ll = open_dl (layout, ld); } rec_id = get_record (); @@ -947,7 +877,7 @@ GDS2ReaderBase::read_box (db::Layout &layout, db::Cell &cell) } ld.datatype = get_ushort (); - std::pair ll = open_dl (layout, ld, m_create_layers); + std::pair ll = open_dl (layout, ld); if (get_record () != sXY) { error (tl::to_string (tr ("XY record expected"))); diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.h b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.h index a094da9fb..d31c0c537 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.h +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.h @@ -69,42 +69,20 @@ public: const std::string &libname () const { return m_libname; } protected: - /** - * @brief The basic read method - * - * This method will read the stream data and translate this to - * insert calls into the layout object. This will not do much - * on the layout object beside inserting the objects. - * It can be given a couple of options specified with the - * LoadLayoutOptions object. - * The returned map will contain all layers, the passed - * ones and the newly created ones. - * - * @param layout The layout object to write to - * @param layer_map The layer mapping on input - * @param create_other_layer A flag indicating whether to read all other layers - * @param enable_text_objects A flag indicating whether to read text objects - * @param enable_properties A flag indicating whether to read user properties - * @param allow_multi_xy_records If true, tries to check for multiple XY records for BOUNDARY elements - * @param box_mode How to treat BOX records (0: ignore, 1: as rectangles, 2: as boundaries, 3: error) - * @param cc_resolution The cell name conflict resolution mode - * @return The LayerMap object that tells where which layer was loaded - */ - const LayerMap &basic_read (db::Layout &layout, const LayerMap &layer_map, bool create_other_layers, bool enable_text_objects, bool enable_properties, bool allow_multi_xy_records, unsigned int box_mode, db::CommonReader::CellConflictResolution cc_resolution); - /** * @brief Accessor method to the current cellname */ const std::string &cellname () const { return m_cellname; } + virtual void do_read (db::Layout &layout); + virtual void init (const LoadLayoutOptions &options); + private: friend class GDS2ReaderLayerMapping; - LayerMap m_layer_map; std::string m_cellname; std::string m_libname; double m_dbu, m_dbuu; - bool m_create_layers; bool m_read_texts; bool m_read_properties; bool m_allow_multi_xy_records; @@ -119,9 +97,6 @@ private: void read_box (db::Layout &layout, db::Cell &cell); void read_ref (db::Layout &layout, db::Cell &cell, bool array, tl::vector &instances, tl::vector &insts_wp); - void do_read (db::Layout &layout); - - std::pair open_dl (db::Layout &layout, const LDPair &dl, bool create); std::pair finish_element (db::PropertiesRepository &rep); void finish_element (); diff --git a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc b/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc index 7361c67a2..dc53a8db7 100644 --- a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc +++ b/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc @@ -443,7 +443,7 @@ TEST(4_CollectModeRename) db::Layout layout (&m); db::LoadLayoutOptions options; - options.get_options ().cell_conflict_resolution = db::CommonReader::RenameCell; + options.get_options ().cell_conflict_resolution = db::RenameCell; { tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds"); @@ -467,7 +467,7 @@ TEST(4_CollectModeOverwrite) db::Layout layout (&m); db::LoadLayoutOptions options; - options.get_options ().cell_conflict_resolution = db::CommonReader::OverwriteCell; + options.get_options ().cell_conflict_resolution = db::OverwriteCell; { tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds"); @@ -491,7 +491,7 @@ TEST(4_CollectModeSkip) db::Layout layout (&m); db::LoadLayoutOptions options; - options.get_options ().cell_conflict_resolution = db::CommonReader::SkipNewCell; + options.get_options ().cell_conflict_resolution = db::SkipNewCell; { tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds"); @@ -515,7 +515,7 @@ TEST(4_CollectModeAdd) db::Layout layout (&m); db::LoadLayoutOptions options; - options.get_options ().cell_conflict_resolution = db::CommonReader::AddToCell; + options.get_options ().cell_conflict_resolution = db::AddToCell; { tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds"); diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc index 131fb3e9a..ce6f1a3f1 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc @@ -38,35 +38,6 @@ namespace db // --------------------------------------------------------------- -/** - * @brief A utility class that maps the layers for the proxy cell recovery - */ -class OASISReaderLayerMapping - : public db::ImportLayerMapping -{ -public: - OASISReaderLayerMapping (db::OASISReader *reader, db::Layout *layout, bool create) - : mp_reader (reader), mp_layout (layout), m_create (create) - { - // .. nothing yet .. - } - - std::pair map_layer (const db::LayerProperties &lprops) - { - // named layers that are imported from a library are ignored - if (lprops.is_named ()) { - return std::make_pair (false, 0); - } else { - return mp_reader->open_dl (*mp_layout, LDPair (lprops.layer, lprops.datatype), m_create); - } - } - -private: - db::OASISReader *mp_reader; - db::Layout *mp_layout; - bool m_create; -}; - // --------------------------------------------------------------- // OASISReader @@ -101,7 +72,6 @@ OASISReader::OASISReader (tl::InputStream &s) mm_last_property_name (this, "last-property-name"), mm_last_property_is_sprop (this, "last-property-is-stdprop"), mm_last_value_list(this, "last-value-list"), - m_create_layers (false), m_read_texts (true), m_read_properties (true), m_read_all_properties (false), @@ -129,40 +99,17 @@ OASISReader::~OASISReader () // .. nothing yet .. } -const LayerMap & -OASISReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) +void +OASISReader::init (const db::LoadLayoutOptions &options) { - db::OASISReaderOptions oasis_options = options.get_options (); - db::CommonReaderOptions common_options = options.get_options (); + CommonReader::init (options); - m_layer_map = common_options.layer_map; - m_layer_map.prepare (layout); - m_layers_created.clear (); - m_read_texts = common_options.enable_text_objects; - m_read_properties = common_options.enable_properties; - m_create_layers = common_options.create_other_layers; + m_read_texts = common_options ().enable_text_objects; + m_read_properties = common_options ().enable_properties; + + db::OASISReaderOptions oasis_options = options.get_options (); m_read_all_properties = oasis_options.read_all_properties; m_expect_strict_mode = oasis_options.expect_strict_mode; - - set_cell_conflict_resolution (common_options.cell_conflict_resolution); - - layout.start_changes (); - try { - do_read (layout); - finish (layout); - layout.end_changes (); - } catch (...) { - layout.end_changes (); - throw; - } - - return m_layer_map; -} - -const LayerMap & -OASISReader::read (db::Layout &layout) -{ - return read (layout, db::LoadLayoutOptions ()); } inline long long @@ -554,44 +501,6 @@ OASISReader::warn (const std::string &msg) } } -std::pair -OASISReader::open_dl (db::Layout &layout, const LDPair &dl, bool create) -{ - std::pair ll = m_layer_map.first_logical (dl, layout); - if (ll.first) { - - return ll; - - } else if (! create) { - - return ll; - - } else { - - // and create the layer - db::LayerProperties lp; - lp.layer = dl.layer; - lp.datatype = dl.datatype; - - // resolve OASIS name if possible - const tl::interval_map *names_dmap = m_layernames.mapped (dl.layer); - if (names_dmap != 0) { - const std::string *name = names_dmap->mapped (dl.datatype); - if (name != 0) { - lp.name = *name; - } - } - - unsigned int ll = layout.insert_layer (lp); - m_layer_map.map (dl, ll, lp); - - m_layers_created.insert (ll); - - return std::make_pair (true, ll); - - } -} - /** * @brief A helper class to join two datatype layer name map members */ @@ -765,7 +674,6 @@ OASISReader::do_read (db::Layout &layout) m_textstrings.clear (); m_propstrings.clear (); m_propnames.clear (); - m_layernames.clear (); m_instances.clear (); m_instances_with_props.clear (); @@ -1077,10 +985,10 @@ OASISReader::do_read (db::Layout &layout) LNameJoinOp1 op1; dt_map.add (dt1, dt2 + 1, name, op1); LNameJoinOp2 op2; - m_layernames.add (l1, l2 + 1, dt_map, op2); + layer_names ().add (l1, l2 + 1, dt_map, op2); // rename layers created before if required - for (std::set::const_iterator i = m_layers_created.begin (); i != m_layers_created.end (); ++i) { + for (std::set::const_iterator i = layers_created ().begin (); i != layers_created ().end (); ++i) { const db::LayerProperties &lp = layout.get_properties (*i); if (lp.layer >= l1 && lp.layer <= l2 && lp.datatype >= dt1 && lp.datatype <= dt2 && lp.name != name) { // need to rename: add a new madding to m_layer_map and adjust the layout's layer properties @@ -1088,7 +996,7 @@ OASISReader::do_read (db::Layout &layout) LNameJoinOp1 nj; nj (lpp.name, name); layout.set_properties (*i, lpp); - m_layer_map.map (LDPair (lp.layer, lp.datatype), *i, lpp); + layer_map ().map (LDPair (lp.layer, lp.datatype), *i, lpp); } } @@ -2038,7 +1946,7 @@ OASISReader::do_read_text (bool xy_absolute, std::pair ll (false, 0); if (m_read_texts) { - ll = open_dl (layout, LDPair (mm_textlayer.get (), mm_texttype.get ()), m_create_layers); + ll = open_dl (layout, LDPair (mm_textlayer.get (), mm_texttype.get ())); } if ((m & 0x4) && read_repetition ()) { @@ -2180,7 +2088,7 @@ OASISReader::do_read_rectangle (bool xy_absolute, db::Box box (db::Point (mm_geometry_x.get (), mm_geometry_y.get ()), db::Point (mm_geometry_x.get () + mm_geometry_w.get (), mm_geometry_y.get () + mm_geometry_h.get ())); - std::pair ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers); + std::pair ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ())); if ((m & 0x4) && read_repetition ()) { @@ -2294,7 +2202,7 @@ OASISReader::do_read_polygon (bool xy_absolute, db::cell_index_type cell_index, db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ()); - std::pair ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers); + std::pair ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ())); if ((m & 0x4) && read_repetition ()) { @@ -2461,7 +2369,7 @@ OASISReader::do_read_path (bool xy_absolute, db::cell_index_type cell_index, db: db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ()); - std::pair ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers); + std::pair ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ())); if ((m & 0x4) && read_repetition ()) { @@ -2620,7 +2528,7 @@ OASISReader::do_read_trapezoid (unsigned char r, bool xy_absolute,db::cell_index db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ()); - std::pair ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers); + std::pair ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ())); db::Point pts [4]; @@ -2775,7 +2683,7 @@ OASISReader::do_read_ctrapezoid (bool xy_absolute,db::cell_index_type cell_index db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ()); - std::pair ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers); + std::pair ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ())); db::Point pts [4]; @@ -3126,7 +3034,7 @@ OASISReader::do_read_circle (bool xy_absolute, db::cell_index_type cell_index, d db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ()); - std::pair ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers); + std::pair ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ())); // ignore this circle if the radius is zero if (mm_circle_radius.get () <= 0) { @@ -3444,7 +3352,7 @@ OASISReader::do_read_cell (db::cell_index_type cell_index, db::Layout &layout) // Restore proxy cell (link to PCell or Library) if (has_context) { - OASISReaderLayerMapping layer_mapping (this, &layout, m_create_layers); + CommonReaderLayerMapping layer_mapping (this, &layout); layout.recover_proxy_as (cell_index, context_strings.begin (), context_strings.end (), &layer_mapping); } diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.h b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.h index a8a56e173..89b18d5fd 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.h +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.h @@ -81,39 +81,6 @@ public: */ ~OASISReader (); - /** - * @brief The basic read method - * - * This method will read the stream data and translate this to - * insert calls into the layout object. This will not do much - * on the layout object beside inserting the objects. - * A set of options can be specified with the LoadLayoutOptions - * object. - * The returned map will contain all layers, the passed - * ones and the newly created ones. - * - * @param layout The layout object to write to - * @param map The LayerMap object - * @param create true, if new layers should be created - * @return The LayerMap object that tells where which layer was loaded - */ - virtual const LayerMap &read (db::Layout &layout, const LoadLayoutOptions &options); - - /** - * @brief The basic read method (without mapping) - * - * This method will read the stream data and translate this to - * insert calls into the layout object. This will not do much - * on the layout object beside inserting the objects. - * This version will read all input layers and return a map - * which tells which OASIS layer has been read into which logical - * layer. - * - * @param layout The layout object to write to - * @return The LayerMap object - */ - virtual const LayerMap &read (db::Layout &layout); - /** * @brief Format */ @@ -136,6 +103,8 @@ protected: virtual void common_reader_error (const std::string &msg) { error (msg); } virtual void common_reader_warn (const std::string &msg) { warn (msg); } + virtual void init (const LoadLayoutOptions &options); + virtual void do_read (db::Layout &layout); private: friend class OASISReaderLayerMapping; @@ -153,8 +122,6 @@ private: }; tl::InputStream &m_stream; - LayerMap m_layer_map; - std::set m_layers_created; tl::AbsoluteProgress m_progress; std::string m_cellname; double m_dbu; @@ -204,12 +171,10 @@ private: std::map m_text_forward_references; std::map m_propstrings; std::map m_propnames; - tl::interval_map > m_layernames; tl::vector m_instances; tl::vector m_instances_with_props; - bool m_create_layers; bool m_read_texts; bool m_read_properties; bool m_read_all_properties; @@ -219,7 +184,6 @@ private: db::property_names_id_type m_s_gds_property_name_id; db::property_names_id_type m_klayout_context_property_name_id; - void do_read (db::Layout &layout); void do_read_cell (db::cell_index_type cell_index, db::Layout &layout); void do_read_placement (unsigned char r, @@ -310,8 +274,6 @@ private: db::Coord get_coord (long grid = 1); db::Coord get_ucoord (unsigned long grid = 1); distance_type get_ucoord_as_distance (unsigned long grid = 1); - - std::pair open_dl (db::Layout &layout, const LDPair &dl, bool create); }; } From a1eb8c121b6b9ecfc643161cd194f3ab8cd577b3 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 19 Dec 2020 15:36:03 +0100 Subject: [PATCH 27/44] WIP: implementation for GDS2 and OASIS, added tests. --- src/db/db/dbCommonReader.cc | 166 ++++++++++++++++-- src/db/db/dbCommonReader.h | 25 +-- .../streamers/gds2/unit_tests/dbGDS2Reader.cc | 49 +++++- .../oasis/db_plugin/dbOASISReader.cc | 20 +-- testdata/gds/alm_au2.gds | Bin 0 -> 11842 bytes 5 files changed, 201 insertions(+), 59 deletions(-) create mode 100644 testdata/gds/alm_au2.gds diff --git a/src/db/db/dbCommonReader.cc b/src/db/db/dbCommonReader.cc index f53db049b..59d59f16f 100644 --- a/src/db/db/dbCommonReader.cc +++ b/src/db/db/dbCommonReader.cc @@ -32,6 +32,34 @@ namespace db // --------------------------------------------------------------- // Common reader implementation +DB_PUBLIC void +join_layer_names (std::string &s, const std::string &n) +{ + if (s == n) { + return; + } + + if (! s.empty ()) { + + size_t i = s.find (n); + if (i != std::string::npos && (i == 0 || s.c_str ()[i - 1] == ';')) { + char after = s.c_str ()[i + n.size ()]; + if (after == 0 || after == ';') { + // n is already contained in s + return; + } + } + + s += ";"; + + } + + s += n; +} + +// --------------------------------------------------------------- +// Common reader implementation + static const size_t null_id = std::numeric_limits::max (); CommonReader::CommonReader () @@ -280,7 +308,7 @@ CommonReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) { init (options); - m_layer_map.prepare (layout); + m_common_options.layer_map.prepare (layout); layout.start_changes (); try { @@ -292,7 +320,7 @@ CommonReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) throw; } - return m_layer_map; + return m_layer_map_out; } const db::LayerMap & @@ -305,12 +333,23 @@ void CommonReader::init (const LoadLayoutOptions &options) { m_common_options = options.get_options (); - m_layer_map = m_common_options.layer_map; m_cc_resolution = m_common_options.cell_conflict_resolution; m_create_layers = m_common_options.create_other_layers; + m_layer_map_out.clear (); + m_multi_mapping_placeholders.clear (); + m_layer_cache.clear (); m_layers_created.clear (); m_layer_names.clear (); + + // create a pseudo-multimapping for single targets + for (db::LayerMap::const_iterator_layers li = m_common_options.layer_map.begin (); li != m_common_options.layer_map.end (); ++li) { + for (db::LayerMap::const_iterator_datatypes di = li->second.begin (); di != li->second.end (); ++di) { + if (di->second.size () == 1) { + m_multi_mapping_placeholders.insert (std::make_pair (di->second, *di->second.begin ())); + } + } + } } void @@ -420,21 +459,77 @@ CommonReader::finish (db::Layout &layout) } } + + // resolve layer multi-mapping + + for (std::map, unsigned int>::const_iterator i = m_multi_mapping_placeholders.begin (); i != m_multi_mapping_placeholders.end (); ++i) { + + if (i->first.size () > 1) { + + bool discard_layer = i->first.find (i->second) == i->first.end (); + + for (std::set::const_iterator l = i->first.begin (); l != i->first.end (); ++l) { + + // last one? this one will get a "move" + std::set::const_iterator ll = l; + if (discard_layer && ++ll == i->first.end ()) { + layout.move_layer (i->second, *l); + layout.delete_layer (i->second); + } else { + layout.copy_layer (i->second, *l); + } + + } + + } + + } + + // rename layers created before if required + + for (std::set::const_iterator i = m_layers_created.begin (); i != m_layers_created.end (); ++i) { + + const db::LayerProperties &lp = layout.get_properties (*i); + + const tl::interval_map *dtmap = layer_names ().mapped (lp.layer); + const std::string *name = 0; + if (dtmap) { + name = dtmap->mapped (lp.datatype); + } + + if (name) { + // need to rename: add a new madding to m_layer_map_out and adjust the layout's layer properties + db::LayerProperties lpp = lp; + join_layer_names (lpp.name, *name); + layout.set_properties (*i, lpp); + m_layer_map_out.map (LDPair (lp.layer, lp.datatype), *i, lpp); + } + + } } std::pair CommonReader::open_dl (db::Layout &layout, const LDPair &dl) { - std::pair ll = m_layer_map.first_logical (dl, layout); - if (ll.first) { - - return ll; - - } else if (! m_create_layers) { - - return ll; - + std::map >::const_iterator lc = m_layer_cache.find (dl); + if (lc != m_layer_cache.end ()) { + return lc->second; } else { + std::pair res = open_dl_uncached (layout, dl); + m_layer_cache.insert (std::make_pair (dl, res)); + return res; + } +} + +std::pair +CommonReader::open_dl_uncached (db::Layout &layout, const LDPair &dl) +{ + const std::set &li = common_options ().layer_map.logical (dl, layout); + if (li.empty ()) { + + if (! m_create_layers) { + return std::make_pair (false, (unsigned int) 0); + } // and create the layer db::LayerProperties lp; @@ -450,18 +545,53 @@ CommonReader::open_dl (db::Layout &layout, const LDPair &dl) } } - unsigned int ll = layout.insert_layer (lp); - m_layer_map.map (dl, ll, lp); + unsigned int nl = layout.insert_layer (lp); + m_layer_map_out.map (dl, nl, lp); - m_layers_created.insert (ll); + m_layers_created.insert (nl); - return std::make_pair (true, ll); + return std::make_pair (true, nl); + + } else if (li.size () == 1) { + + m_layer_map_out.map (dl, *li.begin (), layout.get_properties (*li.begin ())); + + return std::make_pair (true, *li.begin ()); + + } else { + + std::map, unsigned int>::iterator mmp = m_multi_mapping_placeholders.find (li); + if (mmp == m_multi_mapping_placeholders.end ()) { + + // multi-mapping: create a placeholder layer if required + + for (std::set::const_iterator i = li.begin (); i != li.end (); ++i) { + m_layer_map_out.mmap (dl, *i, layout.get_properties (*i)); + } + + for (std::set::const_iterator i = li.begin (); i != li.end (); ++i) { + std::set sl; + sl.insert (*i); + if (m_multi_mapping_placeholders.find (sl) == m_multi_mapping_placeholders.end ()) { + // a layer not used in a single-target context can be used as a placeholder layer (but only once) + m_multi_mapping_placeholders.insert (std::make_pair (sl, *i)); + mmp = m_multi_mapping_placeholders.insert (std::make_pair (li, *i)).first; + break; + } + } + + if (mmp == m_multi_mapping_placeholders.end ()) { + // create a placeholder layer for later + mmp = m_multi_mapping_placeholders.insert (std::make_pair (li, layout.insert_layer ())).first; + } + + } + + return std::make_pair (true, mmp->second); } } - - // --------------------------------------------------------------- // Common format declaration diff --git a/src/db/db/dbCommonReader.h b/src/db/db/dbCommonReader.h index 66b784972..cf53f1895 100644 --- a/src/db/db/dbCommonReader.h +++ b/src/db/db/dbCommonReader.h @@ -31,6 +31,9 @@ namespace db { +DB_PUBLIC void +join_layer_names (std::string &s, const std::string &n); + /** * @brief The CellConflictResolution enum */ @@ -235,14 +238,6 @@ protected: return m_common_options; } - /** - * @brief Gets the layer map - */ - db::LayerMap &layer_map () - { - return m_layer_map; - } - /** * @brief Gets the layer name map */ @@ -251,14 +246,6 @@ protected: return m_layer_names; } - /** - * @brief Gets the list of layers which have been created - */ - std::set &layers_created () - { - return m_layers_created; - } - /** * @brief Enters the a layer with a given layer/datatype */ @@ -271,9 +258,13 @@ private: CellConflictResolution m_cc_resolution; bool m_create_layers; db::CommonReaderOptions m_common_options; - db::LayerMap m_layer_map; + db::LayerMap m_layer_map_out; tl::interval_map > m_layer_names; + std::map > m_layer_cache; + std::map, unsigned int> m_multi_mapping_placeholders; std::set m_layers_created; + + std::pair open_dl_uncached (db::Layout &layout, const LDPair &dl); }; /** diff --git a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc b/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc index dc53a8db7..d045b10d3 100644 --- a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc +++ b/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc @@ -418,7 +418,7 @@ TEST(3_AdvancedMapping) EXPECT_EQ (lm_read.to_string_file_format (), "1/10 : 1/0\n" - "2/0-9,21-*\n" + "2/0-1 : 2/0\n" "1/0 : 1/0\n" "1/1 : 1/1\n" "1/20 : 1/1020\n" @@ -427,16 +427,55 @@ TEST(3_AdvancedMapping) "2/11 : 2/11\n" "42/42 : 142/42\n" "100/0 : 200/0\n" - "2/12-20 : */*\n" - "1/22-30 : 1/*+1000\n" - "1/2-9,11-19,31-* : */*\n" - "0/*;3-41/*;42/0-41,43-*;43-99/*;100/1-*;101-*/* : *+100/*\n" ); std::string fn_au (tl::testsrc () + "/testdata/gds/alm_au.gds"); db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); } +TEST(3_MultiMapping) +{ + db::Manager m (false); + db::Layout layout (&m); + + db::LoadLayoutOptions options; + db::LayerMap lm, lm_read; + + unsigned int n = 0; + lm.map_expr ("*/*: */*", n++); + lm.unmap_expr ("1-2/10"); + lm.mmap_expr ("1-2/10: *+100/*", n++); + lm.mmap_expr ("1/10;2/10: 12/1010", n++); + lm.mmap_expr ("1/0-1: */*+1000", n++); + options.get_options ().layer_map = lm; + + { + tl::InputStream file (tl::testsrc () + "/testdata/gds/alm.gds"); + db::Reader reader (file); + lm_read = reader.read (layout, options); + } + + EXPECT_EQ (lm_read.to_string_file_format (), + "+1-2/10 : 12/1010\n" + "+1/0 : 1/1000\n" + "+1/0 : 1/0\n" + "+1/1 : 1/1001\n" + "+1/1 : 1/1\n" + "+1/10 : 101/10\n" + "1/20 : 1/20\n" + "1/21 : 1/21\n" + "2/0 : 2/0\n" + "2/1 : 2/1\n" + "+2/10 : 102/10\n" + "2/11 : 2/11\n" + "42/42 : 42/42\n" + "100/0 : 100/0\n" + ); + + std::string fn_au (tl::testsrc () + "/testdata/gds/alm_au2.gds"); + db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); +} + TEST(4_CollectModeRename) { db::Manager m (false); diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc index ce6f1a3f1..5042790a8 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc @@ -508,12 +508,7 @@ struct LNameJoinOp1 { void operator() (std::string &a, const std::string &b) { - if (a != b) { - if (! a.empty ()) { - a += ";"; - } - a += b; - } + join_layer_names (a, b); } }; @@ -987,19 +982,6 @@ OASISReader::do_read (db::Layout &layout) LNameJoinOp2 op2; layer_names ().add (l1, l2 + 1, dt_map, op2); - // rename layers created before if required - for (std::set::const_iterator i = layers_created ().begin (); i != layers_created ().end (); ++i) { - const db::LayerProperties &lp = layout.get_properties (*i); - if (lp.layer >= l1 && lp.layer <= l2 && lp.datatype >= dt1 && lp.datatype <= dt2 && lp.name != name) { - // need to rename: add a new madding to m_layer_map and adjust the layout's layer properties - db::LayerProperties lpp = lp; - LNameJoinOp1 nj; - nj (lpp.name, name); - layout.set_properties (*i, lpp); - layer_map ().map (LDPair (lp.layer, lp.datatype), *i, lpp); - } - } - reset_modal_variables (); // ignore properties attached to this name item diff --git a/testdata/gds/alm_au2.gds b/testdata/gds/alm_au2.gds new file mode 100644 index 0000000000000000000000000000000000000000..4492ec4d999fe06e34e1a83c544f52a0f82083d4 GIT binary patch literal 11842 zcmeI2L1>*-7RPU1UcQ&UrZH)g+StUlQ)8P_P)bo}7LpMuGhRe7kX-~Q#9Y_PcpVMHgn)~HFDUJ0H-2L;H z@4WBBKYa1idoSE}{_TfPr^$hJ;;QQO0}rOu9!#m))l&9qxYhqUHlJSK2nEMrSU;f=!Q|dcjllZ=6&jTaB*dAS7#~gL2@8$;w&!p6UMeTj% z>^`iZIpxo!p4JDRACf=EH|4i}w*TaQkopFmsY$+pQ{K<^zrCOM(N81yvDejQB)@vwW;?c^VP)AJ8r&GvKkea3@$#-}4Y@q9Ka&OVFy z@tM4l2ZkSY<~o|{{2+9({~@36$zO}}DNVkwd3`in)4TZk)Qb|4!s2FH~NC;i*ds*X!qsMIH0c}@#v~B@;BE}^hF)$ia5x8 zFyG`wU&gE1ey+aHc;LtQpfBRlkx_BjiN_B+dC^s{_|ZOjn(I7n&%u&nKa!ug<28Lg zSu^Zn(|neAbV2;oO&%W%yVx7wXY1aTdfk(n{E`+~$Iv81Tj(v1vXx6t7mdgdSAKraqs_|ATlwx96j0J=_B8rRHO!&)0_H z`#-CnPxdM<&Q7e?LDmZP2BY>*TT5grk#`Tevml&5F{V_BII0W_vBZ|efiTre1gRDIT-oZ zt3xAZbwJ{_$Gc~onG?qS8jN@9+Zy^-9cBMPADpeOrM{z|*IVCF2fC)8T-QV2KZ5ao zoWFlkx7K%O$;X?&y;x6zoBZA<>L~iA4)o36lxSds?|mYFS-;7T&gmcPad4C0`$Qdf z&dcvx?C){f-$L(wqD~tx6tS%f=|uZF`q+f`fid1c6kXVP5lzHO81A%6f$# z>($WxzFzJ6mvi_Y-@Ag;!#R`uFyhw8Z|_}Mr|^SA?@5Pa>d#(3(;8>Je-%`_oOOps zT(3s_Ww$uBPaf)kai9JZZ`3&yJLl2JZ|zF|(f-i$o{xUu7mPaB=ugo%eyn%ILE2+I zqjg}eI)Vh5k|#fCmuiSd>e(2nNOgflTJDJpjF3ArgPHf6w^obvO8hOigG4hS;&^YV;tDxFNpQB&9K8<5; zN1wD$o}S4R0`CvN;XQCHz7`Xc+@dp+K`>~ZMJ+EHF>SNTf&4|?35|0qs=g}F}E+pCl4 zPthU$L5E{EyZ)$;^WEOvuEQX8qCfH*bKDyFZCybpk`{ai=WIM}+vd6V&k_&=g_I^_Mi&#BJM=PfQ3icB${#y%6Z(&<5I@;&I_~jC%`^G0@?#vBry%jne_`Zb+0QffJa_AP<99f&^84lcK0oF6P4#&T|9%?% zDf32un73>6`)TAa^G1H=gWnOEhu|jvej0Vyx{`mlv~`~LS?{;V@262`*)O*B@|h0m?8QEH z@SLxo#sz&>ZLFV%&ba;1oAT3MVw692;trkkJcamS*O*v5T=qCv^3$&JmG-q35O-kF z{R?Mh*QI(_?|VDzzZ>Zf>*s-weZQkV_Ps+NY2DMlSEzc~@5pbAxaRyt-{fcgB#!kn zNWaA%9rzfK*jm(*cYEcziH(hlcoqsEr@@e7(AKh?o` zI!HYFEsXpt>o{in@3Hg_|GtFZl@1@x{ByGFaON#PaeHujQnz*XFwUoR%ZvIB<;PWc z!Q-YciwpA4v^>l1hkj^>`-M@*(G~iLdTl*N7t{;M$GlTVzs?NCE27#*FVpwCefoL% zeXj3N{@9J`4|(X1G488gix<%waj@j4UFD1R4}anL4!`Ptg}F}E+pG8JkDV9L7yU76 zJgQl*&-k9}YC5PoIY*P<7;(+{ZGO=Q`Hjktju>x9{n&$y!(hwDgZ-WU8s!)MMvX6V z%q#B|f|loM&L`3i_Y0$r=6Y>@cRc3xLh|u$kvh7{Wz<+Rzg>}e#LoQiF5D=8?8MO@ z@)Y8S{c?^Mcb?XF*{M3G~qp41NZg~!<)2O`Yd`5YVZ;8_XOt9_G z5&3zZO58g0h2HQ(U&KM`#LhUNe~2E<{#DO?)nW0f3mp^Bb7E8+<6!af!%lqUfyIyZ zy^f}Fu=7v%{YKcZoMDj(;0WyfN%K Jz9Tuc)3=nOb|C-& literal 0 HcmV?d00001 From 02f96f022af7895a4cb8be44a62e22d0356b79c5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 19 Dec 2020 16:37:58 +0100 Subject: [PATCH 28/44] WIP: added brackets for clarity in mapping expressions. --- src/buddies/src/bd/bdReaderOptions.cc | 32 +++++++++++++++++-------- src/db/db/dbStreamLayers.cc | 30 ++++++++++++++++++++++- src/db/unit_tests/dbStreamLayerTests.cc | 19 +++++++++++++++ src/lay/lay/doc/about/layer_mapping.xml | 25 +++++++++++++++++++ 4 files changed, 95 insertions(+), 11 deletions(-) diff --git a/src/buddies/src/bd/bdReaderOptions.cc b/src/buddies/src/bd/bdReaderOptions.cc index 156e06048..6367fa374 100644 --- a/src/buddies/src/bd/bdReaderOptions.cc +++ b/src/buddies/src/bd/bdReaderOptions.cc @@ -155,32 +155,44 @@ GenericReaderOptions::add_options (tl::CommandLineOptions &cmd) "layer is specified, all source layers addressed with the source specification are " "combined into this target layer.\n" "\n" + "For clarity, source and target specifications can be enclosed in round or square brackets. " + "With square brackets, the default target is '*/*' which results in the expansion of a source " + "layer range.\n" + "\n" "To clone layers, add a mapping statement beginning with a '+' character. While other mapping statements " "redefine mappings established before, mapping statement starting with '+' will clone the layer (1:m mapping).\n" "\n" - "It's also possible to cancel mappings established before by using an 'unmap' statement. Such a statement " + "You can cancel mappings established before by using an 'unmap' statement. Such a statement " "begins with a '-' and lists the layers whose mapping is to be removed. This is useful for creating " "'mapping holes' in sequences.\n" "\n" + "If brackets are used, '+' (multi-mapping) and '-' (unmapping) needs to go before the brackets.\n" + "\n" "Examples:\n" "\n" "* 1/0 2/0 3/0-255:17/0\n" - " Selects 1/0, 2/0 and maps layer 3, datatype 0 to 255 to layer 17, datatype 0\n" + " Selects 1/0, 2/0 and maps layer 3, datatype 0 to 255 to layer 17, datatype 0.\n" + " If clarity, the mapping can also be written with brackets like this: '(1/0) (2/0) (3/0-255:17/0)'.\n" "\n" "* A:1/0 B:2/0\n" - " Maps named layer A to 1/0 and named layer B to 2/0" + " Maps named layer A to 1/0 and named layer B to 2/0.\n" + " If clarity, the mapping can also be written with brackets like this: '(A:1/0) (B:2/0)'.\n" "\n" - "* */*:*/* +10/*:1000/*" - " Includes all layers, but in addition copy all layers 10 to 1000 while keeping the datatype\n" + "* [*/*] +(10/*:1000)/*\n" + " Includes all layers, but in addition copies all datatypes of layer 10 to 1000 while keeping the datatype.\n" + " Note the square bracket which implies range expansion and how the brackets give a visual aid for the " + " grouping of the mapping parts.\n" "\n" - "* */*:*/* -10/*" - " Includes all layers, but drops layer 10, all datatypes." + "* [*/*] -(10/*)\n" + " Includes all layers, but drops all datatypes from layer 10 through 'unmapping'.\n" + " Please note, that this specification requires -" + m_prefix + "s (skip unknown layers) because otherwise the " + " unmapped layers are still created through the unknown layer fallback path.\n" ) << tl::arg (group + "--" + m_long_prefix + "layer-map-file=map", this, &GenericReaderOptions::set_layer_map_file, "Specifies the layer mapping for the input as a file", - "This option specifies the layer selection or mapping like + -" + m_prefix + ", but takes the mapping for the given file. " - "Each line in this file is read as one layer mapping expression. Empty lines or lines starting with a hash (#) character are " - "ignored." + "This option specifies the layer selection or mapping like -" + m_prefix + "m, but takes the mapping from the given file. " + "Each line in this file is read as one layer mapping expression. " + "Empty lines or lines starting with a hash (#) character or with double slashes (//) are ignored." ) ; } diff --git a/src/db/db/dbStreamLayers.cc b/src/db/db/dbStreamLayers.cc index ac2cc9819..52c14a679 100644 --- a/src/db/db/dbStreamLayers.cc +++ b/src/db/db/dbStreamLayers.cc @@ -635,6 +635,13 @@ LayerMap::mmap_expr (tl::Extractor &ex, unsigned int l) { try { + bool round_bracket = false, square_bracket = false; + if (ex.test ("(")) { + round_bracket = true; + } else if (ex.test ("[")) { + square_bracket = true; + } + do { tl::Extractor ex_saved = ex; @@ -678,7 +685,15 @@ LayerMap::mmap_expr (tl::Extractor &ex, unsigned int l) LayerProperties lp; lp.read (ex, true); m_target_layers[l] = lp; - } + } else if (square_bracket) { + m_target_layers[l] = LayerProperties (db::any_ld (), db::any_ld ()); + } + + if (round_bracket) { + ex.expect (")"); + } else if (square_bracket) { + ex.expect ("]"); + } } catch (...) { throw LayerSpecFormatException (ex.skip ()); @@ -790,6 +805,13 @@ LayerMap::unmap_expr (tl::Extractor &ex) { try { + bool round_bracket = false, square_bracket = false; + if (ex.test ("(")) { + round_bracket = true; + } else if (ex.test ("[")) { + square_bracket = true; + } + do { tl::Extractor ex_saved = ex; @@ -829,6 +851,12 @@ LayerMap::unmap_expr (tl::Extractor &ex) lp.read (ex, true); } + if (round_bracket) { + ex.expect (")"); + } else if (square_bracket) { + ex.expect ("]"); + } + } catch (...) { throw LayerSpecFormatException (ex.skip ()); } diff --git a/src/db/unit_tests/dbStreamLayerTests.cc b/src/db/unit_tests/dbStreamLayerTests.cc index f031de1f3..81d6ab21a 100644 --- a/src/db/unit_tests/dbStreamLayerTests.cc +++ b/src/db/unit_tests/dbStreamLayerTests.cc @@ -74,6 +74,25 @@ TEST(1) EXPECT_EQ (lm.first_logical (db::LDPair(10, 7)).first, false); lm.map_expr ("'XP';10/7-8 : XN", 13); EXPECT_EQ (lm.mapping_str (13), "10/7-8;XP : XN"); + + // brackets, "add_expr" + lm.clear (); + lm.add_expr ("[1-10/*]", 1); + EXPECT_EQ (lm.mapping_str (1), "1-10/* : */*"); + lm.add_expr ("-(5/*)", 0); + EXPECT_EQ (lm.mapping_str (1), "1-4/*;6-10/* : */*"); + + lm.clear (); + lm.add_expr ("[1/15]", 1); + lm.add_expr ("+(1/5:1001/5)", 1); + // NOTE: the target is taken from the second expression (the last one wins) + EXPECT_EQ (lm.mapping_str (1), "1/5,15 : 1001/5"); + + lm.clear (); + lm.add_expr ("+(1/5:1001/5)", 1); + lm.add_expr ("[1/15]", 1); + // NOTE: the target is taken from the second expression (the last one wins) + EXPECT_EQ (lm.mapping_str (1), "1/5,15 : */*"); } TEST(2) diff --git a/src/lay/lay/doc/about/layer_mapping.xml b/src/lay/lay/doc/about/layer_mapping.xml index 2f3ea4c82..4376bc1e5 100644 --- a/src/lay/lay/doc/about/layer_mapping.xml +++ b/src/lay/lay/doc/about/layer_mapping.xml @@ -201,5 +201,30 @@ when using unmapping and multi-mapping.

+

Brackets

+ +

+ Square brackets can be used to imply mapping to the original layer. When putting square brackets + around a mapping expression, the default target is "*/*", which means expansion to the original layer. + Hence the following statements are identical: +

+ +
[1-10/*]
+1-10/* : */*
+
+ +

+ When combining this with "+" for multi-mapping, put "+" in front of the bracket. +

+ +

+ You can put round brackets around mapping expressions for visual clarity, specifically when + combining them with "-" (unmapping) or "+" (multi-mapping): +

+ +
-(1-10/*)
++(17/0 : 1017/0)
+
+ From 2b61b481641dc9c5cf08d7f9fdc3b00797b03115 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 19 Dec 2020 18:25:53 +0100 Subject: [PATCH 29/44] WIP: multi-mapping for named layer readers, bugfix for GDS/OASIS --- src/db/db/dbCommonReader.cc | 29 ++---- src/db/db/dbNamedLayerReader.cc | 92 +++++++++++++++--- src/db/db/dbNamedLayerReader.h | 13 ++- .../streamers/cif/db_plugin/dbCIFReader.cc | 10 +- .../streamers/cif/unit_tests/dbCIFReader.cc | 12 +-- .../streamers/dxf/db_plugin/dbDXFReader.cc | 21 ++-- .../streamers/gds2/unit_tests/dbGDS2Reader.cc | 41 ++++++++ .../streamers/magic/db_plugin/dbMAGReader.cc | 10 +- testdata/gds/alm_au2.gds | Bin 11842 -> 8906 bytes 9 files changed, 155 insertions(+), 73 deletions(-) diff --git a/src/db/db/dbCommonReader.cc b/src/db/db/dbCommonReader.cc index 59d59f16f..0bf21814a 100644 --- a/src/db/db/dbCommonReader.cc +++ b/src/db/db/dbCommonReader.cc @@ -560,31 +560,14 @@ CommonReader::open_dl_uncached (db::Layout &layout, const LDPair &dl) } else { + for (std::set::const_iterator i = li.begin (); i != li.end (); ++i) { + m_layer_map_out.mmap (dl, *i, layout.get_properties (*i)); + } + std::map, unsigned int>::iterator mmp = m_multi_mapping_placeholders.find (li); if (mmp == m_multi_mapping_placeholders.end ()) { - - // multi-mapping: create a placeholder layer if required - - for (std::set::const_iterator i = li.begin (); i != li.end (); ++i) { - m_layer_map_out.mmap (dl, *i, layout.get_properties (*i)); - } - - for (std::set::const_iterator i = li.begin (); i != li.end (); ++i) { - std::set sl; - sl.insert (*i); - if (m_multi_mapping_placeholders.find (sl) == m_multi_mapping_placeholders.end ()) { - // a layer not used in a single-target context can be used as a placeholder layer (but only once) - m_multi_mapping_placeholders.insert (std::make_pair (sl, *i)); - mmp = m_multi_mapping_placeholders.insert (std::make_pair (li, *i)).first; - break; - } - } - - if (mmp == m_multi_mapping_placeholders.end ()) { - // create a placeholder layer for later - mmp = m_multi_mapping_placeholders.insert (std::make_pair (li, layout.insert_layer ())).first; - } - + // create a placeholder layer + mmp = m_multi_mapping_placeholders.insert (std::make_pair (li, layout.insert_layer ())).first; } return std::make_pair (true, mmp->second); diff --git a/src/db/db/dbNamedLayerReader.cc b/src/db/db/dbNamedLayerReader.cc index adff2797f..9716f4cab 100644 --- a/src/db/db/dbNamedLayerReader.cc +++ b/src/db/db/dbNamedLayerReader.cc @@ -122,21 +122,32 @@ extract_ld (const char *s, int &l, int &d, std::string &n) std::pair NamedLayerReader::open_layer (db::Layout &layout, const std::string &n) +{ + std::map >::const_iterator lc = m_layer_cache.find (n); + if (lc != m_layer_cache.end ()) { + return lc->second; + } else { + std::pair res = open_layer_uncached (layout, n); + m_layer_cache.insert (std::make_pair (n, res)); + return res; + } +} + +std::pair +NamedLayerReader::open_layer_uncached (db::Layout &layout, const std::string &n) { int l = -1, d = -1; std::string on; - std::pair ll (false, 0); - - ll = m_layer_map.first_logical (n, layout); - if (! ll.first && !m_keep_layer_names) { + std::set li = m_layer_map.logical (n, layout); + if (li.empty () && ! m_keep_layer_names) { if (extract_plain_layer (n.c_str (), l)) { db::LayerProperties lp; lp.layer = l; lp.datatype = 0; - ll = m_layer_map.first_logical (lp, layout); + li = m_layer_map.logical (lp, layout); } else if (extract_ld (n.c_str (), l, d, on)) { @@ -144,20 +155,33 @@ NamedLayerReader::open_layer (db::Layout &layout, const std::string &n) lp.layer = l; lp.datatype = d; lp.name = on; - ll = m_layer_map.first_logical (lp, layout); + li = m_layer_map.logical (lp, layout); } } - if (ll.first) { + if (! li.empty ()) { - // 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)); + for (std::set::const_iterator i = li.begin (); i != li.end (); ++i) { + m_layer_map_out.mmap (n, *i, layout.get_properties (*i)); } - return ll; + if (li.size () == 1) { + + return std::make_pair (true, *li.begin ()); + + } else { + + std::map, unsigned int>::iterator mmp = m_multi_mapping_placeholders.find (li); + if (mmp == m_multi_mapping_placeholders.end ()) { + // create a placeholder layer for later + mmp = m_multi_mapping_placeholders.insert (std::make_pair (li, layout.insert_layer ())).first; + } + + return std::make_pair (true, mmp->second); + + } } else if (! m_create_layers) { @@ -188,21 +212,61 @@ NamedLayerReader::open_layer (db::Layout &layout, const std::string &n) void NamedLayerReader::map_layer (const std::string &name, unsigned int layer) { - m_layer_map.map (name, layer); + m_layer_map_out.map (name, layer); } void -NamedLayerReader::prepare_layers () +NamedLayerReader::prepare_layers (db::Layout &layout) { m_new_layers.clear (); m_next_layer_index = m_layer_map.next_index (); + + m_layer_map_out.clear (); + m_multi_mapping_placeholders.clear (); + m_layer_cache.clear (); + + m_layer_map.prepare (layout); + + // create a pseudo-multimapping for single targets + for (db::LayerMap::const_iterator_layers li = m_layer_map.begin (); li != m_layer_map.end (); ++li) { + for (db::LayerMap::const_iterator_datatypes di = li->second.begin (); di != li->second.end (); ++di) { + if (di->second.size () == 1) { + m_multi_mapping_placeholders.insert (std::make_pair (di->second, *di->second.begin ())); + } + } + } } void NamedLayerReader::finish_layers (db::Layout &layout) { + // resolve layer multi-mapping + + for (std::map, unsigned int>::const_iterator i = m_multi_mapping_placeholders.begin (); i != m_multi_mapping_placeholders.end (); ++i) { + + if (i->first.size () > 1) { + + bool discard_layer = i->first.find (i->second) == i->first.end (); + + for (std::set::const_iterator l = i->first.begin (); l != i->first.end (); ++l) { + + // last one? this one will get a "move" + std::set::const_iterator ll = l; + if (discard_layer && ++ll == i->first.end ()) { + layout.move_layer (i->second, *l); + layout.delete_layer (i->second); + } else { + layout.copy_layer (i->second, *l); + } + + } + + } + + } + // assign layer numbers to new layers - if (! m_new_layers.empty () && !m_keep_layer_names) { + if (! m_new_layers.empty () && ! m_keep_layer_names) { std::set > used_ld; for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) { diff --git a/src/db/db/dbNamedLayerReader.h b/src/db/db/dbNamedLayerReader.h index d3b677111..53c68d9f4 100644 --- a/src/db/db/dbNamedLayerReader.h +++ b/src/db/db/dbNamedLayerReader.h @@ -54,6 +54,7 @@ public: */ NamedLayerReader (); +protected: /** * @brief Sets a value indicating whether to create new layers */ @@ -75,9 +76,9 @@ public: /** * @brief Gets the layer map */ - const LayerMap &layer_map () + const LayerMap &layer_map_out () { - return m_layer_map; + return m_layer_map_out; } /** @@ -96,7 +97,6 @@ public: return m_keep_layer_names; } -protected: /** * @brief Opens a new layer * This method will create or locate a layer for a given name. @@ -121,7 +121,7 @@ protected: * @brief Prepares reading * This method must be called before the reading is done. */ - void prepare_layers (); + void prepare_layers (db::Layout &layout); private: bool m_create_layers; @@ -129,6 +129,11 @@ private: LayerMap m_layer_map; unsigned int m_next_layer_index; std::map m_new_layers; + db::LayerMap m_layer_map_out; + std::map > m_layer_cache; + std::map, unsigned int> m_multi_mapping_placeholders; + + std::pair open_layer_uncached (db::Layout &layout, const std::string &name); }; } diff --git a/src/plugins/streamers/cif/db_plugin/dbCIFReader.cc b/src/plugins/streamers/cif/db_plugin/dbCIFReader.cc index 2f0f4f28d..057ff47f3 100644 --- a/src/plugins/streamers/cif/db_plugin/dbCIFReader.cc +++ b/src/plugins/streamers/cif/db_plugin/dbCIFReader.cc @@ -59,22 +59,20 @@ CIFReader::~CIFReader () const LayerMap & CIFReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) { - prepare_layers (); - const db::CIFReaderOptions &specific_options = options.get_options (); m_wire_mode = specific_options.wire_mode; m_dbu = specific_options.dbu; - db::LayerMap lm = specific_options.layer_map; - lm.prepare (layout); - set_layer_map (lm); + set_layer_map (specific_options.layer_map); set_create_layers (specific_options.create_other_layers); set_keep_layer_names (specific_options.keep_layer_names); + prepare_layers (layout); + do_read (layout); finish_layers (layout); - return layer_map (); + return layer_map_out (); } const LayerMap & diff --git a/src/plugins/streamers/cif/unit_tests/dbCIFReader.cc b/src/plugins/streamers/cif/unit_tests/dbCIFReader.cc index 7b74f0846..2d41920e8 100644 --- a/src/plugins/streamers/cif/unit_tests/dbCIFReader.cc +++ b/src/plugins/streamers/cif/unit_tests/dbCIFReader.cc @@ -39,13 +39,8 @@ static void run_test (tl::TestBase *_this, const std::string &base, const char * unsigned int ln = 0; tl::Extractor ex (map); while (! ex.at_end ()) { - std::string n; - int l; - ex.read_word_or_quoted (n); - ex.test (":"); - ex.read (l); + lm.add_expr (ex, ln++); ex.test (","); - lm.map (n, ln++, db::LayerProperties (l, 0)); } opt->layer_map = lm; opt->create_other_layers = true; @@ -173,6 +168,11 @@ TEST(3b) run_test (_this, tl::testsrc_private (), "t3.cif.gz", "t3b_au.gds.gz", "CAA:43,CCA:48,CCP:47,CMF:49,CMS:51,CPG:46,CSN:45,CSP:44,CVA:50,CWN:42,XP:26", 0.00012); } +TEST(3c) +{ + run_test (_this, tl::testsrc_private (), "t3.cif.gz", "t3c_au.gds.gz", "(CPG:1/0) +(CPG:1000/0) (CCP:1/0) (CMF:2/0) +(CMF:1000/0) (CVA:3/0)", 0.00012); +} + TEST(4) { run_test (_this, tl::testsrc_private (), "t4.cif.gz", "t4_au.gds.gz"); diff --git a/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc b/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc index 5517001d8..2335d238d 100644 --- a/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc +++ b/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc @@ -318,9 +318,7 @@ DXFReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) m_stream.reset (); m_initial = true; m_line_number = 0; - db::LayerMap lm = specific_options.layer_map; - lm.prepare (layout); - set_layer_map (lm); + set_layer_map (specific_options.layer_map); set_create_layers (specific_options.create_other_layers); set_keep_layer_names (specific_options.keep_layer_names); @@ -330,7 +328,7 @@ DXFReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) do_read (layout, top); cleanup (layout, top); - return layer_map (); + return layer_map_out (); } const LayerMap & @@ -379,29 +377,24 @@ DXFReader::open_layer (db::Layout &layout, const std::string &n) void DXFReader::do_read (db::Layout &layout, db::cell_index_type top) { + prepare_layers (layout); + // create the zero layer - this is not mapped to GDS but can be specified in the layer mapping as // a layer named "0". - std::pair ll = layer_map ().first_logical (zero_layer_name, layout); + std::pair ll = open_layer (layout, zero_layer_name); 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, layer_map ().mapping (ll.second)); - } - + // layer exists m_zero_layer = ll.second; } else { // or explicitly create the layer: - m_zero_layer = layer_map ().next_index (); - layout.insert_layer (m_zero_layer, db::LayerProperties (0, 0, zero_layer_name)); + m_zero_layer = layout.insert_layer (db::LayerProperties (0, 0, zero_layer_name)); map_layer (zero_layer_name, m_zero_layer); } - prepare_layers (); - // Read sections int g; diff --git a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc b/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc index d045b10d3..6a70c0821 100644 --- a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc +++ b/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc @@ -476,6 +476,47 @@ TEST(3_MultiMapping) db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); } +TEST(3_MultiMapping2) +{ + db::Manager m (false); + db::Layout layout (&m); + + db::LoadLayoutOptions options; + db::LayerMap lm, lm_read; + + unsigned int n = 0; + lm.add_expr ("(1/0:1/0)", n++); + lm.add_expr ("+(1/0:1000/0)", n++); + lm.add_expr ("(4/0:1/0)", n++); + lm.add_expr ("(2/0:2/0)", n++); + lm.add_expr ("+(2/0:1000/0)", n++); + lm.add_expr ("(3/0:3/0)", n++); + options.get_options ().layer_map = lm; + + { + tl::InputStream file (tl::testsrc () + "/testdata/gds/t10.gds"); + db::Reader reader (file); + lm_read = reader.read (layout, options); + } + + EXPECT_EQ (lm_read.to_string_file_format (), + "+1/0;4/0 : 1/0\n" + "+1-2/0 : 1000/0\n" + "+2/0 : 2/0\n" + "3/0 : 3/0\n" + "6/0 : 6/0\n" + "8/0 : 8/0\n" + "5/0 : 5/0\n" + "7/0 : 7/0\n" + "3/1 : 3/1\n" + "6/1 : 6/1\n" + "8/1 : 8/1\n" + ); + + std::string fn_au (tl::testsrc () + "/testdata/gds/alm_au3.gds"); + db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); +} + TEST(4_CollectModeRename) { db::Manager m (false); diff --git a/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc b/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc index f60be213e..b19aa1c78 100644 --- a/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc +++ b/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc @@ -72,8 +72,6 @@ MAGReader::read (db::Layout &layout) const LayerMap & MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) { - prepare_layers (); - mp_klayout_tech = 0; std::string klayout_tech_name = layout.meta_info_value ("technology"); if (! klayout_tech_name.empty () && db::Technologies::instance ()->has_technology (klayout_tech_name)) { @@ -87,9 +85,7 @@ MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) m_merge = specific_options.merge; mp_current_stream = 0; - db::LayerMap lm = specific_options.layer_map; - lm.prepare (layout); - set_layer_map (lm); + set_layer_map (specific_options.layer_map); set_create_layers (specific_options.create_other_layers); set_keep_layer_names (specific_options.keep_layer_names); @@ -110,6 +106,8 @@ MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) m_dbu_trans_inv = db::CplxTrans (m_dbu).inverted (); m_tech.clear (); + prepare_layers (layout); + { tl::SelfTimer timer (tl::verbosity () >= 11, "Reading MAGIC file tree"); @@ -129,7 +127,7 @@ MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) } finish_layers (layout); - return layer_map (); + return layer_map_out (); } void diff --git a/testdata/gds/alm_au2.gds b/testdata/gds/alm_au2.gds index 4492ec4d999fe06e34e1a83c544f52a0f82083d4..c1267e0bde4e5045028ad455cd2b09dc8552b411 100644 GIT binary patch delta 92 zcmX>UbIMhTfsKKQDS|0Kob6jBDoXxYA YadLqG$0osM=FPXo0=PGyRw?HM0QaL5Q~&?~ delta 122 zcmX@*dMHMTfsKKQDS|0L%S Date: Sat, 19 Dec 2020 19:42:40 +0100 Subject: [PATCH 30/44] WIP: LEF/DEF multi-mapping. --- .../lefdef/db_plugin/dbDEFImporter.cc | 86 +++---- .../lefdef/db_plugin/dbLEFDEFImporter.cc | 210 +++++++++++------- .../lefdef/db_plugin/dbLEFDEFImporter.h | 8 +- 3 files changed, 176 insertions(+), 128 deletions(-) diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc index 4dc1d25ac..3917c4c85 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc @@ -157,14 +157,14 @@ DEFImporter::read_diearea (db::Layout &layout, db::Cell &design, double scale) if (points.size () >= 2) { // create outline shape - std::pair dl = open_layer (layout, std::string (), Outline, 0); - if (dl.first) { + std::set dl = open_layer (layout, std::string (), Outline, 0); + for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { if (points.size () == 2) { - design.shapes (dl.second).insert (db::Box (points [0], points [1])); + design.shapes (*l).insert (db::Box (points [0], points [1])); } else { db::Polygon p; p.assign_hull (points.begin (), points.end ()); - design.shapes (dl.second).insert (p); + design.shapes (*l).insert (p); } } @@ -305,9 +305,9 @@ DEFImporter::read_blockages (db::Layout &layout, db::Cell &design, double scale) db::Polygon p; read_polygon (p, scale); - std::pair dl = open_layer (layout, layer, layer.empty () ? PlacementBlockage : Blockage, 0); - if (dl.first) { - design.shapes (dl.second).insert (p); + std::set dl = open_layer (layout, layer, layer.empty () ? PlacementBlockage : Blockage, 0); + for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { + design.shapes (*l).insert (p); } } else if (test ("RECT")) { @@ -315,9 +315,9 @@ DEFImporter::read_blockages (db::Layout &layout, db::Cell &design, double scale) db::Polygon p; read_rect (p, scale); - std::pair dl = open_layer (layout, layer, layer.empty () ? PlacementBlockage : Blockage, 0); - if (dl.first) { - design.shapes (dl.second).insert (p); + std::set dl = open_layer (layout, layer, layer.empty () ? PlacementBlockage : Blockage, 0); + for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { + design.shapes (*l).insert (p); } } else { @@ -554,17 +554,19 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C test (")"); - std::pair dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask); - if (dl.first) { + std::set dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask); + if (! dl.empty ()) { db::Point p (x, y); db::Box rect (db::Point (db::DPoint ((x + x1) * scale, (y + y1) * scale)), db::Point (db::DPoint ((x + x2) * scale, (y + y2) * scale))); - if (prop_id != 0) { - design.shapes (dl.second).insert (db::object_with_properties (rect, prop_id)); - } else { - design.shapes (dl.second).insert (rect); + for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { + if (prop_id != 0) { + design.shapes (*l).insert (db::object_with_properties (rect, prop_id)); + } else { + design.shapes (*l).insert (rect); + } } } @@ -615,9 +617,9 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C } if (pts.size () > 1) { - std::pair dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask); - if (dl.first) { - produce_routing_geometry (design, style, dl.second, prop_id, pts, ext, w); + std::set dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask); + for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { + produce_routing_geometry (design, style, *l, prop_id, pts, ext, w); } } @@ -803,12 +805,12 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool db::Polygon p; read_polygon (p, scale); - std::pair dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask); - if (dl.first) { + std::set dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask); + for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { if (prop_id != 0) { - design.shapes (dl.second).insert (db::object_with_properties (p, prop_id)); + design.shapes (*l).insert (db::object_with_properties (p, prop_id)); } else { - design.shapes (dl.second).insert (p); + design.shapes (*l).insert (p); } } @@ -821,12 +823,12 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool db::Polygon p; read_rect (p, scale); - std::pair dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask); - if (dl.first) { + std::set dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask); + for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { if (prop_id != 0) { - design.shapes (dl.second).insert (db::object_with_properties (p, prop_id)); + design.shapes (*l).insert (db::object_with_properties (p, prop_id)); } else { - design.shapes (dl.second).insert (p); + design.shapes (*l).insert (p); } } @@ -1191,8 +1193,8 @@ DEFImporter::read_pins (db::Layout &layout, db::Cell &design, double scale) // Produce geometry collected so far for (std::map, std::vector >::const_iterator g = geometry.begin (); g != geometry.end (); ++g) { - std::pair dl = open_layer (layout, g->first.first, Pins, g->first.second); - if (dl.first) { + std::set dl = open_layer (layout, g->first.first, Pins, g->first.second); + if (! dl.empty ()) { db::properties_id_type prop_id = 0; if (produce_pin_props ()) { @@ -1204,21 +1206,27 @@ DEFImporter::read_pins (db::Layout &layout, db::Cell &design, double scale) for (std::vector::const_iterator p = g->second.begin (); p != g->second.end (); ++p) { db::Polygon pt = p->transformed (trans); if (prop_id == 0) { - design.shapes (dl.second).insert (pt); + for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { + design.shapes (*l).insert (pt); + } } else { - design.shapes (dl.second).insert (db::PolygonWithProperties (pt, prop_id)); + for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { + design.shapes (*l).insert (db::PolygonWithProperties (pt, prop_id)); + } } } } dl = open_layer (layout, g->first.first, Label, 0); - if (dl.first) { + if (! dl.empty ()) { db::Box bbox; if (! g->second.empty ()) { bbox = g->second.back ().box ().transformed (trans); } - design.shapes (dl.second).insert (db::Text (label.c_str (), db::Trans (db::Vector (bbox.center ())))); + for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { + design.shapes (*l).insert (db::Text (label.c_str (), db::Trans (db::Vector (bbox.center ())))); + } } } @@ -1554,10 +1562,10 @@ DEFImporter::do_read (db::Layout &layout) } else { - std::pair dl = open_layer (layout, std::string (), Regions, 0); - if (dl.first) { + std::set dl = open_layer (layout, std::string (), Regions, 0); + for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { for (std::vector::const_iterator p = r->second.begin (); p != r->second.end (); ++p) { - group_cell->shapes (dl.second).insert (*p); + group_cell->shapes (*l).insert (*p); } } regions.erase (r); @@ -1597,12 +1605,12 @@ DEFImporter::do_read (db::Layout &layout) if (! regions.empty ()) { - std::pair dl = open_layer (layout, std::string (), Regions, 0); - if (dl.first) { + std::set dl = open_layer (layout, std::string (), Regions, 0); + for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { for (std::map >::const_iterator r = regions.begin (); r != regions.end (); ++r) { for (std::vector::const_iterator p = r->second.begin (); p != r->second.end (); ++p) { - others_cell->shapes (dl.second).insert (*p); + others_cell->shapes (*l).insert (*p); } } diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index f68700609..f8f6b0d4d 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -146,16 +146,16 @@ RuleBasedViaGenerator::create_cell (LEFDEFReaderState &reader, Layout &layout, d 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); + std::set dl; 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))); + for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { + cell.shapes (*l).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))); + for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { + cell.shapes (*l).insert (db::Polygon (via_box.enlarged (m_te).moved (m_bo))); } const char *p = m_pattern.c_str (); @@ -253,8 +253,8 @@ RuleBasedViaGenerator::create_cell (LEFDEFReaderState &reader, Layout &layout, d } dl = reader.open_layer (layout, m_cut_layer, ViaGeometry, cm); - if (dl.first) { - cell.shapes (dl.second).insert (db::Polygon (vb)); + for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { + cell.shapes (*l).insert (db::Polygon (vb)); } } @@ -322,9 +322,9 @@ GeometryBasedLayoutGenerator::create_cell (LEFDEFReaderState &reader, Layout &la unsigned int mshift = get_maskshift (g->first.first, ext_msl, masks); unsigned int mask = mask_for (g->first.first, g->first.second.second, mshift, nm); - std::pair dl = reader.open_layer (layout, g->first.first, g->first.second.first, mask); - if (dl.first) { - cell.shapes (dl.second).insert (g->second); + std::set dl = reader.open_layer (layout, g->first.first, g->first.second.first, mask); + for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { + cell.shapes (*l).insert (g->second); } } @@ -809,7 +809,9 @@ void LEFDEFReaderState::map_layer_explicit (const std::string &n, LayerPurpose purpose, const db::LayerProperties &lp, unsigned int layer, unsigned int mask) { tl_assert (m_has_explicit_layer_mapping); - m_layers [std::make_pair (n, std::make_pair (purpose, mask))] = std::make_pair (true, layer); + std::set ll; + ll.insert (layer); + m_layers [std::make_pair (n, std::make_pair (purpose, mask))] = ll; m_layer_map.map (lp, layer); } @@ -1040,13 +1042,13 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) } } -std::pair +std::set LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPurpose purpose, unsigned int mask) { - std::map >, std::pair >::const_iterator nl = m_layers.find (std::make_pair (n, std::make_pair (purpose, mask))); + std::map >, std::set >::const_iterator nl = m_layers.find (std::make_pair (n, std::make_pair (purpose, mask))); if (nl == m_layers.end ()) { - std::pair ll (false, 0); + std::set ll; if (n.empty () || ! m_has_explicit_layer_mapping) { ll = open_layer_uncached (layout, n, purpose, mask); @@ -1134,8 +1136,7 @@ static std::string purpose_to_name (LayerPurpose purpose) * 4/17 4/17 : 4/11 OUTLINE 4/11 */ -std::pair -LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n, LayerPurpose purpose, unsigned int mask) +std::set LEFDEFReaderState::open_layer_uncached(db::Layout &layout, const std::string &n, LayerPurpose purpose, unsigned int mask) { if (n.empty ()) { @@ -1154,7 +1155,7 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n } if (! produce) { - return std::make_pair (false, 0); + return std::set (); } db::LayerProperties lp; @@ -1180,35 +1181,55 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n } // employ the layer map to find the target layer - std::pair ll = m_layer_map.first_logical (lp, layout); + std::set ll = m_layer_map.logical (lp, layout); + if (ll.empty () && ! m_create_layers) { + return std::set (); + } - if (ll.first) { + std::set res; + + // map the layers to targets from the layout + // (NOTE: the other readers will do this in advance, but LEF/DEF is too dynamic) + + bool at_least_once = true; + for (std::set::const_iterator l = ll.begin (); l != ll.end () || at_least_once; ++l) { + + at_least_once = false; // If the layer map provides a target, use that one for the layer - const db::LayerProperties *lpp = m_layer_map.target (ll.second); + db::LayerProperties lp_new = lp; + const db::LayerProperties *lpp = (l == ll.end () ? 0 : m_layer_map.target (*l)); if (lpp) { if (! lpp->name.empty ()) { - lp.name = lpp->name; + lp_new.name = lpp->name; } if (lpp->datatype >= 0) { - lp.datatype = lpp->datatype; + lp_new.datatype = lpp->datatype; } if (lpp->layer >= 0) { - lp.layer = lpp->layer; + lp_new.layer = lpp->layer; } } - } else if (! m_create_layers) { - return std::make_pair (false, 0); - } - - for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) { - if ((*l).second->log_equal (lp)) { - return std::make_pair (true, (*l).first); + bool found = false; + for (db::Layout::layer_iterator i = layout.begin_layers (); i != layout.end_layers () && ! found; ++i) { + if ((*i).second->log_equal (lp_new)) { + found = true; + res.insert ((*i).first); + } } + + if (! found) { + res.insert (layout.insert_layer (lp_new)); + } + + if (l == ll.end ()) { + break; + } + } - return std::make_pair (true, layout.insert_layer (lp)); + return res; } else { @@ -1242,7 +1263,7 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n break; } if (! produce) { - return std::make_pair (false, 0); + return std::set (); } } @@ -1300,48 +1321,63 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n // Route the layer through the layer map, first the decorated name and if there is no mapping, the // undecorated one. - std::pair ll = m_layer_map.first_logical (name, layout); + std::set ll = m_layer_map.logical (name, layout); bool generic_match = false; - if (! ll.first) { - ll = m_layer_map.first_logical (n, layout); + if (ll.empty ()) { + ll = m_layer_map.logical (n, layout); generic_match = true; } else if (n == name) { // no suffix defined in tech component -> treat as generic match and combine datatypes generic_match = true; } - if (ll.first) { + if (ll.empty () && ! m_create_layers) { + return std::set (); + } + + std::set res; + + bool at_least_once = true; + for (std::set::const_iterator l = ll.begin (); l != ll.end () || at_least_once; ++l) { + + at_least_once = false; // If the layer map provides a target, use that one for the layer - // Datatypes from the target and the tech component's x_datatype specification are additive - const db::LayerProperties *lpp = m_layer_map.target (ll.second); + db::LayerProperties lp_new = lp; + const db::LayerProperties *lpp = (l == ll.end () ? 0 : m_layer_map.target (*l)); if (lpp) { - lp = *lpp; - if (lp.datatype < 0) { - lp.datatype = dt; + lp_new = *lpp; + if (lp_new.datatype < 0) { + lp_new.datatype = dt; } else if (generic_match) { - lp.datatype += dt; + lp_new.datatype += dt; } - if (lp.name.empty ()) { - lp.name = name; + if (lp_new.name.empty ()) { + lp_new.name = name; } else if (generic_match) { - lp.name += name_suffix; + lp_new.name += name_suffix; } } - } else if (! m_create_layers) { - return std::make_pair (false, 0); - } - - if (lp.layer >= 0 && lp.datatype >= 0) { - for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) { - if ((*l).second->log_equal (lp)) { - return std::make_pair (true, (*l).first); + bool found = false; + for (db::Layout::layer_iterator i = layout.begin_layers (); i != layout.end_layers () && ! found; ++i) { + if ((*i).second->log_equal (lp_new)) { + found = true; + res.insert ((*i).first); } } + + if (! found) { + res.insert (layout.insert_layer (lp_new)); + } + + if (l == ll.end ()) { + break; + } + } - return std::make_pair (true, layout.insert_layer (lp)); + return res; } } @@ -1368,42 +1404,14 @@ LEFDEFReaderState::finish (db::Layout &layout) db::LayerMap lm; - for (std::map >, std::pair >::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) { + for (std::map >, std::set >::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) { - if (! l->second.first) { + if (l->second.empty ()) { continue; } std::string ps = purpose_to_name (l->first.second.first); - unsigned int layer_index = l->second.second; - db::LayerProperties lp = layout.get_properties (layer_index); - - if (lp.layer < 0) { - - std::map::const_iterator n4n = number_for_name.end (); - if (! l->first.first.empty ()) { - n4n = number_for_name.find (l->first.first); - } - - if (n4n == number_for_name.end ()) { - do { - ++lnum; - } while (used_numbers.find (lnum) != used_numbers.end ()); - number_for_name.insert (std::make_pair (l->first.first, lnum)); - lp.layer = lnum; - } else { - lp.layer = n4n->second; - } - - } - - if (lp.datatype < 0) { - lp.datatype = 0; - } - - layout.set_properties (layer_index, lp); - std::string n = l->first.first; if (! n.empty ()) { n += "."; @@ -1415,7 +1423,39 @@ LEFDEFReaderState::finish (db::Layout &layout) n += tl::to_string (l->first.second.second); } - lm.map (db::LayerProperties (n), l->second.second, lp); + for (std::set::const_iterator li = l->second.begin (); li != l->second.end (); ++li) { + + unsigned int layer_index = *li; + db::LayerProperties lp = layout.get_properties (layer_index); + + if (lp.layer < 0) { + + std::map::const_iterator n4n = number_for_name.end (); + if (! l->first.first.empty ()) { + n4n = number_for_name.find (l->first.first); + } + + if (n4n == number_for_name.end ()) { + do { + ++lnum; + } while (used_numbers.find (lnum) != used_numbers.end ()); + number_for_name.insert (std::make_pair (l->first.first, lnum)); + lp.layer = lnum; + } else { + lp.layer = n4n->second; + } + + } + + if (lp.datatype < 0) { + lp.datatype = 0; + } + + layout.set_properties (layer_index, lp); + + lm.mmap (db::LayerProperties (n), layer_index, lp); + + } } diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h index 078361d33..f123490be 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h @@ -1054,7 +1054,7 @@ public: /** * @brief Create a new layer or return the index of the given layer */ - std::pair open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask); + std::set open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask); /** * @brief Registers a layer (assign a new default layer number) @@ -1188,7 +1188,7 @@ private: LEFDEFReaderState (const LEFDEFReaderState &); LEFDEFReaderState &operator= (const LEFDEFReaderState &); - std::map >, std::pair > m_layers; + std::map >, std::set > m_layers; db::LayerMap m_layer_map; bool m_create_layers; bool m_has_explicit_layer_mapping; @@ -1201,7 +1201,7 @@ private: std::map m_macro_generators; std::map m_foreign_cells; - std::pair open_layer_uncached (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask); + std::set 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); db::cell_index_type foreign_cell(Layout &layout, const std::string &name); }; @@ -1364,7 +1364,7 @@ protected: /** * @brief Create a new layer or return the index of the given layer */ - std::pair open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask) + std::set open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask) { return mp_reader_state->open_layer (layout, name, purpose, mask); } From d4b5dab0dbda53b4856682a1765271213e2161e5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 19 Dec 2020 20:35:58 +0100 Subject: [PATCH 31/44] WIP: bugfix. --- .../streamers/lefdef/db_plugin/dbLEFDEFImporter.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index f8f6b0d4d..b4fc56598 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -1360,10 +1360,12 @@ std::set LEFDEFReaderState::open_layer_uncached(db::Layout &layout } bool found = false; - for (db::Layout::layer_iterator i = layout.begin_layers (); i != layout.end_layers () && ! found; ++i) { - if ((*i).second->log_equal (lp_new)) { - found = true; - res.insert ((*i).first); + if (lp_new.layer >= 0 && lp_new.datatype >= 0) { + for (db::Layout::layer_iterator i = layout.begin_layers (); i != layout.end_layers () && ! found; ++i) { + if ((*i).second->log_equal (lp_new)) { + found = true; + res.insert ((*i).first); + } } } From 9688da9ffd2c97b10e006a471e766dc290db42a8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 19 Dec 2020 21:28:22 +0100 Subject: [PATCH 32/44] WIP: test for multimapping in LEF/DEF --- src/db/db/dbCommonReader.cc | 28 ------------------ src/db/db/dbCommonReader.h | 3 -- src/db/db/dbReader.cc | 27 +++++++++++++++++ src/db/db/dbReader.h | 8 +++++ .../lefdef/db_plugin/dbLEFDEFImporter.cc | 14 +++++---- .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 18 +++++++++++ testdata/lefdef/multimap/.test.def.swp | Bin 0 -> 12288 bytes testdata/lefdef/multimap/au.oas.gz | Bin 0 -> 598 bytes testdata/lefdef/multimap/test.def | 28 ++++++++++++++++++ 9 files changed, 90 insertions(+), 36 deletions(-) create mode 100644 testdata/lefdef/multimap/.test.def.swp create mode 100644 testdata/lefdef/multimap/au.oas.gz create mode 100644 testdata/lefdef/multimap/test.def diff --git a/src/db/db/dbCommonReader.cc b/src/db/db/dbCommonReader.cc index 0bf21814a..a64de5f72 100644 --- a/src/db/db/dbCommonReader.cc +++ b/src/db/db/dbCommonReader.cc @@ -32,34 +32,6 @@ namespace db // --------------------------------------------------------------- // Common reader implementation -DB_PUBLIC void -join_layer_names (std::string &s, const std::string &n) -{ - if (s == n) { - return; - } - - if (! s.empty ()) { - - size_t i = s.find (n); - if (i != std::string::npos && (i == 0 || s.c_str ()[i - 1] == ';')) { - char after = s.c_str ()[i + n.size ()]; - if (after == 0 || after == ';') { - // n is already contained in s - return; - } - } - - s += ";"; - - } - - s += n; -} - -// --------------------------------------------------------------- -// Common reader implementation - static const size_t null_id = std::numeric_limits::max (); CommonReader::CommonReader () diff --git a/src/db/db/dbCommonReader.h b/src/db/db/dbCommonReader.h index cf53f1895..81d361672 100644 --- a/src/db/db/dbCommonReader.h +++ b/src/db/db/dbCommonReader.h @@ -31,9 +31,6 @@ namespace db { -DB_PUBLIC void -join_layer_names (std::string &s, const std::string &n); - /** * @brief The CellConflictResolution enum */ diff --git a/src/db/db/dbReader.cc b/src/db/db/dbReader.cc index fc6f13adb..2ac8add6b 100644 --- a/src/db/db/dbReader.cc +++ b/src/db/db/dbReader.cc @@ -30,6 +30,33 @@ namespace db { +// --------------------------------------------------------------- + +DB_PUBLIC void +join_layer_names (std::string &s, const std::string &n) +{ + if (s == n) { + return; + } + + if (! s.empty ()) { + + size_t i = s.find (n); + if (i != std::string::npos && (i == 0 || s.c_str ()[i - 1] == ';')) { + char after = s.c_str ()[i + n.size ()]; + if (after == 0 || after == ';') { + // n is already contained in s + return; + } + } + + s += ";"; + + } + + s += n; +} + // --------------------------------------------------------------- // ReaderBase implementation diff --git a/src/db/db/dbReader.h b/src/db/db/dbReader.h index bab39df87..65c2ebf0d 100644 --- a/src/db/db/dbReader.h +++ b/src/db/db/dbReader.h @@ -54,6 +54,14 @@ public: { } }; +/** + * @brief Joins layer names into a single, combined layer + * @param s The first layer name and output + * @param n The name to add + */ +DB_PUBLIC void +join_layer_names (std::string &s, const std::string &n); + /** * @brief The generic reader base class */ diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index b4fc56598..e3a90c6ee 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -1359,18 +1359,22 @@ std::set LEFDEFReaderState::open_layer_uncached(db::Layout &layout } } - bool found = false; + int lfound = -1; if (lp_new.layer >= 0 && lp_new.datatype >= 0) { - for (db::Layout::layer_iterator i = layout.begin_layers (); i != layout.end_layers () && ! found; ++i) { + for (db::Layout::layer_iterator i = layout.begin_layers (); i != layout.end_layers () && lfound < 0; ++i) { if ((*i).second->log_equal (lp_new)) { - found = true; - res.insert ((*i).first); + lfound = int ((*i).first); } } } - if (! found) { + if (lfound < 0) { res.insert (layout.insert_layer (lp_new)); + } else { + res.insert ((unsigned int) lfound); + db::LayerProperties lp_org = layout.get_properties ((unsigned int) lfound); + join_layer_names (lp_org.name, name); + layout.set_properties ((unsigned int) lfound, lp_org); } if (l == ll.end ()) { diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index c46067119..eba689a5c 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -724,6 +724,24 @@ TEST(118_density) run_test (_this, "density", "read:in.lef", "au.oas.gz", default_options (), false); } +TEST(119_multimapping) +{ + db::LEFDEFReaderOptions options = default_options (); + db::LayerMap lm = db::LayerMap::from_string_file_format ("(M1:1/0)\n(M2:3/0)\n+(M1:100/0)\n+(M2:100/0)\n(VIA1:2/0)"); + options.set_layer_map (lm); + + db::LayerMap lm_read = run_test (_this, "multimap", "def:test.def", "au.oas.gz", options, false); + EXPECT_EQ (lm_read.to_string (), + "layer_map(" + "'OUTLINE : OUTLINE (4/0)';" + "'+M1.VIA : M1 (1/0)';" + "'+M1.VIA;M2.VIA : \\'M1;M2\\' (100/0)';" + "'+M2.VIA : M2 (3/0)';" + "'VIA1.VIA : VIA1 (2/0)'" + ")" + ) +} + TEST(200_lefdef_plugin) { db::Layout ly; diff --git a/testdata/lefdef/multimap/.test.def.swp b/testdata/lefdef/multimap/.test.def.swp new file mode 100644 index 0000000000000000000000000000000000000000..736b58e7c8210923ca3ae77b5515507a33796e9a GIT binary patch literal 12288 zcmeI2F>ljA6vwZK31~sEFfcrVgc?<;?W83|ncUd4CpC6zJE>YgmXo+m)TA|uJ9GfP z2ooQJi3N#)g$X7Q3p<|x{^ulWg{soE=$-VpefR$N-n(DCL`h3;${MXK8Uo{%5O=q} zg&$_0&HTJNCk9cPc6-rCh0Yt@q|lF&^e{QkgxITTLT$ev9UmU0+8`RG@lZ?SQQC>p zNbASDop@Ip9QD)QAWE{pB3Ay9n8Qqf30#1{tSA)?T^S$b?$e#yjSK8y3lm@hOn?b6 z0Vco%m;e)C0{;tvG?@{vahNNU1Kpe4Xa2fRrhH=pOn?b60Vco%m;e)C0!)AjFaajO z1TGwU55np8MWR*FQEfS)owvNm;e)C0!)AjFaajO1egF5U;>w%fbCdh*}hzJ zgnIO=rc+%vrQ?eQ@&mU{t^Q$q-_S;BG)%)`Jc`q>gZm!&7FEPq(Q$a5q@z4}nkTmr z(B=;1r}kuT5VoQCKxN9ZooQd7CmXIANM|kU#`J<|JFU?$+p5zhLUlxBAYF&rS+}A< z?QYaNFv7|Ft@|1>268S#xa(3 z3@SasB~MLh8e!*XFgPa5B?F5(t!|S6YIdEiJ_ha6;2&Ms9v(hENPpb zZ6YIz!>q2;0%}3e7+|F$8jcKnvZNp2jj^dFtDfs1i!xQj_?5z^&`U!6_Z};&4S!Vz ic(**Ca!;S+;R4CduxWH!_@V0gjKfDB|rrGn#q9V6m{J>C6WUE)3cLR{TlgW|(I zT|zuKSY&u*Akv|J*c8Z!as|hS_y@#0yZZR>a3p7B7Q~n27ce7Od|{rB@jz@CpHiBe zTglDt9~$E0>F3JK!py*f%;9G8HDqQ43PNdaR$oJFUnAxepb&xyRAt1>3|0lExmiGF zGcy52;4EH7QENs9My3rc3)m(y&twv{Okretz`TL;Cd)@gQ43@VW+VwqCPty7ytuy%?AJg literal 0 HcmV?d00001 diff --git a/testdata/lefdef/multimap/test.def b/testdata/lefdef/multimap/test.def new file mode 100644 index 000000000..6381b8523 --- /dev/null +++ b/testdata/lefdef/multimap/test.def @@ -0,0 +1,28 @@ + +VERSION 5.8 ; +DIVIDERCHAR "/" ; +BUSBITCHARS "[]" ; +DESIGN chip_top ; +UNITS DISTANCE MICRONS 1000 ; +DIEAREA ( 30000 3000 ) ( 10000000 4000 ) ; +VIAS 1 ; + - VIA1_dummy + + RECT M1 ( -200 -140 ) ( 200 140 ) + + RECT VIA1 ( -100 -100 ) ( 100 100 ) + + RECT M2 ( -300 -120 ) ( 300 120 ) ; +END VIAS +SPECIALNETS 1 ; +- dummy + + ROUTED M1 150 + SHAPE IOWIRE ( 40000 3600 ) VIA1_dummy DO 16000 BY 1 STEP 700 0 +; +END SPECIALNETS +SCANCHAINS 77 ; +- chain1_clock1 ++ PARTITION clock1 ++ START block1/bsr_reg_0 Q ++ FLOATING +block1/pgm_cgm_en_reg_reg ( IN SD ) ( OUT QZ ) +block1/start_reset_dd_reg ( IN SD ) ( OUT QZ ) ++ STOP block1/start_reset_d_reg SD ; +END SCANCHAINS +END DESIGN From 953367f3c12c3dc82f0b155d409d044380cebfee Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 19 Dec 2020 22:11:23 +0100 Subject: [PATCH 33/44] Multi-mapping for layer map files for LEF/DEF reader --- .../lefdef/db_plugin/dbLEFDEFImporter.cc | 74 +++++++++++------- .../lefdef/db_plugin/dbLEFDEFImporter.h | 1 - .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 18 ++++- testdata/lefdef/multimap/.test.def.swp | Bin 12288 -> 0 bytes 4 files changed, 58 insertions(+), 35 deletions(-) delete mode 100644 testdata/lefdef/multimap/.test.def.swp diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index e3a90c6ee..0b3856917 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -805,16 +805,6 @@ LEFDEFReaderState::register_layer (const std::string &ln) ++m_laynum; } -void -LEFDEFReaderState::map_layer_explicit (const std::string &n, LayerPurpose purpose, const db::LayerProperties &lp, unsigned int layer, unsigned int mask) -{ - tl_assert (m_has_explicit_layer_mapping); - std::set ll; - ll.insert (layer); - m_layers [std::make_pair (n, std::make_pair (purpose, mask))] = ll; - m_layer_map.map (lp, layer); -} - static bool try_read_layers (tl::Extractor &ex, std::vector &layers) { int l = 0; @@ -861,7 +851,7 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) purpose_translation_rev.insert (std::make_pair (i->second, i->first)); } - std::map >, db::LayerProperties> layer_map; + std::map >, std::vector > layer_map; while (! ts.at_end ()) { @@ -875,31 +865,37 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) } else { std::string w1, w2; - int layer = 0, datatype = 0; - std::vector layers; + std::vector layers, datatypes; size_t max_purpose_str = 10; - if (! ex.try_read_word (w1) || ! ex.try_read_word (w2, "._$,/:") || ! try_read_layers (ex, layers) || ! ex.try_read (datatype)) { + if (! ex.try_read_word (w1) || ! ex.try_read_word (w2, "._$,/:") || ! try_read_layers (ex, layers) || ! try_read_layers (ex, datatypes)) { tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d not understood - skipped")), path, ts.line_number ()); continue; } - if (layers.size () > 1) { - tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: mapping to multiple layers not supported currently - first one taken")), path, ts.line_number ()); - } - layer = layers.front (); - if (w1 == "DIEAREA") { - layer_map [std::make_pair (std::string (), std::make_pair (Outline, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "OUTLINE"); + for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { + for (std::vector::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) { + layer_map [std::make_pair (std::string (), std::make_pair (Outline, (unsigned int) 0))].push_back (db::LayerProperties (*l, *d, "OUTLINE")); + } + } } else if (w1 == "REGIONS") { - layer_map [std::make_pair (std::string (), std::make_pair (Regions, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "REGIONS"); + for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { + for (std::vector::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) { + layer_map [std::make_pair (std::string (), std::make_pair (Regions, (unsigned int) 0))].push_back (db::LayerProperties (*l, *d, "REGIONS")); + } + } } else if (w1 == "BLOCKAGE") { - layer_map [std::make_pair (std::string (), std::make_pair (PlacementBlockage, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "PLACEMENT_BLK"); + for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { + for (std::vector::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) { + layer_map [std::make_pair (std::string (), std::make_pair (PlacementBlockage, (unsigned int) 0))].push_back (db::LayerProperties (*l, *d, "PLACEMENT_BLK")); + } + } } else if (w1 == "NAME") { @@ -909,19 +905,23 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) // "(M1/LABELS): M1.LABEL" // "(M2/LABELS): M2.LABEL" - std::vector layers; + std::vector layer_names; std::vector purposes = tl::split (w2, ","); for (std::vector::const_iterator p = purposes.begin (); p != purposes.end (); ++p) { if (*p == "DIEAREA" || *p == "ALL" || *p == "COMP") { tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: NAME record ignored for entity: %s")), path, ts.line_number (), *p); } else { - layers.push_back (tl::split (*p, "/").front ()); + layer_names.push_back (tl::split (*p, "/").front ()); } } - 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, std::make_pair (Label, (unsigned int) 0))] = db::LayerProperties (layer, datatype, final_name); + std::string final_name = tl::join (layer_names, "/") + ".LABEL"; + for (std::vector::const_iterator ln = layer_names.begin (); ln != layer_names.end (); ++ln) { + for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { + for (std::vector::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) { + layer_map [std::make_pair (*ln, std::make_pair (Label, (unsigned int) 0))].push_back (db::LayerProperties (*l, *d, final_name)); + } + } } } else if (w1 == "COMP") { @@ -1027,7 +1027,11 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) std::string final_name = w1 + "." + purpose_str; 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); + for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { + for (std::vector::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) { + layer_map [std::make_pair (w1, *p)].push_back (db::LayerProperties (*l, *d, final_name)); + } + } } } @@ -1036,9 +1040,19 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) } + // build an explicit layer mapping now. + + tl_assert (m_has_explicit_layer_mapping); + m_layers.clear (); + m_layer_map.clear (); + 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.first, i->second, lm.map_layer (i->second).second, i->first.second.second); + for (std::map >, std::vector >::const_iterator i = layer_map.begin (); i != layer_map.end (); ++i) { + for (std::vector::const_iterator j = i->second.begin (); j != i->second.end (); ++j) { + unsigned int layer = lm.map_layer (*j).second; + m_layers [i->first].insert (layer); + m_layer_map.mmap (*j, layer); + } } } diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h index f123490be..85bd52395 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h @@ -1202,7 +1202,6 @@ private: std::map m_foreign_cells; std::set 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); db::cell_index_type foreign_cell(Layout &layout, const std::string &name); }; diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index eba689a5c..f896ab0e5 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -710,10 +710,20 @@ TEST(117_mapfile_all) EXPECT_EQ (lm_read.to_string (), "layer_map(" "'OUTLINE : OUTLINE (1/0)';" - "'M1.BLK;M1.LEFOBS;M1.LEFPIN;M1.NET;M1.PIN;M1.SPNET;M1.VIA : \\'M1.NET/PIN/...\\' (22/2)';" - "'\\'M1.NET:1\\' : \\'M1.NET:1\\' (7/0)';" - "'\\'M1.PIN:1\\';\\'M1.SPNET:1\\';\\'M1.VIA:1\\' : \\'M1.NET:1/...\\' (6/0)';" - "'M1.LABEL : M1.LABEL (28/1)';" + "'+M1.LEFOBS;M1.LEFPIN;M1.NET;M1.PIN;M1.SPNET;M1.VIA : \\'M1.NET/PIN/...\\' (1/5)';" + "'+M1.NET;M1.SPNET : \\'M1.NET/SPNET\\' (16/0)';" + "'+M1.NET : M1.NET (18/0)';" + "'+M1.BLK;M1.LEFOBS;M1.LEFPIN;M1.NET;M1.PIN;M1.SPNET;M1.VIA : \\'M1.NET/PIN/...\\' (22/2)';" + "'+\\'M1.NET:1\\';\\'M1.PIN:1\\';\\'M1.SPNET:1\\';\\'M1.VIA:1\\' : \\'M1.NET:1/...\\' (6/0)';" + "'+\\'M1.NET:1\\' : \\'M1.NET:1\\' (7/0)';" + "'+M1.PIN : M1.PIN (3/0)';" + "'+M1.PIN : M1.PIN (4/0)';" + "'+M1.VIA : M1.VIA (20/0)';" + "'+M1.VIA : M1.VIA (21/0)';" + "'+M1.LABEL : M1.LABEL (26/0)';" + "'+M1.LABEL : M1.LABEL (27/0)';" + "'+M1.LABEL : M1.LABEL (28/1)';" + "'+M1.BLK : M1.BLOCKAGE (13/0)';" "'M1_TEXT.LABEL : M1_TEXT.LABEL (29/0)'" ")" ) diff --git a/testdata/lefdef/multimap/.test.def.swp b/testdata/lefdef/multimap/.test.def.swp deleted file mode 100644 index 736b58e7c8210923ca3ae77b5515507a33796e9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2F>ljA6vwZK31~sEFfcrVgc?<;?W83|ncUd4CpC6zJE>YgmXo+m)TA|uJ9GfP z2ooQJi3N#)g$X7Q3p<|x{^ulWg{soE=$-VpefR$N-n(DCL`h3;${MXK8Uo{%5O=q} zg&$_0&HTJNCk9cPc6-rCh0Yt@q|lF&^e{QkgxITTLT$ev9UmU0+8`RG@lZ?SQQC>p zNbASDop@Ip9QD)QAWE{pB3Ay9n8Qqf30#1{tSA)?T^S$b?$e#yjSK8y3lm@hOn?b6 z0Vco%m;e)C0{;tvG?@{vahNNU1Kpe4Xa2fRrhH=pOn?b60Vco%m;e)C0!)AjFaajO z1TGwU55np8MWR*FQEfS)owvNm;e)C0!)AjFaajO1egF5U;>w%fbCdh*}hzJ zgnIO=rc+%vrQ?eQ@&mU{t^Q$q-_S;BG)%)`Jc`q>gZm!&7FEPq(Q$a5q@z4}nkTmr z(B=;1r}kuT5VoQCKxN9ZooQd7CmXIANM|kU#`J<|JFU?$+p5zhLUlxBAYF&rS+}A< z?QYaNFv7|Ft@|1>268S#xa(3 z3@SasB~MLh8e!*XFgPa5B?F5(t!|S6YIdEiJ_ha6;2&Ms9v(hENPpb zZ6YIz!>q2;0%}3e7+|F$8jcKnvZNp2jj^dFtDfs1i!xQj_?5z^&`U!6_Z};&4S!Vz ic(**Ca!;S Date: Sat, 19 Dec 2020 22:46:22 +0100 Subject: [PATCH 34/44] WIP: tests fixed. --- testdata/ruby/dbLayout.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/testdata/ruby/dbLayout.rb b/testdata/ruby/dbLayout.rb index 33a1decae..c7ec7732e 100644 --- a/testdata/ruby/dbLayout.rb +++ b/testdata/ruby/dbLayout.rb @@ -43,7 +43,7 @@ class DBLayout_TestClass < TestBase lmap.map( "4/2", 1 ) lmap.map( "1/2", 1 ) lmap.map( "0/0", 1 ) - assert_equal( lmap.mapping_str(1), "0/0;1/2;2-4/2" ) # could be "0/0;1-4/2" as well ... + assert_equal( lmap.mapping_str(1), "0/0;1-4/2" ) # could be "0/0;1-4/2" as well ... lmap.map( RBA::LayerInfo::new(2, 2), RBA::LayerInfo::new(4, 4), 2 ) lmap.map( RBA::LayerInfo::new(0, 1), 2 ) @@ -109,31 +109,31 @@ class DBLayout_TestClass < TestBase lmap.clear lmap.map("*/*", 0) lmap.mmap(RBA::LayerInfo::new(5, 10), 1) - assert_equal(lmap.mapping_str(0), "+0-4/*;5/0-9,10,11-*;6-*/*") + assert_equal(lmap.mapping_str(0), "+*/*") assert_equal(lmap.mapping_str(1), "+5/10") lmap.clear lmap.map("*/*", 0) lmap.mmap(RBA::LayerInfo::new(5, 10), 1, RBA::LayerInfo::new(100, 0)) - assert_equal(lmap.mapping_str(0), "+0-4/*;5/0-9,10,11-*;6-*/*") + assert_equal(lmap.mapping_str(0), "+*/*") assert_equal(lmap.mapping_str(1), "+5/10 : 100/0") lmap.clear lmap.map("*/*", 0) lmap.mmap(RBA::LayerInfo::new(5, 10), RBA::LayerInfo::new(16, 21), 1) - assert_equal(lmap.mapping_str(0), "+0-4/*;5-16/0-9,10-21,22-*;17-*/*") + assert_equal(lmap.mapping_str(0), "+*/*") assert_equal(lmap.mapping_str(1), "+5-16/10-21") lmap.clear lmap.map("*/*", 0) lmap.mmap(RBA::LayerInfo::new(5, 10), RBA::LayerInfo::new(16, 21), 1, RBA::LayerInfo::new(100, 0)) - assert_equal(lmap.mapping_str(0), "+0-4/*;5-16/0-9,10-21,22-*;17-*/*") + assert_equal(lmap.mapping_str(0), "+*/*") assert_equal(lmap.mapping_str(1), "+5-16/10-21 : 100/0") lmap.clear lmap.map("*/*", 0) lmap.mmap("5-16/10-21", 1) - assert_equal(lmap.mapping_str(0), "+0-4/*;5-16/0-9,10-21,22-*;17-*/*") + assert_equal(lmap.mapping_str(0), "+*/*") assert_equal(lmap.mapping_str(1), "+5-16/10-21") assert_equal(lmap.logicals(RBA::LayerInfo::new(5, 10)), [ 0, 1 ]) From b6f710a9fecd09ea7c499aafda883bbca30c420c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 19 Dec 2020 23:37:37 +0100 Subject: [PATCH 35/44] WIP: Fixed DXF reader --- src/db/db/dbNamedLayerReader.cc | 15 ++++++++--- src/db/db/dbNamedLayerReader.h | 18 ++++++++++++- .../streamers/dxf/db_plugin/dbDXFReader.cc | 27 +++++++------------ .../streamers/dxf/db_plugin/dbDXFReader.h | 1 - .../{dbDXFReader.cc => dbDXFReaderTests.cc} | 0 .../streamers/dxf/unit_tests/unit_tests.pro | 2 +- 6 files changed, 39 insertions(+), 24 deletions(-) rename src/plugins/streamers/dxf/unit_tests/{dbDXFReader.cc => dbDXFReaderTests.cc} (100%) diff --git a/src/db/db/dbNamedLayerReader.cc b/src/db/db/dbNamedLayerReader.cc index 9716f4cab..ca7fef294 100644 --- a/src/db/db/dbNamedLayerReader.cc +++ b/src/db/db/dbNamedLayerReader.cc @@ -122,25 +122,31 @@ extract_ld (const char *s, int &l, int &d, std::string &n) std::pair NamedLayerReader::open_layer (db::Layout &layout, const std::string &n) +{ + return open_layer (layout, n, keep_layer_names (), create_layers ()); +} + +std::pair +NamedLayerReader::open_layer (db::Layout &layout, const std::string &n, bool keep_layer_name, bool create_layer) { std::map >::const_iterator lc = m_layer_cache.find (n); if (lc != m_layer_cache.end ()) { return lc->second; } else { - std::pair res = open_layer_uncached (layout, n); + std::pair res = open_layer_uncached (layout, n, keep_layer_name, create_layer); m_layer_cache.insert (std::make_pair (n, res)); return res; } } std::pair -NamedLayerReader::open_layer_uncached (db::Layout &layout, const std::string &n) +NamedLayerReader::open_layer_uncached (db::Layout &layout, const std::string &n, bool keep_layer_name, bool create_layer) { int l = -1, d = -1; std::string on; std::set li = m_layer_map.logical (n, layout); - if (li.empty () && ! m_keep_layer_names) { + if (li.empty () && ! keep_layer_name) { if (extract_plain_layer (n.c_str (), l)) { @@ -183,7 +189,7 @@ NamedLayerReader::open_layer_uncached (db::Layout &layout, const std::string &n) } - } else if (! m_create_layers) { + } else if (! create_layer) { return std::pair (false, 0); @@ -212,6 +218,7 @@ NamedLayerReader::open_layer_uncached (db::Layout &layout, const std::string &n) void NamedLayerReader::map_layer (const std::string &name, unsigned int layer) { + m_layer_cache [name] = std::make_pair (true, layer); m_layer_map_out.map (name, layer); } diff --git a/src/db/db/dbNamedLayerReader.h b/src/db/db/dbNamedLayerReader.h index 53c68d9f4..5bf234b47 100644 --- a/src/db/db/dbNamedLayerReader.h +++ b/src/db/db/dbNamedLayerReader.h @@ -73,6 +73,14 @@ protected: */ void set_layer_map (const LayerMap &lm); + /** + * @brief Gets the input layer map + */ + const LayerMap &layer_map () + { + return m_layer_map; + } + /** * @brief Gets the layer map */ @@ -105,6 +113,14 @@ protected: */ std::pair open_layer (db::Layout &layout, const std::string &name); + /** + * @brief Opens a new layer + * This method will create or locate a layer for a given name. + * The result's first attribute is true, if such a layer could be found + * or created. In this case, the second attribute is the layer index. + */ + std::pair open_layer (db::Layout &layout, const std::string &name, bool keep_layer_name, bool create_layer); + /** * @brief Force mapping of a name to a layer index */ @@ -133,7 +149,7 @@ private: std::map > m_layer_cache; std::map, unsigned int> m_multi_mapping_placeholders; - std::pair open_layer_uncached (db::Layout &layout, const std::string &name); + std::pair open_layer_uncached (db::Layout &layout, const std::string &name, bool keep_layer_name, bool create_layer); }; } diff --git a/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc b/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc index 2335d238d..c0858a500 100644 --- a/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc +++ b/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc @@ -364,16 +364,6 @@ DXFReader::warn (const std::string &msg) } } -std::pair -DXFReader::open_layer (db::Layout &layout, const std::string &n) -{ - if (n == zero_layer_name) { - return std::make_pair (true, m_zero_layer); - } else { - return NamedLayerReader::open_layer (layout, n); - } -} - void DXFReader::do_read (db::Layout &layout, db::cell_index_type top) { @@ -381,21 +371,24 @@ DXFReader::do_read (db::Layout &layout, db::cell_index_type top) // create the zero layer - this is not mapped to GDS but can be specified in the layer mapping as // a layer named "0". - std::pair ll = open_layer (layout, zero_layer_name); - if (ll.first) { - // layer exists - m_zero_layer = ll.second; + std::pair li = NamedLayerReader::open_layer (layout, zero_layer_name, true /*keep layer name*/, false /*don't create a new layer*/); + if (li.first) { + + // we got one from the layer mapping + m_zero_layer = li.second; } else { - // or explicitly create the layer: - m_zero_layer = layout.insert_layer (db::LayerProperties (0, 0, zero_layer_name)); + // or we explicitly create the layer + db::LayerProperties lp_zero (0, 0, zero_layer_name); + m_zero_layer = layout.insert_layer (lp_zero); map_layer (zero_layer_name, m_zero_layer); } - // Read sections + // Read sections + int g; while (true) { diff --git a/src/plugins/streamers/dxf/db_plugin/dbDXFReader.h b/src/plugins/streamers/dxf/db_plugin/dbDXFReader.h index 54881d2cd..beed6dfcf 100644 --- a/src/plugins/streamers/dxf/db_plugin/dbDXFReader.h +++ b/src/plugins/streamers/dxf/db_plugin/dbDXFReader.h @@ -193,7 +193,6 @@ private: void do_read (db::Layout &layout, db::cell_index_type top); - std::pair open_layer (db::Layout &layout, const std::string &n); db::cell_index_type make_layer_variant (db::Layout &layout, const std::string &cellname, db::cell_index_type template_cell, unsigned int layer, double sx, double sy); void cleanup (db::Layout &layout, db::cell_index_type top); diff --git a/src/plugins/streamers/dxf/unit_tests/dbDXFReader.cc b/src/plugins/streamers/dxf/unit_tests/dbDXFReaderTests.cc similarity index 100% rename from src/plugins/streamers/dxf/unit_tests/dbDXFReader.cc rename to src/plugins/streamers/dxf/unit_tests/dbDXFReaderTests.cc diff --git a/src/plugins/streamers/dxf/unit_tests/unit_tests.pro b/src/plugins/streamers/dxf/unit_tests/unit_tests.pro index de728685d..98d781faa 100644 --- a/src/plugins/streamers/dxf/unit_tests/unit_tests.pro +++ b/src/plugins/streamers/dxf/unit_tests/unit_tests.pro @@ -6,7 +6,7 @@ TARGET = dxf_tests include($$PWD/../../../../lib_ut.pri) SOURCES = \ - dbDXFReader.cc \ + dbDXFReaderTests.cc INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common From 4b8577a89ba64dd1b8249a04dbf139c418e4216c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 20 Dec 2020 00:35:23 +0100 Subject: [PATCH 36/44] Temporary compatibility with lefdef branch - remove when this branch is merged. --- src/db/db/dbStreamLayers.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/db/db/dbStreamLayers.h b/src/db/db/dbStreamLayers.h index b142d7d95..630dc6bb8 100644 --- a/src/db/db/dbStreamLayers.h +++ b/src/db/db/dbStreamLayers.h @@ -215,6 +215,15 @@ public: */ std::pair logical (const db::LayerProperties &p) const; + /** + * @brief A compatibility function for future enhancements + * TODO: remove when lefdef branch is merged + */ + std::pair first_logical (const db::LayerProperties &p) const + { + return logical (p); + } + /** * @brief Query or install a layer mapping from a name or LDPair * From 09e088b68666ce39d05aafb849ecf8828591c8d7 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 20 Dec 2020 00:37:06 +0100 Subject: [PATCH 37/44] Added missing file. --- testdata/gds/alm_au3.gds | Bin 0 -> 2890 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 testdata/gds/alm_au3.gds diff --git a/testdata/gds/alm_au3.gds b/testdata/gds/alm_au3.gds new file mode 100644 index 0000000000000000000000000000000000000000..324c893f7b7d87ff7b20f22c263fc1b937fe5319 GIT binary patch literal 2890 zcmbW3O-NKx6vxlJ8Si^DjvuK6Mnp+Lfmvi3A&HfhVrb|jC4w&71VJJZ6+#J?1VOE= zMFiQxT@VPhiimL4GAP1Di#CDK$|2|VKkvNLdw1}Slra8=bMOD2^X~b0LxvpZB5hAO z?sv*lBQ;Ph)y2P)=a_SSCyAQURb40U9qs?{a`jlx(t&4BMhmpPDp{8^rZ9A3V3;W5 z5t$l?QehandO3iBcV`kEnJUP10j;3pC3@ ze*rA9f1%ow{j-k!3sW7e!zZNLZU5;X@#kNkg8x0fzdi-s7b54rQteDDe&>JnS-Jmo zs5iSf3tn9s|BKXA&m`afy}~3)@3g!c%j;W2br(^;MYK0@W4o1VXC~=!_}5?^WF4Nm zN2&Hm?^4D3@{H*l7&%0l98s=8Yb_tt*45xag4)@5HMc4;TB~MTYMKZqAf|^2CzS2c zb2h5*;w+Kt`98DuGf~y`h-!De_+8l*^6z@m3+2NQtiyR|F|A^ z&={6>sC-L#o}(TY5M0k4n3P=X)dcUn7UN@I9p3OK&Ra zq3LHmVn5CLh-#<)%KGf0=yNYbuT*<>v9i9pQ}p>GqF1WDx>NM|zw>%4zcn$Dq;62B zrWsSu+J!3BU4N_DYc_)y3P=#YJvW)7cux=Y4V)dsPE13uL8dBvB1ZYsIclxt&IgMd zt~EVNUfZ#nytc19d9B@^$W|=JSCVzT2b0%^rjyskK1FL75B&SZng`|6srX)|6SI6e zg?g(W*Ltz98~p&f@HL9JgHr9L+p4FSo@jh8>xHbFSQ0%`?PYqapVl5>-yHmd?hN|z zK}5BiIm>@cPjsoB^+Io(N4;8#-q5uE@ literal 0 HcmV?d00001 From ee47a1e08749accd4f2c8c65bc46bc3a2d9de601 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Dec 2020 22:13:51 +0100 Subject: [PATCH 38/44] Fixed the manager's 'cancel' implementation: with this, redo of a cancelled operation isn't possible any more --- src/db/db/dbManager.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/db/db/dbManager.cc b/src/db/db/dbManager.cc index 5e53b1a83..0a9e24016 100644 --- a/src/db/db/dbManager.cc +++ b/src/db/db/dbManager.cc @@ -156,16 +156,14 @@ Manager::cancel () m_opened = false; if (m_current->first.begin () != m_current->first.end ()) { - ++m_current; undo (); - - } else { - // empty transactions .. just delete - erase_transactions (m_current, m_transactions.end ()); - m_current = m_transactions.end (); } + // wipe following history as we don't want the cancelled operation to be redoable + erase_transactions (m_current, m_transactions.end ()); + m_current = m_transactions.end (); + } } From 5a828b4c8f10ae802b255b27d2b8b60c1fa16dfc Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 20 Dec 2020 17:57:34 +0100 Subject: [PATCH 39/44] WIP: code cleanup --- src/db/db/dbCommonReader.cc | 9 --------- src/db/db/dbNamedLayerReader.cc | 9 --------- 2 files changed, 18 deletions(-) diff --git a/src/db/db/dbCommonReader.cc b/src/db/db/dbCommonReader.cc index a64de5f72..f52e5cdf2 100644 --- a/src/db/db/dbCommonReader.cc +++ b/src/db/db/dbCommonReader.cc @@ -313,15 +313,6 @@ CommonReader::init (const LoadLayoutOptions &options) m_layer_cache.clear (); m_layers_created.clear (); m_layer_names.clear (); - - // create a pseudo-multimapping for single targets - for (db::LayerMap::const_iterator_layers li = m_common_options.layer_map.begin (); li != m_common_options.layer_map.end (); ++li) { - for (db::LayerMap::const_iterator_datatypes di = li->second.begin (); di != li->second.end (); ++di) { - if (di->second.size () == 1) { - m_multi_mapping_placeholders.insert (std::make_pair (di->second, *di->second.begin ())); - } - } - } } void diff --git a/src/db/db/dbNamedLayerReader.cc b/src/db/db/dbNamedLayerReader.cc index ca7fef294..c9fce8438 100644 --- a/src/db/db/dbNamedLayerReader.cc +++ b/src/db/db/dbNamedLayerReader.cc @@ -233,15 +233,6 @@ NamedLayerReader::prepare_layers (db::Layout &layout) m_layer_cache.clear (); m_layer_map.prepare (layout); - - // create a pseudo-multimapping for single targets - for (db::LayerMap::const_iterator_layers li = m_layer_map.begin (); li != m_layer_map.end (); ++li) { - for (db::LayerMap::const_iterator_datatypes di = li->second.begin (); di != li->second.end (); ++di) { - if (di->second.size () == 1) { - m_multi_mapping_placeholders.insert (std::make_pair (di->second, *di->second.begin ())); - } - } - } } void From 4213f44d72c609d88ef76d37468ba2e075f261bd Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 20 Dec 2020 17:58:37 +0100 Subject: [PATCH 40/44] More robustness against configuration corruption. --- src/edt/edt/edtRecentConfigurationPage.cc | 48 +++++++++++++++++------ 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/src/edt/edt/edtRecentConfigurationPage.cc b/src/edt/edt/edtRecentConfigurationPage.cc index 554f85be0..ca17ad53b 100644 --- a/src/edt/edt/edtRecentConfigurationPage.cc +++ b/src/edt/edt/edtRecentConfigurationPage.cc @@ -27,6 +27,7 @@ #include "layLayerTreeModel.h" #include "dbLibraryManager.h" #include "dbLibrary.h" +#include "tlLog.h" #include #include @@ -89,16 +90,24 @@ RecentConfigurationPage::get_stored_values () const std::string serialized_list = dispatcher ()->config_get (m_recent_cfg_name); std::list > values; - tl::Extractor ex (serialized_list.c_str ()); - while (! ex.at_end ()) { - values.push_back (std::vector ()); - while (! ex.at_end () && ! ex.test (";")) { - values.back ().push_back (std::string ()); - ex.read_word_or_quoted (values.back ().back ()); - ex.test (","); + try { + + tl::Extractor ex (serialized_list.c_str ()); + while (! ex.at_end ()) { + + values.push_back (std::vector ()); + while (! ex.at_end () && ! ex.test (";")) { + values.back ().push_back (std::string ()); + ex.read_word_or_quoted (values.back ().back ()); + ex.test (","); + } + } + } catch (tl::Exception &ex) { + tl::error << tl::to_string (tr ("Error reading configuration item ")) << m_recent_cfg_name << ": " << ex.msg (); + values.clear (); } return values; @@ -158,7 +167,11 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std case RecentConfigurationPage::Bool: { bool f = false; - tl::from_string (values [column], f); + try { + tl::from_string (values [column], f); + } catch (tl::Exception &ex) { + tl::error << tl::to_string (tr ("Configuration error (ArrayFlag/Bool): ")) << ex.msg (); + } static QString checkmark = QString::fromUtf8 ("\xe2\x9c\x93"); item->setText (column, f ? checkmark : QString ()); // "checkmark" } @@ -167,7 +180,12 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std case RecentConfigurationPage::Layer: { int icon_size = mp_view->style ()->pixelMetric (QStyle::PM_ButtonIconSize); - lay::LayerPropertiesConstIterator l = lp_iter_from_string (mp_view, values [column]); + lay::LayerPropertiesConstIterator l; + try { + l = lp_iter_from_string (mp_view, values [column]); + } catch (tl::Exception &ex) { + tl::error << tl::to_string (tr ("Configuration error (Layer): ")) << ex.msg (); + } if (! l.is_null () && ! l.at_end ()) { item->setIcon (column, lay::LayerTreeModel::icon_for_layer (l, mp_view, icon_size, icon_size, 0, true)); item->setText (column, tl::to_qstring (values [column])); @@ -199,7 +217,11 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std int flag_column = 0; for (std::list::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++flag_column) { if (c->rendering == RecentConfigurationPage::ArrayFlag) { - tl::from_string (values [flag_column], is_array); + try { + tl::from_string (values [flag_column], is_array); + } catch (tl::Exception &ex) { + tl::error << tl::to_string (tr ("Configuration error (IntIfArray/DoubleIfArray): ")) << ex.msg (); + } break; } } @@ -254,7 +276,11 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std case RecentConfigurationPage::PCellParameters: { std::map pcp; - pcp = pcell_parameters_from_string (values [column]); + try { + pcp = pcell_parameters_from_string (values [column]); + } catch (tl::Exception &ex) { + tl::error << tl::to_string (tr ("Configuration error (PCellParameters): ")) << ex.msg (); + } std::string r; for (std::map::const_iterator p = pcp.begin (); p != pcp.end (); ++p) { if (p != pcp.begin ()) { From 9290bb715402c6c1a9da216e4d23ec446d217a35 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 20 Dec 2020 19:27:54 +0100 Subject: [PATCH 41/44] Fixed a merge conflict --- src/db/db/dbStreamLayers.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/db/db/dbStreamLayers.h b/src/db/db/dbStreamLayers.h index 9690f77b7..61eaad77a 100644 --- a/src/db/db/dbStreamLayers.h +++ b/src/db/db/dbStreamLayers.h @@ -253,15 +253,6 @@ public: */ std::set logical (const db::LayerProperties &p) const; - /** - * @brief A compatibility function for future enhancements - * TODO: remove when lefdef branch is merged - */ - std::pair first_logical (const db::LayerProperties &p) const - { - return logical (p); - } - /** * @brief Query or install a layer mapping from a name or LDPair * From db19e92083f3a1cab810304337199952621df366 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 20 Dec 2020 20:53:43 +0100 Subject: [PATCH 42/44] Fixed some merge issues. --- src/db/unit_tests/dbLibrariesTests.cc | 115 +++++++++++------- .../streamers/magic/db_plugin/dbMAGReader.cc | 2 +- 2 files changed, 71 insertions(+), 46 deletions(-) diff --git a/src/db/unit_tests/dbLibrariesTests.cc b/src/db/unit_tests/dbLibrariesTests.cc index 971f0df6f..b7730a7d0 100644 --- a/src/db/unit_tests/dbLibrariesTests.cc +++ b/src/db/unit_tests/dbLibrariesTests.cc @@ -619,59 +619,84 @@ TEST(3) TEST(4) { - LIBT_A *lib_a1 = new LIBT_A (); + tl::weak_ptr lib_a1 (new LIBT_A ()); lib_a1->add_technology ("X"); - db::LibraryManager::instance ().register_lib (lib_a1); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a1->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a1->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ()); - - LIBT_A *lib_a2 = new LIBT_A (); + tl::weak_ptr lib_a2 (new LIBT_A ()); lib_a2->add_technology ("Y"); - db::LibraryManager::instance ().register_lib (lib_a2); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a2->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a2->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); - - LIBT_A *lib_a3 = new LIBT_A (); + tl::weak_ptr lib_a3 (new LIBT_A ()); lib_a3->add_technology ("X"); - db::LibraryManager::instance ().register_lib (lib_a3); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a3->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a3->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); + tl::weak_ptr lib_a4 (new LIBT_A ()); + try { - LIBT_A *lib_a4 = new LIBT_A (); - db::LibraryManager::instance ().register_lib (lib_a4); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a3->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").second, lib_a4->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a3->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); + db::LibraryManager::instance ().register_lib (lib_a1.get ()); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ()); + + db::LibraryManager::instance ().register_lib (lib_a2.get ()); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); + + db::LibraryManager::instance ().register_lib (lib_a3.get ()); + // lib_a3 replaces lib_a1 + EXPECT_EQ (lib_a1.get () == 0, true); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); + + db::LibraryManager::instance ().register_lib (lib_a4.get ()); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a4->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").second, lib_a4->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a4->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); + + // because we switch to editable mode in between we have to clear the repository explicitly. Otherwise it's being cleared + // on next entry of TEST which will cause a segmentation fault if editable mode is different then. + if (lib_a1.get ()) { db::LibraryManager::instance ().delete_lib (lib_a1.get ()); } + if (lib_a2.get ()) { db::LibraryManager::instance ().delete_lib (lib_a2.get ()); } + if (lib_a3.get ()) { db::LibraryManager::instance ().delete_lib (lib_a3.get ()); } + if (lib_a4.get ()) { db::LibraryManager::instance ().delete_lib (lib_a4.get ()); } + + } catch (...) { + + // because we switch to editable mode in between we have to clear the repository explicitly. Otherwise it's being cleared + // on next entry of TEST which will cause a segmentation fault if editable mode is different then. + if (lib_a1.get ()) { db::LibraryManager::instance ().delete_lib (lib_a1.get ()); } + if (lib_a2.get ()) { db::LibraryManager::instance ().delete_lib (lib_a2.get ()); } + if (lib_a3.get ()) { db::LibraryManager::instance ().delete_lib (lib_a3.get ()); } + if (lib_a4.get ()) { db::LibraryManager::instance ().delete_lib (lib_a4.get ()); } + throw; + + } } diff --git a/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc b/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc index 23c7d3678..29bb3fe1d 100644 --- a/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc +++ b/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc @@ -72,7 +72,7 @@ MAGReader::read (db::Layout &layout) const LayerMap & MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) { - prepare_layers (); + prepare_layers (layout); mp_klayout_tech = layout.technology (); From 1c6ffb408603c2c779a3368b132d27a30b1a47c6 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 20 Dec 2020 21:45:55 +0100 Subject: [PATCH 43/44] Fixed unit tests. --- src/db/unit_tests/dbLayoutTests.cc | 40 +++++++++++++++++------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/db/unit_tests/dbLayoutTests.cc b/src/db/unit_tests/dbLayoutTests.cc index 49a44f837..bbdfe3e4d 100644 --- a/src/db/unit_tests/dbLayoutTests.cc +++ b/src/db/unit_tests/dbLayoutTests.cc @@ -566,22 +566,26 @@ TEST(5) EXPECT_EQ (dynamic_cast (cell) != 0, true); EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 2 0 {0 0} {200 100}\nend_cell\nend_lib\n"); - m.undo (); - EXPECT_EQ (l.technology_name (), "C"); + if (l.is_editable ()) { - cell = &l.cell (l.cell_by_name ("LIBCELL").second); - EXPECT_EQ (dynamic_cast (cell) != 0, true); - EXPECT_EQ (cell->get_qualified_name (), "LIB.LIBCELL"); - EXPECT_EQ (cell->get_basic_name (), "LIBCELL"); - EXPECT_EQ (cell->get_display_name (), "LIB.LIBCELL"); - EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 1 0 {0 0} {100 200}\nend_cell\nend_lib\n"); + m.undo (); + EXPECT_EQ (l.technology_name (), "C"); - m.redo (); + cell = &l.cell (l.cell_by_name ("LIBCELL").second); + EXPECT_EQ (dynamic_cast (cell) != 0, true); + EXPECT_EQ (cell->get_qualified_name (), "LIB.LIBCELL"); + EXPECT_EQ (cell->get_basic_name (), "LIBCELL"); + EXPECT_EQ (cell->get_display_name (), "LIB.LIBCELL"); + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 1 0 {0 0} {100 200}\nend_cell\nend_lib\n"); - EXPECT_EQ (l.technology_name (), "B"); - cell = &l.cell (l.cell_by_name ("LIBCELL").second); - EXPECT_EQ (dynamic_cast (cell) != 0, true); - EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 2 0 {0 0} {200 100}\nend_cell\nend_lib\n"); + m.redo (); + + EXPECT_EQ (l.technology_name (), "B"); + cell = &l.cell (l.cell_by_name ("LIBCELL").second); + EXPECT_EQ (dynamic_cast (cell) != 0, true); + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 2 0 {0 0} {200 100}\nend_cell\nend_lib\n"); + + } db::LibraryManager::instance ().delete_lib (lib_a); db::LibraryManager::instance ().delete_lib (lib_b); @@ -629,8 +633,10 @@ TEST(6) EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-2071 -5000} {-5000 -2071} {-5000 2071} {-2071 5000} {2071 5000} {5000 2071} {5000 -2071} {2071 -5000} {-2071 -5000}\nend_cell\nend_lib\n"); - m.undo (); - EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-4142 -10000} {-10000 -4142} {-10000 4142} {-4142 10000} {4142 10000} {10000 4142} {10000 -4142} {4142 -10000} {-4142 -10000}\nend_cell\nend_lib\n"); - m.redo (); - EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-2071 -5000} {-5000 -2071} {-5000 2071} {-2071 5000} {2071 5000} {5000 2071} {5000 -2071} {2071 -5000} {-2071 -5000}\nend_cell\nend_lib\n"); + if (l.is_editable ()) { + m.undo (); + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-4142 -10000} {-10000 -4142} {-10000 4142} {-4142 10000} {4142 10000} {10000 4142} {10000 -4142} {4142 -10000} {-4142 -10000}\nend_cell\nend_lib\n"); + m.redo (); + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-2071 -5000} {-5000 -2071} {-5000 2071} {-2071 5000} {2071 5000} {5000 2071} {5000 -2071} {2071 -5000} {-2071 -5000}\nend_cell\nend_lib\n"); + } } From ca1ec353fbc62954b3e402ae19472f0d29a2a840 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 20 Dec 2020 23:49:29 +0100 Subject: [PATCH 44/44] Some fixes for the technology feature - Fixed some potential segfaults due to invalid layout object - More consistent handling of potential technology switch due to active cellview change --- src/edt/edt/edtEditorOptionsPages.cc | 2 +- src/edt/edt/edtInstPropertiesPage.cc | 2 +- src/edt/edt/edtPCellParametersPage.cc | 15 +++--- src/edt/edt/edtPCellParametersPage.h | 3 +- src/lay/lay/layTechnologyController.cc | 4 -- src/laybasic/laybasic/layLayoutView.cc | 25 +++++++-- src/laybasic/laybasic/layLayoutView.h | 9 +++- src/laybasic/laybasic/layWidgets.cc | 73 ++++++++++++++++---------- 8 files changed, 82 insertions(+), 51 deletions(-) diff --git a/src/edt/edt/edtEditorOptionsPages.cc b/src/edt/edt/edtEditorOptionsPages.cc index 779398f97..df2f67f69 100644 --- a/src/edt/edt/edtEditorOptionsPages.cc +++ b/src/edt/edt/edtEditorOptionsPages.cc @@ -872,7 +872,7 @@ EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector pcell_declaration (pc.second) && view ()->cellview (m_cv_index).is_valid ()) { mp_pcell_parameters = new PCellParametersPage (this, true /*dense*/); - mp_pcell_parameters->setup (&view ()->cellview (m_cv_index)->layout (), view (), m_cv_index, layout->pcell_declaration (pc.second), parameters); + mp_pcell_parameters->setup (view (), m_cv_index, layout->pcell_declaration (pc.second), parameters); this->layout ()->addWidget (mp_pcell_parameters); mp_pcell_parameters->set_state (pcp_state); diff --git a/src/edt/edt/edtInstPropertiesPage.cc b/src/edt/edt/edtInstPropertiesPage.cc index 08a4c27fa..40f805210 100644 --- a/src/edt/edt/edtInstPropertiesPage.cc +++ b/src/edt/edt/edtInstPropertiesPage.cc @@ -810,7 +810,7 @@ InstPropertiesPage::update_pcell_parameters () mp_pcell_parameters = new PCellParametersPage (pcell_tab); connect (mp_pcell_parameters, SIGNAL (edited ()), this, SIGNAL (edited ())); - mp_pcell_parameters->setup (&cv->layout (), mp_service->view (), pos->cv_index (), layout->pcell_declaration (pc.second), parameters); + mp_pcell_parameters->setup (mp_service->view (), pos->cv_index (), layout->pcell_declaration (pc.second), parameters); pcell_tab->layout ()->addWidget (mp_pcell_parameters); } diff --git a/src/edt/edt/edtPCellParametersPage.cc b/src/edt/edt/edtPCellParametersPage.cc index 5908c8d36..150f0f76d 100644 --- a/src/edt/edt/edtPCellParametersPage.cc +++ b/src/edt/edt/edtPCellParametersPage.cc @@ -25,6 +25,7 @@ #include "edtPropertiesPageUtils.h" #include "layWidgets.h" #include "layQtTools.h" +#include "layLayoutView.h" #include "tlScriptError.h" #include @@ -40,7 +41,7 @@ namespace edt { -static void set_value (const db::PCellParameterDeclaration &p, const db::Layout * /*layout*/, QWidget *widget, const tl::Variant &value) +static void set_value (const db::PCellParameterDeclaration &p, QWidget *widget, const tl::Variant &value) { if (p.get_choices ().empty ()) { @@ -154,7 +155,6 @@ void PCellParametersPage::init () { mp_pcell_decl.reset (0); - mp_layout = 0; mp_view = 0; m_cv_index = 0; mp_parameters_area = 0; @@ -183,10 +183,9 @@ PCellParametersPage::init () } void -PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters) +PCellParametersPage::setup (lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters) { mp_pcell_decl.reset (const_cast (pcell_decl)); // no const weak_ptr ... - mp_layout = layout; mp_view = view; m_cv_index = cv_index; m_parameters = parameters; @@ -385,7 +384,7 @@ PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int } - set_value (*p, mp_layout, m_widgets.back (), value); + set_value (*p, m_widgets.back (), value); ++row; if (inner_frame == main_frame) { @@ -592,7 +591,9 @@ PCellParametersPage::get_parameters (bool *ok) } // coerce the parameters - mp_pcell_decl->coerce_parameters (*mp_layout, parameters); + if (mp_view->cellview (m_cv_index).is_valid ()) { + mp_pcell_decl->coerce_parameters (mp_view->cellview (m_cv_index)->layout (), parameters); + } set_parameters (parameters); mp_error_label->hide (); @@ -642,7 +643,7 @@ PCellParametersPage::set_parameters (const std::vector ¶meters) const std::vector &pcp = mp_pcell_decl->parameter_declarations (); for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) { if (r < parameters.size () && m_widgets [r]) { - set_value (*p, mp_layout, m_widgets [r], parameters [r]); + set_value (*p, m_widgets [r], parameters [r]); } } } diff --git a/src/edt/edt/edtPCellParametersPage.h b/src/edt/edt/edtPCellParametersPage.h index 158a3cb07..a180d4f9c 100644 --- a/src/edt/edt/edtPCellParametersPage.h +++ b/src/edt/edt/edtPCellParametersPage.h @@ -78,7 +78,7 @@ public: * @param pcell_decl The PCell declaration * @param parameters The parameter values to show (if empty, the default values are used) */ - void setup (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters); + void setup (lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters); /** * @brief Gets the pages current state @@ -124,7 +124,6 @@ private: QLabel *mp_error_icon; tl::weak_ptr mp_pcell_decl; std::vector m_widgets; - const db::Layout *mp_layout; lay::LayoutView *mp_view; int m_cv_index; db::pcell_parameters_type m_parameters; diff --git a/src/lay/lay/layTechnologyController.cc b/src/lay/lay/layTechnologyController.cc index 53f85f05a..eec75c495 100644 --- a/src/lay/lay/layTechnologyController.cc +++ b/src/lay/lay/layTechnologyController.cc @@ -290,10 +290,6 @@ TechnologyController::menu_activated (const std::string &symbol) const if (mp_mw) { - // Cancels the current modes - changing the technology may make libraries unavailable - // for example. - mp_mw->cancel (); - // apply technology with undo mp_mw->manager ().transaction (tl::sprintf (tl::to_string (tr ("Apply technology '%s'")), m_current_technology)); try { diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc index fe3c642b7..18f1c6ddc 100644 --- a/src/laybasic/laybasic/layLayoutView.cc +++ b/src/laybasic/laybasic/layLayoutView.cc @@ -2538,7 +2538,7 @@ LayoutView::erase_cellview (unsigned int index) return; } - cancel (); + cancel_esc (); // issue to event that signals a change in the cellviews cellviews_about_to_change_event (); @@ -2704,6 +2704,8 @@ LayoutView::signal_apply_technology (lay::LayoutHandle *layout_handle) if (cellview (i).handle () == layout_handle) { + cancel_esc (); + std::string lyp_file; const db::Technology *tech = db::Technologies::instance ()->technology_by_name (cellview (i)->tech_name ()); if (tech && ! tech->eff_layer_properties_file ().empty ()) { @@ -3056,7 +3058,7 @@ void LayoutView::reload_layout (unsigned int cv_index) { stop (); - cancel (); + cancel_esc (); // save the current view state lay::DisplayState state; @@ -3948,6 +3950,13 @@ LayoutView::cancel () clear_selection (); } +void +LayoutView::cancel_esc () +{ + cancel (); + switch_mode (default_mode ()); +} + void LayoutView::bookmark_current_view () { @@ -4751,7 +4760,7 @@ LayoutView::select_cellviews_fit (const std::list &cvs) cellviews_about_to_change_event (); set_min_hier_levels (0); - cancel (); + cancel_esc (); m_cellviews = cvs; zoom_fit (); finish_cellviews_changed (); @@ -4772,6 +4781,12 @@ LayoutView::active_cellview_changed (int index) { if (m_active_cellview_changed_event_enabled) { + // we need to cancel pending drawing or dragging operations to reflect the new cellview (different target, may have different technology etc.) + cancel_esc (); + + // we need to setup the editor option pages because the technology may have changed + dm_setup_editor_option_pages (); + active_cellview_changed_event (); active_cellview_changed_with_index_event (index); @@ -4889,7 +4904,7 @@ LayoutView::select_cellviews (const std::list &cvs) cellviews_about_to_change_event (); set_min_hier_levels (0); - cancel (); + cancel_esc (); m_cellviews = cvs; redraw (); @@ -4914,7 +4929,7 @@ LayoutView::select_cellview (int index, const CellView &cv) cellview_about_to_change_event (index); - cancel (); + cancel_esc (); *cellview_iter (index) = cv; redraw (); diff --git a/src/laybasic/laybasic/layLayoutView.h b/src/laybasic/laybasic/layLayoutView.h index 66469b163..a54e731fb 100644 --- a/src/laybasic/laybasic/layLayoutView.h +++ b/src/laybasic/laybasic/layLayoutView.h @@ -2576,12 +2576,17 @@ public slots: void store_state (); /** - * @brief Cancel all edit operations and clear the selection + * @brief Cancels all edit operations, clears the selection and resets the mode to "Select" + */ + void cancel_esc (); + + /** + * @brief Cancels all edit operations and clears the selection */ void cancel (); /** - * @brief Cancel all edit operations but leave selection + * @brief Cancels all edit operations but maintains selection */ void cancel_edits (); diff --git a/src/laybasic/laybasic/layWidgets.cc b/src/laybasic/laybasic/layWidgets.cc index a84b96601..c40d666b4 100644 --- a/src/laybasic/laybasic/layWidgets.cc +++ b/src/laybasic/laybasic/layWidgets.cc @@ -420,7 +420,7 @@ LayerSelectionComboBox::set_view (lay::LayoutView *view, int cv_index, bool all_ return; } - mp_private->layout = &view->cellview (cv_index)->layout (); + mp_private->layout = 0; mp_private->view = view; mp_private->cv_index = cv_index; mp_private->all_layers = all_layers; @@ -465,45 +465,60 @@ LayerSelectionComboBox::update_layer_list () if (mp_private->view) { - LPIPairCompareOp cmp_op; - std::map, std::string, LPIPairCompareOp> name_for_layer (cmp_op); - LayerPropertiesConstIterator lp = mp_private->view->begin_layers (); - while (! lp.at_end ()) { - if (lp->cellview_index () == mp_private->cv_index && ! lp->has_children () && (mp_private->all_layers || lp->layer_index () >= 0) && lp->source (true).layer_props () != db::LayerProperties ()) { - std::pair k (lp->source (true).layer_props (), lp->layer_index ()); - name_for_layer.insert (std::make_pair (k, lp->display_string (mp_private->view, true, true /*always show source*/))); - mp_private->layers.push_back (k); - } - ++lp; + const db::Layout *layout = 0; + + const CellView &cv = mp_private->view->cellview (mp_private->cv_index); + if (cv.is_valid ()) { + layout = & cv->layout (); } - size_t nk = mp_private->layers.size (); + if (! layout) { - for (unsigned int l = 0; l < mp_private->layout->layers (); ++l) { - if (mp_private->layout->is_valid_layer (l)) { - std::pair k (mp_private->layout->get_properties (l), int (l)); - if (name_for_layer.find (k) == name_for_layer.end ()) { + set_current_layer (-1); + + } else { + + LPIPairCompareOp cmp_op; + std::map, std::string, LPIPairCompareOp> name_for_layer (cmp_op); + LayerPropertiesConstIterator lp = mp_private->view->begin_layers (); + while (! lp.at_end ()) { + if (lp->cellview_index () == mp_private->cv_index && ! lp->has_children () && (mp_private->all_layers || lp->layer_index () >= 0) && lp->source (true).layer_props () != db::LayerProperties ()) { + std::pair k (lp->source (true).layer_props (), lp->layer_index ()); + name_for_layer.insert (std::make_pair (k, lp->display_string (mp_private->view, true, true /*always show source*/))); mp_private->layers.push_back (k); } + ++lp; } - } - std::sort (mp_private->layers.begin () + nk, mp_private->layers.end ()); + size_t nk = mp_private->layers.size (); - for (std::vector >::iterator ll = mp_private->layers.begin (); ll != mp_private->layers.end (); ++ll) { - std::map, std::string, LPIPairCompareOp>::const_iterator ln = name_for_layer.find (*ll); - if (ln != name_for_layer.end ()) { - addItem (tl::to_qstring (ln->second)); - } else { - addItem (tl::to_qstring (ll->first.to_string ())); + for (unsigned int l = 0; l < layout->layers (); ++l) { + if (layout->is_valid_layer (l)) { + std::pair k (layout->get_properties (l), int (l)); + if (name_for_layer.find (k) == name_for_layer.end ()) { + mp_private->layers.push_back (k); + } + } } - } - if (mp_private->new_layer_enabled) { - addItem (QObject::tr ("New Layer ..")); - } + std::sort (mp_private->layers.begin () + nk, mp_private->layers.end ()); - set_current_layer (props); + for (std::vector >::iterator ll = mp_private->layers.begin (); ll != mp_private->layers.end (); ++ll) { + std::map, std::string, LPIPairCompareOp>::const_iterator ln = name_for_layer.find (*ll); + if (ln != name_for_layer.end ()) { + addItem (tl::to_qstring (ln->second)); + } else { + addItem (tl::to_qstring (ll->first.to_string ())); + } + } + + if (mp_private->new_layer_enabled) { + addItem (QObject::tr ("New Layer ..")); + } + + set_current_layer (props); + + } } else if (mp_private->layout) {