verilator/test_regress/t/t_dist_warn_coverage.py

343 lines
15 KiB
Python
Raw Normal View History

2024-09-08 19:00:03 +02:00
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# 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-FileCopyrightText: 2024 Wilson Snyder
2024-09-08 19:00:03 +02:00
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('dist')
Messages = {}
Outputs = {}
Suppressed = {}
Used_Suppressed = {}
2024-09-08 19:00:03 +02:00
for s in [
# Cannot hit, and comment as to why
# Instead of adding here, consider adding a LCOV_EXCL_LINE/START/STOP to the sources on the message
'exited with', # Is hit; driver.py filters out
'loading non-variable', # Instead 'storing to parameter' or syntax error
2025-05-17 04:32:25 +02:00
'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
'Expecting define formal arguments. Found:', # Instead define syntax error
'Syntax error: Range \':\', \'+:\' etc are not allowed in the instance', # Instead get syntax error
2024-09-08 19:00:03 +02:00
'dynamic new() not expected in this context (expected under an assign)', # Instead get syntax error
# Tested in t_vpi_force.cpp, but not picked up by pattern matching in this script yet
'%s: Trailing garbage \'%s\' in \'%s\' as value %s for \'%s\'',
'%s: Non hex character \'%c\' in \'%s\' as value %s for \'%s\'',
'%s: Non octal character \'%c\' in \'%s\' as value %s for \'%s\'',
2024-09-08 19:00:03 +02:00
# Not yet analyzed
'$VERILATOR_ROOT needs to be in environment',
'--pipe-filter protocol error, unexpected:',
2025-03-24 00:51:54 +01:00
'--pipe-filter returned bad status',
'--pipe-filter: stdin/stdout closed before pipe opened',
'--pipe-filter: write to closed file',
'Assigning >32 bit to unranged parameter (defaults to 32 bits)',
2024-09-08 19:00:03 +02:00
'Assignment pattern with no members',
'%%Warning: DPI C Function called by Verilog DPI import with missing',
'%%Warning: DPI svOpenArrayHandle function called on',
'%%Warning: DPI svOpenArrayHandle function index 1',
'%%Warning: DPI svOpenArrayHandle function index 2',
'%%Warning: DPI svOpenArrayHandle function index 3',
'%s: Ignoring vpi_put_value to vpiConstant \'%s\'',
'%s: Ignoring vpi_put_value to vpiParameter \'%s\'',
2026-02-04 01:57:23 +01:00
'%s: Index %u for object \'%s\' is out of bounds [%u,%u]',
'%s: Parsing failed for \'%s\' as value %s for \'%s\'',
2026-02-04 01:57:23 +01:00
'%s: Requested elements (%u) exceed array size (%u)',
'%s: Requested elements to set (%u) exceed array size (%u)',
'%s: Unsupported callback type %s',
'%s: Unsupported flags (%x)',
'%s: Unsupported format (%s) as requested for \'%s\'',
'%s: Unsupported format (%s) for \'%s\'',
'%s: Unsupported p_vpi_value as requested for \'%s\' with vpiInertialDelay',
'%s: Unsupported property %s, nothing will be returned',
'%s: Unsupported type %s, ignoring',
'%s: Unsupported type %s, nothing will be returned',
'%s: Unsupported type (%d)',
'%s: Unsupported type (%p, %s)',
'%s: Unsupported vltype (%d)',
'%s: Unsupported vpiHandle (%p)',
'%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned',
'%s: Unsupported vpiUserAllocFlag (%x)',
2026-02-04 01:57:23 +01:00
'%s: VPI callback data pointer is null',
'Ignoring vpi_get_time with nullptr value pointer',
'Ignoring vpi_get_value_array with null index pointer',
'Ignoring vpi_get_value_array with null value pointer',
'Ignoring vpi_put_value with nullptr value pointer',
'Ignoring vpi_put_value_array to signal marked read-only,',
'Ignoring vpi_put_value_array with null index pointer',
'Ignoring vpi_put_value_array with null value pointer',
'vpi_put_value was used on signal marked read-only,',
'Can\'t find varpin scope of',
'Can\'t read annotation file:',
2024-09-08 19:00:03 +02:00
'Can\'t resolve module reference: \'',
'Can\'t write file:',
'Circular logic when ordering code (non-cutable edge loop)',
'Expected data type, not a',
2024-09-08 19:00:03 +02:00
'Extern declaration\'s scope is not a defined class',
'File not found:',
2024-09-08 19:00:03 +02:00
'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:',
'Instance pin connected by name with empty reference:',
'Interface port declaration',
'Invalid reference: Process might outlive variable',
'Modport item is not a function/task:',
'Modport item is not a variable:',
2024-09-08 19:00:03 +02:00
'Modport not referenced as <interface>.',
'Modport not referenced from underneath an interface:',
'Need $SYSTEMC_INCLUDE in environment or when Verilator configured,',
'Non-interface used as an interface:',
'Parameter type pin value isn\'t a type: Param',
'Parameter type variable isn\'t a type: Param',
2024-09-08 19:00:03 +02:00
'Pattern replication value of 0 is not legal.',
'Signals inside functions/tasks cannot be marked forceable',
'Slice size cannot be zero.',
'Slices of arrays in assignments have different unpacked dimensions,',
'Symbol matching',
'Thread scheduler is unable to provide requested',
2024-09-08 19:00:03 +02:00
'Unexpected connection to arrayed port',
'Unsized numbers/parameters not allowed in streams.',
'Unsupported LHS node type in array assignment',
'Unsupported RHS tristate construct:',
2024-09-08 19:00:03 +02:00
'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/unknown built-in queue method',
2024-09-08 19:00:03 +02:00
'Unsupported: $bits for queue',
'Unsupported: 4-state numbers in this context',
'Unsupported: Assignments with signal strength with LHS of type:',
2024-09-22 15:10:03 +02:00
'Unsupported: Bind with instance list',
'Unsupported: Cast to',
'Unsupported: Concatenation to form',
'Unsupported: Creating tristate signal not underneath a module:',
'Unsupported: Default value on module inout/ref/constref:',
'Unsupported: Modport empty expression',
'Unsupported: Non-constant default value in missing argument',
'Unsupported: Non-constant index when passing interface to module',
2024-09-08 19:00:03 +02:00
'Unsupported: Only one PSL clock allowed per assertion',
'Unsupported: Per-bit array instantiations',
'Unsupported: Public functions with >64 bit outputs;',
'Unsupported: Public functions with return > 64 bits wide.',
'Unsupported: Release statement argument is too complex array select',
'Unsupported: Replication to form',
'Unsupported: Shifting of by over 32-bit number isn\'t supported.',
2024-09-08 19:00:03 +02:00
'Unsupported: Size-changing cast on non-basic data type',
'Unsupported: Slice of non-constant bounds',
'Unsupported: Stream operation on a variable of a type',
2024-09-08 19:00:03 +02:00
'Unsupported: Unclocked assertion',
'Unsupported: Using --protect-ids with public function',
'Unsupported: Verilog 1995 gate primitive:',
2024-09-22 15:10:03 +02:00
'Unsupported: [] dimensions',
2025-03-24 00:51:54 +01:00
'Unsupported: \'default :/\' constraint',
2024-09-22 15:10:03 +02:00
'Unsupported: assertion items in clocking blocks',
'Unsupported: don\'t know how to deal with',
'Unsupported: extern constraint definition with class-in-class',
2024-09-22 15:10:03 +02:00
'Unsupported: extern forkjoin',
'Unsupported: extern task',
2025-03-24 00:51:54 +01:00
'Unsupported: no_inline for tasks',
'Unsupported: non-const assert directive type expression',
2024-09-22 15:10:03 +02:00
'Unsupported: property port \'local\'',
'Unsupported: randsequence production function variable',
2024-09-22 15:10:03 +02:00
'Unsupported: repeat event control',
'Unsupported: static cast to',
2025-03-24 00:51:54 +01:00
'Unsupported: super',
2024-09-22 15:10:03 +02:00
'Unsupported: with[] stream expression',
'expected non-complex non-double',
'is not an unpacked array, but is in an unpacked array context',
'loading other than unpacked-array variable',
'loading other than unpacked/associative-array variable',
# These are safety limits requiring >1000 bins or >10000 members to trigger
2024-09-08 19:00:03 +02:00
]:
Suppressed[s] = True
def read_messages():
for filename in (test.glob_some(test.root + "/src/*") +
test.glob_some(test.root + "/include/*")):
2024-09-08 19:00:03 +02:00
if not os.path.isfile(filename):
continue
if '#' in filename:
continue
2024-09-08 19:00:03 +02:00
with open(filename, 'r', encoding="utf8") as fh:
lineno = 0
statement = ""
statement_lineno = 0
excl = False
excl_next = False
2024-09-08 19:00:03 +02:00
for origline in fh:
line = origline
lineno += 1
excl = excl_next
if 'LCOV_EXCL_START' in line:
excl = True
excl_next = True
if 'LCOV_EXCL_STOP' in line:
excl_next = False # Reenables coverage on next line, not this one
if 'LCOV_EXCL_LINE' in line:
excl = True
if excl:
statement = ""
continue
if re.match(r'^\s*//', line):
continue
if re.match(r'^\s*/\*', line):
continue
# print(('C ' if (statement != "") else 'L') + line)
line = re.sub(r'\\n', '', line)
line = re.sub(r'\s+//.*', '', line)
line = line.rstrip()
m = re.search(
r'\b((v3error|v3warn|v3fatal|BBUNSUP|VL_FATAL|VL_FATAL_MT|VL_SVDPI_WARN_|VL_WARN|VL_WARN_MT|VL_VPI_ERROR_|VL_VPI_WARNING_)\b.*)',
line)
if m:
statement = m.group(1)
statement_lineno = lineno
if statement == "":
2024-09-08 19:00:03 +02:00
continue
statement += line
if ');' not in statement:
continue # Keep reading lines until get end of statement
if '\\"' in statement:
continue # Parser messes these up
# print("SSS " + statement)
m = re.search(r'"([^"]*)"', statement)
2024-09-08 19:00:03 +02:00
if m:
msg = m.group(1)
msg = re.sub(r'\s+$', '', msg)
msg = re.sub(r'^\s+', '', msg)
fileline = filename + ":" + str(statement_lineno)
# print("FFFF " + fileline + ": " + msg + " LL " + statement)
Messages[msg] = {}
Messages[msg]['fileline'] = fileline
Messages[msg]['line'] = statement
statement = ""
2024-09-08 19:00:03 +02:00
print("Number of messages = " + str(len(Messages)))
def read_outputs():
for filename in (test.glob_some(test.root + "/test_regress/t/*.py") +
test.glob_some(test.root + "/test_regress/t/*.out") +
test.glob_some(test.root + "/docs/gen/*.rst")):
2024-09-08 19:00:03 +02:00
if "t_dist_warn_coverage" in filename: # Avoid our own suppressions
continue
is_python = re.search(r'\.py$', filename)
2024-09-08 19:00:03 +02:00
with open(filename, 'r', encoding="latin-1") as fh:
for line in fh:
# File suppressions based on magic content
if re.match(r'^\$version', line): # Assume it is a VCD file
2024-09-08 19:00:03 +02:00
break
if re.match(r'^# SystemC::Coverage', line): # Coverage data
break
if re.match(r'^//.*verilator_coverage annotation', line): # Coverage data
break
if re.match(r'^{"type":"NETLIST"', line): # JSON
break
if re.match(r'^// *Generated by verilated_saif', line): # SAIF
break
# Line suppressions
if is_python and re.match(r'^#', line): # Assume it is a VCD file
continue
2024-09-08 19:00:03 +02:00
line = line.lstrip().rstrip()
Outputs[line] = True
print("Number of outputs = " + str(len(Outputs)))
def check_msg(msg):
fileline = Messages[msg]['fileline']
# Fast first - exact match
for output in Outputs:
if msg in output:
# print(fileline+": M '" + msg + "' HIT '" + output)
return
# Try regexp, with %s in message changed to .*?
if re.search(r'%[a-z]', msg):
msg_re = re.escape(msg)
msg_re = re.sub(r'^%[a-z]', r'', msg_re)
msg_re = re.sub(r'%[a-z]$', r'', msg_re)
msg_re = re.sub(r'%[a-z]', r'.*?', msg_re)
# print("msg_re='%s'" % (msg_re))
m = re.compile(msg_re)
for output in Outputs:
if re.search(m, output):
# print(fileline+": M '" + msg + "' HIT '" + output)
return
# Some exceptions
if re.match(r'internal:', msg, re.IGNORECASE):
return
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)
2024-09-08 19:00:03 +02:00
def check():
read_messages()
read_outputs()
print("Number of suppressions = " + str(len(Suppressed)))
2025-05-17 22:28:09 +02:00
print("Coverage = %3.1f%%" % (100 - (100 * len(Suppressed) / len(Messages))))
2024-09-08 19:00:03 +02:00
print()
print("Checking for v3error/v3warn messages in sources without")
print("coverage in test_regress/t/*.out:")
2025-03-24 00:51:54 +01:00
print("(Developers: If a message is impossible to test, consider using")
print("UASSERT or v3fatalSrc instead of v3error)")
2024-09-08 19:00:03 +02:00
print()
for msg in sorted(Messages.keys()):
check_msg(msg)
2024-09-08 19:00:03 +02:00
print()
for msg in sorted(Suppressed.keys()):
if msg not in Used_Suppressed:
2024-09-08 19:00:03 +02:00
print("Suppression not used: '" + msg + "'")
print()
if not os.path.exists(test.root + "/.git"):
2024-09-08 19:00:03 +02:00
test.skip("Not in a git repository")
check()
test.passes()
# Local Variables:
# compile-command:"./t_dist_warn_coverage.py"
# End: