| 1 |
2 |
wfjm |
#!/usr/bin/perl -w
|
| 2 |
|
|
# $Id: tbw 314 2010-07-09 17:38:41Z mueller $
|
| 3 |
|
|
#
|
| 4 |
|
|
# Copyright 2007-2010 by Walter F.J. Mueller
|
| 5 |
|
|
#
|
| 6 |
|
|
# This program is free software; you may redistribute and/or modify it under
|
| 7 |
|
|
# the terms of the GNU General Public License as published by the Free
|
| 8 |
|
|
# Software Foundation, either version 2, or at your option any later version.
|
| 9 |
|
|
#
|
| 10 |
|
|
# This program is distributed in the hope that it will be useful, but
|
| 11 |
|
|
# WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
|
| 12 |
|
|
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
| 13 |
|
|
# for complete details.
|
| 14 |
|
|
#
|
| 15 |
|
|
# Revision History:
|
| 16 |
|
|
# Date Rev Version Comment
|
| 17 |
|
|
# 2010-05-23 294 1.2.2 handle tb_code's in non-local directories
|
| 18 |
|
|
# 2010-04-18 279 1.2.1 add -help and more text to print_usage()
|
| 19 |
|
|
# 2009-11-22 252 1.2 add ISim support
|
| 20 |
|
|
# 2007-09-15 82 1.1.1 test for ambigous matches of name arguments; for
|
| 21 |
|
|
# "suff=[l1;l2;..]" style inlines use linkname_tmp.tmp
|
| 22 |
|
|
# as filename
|
| 23 |
|
|
# 2007-09-09 81 1.1 add fifo setup to tbw; allow multiple action lines
|
| 24 |
|
|
# per target; support immediate mode data
|
| 25 |
|
|
# "[line1;line2;...]" values
|
| 26 |
|
|
# 2007-08-03 71 1.0.1 handle redefinition of existing symlink correctly
|
| 27 |
|
|
# 2007-06-30 62 1.0 Initial version
|
| 28 |
|
|
#
|
| 29 |
|
|
# 'test bench wrapper' to setup symlink refering to stimulus file(s)
|
| 30 |
|
|
#
|
| 31 |
|
|
# usage: tbw [file] [args]
|
| 32 |
|
|
#
|
| 33 |
|
|
# will look for file (default is _stim.dat) and setup a symlink
|
| 34 |
|
|
# _stim_dat to refer to it. All args are passed along to
|
| 35 |
|
|
#
|
| 36 |
|
|
|
| 37 |
|
|
use 5.005; # require Perl 5.005 or higher
|
| 38 |
|
|
use strict; # require strict checking
|
| 39 |
|
|
use POSIX qw(mkfifo);
|
| 40 |
|
|
use FileHandle;
|
| 41 |
|
|
|
| 42 |
|
|
my $tb_code;
|
| 43 |
|
|
my $is_isim;
|
| 44 |
|
|
my $is_isim_run;
|
| 45 |
|
|
|
| 46 |
|
|
my @args_pos; # list of positional args
|
| 47 |
|
|
my @args_nam; # list of named args
|
| 48 |
|
|
my @file_dsc; # file descriptors from tbw.dat
|
| 49 |
|
|
|
| 50 |
|
|
sub print_usage;
|
| 51 |
|
|
|
| 52 |
|
|
autoflush STDOUT 1; # autoflush, so noting lost on exec later
|
| 53 |
|
|
|
| 54 |
|
|
if (scalar(@ARGV) && $ARGV[0] =~ /^-*help$/) { # -help or --help given
|
| 55 |
|
|
print_usage;
|
| 56 |
|
|
exit 0;
|
| 57 |
|
|
}
|
| 58 |
|
|
|
| 59 |
|
|
if (scalar(@ARGV) == 0) {
|
| 60 |
|
|
print "tbw-E: name of test bench code missing\n";
|
| 61 |
|
|
print_usage;
|
| 62 |
|
|
exit 1;
|
| 63 |
|
|
}
|
| 64 |
|
|
|
| 65 |
|
|
$tb_code = shift @ARGV;
|
| 66 |
|
|
my $tb_code_path = ".";
|
| 67 |
|
|
my $tb_code_name = $tb_code;
|
| 68 |
|
|
if ($tb_code =~ m|^(.*)/(.*)$|) {
|
| 69 |
|
|
$tb_code_path = $1;
|
| 70 |
|
|
$tb_code_name = $2;
|
| 71 |
|
|
}
|
| 72 |
|
|
|
| 73 |
|
|
my $tb_code_stem = $tb_code_name;
|
| 74 |
|
|
$tb_code_stem =~ s/_[fst]sim$//; # drop _ssim,_fsim, or _tsim
|
| 75 |
|
|
|
| 76 |
|
|
if ($tb_code_stem =~ /_ISim$/) { # is it an ISim executable ?
|
| 77 |
|
|
$is_isim = 1;
|
| 78 |
|
|
$tb_code_stem =~ s/_ISim$//; # drop _ISim
|
| 79 |
|
|
if (scalar(@ARGV) && $ARGV[0] eq "-run") {
|
| 80 |
|
|
$is_isim_run = 1;
|
| 81 |
|
|
shift @ARGV;
|
| 82 |
|
|
}
|
| 83 |
|
|
}
|
| 84 |
|
|
|
| 85 |
|
|
if (not -e $tb_code) {
|
| 86 |
|
|
print "tbw-E: $tb_code not existing or not executable\n";
|
| 87 |
|
|
print_usage;
|
| 88 |
|
|
exit 1;
|
| 89 |
|
|
}
|
| 90 |
|
|
|
| 91 |
|
|
#
|
| 92 |
|
|
# read tbw.dat file in current directory or directory of executable
|
| 93 |
|
|
#
|
| 94 |
|
|
|
| 95 |
|
|
my $tbwdat_file = "tbw.dat";
|
| 96 |
|
|
$tbwdat_file = "$tb_code_path/tbw.dat" unless (-r "tbw.dat");
|
| 97 |
|
|
|
| 98 |
|
|
if (-r $tbwdat_file) {
|
| 99 |
|
|
my $ok = 0;
|
| 100 |
|
|
my $done = 0;
|
| 101 |
|
|
|
| 102 |
|
|
open (TBW, $tbwdat_file) or die "failed to open $tbwdat_file: $!";
|
| 103 |
|
|
while () {
|
| 104 |
|
|
chomp;
|
| 105 |
|
|
next if /^#/;
|
| 106 |
|
|
if (/^\s*\[([\.\/a-zA-Z0-9_]*)\]\s*$/) {
|
| 107 |
|
|
last if $done;
|
| 108 |
|
|
$ok = 0;
|
| 109 |
|
|
$ok = 1 if ($1 eq $tb_code || $1 eq $tb_code_stem);
|
| 110 |
|
|
} elsif (/^\s*([a-zA-Z0-9_]*)\s*=\s*([a-zA-Z0-9_.<>]*)\s*$/) {
|
| 111 |
|
|
if ($ok) {
|
| 112 |
|
|
push @file_dsc, {tag=>$1, val=>$2};
|
| 113 |
|
|
$done = 1;
|
| 114 |
|
|
}
|
| 115 |
|
|
}
|
| 116 |
|
|
}
|
| 117 |
|
|
}
|
| 118 |
|
|
|
| 119 |
|
|
#
|
| 120 |
|
|
# if no matching stanza found, setup default _stim linkage
|
| 121 |
|
|
#
|
| 122 |
|
|
|
| 123 |
|
|
unless (scalar (@file_dsc)) {
|
| 124 |
|
|
push @file_dsc, {tag=>$tb_code_stem . "_stim",
|
| 125 |
|
|
val=>$tb_code_stem . "_stim.dat"};
|
| 126 |
|
|
}
|
| 127 |
|
|
|
| 128 |
|
|
#
|
| 129 |
|
|
# now process argument list
|
| 130 |
|
|
#
|
| 131 |
|
|
|
| 132 |
|
|
{
|
| 133 |
|
|
my $ind = 0;
|
| 134 |
|
|
while (scalar(@ARGV)>0 && not $ARGV[0] =~ /^-/) {
|
| 135 |
|
|
my $arg = shift @ARGV;
|
| 136 |
|
|
my $ok;
|
| 137 |
|
|
if ($arg =~ /([a-zA-Z0-9_]*)=(.*)/) { # named argument
|
| 138 |
|
|
my $tag = $1;
|
| 139 |
|
|
my $val = $2;
|
| 140 |
|
|
foreach my $dsc (@file_dsc) {
|
| 141 |
|
|
if ($dsc->{tag} =~ /$tag$/) {
|
| 142 |
|
|
$dsc->{val} = $val;
|
| 143 |
|
|
$ok += 1;
|
| 144 |
|
|
}
|
| 145 |
|
|
}
|
| 146 |
|
|
if ($ok == 0) {
|
| 147 |
|
|
print STDERR "tbw-F: can't match named argument: $arg\n";
|
| 148 |
|
|
exit 1;
|
| 149 |
|
|
} elsif ($ok > 1) {
|
| 150 |
|
|
print STDERR "tbw-F: ambiguous match for named argument: $arg\n";
|
| 151 |
|
|
exit 1;
|
| 152 |
|
|
}
|
| 153 |
|
|
|
| 154 |
|
|
} else { # positional argument
|
| 155 |
|
|
if ($ind < scalar(@file_dsc)) {
|
| 156 |
|
|
$file_dsc[$ind]->{val} = $arg;
|
| 157 |
|
|
} else {
|
| 158 |
|
|
print STDERR "tbw-F: too many positional arguments: $arg\n";
|
| 159 |
|
|
exit 1;
|
| 160 |
|
|
}
|
| 161 |
|
|
$ind += 1;
|
| 162 |
|
|
}
|
| 163 |
|
|
}
|
| 164 |
|
|
}
|
| 165 |
|
|
|
| 166 |
|
|
#
|
| 167 |
|
|
# now handle all specified file descriptors
|
| 168 |
|
|
#
|
| 169 |
|
|
|
| 170 |
|
|
foreach my $dsc (@file_dsc) {
|
| 171 |
|
|
my $tag = $dsc->{tag};
|
| 172 |
|
|
my $val = $dsc->{val};
|
| 173 |
|
|
if ($val eq "") { # handle FIFO's
|
| 174 |
|
|
next if (-p $tag);
|
| 175 |
|
|
print "tbw-I: create FIFO $tag\n";
|
| 176 |
|
|
mkfifo($tag, 0666) || die "can't mkfifo $tag: $!";
|
| 177 |
|
|
|
| 178 |
|
|
} else { # handle link to file cases
|
| 179 |
|
|
|
| 180 |
|
|
if ($val =~ /^\[(.*)\]$/) { # immediate data case: "[line1;line2;...]"
|
| 181 |
|
|
my @lines = split /;/, $1;
|
| 182 |
|
|
my $fname = "$tag\_tmp.tmp";
|
| 183 |
|
|
open TFILE,">$fname" or die "can't create temporary file $fname: $!";
|
| 184 |
|
|
foreach (@lines) {
|
| 185 |
|
|
s/^\s*//;
|
| 186 |
|
|
s/\s*$//;
|
| 187 |
|
|
print TFILE "$_\n";
|
| 188 |
|
|
}
|
| 189 |
|
|
close TFILE;
|
| 190 |
|
|
$val = $fname;
|
| 191 |
|
|
|
| 192 |
|
|
} else {
|
| 193 |
|
|
unlink "$tag\_tmp.tmp" if (-e "$tag\_tmp.tmp"); # remove old .tmp file
|
| 194 |
|
|
$val = "/dev/null" if ($val eq ""); # null file case
|
| 195 |
|
|
}
|
| 196 |
|
|
|
| 197 |
|
|
if (not -r $val) {
|
| 198 |
|
|
print "tbw-F: file for $tag not existing or not readable: $val\n";
|
| 199 |
|
|
exit 1;
|
| 200 |
|
|
}
|
| 201 |
|
|
if (-l $tag) {
|
| 202 |
|
|
my $cur_link = readlink $tag;
|
| 203 |
|
|
if ($cur_link ne $val) {
|
| 204 |
|
|
print "tbw-I: redefine $tag -> $val\n";
|
| 205 |
|
|
unlink $tag
|
| 206 |
|
|
or die "failed to unlink: $!";
|
| 207 |
|
|
symlink $val, $tag
|
| 208 |
|
|
or die "failed to symlink 1: $!";
|
| 209 |
|
|
}
|
| 210 |
|
|
} else {
|
| 211 |
|
|
if (-e $tag) {
|
| 212 |
|
|
print "tbw-F: $tag exists but is not a symlink\n";
|
| 213 |
|
|
exit 1;
|
| 214 |
|
|
} else {
|
| 215 |
|
|
print "tbw-I: define $tag -> $val\n";
|
| 216 |
|
|
symlink $val, $tag
|
| 217 |
|
|
or die "failed to symlink 2: $!";
|
| 218 |
|
|
}
|
| 219 |
|
|
}
|
| 220 |
|
|
}
|
| 221 |
|
|
}
|
| 222 |
|
|
|
| 223 |
|
|
#
|
| 224 |
|
|
# here all ok, finally exec test bench
|
| 225 |
|
|
#
|
| 226 |
|
|
|
| 227 |
|
|
if ($is_isim_run) { # handle for isim 'run all'
|
| 228 |
|
|
my $cmd = $tb_code . " " . join " ",@ARGV;
|
| 229 |
|
|
open (ISIM_RUN, "| $cmd")
|
| 230 |
|
|
or die "failed to open process pipe to isim: $!";
|
| 231 |
|
|
print ISIM_RUN "run all\n";
|
| 232 |
|
|
print ISIM_RUN "quit\n";
|
| 233 |
|
|
close (ISIM_RUN)
|
| 234 |
|
|
or die "failed to close process pipe to isim: $!";
|
| 235 |
|
|
|
| 236 |
|
|
} else { # otherwise just exec
|
| 237 |
|
|
exec $tb_code,@ARGV
|
| 238 |
|
|
or die "failed to exec: $!";
|
| 239 |
|
|
}
|
| 240 |
|
|
|
| 241 |
|
|
# ----------------------------------------------------------------------------
|
| 242 |
|
|
sub print_usage {
|
| 243 |
|
|
print "usage: tbw [-run] [filedefs] [opts]\n";
|
| 244 |
|
|
print " -run for _ISim tb's, runs the tb with a 'run all' command\n";
|
| 245 |
|
|
print " filedefs define tb input, either filename in tbw.dat order or\n";
|
| 246 |
|
|
print " tag=name or tag=[] pairs with tag matching one in in\n";
|
| 247 |
|
|
print " tbw.dat. The [] form allows to give data inline, e.g.\n";
|
| 248 |
|
|
print " like \"_conf=[.rpmon 1]\"\n";
|
| 249 |
|
|
print " opts are all other options starting with a '-', they are passed\n";
|
| 250 |
|
|
print " to the testbench. Some useful ghdl options are:\n";
|
| 251 |
|
|
print " --wave=x.ghw\n";
|
| 252 |
|
|
print " --stack-max-size=16384\n";
|
| 253 |
|
|
print " --stop-time=1ns --disp-time --trace-processes\n";
|
| 254 |
|
|
}
|