forked from steveicarus/ivtest
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvpi_reg.pl
executable file
·274 lines (242 loc) · 8.71 KB
/
vpi_reg.pl
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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
#!/usr/bin/perl
#
# Script to handle regression for VPI routines
#
$| = 1; # This turns off buffered I/O
# We support a --suffix= and --with-valgrind flags.
use Getopt::Long;
$sfx = ""; # Default suffix.
$with_valg = 0; # Default valgrind usage (keep this off).
if (!GetOptions("suffix=s" => \$sfx,
"with-valgrind" => \$with_valg,
"help" => \&usage)) {
die "Error: Invalid argument(s).\n";
}
sub usage {
warn "$0 usage:\n\n" .
" --suffix=<suffix> # The Icarus executables suffix, " .
"default \"\".\n" .
" --with-valgrind # Run the test suite with valgrind, " .
"default \"off\".\n" .
" <regression file> # The regression file, " .
"default \"./vpi_regress.list\".\n\n";
exit;
}
$regress_fn = "./vpi_regress.list"; # Default regression list.
# Is there a command line argument (alternate regression list)?
if ($#ARGV != -1) {
$regress_fn = $ARGV[0];
-e $regress_fn or
die "Error: command line regression file $regress_fn doesn't exist.\n";
-f $regress_fn or
die "Error: command line regression file $regress_fn is not a file.\n";
-r $regress_fn or
die "Error: command line regression file $regress_fn is not ".
"readable.\n";
if ($#ARGV > 0) {
warn "Warning: only using first file argument to script.\n";
}
}
#
# Main script
#
($ver) = `iverilog$sfx -V` =~ /^Icarus Verilog version (\d+\.\d+)/;
my $msg = $with_valg ? " (with valgrind)" : "";
print ("Running VPI tests for Icarus Verilog version: $ver$msg.\n");
print "-" x 76 . "\n";
&read_regression_list;
&execute_regression;
#
# parses the regression list file
#
# (from left-to-right in regression file):
#
# test_name type c/c++_code gold_file opt_c/c++_defines
#
sub read_regression_list {
my ($line, @fields, $tname, $tver, %nameidx);
open (REGRESS_LIST, "<$regress_fn") or
die "Error: unable to open $regress_fn for reading.\n";
while ($line = <REGRESS_LIST>) {
chomp $line;
next if ($line =~ /^\s*#/); # Skip comments.
next if ($line =~ /^\s*$/); # Skip blank lines.
$line =~ s/#.*$//; # Strip in line comments.
$line =~ s/\s+$//; # Strip trailing white space.
# You must specify at least the first four fields, cargs is optional
# and gets the rest of the fields if present.
@fields = split(' ', $line, 5);
if (@fields < 3) {
die "Error: $fields[0] must have at least 4 fields.\n";
}
$tname = $fields[0];
# Check for a version specific line.
if ($tname =~ /:/) {
($tver, $tname) = split(':', $tname);
next if ($tver ne "v$ver"); # Skip if this is not our version.
# Get the test type and any iverilog arguments.
if ($fields[1] =~ ',') {
($testtype, $args{$tname}) = split(',', $fields[1], 2);
# For now we just support args to iverilog.
if ($args{$tname} =~ ',') {
$args{$tname} = join(' ', split(',', $args{$tname}));
}
} else {
$testtype = $fields[1];
$args{$tname} = "";
}
# This version of the program does not implement something
# required to run this test.
if ($testtype eq "NI") {
$args{$tname} = "";
$ccode{$tname} = "";
$goldfile{$tname} = "";
$cargs{$tname} = "";
} else {
$ccode{$tname} = $fields[2];
$goldfile{$tname} = $fields[3];
$cargs{$tname} = $fields[4];
}
# print "Read $tver:$tname=$ccode{$tname}, $goldfile{$tname}, ".
# "$args{$tname}, $cargs{$tname}\n";
} else {
next if (exists($ccode{$tname})); # Skip if already defined.
# Get the test type and any iverilog arguments.
if ($fields[1] =~ ',') {
($testtype, $args{$tname}) = split(',', $fields[1], 2);
# For now we just support args to iverilog.
if ($args{$tname} =~ ',') {
$args{$tname} = join(' ', split(',', $args{$tname}));
}
} else {
$args{$tname} = "";
}
$ccode{$tname} = $fields[2];
$goldfile{$tname} = $fields[3];
$cargs{$tname} = $fields[4];
# print "Read $tname=$ccode{$tname}, $goldfile{$tname}, ".
# "$args{$tname}, $cargs{$tname}\n";
}
# If there wasn't a cargs field make it a null string.
$cargs{$tname} = "" if (!defined($cargs{$tname}));
# If the name exists this is a replacement so skip the original one.
if (exists($nameidx{$tname})) {
splice(@testlist, $nameidx{$tname}, 1, "");
}
push (@testlist,$tname);
$nameidx{$tname} = @testlist - 1;
}
close (REGRESS_LIST);
}
#
# execute_regression sequentially compiles and executes each test in
# the regression. It then checks that the output matched the gold file.
#
sub execute_regression {
my ($tname, $total, $passed, $failed, $not_impl, $len, $cmd);
$total = 0;
$passed = 0;
$failed = 0;
$not_impl = 0;
$len = 0;
foreach $tname (@testlist) {
$len = length($tname) if (length($tname) > $len);
}
# Make sure we have a log directory.
if (! -d 'vpi_log') {
mkdir 'vpi_log' or die "Error: unable to create vpi_log directory.\n";
}
foreach $tname (@testlist) {
next if ($tname eq ""); # Skip test that have been replaced.
$total++;
printf "%${len}s: ", $tname;
if (-e "vpi_log/$tname.log") {
unlink "vpi_log/$tname.log" or
die "Error: unable to remove old log file ".
"vpi_log/$tname.log.\n";
}
if ($ccode{$tname} eq "") {
print "Not Implemented.\n";
$not_impl++;
next;
}
$cmd = "iverilog-vpi$sfx --name=$tname $cargs{$tname} " .
"vpi/$ccode{$tname} > vpi_log/$tname.log 2>&1";
if (system("$cmd")) {
print "==> Failed - running iverilog-vpi.\n";
$failed++;
next;
}
$cmd = $with_valg ? "valgrind --trace-children=yes " : "";
$cmd .= "iverilog$sfx $args{$tname} -o vsim vpi/$tname.v >> " .
"vpi_log/$tname.log 2>&1";
if (system("$cmd")) {
print "==> Failed - running iverilog.\n";
$failed++;
next;
}
$cmd = $with_valg ? "valgrind --leak-check=full " .
"--show-reachable=yes " : "";
$cmd .= "vvp$sfx -M . -m $tname vsim >> vpi_log/$tname.log 2>&1";
if (system("$cmd")) {
print "==> Failed - running vvp.\n";
$failed++;
next;
}
if (diff("vpi_gold/$goldfile{$tname}", "vpi_log/$tname.log")) {
print "==> Failed - output does not match gold file.\n";
$failed++;
next;
}
print "Passed.\n";
$passed++;
} continue {
# We have to use system and not unlink here since these files
# were created by this process and it doesn't seem to know they
# are not being used.
if ($tname ne "" and $ccode{$tname} ne "") {
my $doto = $ccode{$tname};
$doto =~ s/\.(c|cc|cpp)$/.o/;
system("rm -f $doto $tname.vpi vsim") and
die "Error: failed to remove temporary files.\n";
}
}
print "=" x 76 . "\n";
print "Test results: Total=$total, Passed=$passed, Failed=$failed,".
" Not Implemented=$not_impl\n";
}
#
# We only need a simple diff, but we need to strip \r at the end of line.
#
sub diff {
my ($gold, $log) = @_;
my ($diff, $gline, $lline);
$diff = 0;
open (GOLD, "<$gold") or die "Error: unable to open $gold for reading.\n";
open (LOG, "<$log") or die "Error: unable to open $log for reading.\n";
# Loop on the gold file lines.
foreach $gline (<GOLD>) {
if (eof LOG) {
$diff = 1;
last;
}
$lline = <LOG>;
# Skip lines from valgrind ^==\d+== or ^**\d+**
while ($lline =~ m/^(==|\*\*)\d+(==|\*\*)/) {
$lline = <LOG>;
}
$lline =~ s/\r\n$/\n/; # Strip <CR> at the end of line.
if ($gline ne $lline) {
$diff = 1;
last;
}
}
# Check to see if the log file has extra lines.
while (!eof LOG and !$diff) {
$lline = <LOG>;
$diff = 1 if ($lline !~ m/^(==|\*\*)\d+(==|\*\*)/);
}
close (LOG);
close (GOLD);
return $diff
}