2024-09-08 19:00:03 +02:00
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
2026-01-27 02:24:34 +01:00
# 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 = { }
2026-02-04 01:51:23 +01:00
Used_Suppressed = { }
2024-09-08 19:00:03 +02:00
for s in [
2025-10-12 02:58:03 +02:00
# 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
2025-12-21 22:15:33 +01:00
' 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
2025-12-21 22:15:33 +01:00
' 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
2026-02-04 01:03:43 +01:00
# Tested in t_vpi_force.cpp, but not picked up by pattern matching in this script yet
' %s : Signal \' %s \' is marked forceable, but force ' ,
' %s : Signal \' %s \' with vpiHandle \' % p \' is marked forceable, but force ' ,
' %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 ' ,
2026-02-04 01:57:23 +01:00
' %s : VPI force or release requested for \' %s \' , but vpiHandle \' % p \' of enable ' , # Emitted as part of a different error message because this is thrown by a nested function
' %s : VPI force or release requested for \' %s \' , but vpiHandle \' % p \' of value ' , # Emitted as part of a different error message because this is thrown by a nested function
2026-02-04 01:03:43 +01:00
2024-09-08 19:00:03 +02:00
# Not yet analyzed
2025-12-21 22:15:33 +01:00
' $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 ' ,
2025-12-21 22:15:33 +01:00
' --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 ' ,
2026-01-10 10:08:08 +01:00
' %% 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 ] ' ,
2026-01-10 10:08:08 +01:00
' %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 ) ' ,
2026-01-10 10:08:08 +01:00
' %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 ' ,
2026-01-10 10:08:08 +01:00
' 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_get_value with more than VL_VALUE_STRING_MAX_WORDS; increase and ' ,
' vpi_put_value was used on signal marked read-only, ' ,
2025-12-21 22:15:33 +01:00
' Can \' t find varpin scope of ' ,
' Can \' t read annotation file: ' ,
2024-09-08 19:00:03 +02:00
' Can \' t resolve module reference: \' ' ,
2025-12-21 22:15:33 +01:00
' 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 ' ,
2025-12-21 22:15:33 +01:00
' File not found: ' ,
2024-09-08 19:00:03 +02:00
' Format to $display-like function must have constant format string ' ,
2025-12-21 22:15:33 +01:00
' 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>. ' ,
2025-12-21 22:15:33 +01:00
' 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. ' ,
2025-12-21 22:15:33 +01:00
' Slices of arrays in assignments have different unpacked dimensions, ' ,
' String of ' ,
' Symbol matching ' ,
2026-02-04 01:51:23 +01:00
' 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. ' ,
2025-12-21 22:15:33 +01:00
' Unsupported (or syntax error): Foreach on this array \' s construct ' ,
' 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. ' ,
2025-12-21 22:15:33 +01:00
' 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 ' ,
2025-12-21 22:15:33 +01:00
' Unsupported: Assignments with signal strength with LHS of type: ' ,
2024-09-22 15:10:03 +02:00
' Unsupported: Bind with instance list ' ,
2025-12-21 22:15:33 +01:00
' Unsupported: Cast to ' ,
' Unsupported: Concatenation to form ' ,
' Unsupported: Creating tristate signal not underneath a module: ' ,
' Unsupported: Default value on module inout/ref/constref: ' ,
2025-12-21 14:58:21 +01:00
' Unsupported: Modport empty expression ' ,
2024-09-22 15:10:03 +02:00
' Unsupported: Modport export with prototype ' ,
' Unsupported: Modport import with prototype ' ,
2025-12-21 22:15:33 +01:00
' 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 ' ,
2025-12-21 22:15:33 +01:00
' 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 ' ,
2025-12-21 22:15:33 +01:00
' Unsupported: Stream operation on a variable of a type ' ,
2024-09-08 19:00:03 +02:00
' Unsupported: Unclocked assertion ' ,
2025-12-21 22:15:33 +01:00
' 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 ' ,
2025-12-21 22:15:33 +01:00
' 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: modport export ' ,
' Unsupported: no_inline for tasks ' ,
2025-12-21 22:15:33 +01:00
' Unsupported: non-const assert directive type expression ' ,
2024-09-22 15:10:03 +02:00
' Unsupported: property port \' local \' ' ,
2025-12-21 22:15:33 +01:00
' Unsupported: randsequence production function variable ' ,
2024-09-22 15:10:03 +02:00
' Unsupported: repeat event control ' ,
2025-12-21 22:15:33 +01:00
' 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 ' ,
2025-12-21 22:15:33 +01:00
' 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 ' ,
2024-09-08 19:00:03 +02:00
] :
Suppressed [ s ] = True
def read_messages ( ) :
2026-01-06 04:55:53 +01:00
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
2025-09-28 02:50:32 +02:00
if ' # ' in filename :
continue
2024-09-08 19:00:03 +02:00
with open ( filename , ' r ' , encoding = " utf8 " ) as fh :
lineno = 0
2025-12-21 22:15:33 +01:00
statement = " "
statement_lineno = 0
2025-10-12 02:58:03 +02:00
excl = False
excl_next = False
2024-09-08 19:00:03 +02:00
for origline in fh :
line = origline
lineno + = 1
2025-12-21 22:15:33 +01:00
2026-02-04 01:03:43 +01:00
excl = excl_next
2025-10-12 02:58:03 +02:00
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
2025-12-21 22:15:33 +01:00
if ' LCOV_EXCL_LINE ' in line :
excl = True
if excl :
statement = " "
continue
2026-02-04 01:03:43 +01:00
if re . match ( r ' ^ \ s*// ' , line ) :
continue
if re . match ( r ' ^ \ s*/ \ * ' , line ) :
continue
# print(('C ' if (statement != "") else 'L') + line)
2025-12-21 22:15:33 +01:00
line = re . sub ( r ' \\ n ' , ' ' , line )
line = re . sub ( r ' \ s+//.* ' , ' ' , line )
line = line . rstrip ( )
2026-01-10 10:08:08 +01:00
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 )
2025-12-21 22:15:33 +01:00
if m :
statement = m . group ( 1 )
statement_lineno = lineno
if statement == " " :
2024-09-08 19:00:03 +02:00
continue
2025-12-21 22:15:33 +01:00
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 :
2025-12-21 22:15:33 +01:00
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 ( ) :
2025-09-14 14:43:52 +02:00
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
2026-02-04 01:51:23 +01:00
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 :
2026-02-04 01:51:23 +01:00
# 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
2026-02-04 01:51:23 +01:00
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 ) ) )
2026-02-04 01:51:23 +01:00
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 ( ) ) :
2026-02-04 01:51:23 +01:00
check_msg ( msg )
2024-09-08 19:00:03 +02:00
print ( )
for msg in sorted ( Suppressed . keys ( ) ) :
2026-02-04 01:51:23 +01:00
if msg not in Used_Suppressed :
2024-09-08 19:00:03 +02:00
print ( " Suppression not used: ' " + msg + " ' " )
print ( )
2025-09-14 14:43:52 +02:00
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: