afsvalint 2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. afsvalint-2.0/PKG-INFO +7 -0
  2. afsvalint-2.0/README.md +67 -0
  3. afsvalint-2.0/setup.cfg +4 -0
  4. afsvalint-2.0/setup.py +18 -0
  5. afsvalint-2.0/src/SVALint/__init__.py +0 -0
  6. afsvalint-2.0/src/SVALint/__main__.py +9 -0
  7. afsvalint-2.0/src/SVALint/af_lint_rule.py +58 -0
  8. afsvalint-2.0/src/SVALint/asfigo_linter.py +121 -0
  9. afsvalint-2.0/src/SVALint/rules/__init__.py +0 -0
  10. afsvalint-2.0/src/SVALint/rules/af_asrt_naming.py +45 -0
  11. afsvalint-2.0/src/SVALint/rules/af_asrt_no_label.py +30 -0
  12. afsvalint-2.0/src/SVALint/rules/af_assume_naming.py +39 -0
  13. afsvalint-2.0/src/SVALint/rules/af_cover_naming.py +39 -0
  14. afsvalint-2.0/src/SVALint/rules/af_func_cov_nolap.py +33 -0
  15. afsvalint-2.0/src/SVALint/rules/af_func_cov_olap.py +33 -0
  16. afsvalint-2.0/src/SVALint/rules/af_func_missing_fablk.py +36 -0
  17. afsvalint-2.0/src/SVALint/rules/af_func_no_ub_in_cnseq.py +43 -0
  18. afsvalint-2.0/src/SVALint/rules/af_missing_elbl_prop.py +34 -0
  19. afsvalint-2.0/src/SVALint/rules/af_missing_elbl_seq.py +34 -0
  20. afsvalint-2.0/src/SVALint/rules/af_no_aa_exists_sva.py +56 -0
  21. afsvalint-2.0/src/SVALint/rules/af_no_dollar_time.py +41 -0
  22. afsvalint-2.0/src/SVALint/rules/af_no_fmatch_oper.py +44 -0
  23. afsvalint-2.0/src/SVALint/rules/af_no_pop_back_sva.py +57 -0
  24. afsvalint-2.0/src/SVALint/rules/af_no_pop_front_sva.py +57 -0
  25. afsvalint-2.0/src/SVALint/rules/af_no_range_ant.py +58 -0
  26. afsvalint-2.0/src/SVALint/rules/af_no_timeliteral.py +37 -0
  27. afsvalint-2.0/src/SVALint/rules/af_no_within_oper.py +46 -0
  28. afsvalint-2.0/src/SVALint/rules/af_perf_missing_impl_oper.py +29 -0
  29. afsvalint-2.0/src/SVALint/rules/af_perf_no_large_del.py +33 -0
  30. afsvalint-2.0/src/SVALint/rules/af_perf_no_pass_ablk.py +37 -0
  31. afsvalint-2.0/src/SVALint/rules/af_perf_no_ub_range_ant.py +51 -0
  32. afsvalint-2.0/src/SVALint/rules/af_prop_naming.py +37 -0
  33. afsvalint-2.0/src/SVALint/rules/af_reuse_fa_one_liner.py +42 -0
  34. afsvalint-2.0/src/SVALint/rules/af_use_simple_cnseq.py +45 -0
  35. afsvalint-2.0/src/afsvalint.egg-info/PKG-INFO +7 -0
  36. afsvalint-2.0/src/afsvalint.egg-info/SOURCES.txt +38 -0
  37. afsvalint-2.0/src/afsvalint.egg-info/dependency_links.txt +1 -0
  38. afsvalint-2.0/src/afsvalint.egg-info/entry_points.txt +2 -0
  39. afsvalint-2.0/src/afsvalint.egg-info/requires.txt +3 -0
  40. afsvalint-2.0/src/afsvalint.egg-info/top_level.txt +1 -0
afsvalint-2.0/PKG-INFO ADDED
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: afsvalint
3
+ Version: 2.0
4
+ Requires-Dist: anytree
5
+ Requires-Dist: tomli
6
+ Requires-Dist: python-string-utils
7
+ Dynamic: requires-dist
@@ -0,0 +1,67 @@
1
+ # SVALint
2
+ Linter for SystemVerilog Assertions (SVA). Following the philosophy of BYOL - Build Your Own Linter, SVALint is an example of how users can roll out their own linters!
3
+
4
+ **SVALint** is an open-source **minimalist** linter tool designed to enforce style and consistency rules for SystemVerilog code. It provides a framework for **Build Your Own Linter** (**BYOL**), allowing users to create their own custom lint rules while benefiting from built-in checks such as proper encapsulation, naming conventions, line spacing, and other cosmetic rules. This linter integrates seamlessly into your development pipeline to ensure consistent, high-quality code.
5
+ ## Table of Contents
6
+ 1. [SVALint: SystemVerilog Checker - Linter](#svalint-systemverilog-checker---linter)
7
+ 2. [BYOL - Build Your Own Linter](#byol---build-your-own-linter)
8
+ 3. [Open Source](#open-source)
9
+ 4. [Directory Structure](#directory-structure)
10
+ 5. [Installation](#installation)
11
+ 6. [Usage](#usage)   - [Running the Linter from Command Line](#running-the-linter-from-command-line)   - [Running with Makefile (Optional)](#running-with-makefile-optional)   - [Test Cases](#test-cases)
12
+ 7. [Adding New Lint Rules](#adding-new-lint-rules)
13
+ 8. [Example Rule (in `src/rules/`)](#example-rule-in-srcrules)
14
+ 9. [Dependencies](#dependencies)
15
+ 10. [License](#license)
16
+ 11. [Credits](#credits)
17
+
18
+ ## BYOL - Build Your Own Linter
19
+ The core concept of **SVALint** is **BYOL** (Build Your Own Linter), a framework that lets you easily define custom linting rules tailored to your specific needs. Whether it's enforcing naming conventions, checking for proper encapsulation, or any other rule, **SVALint** is flexible and extensible.
20
+ With **BYOL**, you can create new rules quickly and add them to your pipeline. The linter is fully customizable, empowering you to ensure that your SystemVerilog code adheres to your specific standards.
21
+ ## Open Source
22
+ This project is **open source** and licensed under the MIT License. Contributions are welcome, and you are free to fork, modify, and distribute it according to your needs. We encourage you to contribute to the community by adding new rules, improving the existing ones, or integrating **SVALint** with other tools and environments.
23
+ ## Directory Structure
24
+ TBD
25
+ ## Installation
26
+ 1. Clone the repository:
27
+ ```bash
28
+ git clone https://github.com/AsFigo/svalint.git
29
+ cd svalint
30
+ ```
31
+ 3. Install required dependencies - Verible mainly
32
+
33
+ See: https://github.com/chipsalliance/verible
34
+
35
+ 3. pip install anytree
36
+ 4. pip install tomli
37
+
38
+
39
+ ## Usage
40
+ ### Running the Linter from Command Line
41
+ The linter can be run using the `svalint.py` script located in the `bin/` directory. This script checks SystemVerilog files against the defined style rules.
42
+ 1. To run the linter on a specific file:
43
+ ```bash
44
+ python bin/svalint.py -t <path_to_file.sv>
45
+ ```
46
+
47
+ ### Adding New Lint Rules
48
+ 1. Create a new Python file inside the `src/rules/` directory. Each file should contain a class that inherits from the base linter class (`AsFigoLinter`).
49
+ 2. Implement the rule logic in the derived class. Each rule should implement a method like `apply` or `run` to check for the specific violation.
50
+ 3. After implementing the rule, add the rule to the configuration to enable or disable it.
51
+
52
+ ## Example Rule (in `src/rules/`)
53
+
54
+ ## Dependencies
55
+ - Python 3.x- Any necessary libraries like `verible_verilog_syntax`
56
+
57
+ ## License
58
+ This project is **open source** and licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
59
+ ---
60
+ This **SVALint** linter is part of the **BYOL** (Build Your Own Linter) framework from **AsFigo Technologies**. It's an open-source tool, and we encourage you to contribute to its growth, whether through adding new lint rules, improving existing ones, or enhancing documentation.
61
+ Let us know how you're using **SVALint**, and feel free to contribute back to the community!
62
+
63
+ ## Credits
64
+ The rules and guidelines in **SVALint** are based on the following sources:
65
+ - **SystemVerilog Assertions Handbook*** Ben Cohen, Ajeetha Kumari Venkatesan, Lisa Piper, Srinivasan Venkataramanan: Many of the rules in this linter are inspired by the coding practices and design patterns outlined in this book, which provides a comprehensive approach to SystemVerilog Assertions, focusing on best practices for code quality and maintainability.
66
+ - **lowRISC Coding Guidelines**: This linter also draws upon the coding standards and guidelines from the lowRISC project. Their best practices for SystemVerilog coding have been a key resource for defining rules related to naming conventions, encapsulation, and other critical aspects of design quality.
67
+ - **Verible**: is an opensource SystemVerilog parser from Google and available via ChipsAlliance
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
afsvalint-2.0/setup.py ADDED
@@ -0,0 +1,18 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="afsvalint",
5
+ version="2.0",
6
+ packages=find_packages(where="src"),
7
+ package_dir={"": "src"},
8
+ install_requires=[
9
+ "anytree",
10
+ "tomli",
11
+ "python-string-utils"
12
+ ],
13
+ entry_points={
14
+ "console_scripts": [
15
+ "svalint = bin.svalint:main",
16
+ ],
17
+ },
18
+ )
File without changes
@@ -0,0 +1,9 @@
1
+ import logging
2
+ from .asfigo_linter import SVALinter
3
+
4
+ def main():
5
+ byolDemo = SVALinter(configFile="config.toml", logLevel=logging.INFO)
6
+ byolDemo.runLinter()
7
+
8
+ if __name__ == "__main__":
9
+ main()
@@ -0,0 +1,58 @@
1
+ # ----------------------------------------------------
2
+ # SPDX-FileCopyrightText: AsFigo Technologies, UK
3
+ # SPDX-FileCopyrightText: VerifWorks, India
4
+ # SPDX-License-Identifier: MIT
5
+ # ----------------------------------------------------
6
+ import logging
7
+ from bin import verible_verilog_syntax
8
+ from abc import ABC, abstractmethod
9
+
10
+ class AsFigoLintRule(ABC):
11
+ """Base class for all linting rules."""
12
+
13
+ VeribleSyntax = verible_verilog_syntax
14
+ rule_count = 0 # Class variable to track rules executed
15
+
16
+
17
+ def __init__(self, linter):
18
+ self.linter = linter # Store the linter instance
19
+ self.ruleID = 'SVALintDefaultRuleID'
20
+ '''
21
+ if not hasattr(self, "ruleID"): # Ensure ruleID exists in subclasses
22
+ raise ValueError(f"{self.__class__.__name__} must define a `ruleID` attribute!")
23
+ '''
24
+
25
+
26
+ @classmethod
27
+ def get_rule_count(cls):
28
+ return cls.rule_count # Get the count of rules applied
29
+
30
+ @abstractmethod
31
+ def apply(self, filePath: str, data: verible_verilog_syntax.SyntaxData):
32
+ """Abstract method to apply the rule."""
33
+ raise NotImplementedError
34
+
35
+ def getClassName(self, classNode):
36
+ """Extracts the class name from a class declaration."""
37
+ for header in classNode.iter_find_all({"tag": "kClassHeader"}):
38
+ for identifier in header.iter_find_all({"tag": "SymbolIdentifier"}):
39
+ return identifier.text
40
+ return "Unknown"
41
+
42
+ def getQualifiers(self, varNode):
43
+ """Extracts variable qualifiers (e.g., local, protected, rand)."""
44
+ qualifiers = set()
45
+ for qualList in varNode.iter_find_all({"tag": "kQualifierList"}):
46
+ qualifiers.update(qualList.text.split()) # Extract words
47
+ return qualifiers
48
+
49
+ def run(self, filePath: str, data: verible_verilog_syntax.SyntaxData):
50
+ """Wrapper method to automatically count and apply the rule."""
51
+ AsFigoLintRule.rule_count += 1 # Automatically increment rule count
52
+ message = (
53
+ f"Running lint ruleID: {self.ruleID} on file: {filePath}\n"
54
+ )
55
+
56
+ self.linter.logInfo(self.ruleID, message)
57
+
58
+ self.apply(filePath, data) # Call the actual rule logic
@@ -0,0 +1,121 @@
1
+ # ----------------------------------------------------
2
+ # SPDX-FileCopyrightText: AsFigo Technologies, UK
3
+ # SPDX-FileCopyrightText: VerifWorks, India
4
+ # SPDX-License-Identifier: MIT
5
+ # ----------------------------------------------------
6
+
7
+ import argparse
8
+ import tomli
9
+ import os.path
10
+ import copy
11
+ import functools
12
+ from operator import countOf
13
+ import operator as op
14
+ import logging
15
+ import json
16
+ import string_utils.validation as str_val
17
+ from .af_lint_rule import AsFigoLintRule
18
+
19
+ class BaseLintLogger:
20
+ def __init__(self, prefix, configFile="config.toml", logLevel=logging.INFO, logFile="svalint_run.log"):
21
+ self.prefix = prefix
22
+ self.logger = logging.getLogger(f"{prefix}Logger")
23
+ self.logger.setLevel(logLevel)
24
+
25
+ formatter = logging.Formatter('%(message)s')
26
+
27
+ stream_handler = logging.StreamHandler()
28
+ stream_handler.setLevel(logLevel)
29
+ stream_handler.setFormatter(formatter)
30
+
31
+ file_handler = logging.FileHandler(logFile, mode='a')
32
+ file_handler.setLevel(logLevel)
33
+ file_handler.setFormatter(formatter)
34
+
35
+ if self.logger.hasHandlers():
36
+ self.logger.handlers.clear()
37
+
38
+ self.logger.addHandler(stream_handler)
39
+ self.logger.addHandler(file_handler)
40
+
41
+ self.rulesConfig = self.loadConfig(configFile)
42
+ self.infoCount = 0
43
+ self.warningCount = 0
44
+ self.errorCount = 0
45
+ self.errorList = []
46
+ self.warningList = []
47
+
48
+ def loadConfig(self, configFile):
49
+ try:
50
+ with open(configFile, "rb") as file:
51
+ config = tomli.load(file)
52
+ return config.get("rules", {})
53
+ except FileNotFoundError:
54
+ self.logger.warning(f"{self.prefix}: Config file '{configFile}' not found. Using default settings.")
55
+ return {}
56
+
57
+ def ruleEnabled(self, ruleId):
58
+ return self.rulesConfig.get(ruleId, True)
59
+
60
+ def logInfo(self, ruleId, msg, severity="INFO"):
61
+ self.infoCount += 1
62
+
63
+ logMsg = f"{self.prefix}: INFO: {msg}"
64
+ self.logger.info(logMsg)
65
+
66
+ def logViolation(self, ruleId, msg, severity="ERROR"):
67
+ if self.ruleEnabled(ruleId):
68
+ wrapped_msg = msg
69
+ logMsg = f"{self.prefix}: Violation: [{ruleId}]:\n{msg}"
70
+
71
+ if severity == "ERROR":
72
+ self.errorCount += 1
73
+ self.errorList.append(ruleId) # Store error ID
74
+ self.logger.error(logMsg)
75
+ elif severity == "WARNING":
76
+ self.warningCount += 1
77
+ self.warningList.append(ruleId) # Store warning ID
78
+ self.logger.warning(logMsg)
79
+ else:
80
+ raise ValueError(f"Unsupported severity level: {severity}")
81
+ else:
82
+ self.logger.info(f"{self.prefix}: Rule [{ruleId}] is disabled and will not be logged.")
83
+
84
+ def logSummary(self):
85
+ self.logger.info("\n--------------------------------")
86
+ self.logger.info("AsFigo SVALint Report Summary")
87
+ self.logger.info(f"Total lint rules executed: {AsFigoLintRule.get_rule_count()}")
88
+
89
+ self.logger.info("--------------------------------")
90
+ # Report counts by severity
91
+ self.logger.info("** Report counts by severity")
92
+ self.logger.info(f"INFO : {self.infoCount}")
93
+ self.logger.info(f"WARNING : {self.warningCount}")
94
+ self.logger.info(f"ERROR : {self.errorCount}")
95
+
96
+ # Report counts by ID (show each unique rule ID and how many times it was logged)
97
+ self.logger.info("\n** Report counts by ID")
98
+ self._printRuleCounts(self.errorList, "ERROR")
99
+ self._printRuleCounts(self.warningList, "WARNING")
100
+
101
+ self.logger.info("--------------------------------\n")
102
+
103
+ def _printRuleCounts(self, ruleList, severity):
104
+ ruleDict = {}
105
+ for ruleId in ruleList:
106
+ ruleDict[ruleId] = ruleDict.get(ruleId, 0) + 1
107
+
108
+ for ruleId, count in sorted(ruleDict.items(), key=lambda x: -x[1]): # Sort by highest count
109
+ self.logger.info(f"[{ruleId}] {count}")
110
+
111
+ class AsFigoLinter(BaseLintLogger):
112
+ def __init__(self, configFile="config.toml", logLevel=logging.INFO):
113
+ super().__init__(prefix="AsFigo", configFile=configFile, logLevel=logLevel)
114
+ self.args = self.parseArguments()
115
+ self.testName = self.args.test
116
+
117
+ def parseArguments(self):
118
+ parser = argparse.ArgumentParser(description="AsFigoLinter Argument Parser")
119
+ parser.add_argument("-t", "--test", required=True, help="Input test name (file path)")
120
+ return parser.parse_args()
121
+
File without changes
@@ -0,0 +1,45 @@
1
+ # ----------------------------------------------------
2
+ # SPDX-FileCopyrightText: AsFigo Technologies, UK
3
+ # SPDX-FileCopyrightText: VerifWorks, India
4
+ # SPDX-License-Identifier: MIT
5
+ # Author: Himank Gangwal, Sep 02, 2025
6
+ # ----------------------------------------------------
7
+
8
+ from ..af_lint_rule import AsFigoLintRule
9
+ import logging
10
+ import anytree
11
+
12
+ class AssertNaming(AsFigoLintRule):
13
+ """Checks if assert follows a naming convention - start with "a_" """
14
+
15
+ def __init__(self, linter):
16
+ self.linter = linter
17
+ self.ruleID = "ASSERT_NAMING"
18
+
19
+ def apply(self, filePath: str, data: AsFigoLintRule.VeribleSyntax.SyntaxData):
20
+ for curNode in data.tree.iter_find_all({"tag": "kAssertionItem"}):
21
+ lvLabel = curNode.children[0].text
22
+ lvVerifDirType = curNode.children[1]
23
+ if (not 'kAssertPropertyStatement' in lvVerifDirType.tag):
24
+ continue
25
+
26
+ if not lvLabel:
27
+ continue
28
+
29
+ if not lvLabel.startswith("a_"):
30
+ message = (
31
+ f"Debug: Found assert name without a_ prefix. "
32
+ f"Use a_ as assert prefix. This helps users to "
33
+ f"look for specific patterns in their log files. "
34
+ f"Found an Assertion as:\n"
35
+ f"{curNode.text}\n"
36
+ )
37
+ self.linter.logViolation(self.ruleID, message, "WARNING")
38
+
39
+ def getAssertPropertyName(self, assert_node):
40
+ """Extracts the assert property name from an assert property statement."""
41
+ # Look for SymbolIdentifier nodes that represent the assert property name
42
+ for identifier in assert_node.iter_find_all({"tag": "SymbolIdentifier"}):
43
+ # The first SymbolIdentifier in an assert property is usually the name
44
+ return identifier.text
45
+ return "Unknown"
@@ -0,0 +1,30 @@
1
+ # ----------------------------------------------------
2
+ # SPDX-FileCopyrightText: AsFigo Technologies, UK
3
+ # SPDX-FileCopyrightText: VerifWorks, India
4
+ # SPDX-License-Identifier: MIT
5
+ # ----------------------------------------------------
6
+
7
+ from ..af_lint_rule import AsFigoLintRule
8
+ import logging
9
+ import anytree
10
+
11
+ class MissingLabelChk(AsFigoLintRule):
12
+ """Enhance debug-ability of assertions by using labels """
13
+
14
+ def __init__(self, linter):
15
+ self.linter = linter # Store the linter instance
16
+ self.ruleID = "ASSERT_MISSING_LABEL"
17
+
18
+ def apply(self, filePath: str, data: AsFigoLintRule.VeribleSyntax.SyntaxData):
19
+
20
+ for curNode in data.tree.iter_find_all({"tag": "kAssertionItem"}):
21
+ lvSvaCode = curNode.text
22
+ lvAsrtLabel = curNode.children[0]
23
+ if (( ":" not in lvAsrtLabel.text)):
24
+ message = (
25
+ f"Error: Missing label for an assert statement.\n"
26
+ f"{lvSvaCode}\n"
27
+ )
28
+ self.linter.logViolation(self.ruleID, message)
29
+
30
+
@@ -0,0 +1,39 @@
1
+ # ----------------------------------------------------
2
+ # SPDX-FileCopyrightText: AsFigo Technologies, UK
3
+ # SPDX-FileCopyrightText: VerifWorks, India
4
+ # SPDX-License-Identifier: MIT
5
+ # Author: Himank Gangwal, Sep 02, 2025
6
+ # ----------------------------------------------------
7
+
8
+ from ..af_lint_rule import AsFigoLintRule
9
+ import logging
10
+ import anytree
11
+
12
+ class AssumeNaming(AsFigoLintRule):
13
+ """Checks if assume follows a naming convention - start with "m_" """
14
+
15
+ def __init__(self, linter):
16
+ self.linter = linter
17
+ self.ruleID = "ASSUME_NAMING"
18
+
19
+ def apply(self, filePath: str, data: AsFigoLintRule.VeribleSyntax.SyntaxData):
20
+ for curNode in data.tree.iter_find_all({"tag": "kAssertionItem"}):
21
+ lvLabel = curNode.children[0].text
22
+ lvVerifDirType = curNode.children[1]
23
+
24
+ if (not 'kAssumePropertyStatement' in lvVerifDirType.tag):
25
+ continue
26
+
27
+ if not lvLabel:
28
+ continue
29
+
30
+ if not lvLabel.startswith("m_"):
31
+ message = (
32
+ f"Debug: Found assume name without m_ prefix. "
33
+ f"Use m_ as assume prefix. This helps users to "
34
+ f"look for specific patterns in their log files. "
35
+ f"Found an Assume as:\n"
36
+ f"{curNode.text}\n"
37
+ )
38
+ self.linter.logViolation(self.ruleID, message, "WARNING")
39
+
@@ -0,0 +1,39 @@
1
+ # ----------------------------------------------------
2
+ # SPDX-FileCopyrightText: AsFigo Technologies, UK
3
+ # SPDX-FileCopyrightText: VerifWorks, India
4
+ # SPDX-License-Identifier: MIT
5
+ # Author: Himank Gangwal, Sep 02, 2025
6
+ # ----------------------------------------------------
7
+
8
+ from ..af_lint_rule import AsFigoLintRule
9
+ import logging
10
+ import anytree
11
+
12
+ class CoverNaming(AsFigoLintRule):
13
+ """Checks if cover follows a naming convention - start with "c_" """
14
+
15
+ def __init__(self, linter):
16
+ self.linter = linter
17
+ self.ruleID = "COVER_NAMING"
18
+
19
+ def apply(self, filePath: str, data: AsFigoLintRule.VeribleSyntax.SyntaxData):
20
+ for curNode in data.tree.iter_find_all({"tag": "kAssertionItem"}):
21
+ lvLabel = curNode.children[0].text
22
+ lvVerifDirType = curNode.children[1]
23
+
24
+ if (not 'kCoverPropertyStatement' in lvVerifDirType.tag):
25
+ continue
26
+
27
+ if not lvLabel:
28
+ continue
29
+
30
+ if not lvLabel.startswith("c_"):
31
+ message = (
32
+ f"Debug: Found cover name without c_ prefix. "
33
+ f"Use c_ as cover prefix. This helps users to "
34
+ f"look for specific patterns in their log files. "
35
+ f"Found a cover as:\n"
36
+ f"{curNode.text}\n"
37
+ )
38
+ self.linter.logViolation(self.ruleID, message, "WARNING")
39
+
@@ -0,0 +1,33 @@
1
+ # ----------------------------------------------------
2
+ # SPDX-FileCopyrightText: AsFigo Technologies, UK
3
+ # SPDX-FileCopyrightText: VerifWorks, India
4
+ # SPDX-License-Identifier: MIT
5
+ # ----------------------------------------------------
6
+ from ..af_lint_rule import AsFigoLintRule
7
+ import logging
8
+ import anytree
9
+
10
+ class FuncNOLAPInCoverProp(AsFigoLintRule):
11
+ """Cover Property with non-overlapped implicaiton operator leads to false-positives """
12
+
13
+ def __init__(self, linter):
14
+ self.linter = linter # Store the linter instance
15
+ self.ruleID = "FUNC_NO_NON_OLAP_COVER"
16
+
17
+ def apply(self, filePath: str, data: AsFigoLintRule.VeribleSyntax.SyntaxData):
18
+
19
+ for curNode in data.tree.iter_find_all({"tag": "kCoverPropertyStatement"}):
20
+ lvSvaCode = curNode.text
21
+ lvNonOlapImplG = curNode.iter_find_all({"tag": "|=>"})
22
+ if (len(list(lvNonOlapImplG)) > 0):
23
+ message = (
24
+ f"FUNC: Found a non-overlapped implication operator with "
25
+ f"cover property directive. This leads to vacuous/bogus "
26
+ f"functional/assertion/temporal coverage to be collected "
27
+ f"and reported. This can be a serious hole in the verification "
28
+ f"process as it gives a false-sense of security/coverage."
29
+ f"Use ##1 instead. Code snippet: \n"
30
+ f"{lvSvaCode}\n"
31
+ )
32
+ self.linter.logViolation(self.ruleID, message)
33
+
@@ -0,0 +1,33 @@
1
+ # ----------------------------------------------------
2
+ # SPDX-FileCopyrightText: AsFigo Technologies, UK
3
+ # SPDX-FileCopyrightText: VerifWorks, India
4
+ # SPDX-License-Identifier: MIT
5
+ # ----------------------------------------------------
6
+ from ..af_lint_rule import AsFigoLintRule
7
+ import logging
8
+ import anytree
9
+
10
+ class FuncOLAPInCoverProp(AsFigoLintRule):
11
+ """Cover Property with overlapped implicaiton operator leads to false-positives """
12
+
13
+ def __init__(self, linter):
14
+ self.linter = linter # Store the linter instance
15
+ self.ruleID = "FUNC_NO_OLAP_COVER"
16
+
17
+ def apply(self, filePath: str, data: AsFigoLintRule.VeribleSyntax.SyntaxData):
18
+
19
+ for curNode in data.tree.iter_find_all({"tag": "kCoverPropertyStatement"}):
20
+ lvSvaCode = curNode.text
21
+ lvNonOlapImplG = curNode.iter_find_all({"tag": "|->"})
22
+ if (len(list(lvNonOlapImplG)) > 0):
23
+ message = (
24
+ f"FUNC: Found a overlapped implication operator with "
25
+ f"cover property directive. This leads to vacuous/bogus "
26
+ f"functional/assertion/temporal coverage to be collected "
27
+ f"and reported. This can be a serious hole in the verification "
28
+ f"process as it gives a false-sense of security/coverage."
29
+ f"Use ##0 instead. Code snippet: \n"
30
+ f"{lvSvaCode}\n"
31
+ )
32
+ self.linter.logViolation(self.ruleID, message)
33
+
@@ -0,0 +1,36 @@
1
+ # ----------------------------------------------------
2
+ # SPDX-FileCopyrightText: AsFigo Technologies, UK
3
+ # SPDX-FileCopyrightText: VerifWorks, India
4
+ # SPDX-License-Identifier: MIT
5
+ # ----------------------------------------------------
6
+ from ..af_lint_rule import AsFigoLintRule
7
+ import logging
8
+ import anytree
9
+
10
+ class FuncMissingFABLK(AsFigoLintRule):
11
+ """Action block related checks """
12
+
13
+ def __init__(self, linter):
14
+ self.linter = linter # Store the linter instance
15
+ self.ruleID = "FUNC_MISSING_FAIL_ABLK"
16
+
17
+ def apply(self, filePath: str, data: AsFigoLintRule.VeribleSyntax.SyntaxData):
18
+
19
+ for curNode in data.tree.iter_find_all({"tag": "kAssertionItem"}):
20
+ lvSvaCode = curNode.text
21
+
22
+ lvAsrtIter = curNode.iter_find_all({"tag": "kAssertPropertyStatement"})
23
+ lvAsrtProp = next(lvAsrtIter, None)
24
+ if lvAsrtProp is None:
25
+ continue
26
+
27
+ lvAsrtFailAblkNode = curNode.iter_find_all({"tag": "kElseClause"})
28
+ lvAsrtFailAblkNodeNxt = next(lvAsrtFailAblkNode, None)
29
+ if lvAsrtFailAblkNodeNxt is None:
30
+ message = (
31
+ f"FUNC: Missing fail action block in assert statement.\n"
32
+ f"Severly impacts verification completeness as errors may go undetected\n"
33
+ f"{lvSvaCode}\n"
34
+ )
35
+ self.linter.logViolation(self.ruleID, message)
36
+
@@ -0,0 +1,43 @@
1
+ # ----------------------------------------------------
2
+ # SPDX-FileCopyrightText: AsFigo Technologies, UK
3
+ # SPDX-FileCopyrightText: VerifWorks, India
4
+ # SPDX-License-Identifier: MIT
5
+ # ----------------------------------------------------
6
+
7
+ from ..af_lint_rule import AsFigoLintRule
8
+ import logging
9
+ import anytree
10
+
11
+
12
+ class NoUBRangeInConseqAsrt(AsFigoLintRule):
13
+ lvMsg = """
14
+ From book: https://payhip.com/b/7HvMk
15
+
16
+ by @hdlcohen
17
+
18
+ An assertion with an infinite range in its consequent can never FAIL, but can PASS.
19
+
20
+ $rose(req) |-> ##[0:$] ack);
21
+ Consider using a more deterministic delay
22
+
23
+ """
24
+
25
+ def __init__(self, linter):
26
+ self.linter = linter
27
+ # Store the linter instance
28
+ self.ruleID = "FUNC_AVOID_$_RANGE_IN_CONSEQ_A"
29
+
30
+ def apply(self, filePath: str, data: AsFigoLintRule.VeribleSyntax.SyntaxData):
31
+
32
+ for curNode in data.tree.iter_find_all({"tag": "kAssertionItem"}):
33
+ lvSvaCode = curNode.text
34
+ for curImplNode in curNode.iter_find_all({"tag": "|->"}):
35
+ lvImplCnseqNode = curImplNode.siblings[1]
36
+ lvRangeG = lvImplCnseqNode.iter_find_all({"tag": "kCycleDelayRange"})
37
+ for curDelRangeNode in lvRangeG:
38
+ lvCnseqUBRangeG = curDelRangeNode.iter_find_all({"tag": "$"})
39
+ lvCnseqUBRangeList = list(lvCnseqUBRangeG)
40
+ if len(lvCnseqUBRangeList) > 0:
41
+ message = f"{self.lvMsg}\n" f"{lvSvaCode}\n"
42
+
43
+ self.linter.logViolation(self.ruleID, message)
@@ -0,0 +1,34 @@
1
+ # ----------------------------------------------------
2
+ # SPDX-FileCopyrightText: AsFigo Technologies, UK
3
+ # SPDX-FileCopyrightText: VerifWorks, India
4
+ # SPDX-License-Identifier: MIT
5
+ # ----------------------------------------------------
6
+
7
+ from ..af_lint_rule import AsFigoLintRule
8
+ import logging
9
+ import anytree
10
+
11
+
12
+ class MissingEndLblProp(AsFigoLintRule):
13
+ """Checks for missing end-labels in property """
14
+
15
+ def __init__(self, linter):
16
+ self.linter = linter
17
+ # Store the linter instance
18
+ self.ruleID = "DBG_MISS_END_LBL_PROP"
19
+
20
+ def apply(
21
+ self, filePath: str, data: AsFigoLintRule.VeribleSyntax.SyntaxData
22
+ ):
23
+ for curNode in data.tree.iter_find_all(
24
+ {"tag": "kPropertyDeclaration"}):
25
+ lvSvaCode = curNode.text
26
+ lvLastElem = curNode.descendants[-1]
27
+ if (not lvLastElem.text):
28
+ message = (
29
+ f"Debug: Found a property without endlabel. Use of endlabels "
30
+ f"greatly enhances debug and increases productivity\n"
31
+ f"{lvSvaCode}\n"
32
+ )
33
+
34
+ self.linter.logViolation(self.ruleID, message)