Merge pull request #499 from antmicro/mglb/StreamingOperator

Improve right-to-left streaming operator support.
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1ab44d1..95737de 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -78,3 +78,35 @@
       env:
         OS: ${{ runner.os }}
         PLUGIN_NAME: ${{ matrix.plugin }}
+
+  release-tagging:
+    name: Version Tagging
+    runs-on: ubuntu-20.04
+    if: ${{github.event_name == 'push' && github.ref == 'refs/heads/main'}}
+    permissions:
+      contents: write
+
+    steps:
+    - uses: actions/checkout@v2
+      with:
+       fetch-depth: 0
+       token: ${{ secrets.GITHUB_TOKEN }}
+
+    - name: Tag with Makefile version if not already.
+      run: |
+        git config --local user.name "Development Bot"
+        git config --local user.email "f4pga-dev@chipsalliance.org"
+
+        # We want to tag whenever the version in the Makefile changes.
+        # So extract the hash of when the current version was entered.
+        read TAG_HASH TAG_VERSION <<<$(git annotate -l Makefile | sed 's/\(^[0-9A-Fa-f]\+\).*PLUGIN_VERSION\s\+=\s\+\([0-9]\+\.[0-9]\+\).*/\1 \2/p;d')
+
+        echo "F4PGA Yosys Plugin Version v${TAG_VERSION} at hash ${TAG_HASH}"
+
+        # If this is the first time we see this tag: apply.
+        if [ -z "$(git tag -l "v${TAG_VERSION}")" ]; then
+          git tag -a "v${TAG_VERSION}" ${TAG_HASH} -m "Update to v${TAG_VERSION}"
+          git push origin "v${TAG_VERSION}"
+        else
+          echo "Tag already applied"
+        fi
diff --git a/Makefile b/Makefile
index 70433f7..392f966 100644
--- a/Makefile
+++ b/Makefile
@@ -14,6 +14,16 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 
+# Version number of Plugins. For simplicity, based on date when we choose to
+# release. We can get more sophisticated later (but then need bump Major >= 2).
+# Version number has a Major and Minor version number, git-tags are free to
+# append a patchlevel (which is number of commits since last X.Y update).
+#
+# The CI will automatically tag the release with v${PLLUGIN_VERSION}
+#
+# TODO: pass as -D to gcc so that modules can provide e.g. --version flags.
+PLUGIN_VERSION = 1.20230425
+
 PLUGIN_LIST := fasm xdc params sdc ql-iob design_introspection integrateinv ql-qlf systemverilog uhdm dsp-ff
 PLUGINS := $(foreach plugin,$(PLUGIN_LIST),$(plugin).so)
 PLUGINS_INSTALL := $(foreach plugin,$(PLUGIN_LIST),install_$(plugin))
diff --git a/clockgating-plugin/tests/regfile/regfile.tcl b/clockgating-plugin/tests/regfile/regfile.tcl
index 22bd9d6..b96ce2e 100644
--- a/clockgating-plugin/tests/regfile/regfile.tcl
+++ b/clockgating-plugin/tests/regfile/regfile.tcl
@@ -1,18 +1,20 @@
 yosys -import
-if { [info procs getparam] == {} } { plugin -i params }
+if { [info procs reg_clock_gating] == {} } { plugin -i clockgating }
 yosys -import  ;# ingest plugin commands
 
+set LIBDIR [file dirname $::env(DESIGN_TOP)]/lib
+
 read_verilog $::env(DESIGN_TOP).v
-read_liberty -lib -ignore_miss_dir -setattr blackbox ./lib/sky130_fd_sc_hd.lib 
-read_verilog ./lib/sky130_hd_clkg_blackbox.v
+read_liberty -lib -ignore_miss_dir -setattr blackbox $LIBDIR/sky130_fd_sc_hd.lib
+read_verilog $LIBDIR/sky130_hd_clkg_blackbox.v
 hierarchy -check -auto-top
 
 
-reg_clock_gating ./lib/sky130_hd_ff_map.v
+reg_clock_gating $LIBDIR/sky130_hd_ff_map.v
 opt_clean -purge
 synth -top top
-dfflibmap -liberty ./lib/sky130_fd_sc_hd.lib 
-abc -D 1250 -liberty ./lib/sky130_fd_sc_hd.lib 
+dfflibmap -liberty $LIBDIR/sky130_fd_sc_hd.lib
+abc -D 1250 -liberty $LIBDIR/sky130_fd_sc_hd.lib
 splitnets
 opt_clean -purge
 hilomap -hicell sky130_fd_sc_hd__conb_1 HI -locell sky130_fd_sc_hd__conb_1 LO
@@ -21,7 +23,6 @@
 insbuf -buf sky130_fd_sc_hd__buf_2 A X
 dffinit
 flatten
-opt;; 
+opt;;
 #check
-write_verilog -noattr -noexpr -nohex -nodec -defparam clockgated_regfile.v
-            
\ No newline at end of file
+write_verilog -noattr -noexpr -nohex -nodec -defparam [test_output_path "clockgated_regfile.v"]
diff --git a/systemverilog-plugin/UhdmAst.cc b/systemverilog-plugin/UhdmAst.cc
index 740fcc8..94736fe 100644
--- a/systemverilog-plugin/UhdmAst.cc
+++ b/systemverilog-plugin/UhdmAst.cc
@@ -49,6 +49,7 @@
 
 namespace attr_id
 {
+static bool already_initialized = false;
 static IdString partial;
 static IdString packed_ranges;
 static IdString unpacked_ranges;
@@ -71,10 +72,9 @@
 void attr_id_init()
 {
     // Initialize only once
-    static bool already_initialized = false;
-    if (already_initialized)
+    if (attr_id::already_initialized)
         return;
-    already_initialized = true;
+    attr_id::already_initialized = true;
 
     // Actual initialization
 
@@ -101,6 +101,7 @@
     attr_id::packed_ranges = IdString();
     attr_id::partial = IdString();
     attr_id::is_type_parameter = IdString();
+    attr_id::already_initialized = false;
 }
 
 static AST::AstNode *get_attribute(AST::AstNode *node, const IdString &attribute)
@@ -1982,7 +1983,14 @@
                               shared.top_nodes[node->str] = node;
                           }
                       });
-    visit_one_to_many({vpiParameter, vpiParamAssign}, obj_h, [&](AST::AstNode *node) {});
+    visit_one_to_many({vpiParameter, vpiParamAssign}, obj_h, [&](AST::AstNode *node) {
+        if (get_attribute(node, attr_id::is_type_parameter)) {
+            // Don't process type parameters.
+            delete node;
+            return;
+        }
+        add_or_replace_child(current_node, node);
+    });
     visit_one_to_many({vpiTypedef}, obj_h, [&](AST::AstNode *node) {
         if (node)
             move_type_to_new_typedef(current_node, node);
@@ -2095,6 +2103,11 @@
                                vpiContAssign, vpiVariables},
                               obj_h, [&](AST::AstNode *node) {
                                   if (node) {
+                                      if (get_attribute(node, attr_id::is_type_parameter)) {
+                                          // Don't process type parameters.
+                                          delete node;
+                                          return;
+                                      }
                                       add_or_replace_child(current_node, node);
                                   }
                               });
@@ -2121,8 +2134,12 @@
             });
             visit_one_to_many({vpiModule, vpiParameter, vpiParamAssign, vpiNet, vpiArrayNet, vpiProcess}, obj_h, [&](AST::AstNode *node) {
                 if (node) {
-                    if ((node->type == AST::AST_ASSIGN && node->children.size() < 2) ||
-                        (node->type == AST::AST_PARAMETER && get_attribute(node, attr_id::is_type_parameter))) {
+                    if (get_attribute(node, attr_id::is_type_parameter)) {
+                        // Don't process type parameters.
+                        delete node;
+                        return;
+                    }
+                    if ((node->type == AST::AST_ASSIGN && node->children.size() < 2)) {
                         delete node;
                         return;
                     }
@@ -3004,6 +3021,11 @@
     });
     visit_one_to_many({vpiParameter, vpiParamAssign}, obj_h, [&](AST::AstNode *node) {
         if (node) {
+            if (get_attribute(node, attr_id::is_type_parameter)) {
+                // Don't process type parameters.
+                delete node;
+                return;
+            }
             node->str = strip_package_name(node->str);
             for (auto c : node->children) {
                 c->str = strip_package_name(c->str);
@@ -3962,6 +3984,11 @@
       {vpiParameter, vpiParamAssign, vpiNet, vpiArrayNet, vpiVariables, vpiContAssign, vpiProcess, vpiModule, vpiGenScopeArray, vpiTaskFunc}, obj_h,
       [&](AST::AstNode *node) {
           if (node) {
+              if (get_attribute(node, attr_id::is_type_parameter)) {
+                  // Don't process type parameters.
+                  delete node;
+                  return;
+              }
               add_or_replace_child(current_node, node);
           }
       });
@@ -4091,6 +4118,11 @@
     });
     visit_one_to_many({vpiParameter, vpiParamAssign}, obj_h, [&](AST::AstNode *node) {
         if (node) {
+            if (get_attribute(node, attr_id::is_type_parameter)) {
+                // Don't process type parameters.
+                delete node;
+                return;
+            }
             add_or_replace_child(current_node, node);
         }
     });
diff --git a/systemverilog-plugin/tests/break_continue/break_continue.tcl b/systemverilog-plugin/tests/break_continue/break_continue.tcl
index 166c38e..911db18 100644
--- a/systemverilog-plugin/tests/break_continue/break_continue.tcl
+++ b/systemverilog-plugin/tests/break_continue/break_continue.tcl
@@ -10,4 +10,4 @@
 # Testing simple round-trip
 read_systemverilog -o $TMP_DIR/break-continue-test $::env(DESIGN_TOP).v
 prep
-write_table $::env(DESIGN_TOP).out
+write_table [test_output_path $::env(DESIGN_TOP).out]
diff --git a/systemverilog-plugin/tests/defaults/defaults.tcl b/systemverilog-plugin/tests/defaults/defaults.tcl
index a363895..6639834 100644
--- a/systemverilog-plugin/tests/defaults/defaults.tcl
+++ b/systemverilog-plugin/tests/defaults/defaults.tcl
@@ -12,12 +12,12 @@
 # Stash it
 systemverilog_defaults -push
 systemverilog_defaults -clear
-read_systemverilog $::env(DESIGN_TOP).v
+read_systemverilog -o $TMP_DIR/defaults-test $::env(DESIGN_TOP).v
 # Allow parsing the module again
 delete top
 systemverilog_defaults -pop
 # Skip check for forbidden value
 systemverilog_defaults -add -Pbypass=1
-read_systemverilog $::env(DESIGN_TOP).v
+read_systemverilog -o $TMP_DIR/defaults-test $::env(DESIGN_TOP).v
 hierarchy
 write_verilog
diff --git a/systemverilog-plugin/tests/defines/defines.tcl b/systemverilog-plugin/tests/defines/defines.tcl
index 030c1ad..81a93d4 100644
--- a/systemverilog-plugin/tests/defines/defines.tcl
+++ b/systemverilog-plugin/tests/defines/defines.tcl
@@ -10,6 +10,6 @@
 systemverilog_defines -DPONA
 systemverilog_defines -DPAKALA
 systemverilog_defines -UPAKALA
-read_systemverilog $::env(DESIGN_TOP).v
+read_systemverilog -o $TMP_DIR/defines-test $::env(DESIGN_TOP).v
 hierarchy
 write_verilog
diff --git a/systemverilog-plugin/tests/formal/formal.tcl b/systemverilog-plugin/tests/formal/formal.tcl
index 2474219..e383c08 100644
--- a/systemverilog-plugin/tests/formal/formal.tcl
+++ b/systemverilog-plugin/tests/formal/formal.tcl
@@ -7,6 +7,6 @@
   set TMP_DIR $::env(TMPDIR)
 }
 
-read_systemverilog -formal $::env(DESIGN_TOP).v
+read_systemverilog -o $TMP_DIR/formal-test -formal $::env(DESIGN_TOP).v
 hierarchy
 write_verilog
diff --git a/systemverilog-plugin/uhdmastfrontend.cc b/systemverilog-plugin/uhdmastfrontend.cc
index 427fb37..d8f782f 100644
--- a/systemverilog-plugin/uhdmastfrontend.cc
+++ b/systemverilog-plugin/uhdmastfrontend.cc
@@ -17,14 +17,10 @@
  *
  */
 
+#include "uhdm/uhdm-version.h" // UHDM_VERSION define
+#include "uhdm/vpi_visitor.h"  // visit_object
 #include "uhdmcommonfrontend.h"
 
-namespace UHDM
-{
-extern void visit_object(vpiHandle obj_h, int indent, const char *relation, std::set<const BaseClass *> *visited, std::ostream &out,
-                         bool shallowVisit = false);
-}
-
 namespace systemverilog_plugin
 {
 
@@ -54,7 +50,11 @@
         if (this->shared.debug_flag || !this->report_directory.empty()) {
             for (auto design : restoredDesigns) {
                 std::ofstream null_stream;
+#if UHDM_VERSION > 1057
+                UHDM::visit_object(design, this->shared.debug_flag ? std::cout : null_stream);
+#else
                 UHDM::visit_object(design, 1, "", &this->shared.report.unhandled, this->shared.debug_flag ? std::cout : null_stream);
+#endif
             }
         }
         UhdmAst uhdm_ast(this->shared);
diff --git a/systemverilog-plugin/uhdmsurelogastfrontend.cc b/systemverilog-plugin/uhdmsurelogastfrontend.cc
index 1361184..cac39ef 100644
--- a/systemverilog-plugin/uhdmsurelogastfrontend.cc
+++ b/systemverilog-plugin/uhdmsurelogastfrontend.cc
@@ -37,12 +37,8 @@
 #include "Surelog/CommandLine/CommandLineParser.h"
 #include "Surelog/ErrorReporting/ErrorContainer.h"
 #include "Surelog/SourceCompile/SymbolTable.h"
-
-namespace UHDM
-{
-extern void visit_object(vpiHandle obj_h, int indent, const char *relation, std::set<const BaseClass *> *visited, std::ostream &out,
-                         bool shallowVisit = false);
-}
+#include "uhdm/uhdm-version.h" // UHDM_VERSION define
+#include "uhdm/vpi_visitor.h"  // visit_object
 
 namespace systemverilog_plugin
 {
@@ -194,7 +190,11 @@
         if (this->shared.debug_flag || !this->report_directory.empty()) {
             for (auto design : uhdm_designs) {
                 std::ofstream null_stream;
+#if UHDM_VERSION > 1057
+                UHDM::visit_object(design, this->shared.debug_flag ? std::cout : null_stream);
+#else
                 UHDM::visit_object(design, 1, "", &this->shared.report.unhandled, this->shared.debug_flag ? std::cout : null_stream);
+#endif
             }
         }
 
diff --git a/test-utils/test-utils.tcl b/test-utils/test-utils.tcl
index cc215ae..1b1188a 100644
--- a/test-utils/test-utils.tcl
+++ b/test-utils/test-utils.tcl
@@ -3,5 +3,6 @@
 # Return path where the test output file "filename"
 # is to be written.
 proc test_output_path { filename } {
+    file mkdir [file dirname "$::env(TEST_OUTPUT_PREFIX)${filename}"]
     return "$::env(TEST_OUTPUT_PREFIX)${filename}"
 }