From 07eb49d482e92f71365ca85f649bc3beb08e21fa Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 27 Apr 2025 01:11:38 +0200 Subject: [PATCH 01/15] Initializing MALY plugin --- .../streamers/maly/db_plugin/dbMALY.cc | 123 ++++++++++++ src/plugins/streamers/maly/db_plugin/dbMALY.h | 62 ++++++ .../streamers/maly/db_plugin/dbMALYFormat.h | 162 ++++++++++++++++ .../streamers/maly/db_plugin/dbMALYReader.cc | 142 ++++++++++++++ .../streamers/maly/db_plugin/dbMALYReader.h | 148 ++++++++++++++ .../streamers/maly/db_plugin/db_plugin.pro | 15 ++ .../streamers/maly/db_plugin/gsiDeclDbMALY.cc | 133 +++++++++++++ .../maly/lay_plugin/MALYReaderOptionPage.ui | 183 ++++++++++++++++++ .../maly/lay_plugin/layMALYReaderPlugin.cc | 110 +++++++++++ .../maly/lay_plugin/layMALYReaderPlugin.h | 59 ++++++ .../streamers/maly/lay_plugin/lay_plugin.pro | 22 +++ src/plugins/streamers/maly/maly.pro | 10 + .../streamers/maly/unit_tests/dbMALYReader.cc | 108 +++++++++++ .../streamers/maly/unit_tests/unit_tests.pro | 19 ++ 14 files changed, 1296 insertions(+) create mode 100644 src/plugins/streamers/maly/db_plugin/dbMALY.cc create mode 100644 src/plugins/streamers/maly/db_plugin/dbMALY.h create mode 100644 src/plugins/streamers/maly/db_plugin/dbMALYFormat.h create mode 100644 src/plugins/streamers/maly/db_plugin/dbMALYReader.cc create mode 100644 src/plugins/streamers/maly/db_plugin/dbMALYReader.h create mode 100644 src/plugins/streamers/maly/db_plugin/db_plugin.pro create mode 100644 src/plugins/streamers/maly/db_plugin/gsiDeclDbMALY.cc create mode 100644 src/plugins/streamers/maly/lay_plugin/MALYReaderOptionPage.ui create mode 100644 src/plugins/streamers/maly/lay_plugin/layMALYReaderPlugin.cc create mode 100644 src/plugins/streamers/maly/lay_plugin/layMALYReaderPlugin.h create mode 100644 src/plugins/streamers/maly/lay_plugin/lay_plugin.pro create mode 100644 src/plugins/streamers/maly/maly.pro create mode 100644 src/plugins/streamers/maly/unit_tests/dbMALYReader.cc create mode 100644 src/plugins/streamers/maly/unit_tests/unit_tests.pro diff --git a/src/plugins/streamers/maly/db_plugin/dbMALY.cc b/src/plugins/streamers/maly/db_plugin/dbMALY.cc new file mode 100644 index 000000000..57d67e416 --- /dev/null +++ b/src/plugins/streamers/maly/db_plugin/dbMALY.cc @@ -0,0 +1,123 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2025 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 "dbMALY.h" +#include "dbMALYReader.h" +#include "dbStream.h" + +#include "tlClassRegistry.h" + +namespace db +{ + +// --------------------------------------------------------------- +// MALYDiagnostics implementation + +MALYDiagnostics::~MALYDiagnostics () +{ + // .. nothing yet .. +} + +// --------------------------------------------------------------- +// MALY format declaration + +class MALYFormatDeclaration + : public db::StreamFormatDeclaration +{ +public: + MALYFormatDeclaration () + { + // .. nothing yet .. + } + + virtual std::string format_name () const { return "MALY"; } + virtual std::string format_desc () const { return "MALY jobdeck"; } + virtual std::string format_title () const { return "MALY (MALY jobdeck format)"; } + virtual std::string file_format () const { return "MALY jobdeck files (*.maly *.MALY)"; } + + virtual bool detect (tl::InputStream &s) const + { + return false; // @@@ + } + + virtual ReaderBase *create_reader (tl::InputStream &s) const + { + return new db::MALYReader (s); + } + + virtual WriterBase *create_writer () const + { + return 0; + // @@@ return new db::MALYWriter (); + } + + virtual bool can_read () const + { + return true; + } + + virtual bool can_write () const + { + return false; + // @@@ return true; + } + + virtual tl::XMLElementBase *xml_reader_options_element () const + { + return new db::ReaderOptionsXMLElement ("mag", + tl::make_member (&db::MALYReaderOptions::dbu, "dbu") + /* @@@ + tl::make_member (&db::MALYReaderOptions::lambda, "lambda") + + tl::make_member (&db::MALYReaderOptions::layer_map, "layer-map") + + tl::make_member (&db::MALYReaderOptions::create_other_layers, "create-other-layers") + + tl::make_member (&db::MALYReaderOptions::keep_layer_names, "keep-layer-names") + + tl::make_member (&db::MALYReaderOptions::merge, "merge") + + tl::make_element, db::MALYReaderOptions> (&db::MALYReaderOptions::lib_paths, "lib-paths", + tl::make_member::const_iterator, std::vector > (&std::vector::begin, &std::vector::end, &std::vector::push_back, "lib-path") + ) + */ + ); + } + + /* @@@ + virtual tl::XMLElementBase *xml_writer_options_element () const + { + return new db::WriterOptionsXMLElement ("mag", + tl::make_member (&db::MALYWriterOptions::lambda, "lambda") + + tl::make_member (&db::MALYWriterOptions::tech, "tech") + + tl::make_member (&db::MALYWriterOptions::write_timestamp, "write-timestamp") + ); + } + @@@ */ +}; + +// NOTE: Because MALY has such a high degree of syntactic freedom, the detection is somewhat +// fuzzy: do MALY at the very end of the detection chain +static tl::RegisteredClass reader_decl (new MALYFormatDeclaration (), 2300, "MALY"); + +// provide a symbol to force linking against +int force_link_MALY = 0; + +} + + diff --git a/src/plugins/streamers/maly/db_plugin/dbMALY.h b/src/plugins/streamers/maly/db_plugin/dbMALY.h new file mode 100644 index 000000000..acd5f1777 --- /dev/null +++ b/src/plugins/streamers/maly/db_plugin/dbMALY.h @@ -0,0 +1,62 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2025 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_dbMALY +#define HDR_dbMALY + +#include "dbPoint.h" + +#include "tlException.h" +#include "tlInternational.h" +#include "tlString.h" +#include "tlAssert.h" + +#include +#include + +namespace db +{ + +/** + * @brief The diagnostics interface for reporting problems in the reader or writer + */ +class MALYDiagnostics +{ +public: + virtual ~MALYDiagnostics (); + + /** + * @brief Issue an error with positional information + */ + virtual void error (const std::string &txt) = 0; + + /** + * @brief Issue a warning with positional information + */ + virtual void warn (const std::string &txt, int warn_level) = 0; +}; + +} + +#endif + diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYFormat.h b/src/plugins/streamers/maly/db_plugin/dbMALYFormat.h new file mode 100644 index 000000000..e2e47b8cb --- /dev/null +++ b/src/plugins/streamers/maly/db_plugin/dbMALYFormat.h @@ -0,0 +1,162 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2025 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_dbMALYFormat +#define HDR_dbMALYFormat + +#include "dbSaveLayoutOptions.h" +#include "dbLoadLayoutOptions.h" +#include "dbPluginCommon.h" + +namespace db +{ + +/** + * @brief Structure that holds the MALY specific options for the reader + * NOTE: this structure is non-public linkage by intention. This way it's instantiated + * in all compile units and the shared object does not need to be linked. + */ +class DB_PLUGIN_PUBLIC MALYReaderOptions + : public FormatSpecificReaderOptions +{ +public: + /** + * @brief The constructor + */ + MALYReaderOptions () + : dbu (0.001), + create_other_layers (true) + { + // .. nothing yet .. + } + + /** + * @brief Specify the database unit to produce + * + * Specify the database unit which the resulting layout will receive. + */ + double dbu; + + /** + * @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 Implementation of FormatSpecificReaderOptions + */ + virtual FormatSpecificReaderOptions *clone () const + { + return new MALYReaderOptions (*this); + } + + /** + * @brief Implementation of FormatSpecificReaderOptions + */ + virtual const std::string &format_name () const + { + static const std::string n ("MALY"); + return n; + } +}; + +#if 0 // @@@ +/** + * @brief Structure that holds the MALY specific options for the Writer + * NOTE: this structure is non-public linkage by intention. This way it's instantiated + * in all compile units and the shared object does not need to be linked. + */ +class DB_PLUGIN_PUBLIC MALYWriterOptions + : public FormatSpecificWriterOptions +{ +public: + /** + * @brief The constructor + */ + MALYWriterOptions () + : lambda (0.0), write_timestamp (true) + { + // .. nothing yet .. + } + + /** + * @brief Specifies the lambda value for writing + * + * The lambda value is the basic scaling parameter. + * If this value is set to 0 or negative, the lambda value stored in the layout + * is used (meta data "lambda"). + */ + double lambda; + + /** + * @brief Specifies the technology value for writing Magic files + * + * If this value is set an empty string, the technology store in the layout's + * "technology" meta data is used. + */ + std::string tech; + + /** + * @brief A value indicating whether the real (true) or fake (false) timestamp is written + * + * A fake, static timestamp is useful for comparing files. + */ + bool write_timestamp; + + /** + * @brief Implementation of FormatSpecificWriterOptions + */ + virtual FormatSpecificWriterOptions *clone () const + { + return new MALYWriterOptions (*this); + } + + /** + * @brief Implementation of FormatSpecificWriterOptions + */ + virtual const std::string &format_name () const + { + static std::string n ("MALY"); + return n; + } +}; +#endif + +} + +#endif + diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc new file mode 100644 index 000000000..1d550ca9e --- /dev/null +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc @@ -0,0 +1,142 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2025 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 "dbMALYReader.h" +#include "dbStream.h" +#include "dbObjectWithProperties.h" +#include "dbArray.h" +#include "dbStatic.h" +#include "dbShapeProcessor.h" +#include "dbTechnology.h" + +#include "tlException.h" +#include "tlString.h" +#include "tlClassRegistry.h" +#include "tlFileUtils.h" +#include "tlUri.h" + +#include +#include + +namespace db +{ + +// --------------------------------------------------------------- +// MALYReader + + +MALYReader::MALYReader (tl::InputStream &s) + : m_stream (s), + m_progress (tl::to_string (tr ("Reading MALY file")), 1000), + m_dbu (0.001) +{ + m_progress.set_format (tl::to_string (tr ("%.0fk lines"))); + m_progress.set_format_unit (1000.0); + m_progress.set_unit (100000.0); +} + +MALYReader::~MALYReader () +{ + // .. nothing yet .. +} + +const LayerMap & +MALYReader::read (db::Layout &layout) +{ + return read (layout, db::LoadLayoutOptions ()); +} + +const LayerMap & +MALYReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) +{ + init (options); + + prepare_layers (layout); + + // @@@ + + finish_layers (layout); + return layer_map_out (); +} + +void +MALYReader::error (const std::string &msg) +{ + throw MALYReaderException (msg, m_stream.line_number (), m_stream.source ()); +} + +void +MALYReader::warn (const std::string &msg, int wl) +{ + if (warn_level () < wl) { + return; + } + + if (first_warning ()) { + tl::warn << tl::sprintf (tl::to_string (tr ("In file %s:")), m_stream.source ()); + } + + int ws = compress_warning (msg); + if (ws < 0) { + tl::warn << msg + << tl::to_string (tr (" (line=")) << m_stream.line_number () + << tl::to_string (tr (", file=")) << m_stream.source () + << ")"; + } else if (ws == 0) { + tl::warn << tl::to_string (tr ("... further warnings of this kind are not shown")); + } +} + +std::string +MALYReader::resolve_path (const std::string &path) +{ + tl::URI path_uri (path); + + if (tl::is_absolute (path_uri.path ())) { + + return path_uri.to_string (); + + } else { + + tl::URI source_uri (m_stream.source ()); + source_uri.set_path (tl::dirname (source_uri.path ())); + return source_uri.resolved (tl::URI (path)).to_string (); + + } +} + +void +MALYReader::do_read (db::Layout &layout, db::cell_index_type cell_index, tl::TextInputStream &stream) +{ + try { + + // @@@ + + } catch (tl::Exception &ex) { + error (ex.msg ()); + } +} + +} + diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.h b/src/plugins/streamers/maly/db_plugin/dbMALYReader.h new file mode 100644 index 000000000..f60f7ebb8 --- /dev/null +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.h @@ -0,0 +1,148 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2025 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_dbMALYReader +#define HDR_dbMALYReader + +#include "dbPluginCommon.h" +#include "dbNamedLayerReader.h" +#include "dbLayout.h" +#include "dbMALY.h" +#include "dbMALYFormat.h" +#include "dbStreamLayers.h" +#include "dbPropertiesRepository.h" + +#include "tlException.h" +#include "tlInternational.h" +#include "tlProgress.h" +#include "tlString.h" +#include "tlStream.h" + +#include +#include + +namespace db +{ + +class Technology; + +/** + * @brief Generic base class of MALY reader exceptions + */ +class DB_PLUGIN_PUBLIC MALYReaderException + : public ReaderException +{ +public: + MALYReaderException (const std::string &msg, size_t l, const std::string &file) + : ReaderException (tl::sprintf (tl::to_string (tr ("%s (line=%ld, file=%s)")), msg, l, file)) + { } +}; + +/** + * @brief The MALY format stream reader + */ +class DB_PLUGIN_PUBLIC MALYReader + : public NamedLayerReader, + public MALYDiagnostics +{ +public: + typedef std::vector property_value_list; + + /** + * @brief Construct a stream reader object + * + * @param s The stream delegate from which to read stream data from + */ + MALYReader (tl::InputStream &s); + + /** + * @brief Destructor + */ + ~MALYReader (); + + /** + * @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 MALY 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 "MALY"; } + + /** + * @brief Issue an error with positional information + * + * Reimplements MALYDiagnostics + */ + virtual void error (const std::string &txt); + + /** + * @brief Issue a warning with positional information + * + * Reimplements MALYDiagnostics + */ + virtual void warn (const std::string &txt, int wl = 1); + +private: + tl::TextInputStream m_stream; + tl::AbsoluteProgress m_progress; + double m_dbu; + + void do_read (db::Layout &layout, db::cell_index_type to_cell, tl::TextInputStream &stream); + std::string resolve_path(const std::string &path); +}; + +} + +#endif + diff --git a/src/plugins/streamers/maly/db_plugin/db_plugin.pro b/src/plugins/streamers/maly/db_plugin/db_plugin.pro new file mode 100644 index 000000000..60b947560 --- /dev/null +++ b/src/plugins/streamers/maly/db_plugin/db_plugin.pro @@ -0,0 +1,15 @@ + +TARGET = maly +DESTDIR = $$OUT_PWD/../../../../db_plugins + +include($$PWD/../../../db_plugin.pri) + +HEADERS = \ + dbMALY.h \ + dbMALYReader.h \ + dbMALYFormat.h \ + +SOURCES = \ + dbMALY.cc \ + dbMALYReader.cc \ + gsiDeclDbMALY.cc \ diff --git a/src/plugins/streamers/maly/db_plugin/gsiDeclDbMALY.cc b/src/plugins/streamers/maly/db_plugin/gsiDeclDbMALY.cc new file mode 100644 index 000000000..c9ebcd37e --- /dev/null +++ b/src/plugins/streamers/maly/db_plugin/gsiDeclDbMALY.cc @@ -0,0 +1,133 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2025 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 "dbMALY.h" +#include "dbMALYReader.h" +#include "dbLoadLayoutOptions.h" +#include "dbSaveLayoutOptions.h" +#include "gsiDecl.h" + +namespace gsi +{ + +// --------------------------------------------------------------- +// gsi Implementation of specific methods + +static void set_maly_dbu (db::LoadLayoutOptions *options, double dbu) +{ + options->get_options ().dbu = dbu; +} + +static double get_maly_dbu (const db::LoadLayoutOptions *options) +{ + return options->get_options ().dbu; +} + +static void set_layer_map (db::LoadLayoutOptions *options, const db::LayerMap &lm, bool f) +{ + options->get_options ().layer_map = lm; + options->get_options ().create_other_layers = f; +} + +static void set_layer_map1 (db::LoadLayoutOptions *options, const db::LayerMap &lm) +{ + options->get_options ().layer_map = lm; +} + +static db::LayerMap &get_layer_map (db::LoadLayoutOptions *options) +{ + return options->get_options ().layer_map; +} + +static void select_all_layers (db::LoadLayoutOptions *options) +{ + options->get_options ().layer_map = db::LayerMap (); + options->get_options ().create_other_layers = true; +} + +static bool create_other_layers (const db::LoadLayoutOptions *options) +{ + return options->get_options ().create_other_layers; +} + +static void set_create_other_layers (db::LoadLayoutOptions *options, bool l) +{ + options->get_options ().create_other_layers = l; +} + +// extend lay::LoadLayoutOptions with the MALY options +static +gsi::ClassExt maly_reader_options ( + gsi::method_ext ("maly_set_layer_map", &set_layer_map, gsi::arg ("map"), gsi::arg ("create_other_layers"), + "@brief Sets the layer map\n" + "This sets a layer mapping for the reader. The layer map allows selection and translation of the original layers, for example to assign layer/datatype numbers to the named layers.\n" + "@param map The layer map to set.\n" + "@param create_other_layers The flag indicating whether other layers will be created as well. Set to false to read only the layers in the layer map.\n" + "\n" + "This method has been added in version 0.26.2." + ) + + gsi::method_ext ("maly_layer_map=", &set_layer_map1, gsi::arg ("map"), + "@brief Sets the layer map\n" + "This sets a layer mapping for the reader. Unlike \\maly_set_layer_map, the 'create_other_layers' flag is not changed.\n" + "@param map The layer map to set.\n" + "\n" + "This method has been added in version 0.26.2." + ) + + gsi::method_ext ("maly_select_all_layers", &select_all_layers, + "@brief Selects all layers and disables the layer map\n" + "\n" + "This disables any layer map and enables reading of all layers.\n" + "New layers will be created when required.\n" + "\n" + "This method has been added in version 0.26.2." + ) + + gsi::method_ext ("maly_layer_map", &get_layer_map, + "@brief Gets the layer map\n" + "@return A reference to the layer map\n" + "\n" + "This method has been added in version 0.26.2." + ) + + gsi::method_ext ("maly_create_other_layers?", &create_other_layers, + "@brief Gets a value indicating whether other layers shall be created\n" + "@return True, if other layers will be created.\n" + "This attribute acts together with a layer map (see \\maly_layer_map=). Layers not listed in this map are created as well when " + "\\maly_create_other_layers? is true. Otherwise they are ignored.\n" + "\n" + "This method has been added in version 0.26.2." + ) + + gsi::method_ext ("maly_create_other_layers=", &set_create_other_layers, gsi::arg ("create"), + "@brief Specifies whether other layers shall be created\n" + "@param create True, if other layers will be created.\n" + "See \\maly_create_other_layers? for a description of this attribute.\n" + "\n" + "This method has been added in version 0.26.2." + ) + + gsi::method_ext ("maly_dbu", &get_maly_dbu, + "@brief Specifies the database unit which the reader uses and produces\n" + "See \\maly_dbu= method for a description of this property.\n" + "\nThis property has been added in version 0.26.2.\n" + ), + "" +); + +} + diff --git a/src/plugins/streamers/maly/lay_plugin/MALYReaderOptionPage.ui b/src/plugins/streamers/maly/lay_plugin/MALYReaderOptionPage.ui new file mode 100644 index 000000000..46ec332d2 --- /dev/null +++ b/src/plugins/streamers/maly/lay_plugin/MALYReaderOptionPage.ui @@ -0,0 +1,183 @@ + + + MALYReaderOptionPage + + + + 0 + 0 + 584 + 530 + + + + Form + + + + + + Input Options + + + + 9 + + + 9 + + + 9 + + + 9 + + + 6 + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Micron + + + + + + + Database unit + + + + + + + This is the database unit of the resulting layout. Mask pattern with a different grid are adapted to this database unit through scaling. + + + true + + + + + + + + + + + 1 + 1 + + + + + + + Layer Subset And Layer Mapping + + + false + + + + 9 + + + 9 + + + 9 + + + 9 + + + 6 + + + + + Read all layers (additionally to the ones in the mapping table) + + + + + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + + + + + + + + lay::LayerMappingWidget + QFrame +
layLayerMappingWidget.h
+ 1 + + enable_all_layers(bool) + +
+
+ + dbu_le + read_all_cbx + + + + + layer_map + enable_all_layers(bool) + read_all_cbx + setChecked(bool) + + + 122 + 186 + + + 109 + 147 + + + + +
diff --git a/src/plugins/streamers/maly/lay_plugin/layMALYReaderPlugin.cc b/src/plugins/streamers/maly/lay_plugin/layMALYReaderPlugin.cc new file mode 100644 index 000000000..c606f8a92 --- /dev/null +++ b/src/plugins/streamers/maly/lay_plugin/layMALYReaderPlugin.cc @@ -0,0 +1,110 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2025 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 "dbMALY.h" +#include "dbMALYReader.h" +#include "dbLoadLayoutOptions.h" +#include "layMALYReaderPlugin.h" +#include "ui_MALYReaderOptionPage.h" +#include "gsiDecl.h" + +#include +#include + +namespace lay +{ + +// --------------------------------------------------------------- +// MALYReaderOptionPage definition and implementation + +MALYReaderOptionPage::MALYReaderOptionPage (QWidget *parent) + : StreamReaderOptionsPage (parent) +{ + mp_ui = new Ui::MALYReaderOptionPage (); + mp_ui->setupUi (this); +} + +MALYReaderOptionPage::~MALYReaderOptionPage () +{ + delete mp_ui; + mp_ui = 0; +} + +void +MALYReaderOptionPage::setup (const db::FormatSpecificReaderOptions *o, const db::Technology * /*tech*/) +{ + static const db::MALYReaderOptions default_options; + const db::MALYReaderOptions *options = dynamic_cast (o); + if (!options) { + options = &default_options; + } + + mp_ui->dbu_le->setText (tl::to_qstring (tl::to_string (options->dbu))); + mp_ui->layer_map->set_layer_map (options->layer_map); + mp_ui->read_all_cbx->setChecked (options->create_other_layers); +} + +void +MALYReaderOptionPage::commit (db::FormatSpecificReaderOptions *o, const db::Technology * /*tech*/) +{ + db::MALYReaderOptions *options = dynamic_cast (o); + if (options) { + + tl::from_string_ext (tl::to_string (mp_ui->dbu_le->text ()), options->dbu); + if (options->dbu > 1000.0 || options->dbu < 1e-9) { + throw tl::Exception (tl::to_string (QObject::tr ("Invalid value for database unit"))); + } + + options->layer_map = mp_ui->layer_map->get_layer_map (); + options->create_other_layers = mp_ui->read_all_cbx->isChecked (); + + } +} + +// --------------------------------------------------------------- +// MALYReaderPluginDeclaration definition and implementation + +class MALYReaderPluginDeclaration + : public StreamReaderPluginDeclaration +{ +public: + MALYReaderPluginDeclaration () + : StreamReaderPluginDeclaration (db::MALYReaderOptions ().format_name ()) + { + // .. nothing yet .. + } + + StreamReaderOptionsPage *format_specific_options_page (QWidget *parent) const + { + return new MALYReaderOptionPage (parent); + } + + db::FormatSpecificReaderOptions *create_specific_options () const + { + return new db::MALYReaderOptions (); + } +}; + +static tl::RegisteredClass plugin_decl (new lay::MALYReaderPluginDeclaration (), 10000, "MALYReader"); + +} + diff --git a/src/plugins/streamers/maly/lay_plugin/layMALYReaderPlugin.h b/src/plugins/streamers/maly/lay_plugin/layMALYReaderPlugin.h new file mode 100644 index 000000000..9de96c41a --- /dev/null +++ b/src/plugins/streamers/maly/lay_plugin/layMALYReaderPlugin.h @@ -0,0 +1,59 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2025 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_layMALYReaderPlugin_h +#define HDR_layMALYReaderPlugin_h + +#include "layStream.h" +#include + +namespace Ui +{ + class MALYReaderOptionPage; +} + +namespace lay +{ + +class MALYReaderOptionPage + : public StreamReaderOptionsPage +{ +Q_OBJECT + +public: + MALYReaderOptionPage (QWidget *parent); + ~MALYReaderOptionPage (); + + void setup (const db::FormatSpecificReaderOptions *options, const db::Technology *tech); + void commit (db::FormatSpecificReaderOptions *options, const db::Technology *tech); + +private: + Ui::MALYReaderOptionPage *mp_ui; +}; + +} + +#endif + + diff --git a/src/plugins/streamers/maly/lay_plugin/lay_plugin.pro b/src/plugins/streamers/maly/lay_plugin/lay_plugin.pro new file mode 100644 index 000000000..0677a2552 --- /dev/null +++ b/src/plugins/streamers/maly/lay_plugin/lay_plugin.pro @@ -0,0 +1,22 @@ + +TARGET = maly_ui +DESTDIR = $$OUT_PWD/../../../../lay_plugins + +include($$PWD/../../../lay_plugin.pri) + +INCLUDEPATH += $$PWD/../db_plugin +DEPENDPATH += $$PWD/../db_plugin +LIBS += -L$$DESTDIR/../db_plugins -lmaly + +!isEmpty(RPATH) { + QMAKE_RPATHDIR += $$RPATH/db_plugins +} + +HEADERS = \ + layMALYReaderPlugin.h \ + +SOURCES = \ + layMALYReaderPlugin.cc \ + +FORMS = \ + MALYReaderOptionPage.ui \ diff --git a/src/plugins/streamers/maly/maly.pro b/src/plugins/streamers/maly/maly.pro new file mode 100644 index 000000000..0a2501ae9 --- /dev/null +++ b/src/plugins/streamers/maly/maly.pro @@ -0,0 +1,10 @@ + +TEMPLATE = subdirs + +SUBDIRS = db_plugin unit_tests +unit_tests.depends += db_plugin + +!equals(HAVE_QT, "0") { + SUBDIRS += lay_plugin + lay_plugin.depends += db_plugin +} diff --git a/src/plugins/streamers/maly/unit_tests/dbMALYReader.cc b/src/plugins/streamers/maly/unit_tests/dbMALYReader.cc new file mode 100644 index 000000000..d43dbe0cc --- /dev/null +++ b/src/plugins/streamers/maly/unit_tests/dbMALYReader.cc @@ -0,0 +1,108 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2025 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 "dbMALYReader.h" +#include "dbLayoutDiff.h" +#include "dbWriter.h" +#include "tlUnitTest.h" + +#include + +static void run_test (tl::TestBase *_this, const std::string &base, const char *file, const char *file_au, const char *map = 0, double lambda = 0.1, double dbu = 0.001, const std::vector *lib_paths = 0) +{ + db::MALYReaderOptions *opt = new db::MALYReaderOptions(); + opt->dbu = dbu; + + db::LayerMap lm; + if (map) { + 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); + ex.test (","); + lm.map (n, ln++, db::LayerProperties (l, 0)); + } + opt->layer_map = lm; + opt->create_other_layers = true; + } + + db::LoadLayoutOptions options; + options.set_options (opt); + + db::Manager m (false); + db::Layout layout (&m), layout2 (&m), layout2_mag (&m), layout_au (&m); + + { + std::string fn (base); + fn += "/maly/"; + fn += file; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (layout, options); + } + + std::string tc_name = layout.cell_name (*layout.begin_top_down ()); + + // normalize the layout by writing to OASIS and reading from .. + + std::string tmp_oas_file = _this->tmp_file (tl::sprintf ("%s.oas", tc_name)); + std::string tmp_maly_file = _this->tmp_file (tl::sprintf ("%s.mag", tc_name)); + + { + tl::OutputStream stream (tmp_oas_file); + db::SaveLayoutOptions options; + options.set_format ("OASIS"); + db::Writer writer (options); + writer.write (layout, stream); + } + + { + tl::InputStream stream (tmp_oas_file); + db::Reader reader (stream); + reader.read (layout2); + } + + { + std::string fn (base); + fn += "/maly/"; + fn += file_au; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (layout_au); + } + + bool equal = db::compare_layouts (layout2, layout_au, db::layout_diff::f_boxes_as_polygons | db::layout_diff::f_verbose | db::layout_diff::f_flatten_array_insts, 1); + if (! equal) { + _this->raise (tl::sprintf ("Compare failed after reading - see %s vs %s\n", tmp_oas_file, file_au)); + } +} + +TEST(1) +{ + run_test (_this, tl::testdata (), "MALY_TEST.maly", "mag_test_au.oas"); +} + diff --git a/src/plugins/streamers/maly/unit_tests/unit_tests.pro b/src/plugins/streamers/maly/unit_tests/unit_tests.pro new file mode 100644 index 000000000..7a6319ee6 --- /dev/null +++ b/src/plugins/streamers/maly/unit_tests/unit_tests.pro @@ -0,0 +1,19 @@ + +DESTDIR_UT = $$OUT_PWD/../../../.. + +TARGET = maly_tests + +include($$PWD/../../../../lib_ut.pri) + +SOURCES = \ + dbMALYReader.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 + +LIBS += -L$$DESTDIR_UT -lklayout_db -lklayout_tl -lklayout_gsi + +PLUGINPATH = $$OUT_PWD/../../../../db_plugins +QMAKE_RPATHDIR += $$PLUGINPATH + +LIBS += -L$$PLUGINPATH -lmaly From f1b35d08261b3bbc9c954d8a099be8ebe55bc462 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 27 Apr 2025 16:56:46 +0200 Subject: [PATCH 02/15] WIP (MALY reader) --- src/plugins/streamers/maly/db_plugin/dbMALY.h | 201 ++++++++++++++++++ .../streamers/maly/db_plugin/gsiDeclDbMALY.cc | 27 ++- 2 files changed, 221 insertions(+), 7 deletions(-) diff --git a/src/plugins/streamers/maly/db_plugin/dbMALY.h b/src/plugins/streamers/maly/db_plugin/dbMALY.h index acd5f1777..c4f81e8f4 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALY.h +++ b/src/plugins/streamers/maly/db_plugin/dbMALY.h @@ -25,6 +25,8 @@ #define HDR_dbMALY #include "dbPoint.h" +#include "dbTrans.h" +#include "dbBox.h" #include "tlException.h" #include "tlInternational.h" @@ -56,6 +58,205 @@ public: virtual void warn (const std::string &txt, int warn_level) = 0; }; +/** + * @brief A class representing a title field on a mask + */ +class MALYTitle +{ +public: + /** + * @brief Default constructor + */ + MALYTitle () + : width (0.0), height (0.0), pitch (0.0), type (String), font (Standard) + { } + + /** + * @brief The type of the title + */ + enum Type + { + String = 0, // A user-defined string + Date = 1, // The date + Serial = 2 // A serial number + }; + + /** + * @brief The font to be used + */ + enum Font + { + Standard = 0, // Standard font + Native = 1 // Native tool font + }; + + /** + * @brief The string for "String" type + */ + std::string string; + + /** + * @brief The transformation of the title + * + * The origin of the title is supposed to be in the center of + * the title field. + */ + db::DTrans transformation; + + /** + * @brief Optional font parameters: character width + */ + double width; + + /** + * @brief Optional font parameters: character height + */ + double height; + + /** + * @brief Optional font parameters: character pitch + */ + double pitch; + + /** + * @brief The type of the title + */ + Type type; + + /** + * @brief The font to be used + */ + Font font; +}; + +/** + * @brief A class representing a structure (pattern) on a mask + */ +class MALYStructure +{ + /** + * @brief Default constructor + */ + MALYStructure () + : nx (1), ny (1), dx (0.0), dy (0.0), layer (-1) + { } + + /** + * @brief The (expanded) path of the pattern file + */ + std::string path; + + /** + * @brief The name of the top cell + * If empty, the topcell is determined automatically + */ + std::string topcell; + + /** + * @brief The pattern window in the original file + */ + db::DBox size; + + /** + * @brief The transformation needed to place the original file + */ + db::DCplxTrans transformation; + + /** + * @brief The number of placements in x direction + */ + int nx; + + /** + * @brief The number of placements in y direction + */ + int ny; + + /** + * @brief The placement pitch in x direction (if nx > 1) + */ + double dx; + + /** + * @brief The placement pitch in y direction (if ny > 1) + */ + double dy; + + /** + * @brief The design name + */ + std::string dname; + + /** + * @brief The name for the mask process + */ + std::string mname; + + /** + * @brief The name for the mask tool + */ + std::string ename; + + /** + * @brief The layer used from the OASIS file + * + * A value of -1 means "all". + */ + int layer; +}; + +/** + * @brief A class representing one mask + */ +class MALYMask +{ + /** + * @brief Default constructor + */ + MALYMask () + : size_um (0.0) + { } + + /** + * @brief Size of the mask in micrometers + */ + double size_um; + + /** + * @brief Name of the mask + * + * This is also the name of the layer generated + */ + std::string name; + + /** + * @brief The list of structures + */ + std::list structures; + + /** + * @brief The list of titles + */ + std::list titles; +}; + +/** + * @brief A class representing the MALY file + */ +class MALYData +{ + /** + * @brief Default constructor + */ + MALYData () + { } + + /** + * @brief The masks defined by the file + */ + std::list masks; +}; + } #endif diff --git a/src/plugins/streamers/maly/db_plugin/gsiDeclDbMALY.cc b/src/plugins/streamers/maly/db_plugin/gsiDeclDbMALY.cc index c9ebcd37e..fa2a9cdcb 100644 --- a/src/plugins/streamers/maly/db_plugin/gsiDeclDbMALY.cc +++ b/src/plugins/streamers/maly/db_plugin/gsiDeclDbMALY.cc @@ -83,14 +83,18 @@ gsi::ClassExt maly_reader_options ( "@param map The layer map to set.\n" "@param create_other_layers The flag indicating whether other layers will be created as well. Set to false to read only the layers in the layer map.\n" "\n" - "This method has been added in version 0.26.2." + "Layer maps can also be used to map the named MALY mask layers to GDS layer/datatypes.\n" + "\n" + "This method has been added in version 0.30.2." ) + gsi::method_ext ("maly_layer_map=", &set_layer_map1, gsi::arg ("map"), "@brief Sets the layer map\n" "This sets a layer mapping for the reader. Unlike \\maly_set_layer_map, the 'create_other_layers' flag is not changed.\n" "@param map The layer map to set.\n" "\n" - "This method has been added in version 0.26.2." + "Layer maps can also be used to map the named MALY mask layers to GDS layer/datatypes.\n" + "\n" + "This method has been added in version 0.30.2." ) + gsi::method_ext ("maly_select_all_layers", &select_all_layers, "@brief Selects all layers and disables the layer map\n" @@ -98,13 +102,13 @@ gsi::ClassExt maly_reader_options ( "This disables any layer map and enables reading of all layers.\n" "New layers will be created when required.\n" "\n" - "This method has been added in version 0.26.2." + "This method has been added in version 0.30.2." ) + gsi::method_ext ("maly_layer_map", &get_layer_map, "@brief Gets the layer map\n" "@return A reference to the layer map\n" "\n" - "This method has been added in version 0.26.2." + "This method has been added in version 0.30.2." ) + gsi::method_ext ("maly_create_other_layers?", &create_other_layers, "@brief Gets a value indicating whether other layers shall be created\n" @@ -112,19 +116,28 @@ gsi::ClassExt maly_reader_options ( "This attribute acts together with a layer map (see \\maly_layer_map=). Layers not listed in this map are created as well when " "\\maly_create_other_layers? is true. Otherwise they are ignored.\n" "\n" - "This method has been added in version 0.26.2." + "This method has been added in version 0.30.2." ) + gsi::method_ext ("maly_create_other_layers=", &set_create_other_layers, gsi::arg ("create"), "@brief Specifies whether other layers shall be created\n" "@param create True, if other layers will be created.\n" "See \\maly_create_other_layers? for a description of this attribute.\n" "\n" - "This method has been added in version 0.26.2." + "This method has been added in version 0.30.2." + ) + + gsi::method_ext ("maly_dbu=", &set_maly_dbu, gsi::arg ("dbu"), + "@brief Specifies the database unit which the reader uses and produces\n" + "The database unit is the final resolution of the produced layout. This physical resolution is usually " + "defined by the layout system - GDS for example typically uses 1nm (maly_dbu=0.001).\n" + "All geometry in the MALY pattern files is brought to the database unit by scaling.\n" + "\n" + "This method has been added in version 0.30.2." ) + gsi::method_ext ("maly_dbu", &get_maly_dbu, "@brief Specifies the database unit which the reader uses and produces\n" "See \\maly_dbu= method for a description of this property.\n" - "\nThis property has been added in version 0.26.2.\n" + "\n" + "This method has been added in version 0.30.2." ), "" ); From e76be5b071256239ef89bcfcb1fd6c9df1711b98 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 27 Apr 2025 20:55:11 +0200 Subject: [PATCH 03/15] WIP --- .../streamers/maly/db_plugin/dbMALY.cc | 28 +--- src/plugins/streamers/maly/db_plugin/dbMALY.h | 3 + .../streamers/maly/db_plugin/dbMALYReader.cc | 139 ++++++++++++++++++ .../streamers/maly/db_plugin/dbMALYReader.h | 12 +- .../{dbMALYReader.cc => dbMALYReaderTests.cc} | 6 +- .../streamers/maly/unit_tests/unit_tests.pro | 2 +- testdata/maly/MALY_TEST.maly | 15 ++ 7 files changed, 176 insertions(+), 29 deletions(-) rename src/plugins/streamers/maly/unit_tests/{dbMALYReader.cc => dbMALYReaderTests.cc} (92%) create mode 100644 testdata/maly/MALY_TEST.maly diff --git a/src/plugins/streamers/maly/db_plugin/dbMALY.cc b/src/plugins/streamers/maly/db_plugin/dbMALY.cc index 57d67e416..b53b4b449 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALY.cc +++ b/src/plugins/streamers/maly/db_plugin/dbMALY.cc @@ -57,7 +57,8 @@ public: virtual bool detect (tl::InputStream &s) const { - return false; // @@@ + db::MALYReader reader (s); + return reader.test (); } virtual ReaderBase *create_reader (tl::InputStream &s) const @@ -68,7 +69,6 @@ public: virtual WriterBase *create_writer () const { return 0; - // @@@ return new db::MALYWriter (); } virtual bool can_read () const @@ -79,36 +79,16 @@ public: virtual bool can_write () const { return false; - // @@@ return true; } virtual tl::XMLElementBase *xml_reader_options_element () const { return new db::ReaderOptionsXMLElement ("mag", - tl::make_member (&db::MALYReaderOptions::dbu, "dbu") - /* @@@ - tl::make_member (&db::MALYReaderOptions::lambda, "lambda") + + tl::make_member (&db::MALYReaderOptions::dbu, "dbu") + tl::make_member (&db::MALYReaderOptions::layer_map, "layer-map") + - tl::make_member (&db::MALYReaderOptions::create_other_layers, "create-other-layers") + - tl::make_member (&db::MALYReaderOptions::keep_layer_names, "keep-layer-names") + - tl::make_member (&db::MALYReaderOptions::merge, "merge") + - tl::make_element, db::MALYReaderOptions> (&db::MALYReaderOptions::lib_paths, "lib-paths", - tl::make_member::const_iterator, std::vector > (&std::vector::begin, &std::vector::end, &std::vector::push_back, "lib-path") - ) - */ + tl::make_member (&db::MALYReaderOptions::create_other_layers, "create-other-layers") ); } - - /* @@@ - virtual tl::XMLElementBase *xml_writer_options_element () const - { - return new db::WriterOptionsXMLElement ("mag", - tl::make_member (&db::MALYWriterOptions::lambda, "lambda") + - tl::make_member (&db::MALYWriterOptions::tech, "tech") + - tl::make_member (&db::MALYWriterOptions::write_timestamp, "write-timestamp") - ); - } - @@@ */ }; // NOTE: Because MALY has such a high degree of syntactic freedom, the detection is somewhat diff --git a/src/plugins/streamers/maly/db_plugin/dbMALY.h b/src/plugins/streamers/maly/db_plugin/dbMALY.h index c4f81e8f4..ec904e969 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALY.h +++ b/src/plugins/streamers/maly/db_plugin/dbMALY.h @@ -134,6 +134,7 @@ public: */ class MALYStructure { +public: /** * @brief Default constructor */ @@ -210,6 +211,7 @@ class MALYStructure */ class MALYMask { +public: /** * @brief Default constructor */ @@ -245,6 +247,7 @@ class MALYMask */ class MALYData { +public: /** * @brief Default constructor */ diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc index 1d550ca9e..2352fe8ed 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc @@ -61,6 +61,22 @@ MALYReader::~MALYReader () // .. nothing yet .. } +bool +MALYReader::test () +{ + return true; // @@@ + try { + + std::string rec = read_record (); + + tl::Extractor ex (rec.c_str ()); + return ex.test ("BEGIN") && ex.test ("MALY"); + + } catch (...) { + return false; + } +} + const LayerMap & MALYReader::read (db::Layout &layout) { @@ -74,12 +90,135 @@ MALYReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) prepare_layers (layout); + const db::MALYReaderOptions &specific_options = options.get_options (); + m_dbu = specific_options.dbu; + + set_layer_map (specific_options.layer_map); + set_create_layers (specific_options.create_other_layers); + // @@@ set_keep_layer_names (specific_options.keep_layer_names); + set_keep_layer_names (true); + + MALYData data = read_maly_file (); + // @@@ finish_layers (layout); return layer_map_out (); } +std::string +MALYReader::read_record () +{ + while (! m_stream.at_end ()) { + std::string r = read_record_internal (); + tl::Extractor ex (r.c_str ()); + if (ex.test ("+")) { + error (tl::to_string (tr ("'+' character past first column - did you mean to continue a line?"))); + } else if (! ex.at_end ()) { + return r; + } + } + + return std::string (); +} + +std::string +MALYReader::read_record_internal () +{ + std::string rec; + + while (! m_stream.at_end ()) { + + char c = m_stream.get_char (); + + // skip comments + if (c == '/') { + char cc = m_stream.peek_char (); + if (cc == '/') { + while (! m_stream.at_end () && (c = m_stream.get_char ()) != '\n') + ; + if (m_stream.at_end ()) { + break; + } + } else if (cc == '*') { + m_stream.get_char (); // eat leading "*" + while (! m_stream.at_end () && (m_stream.get_char () != '*' || m_stream.peek_char () != '/')) + ; + if (m_stream.at_end ()) { + error (tl::to_string (tr ("/*...*/ comment not closed"))); + } + m_stream.get_char (); // eat trailing "/" + if (m_stream.at_end ()) { + break; + } + c = m_stream.get_char (); + } + } + + if (c == '\n') { + if (m_stream.peek_char () == '+') { + // continuation line + m_stream.get_char (); // eat "+" + if (m_stream.at_end ()) { + break; + } + c = m_stream.get_char (); + } else { + break; + } + } + + if (c == '"' || c == '\'') { + + rec += c; + + // skip quoted string + char quote = c; + while (! m_stream.at_end ()) { + c = m_stream.get_char (); + rec += c; + if (c == quote) { + quote = 0; + break; + } else if (c == '\\') { + if (m_stream.at_end ()) { + error (tl::to_string (tr ("Unexpected end of file inside quotee string"))); + } + c = m_stream.get_char (); + rec += c; + } else if (c == '\n') { + error (tl::to_string (tr ("Line break inside quoted string"))); + } + } + + if (quote) { + error (tl::to_string (tr ("Unexpected end of file inside quotee string"))); + } + + } else { + rec += c; + } + + } + + return rec; +} + +MALYData +MALYReader::read_maly_file () +{ + // @@@ + std::cout << "@@@ BEGIN_MALY" << std::endl; + std::string rec; + while (! (rec = read_record ()).empty ()) { + std::cout << rec << std::endl; + } + std::cout << "@@@ END_MALY" << std::endl; + // @@@ + + return MALYData (); // @@@ +} + void MALYReader::error (const std::string &msg) { diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.h b/src/plugins/streamers/maly/db_plugin/dbMALYReader.h index f60f7ebb8..981d3419a 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.h +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.h @@ -76,11 +76,18 @@ public: */ MALYReader (tl::InputStream &s); - /** + /** * @brief Destructor */ ~MALYReader (); + /** + * @brief Tests, if the stream is a valid MALY file + * + * This method can be used for the format detection + */ + bool test (); + /** * @brief The basic read method * @@ -140,6 +147,9 @@ private: void do_read (db::Layout &layout, db::cell_index_type to_cell, tl::TextInputStream &stream); std::string resolve_path(const std::string &path); + MALYData read_maly_file (); + std::string read_record (); + std::string read_record_internal (); }; } diff --git a/src/plugins/streamers/maly/unit_tests/dbMALYReader.cc b/src/plugins/streamers/maly/unit_tests/dbMALYReaderTests.cc similarity index 92% rename from src/plugins/streamers/maly/unit_tests/dbMALYReader.cc rename to src/plugins/streamers/maly/unit_tests/dbMALYReaderTests.cc index d43dbe0cc..cb3f749c3 100644 --- a/src/plugins/streamers/maly/unit_tests/dbMALYReader.cc +++ b/src/plugins/streamers/maly/unit_tests/dbMALYReaderTests.cc @@ -28,7 +28,7 @@ #include -static void run_test (tl::TestBase *_this, const std::string &base, const char *file, const char *file_au, const char *map = 0, double lambda = 0.1, double dbu = 0.001, const std::vector *lib_paths = 0) +static void run_test (tl::TestBase *_this, const std::string &base, const char *file, const char *file_au, const char *map = 0, double dbu = 0.001) { db::MALYReaderOptions *opt = new db::MALYReaderOptions(); opt->dbu = dbu; @@ -54,7 +54,7 @@ static void run_test (tl::TestBase *_this, const std::string &base, const char * options.set_options (opt); db::Manager m (false); - db::Layout layout (&m), layout2 (&m), layout2_mag (&m), layout_au (&m); + db::Layout layout (&m), layout2 (&m), layout_au (&m); { std::string fn (base); @@ -65,12 +65,12 @@ static void run_test (tl::TestBase *_this, const std::string &base, const char * reader.read (layout, options); } + tl_assert (layout.begin_top_down () != layout.end_top_down ()); std::string tc_name = layout.cell_name (*layout.begin_top_down ()); // normalize the layout by writing to OASIS and reading from .. std::string tmp_oas_file = _this->tmp_file (tl::sprintf ("%s.oas", tc_name)); - std::string tmp_maly_file = _this->tmp_file (tl::sprintf ("%s.mag", tc_name)); { tl::OutputStream stream (tmp_oas_file); diff --git a/src/plugins/streamers/maly/unit_tests/unit_tests.pro b/src/plugins/streamers/maly/unit_tests/unit_tests.pro index 7a6319ee6..a9d89c591 100644 --- a/src/plugins/streamers/maly/unit_tests/unit_tests.pro +++ b/src/plugins/streamers/maly/unit_tests/unit_tests.pro @@ -6,7 +6,7 @@ TARGET = maly_tests include($$PWD/../../../../lib_ut.pri) SOURCES = \ - dbMALYReader.cc \ + dbMALYReaderTests.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 diff --git a/testdata/maly/MALY_TEST.maly b/testdata/maly/MALY_TEST.maly new file mode 100644 index 000000000..0fd08fc48 --- /dev/null +++ b/testdata/maly/MALY_TEST.maly @@ -0,0 +1,15 @@ + +// a comment + +BEGIN /* a multiline comment + + +*/ MALY + +// a comment + +SREF " \"// /*hello*/ " SIZE ++ 10,10 + + + From cd468d4d67501dcdc57121a1292f03dc5a3d12ec Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 27 Apr 2025 23:00:46 +0200 Subject: [PATCH 04/15] WIP --- .../streamers/maly/db_plugin/dbMALYReader.cc | 464 +++++++++++++++++- .../streamers/maly/db_plugin/dbMALYReader.h | 19 +- testdata/maly/MALY_TEST.maly | 52 +- 3 files changed, 502 insertions(+), 33 deletions(-) diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc index 2352fe8ed..aa5e19a20 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc @@ -43,8 +43,82 @@ namespace db { // --------------------------------------------------------------- -// MALYReader +// Some helper structures to collect data +struct MALYReaderTitleSpec +{ + MALYReaderTitleSpec () + : enabled (false), width (1.0), height (1.0), pitch (1.0) + { } + + bool enabled; + db::DTrans trans; + double width, height, pitch; +}; + +struct MALYReaderTitleData +{ + MALYReaderTitleData () + { } + + MALYReaderTitleSpec date_spec; + MALYReaderTitleSpec serial_spec; + std::list > string_titles; +}; + +struct MALYReaderParametersData +{ + MALYReaderParametersData () + : base (Center), array_base (Center), masksize (0.0), maskmirror (false), font (MALYTitle::Standard) + { } + + enum Base + { + Origin, + Center, + LowerLeft + }; + + Base base; + Base array_base; + double masksize; + bool maskmirror; + MALYTitle::Font font; + std::list > roots; +}; + +struct MALYReaderStrRefData +{ + MALYReaderStrRefData () + : layer (-1), scale (1.0), nx (1), ny (1), dx (0.0), dy (0.0) + { } + + std::string file; + std::string name; + int layer; + db::DVector org; + db::DBox size; + double scale; + int nx, ny; + double dx, dy; +}; + +struct MALYReaderStrGroupData +{ + std::string name; + std::list refs; +}; + +struct MALYReaderMaskData +{ + MALYReaderParametersData parameters; + MALYReaderTitleData title; + std::list strgroups; +}; + + +// --------------------------------------------------------------- +// MALYReader MALYReader::MALYReader (tl::InputStream &s) : m_stream (s), @@ -64,12 +138,9 @@ MALYReader::~MALYReader () bool MALYReader::test () { - return true; // @@@ try { - std::string rec = read_record (); - - tl::Extractor ex (rec.c_str ()); + tl::Extractor ex = read_record (); return ex.test ("BEGIN") && ex.test ("MALY"); } catch (...) { @@ -106,20 +177,31 @@ MALYReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) return layer_map_out (); } -std::string +void +MALYReader::unget_record () +{ + m_record_returned = m_record; +} + +tl::Extractor MALYReader::read_record () { + if (! m_record_returned.empty ()) { + m_record = m_record_returned; + return tl::Extractor (m_record.c_str ()); + } + while (! m_stream.at_end ()) { - std::string r = read_record_internal (); - tl::Extractor ex (r.c_str ()); + m_record = read_record_internal (); + tl::Extractor ex (m_record.c_str ()); if (ex.test ("+")) { error (tl::to_string (tr ("'+' character past first column - did you mean to continue a line?"))); } else if (! ex.at_end ()) { - return r; + return ex; } } - return std::string (); + return tl::Extractor (); } std::string @@ -207,16 +289,362 @@ MALYReader::read_record_internal () MALYData MALYReader::read_maly_file () { - // @@@ - std::cout << "@@@ BEGIN_MALY" << std::endl; - std::string rec; - while (! (rec = read_record ()).empty ()) { - std::cout << rec << std::endl; + MALYData data; + try { + do_read_maly_file (data); + } catch (tl::Exception &ex) { + error (ex.msg ()); } - std::cout << "@@@ END_MALY" << std::endl; - // @@@ + return data; +} - return MALYData (); // @@@ +void +MALYReader::extract_title_trans (tl::Extractor &ex, MALYReaderTitleSpec &spec) +{ + double x = 0.0, y = 0.0; + bool ymirror = false; + int rot = 0; + + ex.read (x); + ex.read (y); + + if (ex.test ("SIZE")) { + ex.read (spec.width); + ex.read (spec.height); + ex.read (spec.pitch); + } + + if (ex.test ("MIRROR")) { + if (ex.test ("Y")) { + ymirror = true; + } else if (ex.test ("OFF")) { // @@@ + ymirror = false; + } else { + error (tl::to_string (tr ("Expected 'Y' or 'OFF' for MIRROR spec"))); + } + } + + if (ex.test ("ROTATE")) { + unsigned int a = 0; + ex.read (a); + rot = (a / 90) % 4; + } + + spec.trans = db::DTrans (rot, ymirror, db::DVector (x, y)); +} + +static +MALYReaderParametersData::Base string_to_base (const std::string &string) +{ + if (string == "ORIGIN") { + return MALYReaderParametersData::Origin; + } else if (string == "LOWERLEFT") { // @@@? + return MALYReaderParametersData::LowerLeft; + } else if (string == "CENTER") { + return MALYReaderParametersData::Center; + } else { + // @@@ error + return MALYReaderParametersData::Center; + } +} + +void +MALYReader::read_parameter (MALYReaderParametersData &data) +{ + while (true) { + + tl::Extractor ex = read_record (); + if (ex.test ("MASKMIRROR")) { + + if (ex.test ("NONE")) { + data.maskmirror = false; + } else if (ex.test ("Y")) { + data.maskmirror = true; + } else { + error (tl::to_string (tr ("Expected value Y or NONE for MASKMIRROR"))); + } + + } else if (ex.test ("MASKSIZE")) { + + data.masksize = 0.0; + ex.read (data.masksize); + + } else if (ex.test ("FONT")) { + + if (ex.test ("STANDARD")) { + data.font = MALYTitle::Standard; + } else if (ex.test ("NATIVE")) { + data.font = MALYTitle::Native; + } else { + error (tl::to_string (tr ("Expected value STANDARD or NATIVE for FONT"))); + } + + } else if (ex.test ("BASE")) { + + std::string base; + ex.read_word (base); + data.base = string_to_base (base); + + } else if (ex.test ("ARYBASE")) { + + std::string base; + ex.read_word (base); + data.array_base = string_to_base (base); + + } else if (ex.test ("REFERENCE")) { + + ex.expect ("TOOL"); + + std::string para; + ex.read_word_or_quoted (para); + // @@@ TODO: what to do with "para" + + ex.expect_end (); + + } else if (ex.test ("ROOT")) { + + std::string format, path; + ex.read_word_or_quoted (format); + ex.read_word_or_quoted (path, ".\\/+-"); + ex.expect_end (); + + data.roots.push_back (std::make_pair (format, path)); + + } else if (ex.test ("END")) { + + ex.expect ("PARAMETER"); + return; + + } else { + error (tl::to_string (tr ("Parameter spec expected or END PARAMETER"))); + } + + } +} + +void +MALYReader::read_title (MALYReaderTitleData &data) +{ + while (true) { + + tl::Extractor ex = read_record (); + if (ex.test ("DATE")) { + + if (ex.test ("OFF")) { + data.date_spec.enabled = false; + } else { + data.date_spec.enabled = true; + extract_title_trans (ex, data.date_spec); + ex.expect_end (); + } + + } else if (ex.test ("SERIAL")) { + + if (ex.test ("OFF")) { + data.serial_spec.enabled = false; + } else { + data.serial_spec.enabled = true; + extract_title_trans (ex, data.serial_spec); + ex.expect_end (); + } + + } else if (ex.test ("STRING")) { + + std::string text; + ex.read_word_or_quoted (text); + + data.string_titles.push_back (std::make_pair (text, MALYReaderTitleSpec ())); + data.string_titles.back ().second.enabled = true; + extract_title_trans (ex, data.string_titles.back ().second); + + ex.expect_end (); + + } else if (ex.test ("END")) { + + ex.expect ("TITLE"); + return; + + } else { + error (tl::to_string (tr ("Title spec expected or END TITLE"))); + } + + } +} + +void +MALYReader::read_strgroup (MALYReaderStrGroupData &data) +{ + while (true) { + + bool is_sref = false; + + tl::Extractor ex = read_record (); + if ((is_sref = ex.test ("SREF")) || ex.test ("AREF")) { + + data.refs.push_back (MALYReaderStrRefData ()); + MALYReaderStrRefData &ref = data.refs.back (); + + ex.read_word_or_quoted (ref.file); + ex.read_word_or_quoted (ref.name); + ex.read (ref.layer); + + if (ex.test ("ORG")) { + double x = 0.0, y = 0.0; + ex.read (x); + ex.read (y); + ref.org = db::DVector (x, y); + } + + if (ex.test ("SIZE")) { + double l = 0.0, b = 0.0, r = 0.0, t = 0.0; + ex.read (l); + ex.read (b); + ex.read (r); + ex.read (t); + ref.size = db::DBox (l, b, r, t); + } + + if (ex.test ("SCALE")) { + ex.read (ref.scale); + } + + if (! is_sref && ex.test ("ITERATION")) { + ex.read (ref.nx); + ex.read (ref.ny); + ex.read (ref.dx); + ex.read (ref.dy); + } + + ex.expect_end (); + + } else if (ex.test ("END")) { + + ex.expect ("STRGROUP"); + return; + + } else { + error (tl::to_string (tr ("SREF or AREF spec expected or END STRGROUP"))); + } + + } +} + +void +MALYReader::read_mask (MALYReaderMaskData &mask, bool cmask) +{ + while (true) { + + tl::Extractor ex = read_record (); + if (ex.test ("BEGIN")) { + + if (ex.test ("PARAMETER")) { + + ex.expect_end (); + read_parameter (mask.parameters); + + } else if (ex.test ("TITLE")) { + + ex.expect_end (); + read_title (mask.title); + + } else if (ex.test ("STRGROUP")) { + + mask.strgroups.push_back (MALYReaderStrGroupData ()); + + ex.read_word_or_quoted (mask.strgroups.back ().name); + ex.expect_end (); + + read_strgroup (mask.strgroups.back ()); + + } else { + error (tl::to_string (tr ("Mask component expected (PARAMETER, TITLE, STRGROUP)"))); + } + + } else if (ex.test ("END")) { + + ex.expect (cmask ? "CMASK" : "MASK"); + break; + + } else { + error (tl::to_string (tr ("Mask component expected (PARAMETER, TITLE, STRGROUP)"))); + } + + } +} + +bool +MALYReader::read_maskset (MALYData &data) +{ + tl::Extractor ex = read_record (); + if (! ex.test ("BEGIN") || ! ex.test ("MASKSET")) { + unget_record (); + return false; + } + + MALYReaderMaskData cmask; + std::list masks; + + while (true) { + + ex = read_record (); + + if (ex.test ("END")) { + + ex.expect ("MASKSET"); + ex.expect_end (); + // @@@ create_masks (cmask, masks, data); + return true; + + } else if (ex.test ("BEGIN")) { + + MALYReaderMaskData *mm = 0; + bool cm = false; + if (ex.test ("MASK")) { + masks.push_back (MALYReaderMaskData ()); + mm = &masks.back (); + } else if (ex.test ("CMASK")) { + mm = &cmask; + cm = true; + } else { + error (tl::to_string (tr ("'BEGIN MASK' or 'BEGIN CMASK' record expected"))); + } + + ex.expect_end (); + read_mask (*mm, cm); + + } else { + error (tl::to_string (tr ("'BEGIN MASK' or 'BEGIN CMASK' record expected"))); + } + + } +} + +void +MALYReader::do_read_maly_file (MALYData &data) +{ + tl::Extractor ex = read_record (); + if (! ex.test ("BEGIN") || ! ex.test ("MALY")) { + error (tl::to_string (tr ("Header expected ('BEGIN MALY')"))); + } + + std::string version; + ex.read (version, "."); + // @@@ TODO: what to do with version string? + + ex.expect_end (); + + while (read_maskset (data)) + ; + + ex = read_record (); + if (! ex.test ("END") || ! ex.test ("MALY")) { + error (tl::to_string (tr ("Terminator expected ('END MALY')"))); + } + + ex = read_record (); + if (! ex.at_end ()) { + error (tl::to_string (tr ("Records found past end of file"))); + } } void diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.h b/src/plugins/streamers/maly/db_plugin/dbMALYReader.h index 981d3419a..0272b6886 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.h +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.h @@ -45,7 +45,11 @@ namespace db { -class Technology; +class MALYReaderMaskData; +class MALYReaderTitleData; +class MALYReaderParametersData; +class MALYReaderStrGroupData; +class MALYReaderTitleSpec; /** * @brief Generic base class of MALY reader exceptions @@ -144,12 +148,23 @@ private: tl::TextInputStream m_stream; tl::AbsoluteProgress m_progress; double m_dbu; + std::string m_record; + std::string m_record_returned; void do_read (db::Layout &layout, db::cell_index_type to_cell, tl::TextInputStream &stream); std::string resolve_path(const std::string &path); MALYData read_maly_file (); - std::string read_record (); + tl::Extractor read_record (); + void unget_record (); std::string read_record_internal (); + void do_read_maly_file (MALYData &data); + bool read_maskset (MALYData &data); + void read_mask (MALYReaderMaskData &mask, bool cmask); + void read_title (MALYReaderTitleData &mask); + void read_parameter (MALYReaderParametersData &mask); + void read_strgroup (MALYReaderStrGroupData &mask); + db::DTrans extract_title_trans (tl::Extractor &ex); + void extract_title_trans (tl::Extractor &ex, MALYReaderTitleSpec &spec); }; } diff --git a/testdata/maly/MALY_TEST.maly b/testdata/maly/MALY_TEST.maly index 0fd08fc48..ca7b71601 100644 --- a/testdata/maly/MALY_TEST.maly +++ b/testdata/maly/MALY_TEST.maly @@ -1,15 +1,41 @@ -// a comment +BEGIN MALY 1.1 + BEGIN MASKSET + BEGIN CMASK + BEGIN PARAMETER + MASKSIZE 5 + FONT STANDARD + BASE ORIGIN + ARYBASE ORIGIN + ROOT OASIS.MASK /home/MASK + ROOT NATIVE /home/NATIVE + REFERENCE TOOL a.para + END PARAMETER + BEGIN TITLE + DATE 50.0 -50.0 MIRROR Y ROTATE 180 + SERIAL 0 -50.0 + STRING TEST 50.0 0 SIZE 1.0 1.0 1.0 MIRROR Y ROTATE 90 + END TITLE + END CMASK + BEGIN MASK A + BEGIN PARAMETER + ROOT OASIS.MASK /home/mask1 + MASKMIRROR Y + END PARAMETER + BEGIN TITLE + DATE OFF + STRING MaskA1 -50.0 50.00 + END TITLE + BEGIN STRGROUP G1 + SREF A1.oas CHIP_A 1 ORG -20.0 0 SIZE 0.0 0.0 10.0 10.0 + AREF A2.oas CHIP_A 2 ORG -20.0 0 SIZE 0.0 0.0 50.0 50.0 ++ SCALE 0.800 ITERATION 5 2 2.0 1.0 + PROPERTY DNAME d001 ENAME e001 + END STRGROUP + BEGIN STRGROUP G2 + SREF B3.oas CHIP_A 2 ORG -20.0 0.0 SIZE 0.0 0.0 12.0 12.0 + END STRGROUP + END MASK + END MASKSET +END MALY -BEGIN /* a multiline comment - - -*/ MALY - -// a comment - -SREF " \"// /*hello*/ " SIZE -+ 10,10 - - - From 7820733bd59881ed5ca6e356c839bc52a575bc47 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 29 Apr 2025 00:28:46 +0200 Subject: [PATCH 05/15] WIP --- .../streamers/maly/db_plugin/dbMALYReader.cc | 177 +++++++++++------- .../streamers/maly/db_plugin/dbMALYReader.h | 6 +- 2 files changed, 111 insertions(+), 72 deletions(-) diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc index aa5e19a20..ebf2d7b0b 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc @@ -348,13 +348,71 @@ MALYReaderParametersData::Base string_to_base (const std::string &string) } } +bool +MALYReader::begin_section (tl::Extractor &ex, const std::string &name) +{ + tl::Extractor ex_saved = ex; + + if (ex.test ("BEGIN")) { + if (name.empty ()) { + m_sections.push_back (std::string ()); + ex.read_word (m_sections.back ()); + return true; + } else if (ex.test (name.c_str ())) { + m_sections.push_back (name); + return true; + } + } + + ex = ex_saved; + return false; +} + +bool +MALYReader::end_section (tl::Extractor &ex) +{ + tl_assert (! m_sections.empty ()); + if (ex.at_end ()) { + + error (tl::to_string (tr ("Unexpected end of file during section"))); + return false; + + } else if (ex.test ("END")) { + + ex.expect (m_sections.back ().c_str ()); + m_sections.pop_back (); + return true; + + } else { + + return false; + + } +} + +void +MALYReader::skip_section () +{ + while (true) { + tl::Extractor ex = read_record (); + if (begin_section (ex)) { + skip_section (); + } else if (end_section (ex)) { + break; + } + } +} + void MALYReader::read_parameter (MALYReaderParametersData &data) { while (true) { tl::Extractor ex = read_record (); - if (ex.test ("MASKMIRROR")) { + + if (end_section (ex)) { + break; + } else if (ex.test ("MASKMIRROR")) { if (ex.test ("NONE")) { data.maskmirror = false; @@ -410,13 +468,8 @@ MALYReader::read_parameter (MALYReaderParametersData &data) data.roots.push_back (std::make_pair (format, path)); - } else if (ex.test ("END")) { - - ex.expect ("PARAMETER"); - return; - } else { - error (tl::to_string (tr ("Parameter spec expected or END PARAMETER"))); + warn (tl::to_string (tr ("Unknown record ignored"))); } } @@ -428,7 +481,10 @@ MALYReader::read_title (MALYReaderTitleData &data) while (true) { tl::Extractor ex = read_record (); - if (ex.test ("DATE")) { + + if (end_section (ex)) { + break; + } else if (ex.test ("DATE")) { if (ex.test ("OFF")) { data.date_spec.enabled = false; @@ -459,13 +515,8 @@ MALYReader::read_title (MALYReaderTitleData &data) ex.expect_end (); - } else if (ex.test ("END")) { - - ex.expect ("TITLE"); - return; - } else { - error (tl::to_string (tr ("Title spec expected or END TITLE"))); + warn (tl::to_string (tr ("Unknown record ignored"))); } } @@ -479,7 +530,9 @@ MALYReader::read_strgroup (MALYReaderStrGroupData &data) bool is_sref = false; tl::Extractor ex = read_record (); - if ((is_sref = ex.test ("SREF")) || ex.test ("AREF")) { + if (end_section (ex)) { + break; + } else if ((is_sref = ex.test ("SREF")) || ex.test ("AREF")) { data.refs.push_back (MALYReaderStrRefData ()); MALYReaderStrRefData &ref = data.refs.back (); @@ -517,56 +570,44 @@ MALYReader::read_strgroup (MALYReaderStrGroupData &data) ex.expect_end (); - } else if (ex.test ("END")) { - - ex.expect ("STRGROUP"); - return; - } else { - error (tl::to_string (tr ("SREF or AREF spec expected or END STRGROUP"))); + warn (tl::to_string (tr ("Unknown record ignored"))); } } } void -MALYReader::read_mask (MALYReaderMaskData &mask, bool cmask) +MALYReader::read_mask (MALYReaderMaskData &mask) { while (true) { tl::Extractor ex = read_record (); - if (ex.test ("BEGIN")) { - - if (ex.test ("PARAMETER")) { - - ex.expect_end (); - read_parameter (mask.parameters); - - } else if (ex.test ("TITLE")) { - - ex.expect_end (); - read_title (mask.title); - - } else if (ex.test ("STRGROUP")) { - - mask.strgroups.push_back (MALYReaderStrGroupData ()); - - ex.read_word_or_quoted (mask.strgroups.back ().name); - ex.expect_end (); - - read_strgroup (mask.strgroups.back ()); - - } else { - error (tl::to_string (tr ("Mask component expected (PARAMETER, TITLE, STRGROUP)"))); - } - - } else if (ex.test ("END")) { - - ex.expect (cmask ? "CMASK" : "MASK"); + if (end_section (ex)) { break; + } else if (begin_section (ex, "PARAMETER")) { + ex.expect_end (); + read_parameter (mask.parameters); + + } else if (begin_section (ex, "TITLE")) { + + ex.expect_end (); + read_title (mask.title); + + } else if (begin_section (ex, "STRGROUP")) { + + mask.strgroups.push_back (MALYReaderStrGroupData ()); + + ex.read_word_or_quoted (mask.strgroups.back ().name); + ex.expect_end (); + + read_strgroup (mask.strgroups.back ()); + + } else if (begin_section (ex)) { + skip_section (); } else { - error (tl::to_string (tr ("Mask component expected (PARAMETER, TITLE, STRGROUP)"))); + warn (tl::to_string (tr ("Unknown record ignored"))); } } @@ -576,7 +617,8 @@ bool MALYReader::read_maskset (MALYData &data) { tl::Extractor ex = read_record (); - if (! ex.test ("BEGIN") || ! ex.test ("MASKSET")) { + + if (! begin_section (ex, "MASKSET")) { unget_record (); return false; } @@ -588,32 +630,25 @@ MALYReader::read_maskset (MALYData &data) ex = read_record (); - if (ex.test ("END")) { + if (end_section (ex)) { - ex.expect ("MASKSET"); ex.expect_end (); // @@@ create_masks (cmask, masks, data); return true; - } else if (ex.test ("BEGIN")) { - - MALYReaderMaskData *mm = 0; - bool cm = false; - if (ex.test ("MASK")) { - masks.push_back (MALYReaderMaskData ()); - mm = &masks.back (); - } else if (ex.test ("CMASK")) { - mm = &cmask; - cm = true; - } else { - error (tl::to_string (tr ("'BEGIN MASK' or 'BEGIN CMASK' record expected"))); - } + } else if (begin_section (ex, "MASK")) { ex.expect_end (); - read_mask (*mm, cm); + masks.push_back (MALYReaderMaskData ()); + read_mask (masks.back ()); + + } else if (begin_section (ex, "CMASK")) { + + ex.expect_end (); + read_mask (cmask); } else { - error (tl::to_string (tr ("'BEGIN MASK' or 'BEGIN CMASK' record expected"))); + warn (tl::to_string (tr ("Unknown record ignored"))); } } @@ -623,7 +658,7 @@ void MALYReader::do_read_maly_file (MALYData &data) { tl::Extractor ex = read_record (); - if (! ex.test ("BEGIN") || ! ex.test ("MALY")) { + if (! begin_section (ex, "MALY")) { error (tl::to_string (tr ("Header expected ('BEGIN MALY')"))); } @@ -637,7 +672,7 @@ MALYReader::do_read_maly_file (MALYData &data) ; ex = read_record (); - if (! ex.test ("END") || ! ex.test ("MALY")) { + if (! end_section (ex)) { error (tl::to_string (tr ("Terminator expected ('END MALY')"))); } diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.h b/src/plugins/streamers/maly/db_plugin/dbMALYReader.h index 0272b6886..e8544782a 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.h +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.h @@ -150,6 +150,7 @@ private: double m_dbu; std::string m_record; std::string m_record_returned; + std::list m_sections; void do_read (db::Layout &layout, db::cell_index_type to_cell, tl::TextInputStream &stream); std::string resolve_path(const std::string &path); @@ -159,12 +160,15 @@ private: std::string read_record_internal (); void do_read_maly_file (MALYData &data); bool read_maskset (MALYData &data); - void read_mask (MALYReaderMaskData &mask, bool cmask); + void read_mask (MALYReaderMaskData &mask); void read_title (MALYReaderTitleData &mask); void read_parameter (MALYReaderParametersData &mask); void read_strgroup (MALYReaderStrGroupData &mask); db::DTrans extract_title_trans (tl::Extractor &ex); void extract_title_trans (tl::Extractor &ex, MALYReaderTitleSpec &spec); + bool begin_section (tl::Extractor &ex, const std::string &name = std::string ()); + bool end_section (tl::Extractor &ex); + void skip_section (); }; } From fa30fd0f7b764a7215b0ccce4113efc343afb2e5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 29 Apr 2025 22:19:59 +0200 Subject: [PATCH 06/15] WIP, MALY reader --- .../streamers/maly/db_plugin/dbMALY.cc | 80 +++++ src/plugins/streamers/maly/db_plugin/dbMALY.h | 31 +- .../streamers/maly/db_plugin/dbMALYReader.cc | 321 ++++++++++++------ .../streamers/maly/db_plugin/dbMALYReader.h | 87 ++++- 4 files changed, 405 insertions(+), 114 deletions(-) diff --git a/src/plugins/streamers/maly/db_plugin/dbMALY.cc b/src/plugins/streamers/maly/db_plugin/dbMALY.cc index b53b4b449..954514f79 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALY.cc +++ b/src/plugins/streamers/maly/db_plugin/dbMALY.cc @@ -38,6 +38,86 @@ MALYDiagnostics::~MALYDiagnostics () // .. nothing yet .. } +// --------------------------------------------------------------- +// MALYData implementation + +std::string +MALYTitle::to_string () const +{ + std::string res; + res += "\"" + string + "\" " + transformation.to_string (); + res += tl::sprintf (" %g,%g,%g", width, height, pitch); + if (font == Standard) { + res += " [Standard]"; + } else if (font == Native) { + res += " [Native]"; + } + return res; +} + +std::string +MALYStructure::to_string () const +{ + std::string res; + res += path + "{" + topcell + "}"; + if (layer < 0) { + res += "(*)"; + } else { + res += tl::sprintf ("(%d)", layer); + } + + if (! mname.empty ()) { + res += " mname(" + mname + ")"; + } + if (! ename.empty ()) { + res += " ename(" + ename + ")"; + } + if (! dname.empty ()) { + res += " dname(" + dname + ")"; + } + + res += " "; + res += size.to_string (); + + res += " "; + res += transformation.to_string (); + + if (nx > 1 || ny > 1) { + res += tl::sprintf (" [%.12gx%d,%.12gx%d]", dx, nx, dy, ny); + } + + return res; +} + +std::string +MALYMask::to_string () const +{ + std::string res; + res += "Mask " + name + "\n"; + res += " Size " + tl::to_string (size_um); + + for (auto t = titles.begin (); t != titles.end (); ++t) { + res += "\n Title " + t->to_string (); + } + for (auto s = structures.begin (); s != structures.end (); ++s) { + res += "\n Ref " + s->to_string (); + } + return res; +} + +std::string +MALYData::to_string () const +{ + std::string res; + for (auto m = masks.begin (); m != masks.end (); ++m) { + if (m != masks.begin ()) { + res += "\n"; + } + res += m->to_string (); + } + return res; +} + // --------------------------------------------------------------- // MALY format declaration diff --git a/src/plugins/streamers/maly/db_plugin/dbMALY.h b/src/plugins/streamers/maly/db_plugin/dbMALY.h index ec904e969..bdcbaae7b 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALY.h +++ b/src/plugins/streamers/maly/db_plugin/dbMALY.h @@ -76,9 +76,9 @@ public: */ enum Type { - String = 0, // A user-defined string - Date = 1, // The date - Serial = 2 // A serial number + String = 0, // A user-defined string + Date = 1, // The date + Serial = 2 // A serial number }; /** @@ -86,8 +86,9 @@ public: */ enum Font { - Standard = 0, // Standard font - Native = 1 // Native tool font + FontNotSet = 0, // Undef + Standard = 1, // Standard font + Native = 2 // Native tool font }; /** @@ -127,6 +128,11 @@ public: * @brief The font to be used */ Font font; + + /** + * @brief Returns a string representing the structure + */ + std::string to_string () const; }; /** @@ -204,6 +210,11 @@ public: * A value of -1 means "all". */ int layer; + + /** + * @brief Returns a string representing the structure + */ + std::string to_string () const; }; /** @@ -240,6 +251,11 @@ public: * @brief The list of titles */ std::list titles; + + /** + * @brief Returns a string representing the mask + */ + std::string to_string () const; }; /** @@ -258,6 +274,11 @@ public: * @brief The masks defined by the file */ std::list masks; + + /** + * @brief Returns a string representing the data set + */ + std::string to_string () const; }; } diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc index ebf2d7b0b..5d9086c48 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc @@ -42,88 +42,14 @@ namespace db { -// --------------------------------------------------------------- -// Some helper structures to collect data - -struct MALYReaderTitleSpec -{ - MALYReaderTitleSpec () - : enabled (false), width (1.0), height (1.0), pitch (1.0) - { } - - bool enabled; - db::DTrans trans; - double width, height, pitch; -}; - -struct MALYReaderTitleData -{ - MALYReaderTitleData () - { } - - MALYReaderTitleSpec date_spec; - MALYReaderTitleSpec serial_spec; - std::list > string_titles; -}; - -struct MALYReaderParametersData -{ - MALYReaderParametersData () - : base (Center), array_base (Center), masksize (0.0), maskmirror (false), font (MALYTitle::Standard) - { } - - enum Base - { - Origin, - Center, - LowerLeft - }; - - Base base; - Base array_base; - double masksize; - bool maskmirror; - MALYTitle::Font font; - std::list > roots; -}; - -struct MALYReaderStrRefData -{ - MALYReaderStrRefData () - : layer (-1), scale (1.0), nx (1), ny (1), dx (0.0), dy (0.0) - { } - - std::string file; - std::string name; - int layer; - db::DVector org; - db::DBox size; - double scale; - int nx, ny; - double dx, dy; -}; - -struct MALYReaderStrGroupData -{ - std::string name; - std::list refs; -}; - -struct MALYReaderMaskData -{ - MALYReaderParametersData parameters; - MALYReaderTitleData title; - std::list strgroups; -}; - - // --------------------------------------------------------------- // MALYReader MALYReader::MALYReader (tl::InputStream &s) : m_stream (s), m_progress (tl::to_string (tr ("Reading MALY file")), 1000), - m_dbu (0.001) + m_dbu (0.001), + m_last_record_line (0) { m_progress.set_format (tl::to_string (tr ("%.0fk lines"))); m_progress.set_format_unit (1000.0); @@ -171,6 +97,8 @@ MALYReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) MALYData data = read_maly_file (); + // @@@ + std::cout << data.to_string () << std::endl; // @@@ finish_layers (layout); @@ -187,18 +115,26 @@ tl::Extractor MALYReader::read_record () { if (! m_record_returned.empty ()) { + m_record = m_record_returned; + m_record_returned.clear (); + return tl::Extractor (m_record.c_str ()); + } while (! m_stream.at_end ()) { + + m_last_record_line = m_stream.line_number (); m_record = read_record_internal (); + tl::Extractor ex (m_record.c_str ()); if (ex.test ("+")) { error (tl::to_string (tr ("'+' character past first column - did you mean to continue a line?"))); } else if (! ex.at_end ()) { return ex; } + } return tl::Extractor (); @@ -333,12 +269,12 @@ MALYReader::extract_title_trans (tl::Extractor &ex, MALYReaderTitleSpec &spec) spec.trans = db::DTrans (rot, ymirror, db::DVector (x, y)); } -static -MALYReaderParametersData::Base string_to_base (const std::string &string) +MALYReader::MALYReaderParametersData::Base +MALYReader::string_to_base (const std::string &string) { if (string == "ORIGIN") { return MALYReaderParametersData::Origin; - } else if (string == "LOWERLEFT") { // @@@? + } else if (string == "LOWERLEFT") { return MALYReaderParametersData::LowerLeft; } else if (string == "CENTER") { return MALYReaderParametersData::Center; @@ -531,7 +467,27 @@ MALYReader::read_strgroup (MALYReaderStrGroupData &data) tl::Extractor ex = read_record (); if (end_section (ex)) { + break; + + } else if (ex.test ("PROPERTY")) { + + if (data.refs.empty ()) { + error (tl::to_string (tr ("PROPERTY entry without a preceeding SREF or AREF"))); + } + + while (! ex.at_end ()) { + if (ex.test ("DNAME")) { + ex.read_word_or_quoted (data.refs.back ().dname); + } else if (ex.test ("ENAME")) { + ex.read_word_or_quoted (data.refs.back ().ename); + } else if (ex.test ("MNAME")) { + ex.read_word_or_quoted (data.refs.back ().mname); + } else { + error (tl::to_string (tr ("Unknown PROPERTY item"))); + } + } + } else if ((is_sref = ex.test ("SREF")) || ex.test ("AREF")) { data.refs.push_back (MALYReaderStrRefData ()); @@ -633,13 +589,15 @@ MALYReader::read_maskset (MALYData &data) if (end_section (ex)) { ex.expect_end (); - // @@@ create_masks (cmask, masks, data); + create_masks (cmask, masks, data); return true; } else if (begin_section (ex, "MASK")) { - ex.expect_end (); masks.push_back (MALYReaderMaskData ()); + ex.read (masks.back ().name); + + ex.expect_end (); read_mask (masks.back ()); } else if (begin_section (ex, "CMASK")) { @@ -654,6 +612,183 @@ MALYReader::read_maskset (MALYData &data) } } +void +MALYReader::create_masks (const MALYReaderMaskData &cmask, const std::list &masks, MALYData &data) +{ + for (auto i = masks.begin (); i != masks.end (); ++i) { + + data.masks.push_back (MALYMask ()); + MALYMask &m = data.masks.back (); + + m.name = i->name; + + m.size_um = i->parameters.masksize * 25400.0; + if (m.size_um < db::epsilon) { + m.size_um = cmask.parameters.masksize * 25400.0; + } + if (m.size_um < db::epsilon) { + m.size_um = 7.0 * 25400.0; // @@@? + } + + MALYTitle::Font font = i->parameters.font; + if (font == MALYTitle::FontNotSet) { + font = cmask.parameters.font; + } + if (font == MALYTitle::FontNotSet) { + font = MALYTitle::Standard; // @@@? + } + + const MALYReaderTitleSpec *date_spec = 0; + if (i->title.date_spec.enabled) { + date_spec = &i->title.date_spec; + } else if (cmask.title.date_spec.enabled) { + date_spec = &cmask.title.date_spec; + } + if (date_spec) { + m.titles.push_back (create_title (MALYTitle::Date, *date_spec, font, std::string (""))); + } + + const MALYReaderTitleSpec *serial_spec = 0; + if (i->title.serial_spec.enabled) { + serial_spec = &i->title.serial_spec; + } else if (cmask.title.serial_spec.enabled) { + serial_spec = &cmask.title.serial_spec; + } + if (date_spec) { + m.titles.push_back (create_title (MALYTitle::Serial, *serial_spec, font, std::string (""))); + } + + for (auto t = i->title.string_titles.begin (); t != i->title.string_titles.end (); ++t) { + m.titles.push_back (create_title (MALYTitle::String, t->second, font, t->first)); + } + for (auto t = cmask.title.string_titles.begin (); t != cmask.title.string_titles.end (); ++t) { + m.titles.push_back (create_title (MALYTitle::String, t->second, font, t->first)); + } + + MALYReaderParametersData::Base base = i->parameters.base; + if (base == MALYReaderParametersData::BaseNotSet) { + base = cmask.parameters.base; + } + if (base == MALYReaderParametersData::BaseNotSet) { + base = MALYReaderParametersData::Center; // @@@? + } + + MALYReaderParametersData::Base array_base = MALYReaderParametersData::BaseNotSet; + if (array_base == MALYReaderParametersData::BaseNotSet) { + array_base = cmask.parameters.base; + } + if (array_base == MALYReaderParametersData::BaseNotSet) { + array_base = MALYReaderParametersData::Center; // @@@? + } + + for (auto sg = cmask.strgroups.begin (); sg != cmask.strgroups.end (); ++sg) { + for (auto s = sg->refs.begin (); s != sg->refs.end (); ++s) { + m.structures.push_back (create_structure (i->parameters, cmask.parameters, *s, sg->name, base, array_base)); + } + } + for (auto sg = i->strgroups.begin (); sg != i->strgroups.end (); ++sg) { + for (auto s = sg->refs.begin (); s != sg->refs.end (); ++s) { + m.structures.push_back (create_structure (i->parameters, cmask.parameters, *s, sg->name, base, array_base)); + } + } + + } +} + +MALYTitle +MALYReader::create_title (MALYTitle::Type type, const MALYReaderTitleSpec &data, MALYTitle::Font font, const std::string &string) +{ + MALYTitle title; + + title.transformation = data.trans; + title.width = data.width; + title.height = data.height; + title.pitch = data.pitch; + title.type = type; + title.font = font; + title.string = string; + + return title; +} + +MALYStructure +MALYReader::create_structure (const MALYReaderParametersData &mparam, const MALYReaderParametersData &cparam, const MALYReaderStrRefData &data, const std::string & /*strgroup_name*/, MALYReaderParametersData::Base base, MALYReaderParametersData::Base array_base) +{ + MALYStructure str; + + str.size = data.size; + str.dname = data.dname; + str.ename = data.ename; + str.mname = data.mname; + str.topcell = data.name; + str.nx = std::max (1, data.nx); + str.ny = std::max (1, data.ny); + str.dx = data.dx; + str.dy = data.dy; + str.layer = data.layer; + + str.path = resolve_path (mparam, data.file); + if (str.path.empty ()) { + str.path = resolve_path (cparam, data.file); + } + if (str.path.empty ()) { + // try any fail later ... + str.path = data.file; + } + + MALYReaderParametersData::Base eff_base = (data.nx > 1 || data.ny > 1) ? array_base : base; + + db::DPoint rp; + switch (eff_base) { + case MALYReaderParametersData::LowerLeft: + rp = data.size.p1 (); + break; + case MALYReaderParametersData::Center: + default: + // NOTE: the center implies the whole array's center in case of an AREF + rp = (data.size + data.size.moved (db::DVector (str.dx * (str.nx - 1), str.dy * (str.ny - 1)))).center (); + break; + case MALYReaderParametersData::Origin: + break; + } + + db::DCplxTrans mirr (mparam.maskmirror != cparam.maskmirror ? db::DFTrans::m90 : db::DFTrans::r0); + str.transformation = mirr * db::DCplxTrans (data.scale, 0.0, false, data.org + (db::DPoint () - rp)); + + return str; +} + +std::string +MALYReader::resolve_path (const MALYReaderParametersData ¶m, const std::string &path) +{ + if (tl::is_absolute (path)) { + + return path; + + } else { + + // NOTE: we don't differentiate by file type here. Each root is used in the + // same way to find the actual file. + // Relative paths are always resolved relative to the MALY file. + + for (auto r = param.roots.begin (); r != param.roots.end (); ++r) { + + std::string p = tl::combine_path (r->second, path); + if (! tl::is_absolute (p)) { + p = tl::combine_path (tl::dirname (m_stream.source ()), p); + } + + if (tl::file_exists (p)) { + return p; + } + + } + + } + + return std::string (); +} + void MALYReader::do_read_maly_file (MALYData &data) { @@ -663,7 +798,7 @@ MALYReader::do_read_maly_file (MALYData &data) } std::string version; - ex.read (version, "."); + ex.read_word (version, "."); // @@@ TODO: what to do with version string? ex.expect_end (); @@ -685,7 +820,7 @@ MALYReader::do_read_maly_file (MALYData &data) void MALYReader::error (const std::string &msg) { - throw MALYReaderException (msg, m_stream.line_number (), m_stream.source ()); + throw MALYReaderException (msg, m_last_record_line, m_stream.source ()); } void @@ -702,7 +837,7 @@ MALYReader::warn (const std::string &msg, int wl) int ws = compress_warning (msg); if (ws < 0) { tl::warn << msg - << tl::to_string (tr (" (line=")) << m_stream.line_number () + << tl::to_string (tr (" (line=")) << m_last_record_line << tl::to_string (tr (", file=")) << m_stream.source () << ")"; } else if (ws == 0) { @@ -710,24 +845,6 @@ MALYReader::warn (const std::string &msg, int wl) } } -std::string -MALYReader::resolve_path (const std::string &path) -{ - tl::URI path_uri (path); - - if (tl::is_absolute (path_uri.path ())) { - - return path_uri.to_string (); - - } else { - - tl::URI source_uri (m_stream.source ()); - source_uri.set_path (tl::dirname (source_uri.path ())); - return source_uri.resolved (tl::URI (path)).to_string (); - - } -} - void MALYReader::do_read (db::Layout &layout, db::cell_index_type cell_index, tl::TextInputStream &stream) { diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.h b/src/plugins/streamers/maly/db_plugin/dbMALYReader.h index e8544782a..8face4692 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.h +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.h @@ -45,12 +45,6 @@ namespace db { -class MALYReaderMaskData; -class MALYReaderTitleData; -class MALYReaderParametersData; -class MALYReaderStrGroupData; -class MALYReaderTitleSpec; - /** * @brief Generic base class of MALY reader exceptions */ @@ -145,15 +139,89 @@ public: virtual void warn (const std::string &txt, int wl = 1); private: + struct MALYReaderTitleSpec + { + MALYReaderTitleSpec () + : enabled (false), width (1.0), height (1.0), pitch (1.0) + { } + + bool enabled; + db::DTrans trans; + double width, height, pitch; + }; + + struct MALYReaderTitleData + { + MALYReaderTitleData () + { } + + MALYReaderTitleSpec date_spec; + MALYReaderTitleSpec serial_spec; + std::list > string_titles; + }; + + struct MALYReaderParametersData + { + MALYReaderParametersData () + : base (BaseNotSet), array_base (BaseNotSet), masksize (0.0), maskmirror (false), font (MALYTitle::FontNotSet) + { } + + enum Base + { + BaseNotSet, + Origin, + Center, + LowerLeft + }; + + Base base; + Base array_base; + double masksize; + bool maskmirror; + MALYTitle::Font font; + std::list > roots; + }; + + struct MALYReaderStrRefData + { + MALYReaderStrRefData () + : layer (-1), scale (1.0), nx (1), ny (1), dx (0.0), dy (0.0) + { } + + std::string file; + std::string name; + std::string dname, ename, mname; + int layer; + db::DVector org; + db::DBox size; + double scale; + int nx, ny; + double dx, dy; + }; + + struct MALYReaderStrGroupData + { + std::string name; + std::list refs; + }; + + struct MALYReaderMaskData + { + std::string name; + MALYReaderParametersData parameters; + MALYReaderTitleData title; + std::list strgroups; + }; + tl::TextInputStream m_stream; tl::AbsoluteProgress m_progress; double m_dbu; + unsigned int m_last_record_line; std::string m_record; std::string m_record_returned; std::list m_sections; void do_read (db::Layout &layout, db::cell_index_type to_cell, tl::TextInputStream &stream); - std::string resolve_path(const std::string &path); MALYData read_maly_file (); tl::Extractor read_record (); void unget_record (); @@ -169,6 +237,11 @@ private: bool begin_section (tl::Extractor &ex, const std::string &name = std::string ()); bool end_section (tl::Extractor &ex); void skip_section (); + MALYTitle create_title (MALYTitle::Type type, const MALYReaderTitleSpec &data, MALYTitle::Font font, const std::string &string); + void create_masks (const MALYReaderMaskData &cmask, const std::list &masks, MALYData &data); + MALYStructure create_structure (const MALYReaderParametersData &mparam, const MALYReaderParametersData &cparam, const MALYReaderStrRefData &data, const std::string &strgroup_name, MALYReaderParametersData::Base base, MALYReaderParametersData::Base array_base); + std::string resolve_path (const MALYReaderParametersData ¶m, const std::string &path); + static MALYReaderParametersData::Base string_to_base (const std::string &string); }; } From 03873d9b6c33b347d58e140254a7611ab8b47fe6 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 29 Apr 2025 22:56:53 +0200 Subject: [PATCH 07/15] WIP --- .../streamers/maly/db_plugin/dbMALYReader.cc | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc index 5d9086c48..189551635 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc @@ -253,10 +253,10 @@ MALYReader::extract_title_trans (tl::Extractor &ex, MALYReaderTitleSpec &spec) if (ex.test ("MIRROR")) { if (ex.test ("Y")) { ymirror = true; - } else if (ex.test ("OFF")) { // @@@ + } else if (ex.test ("NONE")) { ymirror = false; } else { - error (tl::to_string (tr ("Expected 'Y' or 'OFF' for MIRROR spec"))); + error (tl::to_string (tr ("Expected 'Y' or 'NONE' for MIRROR spec"))); } } @@ -279,8 +279,7 @@ MALYReader::string_to_base (const std::string &string) } else if (string == "CENTER") { return MALYReaderParametersData::Center; } else { - // @@@ error - return MALYReaderParametersData::Center; + error (tl::to_string (tr ("Unknown base specification: ")) + string); } } @@ -391,7 +390,7 @@ MALYReader::read_parameter (MALYReaderParametersData &data) std::string para; ex.read_word_or_quoted (para); - // @@@ TODO: what to do with "para" + // TODO: what to do with "para" ex.expect_end (); @@ -627,7 +626,8 @@ MALYReader::create_masks (const MALYReaderMaskData &cmask, const std::listparameters.font; @@ -635,7 +635,7 @@ MALYReader::create_masks (const MALYReaderMaskData &cmask, const std::list Date: Tue, 29 Apr 2025 22:59:17 +0200 Subject: [PATCH 08/15] WIP --- src/plugins/streamers/maly/db_plugin/dbMALYReader.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc index 189551635..29b56c005 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc @@ -279,7 +279,7 @@ MALYReader::string_to_base (const std::string &string) } else if (string == "CENTER") { return MALYReaderParametersData::Center; } else { - error (tl::to_string (tr ("Unknown base specification: ")) + string); + throw tl::Exception (tl::to_string (tr ("Unknown base specification: ")) + string); } } @@ -627,7 +627,7 @@ MALYReader::create_masks (const MALYReaderMaskData &cmask, const std::listparameters.font; @@ -671,7 +671,7 @@ MALYReader::create_masks (const MALYReaderMaskData &cmask, const std::list Date: Thu, 1 May 2025 23:05:01 +0200 Subject: [PATCH 09/15] WIP, MALY reader --- .../streamers/maly/db_plugin/dbMALYReader.cc | 138 +++++++++++++++--- .../streamers/maly/db_plugin/dbMALYReader.h | 2 +- 2 files changed, 121 insertions(+), 19 deletions(-) diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc index 29b56c005..4c4e38c5b 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc @@ -29,6 +29,8 @@ #include "dbStatic.h" #include "dbShapeProcessor.h" #include "dbTechnology.h" +#include "dbCellMapping.h" +#include "dbLayerMapping.h" #include "tlException.h" #include "tlString.h" @@ -92,19 +94,131 @@ MALYReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) set_layer_map (specific_options.layer_map); set_create_layers (specific_options.create_other_layers); - // @@@ set_keep_layer_names (specific_options.keep_layer_names); set_keep_layer_names (true); MALYData data = read_maly_file (); - - // @@@ - std::cout << data.to_string () << std::endl; - // @@@ + import_data (layout, data); finish_layers (layout); return layer_map_out (); } +void +MALYReader::import_data (db::Layout &layout, const MALYData &data) +{ + db::LayoutLocker locker (&layout); + + // create a new top cell + db::Cell &top_cell = layout.cell (layout.add_cell ("MALY_JOBDECK")); + + // count the number of files to read + size_t n = 0; + for (auto m = data.masks.begin (); m != data.masks.end (); ++m) { + n += m->structures.size (); + } + + tl::RelativeProgress progress (tl::to_string (tr ("Reading layouts")), n, size_t (1)); + + for (auto m = data.masks.begin (); m != data.masks.end (); ++m, ++progress) { + + db::Cell &mask_cell = layout.cell (layout.add_cell (("MASK_" + m->name).c_str ())); + top_cell.insert (db::CellInstArray (mask_cell.cell_index (), db::Trans ())); + + auto lp = open_layer (layout, m->name); + if (! lp.first) { + continue; + } + unsigned int target_layer = lp.second; + + for (auto s = m->structures.begin (); s != m->structures.end (); ++s) { + + db::LoadLayoutOptions options; + + tl::InputStream is (s->path); + db::Layout temp_layout; + db::Reader reader (is); + reader.read (temp_layout, options); + + // configure MEBES reader for compatibility with OASIS.Mask + try { + options.set_option_by_name ("mebes_produce_boundary", false); + options.set_option_by_name ("mebes_data_layer", s->layer); + options.set_option_by_name ("mebes_data_datatype", int (0)); + } catch (...) { + // ignore if there is no MEBES support + } + + db::cell_index_type source_cell; + + if (s->topcell.empty ()) { + + auto t = temp_layout.begin_top_down (); + if (t == temp_layout.end_top_down ()) { + throw tl::Exception (tl::to_string (tr ("Mask pattern file '%s' does not have a top cell")), s->path); + } + + source_cell = *t; + ++t; + if (t != temp_layout.end_top_down ()) { + throw tl::Exception (tl::to_string (tr ("Mask pattern file '%s' does not have a single top cell")), s->path); + } + + } else { + + auto cbm = layout.cell_by_name (s->topcell.c_str ()); + if (! cbm.first) { + throw tl::Exception (tl::to_string (tr ("Mask pattern file '%s' does not have a cell named '%s' as required by mask '%s'")), s->path, s->topcell, m->name); + } + + source_cell = cbm.second; + + } + + int source_layer = layout.get_layer_maybe (db::LayerProperties (s->layer, 0)); + if (source_layer >= 0) { + + // create a host cell for the pattern + + std::string cn = m->name; + if (s->mname.empty ()) { + cn += ".PATTERN"; + } else { + cn += "." + s->mname; + } + db::cell_index_type target_cell = layout.add_cell (cn.c_str ()); + + // create the pattern instance + + db::ICplxTrans trans = db::CplxTrans (layout.dbu ()).inverted () * s->transformation * db::CplxTrans (temp_layout.dbu ()); + db::CellInstArray array; + if (s->nx > 1 || s->ny > 1) { + db::Coord idx = db::coord_traits::rounded (s->dx / layout.dbu ()); + db::Coord idy = db::coord_traits::rounded (s->dy / layout.dbu ()); + array = db::CellInstArray (target_cell, trans, db::Vector (idx, 0), db::Vector (0, idy), s->nx, s->ny); + } else { + array = db::CellInstArray (target_cell, trans); + } + mask_cell.insert (array); + + // move over the shapes from the pattern layout to the target layout + + db::CellMapping cm; + cm.create_single_mapping_full (layout, target_cell, temp_layout, source_cell); + + db::LayerMapping lm; + lm.map (source_layer, target_layer); + + layout.cell (target_cell).move_tree_shapes (temp_layout.cell (source_cell), cm, lm); + + } + + } + + } + + // @@@ TODO: generate titles +} + void MALYReader::unget_record () { @@ -755,7 +869,7 @@ MALYReader::create_structure (const MALYReaderParametersData &mparam, const MALY } db::DCplxTrans mirr (mparam.maskmirror != cparam.maskmirror ? db::DFTrans::m90 : db::DFTrans::r0); - str.transformation = mirr * db::DCplxTrans (data.scale, 0.0, false, data.org + (db::DPoint () - rp)); + str.transformation = mirr * db::DCplxTrans (data.scale, 0.0, false, data.org) * db::DCplxTrans (db::DPoint () - rp); return str; } @@ -847,17 +961,5 @@ MALYReader::warn (const std::string &msg, int wl) } } -void -MALYReader::do_read (db::Layout &layout, db::cell_index_type cell_index, tl::TextInputStream &stream) -{ - try { - - // @@@ - - } catch (tl::Exception &ex) { - error (ex.msg ()); - } -} - } diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.h b/src/plugins/streamers/maly/db_plugin/dbMALYReader.h index 8face4692..acbcd8346 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.h +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.h @@ -221,7 +221,7 @@ private: std::string m_record_returned; std::list m_sections; - void do_read (db::Layout &layout, db::cell_index_type to_cell, tl::TextInputStream &stream); + void import_data (db::Layout &layout, const MALYData &data); MALYData read_maly_file (); tl::Extractor read_record (); void unget_record (); From 226ba429f1bc0d3b5f85da73c4cef56ac8717a56 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 2 May 2025 13:27:59 +0200 Subject: [PATCH 10/15] WIP: MALY reader, debugging, tests --- src/plugins/streamers/maly/db_plugin/dbMALY.h | 8 +- .../streamers/maly/db_plugin/dbMALYReader.cc | 55 +++++++--- .../streamers/maly/db_plugin/dbMALYReader.h | 8 +- .../maly/unit_tests/dbMALYReaderTests.cc | 103 ++++++++++++------ testdata/maly/MALY_test1.maly | 60 ++++++++++ testdata/maly/MALY_test10.maly | 62 +++++++++++ .../maly/{MALY_TEST.maly => MALY_test2a.maly} | 2 +- testdata/maly/MALY_test2b.maly | 42 +++++++ testdata/maly/MALY_test2c.maly | 41 +++++++ testdata/maly/MALY_test2d.maly | 41 +++++++ testdata/maly/MALY_test2e.maly | 41 +++++++ testdata/maly/MALY_test2f.maly | 41 +++++++ testdata/maly/MALY_test2g.maly | 41 +++++++ testdata/maly/MALY_test2h.maly | 41 +++++++ testdata/maly/MALY_test2i.maly | 41 +++++++ testdata/maly/MALY_test2j.maly | 41 +++++++ testdata/maly/MALY_test2k.maly | 41 +++++++ testdata/maly/MALY_test2l.maly | 41 +++++++ testdata/maly/MALY_test2m.maly | 41 +++++++ testdata/maly/MALY_test2n.maly | 41 +++++++ testdata/maly/maly_test10_au.oas | Bin 0 -> 1705 bytes testdata/maly/test10_oas/pat.oas | Bin 0 -> 519 bytes 22 files changed, 776 insertions(+), 56 deletions(-) create mode 100644 testdata/maly/MALY_test1.maly create mode 100644 testdata/maly/MALY_test10.maly rename testdata/maly/{MALY_TEST.maly => MALY_test2a.maly} (93%) create mode 100644 testdata/maly/MALY_test2b.maly create mode 100644 testdata/maly/MALY_test2c.maly create mode 100644 testdata/maly/MALY_test2d.maly create mode 100644 testdata/maly/MALY_test2e.maly create mode 100644 testdata/maly/MALY_test2f.maly create mode 100644 testdata/maly/MALY_test2g.maly create mode 100644 testdata/maly/MALY_test2h.maly create mode 100644 testdata/maly/MALY_test2i.maly create mode 100644 testdata/maly/MALY_test2j.maly create mode 100644 testdata/maly/MALY_test2k.maly create mode 100644 testdata/maly/MALY_test2l.maly create mode 100644 testdata/maly/MALY_test2m.maly create mode 100644 testdata/maly/MALY_test2n.maly create mode 100644 testdata/maly/maly_test10_au.oas create mode 100644 testdata/maly/test10_oas/pat.oas diff --git a/src/plugins/streamers/maly/db_plugin/dbMALY.h b/src/plugins/streamers/maly/db_plugin/dbMALY.h index bdcbaae7b..84f2b3347 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALY.h +++ b/src/plugins/streamers/maly/db_plugin/dbMALY.h @@ -61,7 +61,7 @@ public: /** * @brief A class representing a title field on a mask */ -class MALYTitle +class DB_PUBLIC MALYTitle { public: /** @@ -138,7 +138,7 @@ public: /** * @brief A class representing a structure (pattern) on a mask */ -class MALYStructure +class DB_PUBLIC MALYStructure { public: /** @@ -220,7 +220,7 @@ public: /** * @brief A class representing one mask */ -class MALYMask +class DB_PUBLIC MALYMask { public: /** @@ -261,7 +261,7 @@ public: /** * @brief A class representing the MALY file */ -class MALYData +class DB_PUBLIC MALYData { public: /** diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc index 4c4e38c5b..562cefba2 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc @@ -165,7 +165,7 @@ MALYReader::import_data (db::Layout &layout, const MALYData &data) } else { - auto cbm = layout.cell_by_name (s->topcell.c_str ()); + auto cbm = temp_layout.cell_by_name (s->topcell.c_str ()); if (! cbm.first) { throw tl::Exception (tl::to_string (tr ("Mask pattern file '%s' does not have a cell named '%s' as required by mask '%s'")), s->path, s->topcell, m->name); } @@ -174,27 +174,31 @@ MALYReader::import_data (db::Layout &layout, const MALYData &data) } - int source_layer = layout.get_layer_maybe (db::LayerProperties (s->layer, 0)); + int source_layer = temp_layout.get_layer_maybe (db::LayerProperties (s->layer, 0)); if (source_layer >= 0) { // create a host cell for the pattern std::string cn = m->name; - if (s->mname.empty ()) { - cn += ".PATTERN"; + if (s->topcell.empty ()) { + if (s->mname.empty ()) { + cn += ".PATTERN"; + } else { + cn += "." + s->mname; + } } else { - cn += "." + s->mname; + cn += "." + s->topcell; } db::cell_index_type target_cell = layout.add_cell (cn.c_str ()); // create the pattern instance - db::ICplxTrans trans = db::CplxTrans (layout.dbu ()).inverted () * s->transformation * db::CplxTrans (temp_layout.dbu ()); + db::ICplxTrans trans = db::CplxTrans (layout.dbu ()).inverted () * s->transformation * db::CplxTrans (layout.dbu ()); db::CellInstArray array; if (s->nx > 1 || s->ny > 1) { db::Coord idx = db::coord_traits::rounded (s->dx / layout.dbu ()); db::Coord idy = db::coord_traits::rounded (s->dy / layout.dbu ()); - array = db::CellInstArray (target_cell, trans, db::Vector (idx, 0), db::Vector (0, idy), s->nx, s->ny); + array = db::CellInstArray (target_cell, trans, trans.fp_trans () * db::Vector (idx, 0), trans.fp_trans () * db::Vector (0, idy), s->nx, s->ny); } else { array = db::CellInstArray (target_cell, trans); } @@ -277,6 +281,7 @@ MALYReader::read_record_internal () while (! m_stream.at_end () && (m_stream.get_char () != '*' || m_stream.peek_char () != '/')) ; if (m_stream.at_end ()) { + m_last_record_line = m_stream.line_number (); error (tl::to_string (tr ("/*...*/ comment not closed"))); } m_stream.get_char (); // eat trailing "/" @@ -288,19 +293,25 @@ MALYReader::read_record_internal () } if (c == '\n') { + if (m_stream.peek_char () == '+') { + + if (tl::Extractor (rec.c_str ()).at_end ()) { + m_last_record_line = m_stream.line_number (); + error (tl::to_string (tr ("'+' character at beginning of new record - did you mean to continue a line?"))); + } + // continuation line m_stream.get_char (); // eat "+" if (m_stream.at_end ()) { break; } - c = m_stream.get_char (); + } else { break; } - } - if (c == '"' || c == '\'') { + } else if (c == '"' || c == '\'') { rec += c; @@ -314,16 +325,19 @@ MALYReader::read_record_internal () break; } else if (c == '\\') { if (m_stream.at_end ()) { - error (tl::to_string (tr ("Unexpected end of file inside quotee string"))); + m_last_record_line = m_stream.line_number (); + error (tl::to_string (tr ("Unexpected end of file inside quoted string"))); } c = m_stream.get_char (); rec += c; } else if (c == '\n') { + m_last_record_line = m_stream.line_number (); error (tl::to_string (tr ("Line break inside quoted string"))); } } if (quote) { + m_last_record_line = m_stream.line_number (); error (tl::to_string (tr ("Unexpected end of file inside quotee string"))); } @@ -512,11 +526,14 @@ MALYReader::read_parameter (MALYReaderParametersData &data) std::string format, path; ex.read_word_or_quoted (format); - ex.read_word_or_quoted (path, ".\\/+-"); + ex.read_word_or_quoted (path, ".\\/+-_"); ex.expect_end (); data.roots.push_back (std::make_pair (format, path)); + } else if (begin_section (ex)) { + warn (tl::to_string (tr ("Unknown section ignored"))); + skip_section (); } else { warn (tl::to_string (tr ("Unknown record ignored"))); } @@ -564,6 +581,9 @@ MALYReader::read_title (MALYReaderTitleData &data) ex.expect_end (); + } else if (begin_section (ex)) { + warn (tl::to_string (tr ("Unknown section ignored"))); + skip_section (); } else { warn (tl::to_string (tr ("Unknown record ignored"))); } @@ -639,6 +659,9 @@ MALYReader::read_strgroup (MALYReaderStrGroupData &data) ex.expect_end (); + } else if (begin_section (ex)) { + warn (tl::to_string (tr ("Unknown section ignored"))); + skip_section (); } else { warn (tl::to_string (tr ("Unknown record ignored"))); } @@ -674,6 +697,7 @@ MALYReader::read_mask (MALYReaderMaskData &mask) read_strgroup (mask.strgroups.back ()); } else if (begin_section (ex)) { + warn (tl::to_string (tr ("Unknown section ignored"))); skip_section (); } else { warn (tl::to_string (tr ("Unknown record ignored"))); @@ -718,6 +742,9 @@ MALYReader::read_maskset (MALYData &data) ex.expect_end (); read_mask (cmask); + } else if (begin_section (ex)) { + warn (tl::to_string (tr ("Unknown section ignored"))); + skip_section (); } else { warn (tl::to_string (tr ("Unknown record ignored"))); } @@ -788,9 +815,9 @@ MALYReader::create_masks (const MALYReaderMaskData &cmask, const std::listparameters.array_base; if (array_base == MALYReaderParametersData::BaseNotSet) { - array_base = cmask.parameters.base; + array_base = cmask.parameters.array_base; } if (array_base == MALYReaderParametersData::BaseNotSet) { array_base = MALYReaderParametersData::Center; diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.h b/src/plugins/streamers/maly/db_plugin/dbMALYReader.h index acbcd8346..1cf4787c7 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.h +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.h @@ -138,6 +138,13 @@ public: */ virtual void warn (const std::string &txt, int wl = 1); + /** + * @brief Reads the MALY file into a MALYData structure + * + * This method is provided for test purposes mainly. + */ + MALYData read_maly_file (); + private: struct MALYReaderTitleSpec { @@ -222,7 +229,6 @@ private: std::list m_sections; void import_data (db::Layout &layout, const MALYData &data); - MALYData read_maly_file (); tl::Extractor read_record (); void unget_record (); std::string read_record_internal (); diff --git a/src/plugins/streamers/maly/unit_tests/dbMALYReaderTests.cc b/src/plugins/streamers/maly/unit_tests/dbMALYReaderTests.cc index cb3f749c3..fdb94953a 100644 --- a/src/plugins/streamers/maly/unit_tests/dbMALYReaderTests.cc +++ b/src/plugins/streamers/maly/unit_tests/dbMALYReaderTests.cc @@ -24,6 +24,7 @@ #include "dbMALYReader.h" #include "dbLayoutDiff.h" #include "dbWriter.h" +#include "dbTestSupport.h" #include "tlUnitTest.h" #include @@ -54,7 +55,7 @@ static void run_test (tl::TestBase *_this, const std::string &base, const char * options.set_options (opt); db::Manager m (false); - db::Layout layout (&m), layout2 (&m), layout_au (&m); + db::Layout layout (&m); { std::string fn (base); @@ -65,44 +66,74 @@ static void run_test (tl::TestBase *_this, const std::string &base, const char * reader.read (layout, options); } - tl_assert (layout.begin_top_down () != layout.end_top_down ()); - std::string tc_name = layout.cell_name (*layout.begin_top_down ()); + std::string fn_au (base); + fn_au += "/maly/"; + fn_au += file_au; - // normalize the layout by writing to OASIS and reading from .. - - std::string tmp_oas_file = _this->tmp_file (tl::sprintf ("%s.oas", tc_name)); - - { - tl::OutputStream stream (tmp_oas_file); - db::SaveLayoutOptions options; - options.set_format ("OASIS"); - db::Writer writer (options); - writer.write (layout, stream); - } - - { - tl::InputStream stream (tmp_oas_file); - db::Reader reader (stream); - reader.read (layout2); - } - - { - std::string fn (base); - fn += "/maly/"; - fn += file_au; - tl::InputStream stream (fn); - db::Reader reader (stream); - reader.read (layout_au); - } - - bool equal = db::compare_layouts (layout2, layout_au, db::layout_diff::f_boxes_as_polygons | db::layout_diff::f_verbose | db::layout_diff::f_flatten_array_insts, 1); - if (! equal) { - _this->raise (tl::sprintf ("Compare failed after reading - see %s vs %s\n", tmp_oas_file, file_au)); - } + db::compare_layouts (_this, layout, fn_au, db::WriteOAS); } -TEST(1) +TEST(1_Basic) { - run_test (_this, tl::testdata (), "MALY_TEST.maly", "mag_test_au.oas"); + std::string fn (tl::testdata ()); + fn += "/maly/MALY_test1.maly"; + + tl::InputStream stream (fn); + db::MALYReader reader (stream); + + db::MALYData data = reader.read_maly_file (); + + EXPECT_EQ (data.to_string (), + "Mask A\n" + " Size 127000\n" + " Title \"\" m90 50,-50 1,1,1 [Standard]\n" + " Title \"\" r0 0,-50 1,1,1 [Standard]\n" + " Title \"MaskA1\" r0 -50,50 1,1,1 [Standard]\n" + " Title \"WITH \"QUOTES\"\" m45 50,0 1,1,1 [Standard]\n" + " Ref A1.oas{CHIP_A}(1) (0,0;10,10) m90 *1 20,0\n" + " Ref A2.oas{CHIP_A}(2) ename(e001) dname(d001) (0,0;50,50) m90 *0.8 20,0 [2x5,1x2]\n" + " Ref B3.oas{CHIP_A}(2) (0,0;12,12) m90 *1 20,0" + ) +} + +static std::string run_test_with_error (tl::TestBase * /*_this*/, const std::string &file) +{ + std::string fn (tl::testdata ()); + fn += "/maly/"; + fn += file; + + tl::InputStream stream (fn); + db::MALYReader reader (stream); + + try { + reader.read_maly_file (); + tl_assert (false); + } catch (tl::Exception &ex) { + tl::error << ex.msg (); + return ex.msg (); + } +} + +TEST(2_Errors) +{ + EXPECT_EQ (run_test_with_error (_this, "MALY_test2a.maly").find ("Line break inside quoted string (line=17,"), size_t (0)); + EXPECT_EQ (run_test_with_error (_this, "MALY_test2b.maly").find ("/*...*/ comment not closed (line=43,"), size_t (0)); + EXPECT_EQ (run_test_with_error (_this, "MALY_test2c.maly").find ("Expected value STANDARD or NATIVE for FONT (line=7,"), size_t (0)); + EXPECT_EQ (run_test_with_error (_this, "MALY_test2d.maly").find ("Unknown base specification: NOVALIDBASE (line=8,"), size_t (0)); + EXPECT_EQ (run_test_with_error (_this, "MALY_test2e.maly").find ("Expected end of text here: NOVALIDKEY .. (line=15,"), size_t (0)); + EXPECT_EQ (run_test_with_error (_this, "MALY_test2f.maly").find ("Expected 'Y' or 'NONE' for MIRROR spec (line=15,"), size_t (0)); + EXPECT_EQ (run_test_with_error (_this, "MALY_test2g.maly").find ("Expected end of text here: UNEXPECTED (line=20,"), size_t (0)); + EXPECT_EQ (run_test_with_error (_this, "MALY_test2h.maly").find ("Expected value Y or NONE for MASKMIRROR (line=23,"), size_t (0)); + EXPECT_EQ (run_test_with_error (_this, "MALY_test2i.maly").find ("Expected end of text here: UNEXPECTED (line=29,"), size_t (0)); + EXPECT_EQ (run_test_with_error (_this, "MALY_test2j.maly").find ("Expected end of text here: NOVALIDKEY .. (line=30,"), size_t (0)); + EXPECT_EQ (run_test_with_error (_this, "MALY_test2k.maly").find ("Expected a real number here: SCALE 0.80 .. (line=31,"), size_t (0)); + EXPECT_EQ (run_test_with_error (_this, "MALY_test2l.maly").find ("Expected 'PARAMETER' here: CMASK (line=19,"), size_t (0)); + EXPECT_EQ (run_test_with_error (_this, "MALY_test2m.maly").find ("Expected 'CMASK' here: TITLE (line=18,"), size_t (0)); + EXPECT_EQ (run_test_with_error (_this, "MALY_test2n.maly").find ("Header expected ('BEGIN MALY') (line=2, "), size_t (0)); +} + +TEST(10_BasicLayout) +{ + run_test (_this, tl::testdata (), "MALY_test10.maly", "maly_test10_au.oas"); } diff --git a/testdata/maly/MALY_test1.maly b/testdata/maly/MALY_test1.maly new file mode 100644 index 000000000..92512ae14 --- /dev/null +++ b/testdata/maly/MALY_test1.maly @@ -0,0 +1,60 @@ + +// A comment + +/* +A multi-line comment +BEGIN MALY 1.1 -- not seend +*/ + +BEGIN MALY 1.1 // ignored + BEGIN MASKSET + BEGIN CMASK + AN UNKNOWN MASK RECORD + BEGIN NONSENSE + SOMETHING INSIDE A NONSENSE RECORD + BEGIN MORE + SOMETHING INSIDE ANOTHER NONSENSE RECORD + END MORE + END NONSENSE + BEGIN PARAMETER + MASKSIZE 5 + FONT STANDARD + BASE ORIGIN + ARYBASE ORIGIN + ROOT OASIS.MASK /home/MASK + ROOT NATIVE "/home/NATIVE" + REFERENCE TOOL a.para + AN UNKNOWN PARAMETER + END PARAMETER + BEGIN TITLE + AN UNKNOWN TITLE RECORD + DATE 50.0 -50.0 MIRROR Y ROTATE 180 + SERIAL 0 -50.0 + STRING "WITH \"QUOTES\"" 50.0 0 ++SIZE 1.0 1.0 1.0 MIRROR Y ROTATE 90 ++// with a continuation line + END TITLE + END CMASK + BEGIN MASK A + BEGIN PARAMETER + ROOT OASIS.MASK /home/mask1 + MASKMIRROR Y + END PARAMETER + BEGIN TITLE + DATE OFF + STRING MaskA1 -50.0 50.00 + END TITLE + BEGIN STRGROUP G1 + SREF A1.oas CHIP_A 1 ORG -20.0 0 SIZE 0.0 0.0 10.0 10.0 + AREF A2.oas CHIP_A 2 ORG -20.0 0 SIZE 0.0 0.0 50.0 50.0 ++ SCALE 0.800 ITERATION 5 2 2.0 1.0 + PROPERTY DNAME d001 ENAME e001 + END STRGROUP + BEGIN STRGROUP G2 + SREF B3.oas CHIP_A 2 ORG -20.0 0.0 SIZE 0.0 0.0 12.0 12.0 + END STRGROUP + END MASK + END MASKSET +END MALY + +// A comment at the end diff --git a/testdata/maly/MALY_test10.maly b/testdata/maly/MALY_test10.maly new file mode 100644 index 000000000..0e70b1ee2 --- /dev/null +++ b/testdata/maly/MALY_test10.maly @@ -0,0 +1,62 @@ + +BEGIN MALY 1.1 + BEGIN MASKSET + BEGIN CMASK + BEGIN PARAMETER + MASKSIZE 7 + FONT STANDARD + BASE ORIGIN + ARYBASE ORIGIN + ROOT OASIS.MASK test10_oas + MASKMIRROR NONE + END PARAMETER + END CMASK + BEGIN MASK A + BEGIN STRGROUP G1 + SREF pat.oas TOP 1 ORG -2000.0 0 SIZE -250.0 -250.0 1000.0 1000.0 SCALE 0.8 + AREF pat.oas TOP 2 ORG 1000 0 SIZE -250.0 -250.0 1000.0 1000.0 SCALE 1.0 ITERATION 2 5 1500 2000 + END STRGROUP + BEGIN STRGROUP G2 + SREF pat.oas TOP 3 ORG -3000.0 2000 SIZE -250.0 -250.0 1000.0 1000.0 SCALE 2.0 + END STRGROUP + END MASK + BEGIN MASK B + BEGIN PARAMETER + MASKMIRROR Y + END PARAMETER + BEGIN STRGROUP G1 + SREF pat.oas TOP 1 ORG -2000.0 0 SIZE -250.0 -250.0 1000.0 1000.0 SCALE 0.8 + AREF pat.oas TOP 2 ORG 1000 0 SIZE -250.0 -250.0 1000.0 1000.0 SCALE 1.0 ITERATION 2 5 1500 2000 + END STRGROUP + BEGIN STRGROUP G2 + SREF pat.oas TOP 3 ORG -3000.0 2000 SIZE -250.0 -250.0 1000.0 1000.0 SCALE 2.0 + END STRGROUP + END MASK + BEGIN MASK C + BEGIN PARAMETER + ARYBASE LOWERLEFT + BASE LOWERLEFT + END PARAMETER + BEGIN STRGROUP G1 + SREF pat.oas TOP 1 ORG -2000.0 0 SIZE -250.0 -250.0 1000.0 1000.0 SCALE 0.8 + AREF pat.oas TOP 2 ORG 1000 0 SIZE -250.0 -250.0 1000.0 1000.0 SCALE 1.0 ITERATION 2 5 1500 2000 + END STRGROUP + BEGIN STRGROUP G2 + SREF pat.oas TOP 3 ORG -3000.0 2000 SIZE -250.0 -250.0 1000.0 1000.0 SCALE 2.0 + END STRGROUP + END MASK + BEGIN MASK D + BEGIN PARAMETER + ARYBASE CENTER + BASE CENTER + END PARAMETER + BEGIN STRGROUP G1 + SREF pat.oas TOP 1 ORG -2000.0 0 SIZE -250.0 -250.0 1000.0 1000.0 SCALE 0.8 + AREF pat.oas TOP 2 ORG 1000 0 SIZE -250.0 -250.0 1000.0 1000.0 SCALE 1.0 ITERATION 2 5 1500 2000 + END STRGROUP + BEGIN STRGROUP G2 + SREF pat.oas TOP 3 ORG -3000.0 2000 SIZE -250.0 -250.0 1000.0 1000.0 SCALE 2.0 + END STRGROUP + END MASK + END MASKSET +END MALY diff --git a/testdata/maly/MALY_TEST.maly b/testdata/maly/MALY_test2a.maly similarity index 93% rename from testdata/maly/MALY_TEST.maly rename to testdata/maly/MALY_test2a.maly index ca7b71601..53f459c17 100644 --- a/testdata/maly/MALY_TEST.maly +++ b/testdata/maly/MALY_test2a.maly @@ -14,7 +14,7 @@ BEGIN MALY 1.1 BEGIN TITLE DATE 50.0 -50.0 MIRROR Y ROTATE 180 SERIAL 0 -50.0 - STRING TEST 50.0 0 SIZE 1.0 1.0 1.0 MIRROR Y ROTATE 90 + STRING "TEST\" 50.0 0 SIZE 1.0 1.0 1.0 MIRROR Y ROTATE 90 END TITLE END CMASK BEGIN MASK A diff --git a/testdata/maly/MALY_test2b.maly b/testdata/maly/MALY_test2b.maly new file mode 100644 index 000000000..19d98c940 --- /dev/null +++ b/testdata/maly/MALY_test2b.maly @@ -0,0 +1,42 @@ + +BEGIN MALY 1.1 + BEGIN MASKSET + BEGIN CMASK + BEGIN PARAMETER + MASKSIZE 5 + FONT STANDARD + BASE ORIGIN + ARYBASE ORIGIN + ROOT OASIS.MASK /home/MASK + ROOT NATIVE /home/NATIVE + REFERENCE TOOL a.para + END PARAMETER + BEGIN TITLE + DATE 50.0 -50.0 MIRROR Y ROTATE 180 + SERIAL 0 -50.0 + STRING "TEST" 50.0 0 SIZE 1.0 1.0 1.0 MIRROR Y ROTATE 90 + /* not terminated + END TITLE + END CMASK + BEGIN MASK A + BEGIN PARAMETER + ROOT OASIS.MASK /home/mask1 + MASKMIRROR Y + END PARAMETER + BEGIN TITLE + DATE OFF + STRING MaskA1 -50.0 50.00 + END TITLE + BEGIN STRGROUP G1 + SREF A1.oas CHIP_A 1 ORG -20.0 0 SIZE 0.0 0.0 10.0 10.0 + AREF A2.oas CHIP_A 2 ORG -20.0 0 SIZE 0.0 0.0 50.0 50.0 ++ SCALE 0.800 ITERATION 5 2 2.0 1.0 + PROPERTY DNAME d001 ENAME e001 + END STRGROUP + BEGIN STRGROUP G2 + SREF B3.oas CHIP_A 2 ORG -20.0 0.0 SIZE 0.0 0.0 12.0 12.0 + END STRGROUP + END MASK + END MASKSET +END MALY + diff --git a/testdata/maly/MALY_test2c.maly b/testdata/maly/MALY_test2c.maly new file mode 100644 index 000000000..671061bef --- /dev/null +++ b/testdata/maly/MALY_test2c.maly @@ -0,0 +1,41 @@ + +BEGIN MALY 1.1 + BEGIN MASKSET + BEGIN CMASK + BEGIN PARAMETER + MASKSIZE 5 + FONT NOVALIDFONT // wrong keyword + BASE ORIGIN + ARYBASE ORIGIN + ROOT OASIS.MASK /home/MASK + ROOT NATIVE /home/NATIVE + REFERENCE TOOL a.para + END PARAMETER + BEGIN TITLE + DATE 50.0 -50.0 MIRROR Y ROTATE 180 + SERIAL 0 -50.0 + STRING "TEST" 50.0 0 SIZE 1.0 1.0 1.0 MIRROR Y ROTATE 90 + END TITLE + END CMASK + BEGIN MASK A + BEGIN PARAMETER + ROOT OASIS.MASK /home/mask1 + MASKMIRROR Y + END PARAMETER + BEGIN TITLE + DATE OFF + STRING MaskA1 -50.0 50.00 + END TITLE + BEGIN STRGROUP G1 + SREF A1.oas CHIP_A 1 ORG -20.0 0 SIZE 0.0 0.0 10.0 10.0 + AREF A2.oas CHIP_A 2 ORG -20.0 0 SIZE 0.0 0.0 50.0 50.0 ++ SCALE 0.800 ITERATION 5 2 2.0 1.0 + PROPERTY DNAME d001 ENAME e001 + END STRGROUP + BEGIN STRGROUP G2 + SREF B3.oas CHIP_A 2 ORG -20.0 0.0 SIZE 0.0 0.0 12.0 12.0 + END STRGROUP + END MASK + END MASKSET +END MALY + diff --git a/testdata/maly/MALY_test2d.maly b/testdata/maly/MALY_test2d.maly new file mode 100644 index 000000000..ef775d98a --- /dev/null +++ b/testdata/maly/MALY_test2d.maly @@ -0,0 +1,41 @@ + +BEGIN MALY 1.1 + BEGIN MASKSET + BEGIN CMASK + BEGIN PARAMETER + MASKSIZE 5 + FONT STANDARD + BASE NOVALIDBASE // not a valid keyword + ARYBASE ORIGIN + ROOT OASIS.MASK /home/MASK + ROOT NATIVE /home/NATIVE + REFERENCE TOOL a.para + END PARAMETER + BEGIN TITLE + DATE 50.0 -50.0 MIRROR Y ROTATE 180 + SERIAL 0 -50.0 + STRING "TEST" 50.0 0 SIZE 1.0 1.0 1.0 MIRROR Y ROTATE 90 + END TITLE + END CMASK + BEGIN MASK A + BEGIN PARAMETER + ROOT OASIS.MASK /home/mask1 + MASKMIRROR Y + END PARAMETER + BEGIN TITLE + DATE OFF + STRING MaskA1 -50.0 50.00 + END TITLE + BEGIN STRGROUP G1 + SREF A1.oas CHIP_A 1 ORG -20.0 0 SIZE 0.0 0.0 10.0 10.0 + AREF A2.oas CHIP_A 2 ORG -20.0 0 SIZE 0.0 0.0 50.0 50.0 ++ SCALE 0.800 ITERATION 5 2 2.0 1.0 + PROPERTY DNAME d001 ENAME e001 + END STRGROUP + BEGIN STRGROUP G2 + SREF B3.oas CHIP_A 2 ORG -20.0 0.0 SIZE 0.0 0.0 12.0 12.0 + END STRGROUP + END MASK + END MASKSET +END MALY + diff --git a/testdata/maly/MALY_test2e.maly b/testdata/maly/MALY_test2e.maly new file mode 100644 index 000000000..212ed0556 --- /dev/null +++ b/testdata/maly/MALY_test2e.maly @@ -0,0 +1,41 @@ + +BEGIN MALY 1.1 + BEGIN MASKSET + BEGIN CMASK + BEGIN PARAMETER + MASKSIZE 5 + FONT STANDARD + BASE ORIGIN + ARYBASE ORIGIN + ROOT OASIS.MASK /home/MASK + ROOT NATIVE /home/NATIVE + REFERENCE TOOL a.para + END PARAMETER + BEGIN TITLE + DATE 50.0 -50.0 MIRROR Y ROTATE 180 NOVALIDKEYWORD + SERIAL 0 -50.0 + STRING "TEST" 50.0 0 SIZE 1.0 1.0 1.0 MIRROR Y ROTATE 90 + END TITLE + END CMASK + BEGIN MASK A + BEGIN PARAMETER + ROOT OASIS.MASK /home/mask1 + MASKMIRROR Y + END PARAMETER + BEGIN TITLE + DATE OFF + STRING MaskA1 -50.0 50.00 + END TITLE + BEGIN STRGROUP G1 + SREF A1.oas CHIP_A 1 ORG -20.0 0 SIZE 0.0 0.0 10.0 10.0 + AREF A2.oas CHIP_A 2 ORG -20.0 0 SIZE 0.0 0.0 50.0 50.0 ++ SCALE 0.800 ITERATION 5 2 2.0 1.0 + PROPERTY DNAME d001 ENAME e001 + END STRGROUP + BEGIN STRGROUP G2 + SREF B3.oas CHIP_A 2 ORG -20.0 0.0 SIZE 0.0 0.0 12.0 12.0 + END STRGROUP + END MASK + END MASKSET +END MALY + diff --git a/testdata/maly/MALY_test2f.maly b/testdata/maly/MALY_test2f.maly new file mode 100644 index 000000000..1fc9256b5 --- /dev/null +++ b/testdata/maly/MALY_test2f.maly @@ -0,0 +1,41 @@ + +BEGIN MALY 1.1 + BEGIN MASKSET + BEGIN CMASK + BEGIN PARAMETER + MASKSIZE 5 + FONT STANDARD + BASE ORIGIN + ARYBASE ORIGIN + ROOT OASIS.MASK /home/MASK + ROOT NATIVE /home/NATIVE + REFERENCE TOOL a.para + END PARAMETER + BEGIN TITLE + DATE 50.0 -50.0 MIRROR NOVALIDSPEC ROTATE 180 + SERIAL 0 -50.0 + STRING "TEST" 50.0 0 SIZE 1.0 1.0 1.0 MIRROR Y ROTATE 90 + END TITLE + END CMASK + BEGIN MASK A + BEGIN PARAMETER + ROOT OASIS.MASK /home/mask1 + MASKMIRROR Y + END PARAMETER + BEGIN TITLE + DATE OFF + STRING MaskA1 -50.0 50.00 + END TITLE + BEGIN STRGROUP G1 + SREF A1.oas CHIP_A 1 ORG -20.0 0 SIZE 0.0 0.0 10.0 10.0 + AREF A2.oas CHIP_A 2 ORG -20.0 0 SIZE 0.0 0.0 50.0 50.0 ++ SCALE 0.800 ITERATION 5 2 2.0 1.0 + PROPERTY DNAME d001 ENAME e001 + END STRGROUP + BEGIN STRGROUP G2 + SREF B3.oas CHIP_A 2 ORG -20.0 0.0 SIZE 0.0 0.0 12.0 12.0 + END STRGROUP + END MASK + END MASKSET +END MALY + diff --git a/testdata/maly/MALY_test2g.maly b/testdata/maly/MALY_test2g.maly new file mode 100644 index 000000000..041baf271 --- /dev/null +++ b/testdata/maly/MALY_test2g.maly @@ -0,0 +1,41 @@ + +BEGIN MALY 1.1 + BEGIN MASKSET + BEGIN CMASK + BEGIN PARAMETER + MASKSIZE 5 + FONT STANDARD + BASE ORIGIN + ARYBASE ORIGIN + ROOT OASIS.MASK /home/MASK + ROOT NATIVE /home/NATIVE + REFERENCE TOOL a.para + END PARAMETER + BEGIN TITLE + DATE 50.0 -50.0 MIRROR Y ROTATE 180 + SERIAL 0 -50.0 + STRING "TEST" 50.0 0 SIZE 1.0 1.0 1.0 MIRROR Y ROTATE 90 + END TITLE + END CMASK + BEGIN MASK A UNEXPECTED + BEGIN PARAMETER + ROOT OASIS.MASK /home/mask1 + MASKMIRROR Y + END PARAMETER + BEGIN TITLE + DATE OFF + STRING MaskA1 -50.0 50.00 + END TITLE + BEGIN STRGROUP G1 + SREF A1.oas CHIP_A 1 ORG -20.0 0 SIZE 0.0 0.0 10.0 10.0 + AREF A2.oas CHIP_A 2 ORG -20.0 0 SIZE 0.0 0.0 50.0 50.0 ++ SCALE 0.800 ITERATION 5 2 2.0 1.0 + PROPERTY DNAME d001 ENAME e001 + END STRGROUP + BEGIN STRGROUP G2 + SREF B3.oas CHIP_A 2 ORG -20.0 0.0 SIZE 0.0 0.0 12.0 12.0 + END STRGROUP + END MASK + END MASKSET +END MALY + diff --git a/testdata/maly/MALY_test2h.maly b/testdata/maly/MALY_test2h.maly new file mode 100644 index 000000000..24b8c96a9 --- /dev/null +++ b/testdata/maly/MALY_test2h.maly @@ -0,0 +1,41 @@ + +BEGIN MALY 1.1 + BEGIN MASKSET + BEGIN CMASK + BEGIN PARAMETER + MASKSIZE 5 + FONT STANDARD + BASE ORIGIN + ARYBASE ORIGIN + ROOT OASIS.MASK /home/MASK + ROOT NATIVE /home/NATIVE + REFERENCE TOOL a.para + END PARAMETER + BEGIN TITLE + DATE 50.0 -50.0 MIRROR Y ROTATE 180 + SERIAL 0 -50.0 + STRING "TEST" 50.0 0 SIZE 1.0 1.0 1.0 MIRROR Y ROTATE 90 + END TITLE + END CMASK + BEGIN MASK A + BEGIN PARAMETER + ROOT OASIS.MASK /home/mask1 + MASKMIRROR NOVALIDKEYWORD + END PARAMETER + BEGIN TITLE + DATE OFF + STRING MaskA1 -50.0 50.00 + END TITLE + BEGIN STRGROUP G1 + SREF A1.oas CHIP_A 1 ORG -20.0 0 SIZE 0.0 0.0 10.0 10.0 + AREF A2.oas CHIP_A 2 ORG -20.0 0 SIZE 0.0 0.0 50.0 50.0 ++ SCALE 0.800 ITERATION 5 2 2.0 1.0 + PROPERTY DNAME d001 ENAME e001 + END STRGROUP + BEGIN STRGROUP G2 + SREF B3.oas CHIP_A 2 ORG -20.0 0.0 SIZE 0.0 0.0 12.0 12.0 + END STRGROUP + END MASK + END MASKSET +END MALY + diff --git a/testdata/maly/MALY_test2i.maly b/testdata/maly/MALY_test2i.maly new file mode 100644 index 000000000..5c02ca50e --- /dev/null +++ b/testdata/maly/MALY_test2i.maly @@ -0,0 +1,41 @@ + +BEGIN MALY 1.1 + BEGIN MASKSET + BEGIN CMASK + BEGIN PARAMETER + MASKSIZE 5 + FONT STANDARD + BASE ORIGIN + ARYBASE ORIGIN + ROOT OASIS.MASK /home/MASK + ROOT NATIVE /home/NATIVE + REFERENCE TOOL a.para + END PARAMETER + BEGIN TITLE + DATE 50.0 -50.0 MIRROR Y ROTATE 180 + SERIAL 0 -50.0 + STRING "TEST" 50.0 0 SIZE 1.0 1.0 1.0 MIRROR Y ROTATE 90 + END TITLE + END CMASK + BEGIN MASK A + BEGIN PARAMETER + ROOT OASIS.MASK /home/mask1 + MASKMIRROR Y + END PARAMETER + BEGIN TITLE + DATE OFF + STRING MaskA1 -50.0 50.00 + END TITLE + BEGIN STRGROUP G1 UNEXPECTED + SREF A1.oas CHIP_A 1 ORG -20.0 0 SIZE 0.0 0.0 10.0 10.0 + AREF A2.oas CHIP_A 2 ORG -20.0 0 SIZE 0.0 0.0 50.0 50.0 ++ SCALE 0.800 ITERATION 5 2 2.0 1.0 + PROPERTY DNAME d001 ENAME e001 + END STRGROUP + BEGIN STRGROUP G2 + SREF B3.oas CHIP_A 2 ORG -20.0 0.0 SIZE 0.0 0.0 12.0 12.0 + END STRGROUP + END MASK + END MASKSET +END MALY + diff --git a/testdata/maly/MALY_test2j.maly b/testdata/maly/MALY_test2j.maly new file mode 100644 index 000000000..7d561956e --- /dev/null +++ b/testdata/maly/MALY_test2j.maly @@ -0,0 +1,41 @@ + +BEGIN MALY 1.1 + BEGIN MASKSET + BEGIN CMASK + BEGIN PARAMETER + MASKSIZE 5 + FONT STANDARD + BASE ORIGIN + ARYBASE ORIGIN + ROOT OASIS.MASK /home/MASK + ROOT NATIVE /home/NATIVE + REFERENCE TOOL a.para + END PARAMETER + BEGIN TITLE + DATE 50.0 -50.0 MIRROR Y ROTATE 180 + SERIAL 0 -50.0 + STRING "TEST" 50.0 0 SIZE 1.0 1.0 1.0 MIRROR Y ROTATE 90 + END TITLE + END CMASK + BEGIN MASK A + BEGIN PARAMETER + ROOT OASIS.MASK /home/mask1 + MASKMIRROR Y + END PARAMETER + BEGIN TITLE + DATE OFF + STRING MaskA1 -50.0 50.00 + END TITLE + BEGIN STRGROUP G1 + SREF A1.oas CHIP_A 1 ORG -20.0 0 SIZE 0.0 0.0 10.0 10.0 NOVALIDKEYWORD + AREF A2.oas CHIP_A 2 ORG -20.0 0 SIZE 0.0 0.0 50.0 50.0 ++ SCALE 0.800 ITERATION 5 2 2.0 1.0 + PROPERTY DNAME d001 ENAME e001 + END STRGROUP + BEGIN STRGROUP G2 + SREF B3.oas CHIP_A 2 ORG -20.0 0.0 SIZE 0.0 0.0 12.0 12.0 + END STRGROUP + END MASK + END MASKSET +END MALY + diff --git a/testdata/maly/MALY_test2k.maly b/testdata/maly/MALY_test2k.maly new file mode 100644 index 000000000..170e50cab --- /dev/null +++ b/testdata/maly/MALY_test2k.maly @@ -0,0 +1,41 @@ + +BEGIN MALY 1.1 + BEGIN MASKSET + BEGIN CMASK + BEGIN PARAMETER + MASKSIZE 5 + FONT STANDARD + BASE ORIGIN + ARYBASE ORIGIN + ROOT OASIS.MASK /home/MASK + ROOT NATIVE /home/NATIVE + REFERENCE TOOL a.para + END PARAMETER + BEGIN TITLE + DATE 50.0 -50.0 MIRROR Y ROTATE 180 + SERIAL 0 -50.0 + STRING "TEST" 50.0 0 SIZE 1.0 1.0 1.0 MIRROR Y ROTATE 90 + END TITLE + END CMASK + BEGIN MASK A + BEGIN PARAMETER + ROOT OASIS.MASK /home/mask1 + MASKMIRROR Y + END PARAMETER + BEGIN TITLE + DATE OFF + STRING MaskA1 -50.0 50.00 + END TITLE + BEGIN STRGROUP G1 + SREF A1.oas CHIP_A 1 ORG -20.0 0 SIZE 0.0 0.0 10.0 10.0 + AREF A2.oas CHIP_A 2 ORG -20.0 0 SIZE 0.0 0.0 50.0 // missing argument ++ SCALE 0.800 ITERATION 5 2 2.0 1.0 + PROPERTY DNAME d001 ENAME e001 + END STRGROUP + BEGIN STRGROUP G2 + SREF B3.oas CHIP_A 2 ORG -20.0 0.0 SIZE 0.0 0.0 12.0 12.0 + END STRGROUP + END MASK + END MASKSET +END MALY + diff --git a/testdata/maly/MALY_test2l.maly b/testdata/maly/MALY_test2l.maly new file mode 100644 index 000000000..1b3e40065 --- /dev/null +++ b/testdata/maly/MALY_test2l.maly @@ -0,0 +1,41 @@ + +BEGIN MALY 1.1 + BEGIN MASKSET + BEGIN CMASK + BEGIN PARAMETER + MASKSIZE 5 + FONT STANDARD + BASE ORIGIN + ARYBASE ORIGIN + ROOT OASIS.MASK /home/MASK + ROOT NATIVE /home/NATIVE + REFERENCE TOOL a.para + // missing closing section END PARAMETER + BEGIN TITLE + DATE 50.0 -50.0 MIRROR Y ROTATE 180 + SERIAL 0 -50.0 + STRING "TEST" 50.0 0 SIZE 1.0 1.0 1.0 MIRROR Y ROTATE 90 + END TITLE + END CMASK + BEGIN MASK A + BEGIN PARAMETER + ROOT OASIS.MASK /home/mask1 + MASKMIRROR Y + END PARAMETER + BEGIN TITLE + DATE OFF + STRING MaskA1 -50.0 50.00 + END TITLE + BEGIN STRGROUP G1 + SREF A1.oas CHIP_A 1 ORG -20.0 0 SIZE 0.0 0.0 10.0 10.0 + AREF A2.oas CHIP_A 2 ORG -20.0 0 SIZE 0.0 0.0 50.0 50.0 ++ SCALE 0.800 ITERATION 5 2 2.0 1.0 + PROPERTY DNAME d001 ENAME e001 + END STRGROUP + BEGIN STRGROUP G2 + SREF B3.oas CHIP_A 2 ORG -20.0 0.0 SIZE 0.0 0.0 12.0 12.0 + END STRGROUP + END MASK + END MASKSET +END MALY + diff --git a/testdata/maly/MALY_test2m.maly b/testdata/maly/MALY_test2m.maly new file mode 100644 index 000000000..5a9530e3d --- /dev/null +++ b/testdata/maly/MALY_test2m.maly @@ -0,0 +1,41 @@ + +BEGIN MALY 1.1 + BEGIN MASKSET + BEGIN CMASK + BEGIN PARAMETER + MASKSIZE 5 + FONT STANDARD + BASE ORIGIN + ARYBASE ORIGIN + ROOT OASIS.MASK /home/MASK + ROOT NATIVE /home/NATIVE + REFERENCE TOOL a.para + END PARAMETER + // missing opening BEGIN TITLE + DATE 50.0 -50.0 MIRROR Y ROTATE 180 + SERIAL 0 -50.0 + STRING "TEST" 50.0 0 SIZE 1.0 1.0 1.0 MIRROR Y ROTATE 90 + END TITLE + END CMASK + BEGIN MASK A + BEGIN PARAMETER + ROOT OASIS.MASK /home/mask1 + MASKMIRROR Y + END PARAMETER + BEGIN TITLE + DATE OFF + STRING MaskA1 -50.0 50.00 + END TITLE + BEGIN STRGROUP G1 + SREF A1.oas CHIP_A 1 ORG -20.0 0 SIZE 0.0 0.0 10.0 10.0 + AREF A2.oas CHIP_A 2 ORG -20.0 0 SIZE 0.0 0.0 50.0 50.0 ++ SCALE 0.800 ITERATION 5 2 2.0 1.0 + PROPERTY DNAME d001 ENAME e001 + END STRGROUP + BEGIN STRGROUP G2 + SREF B3.oas CHIP_A 2 ORG -20.0 0.0 SIZE 0.0 0.0 12.0 12.0 + END STRGROUP + END MASK + END MASKSET +END MALY + diff --git a/testdata/maly/MALY_test2n.maly b/testdata/maly/MALY_test2n.maly new file mode 100644 index 000000000..b80eafdad --- /dev/null +++ b/testdata/maly/MALY_test2n.maly @@ -0,0 +1,41 @@ + +BEGIN WRONG 1.1 + BEGIN MASKSET + BEGIN CMASK + BEGIN PARAMETER + MASKSIZE 5 + FONT STANDARD + BASE ORIGIN + ARYBASE ORIGIN + ROOT OASIS.MASK /home/MASK + ROOT NATIVE /home/NATIVE + REFERENCE TOOL a.para + END PARAMETER + BEGIN TITLE + DATE 50.0 -50.0 MIRROR Y ROTATE 180 + SERIAL 0 -50.0 + STRING "TEST" 50.0 0 SIZE 1.0 1.0 1.0 MIRROR Y ROTATE 90 + END TITLE + END CMASK + BEGIN MASK A + BEGIN PARAMETER + ROOT OASIS.MASK /home/mask1 + MASKMIRROR Y + END PARAMETER + BEGIN TITLE + DATE OFF + STRING MaskA1 -50.0 50.00 + END TITLE + BEGIN STRGROUP G1 + SREF A1.oas CHIP_A 1 ORG -20.0 0 SIZE 0.0 0.0 10.0 10.0 + AREF A2.oas CHIP_A 2 ORG -20.0 0 SIZE 0.0 0.0 50.0 50.0 ++ SCALE 0.800 ITERATION 5 2 2.0 1.0 + PROPERTY DNAME d001 ENAME e001 + END STRGROUP + BEGIN STRGROUP G2 + SREF B3.oas CHIP_A 2 ORG -20.0 0.0 SIZE 0.0 0.0 12.0 12.0 + END STRGROUP + END MASK + END MASKSET +END MALY + diff --git a/testdata/maly/maly_test10_au.oas b/testdata/maly/maly_test10_au.oas new file mode 100644 index 0000000000000000000000000000000000000000..89f1533a83498c4122fbf50e6441587ad693bace GIT binary patch literal 1705 zcmY!lcJ=kt^>+;R4CduxWH!_@V0gjKC?n3q!6L)YEF;ds&!EJR>XUoMnybM;fb~F; z;|1o9>4KX(8~>b$4qRRSKbqrK6n{_8gJqftG@5`%@xYguLQ5Cs4_D`M3`5Qmrqog z2_eG6%f-tss?3NGVdZ7!l@|OVb8r?95HT{d0F7#R#3^#0g<(N2+rmR~K*Y_kVTPLo zucY7)DZZ62$${8FMlT!C0A6t=1}_)kKZ=C~V*CPz zMw?}39KHOZBlya!*2anN4?HqE#{4`~?w?-X4K2nL9Sarq6dfB7@gt8dg?Xu*j(Ai- z6`OK^NCyM2h~N)V3@0&TxLio^hcIDfM7Uf4>hcP7m(L{C<-CGF_%NKrgyC{-B?fmV z;Xen93&c1OA@#&g_;6F)w$}D14IQ%+5A&FF26DUgvG4B|U-L2lj@HHxyCnmX4k}s- zNS}C-%KVCrftM5F@Pno34(}w@;cS9G*fAW=h~aP+!5^%Il@Sr-Oi-8Cpu2n`sV)~& zVsNzrCOgYQ#s9~?W$N_soZ;_tH7^O{teu>ekd)rg)Xwj3q;Fx{9Qb0k#qTvU6+T>& z)2saOkY`!*^H2s}exQC!;a_Tp4jehhz{cRZLNqs;udIr$>* z+)$_cEH~26vNTTrR`9jAJm1(XXDR~&FNe@~UIr$HEsPDb-!U~z`obvqm%FjEih+ZH zx#i6c?xqO~`GuZyvd@|c0x#`B3W17v8I>694TOIkI|jD3ck_KiQ=ealG=4NMUAVcc zabn}ogBvpxykAHPLmj+OVub($FN5F#F~I};f(JMR4**U0!*r3+b;52w#y}C**yE-u zRlPyF_xg+Eq>_z$#*tvoeZ&zwmj-_NYGHraU0b5h#6=j9a=D!&@GD>Uy<0w~{K+hm1Zo^9E>$~10#PUq))3aZ+Ba0#Y)n4Ig>VaJ=_fKTkXFmF}KjCP4@kdrB X#!H;Ql1!Pgn6Z(Ok)dH^0R{#DaEYlE literal 0 HcmV?d00001 diff --git a/testdata/maly/test10_oas/pat.oas b/testdata/maly/test10_oas/pat.oas new file mode 100644 index 0000000000000000000000000000000000000000..2818a3a183fc24e5bc0de03ad8d6abb978ab10d1 GIT binary patch literal 519 zcmY!lcJ=kt^>+;R4CduxWH!_@U@&5o5oh9Hk>O{S5oh6NP+~~+$vtDu)nFjNdZ5Vh z0&~Z7!OfkGe@;XPt}g!{&2cM=zo+NHGR=)u{H8MxJUDPI`*Pm)GYN6}N^Oh!HqKys zYqNNB?6mWJpH?$xY~A~lnUguhKY*7(RGFE9k!gb81V3IzC5DP@;XelrF6J+iS2jM) zvY)w3>HADct1IDhX)H>4ZI Date: Fri, 2 May 2025 14:25:34 +0200 Subject: [PATCH 11/15] Added title support, tests, debugging --- .../streamers/maly/db_plugin/dbMALYReader.cc | 60 ++++++++++++++---- .../streamers/maly/db_plugin/dbMALYReader.h | 5 +- .../maly/unit_tests/dbMALYReaderTests.cc | 12 ++-- testdata/maly/MALY_test11.maly | 38 +++++++++++ testdata/maly/maly_test11_au.oas | Bin 0 -> 3437 bytes 5 files changed, 95 insertions(+), 20 deletions(-) create mode 100644 testdata/maly/MALY_test11.maly create mode 100644 testdata/maly/maly_test11_au.oas diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc index 562cefba2..5f4d88fb2 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc @@ -31,6 +31,7 @@ #include "dbTechnology.h" #include "dbCellMapping.h" #include "dbLayerMapping.h" +#include "dbGlyphs.h" #include "tlException.h" #include "tlString.h" @@ -218,9 +219,30 @@ MALYReader::import_data (db::Layout &layout, const MALYData &data) } + // produce the titles + + for (auto t = m->titles.begin (); t != m->titles.end (); ++t) { + + const double one_mm = 1000.0; + + auto gen = db::TextGenerator::default_generator (); + double scale = std::min (t->width * one_mm / (gen->width () * gen->dbu ()), t->height * one_mm / (gen->height () * gen->dbu ())); + + auto &s = t->string; + int len = int (s.size ()); + db::DVector shift (-t->width * one_mm * len * 0.5, -t->height * one_mm * 0.5); + double char_spacing = t->width * one_mm - gen->width () * gen->dbu () * scale; + + db::Region text = gen->text_as_region (s, layout.dbu (), scale, false, 0.0, char_spacing, 0.0); + text.transform (db::Trans (db::CplxTrans (layout.dbu ()).inverted () * shift)); + text.transform (db::CplxTrans (layout.dbu ()).inverted () * db::DCplxTrans (t->transformation) * db::CplxTrans (layout.dbu ())); + + text.insert_into (&layout, mask_cell.cell_index (), target_layer); + + } + } - // @@@ TODO: generate titles } void @@ -376,6 +398,10 @@ MALYReader::extract_title_trans (tl::Extractor &ex, MALYReaderTitleSpec &spec) ex.read (spec.width); ex.read (spec.height); ex.read (spec.pitch); + } else { + spec.width = 1.0; + spec.height = 1.0; + spec.pitch = 1.0; } if (ex.test ("MIRROR")) { @@ -394,7 +420,7 @@ MALYReader::extract_title_trans (tl::Extractor &ex, MALYReaderTitleSpec &spec) rot = (a / 90) % 4; } - spec.trans = db::DTrans (rot, ymirror, db::DVector (x, y)); + spec.trans = db::DTrans (rot, false, db::DVector (x, y)) * db::DTrans (ymirror ? db::DFTrans::m90 : db::DFTrans::r0); } MALYReader::MALYReaderParametersData::Base @@ -552,6 +578,8 @@ MALYReader::read_title (MALYReaderTitleData &data) break; } else if (ex.test ("DATE")) { + data.date_spec.given = true; + if (ex.test ("OFF")) { data.date_spec.enabled = false; } else { @@ -562,6 +590,8 @@ MALYReader::read_title (MALYReaderTitleData &data) } else if (ex.test ("SERIAL")) { + data.serial_spec.given = true; + if (ex.test ("OFF")) { data.serial_spec.enabled = false; } else { @@ -779,31 +809,33 @@ MALYReader::create_masks (const MALYReaderMaskData &cmask, const std::listparameters.maskmirror != cmask.parameters.maskmirror); + const MALYReaderTitleSpec *date_spec = 0; - if (i->title.date_spec.enabled) { + if (i->title.date_spec.given) { date_spec = &i->title.date_spec; - } else if (cmask.title.date_spec.enabled) { + } else if (cmask.title.date_spec.given) { date_spec = &cmask.title.date_spec; } - if (date_spec) { - m.titles.push_back (create_title (MALYTitle::Date, *date_spec, font, std::string (""))); + if (date_spec && date_spec->enabled) { + m.titles.push_back (create_title (MALYTitle::Date, *date_spec, font, maskmirror, std::string (""))); } const MALYReaderTitleSpec *serial_spec = 0; - if (i->title.serial_spec.enabled) { + if (i->title.serial_spec.given) { serial_spec = &i->title.serial_spec; - } else if (cmask.title.serial_spec.enabled) { + } else if (cmask.title.serial_spec.given) { serial_spec = &cmask.title.serial_spec; } - if (date_spec) { - m.titles.push_back (create_title (MALYTitle::Serial, *serial_spec, font, std::string (""))); + if (serial_spec && serial_spec->enabled) { + m.titles.push_back (create_title (MALYTitle::Serial, *serial_spec, font, maskmirror, std::string (""))); } for (auto t = i->title.string_titles.begin (); t != i->title.string_titles.end (); ++t) { - m.titles.push_back (create_title (MALYTitle::String, t->second, font, t->first)); + m.titles.push_back (create_title (MALYTitle::String, t->second, font, maskmirror, t->first)); } for (auto t = cmask.title.string_titles.begin (); t != cmask.title.string_titles.end (); ++t) { - m.titles.push_back (create_title (MALYTitle::String, t->second, font, t->first)); + m.titles.push_back (create_title (MALYTitle::String, t->second, font, maskmirror, t->first)); } MALYReaderParametersData::Base base = i->parameters.base; @@ -839,11 +871,11 @@ MALYReader::create_masks (const MALYReaderMaskData &cmask, const std::list &masks, MALYData &data); MALYStructure create_structure (const MALYReaderParametersData &mparam, const MALYReaderParametersData &cparam, const MALYReaderStrRefData &data, const std::string &strgroup_name, MALYReaderParametersData::Base base, MALYReaderParametersData::Base array_base); std::string resolve_path (const MALYReaderParametersData ¶m, const std::string &path); diff --git a/src/plugins/streamers/maly/unit_tests/dbMALYReaderTests.cc b/src/plugins/streamers/maly/unit_tests/dbMALYReaderTests.cc index fdb94953a..438613561 100644 --- a/src/plugins/streamers/maly/unit_tests/dbMALYReaderTests.cc +++ b/src/plugins/streamers/maly/unit_tests/dbMALYReaderTests.cc @@ -86,10 +86,9 @@ TEST(1_Basic) EXPECT_EQ (data.to_string (), "Mask A\n" " Size 127000\n" - " Title \"\" m90 50,-50 1,1,1 [Standard]\n" - " Title \"\" r0 0,-50 1,1,1 [Standard]\n" - " Title \"MaskA1\" r0 -50,50 1,1,1 [Standard]\n" - " Title \"WITH \"QUOTES\"\" m45 50,0 1,1,1 [Standard]\n" + " Title \"\" m90 0,-50 1,1,1 [Standard]\n" + " Title \"MaskA1\" m90 50,50 1,1,1 [Standard]\n" + " Title \"WITH \"QUOTES\"\" r270 -50,0 1,1,1 [Standard]\n" " Ref A1.oas{CHIP_A}(1) (0,0;10,10) m90 *1 20,0\n" " Ref A2.oas{CHIP_A}(2) ename(e001) dname(d001) (0,0;50,50) m90 *0.8 20,0 [2x5,1x2]\n" " Ref B3.oas{CHIP_A}(2) (0,0;12,12) m90 *1 20,0" @@ -137,3 +136,8 @@ TEST(10_BasicLayout) run_test (_this, tl::testdata (), "MALY_test10.maly", "maly_test10_au.oas"); } +TEST(11_Titles) +{ + run_test (_this, tl::testdata (), "MALY_test11.maly", "maly_test11_au.oas"); +} + diff --git a/testdata/maly/MALY_test11.maly b/testdata/maly/MALY_test11.maly new file mode 100644 index 000000000..4bfc631f1 --- /dev/null +++ b/testdata/maly/MALY_test11.maly @@ -0,0 +1,38 @@ + +BEGIN MALY 1.1 + BEGIN MASKSET + BEGIN CMASK + BEGIN PARAMETER + MASKSIZE 7 + FONT STANDARD + BASE ORIGIN + ARYBASE ORIGIN + ROOT OASIS.MASK test10_oas + MASKMIRROR NONE + END PARAMETER + BEGIN TITLE + DATE -50000 -5000 MIRROR Y ROTATE 90 + SERIAL -50000 -10000 + STRING "A STRING TITLE UPSIDE DOWN" 0 -50000 MIRROR Y ROTATE 180 + STRING "A STRING TITLE" 0 -51500 + END TITLE + END CMASK + BEGIN MASK A + END MASK + BEGIN MASK B + BEGIN PARAMETER + MASKMIRROR Y + END PARAMETER + BEGIN TITLE + SERIAL OFF + STRING "A STRING TITLE FOR MASK B" 5000 -53000 + END TITLE + END MASK + BEGIN MASK C + BEGIN TITLE + DATE OFF + STRING "A STRING TITLE FOR MASK C" 0 -55000 SIZE 1.5 2.0 3.0 + END TITLE + END MASK + END MASKSET +END MALY diff --git a/testdata/maly/maly_test11_au.oas b/testdata/maly/maly_test11_au.oas new file mode 100644 index 0000000000000000000000000000000000000000..cb76b91c4d0e6a08db546844e97ade3454571b88 GIT binary patch literal 3437 zcmd_pha(h>!@%*oBlBcu@4b#AT)AX(IO~ifC-X?MXYz1l9Vf}os9a?46>)ZCSC^SR zdQLgxF-p9@|Kt6B{)Vp<$`FZAveZQ(P%KP98Yn~suuBgV$jLDtKIIO1eY5j0c!w5#|nmgV%wbU~()Hf3c$O~>@Lp`yc*j1d> zQo6;sxu|gdIyMxGr8^*T0a$3n0o@!+3g9zovY^O3O;X_KmdfQv($v0+18K+nQM37oVb=E>>s-oyh@i^bZb3PR7&=Syw}( zV?<7uBlhp?lsHffS_WFAK_gv9lZvz%(dQ^47wnvLK;u2yPU-ns`p3QIJpA(a$nN`q zuKe1wli31#Bkocj*cLPMb9e?fjkj-`@@epY?{c8g-7@vJmr0HzSibGEKE-E-zlUlv z>Y3_0GD&G9&1jD;NB!Yk9MQ^C1F0-r8F!L#StNkO&Y9V$rXgp)sEr&F7jRK38<(;lT?$e?tao- zrQmFLYRe7ub=GYoD!YpnQmVEKbG0=Pxq_>YFl~HmUWKYKQ0%p^4ulU3P>`18YM0RQ z2PWn$0Nu12YG1>*?-Kcq7iRA{bB{Rb;(gX0JXX`L_7y|<3Ynfd1C zOLP979|@h9uF8GscuM^M^TxDao}%41Xkq5EIi|@rHQUb3KLhi_dL~|SYtQIKJI@WnPtV}fdx#7ED|$!_nLdrTrGbO z&tdAa*EK!uFlMCzs8urc=d%D2$H?POfk(m>ZMCv%31#Y8=~B!^u0iX(-C&KO1V;(T zSAjZt&+000R=!Z?4aobdgka@=F(5~>iHU%$uP(9=BE`*XD_L5M_26Y}$>x~D=gVfe zsVMx`W20?lfVKI7I}es!s1J!!yKho@CXWB%3A2htYCfx5BtP&mChz)+h`u$`tOZmu z;rf&KzmI9t{#M@4euWT!sD=wspXWpkC3N=q2G{KxGUY*{<@6hjfGrOh0HN#j3nP*8>U*( z+ghXf9*PdO2JD5_y6lYX23&WhPKCpoTV93r>}#z=t?Wd7--#gzAN)Dip!7ArQfqrh z@Xq>So>k3dv1dM8T&kM8H|Qf>Fd^9}>we#?lxb=zeXuOyF;@k7)4Nvf)y#u4LJ#wZGnAd9jDr@&TNcElfx z9W8ro#?GM-IsmN;8#9R|Gv$!a+t!osL=xcR4T1Ei>4Su`yN;- z9bj!6)s8Jfp`jk{{cF0EwLltP?Ch{y3D9`ruBXH0BprH;L;Ru6ZHB}c_CckZ6O)l$bO z(ocCjulC>l4|(HT;WnA|@@raaJC8Nu151M-m1x@*heQO&E189Srs*~i>s`b)%LrM> zVGO=2g&6%$DOeKjvMup=XpX-42o1pRfA$t{#KbJq)4^228%7OJ=@gG;6@ zcl?=})!sXVna43OgnCP94XA@9e0R4pudjUKu<)v33{jK4ig~Rd3DDnkPrn!9L!WkTm!sW5RrM<|PlSh*m{gGpQzVM=Z zc=G1x#Qu!>R&Kt#WJru=zd+b|o|Mlfhy8_dsr#r#&@_dp_-Ca3h;FtixQ{~gOV;H3 z<hHhRybLeXAArYdU3XO;(zXp} zV(A0-A)$at?U^U3u}KJL0M3z*7AC9UFx{xczEO;dW3-(=)*Y@rHfqJ#0M3twfE<0E zUGOpZ2fKfL%0<2MxdPa1NrT$a1({$)%Yqy=_foDVu=G~a&8MteMIUacjxsq|G?IhnyQ!k(D{Pu8WC7Vy*akH zk=*1oT&gO4nTNb}G=UVIxR~FYt`cbDd=vcQ;S45m#fnP2d>k0HWg4$F3N~mPoTw7p znJ&JehVmfeC5HGgLc|C56$lHB?@I*rP7UW@pDaJ$P%BO!P3X*m@69~Pw#wW85v&)b zlNY?lTySH^Oe%-JkU2!&nuo!)Kawqn36fiQ`ZZZYER2Igz3ufw@HwZzN)1_@Q|SB1 zV$c&|>j+~Luh>?cPM{Z9B3|b(n=K+PW~&b8cGNT3!DB zp|FNLqka(DU&Vj34HjNzMsX+3FfbIOhD4*5Wq`}d$R;F;4Q0gQD98R;fA&!1U8TWH zi=^1FtcevflfZ;i>;1ljm0LtB1el6@7>%! z{^Fzy#Q{7QOuWVbU!JO931hzH!u&$koK4?24m$XN)XZOV2L18Dk?B1(r<-YN43h$oKKEwJ?o~MUJI^FgV*(tuk cdmkA9AmDpmAOI)<3<2VRKtSC8uK Date: Fri, 2 May 2025 14:49:13 +0200 Subject: [PATCH 12/15] Providing meta info (boundary per mask) from MALY reader --- .../streamers/gds2/db_plugin/dbGDS2ReaderBase.cc | 2 -- src/plugins/streamers/maly/db_plugin/dbMALY.cc | 2 +- .../streamers/maly/db_plugin/dbMALYReader.cc | 15 +++++++++++++++ .../streamers/maly/db_plugin/dbMALYReader.h | 1 + 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc index 413db5084..dad91a563 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc @@ -33,8 +33,6 @@ namespace db { -// --------------------------------------------------------------- - // --------------------------------------------------------------- // GDS2ReaderBase diff --git a/src/plugins/streamers/maly/db_plugin/dbMALY.cc b/src/plugins/streamers/maly/db_plugin/dbMALY.cc index 954514f79..385e217fa 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALY.cc +++ b/src/plugins/streamers/maly/db_plugin/dbMALY.cc @@ -133,7 +133,7 @@ public: virtual std::string format_name () const { return "MALY"; } virtual std::string format_desc () const { return "MALY jobdeck"; } virtual std::string format_title () const { return "MALY (MALY jobdeck format)"; } - virtual std::string file_format () const { return "MALY jobdeck files (*.maly *.MALY)"; } + virtual std::string file_format () const { return "MALY jobdeck files (*.maly *.MALY *.mly *.MLY)"; } virtual bool detect (tl::InputStream &s) const { diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc index 5f4d88fb2..d57efcd59 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc @@ -99,11 +99,26 @@ MALYReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) MALYData data = read_maly_file (); import_data (layout, data); + create_metadata (layout, data); finish_layers (layout); return layer_map_out (); } +void +MALYReader::create_metadata (db::Layout &layout, const MALYData &data) +{ + tl::Variant boundary_per_mask = tl::Variant::empty_array (); + + for (auto m = data.masks.begin (); m != data.masks.end (); ++m) { + double ms = m->size_um; + db::DBox box (-0.5 * ms, -0.5 * ms, 0.5 * ms, 0.5 * ms); + boundary_per_mask.insert (m->name, box); + } + + layout.add_meta_info ("boundary_per_mask", MetaInfo (tl::to_string (tr ("Physical mask boundary per mask name")), boundary_per_mask)); +} + void MALYReader::import_data (db::Layout &layout, const MALYData &data) { diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.h b/src/plugins/streamers/maly/db_plugin/dbMALYReader.h index bf6ed2989..ea4feabbb 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.h +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.h @@ -230,6 +230,7 @@ private: std::list m_sections; void import_data (db::Layout &layout, const MALYData &data); + void create_metadata (db::Layout &layout, const MALYData &data); tl::Extractor read_record (); void unget_record (); std::string read_record_internal (); From b77b4d7d3c71a24308fdea91dbb60b1919dd6492 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 2 May 2025 15:02:18 +0200 Subject: [PATCH 13/15] Bug fixes --- src/plugins/streamers/maly/db_plugin/dbMALYReader.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc index d57efcd59..a474874a7 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc +++ b/src/plugins/streamers/maly/db_plugin/dbMALYReader.cc @@ -88,8 +88,6 @@ MALYReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) { init (options); - prepare_layers (layout); - const db::MALYReaderOptions &specific_options = options.get_options (); m_dbu = specific_options.dbu; @@ -97,6 +95,8 @@ MALYReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) set_create_layers (specific_options.create_other_layers); set_keep_layer_names (true); + prepare_layers (layout); + MALYData data = read_maly_file (); import_data (layout, data); create_metadata (layout, data); From 1932532416a6fedfd0e2567e0c76974e2092c620 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 2 May 2025 15:07:28 +0200 Subject: [PATCH 14/15] Bug fixes, tests --- src/plugins/streamers/maly/db_plugin/dbMALY.cc | 2 +- .../maly/unit_tests/dbMALYReaderTests.cc | 1 + testdata/maly/maly_test10_lm_au.oas | Bin 0 -> 1705 bytes 3 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 testdata/maly/maly_test10_lm_au.oas diff --git a/src/plugins/streamers/maly/db_plugin/dbMALY.cc b/src/plugins/streamers/maly/db_plugin/dbMALY.cc index 385e217fa..372b91f2d 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALY.cc +++ b/src/plugins/streamers/maly/db_plugin/dbMALY.cc @@ -163,7 +163,7 @@ public: virtual tl::XMLElementBase *xml_reader_options_element () const { - return new db::ReaderOptionsXMLElement ("mag", + return new db::ReaderOptionsXMLElement ("maly", tl::make_member (&db::MALYReaderOptions::dbu, "dbu") + tl::make_member (&db::MALYReaderOptions::layer_map, "layer-map") + tl::make_member (&db::MALYReaderOptions::create_other_layers, "create-other-layers") diff --git a/src/plugins/streamers/maly/unit_tests/dbMALYReaderTests.cc b/src/plugins/streamers/maly/unit_tests/dbMALYReaderTests.cc index 438613561..95a6ff447 100644 --- a/src/plugins/streamers/maly/unit_tests/dbMALYReaderTests.cc +++ b/src/plugins/streamers/maly/unit_tests/dbMALYReaderTests.cc @@ -134,6 +134,7 @@ TEST(2_Errors) TEST(10_BasicLayout) { run_test (_this, tl::testdata (), "MALY_test10.maly", "maly_test10_au.oas"); + run_test (_this, tl::testdata (), "MALY_test10.maly", "maly_test10_lm_au.oas", "A: 10, B: 11, C: 12, D: 13"); } TEST(11_Titles) diff --git a/testdata/maly/maly_test10_lm_au.oas b/testdata/maly/maly_test10_lm_au.oas new file mode 100644 index 0000000000000000000000000000000000000000..5d495f5b1ab34757a7892a6949e138bc9fae5b11 GIT binary patch literal 1705 zcmY!lcJ=kt^>+;R4CduxWH!_@V0gjKC?n3q!6L)YEF;ds&!EJR>XUoMnybM;fb~F; z;|1o9>4KX(8~>b$4qRRSKbqrK6n{_8gJqftG@5`%@xvym(W8jq$Rpw=2WI8a52Z(s3cqMp6MU{CFBEr0aynLd{ z+z1gKUM^mCQDrWK2rDl$ue9I~nS--mBTkX~ybKF^*%ls>10rsQ4Kv&% zcqIjYND)>hYQf0y;CJzYHU5oTB^G`+1L|LJNDjmXGJ4s72Jnh2F?hKM|4}R~5aSmx zG}dm|{=g%%W6aM(<^JjA-Oyr8(XmirPtmaf5kK4--a zRIw=sh;%UUiU|G?#c&c2hRcNne+Uy+Muf`+pf0aKcX>OhF6R~e!H3}_ZVZ=mD>1k` z3I91*Tp-4Q2&pG_=7*c&wzalDY3P`pc$mkWGmzV@k9~i)_?nOTceFNs*ew~5bWqV! zK>EasROVM~47{8WhaW6Oclc~l9nL2BgB`=+To?{#5&XeQSQ!yP&IEON4Z6#_Np-oH z5`(K1FxgoaD*iwAEmNn5=L~F zoL=RJhdj%gpNBH=@&ol-3jb0&bl}K223GdvxhYl*N1E(g#OBO9xZ}YD8D-|r&B+&e z=Y~4nXStDnmZfp}w}P*|<@v^DIa3)JcsYc=^D;0oY+-De{f?<&(icX-zub+TRSX;q z%q?$ra5qg@$S?GqlYQ1q5O`@1QV3MU%c#U)Zy@~Z*fFrJy_@eFn)>`Yr17J9>B7xj zjT0Mx9^9Cr;Qc~U80z4K5-S84co_r_hzTCx7d*frcmQa^AEt|pt`m0iF$Rjb#vV6S zsp<{Vz1LqPCzWg@#HD4glGW*=Z|C6Rt++^#v$I2EiqgLWciXKmueE)BCzNNY&1PGP zZ8fJeZ{?}Udge?L`F>`dwaLa~o|DqnJuk12Q2EucU7>k@8uyIb7J>iU*B=luOwW;c z|LFeK4d*x~O?x*_Wu4c7*;V Date: Sun, 11 May 2025 21:48:01 +0200 Subject: [PATCH 15/15] Fixing a linker issue on Windows. --- src/plugins/streamers/maly/db_plugin/dbMALY.h | 9 +++++---- src/plugins/streamers/streamers.pro | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/streamers/maly/db_plugin/dbMALY.h b/src/plugins/streamers/maly/db_plugin/dbMALY.h index 84f2b3347..32a5e07a7 100644 --- a/src/plugins/streamers/maly/db_plugin/dbMALY.h +++ b/src/plugins/streamers/maly/db_plugin/dbMALY.h @@ -27,6 +27,7 @@ #include "dbPoint.h" #include "dbTrans.h" #include "dbBox.h" +#include "dbPluginCommon.h" #include "tlException.h" #include "tlInternational.h" @@ -61,7 +62,7 @@ public: /** * @brief A class representing a title field on a mask */ -class DB_PUBLIC MALYTitle +class DB_PLUGIN_PUBLIC MALYTitle { public: /** @@ -138,7 +139,7 @@ public: /** * @brief A class representing a structure (pattern) on a mask */ -class DB_PUBLIC MALYStructure +class DB_PLUGIN_PUBLIC MALYStructure { public: /** @@ -220,7 +221,7 @@ public: /** * @brief A class representing one mask */ -class DB_PUBLIC MALYMask +class DB_PLUGIN_PUBLIC MALYMask { public: /** @@ -261,7 +262,7 @@ public: /** * @brief A class representing the MALY file */ -class DB_PUBLIC MALYData +class DB_PLUGIN_PUBLIC MALYData { public: /** diff --git a/src/plugins/streamers/streamers.pro b/src/plugins/streamers/streamers.pro index 5d7bbf3ad..8bfcea845 100644 --- a/src/plugins/streamers/streamers.pro +++ b/src/plugins/streamers/streamers.pro @@ -6,4 +6,3 @@ SUBDIR_LIST = $$files($$PWD/*) SUBDIR_LIST -= $$PWD/streamers.pro SUBDIRS = $$SUBDIR_LIST -