File: t_dist_warn_coverage.py

package info (click to toggle)
verilator 5.038-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 162,552 kB
  • sloc: cpp: 139,204; python: 20,931; ansic: 10,222; yacc: 6,000; lex: 1,925; makefile: 1,260; sh: 494; perl: 282; fortran: 22
file content (242 lines) | stat: -rwxr-xr-x 10,051 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0

import vltest_bootstrap

test.scenarios('dist')

root = ".."

Messages = {}
Outputs = {}
Suppressed = {}

for s in [
        ' exited with ',  # Is hit; driver.py filters out
        ' loading non-variable',  # Instead 'storing to parameter' or syntax error
        '--pipe-filter: Can\'t pipe: ',  # Can't test
        '--pipe-filter: fork failed: ',  # Can't test
        'Assigned pin is neither input nor output',  # Instead earlier error
        'Define missing argument \'',  # Instead get Define passed too many arguments
        'Define or directive not defined: `',  # Instead V3ParseImp will warn
        'EOF in unterminated string',  # Instead get normal unterminated
        'Enum ranges must be integral, per spec',  # Hard to hit
        'Expecting define formal arguments. Found: ',  # Instead define syntax error
        'Import package not found: ',  # Errors earlier, until future parser released
        'Member selection of non-struct/union object \'',  # Instead dotted expression error or V3Link other
        'Return with return value isn\'t underneath a function',  # Hard to hit, get other bad return messages
        'Syntax error parsing real: \'',  # Instead can't lex the number
        'Syntax error: Range \':\', \'+:\' etc are not allowed in the instance ',  # Instead get syntax error
        'Unsupported: Ranges ignored in port-lists',  # Hard to hit
        'dynamic new() not expected in this context (expected under an assign)',  # Instead get syntax error
        # Not yet analyzed
        '--pipe-filter protocol error, unexpected: ',
        '--pipe-filter returned bad status',
        'Argument needed for string.',
        'Array initialization has too few elements, need element ',
        'Assignment pattern with no members',
        'Can\'t find varpin scope of ',
        'Can\'t read annotation file: ',
        'Can\'t resolve module reference: \'',
        'Can\'t write file: ',
        'Expected data type, not a ',
        'Extern declaration\'s scope is not a defined class',
        'File not found: ',
        'Format to $display-like function must have constant format string',
        'Forward typedef used as class/package does not resolve to class/package: ',
        'Illegal +: or -: select; type already selected, or bad dimension: ',
        'Illegal bit or array select; type already selected, or bad dimension: ',
        'Illegal range select; type already selected, or bad dimension: ',
        'Interface port ',
        'Interface port declaration ',
        'Modport item is not a function/task: ',
        'Modport item is not a variable: ',
        'Modport item not found: ',
        'Modport not referenced as <interface>.',
        'Modport not referenced from underneath an interface: ',
        'Non-interface used as an interface: ',
        'Parameter type pin value isn\'t a type: Param ',
        'Parameter type variable isn\'t a type: Param ',
        'Pattern replication value of 0 is not legal.',
        'Reference to \'',
        'Signals inside functions/tasks cannot be marked forceable',
        'Slice size cannot be zero.',
        'Slices of arrays in assignments have different unpacked dimensions, ',
        'String of ',
        'Symbol matching ',
        'Unexpected connection to arrayed port',
        'Unsized numbers/parameters not allowed in streams.',
        'Unsupported RHS tristate construct: ',
        'Unsupported or syntax error: Unsized range in instance or other declaration',
        'Unsupported pullup/down (weak driver) construct.',
        'Unsupported tristate construct (not in propagation graph): ',
        'Unsupported tristate port expression: ',
        'Unsupported: $bits for queue',
        'Unsupported: &&& expression',
        'Unsupported: +%- range',
        'Unsupported: +/- range',
        'Unsupported: 4-state numbers in this context',
        'Unsupported: Bind with instance list',
        'Unsupported: Concatenation to form ',
        'Unsupported: Modport clocking',
        'Unsupported: Modport dotted port name',
        'Unsupported: Modport export with prototype',
        'Unsupported: Modport import with prototype',
        'Unsupported: Only one PSL clock allowed per assertion',
        'Unsupported: Per-bit array instantiations ',
        'Unsupported: Public functions with >64 bit outputs; ',
        'Unsupported: Replication to form ',
        'Unsupported: Shifting of by over 32-bit number isn\'t supported.',
        'Unsupported: Signal strengths are unsupported ',
        'Unsupported: Size-changing cast on non-basic data type',
        'Unsupported: Slice of non-constant bounds',
        'Unsupported: Unclocked assertion',
        'Unsupported: Verilog 1995 deassign',
        'Unsupported: Verilog 1995 gate primitive: ',
        'Unsupported: [] dimensions',
        'Unsupported: \'default :/\' constraint',
        'Unsupported: \'{} .* patterns',
        'Unsupported: assertion items in clocking blocks',
        'Unsupported: don\'t know how to deal with ',
        'Unsupported: eventually[] (in property expression)',
        'Unsupported: extern forkjoin',
        'Unsupported: extern task',
        'Unsupported: modport export',
        'Unsupported: no_inline for tasks',
        'Unsupported: property port \'local\'',
        'Unsupported: repeat event control',
        'Unsupported: static cast to ',
        'Unsupported: super',
        'Unsupported: this.super',
        'Unsupported: with[] stream expression',
]:
    Suppressed[s] = True


def read_messages():
    for filename in test.glob_some(root + "/src/*"):
        if not os.path.isfile(filename):
            continue
        with open(filename, 'r', encoding="utf8") as fh:
            lineno = 0
            read_next = None

            for origline in fh:
                line = origline
                lineno += 1
                if re.match(r'^\s*//', line):
                    continue
                if re.match(r'^\s*/\*', line):
                    continue
                if re.search(r'\b(v3error|v3warn|v3fatal|BBUNSUP)\b\($', line):
                    if 'LCOV_EXCL_LINE' not in line:
                        read_next = True
                    continue
                m = re.search(r'.*\b(v3error|v3warn|v3fatal|BBUNSUP)\b(.*)', line)
                if m:
                    line = m.group(2)
                    if 'LCOV_EXCL_LINE' not in line:
                        read_next = True
                if read_next:
                    read_next = False
                    if 'LCOV_EXCL_LINE' in line:
                        continue
                    if "\\" in line:  # \" messes up next part
                        continue
                    m = re.search(r'"([^"]*)"', line)
                    if m:
                        msg = m.group(1)
                        fileline = filename + ":" + str(lineno)
                        # print("FFFF " + fileline + ": " + msg + "   LL " + line)
                        Messages[msg] = {}
                        Messages[msg]['fileline'] = fileline
                        Messages[msg]['line'] = origline

    print("Number of messages = " + str(len(Messages)))


def read_outputs():
    for filename in (test.glob_some(root + "/test_regress/t/*.py") +
                     test.glob_some(root + "/test_regress/t/*.out") +
                     test.glob_some(root + "/docs/gen/*.rst")):
        if "t_dist_warn_coverage" in filename:  # Avoid our own suppressions
            continue
        with open(filename, 'r', encoding="latin-1") as fh:
            for line in fh:
                if re.match(r'^\$date', line):  # Assume it is a VCD file
                    break
                line = line.lstrip().rstrip()
                Outputs[line] = True

    print("Number of outputs = " + str(len(Outputs)))


def check():
    read_messages()
    read_outputs()

    print("Number of suppressions = " + str(len(Suppressed)))
    print("Coverage = %3.1f%%" % (100 - (100 * len(Suppressed) / len(Messages))))
    print()

    print("Checking for v3error/v3warn messages in sources without")
    print("coverage in test_regress/t/*.out:")
    print("(Developers: If a message is impossible to test, consider using")
    print("UASSERT or v3fatalSrc instead of v3error)")
    print()

    used_suppressed = {}

    for msg in sorted(Messages.keys()):
        fileline = Messages[msg]['fileline']
        next_msg = False
        for output in Outputs:
            if msg in output:
                # print(fileline+": M '" + msg + "' HIT '" + output)
                next_msg = True
                break

        if next_msg:
            continue

        # Some exceptions
        if re.match(r'internal:', msg, re.IGNORECASE):
            continue

        line = Messages[msg]['line']
        line = line.lstrip().rstrip()

        if msg in Suppressed:
            used_suppressed[msg] = True
            if test.verbose:
                print(fileline + ": Suppressed check for message in source: '" + msg + "'")
        else:
            test.error_keep_going(fileline +
                                  ": Missing test_regress/t/*.out test for message in source: '" +
                                  msg + "'")
            if test.verbose:
                print("  Line is: " + line)

    print()
    for msg in sorted(Suppressed.keys()):
        if msg not in used_suppressed:
            print("Suppression not used: '" + msg + "'")
    print()


if not os.path.exists(root + "/.git"):
    test.skip("Not in a git repository")

check()

test.passes()

# Local Variables:
# compile-command:"./t_dist_warn_coverage.py"
# End: