From aa124487470be45c4b680c2a4a25cfe18327e083 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 5 Apr 2025 20:35:11 +0200 Subject: [PATCH 01/18] First attempt to implement a solution for issue #2016 The implementation will not update the PCell on property sheet edits of the guiding shape if lazy evaluation is requested. Still, changes are committed to the PCell on committing the property page. --- src/ant/ant/antPropertiesPage.cc | 2 +- src/ant/ant/antPropertiesPage.h | 2 +- src/edt/edt/edtInstPropertiesPage.cc | 4 ++-- src/edt/edt/edtInstPropertiesPage.h | 4 ++-- src/edt/edt/edtPropertiesPages.cc | 12 +++++------ src/edt/edt/edtPropertiesPages.h | 6 +++--- src/edt/edt/edtService.cc | 29 ++++++++++++++++++++------ src/edt/edt/edtService.h | 9 ++++++-- src/img/img/imgPropertiesPage.cc | 6 +++--- src/img/img/imgPropertiesPage.h | 2 +- src/img/img/imgService.cc | 2 +- src/laybasic/laybasic/layProperties.h | 9 ++++++-- src/layui/layui/layPropertiesDialog.cc | 16 +++++++------- src/layui/layui/layPropertiesDialog.h | 2 +- 14 files changed, 66 insertions(+), 39 deletions(-) diff --git a/src/ant/ant/antPropertiesPage.cc b/src/ant/ant/antPropertiesPage.cc index 6b081bf21..15e19315e 100644 --- a/src/ant/ant/antPropertiesPage.cc +++ b/src/ant/ant/antPropertiesPage.cc @@ -517,7 +517,7 @@ PropertiesPage::readonly () } void -PropertiesPage::apply () +PropertiesPage::apply (bool /*commit*/) { ant::Object obj; get_object (obj); diff --git a/src/ant/ant/antPropertiesPage.h b/src/ant/ant/antPropertiesPage.h index 9b9438d71..c98c42d91 100644 --- a/src/ant/ant/antPropertiesPage.h +++ b/src/ant/ant/antPropertiesPage.h @@ -50,7 +50,7 @@ public: virtual void update (); virtual void leave (); virtual bool readonly (); - virtual void apply (); + virtual void apply (bool commit); private slots: void swap_points_clicked (); diff --git a/src/edt/edt/edtInstPropertiesPage.cc b/src/edt/edt/edtInstPropertiesPage.cc index da06cb814..de27a4d90 100644 --- a/src/edt/edt/edtInstPropertiesPage.cc +++ b/src/edt/edt/edtInstPropertiesPage.cc @@ -925,7 +925,7 @@ InstPropertiesPage::do_apply (bool current_only, bool relative) } void -InstPropertiesPage::apply () +InstPropertiesPage::apply (bool /*commit*/) { do_apply (true, false); } @@ -937,7 +937,7 @@ InstPropertiesPage::can_apply_to_all () const } void -InstPropertiesPage::apply_to_all (bool relative) +InstPropertiesPage::apply_to_all (bool relative, bool /*commit*/) { do_apply (false, relative); } diff --git a/src/edt/edt/edtInstPropertiesPage.h b/src/edt/edt/edtInstPropertiesPage.h index c33d7f3d6..f00a1a659 100644 --- a/src/edt/edt/edtInstPropertiesPage.h +++ b/src/edt/edt/edtInstPropertiesPage.h @@ -66,8 +66,8 @@ protected: edt::PCellParametersPage *mp_pcell_parameters; virtual bool readonly (); - virtual void apply (); - virtual void apply_to_all (bool relative); + virtual void apply (bool commit); + virtual void apply_to_all (bool relative, bool commit); virtual bool can_apply_to_all () const; void do_apply (bool current_only, bool relative); virtual ChangeApplicator *create_applicator (db::Cell &cell, const db::Instance &inst, double dbu); diff --git a/src/edt/edt/edtPropertiesPages.cc b/src/edt/edt/edtPropertiesPages.cc index 365ca1c63..26b1def30 100644 --- a/src/edt/edt/edtPropertiesPages.cc +++ b/src/edt/edt/edtPropertiesPages.cc @@ -215,7 +215,7 @@ ShapePropertiesPage::recompute_selection_ptrs (const std::vector gs = mp_service->handle_guiding_shape_changes (new_sel[index]); + std::pair gs = mp_service->handle_guiding_shape_changes (new_sel[index], commit); if (gs.first) { new_sel[index] = gs.second; @@ -350,9 +350,9 @@ ShapePropertiesPage::do_apply (bool current_only, bool relative) } void -ShapePropertiesPage::apply () +ShapePropertiesPage::apply (bool commit) { - do_apply (true, false); + do_apply (true, false, commit); } bool @@ -362,9 +362,9 @@ ShapePropertiesPage::can_apply_to_all () const } void -ShapePropertiesPage::apply_to_all (bool relative) +ShapePropertiesPage::apply_to_all (bool relative, bool commit) { - do_apply (false, relative); + do_apply (false, relative, commit); } void diff --git a/src/edt/edt/edtPropertiesPages.h b/src/edt/edt/edtPropertiesPages.h index 7d8d5b644..60d844f50 100644 --- a/src/edt/edt/edtPropertiesPages.h +++ b/src/edt/edt/edtPropertiesPages.h @@ -63,10 +63,10 @@ protected: private: virtual void update (); - virtual void apply (); - virtual void apply_to_all (bool relative); + virtual void apply (bool commit); + virtual void apply_to_all (bool relative, bool commit); virtual bool can_apply_to_all () const; - virtual void do_apply (bool current_only, bool relative); + virtual void do_apply (bool current_only, bool relative, bool commit); void recompute_selection_ptrs (const std::vector &new_sel); protected: diff --git a/src/edt/edt/edtService.cc b/src/edt/edt/edtService.cc index 75fbf5428..aeb4223d1 100644 --- a/src/edt/edt/edtService.cc +++ b/src/edt/edt/edtService.cc @@ -76,6 +76,7 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view, db::ShapeIter m_snap_to_objects (true), m_snap_objects_to_grid (true), m_top_level_sel (false), m_show_shapes_of_instances (true), m_max_shapes_of_instances (1000), + m_pcell_lazy_evaluation (0), m_hier_copy_mode (-1), m_indicate_secondary_selection (false), m_seq (0), @@ -391,6 +392,10 @@ Service::configure (const std::string &name, const std::string &value) tl::from_string (value, m_hier_copy_mode); service_configuration_changed (); + } else if (name == cfg_edit_pcell_lazy_eval_mode) { + + tl::from_string (value, m_pcell_lazy_evaluation); + } else { lay::EditorServiceBase::configure (name, value); } @@ -598,7 +603,7 @@ Service::end_move (const db::DPoint & /*p*/, lay::angle_constraint_type ac) transform (db::DCplxTrans (m_move_trans)); move_cancel (); // formally this functionality fits here // accept changes to guiding shapes - handle_guiding_shape_changes (); + handle_guiding_shape_changes (true); } m_alt_ac = lay::AC_Global; } @@ -846,7 +851,7 @@ Service::transform (const db::DCplxTrans &trans, const std::vector -Service::handle_guiding_shape_changes (const lay::ObjectInstPath &obj) const +Service::handle_guiding_shape_changes (const lay::ObjectInstPath &obj, bool commit) const { unsigned int cv_index = obj.cv_index (); lay::CellView cv = view ()->cellview (cv_index); @@ -1874,10 +1879,22 @@ Service::handle_guiding_shape_changes (const lay::ObjectInstPath &obj) const return std::make_pair (false, lay::ObjectInstPath ()); } - if (! layout->is_pcell_instance (obj.cell_index ()).first) { + auto pcell_decl = layout->pcell_declaration_for_pcell_variant (obj.cell_index ()); + if (! pcell_decl) { return std::make_pair (false, lay::ObjectInstPath ()); } + // Don't update unless we're committing or not in lazy PCell update mode + if (! commit) { + if (m_pcell_lazy_evaluation < 0) { + if (pcell_decl->wants_lazy_evaluation ()) { + return std::make_pair (false, lay::ObjectInstPath ()); + } + } else if (m_pcell_lazy_evaluation > 0) { + return std::make_pair (false, lay::ObjectInstPath ()); + } + } + db::cell_index_type top_cell = std::numeric_limits::max (); db::cell_index_type parent_cell = std::numeric_limits::max (); db::Instance parent_inst; @@ -1944,7 +1961,7 @@ Service::handle_guiding_shape_changes (const lay::ObjectInstPath &obj) const } bool -Service::handle_guiding_shape_changes () +Service::handle_guiding_shape_changes (bool commit) { EditableSelectionIterator s = begin_selection (); @@ -1953,7 +1970,7 @@ Service::handle_guiding_shape_changes () return false; } - std::pair gs = handle_guiding_shape_changes (*s); + std::pair gs = handle_guiding_shape_changes (*s, commit); if (gs.first) { // remove superfluous proxies diff --git a/src/edt/edt/edtService.h b/src/edt/edt/edtService.h index 7e2d34801..e782bbfb5 100644 --- a/src/edt/edt/edtService.h +++ b/src/edt/edt/edtService.h @@ -398,17 +398,19 @@ public: * * @return true, if PCells have been updated, indicating that our selection is no longer valid * + * @param commit If true, changes are "final" (and PCells are updated also in lazy evaluation mode) + * * This version assumes there is only one guiding shape selected and will update the selection. * It will also call layout.cleanup() if required. */ - bool handle_guiding_shape_changes (); + bool handle_guiding_shape_changes (bool commit); /** * @brief Handle changes in a specific guiding shape, i.e. create new PCell variants if required * * @return A pair of bool (indicating that the object path has changed) and the new guiding shape path */ - std::pair handle_guiding_shape_changes (const lay::ObjectInstPath &obj) const; + std::pair handle_guiding_shape_changes (const lay::ObjectInstPath &obj, bool commit) const; /** * @brief Gets a value indicating whether a move operation is ongoing @@ -672,9 +674,12 @@ private: bool m_snap_to_objects; bool m_snap_objects_to_grid; db::DVector m_global_grid; + + // Other attributes bool m_top_level_sel; bool m_show_shapes_of_instances; unsigned int m_max_shapes_of_instances; + int m_pcell_lazy_evaluation; // Hierarchical copy mode (-1: ask, 0: shallow, 1: deep) int m_hier_copy_mode; diff --git a/src/img/img/imgPropertiesPage.cc b/src/img/img/imgPropertiesPage.cc index 4ff7a954b..056e7e5ce 100644 --- a/src/img/img/imgPropertiesPage.cc +++ b/src/img/img/imgPropertiesPage.cc @@ -784,7 +784,7 @@ PropertiesPage::reverse_color_order () } void -PropertiesPage::apply () +PropertiesPage::apply (bool /*commit*/) { bool has_error = false; @@ -915,7 +915,7 @@ PropertiesPage::browse () { BEGIN_PROTECTED - apply (); + apply (true); lay::FileDialog file_dialog (this, tl::to_string (QObject::tr ("Load Image File")), tl::to_string (QObject::tr ("All files (*)"))); @@ -941,7 +941,7 @@ PropertiesPage::save_pressed () { BEGIN_PROTECTED - apply (); + apply (true); lay::FileDialog file_dialog (this, tl::to_string (QObject::tr ("Save As KLayout Image File")), tl::to_string (QObject::tr ("KLayout image files (*.lyimg);;All files (*)"))); diff --git a/src/img/img/imgPropertiesPage.h b/src/img/img/imgPropertiesPage.h index b9ccedc33..e715f99cd 100644 --- a/src/img/img/imgPropertiesPage.h +++ b/src/img/img/imgPropertiesPage.h @@ -57,7 +57,7 @@ public: virtual void update (); virtual void leave (); virtual bool readonly (); - virtual void apply (); + virtual void apply (bool commit); void set_direct_image (img::Object *image); diff --git a/src/img/img/imgService.cc b/src/img/img/imgService.cc index 0dc06ae74..3b1c85589 100644 --- a/src/img/img/imgService.cc +++ b/src/img/img/imgService.cc @@ -71,7 +71,7 @@ public: BEGIN_PROTECTED properties_frame->set_direct_image (mp_image_object); - properties_frame->apply (); + properties_frame->apply (true); if (mp_image_object->is_empty ()) { throw tl::Exception (tl::to_string (tr ("No data loaded for that image"))); diff --git a/src/laybasic/laybasic/layProperties.h b/src/laybasic/laybasic/layProperties.h index ef4b8ec3c..09b16c2b9 100644 --- a/src/laybasic/laybasic/layProperties.h +++ b/src/laybasic/laybasic/layProperties.h @@ -154,8 +154,10 @@ public: * Apply any changes to the current objects. If nothing was * changed, the object may be left untouched. * The dialog will start a transaction on the manager object. + * + * @param commit Is true for the "final" changes (i.e. not during editing) */ - virtual void apply () + virtual void apply (bool /*commit*/) { // default implementation is empty. } @@ -174,8 +176,11 @@ public: * Apply any changes to the current object plus all other objects of the same kind. * If nothing was changed, the objects may be left untouched. * The dialog will start a transaction on the manager object. + * + * @param relative Is true if relative mode is selected + * @param commit Is true for the "final" changes (i.e. not during editing) */ - virtual void apply_to_all (bool /*relative*/) + virtual void apply_to_all (bool /*relative*/, bool /*commit*/) { // default implementation is empty. } diff --git a/src/layui/layui/layPropertiesDialog.cc b/src/layui/layui/layPropertiesDialog.cc index b714742e8..edd85844b 100644 --- a/src/layui/layui/layPropertiesDialog.cc +++ b/src/layui/layui/layPropertiesDialog.cc @@ -197,7 +197,7 @@ PropertiesDialog::PropertiesDialog (QWidget * /*parent*/, db::Manager *manager, } for (size_t i = 0; i < mp_properties_pages.size (); ++i) { mp_stack->addWidget (mp_properties_pages [i]); - connect (mp_properties_pages [i], SIGNAL (edited ()), this, SLOT (apply ())); + connect (mp_properties_pages [i], SIGNAL (edited ()), this, SLOT (properties_edited ())); } // Necessary to maintain the page order for UI regression testing of 0.18 vs. 0.19 (because tl::Collection has changed to order) .. @@ -314,7 +314,7 @@ PropertiesDialog::current_index_changed (const QModelIndex &index, const QModelI db::Transaction t (mp_manager, tl::to_string (QObject::tr ("Apply changes")), m_transaction_id); - mp_properties_pages [m_index]->apply (); + mp_properties_pages [m_index]->apply (true); if (! t.is_empty ()) { m_transaction_id = t.id (); @@ -437,7 +437,7 @@ BEGIN_PROTECTED if (! mp_properties_pages [m_index]->readonly ()) { db::Transaction t (mp_manager, tl::to_string (QObject::tr ("Apply changes")), m_transaction_id); - mp_properties_pages [m_index]->apply (); + mp_properties_pages [m_index]->apply (true); if (! t.is_empty ()) { m_transaction_id = t.id (); } @@ -485,7 +485,7 @@ BEGIN_PROTECTED if (! mp_properties_pages [m_index]->readonly ()) { db::Transaction t (mp_manager, tl::to_string (QObject::tr ("Apply changes")), m_transaction_id); - mp_properties_pages [m_index]->apply (); + mp_properties_pages [m_index]->apply (true); if (! t.is_empty ()) { m_transaction_id = t.id (); } @@ -567,7 +567,7 @@ PropertiesDialog::any_prev () const } void -PropertiesDialog::apply () +PropertiesDialog::properties_edited () { BEGIN_PROTECTED @@ -580,9 +580,9 @@ BEGIN_PROTECTED try { if (mp_ui->apply_to_all_cbx->isChecked () && mp_properties_pages [m_index]->can_apply_to_all ()) { - mp_properties_pages [m_index]->apply_to_all (mp_ui->relative_cbx->isChecked ()); + mp_properties_pages [m_index]->apply_to_all (mp_ui->relative_cbx->isChecked (), false); } else { - mp_properties_pages [m_index]->apply (); + mp_properties_pages [m_index]->apply (false); } mp_properties_pages [m_index]->update (); @@ -632,7 +632,7 @@ BEGIN_PROTECTED db::Transaction t (mp_manager, tl::to_string (QObject::tr ("Apply changes")), m_transaction_id); - mp_properties_pages [m_index]->apply (); + mp_properties_pages [m_index]->apply (true); mp_properties_pages [m_index]->update (); if (! t.is_empty ()) { diff --git a/src/layui/layui/layPropertiesDialog.h b/src/layui/layui/layPropertiesDialog.h index 153002127..01e09db45 100644 --- a/src/layui/layui/layPropertiesDialog.h +++ b/src/layui/layui/layPropertiesDialog.h @@ -105,7 +105,7 @@ private: void update_controls (); public slots: - void apply (); + void properties_edited (); void next_pressed (); void prev_pressed (); void cancel_pressed (); From 07eb49d482e92f71365ca85f649bc3beb08e21fa Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 27 Apr 2025 01:11:38 +0200 Subject: [PATCH 02/18] 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 03/18] 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 04/18] 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 05/18] 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 06/18] 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 07/18] 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 08/18] 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 09/18] 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 10/18] 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 11/18] 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 12/18] 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 13/18] 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 14/18] 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 15/18] 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 09:07:55 -0400 Subject: [PATCH 16/18] Use Py_IncRef in pyaCallables.cc --- src/pya/pya/pyaCallables.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pya/pya/pyaCallables.cc b/src/pya/pya/pyaCallables.cc index 829f7076f..27f5fa790 100644 --- a/src/pya/pya/pyaCallables.cc +++ b/src/pya/pya/pyaCallables.cc @@ -49,7 +49,7 @@ pya_object_deallocate (PyObject *self) // may trigger a GC (https://github.com/KLayout/klayout/issues/1054). // According to the comments this may be turned into a release mode assertion, so // we better work around it. - ++self->ob_refcnt; + Py_IncRef(self); // Mute Python warnings in debug case PyObject_GC_UnTrack (self); From 7bee9ebcec43f90e5eb08dddb770f532add0a600 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 11 May 2025 21:48:01 +0200 Subject: [PATCH 17/18] 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 - From f9e2a9257fd11f2a67ff725c8c0c1eb548a23b76 Mon Sep 17 00:00:00 2001 From: Henner Zeller Date: Mon, 19 May 2025 14:15:31 +0200 Subject: [PATCH 18/18] Fix logic error in hex2int. This was probably never noticed as it was the last branch and would behave benign on valid input. Signed-off-by: Henner Zeller --- src/tl/tl/tlUri.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tl/tl/tlUri.cc b/src/tl/tl/tlUri.cc index d0a6aade3..8032a2cc2 100644 --- a/src/tl/tl/tlUri.cc +++ b/src/tl/tl/tlUri.cc @@ -41,7 +41,7 @@ static char hex2int (char c) return c - '0'; } else if (c >= 'A' && c <= 'F') { return (c - 'A') + 10; - } else if (c >= 'a' || c <= 'f') { + } else if (c >= 'a' && c <= 'f') { return (c - 'a') + 10; } else { return 0;