Repository: ucb-bar/hammer
Pull request #886: Update ICV defaults for RHEL9, fix version_number()
Author: login: daniellovell
Created: 2025-02-28T08:36:52Z | Merged: 2025-03-07T01:05:01Z

The BWRC servers migrated to RHEL9, and with that, our old setup using S-2021.06-SP3-2 for the default ICV version is not functional.

In general, users of RHEL9 should adopt W-2024.09-4 for ICV and V-2023.09-SP2 for ICVWB.

Synopsys now defaults to install these newer ICV versions at the /icvalidator/ directory instead of /icv/, so the ICV_HOME env var should reflect this.

Finally, SynopsysTool.version_number() fails to correctly parse W-2024.09-4:
![image](https://github.com/user-attachments/assets/c2a32e9a-2935-4e55-9048-b1f5366348b7)

This change fixes that, and includes regression unit tests to ensure previous versions of ICV can still be successfully parsed

**Related PRs / Issues**
Related to this PR for hammer-intech22-plugin https://bwrcrepo.eecs.berkeley.edu/intech22/hammer-intech22-plugin/-/merge_requests/72

<!-- choose one -->
**Type of change**:
- [x] Bug fix
- [ ] New feature
- [ ] Other enhancement

<!-- choose one -->
**Impact**:
- [ ] Change to core Hammer
- [x] Change to a Hammer plugin
- [ ] Other

<!-- must be filled out completely to be considered for merging -->
**Contributor Checklist**:
- [x] Did you set `master` as the base branch?
- [x] Did you state the type-of-change/impact?
- [x] Did you delete any extraneous prints/debugging code?
- [ ] (If applicable) Did you add documentation for the feature?
- [ ] (If applicable) Did you update the `poetry.lock` file if you updated the requirements in `pyproject.toml`?
- [x] (If applicable) Did you add a unit test demonstrating the PR?
- [ ] (If applicable) Did you run this through the e2e integration tests?
- [ ] (If applicable) Did you update the submodules in `e2e/` if this feature depends on updated plugins?



Diff:
diff --git a/hammer/common/synopsys/__init__.py b/hammer/common/synopsys/__init__.py
index c77622f70..02c71d8fd 100644
--- a/hammer/common/synopsys/__init__.py
+++ b/hammer/common/synopsys/__init__.py
@@ -32,13 +32,25 @@ def version_number(self, version: str) -> int:
         """
         Assumes versions look like NAME-YYYY.MM-SPMINOR.
         Assumes less than 100 minor versions.
+        
+        Handles various version formats:
+        - NAME-YYYY.MM (no minor version)
+        - NAME-YYYY.MM-N (where N is a number like 4)
+        - NAME-YYYY.MM-SPN (where SP is a prefix and N is a number)
+        - NAME-YYYY.MM-PREFIXN (where PREFIX is any text and N is a number)
         """
         date = "-".join(version.split("-")[1:])  # type: str
         year = int(date.split(".")[0])  # type: int
         month = int(date.split(".")[1][:2])  # type: int
         minor_version = 0  # type: int
         if "-" in date:
-            minor_version = int(date.split("-")[1][2:])
+            minor_part = date.split("-")[1]
+            # Try to handle both formats: with prefix (like "SP4") and without (like "4")
+            # If the minor part starts with non-digits, skip them
+            for i, char in enumerate(minor_part):
+                if char.isdigit():
+                    minor_version = int(minor_part[i:])
+                    break
         return (year * 100 + month) * 100 + minor_version
 
     @property
diff --git a/hammer/drc/icv/defaults.yml b/hammer/drc/icv/defaults.yml
index bc43cfe5e..5dc479dcf 100644
--- a/hammer/drc/icv/defaults.yml
+++ b/hammer/drc/icv/defaults.yml
@@ -1,22 +1,24 @@
 # Default settings for ICV DRC, for project/technology configuration and overriding.
 drc.icv:
+    # Note: Older versions of ICV are often located at /icv/ instead of /icvalidator/.
+    # If you are using an older version, you should change the path in addition to the version.
     # Location of the binary
-    icv_drc_bin: "${synopsys.synopsys_home}/icv/${drc.icv.version}/bin/LINUX.64/icv"
+    icv_drc_bin: "${synopsys.synopsys_home}/icvalidator/${drc.icv.version}/bin/LINUX.64/icv"
     icv_drc_bin_meta: lazysubst
 
-    icv_vue_bin: "${synopsys.synopsys_home}/icv/${drc.icv.version}/bin/LINUX.64/icv_vue"
+    icv_vue_bin: "${synopsys.synopsys_home}/icvalidator/${drc.icv.version}/bin/LINUX.64/icv_vue"
     icv_vue_bin_meta: lazysubst
 
     icvwb_bin: "${synopsys.synopsys_home}/icvwb/${drc.icv.icvwb_version}/bin/icvwb"
     icvwb_bin_meta: lazysubst
 
-    ICV_HOME_DIR: "${synopsys.synopsys_home}/icv/${drc.icv.version}"
+    ICV_HOME_DIR: "${synopsys.synopsys_home}/icvalidator/${drc.icv.version}"
     ICV_HOME_DIR_meta: lazysubst
 
     # type: str
-    version: "S-2021.06-SP3-2"
+    version: "W-2024.09-4"
     # type: str
-    icvwb_version: "S-2021.06-SP2"
+    icvwb_version: "V-2023.09-SP2"
     # Port for VUE (violation browser) to communicate with ICVWB (layout browser)
     # Any open port 1000 to 65536 allowed
     # type: int
diff --git a/hammer/lvs/icv/defaults.yml b/hammer/lvs/icv/defaults.yml
index 196dfa50a..fba4e4aeb 100644
--- a/hammer/lvs/icv/defaults.yml
+++ b/hammer/lvs/icv/defaults.yml
@@ -1,25 +1,27 @@
 # Default settings for ICV lvs, for project/technology configuration and overriding.
 lvs.icv:
+    # Note: Older versions of ICV are often located at /icv/ instead of /icvalidator/.
+    # If you are using an older version, you should change the path in addition to the version.
     # Location of the binary
-    icv_lvs_bin: "${synopsys.synopsys_home}/icv/${lvs.icv.version}/bin/LINUX.64/icv"
+    icv_lvs_bin: "${synopsys.synopsys_home}/icvalidator/${lvs.icv.version}/bin/LINUX.64/icv"
     icv_lvs_bin_meta: lazysubst
 
-    icv_nettran_bin: "${synopsys.synopsys_home}/icv/${lvs.icv.version}/bin/LINUX.64/icv_nettran"
+    icv_nettran_bin: "${synopsys.synopsys_home}/icvalidator/${lvs.icv.version}/bin/LINUX.64/icv_nettran"
     icv_nettran_bin_meta: lazysubst
 
-    icv_vue_bin: "${synopsys.synopsys_home}/icv/${lvs.icv.version}/bin/LINUX.64/icv_vue"
+    icv_vue_bin: "${synopsys.synopsys_home}/icvalidator/${lvs.icv.version}/bin/LINUX.64/icv_vue"
     icv_vue_bin_meta: lazysubst
 
     icvwb_bin: "${synopsys.synopsys_home}/icvwb/${lvs.icv.icvwb_version}/bin/icvwb"
     icvwb_bin_meta: lazysubst
 
-    ICV_HOME_DIR: "${synopsys.synopsys_home}/icv/${lvs.icv.version}"
+    ICV_HOME_DIR: "${synopsys.synopsys_home}/icvalidator/${lvs.icv.version}"
     ICV_HOME_DIR_meta: lazysubst
 
     # type: str
-    version: "S-2021.06-SP3-2"
+    version: "W-2024.09-4"
     # type: str
-    icvwb_version: "S-2021.06-SP2"
+    icvwb_version: "V-2023.09-SP2"
     # Port for VUE (violation browser) to communicate with ICVWB (layout browser)
     # Any open port 1000 to 65536 allowed
     # type: int
diff --git a/tests/test_synopsys_tool.py b/tests/test_synopsys_tool.py
new file mode 100644
index 000000000..c3edfb56b
--- /dev/null
+++ b/tests/test_synopsys_tool.py
@@ -0,0 +1,48 @@
+import unittest
+import sys
+import os
+
+# Add the hammer path to the import path
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
+
+from hammer.common.synopsys import SynopsysTool
+
+class TestSynopsysTool(unittest.TestCase):
+    """Test the SynopsysTool class"""
+    
+    def setUp(self):
+        # Create an instance of SynopsysTool for testing
+        class MinimalSynopsysTool(SynopsysTool):
+            def tool_config_prefix(self):
+                return "synopsys"
+            
+            def get_setting(self, key, nullvalue=None):
+                return nullvalue
+                
+            # Implement the abstract property steps
+            @property
+            def steps(self):
+                return []
+        
+        self.tool = MinimalSynopsysTool()
+    
+    def test_version_number_icv_formats(self):
+        """Test actual ICV version formats."""
+        # Test S-2021.06-SP3-2 format
+        version1 = "S-2021.06-SP3-2"
+        expected1 = (2021 * 100 + 6) * 100 + 3  # The method should extract 3 from SP3-2
+        self.assertEqual(self.tool.version_number(version1), expected1)
+        
+        # Test W-2024.09-4 format
+        version2 = "W-2024.09-4"
+        expected2 = (2024 * 100 + 9) * 100 + 4
+        self.assertEqual(self.tool.version_number(version2), expected2)
+        
+        # Test V-2023.09-SP2 format
+        version3 = "V-2023.09-SP2"
+        expected3 = (2023 * 100 + 9) * 100 + 2
+        self.assertEqual(self.tool.version_number(version3), expected3)
+
+
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file


Reviews:
user: login: elamdf
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T00:03:24Z
user: login: daniellovell
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T00:03:25Z
user: login: daniellovell
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-07T00:24:00Z
user: login: elamdf
body: LGTM! Maybe someone like @kenhoberkeley can review + merge the intech PR, I don't have write access to that one
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-07T00:39:29Z

Review comments:
diff_hunk: @@ -1,22 +1,22 @@
 # Default settings for ICV DRC, for project/technology configuration and overriding.
 drc.icv:
     # Location of the binary
-    icv_drc_bin: "${synopsys.synopsys_home}/icv/${drc.icv.version}/bin/LINUX.64/icv"
+    icv_drc_bin: "${synopsys.synopsys_home}/icvalidator/${drc.icv.version}/bin/LINUX.64/icv"
     icv_drc_bin_meta: lazysubst
 
-    icv_vue_bin: "${synopsys.synopsys_home}/icv/${drc.icv.version}/bin/LINUX.64/icv_vue"
+    icv_vue_bin: "${synopsys.synopsys_home}/icvalidator/${drc.icv.version}/bin/LINUX.64/icv_vue"
     icv_vue_bin_meta: lazysubst
 
     icvwb_bin: "${synopsys.synopsys_home}/icvwb/${drc.icv.icvwb_version}/bin/icvwb"
     icvwb_bin_meta: lazysubst
 
-    ICV_HOME_DIR: "${synopsys.synopsys_home}/icv/${drc.icv.version}"
path: hammer/drc/icv/defaults.yml
user: login: elamdf
body: can a comment/log warning be added for version < 2024.09-4 that the icv home dir will be diff?
created_at: 2025-03-06T00:03:17Z
author_association: COLLABORATOR
diff_hunk: @@ -1,22 +1,22 @@
 # Default settings for ICV DRC, for project/technology configuration and overriding.
 drc.icv:
     # Location of the binary
-    icv_drc_bin: "${synopsys.synopsys_home}/icv/${drc.icv.version}/bin/LINUX.64/icv"
+    icv_drc_bin: "${synopsys.synopsys_home}/icvalidator/${drc.icv.version}/bin/LINUX.64/icv"
     icv_drc_bin_meta: lazysubst
 
-    icv_vue_bin: "${synopsys.synopsys_home}/icv/${drc.icv.version}/bin/LINUX.64/icv_vue"
+    icv_vue_bin: "${synopsys.synopsys_home}/icvalidator/${drc.icv.version}/bin/LINUX.64/icv_vue"
     icv_vue_bin_meta: lazysubst
 
     icvwb_bin: "${synopsys.synopsys_home}/icvwb/${drc.icv.icvwb_version}/bin/icvwb"
     icvwb_bin_meta: lazysubst
 
-    ICV_HOME_DIR: "${synopsys.synopsys_home}/icv/${drc.icv.version}"
path: hammer/drc/icv/defaults.yml
user: login: daniellovell
body: @elamdf Requested a comment to users that hints their directory may be /icv/ instead of /icvalidator/
created_at: 2025-03-06T00:03:25Z
author_association: COLLABORATOR
diff_hunk: @@ -1,22 +1,22 @@
 # Default settings for ICV DRC, for project/technology configuration and overriding.
 drc.icv:
     # Location of the binary
-    icv_drc_bin: "${synopsys.synopsys_home}/icv/${drc.icv.version}/bin/LINUX.64/icv"
+    icv_drc_bin: "${synopsys.synopsys_home}/icvalidator/${drc.icv.version}/bin/LINUX.64/icv"
     icv_drc_bin_meta: lazysubst
 
-    icv_vue_bin: "${synopsys.synopsys_home}/icv/${drc.icv.version}/bin/LINUX.64/icv_vue"
+    icv_vue_bin: "${synopsys.synopsys_home}/icvalidator/${drc.icv.version}/bin/LINUX.64/icv_vue"
     icv_vue_bin_meta: lazysubst
 
     icvwb_bin: "${synopsys.synopsys_home}/icvwb/${drc.icv.icvwb_version}/bin/icvwb"
     icvwb_bin_meta: lazysubst
 
-    ICV_HOME_DIR: "${synopsys.synopsys_home}/icv/${drc.icv.version}"
path: hammer/drc/icv/defaults.yml
user: login: daniellovell
body: Resolved in https://github.com/ucb-bar/hammer/pull/886/commits/1bcd48b698aacffc5786038ff567ffc5eb427c34

created_at: 2025-03-07T00:24:00Z
author_association: COLLABORATOR

PR comments:
user: login: daniellovell
created_at: 2025-02-28T09:04:58Z
body: Should pass all checks if #887 is merged.
author_association: COLLABORATOR
user: login: daniellovell
created_at: 2025-03-01T01:13:17Z
body: Note: the fact that this changes the default ICV directory to `/icvalidator/` is a somewhat troublesome change. Users who want to use an older version of icv in their `icv.version` will always need to change the ICV_HOME directory as well. That is to say, this isn't really backward compatible with older default ICV installation directories (`/icv/VERSION_NUM`). It is forward compatible with Synopsys's new default ICV installation directories (`/icvalidator/VERSION_NUM`)


author_association: COLLABORATOR
user: login: daniellovell
created_at: 2025-03-01T02:44:04Z
body: Tested a few runs of ICV DRC, then used the `generated-scripts/view_drc` to pop open ICVWB successfully. 
Removed the DRAFT tag

Ready to be reviewed
author_association: COLLABORATOR
user: login: daniellovell
created_at: 2025-03-07T00:25:05Z
body: Recommend that this is merged together with https://bwrcrepo.eecs.berkeley.edu/intech22/hammer-intech22-plugin/-/merge_requests/72
author_association: COLLABORATOR