| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Module::Build::Xilinx; |
|
2
|
2
|
|
|
2
|
|
26760
|
use base 'Module::Build'; |
|
|
2
|
|
|
|
|
6
|
|
|
|
2
|
|
|
|
|
4979
|
|
|
3
|
|
|
|
|
|
|
|
|
4
|
2
|
|
|
2
|
|
300277
|
use 5.0008; |
|
|
2
|
|
|
|
|
7
|
|
|
|
2
|
|
|
|
|
78
|
|
|
5
|
2
|
|
|
2
|
|
12
|
use strict; |
|
|
2
|
|
|
|
|
9
|
|
|
|
2
|
|
|
|
|
65
|
|
|
6
|
2
|
|
|
2
|
|
11
|
use warnings; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
53
|
|
|
7
|
2
|
|
|
2
|
|
11
|
use Carp; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
237
|
|
|
8
|
2
|
|
|
2
|
|
12
|
use Cwd; |
|
|
2
|
|
|
|
|
6
|
|
|
|
2
|
|
|
|
|
141
|
|
|
9
|
2
|
|
|
2
|
|
12
|
use Config; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
82
|
|
|
10
|
2
|
|
|
2
|
|
10
|
use Data::Dumper; |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
96
|
|
|
11
|
2
|
|
|
2
|
|
13
|
use File::Spec; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
69
|
|
|
12
|
2
|
|
|
2
|
|
10
|
use File::Basename qw/fileparse/; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
183
|
|
|
13
|
2
|
|
|
2
|
|
1964
|
use File::HomeDir; |
|
|
2
|
|
|
|
|
14223
|
|
|
|
2
|
|
|
|
|
15923
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our $VERSION = '0.13'; |
|
16
|
|
|
|
|
|
|
$VERSION = eval $VERSION; |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# Xilinx install path |
|
19
|
|
|
|
|
|
|
__PACKAGE__->add_property('xilinx', undef); |
|
20
|
|
|
|
|
|
|
__PACKAGE__->add_property('xilinx_settings32', undef); |
|
21
|
|
|
|
|
|
|
__PACKAGE__->add_property('xilinx_settings64', undef); |
|
22
|
|
|
|
|
|
|
# project name property |
|
23
|
|
|
|
|
|
|
__PACKAGE__->add_property('proj_name', undef); |
|
24
|
|
|
|
|
|
|
# project extension property |
|
25
|
|
|
|
|
|
|
__PACKAGE__->add_property('proj_ext', '.xise'); |
|
26
|
|
|
|
|
|
|
# project parameters related to the device |
|
27
|
|
|
|
|
|
|
__PACKAGE__->add_property('proj_params', |
|
28
|
|
|
|
|
|
|
default => sub { {} }, |
|
29
|
|
|
|
|
|
|
# this check thing doesnt work |
|
30
|
|
|
|
|
|
|
check => sub { |
|
31
|
|
|
|
|
|
|
if (ref $_ eq 'HASH') { |
|
32
|
|
|
|
|
|
|
return 1 if (defined $_->{family} and defined $_->{device}); |
|
33
|
|
|
|
|
|
|
shift->property_error( |
|
34
|
|
|
|
|
|
|
qq{Property "proj_params" needs "family" and "device" defined}); |
|
35
|
|
|
|
|
|
|
} else { |
|
36
|
|
|
|
|
|
|
shift->property_error( |
|
37
|
|
|
|
|
|
|
qq{Property "proj_params" should be a hash reference.}); |
|
38
|
|
|
|
|
|
|
} |
|
39
|
|
|
|
|
|
|
return 0; |
|
40
|
|
|
|
|
|
|
}, |
|
41
|
|
|
|
|
|
|
); |
|
42
|
|
|
|
|
|
|
__PACKAGE__->add_property('testbench', {}); |
|
43
|
|
|
|
|
|
|
# source files |
|
44
|
|
|
|
|
|
|
__PACKAGE__->add_property('source_files', []); |
|
45
|
|
|
|
|
|
|
# testbench files |
|
46
|
|
|
|
|
|
|
__PACKAGE__->add_property('testbench_files', []); |
|
47
|
|
|
|
|
|
|
# testbench source files |
|
48
|
|
|
|
|
|
|
__PACKAGE__->add_property('testbenchsrc_files', []); |
|
49
|
|
|
|
|
|
|
# tcl file |
|
50
|
|
|
|
|
|
|
__PACKAGE__->add_property('tcl_script', 'program.tcl'); |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub new { |
|
53
|
1
|
|
|
1
|
1
|
99
|
my $class = shift; |
|
54
|
|
|
|
|
|
|
# build the M::B object |
|
55
|
|
|
|
|
|
|
# hide the warnings about module_name |
|
56
|
1
|
|
|
|
|
21
|
my $self = $class->SUPER::new(module_name => $class, @_); |
|
57
|
1
|
|
|
|
|
73935
|
my $os = $self->os_type; |
|
58
|
1
|
50
|
|
|
|
67
|
croak "No support for OS" unless $os =~ /Windows|Linux|Unix/i; |
|
59
|
1
|
50
|
33
|
|
|
48
|
croak "No support for OS" if $os eq 'Unix' and $^O !~ /linux/i; |
|
60
|
1
|
|
|
|
|
35
|
$self->libdoc_dirs([]); |
|
61
|
1
|
|
|
|
|
41
|
$self->bindoc_dirs([]); |
|
62
|
|
|
|
|
|
|
# sanitize proj_params |
|
63
|
1
|
|
|
|
|
27
|
my $pp = $self->proj_params; |
|
64
|
1
|
50
|
|
|
|
20
|
if (defined $pp->{language}) { |
|
65
|
0
|
0
|
|
|
|
0
|
$pp->{language} = 'VHDL' if $pp->{language} =~ /vhdl/i; |
|
66
|
0
|
0
|
|
|
|
0
|
$pp->{language} = 'Verilog' if $pp->{language} =~ /verilog/i; |
|
67
|
0
|
0
|
|
|
|
0
|
$pp->{language} = 'N/A' unless $pp->{language} =~ /VHDL|Verilog/i; |
|
68
|
|
|
|
|
|
|
} |
|
69
|
1
|
|
|
|
|
6
|
$self->proj_params($pp); |
|
70
|
|
|
|
|
|
|
# project name can just be dist_name |
|
71
|
1
|
|
|
|
|
7
|
$self->proj_name($self->dist_name); |
|
72
|
|
|
|
|
|
|
# add the Verilog/VHDL files as build files |
|
73
|
1
|
|
|
|
|
55
|
$self->add_build_element('hdl'); |
|
74
|
|
|
|
|
|
|
# add the Verilog/VHDL testbench files as well |
|
75
|
1
|
|
|
|
|
49
|
$self->add_build_element('tb'); |
|
76
|
|
|
|
|
|
|
# add the ucf files as build files |
|
77
|
1
|
|
|
|
|
24
|
$self->add_build_element('ucf'); |
|
78
|
1
|
50
|
|
|
|
33
|
if (defined $self->tcl_script) { |
|
79
|
1
|
|
|
|
|
41
|
my $tcl = File::Spec->catfile($self->blib, $self->tcl_script); |
|
80
|
1
|
|
|
|
|
50
|
$self->tcl_script($tcl); |
|
81
|
1
|
|
|
|
|
36
|
$self->add_to_cleanup($tcl); |
|
82
|
|
|
|
|
|
|
} |
|
83
|
|
|
|
|
|
|
# find the Xilinx install path |
|
84
|
1
|
|
|
|
|
297
|
my $xil_path = $self->_find_xilinx($ENV{XILINX}); |
|
85
|
1
|
50
|
|
|
|
9
|
$self->xilinx($xil_path) if defined $xil_path; |
|
86
|
1
|
50
|
|
|
|
4
|
print "Found Xilinx installed at $xil_path\n" if defined $xil_path; |
|
87
|
|
|
|
|
|
|
|
|
88
|
1
|
|
50
|
|
|
14
|
my $oref = $self->get_options() || {}; |
|
89
|
1
|
50
|
|
|
|
41
|
$oref->{device} = { type => '=s' } unless exists $oref->{device}; |
|
90
|
1
|
50
|
|
|
|
12
|
$oref->{view} = { type => '=s@' } unless exists $oref->{view}; |
|
91
|
1
|
|
|
|
|
11
|
return $self; |
|
92
|
|
|
|
|
|
|
} |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub ACTION_build { |
|
95
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
96
|
|
|
|
|
|
|
# build invokes the process_*_files() functions |
|
97
|
0
|
0
|
|
|
|
0
|
$self->SUPER::ACTION_build(@_) if $self->SUPER::can_action('build'); |
|
98
|
0
|
|
|
|
|
0
|
my $tcl = $self->tcl_script; |
|
99
|
0
|
|
|
|
|
0
|
$self->log_info("Generating the $tcl script\n"); |
|
100
|
0
|
0
|
|
|
|
0
|
if ($self->verbose) { |
|
101
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Terse = 1; |
|
102
|
0
|
|
|
|
|
0
|
my ($a, $b) = Data::Dumper->Dumper($self->source_files); |
|
103
|
0
|
|
|
|
|
0
|
$self->log_verbose("source files: $b"); |
|
104
|
|
|
|
|
|
|
} |
|
105
|
|
|
|
|
|
|
# add the tcl code |
|
106
|
0
|
0
|
|
|
|
0
|
open my $fh, '>', $tcl or croak "Unable to open $tcl for writing: $!"; |
|
107
|
0
|
|
|
|
|
0
|
print $fh $self->_dump_tcl_code(); |
|
108
|
0
|
|
|
|
|
0
|
close $fh; |
|
109
|
|
|
|
|
|
|
# we do this here since otherwise the tests will fail |
|
110
|
0
|
|
|
|
|
0
|
my $xil_path = $self->xilinx; |
|
111
|
0
|
0
|
|
|
|
0
|
croak $self->_cant_find_xilinx() unless defined $xil_path; |
|
112
|
0
|
|
|
|
|
0
|
1; |
|
113
|
|
|
|
|
|
|
} |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
sub process_ucf_files { |
|
116
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
117
|
0
|
|
|
|
|
0
|
my $regex = qr/\.(?:ucf)$/; |
|
118
|
0
|
|
|
|
|
0
|
return $self->_process_src_files($regex); |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub _process_src_files($) { |
|
122
|
0
|
|
|
0
|
|
0
|
my ($self, $regex) = @_; |
|
123
|
0
|
|
|
|
|
0
|
my @filearray = (); |
|
124
|
0
|
|
|
|
|
0
|
foreach my $dir (qw/lib src/) { |
|
125
|
0
|
0
|
|
|
|
0
|
next unless -d $dir; |
|
126
|
0
|
|
|
|
|
0
|
eval { |
|
127
|
0
|
|
|
|
|
0
|
my $files = $self->rscan_dir($dir, $regex); |
|
128
|
0
|
0
|
0
|
|
|
0
|
push @filearray, @$files if ref $files eq 'ARRAY' and scalar @$files; |
|
129
|
|
|
|
|
|
|
}; |
|
130
|
0
|
0
|
|
|
|
0
|
carp "hdl: $@" if $@; |
|
131
|
|
|
|
|
|
|
} |
|
132
|
|
|
|
|
|
|
# make unique |
|
133
|
0
|
|
|
|
|
0
|
push @filearray, @{$self->source_files}; |
|
|
0
|
|
|
|
|
0
|
|
|
134
|
0
|
|
|
|
|
0
|
my %fh = map { $_ => 1 } @filearray; |
|
|
0
|
|
|
|
|
0
|
|
|
135
|
0
|
|
|
|
|
0
|
$self->source_files([keys %fh]); |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub process_hdl_files { |
|
139
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
140
|
0
|
|
|
|
|
0
|
my $regex = qr/\.(?:vhdl|vhd|v)$/; |
|
141
|
0
|
|
|
|
|
0
|
return $self->_process_src_files($regex); |
|
142
|
|
|
|
|
|
|
} |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
sub process_tb_files { |
|
145
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
146
|
|
|
|
|
|
|
## patterns taken from $Xilinx/data/projnav/xil_tb_patterns.txt |
|
147
|
0
|
|
|
|
|
0
|
my $regex_tb = |
|
148
|
|
|
|
|
|
|
qr/(?:_tb|_tf|_testbench|_tb_[0-9]+|databench\w*|testbench\w*)\.(?:vhdl|vhd|v)$/; |
|
149
|
0
|
|
|
|
|
0
|
my $regex = qr/\.(?:vhdl|vhd|v)$/; |
|
150
|
0
|
|
|
|
|
0
|
return $self->_process_tb_files($regex_tb, $regex); |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub _process_tb_files($$) { |
|
154
|
0
|
|
|
0
|
|
0
|
my ($self, $regex_tb, $regex) = @_; |
|
155
|
0
|
|
|
|
|
0
|
my @filearray = (); |
|
156
|
|
|
|
|
|
|
# find all the _tb files in lib/src |
|
157
|
0
|
|
|
|
|
0
|
foreach my $dir (qw/lib src t tb/) { |
|
158
|
0
|
0
|
|
|
|
0
|
next unless -d $dir; |
|
159
|
0
|
|
|
|
|
0
|
eval { |
|
160
|
0
|
|
|
|
|
0
|
my $files = $self->rscan_dir($dir, $regex_tb); |
|
161
|
0
|
0
|
0
|
|
|
0
|
push @filearray, @$files if ref $files eq 'ARRAY' and scalar @$files; |
|
162
|
|
|
|
|
|
|
}; |
|
163
|
0
|
0
|
|
|
|
0
|
carp "tb: $@" if $@; |
|
164
|
|
|
|
|
|
|
} |
|
165
|
|
|
|
|
|
|
# make unique |
|
166
|
0
|
|
|
|
|
0
|
push @filearray, @{$self->testbench_files}; |
|
|
0
|
|
|
|
|
0
|
|
|
167
|
0
|
|
|
|
|
0
|
my %fh = map { $_ => 1 } @filearray; |
|
|
0
|
|
|
|
|
0
|
|
|
168
|
0
|
|
|
|
|
0
|
$self->testbench_files([keys %fh]); |
|
169
|
|
|
|
|
|
|
# find all the vhd/ver files in t/tb, since multiple testbench files |
|
170
|
|
|
|
|
|
|
# and dependent entity files may co-exist in one as a supplement. |
|
171
|
|
|
|
|
|
|
# this is similar to the t/ directory having a .pm file |
|
172
|
0
|
|
|
|
|
0
|
my $tbsrc = $self->testbenchsrc_files; |
|
173
|
0
|
|
|
|
|
0
|
foreach my $dir (qw/t tb/) { |
|
174
|
0
|
0
|
|
|
|
0
|
next unless -d $dir; |
|
175
|
0
|
|
|
|
|
0
|
eval { |
|
176
|
0
|
|
|
|
|
0
|
my $files = $self->rscan_dir($dir, $regex); |
|
177
|
0
|
|
|
|
|
0
|
foreach (@$files) { |
|
178
|
0
|
0
|
|
|
|
0
|
next if $fh{$_}; |
|
179
|
0
|
|
|
|
|
0
|
push @$tbsrc, $_; |
|
180
|
|
|
|
|
|
|
} |
|
181
|
|
|
|
|
|
|
}; |
|
182
|
0
|
0
|
|
|
|
0
|
carp "tb: $@" if $@; |
|
183
|
|
|
|
|
|
|
} |
|
184
|
0
|
|
|
|
|
0
|
my %fh2 = map { $_ => 1 } @$tbsrc; |
|
|
0
|
|
|
|
|
0
|
|
|
185
|
0
|
|
|
|
|
0
|
$self->testbenchsrc_files([keys %fh2]); |
|
186
|
|
|
|
|
|
|
# find the correct testbench top-levels |
|
187
|
0
|
|
|
|
|
0
|
my $tb = $self->testbench; |
|
188
|
0
|
|
|
|
|
0
|
foreach my $key (keys %fh) { |
|
189
|
|
|
|
|
|
|
# we only care about the files that Xilinx assumes can be a testbench |
|
190
|
0
|
0
|
|
|
|
0
|
next unless $key =~ /$regex_tb/; |
|
191
|
0
|
0
|
|
|
|
0
|
my $hh = exists $tb->{$key} ? $tb->{$key} : {}; |
|
192
|
0
|
0
|
|
|
|
0
|
croak "Property testbench{$key} has to be a hash reference" unless ref $hh eq 'HASH'; |
|
193
|
0
|
|
|
|
|
0
|
my ($file, $dirs, $ext) = fileparse($key, $regex); |
|
194
|
0
|
0
|
|
|
|
0
|
$hh->{toplevel} = 'testbench' unless defined $hh->{toplevel}; |
|
195
|
0
|
0
|
|
|
|
0
|
$hh->{srclib} = 'work' unless defined $hh->{srclib}; |
|
196
|
0
|
0
|
|
|
|
0
|
$hh->{wdb} = $file . '.wdb' unless defined $hh->{wdb}; |
|
197
|
0
|
0
|
|
|
|
0
|
$hh->{exe} = $file . '.exe' unless defined $hh->{exe}; |
|
198
|
0
|
0
|
|
|
|
0
|
$hh->{prj} = $file . '.prj' unless defined $hh->{prj}; |
|
199
|
0
|
0
|
|
|
|
0
|
$hh->{cmd} = $file . '.cmd' unless defined $hh->{cmd}; |
|
200
|
0
|
|
|
|
|
0
|
$tb->{$key} = $hh; |
|
201
|
|
|
|
|
|
|
} |
|
202
|
0
|
|
|
|
|
0
|
$self->testbench($tb); |
|
203
|
|
|
|
|
|
|
} |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
sub _cant_find_xilinx { |
|
206
|
0
|
|
|
0
|
|
0
|
return << 'CANTFIND'; |
|
207
|
|
|
|
|
|
|
Cannot find Xilinx ISE installation. Set the XILINX environment variable to point to it such as |
|
208
|
|
|
|
|
|
|
/opt/Xilinx/13.2/ISE or set the 'xilinx' property in the Build.PL script of the |
|
209
|
|
|
|
|
|
|
Module::Build::Xilinx. You will need to re-run Build.PL after this. |
|
210
|
|
|
|
|
|
|
CANTFIND |
|
211
|
|
|
|
|
|
|
} |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
sub _find_xilinx { |
|
214
|
1
|
|
|
1
|
|
47
|
my $self = shift; |
|
215
|
1
|
|
|
|
|
4
|
my $env_xil = shift; |
|
216
|
1
|
|
|
|
|
6
|
my $xil_path = $self->xilinx; |
|
217
|
1
|
|
|
|
|
26
|
my $homedir = File::HomeDir->my_home(); |
|
218
|
1
|
|
|
|
|
77
|
my @xildirs = (); |
|
219
|
1
|
|
|
|
|
3
|
my @final = (); |
|
220
|
1
|
50
|
33
|
|
|
12
|
push @final, $env_xil if (defined $env_xil and -d $env_xil); |
|
221
|
1
|
50
|
33
|
|
|
6
|
push @final, $xil_path if (defined $xil_path and -d $xil_path); |
|
222
|
1
|
50
|
|
|
|
11
|
if ($self->is_windowsish()) { |
|
223
|
|
|
|
|
|
|
# in Windows the Xilinx is installed in C:/Xilinx by default |
|
224
|
0
|
|
|
|
|
0
|
my @drives = ( $ENV{SystemDrive}, $ENV{HOMEDRIVE} ); |
|
225
|
0
|
|
|
|
|
0
|
@drives = grep { defined $_ } @drives; |
|
|
0
|
|
|
|
|
0
|
|
|
226
|
0
|
|
|
|
|
0
|
foreach (@drives) { |
|
227
|
0
|
|
|
|
|
0
|
my $d = "$_\\Xilinx"; |
|
228
|
0
|
0
|
|
|
|
0
|
push @xildirs, $d if -d $d; |
|
229
|
|
|
|
|
|
|
} |
|
230
|
0
|
|
0
|
|
|
0
|
my $pf = $ENV{ProgramFiles} || $ENV{PROGRAMFILES}; |
|
231
|
0
|
|
0
|
|
|
0
|
my $pfx86 = $ENV{'ProgramFiles(x86)'} || $ENV{'PROGRAMFILES(X86)'}; |
|
232
|
0
|
|
|
|
|
0
|
foreach (($homedir, $pf, $pfx86)) { |
|
233
|
0
|
0
|
|
|
|
0
|
next unless defined $_; |
|
234
|
0
|
0
|
|
|
|
0
|
next unless -d $_; |
|
235
|
0
|
0
|
|
|
|
0
|
push @xildirs, "$_\\Xilinx" if -d "$_\\Xilinx"; |
|
236
|
|
|
|
|
|
|
} |
|
237
|
|
|
|
|
|
|
} else { |
|
238
|
|
|
|
|
|
|
# in Unix/Linux Xilinx is installed in /opt by default |
|
239
|
1
|
|
|
|
|
23
|
foreach (($homedir, '/opt', '/usr', '/usr/local')) { |
|
240
|
4
|
50
|
|
|
|
11
|
next unless defined $_; |
|
241
|
4
|
50
|
|
|
|
70
|
next unless -d $_; |
|
242
|
4
|
50
|
|
|
|
64
|
push @xildirs, "$_/Xilinx" if -d "$_/Xilinx"; |
|
243
|
|
|
|
|
|
|
} |
|
244
|
|
|
|
|
|
|
} |
|
245
|
1
|
50
|
|
|
|
5
|
unless (scalar @xildirs) { |
|
246
|
1
|
|
|
|
|
520
|
carp "Cannot find any directories with Xilinx software installed"; |
|
247
|
1
|
|
|
|
|
208
|
return; |
|
248
|
|
|
|
|
|
|
} |
|
249
|
0
|
0
|
|
|
|
|
if ($self->verbose) { |
|
250
|
0
|
|
|
|
|
|
local $Data::Dumper::Terse = 1; |
|
251
|
0
|
|
|
|
|
|
print "Found directories with Xilinx software installed: ", Dumper(\@xildirs), "\n"; |
|
252
|
|
|
|
|
|
|
} |
|
253
|
0
|
|
|
|
|
|
foreach my $xdir (@xildirs) { |
|
254
|
0
|
0
|
|
|
|
|
opendir my $fd, $xdir or carp "Cannot open directory $xdir"; |
|
255
|
0
|
0
|
|
|
|
|
next unless $fd; |
|
256
|
0
|
|
|
|
|
|
my @filenames = readdir $fd; |
|
257
|
0
|
|
|
|
|
|
closedir $fd; |
|
258
|
0
|
|
|
|
|
|
my @possible = grep { /\d+\.\d+/ } @filenames; |
|
|
0
|
|
|
|
|
|
|
|
259
|
0
|
0
|
|
|
|
|
next unless scalar @possible; |
|
260
|
0
|
|
|
|
|
|
@possible = map(File::Spec->catfile($xdir, $_), @possible); |
|
261
|
0
|
|
|
|
|
|
push @final, @possible; |
|
262
|
|
|
|
|
|
|
} |
|
263
|
0
|
0
|
|
|
|
|
if ($self->verbose) { |
|
264
|
0
|
|
|
|
|
|
print "Found possible directories with Xilinx software installed: ", Dumper(\@final); |
|
265
|
|
|
|
|
|
|
} |
|
266
|
0
|
0
|
|
|
|
|
unless (scalar @final) { |
|
267
|
0
|
|
|
|
|
|
carp "Cannot find any directories with Xilinx software installed"; |
|
268
|
0
|
|
|
|
|
|
return; |
|
269
|
|
|
|
|
|
|
} |
|
270
|
0
|
|
|
|
|
|
my $result; |
|
271
|
0
|
|
|
|
|
|
foreach (@final) { |
|
272
|
0
|
0
|
|
|
|
|
my $ext = $self->is_windowsish() ? 'bat' : 'sh'; |
|
273
|
0
|
|
|
|
|
|
$result = File::Spec->catfile($_, 'ISE_DS'); |
|
274
|
0
|
|
|
|
|
|
my $f32 = File::Spec->catfile($result, "settings32.$ext"); |
|
275
|
0
|
|
|
|
|
|
my $f64 = File::Spec->catfile($result, "settings64.$ext"); |
|
276
|
0
|
0
|
0
|
|
|
|
if (-e $f64 or -e $f32) { |
|
277
|
0
|
|
|
|
|
|
$self->xilinx_settings64($f64); |
|
278
|
0
|
|
|
|
|
|
$self->xilinx_settings32($f32); |
|
279
|
0
|
0
|
|
|
|
|
print "Found $f64 and $f32 in $result\n" if $self->verbose; |
|
280
|
0
|
|
|
|
|
|
last; |
|
281
|
|
|
|
|
|
|
} |
|
282
|
|
|
|
|
|
|
} |
|
283
|
0
|
|
|
|
|
|
return $result; |
|
284
|
|
|
|
|
|
|
} |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
sub _exec_tcl_script($) { |
|
287
|
0
|
|
|
0
|
|
|
my ($self, $opt) = @_; |
|
288
|
|
|
|
|
|
|
# find xtclsh and run the tcl script |
|
289
|
|
|
|
|
|
|
# for that you need to find the Xilinx install path or use a user supplied |
|
290
|
|
|
|
|
|
|
# one and run it here |
|
291
|
0
|
|
|
|
|
|
my $tcl = $self->tcl_script; |
|
292
|
0
|
0
|
|
|
|
|
croak "$tcl is missing. Please run ./Build first" unless -e $tcl; |
|
293
|
0
|
|
|
|
|
|
my $cmd1 = $self->xilinx_settings32; |
|
294
|
0
|
0
|
|
|
|
|
$cmd1 = $self->xilinx_settings64 if $Config{archname} =~ /x86_64|x64/; |
|
295
|
0
|
|
|
|
|
|
my $cmd2 = "xtclsh $tcl $opt"; |
|
296
|
0
|
0
|
|
|
|
|
print "Loading settings from $cmd1 and running $cmd2\n" if $self->verbose; |
|
297
|
0
|
0
|
|
|
|
|
if ($self->is_windowsish()) { |
|
298
|
0
|
|
|
|
|
|
my $bat = File::Spec->catfile($self->blib, 'runtcl.bat'); |
|
299
|
0
|
0
|
|
|
|
|
open my $fh, '>', $bat or croak "Unable to open $bat for writing: $!"; |
|
300
|
0
|
|
|
|
|
|
print $fh "call $cmd1\r\n"; |
|
301
|
0
|
|
|
|
|
|
print $fh "$cmd2\r\n"; |
|
302
|
0
|
|
|
|
|
|
print $fh "echo 'done running $cmd2'\r\n"; |
|
303
|
0
|
|
|
|
|
|
print $fh "exit\r\n"; |
|
304
|
0
|
|
|
|
|
|
close $fh; |
|
305
|
0
|
0
|
|
|
|
|
system($bat) == 0 or croak "Failure while executing '$bat': $!"; |
|
306
|
|
|
|
|
|
|
} else { |
|
307
|
0
|
0
|
|
|
|
|
system("source $cmd1 && $cmd2") == 0 or croak "Failure while executing '$cmd1 && $cmd2': $!"; |
|
308
|
|
|
|
|
|
|
} |
|
309
|
|
|
|
|
|
|
} |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
sub _exec_isimgui($) { |
|
312
|
0
|
|
|
0
|
|
|
my ($self, $wdb) = @_; |
|
313
|
|
|
|
|
|
|
# NO CHDIR here |
|
314
|
|
|
|
|
|
|
# find xtclsh and run the tcl script |
|
315
|
|
|
|
|
|
|
# for that you need to find the Xilinx install path or use a user supplied |
|
316
|
|
|
|
|
|
|
# one and run it here |
|
317
|
0
|
|
|
|
|
|
my $cmd1 = $self->xilinx_settings32; |
|
318
|
0
|
0
|
|
|
|
|
$cmd1 = $self->xilinx_settings64 if $Config{archname} =~ /x86_64|x64/; |
|
319
|
0
|
|
|
|
|
|
my $cmd2 = "isimgui -view $wdb"; |
|
320
|
0
|
0
|
|
|
|
|
print "Loading settings from $cmd1 and running $cmd2\n" if $self->verbose; |
|
321
|
0
|
0
|
|
|
|
|
if ($self->is_windowsish()) { |
|
322
|
0
|
|
|
|
|
|
my $bat = File::Spec->catfile($self->blib, 'runview.bat'); |
|
323
|
0
|
0
|
|
|
|
|
open my $fh, '>', $bat or croak "Unable to open $bat for writing: $!"; |
|
324
|
0
|
|
|
|
|
|
print $fh "call $cmd1\r\n"; |
|
325
|
0
|
|
|
|
|
|
print $fh "$cmd2\r\n"; |
|
326
|
0
|
|
|
|
|
|
print $fh "echo 'done running $cmd2'\r\n"; |
|
327
|
0
|
|
|
|
|
|
print $fh "exit\r\n"; |
|
328
|
0
|
|
|
|
|
|
close $fh; |
|
329
|
0
|
0
|
|
|
|
|
system($bat) == 0 or croak "Failure while executing '$bat': $!"; |
|
330
|
|
|
|
|
|
|
} else { |
|
331
|
0
|
0
|
|
|
|
|
system("source $cmd1 && $cmd2") == 0 or croak "Failure while executing '$cmd1 && $cmd2': $!"; |
|
332
|
|
|
|
|
|
|
} |
|
333
|
|
|
|
|
|
|
} |
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
sub _exec_fuse($$$) { |
|
336
|
0
|
|
|
0
|
|
|
my ($self, $prj, $exe, $topname) = @_; |
|
337
|
0
|
|
|
|
|
|
my $cwd = Cwd::cwd(); |
|
338
|
0
|
|
|
|
|
|
chdir $self->blib; |
|
339
|
|
|
|
|
|
|
|
|
340
|
0
|
|
|
|
|
|
my $cmd1 = $self->xilinx_settings32; |
|
341
|
0
|
0
|
|
|
|
|
$cmd1 = $self->xilinx_settings64 if $Config{archname} =~ /x86_64|x64/; |
|
342
|
0
|
|
|
|
|
|
my $cmd2 = "fuse -incremental $topname -prj $prj -o $exe"; |
|
343
|
0
|
0
|
|
|
|
|
print "Loading settings from $cmd1 and running $cmd2\n" if $self->verbose; |
|
344
|
0
|
0
|
|
|
|
|
if ($self->is_windowsish()) { |
|
345
|
0
|
|
|
|
|
|
my $bat = 'runfuse.bat'; |
|
346
|
0
|
0
|
|
|
|
|
open my $fh, '>', $bat or croak "Unable to open $bat for writing: $!"; |
|
347
|
0
|
|
|
|
|
|
print $fh "call $cmd1\r\n"; |
|
348
|
0
|
|
|
|
|
|
print $fh "$cmd2\r\n"; |
|
349
|
0
|
|
|
|
|
|
print $fh "echo 'done running $cmd2'\r\n"; |
|
350
|
0
|
|
|
|
|
|
print $fh "exit\r\n"; |
|
351
|
0
|
|
|
|
|
|
close $fh; |
|
352
|
0
|
0
|
|
|
|
|
system($bat) == 0 or croak "Failure while executing '$bat': $!"; |
|
353
|
|
|
|
|
|
|
} else { |
|
354
|
0
|
0
|
|
|
|
|
system("source $cmd1 && $cmd2") == 0 or croak "Failure while executing '$cmd1 && $cmd2': $!"; |
|
355
|
|
|
|
|
|
|
} |
|
356
|
0
|
|
|
|
|
|
chdir $cwd; |
|
357
|
|
|
|
|
|
|
} |
|
358
|
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
sub _exec_simulation($$$$) { |
|
360
|
0
|
|
|
0
|
|
|
my ($self, $exe, $cmd, $wdb, $log) = @_; |
|
361
|
0
|
|
|
|
|
|
my $cwd = Cwd::cwd(); |
|
362
|
0
|
|
|
|
|
|
chdir $self->blib; |
|
363
|
|
|
|
|
|
|
|
|
364
|
0
|
|
|
|
|
|
my $cmd1 = $self->xilinx_settings32; |
|
365
|
0
|
0
|
|
|
|
|
$cmd1 = $self->xilinx_settings64 if $Config{archname} =~ /x86_64|x64/; |
|
366
|
0
|
|
|
|
|
|
my $cmd2 = "$exe -tclbatch $cmd -wdb $wdb -log $log"; |
|
367
|
0
|
0
|
|
|
|
|
print "Loading settings from $cmd1 and running $cmd2\n" if $self->verbose; |
|
368
|
0
|
0
|
|
|
|
|
if ($self->is_windowsish()) { |
|
369
|
0
|
|
|
|
|
|
my $bat = 'runsim.bat'; |
|
370
|
0
|
0
|
|
|
|
|
open my $fh, '>', $bat or croak "Unable to open $bat for writing: $!"; |
|
371
|
0
|
|
|
|
|
|
print $fh "call $cmd1\r\n"; |
|
372
|
0
|
|
|
|
|
|
print $fh ".\\$cmd2\r\n"; |
|
373
|
0
|
|
|
|
|
|
print $fh "echo 'done running $cmd2'\r\n"; |
|
374
|
0
|
|
|
|
|
|
print $fh "exit\r\n"; |
|
375
|
0
|
|
|
|
|
|
close $fh; |
|
376
|
0
|
0
|
|
|
|
|
system($bat) == 0 or croak "Failure while executing '$bat': $!"; |
|
377
|
|
|
|
|
|
|
} else { |
|
378
|
0
|
0
|
|
|
|
|
system("source $cmd1 && ./$cmd2") == 0 or croak "Failure while executing '$cmd1 && $cmd2': $!"; |
|
379
|
|
|
|
|
|
|
} |
|
380
|
0
|
|
|
|
|
|
chdir $cwd; |
|
381
|
|
|
|
|
|
|
} |
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub _exec_impact($) { |
|
384
|
0
|
|
|
0
|
|
|
my ($self, $device) = @_; |
|
385
|
0
|
|
|
|
|
|
my $cwd = Cwd::cwd(); |
|
386
|
0
|
|
|
|
|
|
chdir $self->blib; |
|
387
|
|
|
|
|
|
|
|
|
388
|
0
|
|
|
|
|
|
my $cmd1 = $self->xilinx_settings32; |
|
389
|
0
|
0
|
|
|
|
|
$cmd1 = $self->xilinx_settings64 if $Config{archname} =~ /x86_64|x64/; |
|
390
|
0
|
|
|
|
|
|
my $pcmd = File::Spec->catfile(File::Spec->curdir(), 'program_device.cmd'); |
|
391
|
0
|
|
|
|
|
|
my $projipf = File::Spec->catfile(File::Spec->curdir(), $self->proj_name . ".ipf"); |
|
392
|
|
|
|
|
|
|
|
|
393
|
0
|
|
|
|
|
|
my $cmd2 = "impact -batch $pcmd"; |
|
394
|
0
|
0
|
|
|
|
|
print "Loading settings from $cmd1 and running $cmd2\n" if $self->verbose; |
|
395
|
0
|
0
|
|
|
|
|
open my $fh, '>', $pcmd or croak "Unable to write to $pcmd: $!"; |
|
396
|
0
|
|
|
|
|
|
my $data = << 'PROGDATA'; |
|
397
|
|
|
|
|
|
|
setLog -file program_device.log |
|
398
|
|
|
|
|
|
|
setPreference -pref UserLevel:Novice |
|
399
|
|
|
|
|
|
|
setPreference -pref ConfigOnFailure:Stop |
|
400
|
|
|
|
|
|
|
setMode -bscan |
|
401
|
|
|
|
|
|
|
setCable -port auto |
|
402
|
|
|
|
|
|
|
identify |
|
403
|
|
|
|
|
|
|
PROGDATA |
|
404
|
0
|
|
|
|
|
|
print $fh $data; |
|
405
|
0
|
|
|
|
|
|
my $i = 0; |
|
406
|
0
|
|
|
|
|
|
my @bitfiles = <*.bit>; |
|
407
|
|
|
|
|
|
|
## assign the bit files to a tag $i |
|
408
|
0
|
|
|
|
|
|
foreach (@bitfiles) { |
|
409
|
0
|
|
|
|
|
|
$i++; |
|
410
|
0
|
|
|
|
|
|
my $line = << "LINEBIT"; |
|
411
|
|
|
|
|
|
|
assignFile -p $i -file \"$_\" |
|
412
|
|
|
|
|
|
|
LINEBIT |
|
413
|
0
|
|
|
|
|
|
print $fh $line; |
|
414
|
|
|
|
|
|
|
} |
|
415
|
|
|
|
|
|
|
## program all the tags |
|
416
|
0
|
|
|
|
|
|
$i = 0; |
|
417
|
0
|
|
|
|
|
|
foreach (@bitfiles) { |
|
418
|
0
|
|
|
|
|
|
$i++; |
|
419
|
0
|
|
|
|
|
|
my $line = << "LINEBIT"; |
|
420
|
|
|
|
|
|
|
program -p $i |
|
421
|
|
|
|
|
|
|
LINEBIT |
|
422
|
0
|
|
|
|
|
|
print $fh $line; |
|
423
|
|
|
|
|
|
|
} |
|
424
|
0
|
|
|
|
|
|
$data = << "PROGDATA"; |
|
425
|
|
|
|
|
|
|
checkIntegrity |
|
426
|
|
|
|
|
|
|
saveprojectfile -file \"$projipf\" |
|
427
|
|
|
|
|
|
|
quit |
|
428
|
|
|
|
|
|
|
PROGDATA |
|
429
|
0
|
|
|
|
|
|
print $fh $data; |
|
430
|
0
|
|
|
|
|
|
close $fh; |
|
431
|
0
|
0
|
|
|
|
|
if ($self->is_windowsish()) { |
|
432
|
0
|
|
|
|
|
|
my $bat = 'runprog.bat'; |
|
433
|
0
|
0
|
|
|
|
|
open my $fh, '>', $bat or croak "Unable to open $bat for writing: $!"; |
|
434
|
0
|
|
|
|
|
|
print $fh "call $cmd1\r\n"; |
|
435
|
0
|
|
|
|
|
|
print $fh "$cmd2\r\n"; |
|
436
|
0
|
|
|
|
|
|
print $fh "echo 'done running $cmd2'\r\n"; |
|
437
|
0
|
|
|
|
|
|
print $fh "exit\r\n"; |
|
438
|
0
|
|
|
|
|
|
close $fh; |
|
439
|
0
|
0
|
|
|
|
|
system($bat) == 0 or croak "Failure while executing '$bat': $!"; |
|
440
|
|
|
|
|
|
|
} else { |
|
441
|
0
|
0
|
|
|
|
|
system("source $cmd1 && $cmd2") == 0 or croak "Failure while executing '$cmd1 && $cmd2': $!"; |
|
442
|
|
|
|
|
|
|
} |
|
443
|
0
|
|
|
|
|
|
chdir $cwd; |
|
444
|
|
|
|
|
|
|
} |
|
445
|
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
sub ACTION_psetup { |
|
447
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
448
|
0
|
|
|
|
|
|
$self->ACTION_build(@_); |
|
449
|
0
|
|
|
|
|
|
return $self->_exec_tcl_script('-setup'); |
|
450
|
|
|
|
|
|
|
} |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
sub ACTION_pclean { |
|
453
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
454
|
0
|
|
|
|
|
|
$self->ACTION_build(@_); |
|
455
|
0
|
|
|
|
|
|
return $self->_exec_tcl_script('-clean'); |
|
456
|
|
|
|
|
|
|
} |
|
457
|
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
sub ACTION_pbuild { |
|
459
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
460
|
0
|
|
|
|
|
|
$self->ACTION_psetup(@_); |
|
461
|
0
|
|
|
|
|
|
return $self->_exec_tcl_script('-build'); |
|
462
|
|
|
|
|
|
|
} |
|
463
|
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
sub ACTION_test { |
|
465
|
0
|
|
|
0
|
0
|
|
return shift->ACTION_simulate(@_); |
|
466
|
|
|
|
|
|
|
} |
|
467
|
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
sub ACTION_simulate { |
|
469
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
470
|
|
|
|
|
|
|
# manage multiple views. how does one update runtime_params ? hence we just |
|
471
|
|
|
|
|
|
|
# re-run the Build as needed. |
|
472
|
0
|
|
|
|
|
|
$self->ACTION_build(@_); |
|
473
|
0
|
|
|
|
|
|
my $tb_data = $self->testbench; |
|
474
|
0
|
|
0
|
|
|
|
my $simfiles = $self->SUPER::args('sim_files') || [keys %$tb_data]; |
|
475
|
0
|
0
|
|
|
|
|
$simfiles = [$simfiles] unless ref $simfiles eq 'ARRAY'; |
|
476
|
0
|
0
|
|
|
|
|
if (scalar @$simfiles) { |
|
477
|
0
|
0
|
|
|
|
|
if ($self->verbose) { |
|
478
|
0
|
|
|
|
|
|
local $Data::Dumper::Terse = 1; |
|
479
|
0
|
|
|
|
|
|
print "Running tests for the following: ", Dumper($simfiles); |
|
480
|
|
|
|
|
|
|
} |
|
481
|
0
|
|
|
|
|
|
my $blib = $self->blib; |
|
482
|
0
|
|
|
|
|
|
my $flag = File::Spec->catfile($blib, '.done_build'); |
|
483
|
0
|
0
|
|
|
|
|
croak "You need to run 'Build pbuild' before running simulate" unless -e $flag; |
|
484
|
0
|
|
|
|
|
|
foreach my $vf (@$simfiles) { |
|
485
|
0
|
0
|
|
|
|
|
$vf =~ s:\\:/:g if $self->is_windowsish();# convert windows paths out |
|
486
|
0
|
|
|
|
|
|
$vf =~ s:^\./::g; # remove ./ from the beginning |
|
487
|
0
|
0
|
|
|
|
|
unless (exists $tb_data->{$vf}) { |
|
488
|
0
|
|
|
|
|
|
carp "$vf is not a valid testbench file"; |
|
489
|
0
|
|
|
|
|
|
next; |
|
490
|
|
|
|
|
|
|
} |
|
491
|
0
|
|
|
|
|
|
my $prj = $tb_data->{$vf}->{prj}; |
|
492
|
0
|
|
|
|
|
|
my $exe = $tb_data->{$vf}->{exe}; |
|
493
|
0
|
|
|
|
|
|
my $cmd = $tb_data->{$vf}->{cmd}; |
|
494
|
0
|
|
|
|
|
|
my $wdb = $tb_data->{$vf}->{wdb}; |
|
495
|
0
|
|
|
|
|
|
my $topname = $tb_data->{$vf}->{srclib} . '.' . $tb_data->{$vf}->{toplevel}; |
|
496
|
0
|
|
|
|
|
|
my $log = $exe; |
|
497
|
0
|
|
|
|
|
|
$log =~ s/\.exe$/\.log/g; |
|
498
|
0
|
|
|
|
|
|
my $cmdfile = File::Spec->catfile($blib, $cmd); |
|
499
|
0
|
0
|
|
|
|
|
open my $fh, '>', $cmdfile or croak "Unable to open $cmdfile for writing: $!"; |
|
500
|
0
|
|
|
|
|
|
my $tclcode = << 'CMDEOF'; |
|
501
|
|
|
|
|
|
|
onerror {resume} |
|
502
|
|
|
|
|
|
|
wave add / |
|
503
|
|
|
|
|
|
|
run all |
|
504
|
|
|
|
|
|
|
quit -f |
|
505
|
|
|
|
|
|
|
CMDEOF |
|
506
|
0
|
|
|
|
|
|
print $fh $tclcode; |
|
507
|
0
|
|
|
|
|
|
close $fh; |
|
508
|
0
|
0
|
|
|
|
|
print "Done creating $cmdfile\n" if $self->verbose; |
|
509
|
|
|
|
|
|
|
## will do a chdir into $blib |
|
510
|
0
|
|
|
|
|
|
$self->_exec_fuse($prj, $exe, $topname); |
|
511
|
|
|
|
|
|
|
## will do a chdir into $blib |
|
512
|
0
|
|
|
|
|
|
$self->_exec_simulation($exe, $cmd, $wdb, $log); |
|
513
|
|
|
|
|
|
|
} |
|
514
|
|
|
|
|
|
|
# create .done_simulate |
|
515
|
0
|
|
|
|
|
|
my $ds = File::Spec->catfile($blib, '.done_simulate'); |
|
516
|
0
|
0
|
|
|
|
|
open my $dsf, '>', $ds or carp "Unable to create $ds: $!"; |
|
517
|
0
|
|
|
|
|
|
print $dsf "1\n"; |
|
518
|
0
|
|
|
|
|
|
close $dsf; |
|
519
|
|
|
|
|
|
|
} else { |
|
520
|
0
|
|
|
|
|
|
print "No tests were run since no testbenches were found.\n"; |
|
521
|
|
|
|
|
|
|
} |
|
522
|
|
|
|
|
|
|
} |
|
523
|
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
sub ACTION_view { |
|
525
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
526
|
|
|
|
|
|
|
# manage multiple views. how does one update runtime_params ? hence we just |
|
527
|
|
|
|
|
|
|
# re-run the Build as needed. |
|
528
|
0
|
|
|
|
|
|
$self->ACTION_build(@_); |
|
529
|
0
|
|
|
|
|
|
my $tb_data = $self->testbench; |
|
530
|
0
|
|
0
|
|
|
|
my $simfiles = $self->SUPER::args('sim_files') || [keys %$tb_data]; |
|
531
|
0
|
0
|
|
|
|
|
$simfiles = [$simfiles] unless ref $simfiles eq 'ARRAY'; |
|
532
|
0
|
0
|
|
|
|
|
if (scalar @$simfiles) { |
|
533
|
0
|
0
|
|
|
|
|
if ($self->verbose) { |
|
534
|
0
|
|
|
|
|
|
local $Data::Dumper::Terse = 1; |
|
535
|
0
|
|
|
|
|
|
print "Running views for the following: ", Dumper($simfiles); |
|
536
|
|
|
|
|
|
|
} |
|
537
|
0
|
|
|
|
|
|
foreach my $vf (@$simfiles) { |
|
538
|
0
|
0
|
|
|
|
|
$vf =~ s:\\:/:g if $self->is_windowsish();# convert windows paths out |
|
539
|
0
|
|
|
|
|
|
$vf =~ s:^\./::g; # remove ./ from the beginning |
|
540
|
0
|
0
|
0
|
|
|
|
if (exists $tb_data->{$vf} and defined $tb_data->{$vf}->{wdb}) { |
|
541
|
0
|
|
|
|
|
|
my $wdb = File::Spec->catfile($self->blib, $tb_data->{$vf}->{wdb}); |
|
542
|
0
|
0
|
|
|
|
|
unless (-e $wdb) { |
|
543
|
0
|
|
|
|
|
|
carp "$wdb has not been created. You need to run ./Build simulate first"; |
|
544
|
0
|
|
|
|
|
|
next; |
|
545
|
|
|
|
|
|
|
} |
|
546
|
|
|
|
|
|
|
## we do NOT chdir into the blib directory |
|
547
|
0
|
|
|
|
|
|
$self->_exec_isimgui($wdb); |
|
548
|
0
|
|
|
|
|
|
print "Finished viewing the output of $vf\n"; |
|
549
|
|
|
|
|
|
|
} else { |
|
550
|
0
|
|
|
|
|
|
carp "$vf is not a valid testbench file"; |
|
551
|
|
|
|
|
|
|
} |
|
552
|
|
|
|
|
|
|
} |
|
553
|
|
|
|
|
|
|
} else { |
|
554
|
0
|
|
|
|
|
|
print "No tests were run since no testbenches were found.\n"; |
|
555
|
|
|
|
|
|
|
} |
|
556
|
|
|
|
|
|
|
} |
|
557
|
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
sub ACTION_program { |
|
559
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
560
|
0
|
|
|
|
|
|
my $device = $self->SUPER::args('device'); |
|
561
|
0
|
0
|
|
|
|
|
carp "Guessing which device to use for programming." unless defined $device; |
|
562
|
0
|
0
|
0
|
|
|
|
print "Programming the $device\n" if ($self->verbose and defined $device); |
|
563
|
0
|
|
|
|
|
|
$self->ACTION_build(@_); |
|
564
|
0
|
|
|
|
|
|
return $self->_exec_impact($device); |
|
565
|
|
|
|
|
|
|
} |
|
566
|
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
sub _tcl_functions { |
|
568
|
0
|
|
|
0
|
|
|
return << 'TCLFUNC'; |
|
569
|
|
|
|
|
|
|
proc add_parameter {param value} { |
|
570
|
|
|
|
|
|
|
puts stderr "INFO: Setting $param to $value" |
|
571
|
|
|
|
|
|
|
if {[catch {xilinx::project set $param $value} err]} then { |
|
572
|
|
|
|
|
|
|
puts stderr "WARN: Unable to set $param to $value\n$err" |
|
573
|
|
|
|
|
|
|
return 1 |
|
574
|
|
|
|
|
|
|
} |
|
575
|
|
|
|
|
|
|
return 0 |
|
576
|
|
|
|
|
|
|
} |
|
577
|
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
proc add_parameters {plist} { |
|
579
|
|
|
|
|
|
|
array set params $plist |
|
580
|
|
|
|
|
|
|
foreach idx [lsort [array names params]] { |
|
581
|
|
|
|
|
|
|
set param [lindex $params($idx) 0] |
|
582
|
|
|
|
|
|
|
set value [lindex $params($idx) 1] |
|
583
|
|
|
|
|
|
|
add_parameter $param $value |
|
584
|
|
|
|
|
|
|
} |
|
585
|
|
|
|
|
|
|
return 0 |
|
586
|
|
|
|
|
|
|
} |
|
587
|
|
|
|
|
|
|
# we have a separate function for adding source and testbench |
|
588
|
|
|
|
|
|
|
proc add_source_file {ff} { |
|
589
|
|
|
|
|
|
|
if {[file exists $ff]} then { |
|
590
|
|
|
|
|
|
|
set found [xilinx::search $ff -regexp -type file] |
|
591
|
|
|
|
|
|
|
if {[xilinx::collection sizeof $found] == 0} then { |
|
592
|
|
|
|
|
|
|
puts stderr "INFO: Adding $ff" |
|
593
|
|
|
|
|
|
|
if {[catch {xilinx::xfile add $ff} err]} then { |
|
594
|
|
|
|
|
|
|
puts stderr "ERROR: Unable to add $ff\n$err" |
|
595
|
|
|
|
|
|
|
exit 1 |
|
596
|
|
|
|
|
|
|
} |
|
597
|
|
|
|
|
|
|
} else { |
|
598
|
|
|
|
|
|
|
puts stderr "INFO: $ff already in project" |
|
599
|
|
|
|
|
|
|
} |
|
600
|
|
|
|
|
|
|
} else { |
|
601
|
|
|
|
|
|
|
puts stderr "WARN: $ff does not exist" |
|
602
|
|
|
|
|
|
|
} |
|
603
|
|
|
|
|
|
|
} |
|
604
|
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
proc add_testbench_file {ff} { |
|
606
|
|
|
|
|
|
|
set viewname Simulation |
|
607
|
|
|
|
|
|
|
if {[file exists $ff]} then { |
|
608
|
|
|
|
|
|
|
set found [xilinx::search $ff -regexp -type file] |
|
609
|
|
|
|
|
|
|
if {[xilinx::collection sizeof $found] == 0} then { |
|
610
|
|
|
|
|
|
|
puts stderr "INFO: Adding $ff to $viewname" |
|
611
|
|
|
|
|
|
|
if {[catch {xilinx::xfile add $ff -view $viewname} err]} then { |
|
612
|
|
|
|
|
|
|
puts stderr "ERROR: Unable to add $ff\n$err" |
|
613
|
|
|
|
|
|
|
exit 1 |
|
614
|
|
|
|
|
|
|
} |
|
615
|
|
|
|
|
|
|
} else { |
|
616
|
|
|
|
|
|
|
puts stderr "INFO: $ff already in project" |
|
617
|
|
|
|
|
|
|
} |
|
618
|
|
|
|
|
|
|
} else { |
|
619
|
|
|
|
|
|
|
puts stderr "WARN: $ff does not exist" |
|
620
|
|
|
|
|
|
|
} |
|
621
|
|
|
|
|
|
|
} |
|
622
|
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
proc process_run_task {task} { |
|
624
|
|
|
|
|
|
|
if {[catch {xilinx::process run $task} err]} then { |
|
625
|
|
|
|
|
|
|
puts stderr "ERROR: Unable to run $task\n$err" |
|
626
|
|
|
|
|
|
|
return 1 |
|
627
|
|
|
|
|
|
|
} |
|
628
|
|
|
|
|
|
|
set rc [xilinx::process get $task status] |
|
629
|
|
|
|
|
|
|
puts stderr "INFO: Status of $task: $rc\n" |
|
630
|
|
|
|
|
|
|
if {[string compare $rc "errors"] == 0 || |
|
631
|
|
|
|
|
|
|
[string compare $rc "aborted"] == 0 } then { |
|
632
|
|
|
|
|
|
|
puts stderr "ERROR: Unable to run $task: $rc\n" |
|
633
|
|
|
|
|
|
|
return 1 |
|
634
|
|
|
|
|
|
|
} |
|
635
|
|
|
|
|
|
|
return 0 |
|
636
|
|
|
|
|
|
|
} |
|
637
|
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
proc simulation_create {prj exe topname} { |
|
639
|
|
|
|
|
|
|
if {[catch {exec fuse -incremental $topname -prj $prj -o $exe} err]} then { |
|
640
|
|
|
|
|
|
|
puts stderr "ERROR: Unable to run fuse for $prj\n$err" |
|
641
|
|
|
|
|
|
|
return 1 |
|
642
|
|
|
|
|
|
|
} |
|
643
|
|
|
|
|
|
|
return 0 |
|
644
|
|
|
|
|
|
|
} |
|
645
|
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
proc simulation_run {exe cmd wdb logfile} { |
|
647
|
|
|
|
|
|
|
if {[catch {exec $exe -tclbatch $cmd -wdb $wdb -log $logfile} err]} then { |
|
648
|
|
|
|
|
|
|
puts stderr "ERROR: Unable to run $exe with $cmd\n$err" |
|
649
|
|
|
|
|
|
|
return 1 |
|
650
|
|
|
|
|
|
|
} |
|
651
|
|
|
|
|
|
|
return 0 |
|
652
|
|
|
|
|
|
|
} |
|
653
|
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
proc simulation_view {wdb} { |
|
655
|
|
|
|
|
|
|
if {[catch {exec isimgui -view $wdb} err]} then { |
|
656
|
|
|
|
|
|
|
puts stderr "ERROR: Unable to view $wdb\n$err" |
|
657
|
|
|
|
|
|
|
return 1 |
|
658
|
|
|
|
|
|
|
} |
|
659
|
|
|
|
|
|
|
return 0 |
|
660
|
|
|
|
|
|
|
} |
|
661
|
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
proc program_device {bitfiles ipf cmdfile} { |
|
663
|
|
|
|
|
|
|
set cmdfile program_device.cmd |
|
664
|
|
|
|
|
|
|
if {[catch {set fd [open $cmdfile w]} err]} then { |
|
665
|
|
|
|
|
|
|
puts stderr "ERROR: Unable to open $cmdfile for writing\n$err" |
|
666
|
|
|
|
|
|
|
return 1 |
|
667
|
|
|
|
|
|
|
} |
|
668
|
|
|
|
|
|
|
puts $fd "setLog -file program_device.log" |
|
669
|
|
|
|
|
|
|
puts $fd "setPreference -pref UserLevel:Novice" |
|
670
|
|
|
|
|
|
|
puts $fd "setPreference -pref ConfigOnFailure:Stop" |
|
671
|
|
|
|
|
|
|
puts $fd "setMode -bscan" |
|
672
|
|
|
|
|
|
|
puts $fd "setCable -port auto" |
|
673
|
|
|
|
|
|
|
puts $fd "identify" |
|
674
|
|
|
|
|
|
|
for {set idx 0} {$idx < [llength $bitfiles]} {incr idx} { |
|
675
|
|
|
|
|
|
|
set bitf [lindex $bitfiles $idx] |
|
676
|
|
|
|
|
|
|
set ii [expr $idx + 1] |
|
677
|
|
|
|
|
|
|
# we use assignFile over addDevice since it allows over-writing |
|
678
|
|
|
|
|
|
|
puts $fd "assignFile -p $ii -file \"$bitf\"" |
|
679
|
|
|
|
|
|
|
} |
|
680
|
|
|
|
|
|
|
for {set idx 0} {$idx < [llength $bitfiles]} {incr idx} { |
|
681
|
|
|
|
|
|
|
set ii [expr $idx + 1] |
|
682
|
|
|
|
|
|
|
puts $fd "program -p $ii" |
|
683
|
|
|
|
|
|
|
} |
|
684
|
|
|
|
|
|
|
puts $fd "checkIntegrity" |
|
685
|
|
|
|
|
|
|
puts $fd "saveprojectfile -file \"$ipf\"" |
|
686
|
|
|
|
|
|
|
puts $fd "quit" |
|
687
|
|
|
|
|
|
|
catch {close $fd} |
|
688
|
|
|
|
|
|
|
if {[catch {exec impact -batch "./program_device.cmd"} err]} then { |
|
689
|
|
|
|
|
|
|
#TODO: check log here for errors |
|
690
|
|
|
|
|
|
|
puts stderr "ERROR: Unable to run impact to program the device" |
|
691
|
|
|
|
|
|
|
return 1 |
|
692
|
|
|
|
|
|
|
} |
|
693
|
|
|
|
|
|
|
return 0 |
|
694
|
|
|
|
|
|
|
} |
|
695
|
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
proc cleanup_and_exit {xise bdir errcode} { |
|
697
|
|
|
|
|
|
|
if {[catch {xilinx::project close} err]} then { |
|
698
|
|
|
|
|
|
|
puts stderr "WARN: error closing $xise\n$err" |
|
699
|
|
|
|
|
|
|
exit 1 |
|
700
|
|
|
|
|
|
|
} else { |
|
701
|
|
|
|
|
|
|
puts stderr "INFO: Closed $xise" |
|
702
|
|
|
|
|
|
|
} |
|
703
|
|
|
|
|
|
|
cd $bdir |
|
704
|
|
|
|
|
|
|
exit $errcode |
|
705
|
|
|
|
|
|
|
} |
|
706
|
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
proc open_project {projfile projname} { |
|
708
|
|
|
|
|
|
|
if {[file exists $projfile]} then { |
|
709
|
|
|
|
|
|
|
if {[catch {xilinx::project open $projname} err]} then { |
|
710
|
|
|
|
|
|
|
puts stderr "ERROR: Could not open $projfile for reading\n$err" |
|
711
|
|
|
|
|
|
|
exit 1 |
|
712
|
|
|
|
|
|
|
} |
|
713
|
|
|
|
|
|
|
puts stderr "INFO: Opened $projfile" |
|
714
|
|
|
|
|
|
|
} else { |
|
715
|
|
|
|
|
|
|
if {[catch {xilinx::project new $projname} err]} then { |
|
716
|
|
|
|
|
|
|
puts stderr "ERROR: Unable to create $projfile\n$err" |
|
717
|
|
|
|
|
|
|
exit 1 |
|
718
|
|
|
|
|
|
|
} |
|
719
|
|
|
|
|
|
|
puts stderr "INFO: Created $projfile" |
|
720
|
|
|
|
|
|
|
} |
|
721
|
|
|
|
|
|
|
} |
|
722
|
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
# separate tasks that should not be called together |
|
724
|
|
|
|
|
|
|
proc clean_project {projfile} { |
|
725
|
|
|
|
|
|
|
if {[catch {xilinx::project clean} err]} then { |
|
726
|
|
|
|
|
|
|
puts stderr "WARN: Unable to clean $projfile\n$err" |
|
727
|
|
|
|
|
|
|
} else { |
|
728
|
|
|
|
|
|
|
puts stderr "INFO: cleaned project $projfile" |
|
729
|
|
|
|
|
|
|
} |
|
730
|
|
|
|
|
|
|
} |
|
731
|
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
proc print_usage {appname} { |
|
733
|
|
|
|
|
|
|
puts stderr "$appname \[OPTIONS\]\n" |
|
734
|
|
|
|
|
|
|
puts stderr "OPTIONS are any or all of the following:" |
|
735
|
|
|
|
|
|
|
puts stderr "-setup\t\t\tCreates/Opens the project and adds parameters, files" |
|
736
|
|
|
|
|
|
|
puts stderr "-build\t\t\tBuilds the project and generates bitstream" |
|
737
|
|
|
|
|
|
|
puts stderr "-simulate\t\tSimulates the generated bitstream" |
|
738
|
|
|
|
|
|
|
puts stderr "-view\t\t\tView the simulation output using isimgui" |
|
739
|
|
|
|
|
|
|
puts stderr "-all\t\t\tAlias for '-clean -setup -build -simulate'" |
|
740
|
|
|
|
|
|
|
puts stderr "-clean\t\t\tCleans the project. Has highest precedence" |
|
741
|
|
|
|
|
|
|
puts stderr "-program \[dev\]\t\tProgram the device given" |
|
742
|
|
|
|
|
|
|
exit 1 |
|
743
|
|
|
|
|
|
|
} |
|
744
|
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
proc create_file {ff} { |
|
746
|
|
|
|
|
|
|
if {[catch {set fd [open $ff w]} err]} then { |
|
747
|
|
|
|
|
|
|
puts stderr "ERROR: Unable to open $ff for writing\n$err" |
|
748
|
|
|
|
|
|
|
return 1 |
|
749
|
|
|
|
|
|
|
} |
|
750
|
|
|
|
|
|
|
puts $fd "1" |
|
751
|
|
|
|
|
|
|
catch {close $fd} |
|
752
|
|
|
|
|
|
|
} |
|
753
|
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
TCLFUNC |
|
755
|
|
|
|
|
|
|
} |
|
756
|
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
sub _dump_tcl_code { |
|
758
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
759
|
0
|
|
|
|
|
|
my $projext = $self->proj_ext; |
|
760
|
0
|
|
|
|
|
|
my $projname = $self->proj_name; |
|
761
|
0
|
|
|
|
|
|
my $dir_build = $self->blib; |
|
762
|
0
|
|
|
|
|
|
my $src_files = join(' ', @{$self->source_files}); |
|
|
0
|
|
|
|
|
|
|
|
763
|
0
|
|
|
|
|
|
my $tb_files = join(' ', @{$self->testbench_files}); |
|
|
0
|
|
|
|
|
|
|
|
764
|
0
|
|
|
|
|
|
my $tbsrc_files = join(' ', @{$self->testbenchsrc_files}); |
|
|
0
|
|
|
|
|
|
|
|
765
|
0
|
|
|
|
|
|
my @tbfiles = (); # ordered tb matching |
|
766
|
0
|
|
|
|
|
|
my @prjs = (); |
|
767
|
0
|
|
|
|
|
|
my @exes = (); |
|
768
|
0
|
|
|
|
|
|
my @toplevels = (); |
|
769
|
0
|
|
|
|
|
|
my @srclibs = (); |
|
770
|
0
|
|
|
|
|
|
my @cmds = (); |
|
771
|
0
|
|
|
|
|
|
my @wdbs = (); |
|
772
|
|
|
|
|
|
|
|
|
773
|
0
|
|
|
|
|
|
my $tb_data = $self->testbench; |
|
774
|
0
|
|
|
|
|
|
foreach my $f (keys %$tb_data) { |
|
775
|
0
|
|
|
|
|
|
my $hh = $tb_data->{$f}; |
|
776
|
|
|
|
|
|
|
# we assume these have to be defined |
|
777
|
0
|
|
|
|
|
|
push @tbfiles, $f; |
|
778
|
0
|
|
|
|
|
|
push @prjs, $hh->{prj}; |
|
779
|
0
|
|
|
|
|
|
push @cmds, $hh->{cmd}; |
|
780
|
0
|
|
|
|
|
|
push @wdbs, $hh->{wdb}; |
|
781
|
0
|
|
|
|
|
|
push @exes, $hh->{exe}; |
|
782
|
0
|
|
|
|
|
|
push @toplevels, $hh->{toplevel}; |
|
783
|
0
|
|
|
|
|
|
push @srclibs, $hh->{srclib}; |
|
784
|
|
|
|
|
|
|
} |
|
785
|
0
|
|
|
|
|
|
my $total_files = scalar @prjs + scalar @cmds + scalar @wdbs + scalar @exes |
|
786
|
|
|
|
|
|
|
+ scalar @toplevels + scalar @srclibs; |
|
787
|
0
|
0
|
|
|
|
|
carp "There is a mismatch in the count of internal files" if |
|
788
|
|
|
|
|
|
|
(6 * scalar @prjs) != $total_files; |
|
789
|
0
|
|
|
|
|
|
$total_files /= 6; |
|
790
|
0
|
|
|
|
|
|
my $prj_files = join(' ', @prjs); |
|
791
|
0
|
|
|
|
|
|
my $exe_files = join(' ', @exes); |
|
792
|
0
|
|
|
|
|
|
my $toplevels_ = join(' ', @toplevels); |
|
793
|
0
|
|
|
|
|
|
my $srclibs_ = join(' ', @srclibs); |
|
794
|
0
|
|
|
|
|
|
my $cmd_files = join(' ', @cmds); |
|
795
|
0
|
|
|
|
|
|
my $wdb_files = join(' ', @wdbs); |
|
796
|
0
|
|
|
|
|
|
my %pp = %{$self->proj_params}; |
|
|
0
|
|
|
|
|
|
|
|
797
|
0
|
|
0
|
|
|
|
$pp{family} = $pp{family} || 'spartan3a'; |
|
798
|
0
|
|
0
|
|
|
|
$pp{device} = $pp{device} || 'xc3s700a'; |
|
799
|
0
|
|
0
|
|
|
|
$pp{package} = $pp{package} || 'fg484'; |
|
800
|
0
|
|
0
|
|
|
|
$pp{speed} = $pp{speed} || '-4'; |
|
801
|
0
|
|
0
|
|
|
|
$pp{language} = $pp{language} || 'N/A'; |
|
802
|
0
|
|
0
|
|
|
|
$pp{devboard} = $pp{devboard} || 'None Specified'; |
|
803
|
0
|
|
|
|
|
|
my $vars = << "TCLVARS"; |
|
804
|
|
|
|
|
|
|
# input parameters start here |
|
805
|
|
|
|
|
|
|
set projext {$projext} |
|
806
|
|
|
|
|
|
|
set projname {$projname} |
|
807
|
|
|
|
|
|
|
set dir_build $dir_build |
|
808
|
|
|
|
|
|
|
# Tcl arrays are associative arrays. We need these parameters set in order hence |
|
809
|
|
|
|
|
|
|
# we use integers as keys to the parameters |
|
810
|
|
|
|
|
|
|
# the following can be retrieved by running the command partgen -arch spartan3a |
|
811
|
|
|
|
|
|
|
# this allows the same UCF file used in multiple projects as long as the |
|
812
|
|
|
|
|
|
|
# constraint names stay the same |
|
813
|
|
|
|
|
|
|
array set projparams { |
|
814
|
|
|
|
|
|
|
0 {family $pp{family}} |
|
815
|
|
|
|
|
|
|
1 {device $pp{device}} |
|
816
|
|
|
|
|
|
|
2 {package $pp{package}} |
|
817
|
|
|
|
|
|
|
3 {speed $pp{speed}} |
|
818
|
|
|
|
|
|
|
4 {"Preferred Language" $pp{language}} |
|
819
|
|
|
|
|
|
|
5 {"Evaluation Development Board" "$pp{devboard}"} |
|
820
|
|
|
|
|
|
|
6 {"Allow Unmatched LOC Constraints" true} |
|
821
|
|
|
|
|
|
|
7 {"Write Timing Constraints" true} |
|
822
|
|
|
|
|
|
|
} |
|
823
|
|
|
|
|
|
|
# test bench file names matter ! Refer \$Xilinx/data/projnav/xil_tb_patterns.txt |
|
824
|
|
|
|
|
|
|
# it has to end in _tb/_tf or should be named testbench |
|
825
|
|
|
|
|
|
|
# the constraint file and test bench go together for simulation purposes |
|
826
|
|
|
|
|
|
|
set src_files [list $src_files] |
|
827
|
|
|
|
|
|
|
set tb_files [list $tb_files] |
|
828
|
|
|
|
|
|
|
set tbsrc_files [list $tbsrc_files] |
|
829
|
|
|
|
|
|
|
set prj_files [list $prj_files] |
|
830
|
|
|
|
|
|
|
set exe_files [list $exe_files] |
|
831
|
|
|
|
|
|
|
set toplevels [list $toplevels_] |
|
832
|
|
|
|
|
|
|
set srclibs [list $srclibs_] |
|
833
|
|
|
|
|
|
|
set cmd_files [list $cmd_files] |
|
834
|
|
|
|
|
|
|
set wdb_files [list $wdb_files] |
|
835
|
|
|
|
|
|
|
set tb_count $total_files |
|
836
|
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
TCLVARS |
|
838
|
0
|
|
|
|
|
|
my $functions = $self->_tcl_functions; |
|
839
|
0
|
|
|
|
|
|
my $basecode = << 'TCLBASE'; |
|
840
|
|
|
|
|
|
|
# main code starts here |
|
841
|
|
|
|
|
|
|
# |
|
842
|
|
|
|
|
|
|
set mode_setup 0 |
|
843
|
|
|
|
|
|
|
set mode_build 0 |
|
844
|
|
|
|
|
|
|
set mode_simulate 0 |
|
845
|
|
|
|
|
|
|
set mode_view 0 |
|
846
|
|
|
|
|
|
|
set mode_program 0 |
|
847
|
|
|
|
|
|
|
set mode_clean 0 |
|
848
|
|
|
|
|
|
|
set device_name "" |
|
849
|
|
|
|
|
|
|
|
|
850
|
|
|
|
|
|
|
if { $argc > 0 } then { |
|
851
|
|
|
|
|
|
|
for {set idx 0} {$idx < $argc} {incr idx} { |
|
852
|
|
|
|
|
|
|
set opt [lindex $argv $idx] |
|
853
|
|
|
|
|
|
|
if {$opt == "-setup"} then { |
|
854
|
|
|
|
|
|
|
set mode_setup 1 |
|
855
|
|
|
|
|
|
|
} elseif {$opt == "-build"} then { |
|
856
|
|
|
|
|
|
|
set mode_build 1 |
|
857
|
|
|
|
|
|
|
} elseif {$opt == "-simulate"} then { |
|
858
|
|
|
|
|
|
|
set mode_simulate 1 |
|
859
|
|
|
|
|
|
|
} elseif {$opt == "-view"} then { |
|
860
|
|
|
|
|
|
|
set mode_view 1 |
|
861
|
|
|
|
|
|
|
} elseif {$opt == "-clean"} then { |
|
862
|
|
|
|
|
|
|
set mode_clean 1 |
|
863
|
|
|
|
|
|
|
} elseif {$opt == "-all"} then { |
|
864
|
|
|
|
|
|
|
set mode_clean 1 |
|
865
|
|
|
|
|
|
|
set mode_setup 1 |
|
866
|
|
|
|
|
|
|
set mode_build 1 |
|
867
|
|
|
|
|
|
|
set mode_simulate 1 |
|
868
|
|
|
|
|
|
|
} elseif {$opt == "-program"} then { |
|
869
|
|
|
|
|
|
|
set mode_program 1 |
|
870
|
|
|
|
|
|
|
incr idx |
|
871
|
|
|
|
|
|
|
if {$idx < $argc} then { |
|
872
|
|
|
|
|
|
|
set device_name [lindex $argv $idx] |
|
873
|
|
|
|
|
|
|
} else { |
|
874
|
|
|
|
|
|
|
puts stderr "WARN: device name not given." |
|
875
|
|
|
|
|
|
|
} |
|
876
|
|
|
|
|
|
|
} else { |
|
877
|
|
|
|
|
|
|
print_usage $argv0 |
|
878
|
|
|
|
|
|
|
} |
|
879
|
|
|
|
|
|
|
} |
|
880
|
|
|
|
|
|
|
} else { |
|
881
|
|
|
|
|
|
|
print_usage $argv0 |
|
882
|
|
|
|
|
|
|
} |
|
883
|
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
set projfile $projname$projext |
|
885
|
|
|
|
|
|
|
set basedir [pwd] |
|
886
|
|
|
|
|
|
|
set builddir $basedir/$dir_build |
|
887
|
|
|
|
|
|
|
set srcdir $basedir |
|
888
|
|
|
|
|
|
|
set tbdir $basedir |
|
889
|
|
|
|
|
|
|
catch {exec mkdir $builddir} |
|
890
|
|
|
|
|
|
|
cd $builddir |
|
891
|
|
|
|
|
|
|
puts stderr "INFO: In $builddir" |
|
892
|
|
|
|
|
|
|
# this is necessary after the chdir |
|
893
|
|
|
|
|
|
|
set projipf [pwd]/$projname.ipf |
|
894
|
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
open_project $projfile $projname |
|
896
|
|
|
|
|
|
|
if {$mode_clean == 1} then { |
|
897
|
|
|
|
|
|
|
clean_project $projfile |
|
898
|
|
|
|
|
|
|
file delete -force .done_setup .done_build .done_simulate |
|
899
|
|
|
|
|
|
|
} |
|
900
|
|
|
|
|
|
|
# check if other options need to be set |
|
901
|
|
|
|
|
|
|
if {![file exists .done_simulate] && $mode_view == 1} then { |
|
902
|
|
|
|
|
|
|
puts stderr "INFO: No .done_simulate found in $builddir so running simulate" |
|
903
|
|
|
|
|
|
|
set mode_simulate 1 |
|
904
|
|
|
|
|
|
|
} |
|
905
|
|
|
|
|
|
|
if {![file exists .done_build] && ($mode_simulate == 1 || $mode_view == 1 || $mode_program == 1)} then { |
|
906
|
|
|
|
|
|
|
puts stderr "INFO: No .done_build found $builddir so running build" |
|
907
|
|
|
|
|
|
|
set mode_build 1 |
|
908
|
|
|
|
|
|
|
} |
|
909
|
|
|
|
|
|
|
if {![file exists .done_setup] && $mode_build == 1} then { |
|
910
|
|
|
|
|
|
|
puts stderr "INFO: No .done_setup found in $builddir so running setup" |
|
911
|
|
|
|
|
|
|
set mode_setup 1 |
|
912
|
|
|
|
|
|
|
} |
|
913
|
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
TCLBASE |
|
915
|
|
|
|
|
|
|
|
|
916
|
0
|
|
|
|
|
|
my $single_setup = << 'TCLSETUP0'; |
|
917
|
|
|
|
|
|
|
if {$mode_setup == 1} then { |
|
918
|
|
|
|
|
|
|
# perform setting of the project parameters |
|
919
|
|
|
|
|
|
|
add_parameters [array get projparams] |
|
920
|
|
|
|
|
|
|
foreach fname $src_files { |
|
921
|
|
|
|
|
|
|
set ff $srcdir/$fname |
|
922
|
|
|
|
|
|
|
add_source_file $ff |
|
923
|
|
|
|
|
|
|
} |
|
924
|
|
|
|
|
|
|
foreach fname $tb_files { |
|
925
|
|
|
|
|
|
|
set ff $tbdir/$fname |
|
926
|
|
|
|
|
|
|
add_testbench_file $ff |
|
927
|
|
|
|
|
|
|
} |
|
928
|
|
|
|
|
|
|
foreach fname $tbsrc_files { |
|
929
|
|
|
|
|
|
|
set ff $tbdir/$fname |
|
930
|
|
|
|
|
|
|
add_testbench_file $ff |
|
931
|
|
|
|
|
|
|
} |
|
932
|
|
|
|
|
|
|
add_parameter {iMPACT Project File} $projipf |
|
933
|
|
|
|
|
|
|
TCLSETUP0 |
|
934
|
0
|
|
|
|
|
|
for (my $i = 0; $i < scalar @prjs; ++$i) { |
|
935
|
0
|
|
|
|
|
|
my $tb_prj = $prjs[$i]; |
|
936
|
0
|
|
|
|
|
|
my $tb_lib = $srclibs[$i]; |
|
937
|
0
|
|
|
|
|
|
my $tb_f = $tbfiles[$i]; |
|
938
|
0
|
|
|
|
|
|
$single_setup .= << "TCL_PRJ_ADD1"; |
|
939
|
|
|
|
|
|
|
if {1} then { |
|
940
|
|
|
|
|
|
|
set tb_prj $tb_prj |
|
941
|
|
|
|
|
|
|
set tb_lib $tb_lib |
|
942
|
|
|
|
|
|
|
set tb_idx $i |
|
943
|
|
|
|
|
|
|
set tb_f $tb_f |
|
944
|
|
|
|
|
|
|
TCL_PRJ_ADD1 |
|
945
|
0
|
|
|
|
|
|
$single_setup .= << 'TCL_PRJ_ADD2'; |
|
946
|
|
|
|
|
|
|
# also create the prj file for simulation later |
|
947
|
|
|
|
|
|
|
if {[catch {set fd [open $tb_prj w]} err]} then { |
|
948
|
|
|
|
|
|
|
puts stderr "ERROR: Unable to open $tb_prj for writing\n$err" |
|
949
|
|
|
|
|
|
|
cleanup_and_exit $projfile $basedir 1 |
|
950
|
|
|
|
|
|
|
} |
|
951
|
|
|
|
|
|
|
foreach fname $src_files { |
|
952
|
|
|
|
|
|
|
set ff $srcdir/$fname |
|
953
|
|
|
|
|
|
|
if {[string match *.ucf $fname]} then { |
|
954
|
|
|
|
|
|
|
puts stderr "INFO: Not adding $ff to $tb_prj" |
|
955
|
|
|
|
|
|
|
} elseif {[string match *.vhd $fname]} then { |
|
956
|
|
|
|
|
|
|
puts $fd "vhdl $tb_lib \"$ff\"" |
|
957
|
|
|
|
|
|
|
} elseif {[string match *.vhdl $fname]} then { |
|
958
|
|
|
|
|
|
|
puts $fd "vhdl $tb_lib \"$ff\"" |
|
959
|
|
|
|
|
|
|
} else { |
|
960
|
|
|
|
|
|
|
puts $fd "verilog $tb_lib \"$ff\"" |
|
961
|
|
|
|
|
|
|
} |
|
962
|
|
|
|
|
|
|
} |
|
963
|
|
|
|
|
|
|
foreach fname $tbsrc_files { |
|
964
|
|
|
|
|
|
|
set ff $tbdir/$fname |
|
965
|
|
|
|
|
|
|
if {[string match *.ucf $fname]} then { |
|
966
|
|
|
|
|
|
|
puts stderr "INFO: Not adding $ff to $tb_prj" |
|
967
|
|
|
|
|
|
|
} elseif {[string match *.vhd $fname]} then { |
|
968
|
|
|
|
|
|
|
puts $fd "vhdl $tb_lib \"$ff\"" |
|
969
|
|
|
|
|
|
|
} elseif {[string match *.vhdl $fname]} then { |
|
970
|
|
|
|
|
|
|
puts $fd "vhdl $tb_lib \"$ff\"" |
|
971
|
|
|
|
|
|
|
} else { |
|
972
|
|
|
|
|
|
|
puts $fd "verilog $tb_lib \"$ff\"" |
|
973
|
|
|
|
|
|
|
} |
|
974
|
|
|
|
|
|
|
} |
|
975
|
|
|
|
|
|
|
if {[string match *.vhd $tb_f]} then { |
|
976
|
|
|
|
|
|
|
puts $fd "vhdl $tb_lib \"$tbdir/$tb_f\"" |
|
977
|
|
|
|
|
|
|
} elseif {[string match *.vhdl $tb_f]} then { |
|
978
|
|
|
|
|
|
|
puts $fd "vhdl $tb_lib \"$tbdir/$tb_f\"" |
|
979
|
|
|
|
|
|
|
} else { |
|
980
|
|
|
|
|
|
|
puts $fd "verilog $tb_lib \"$tbdir/$tb_f\"" |
|
981
|
|
|
|
|
|
|
} |
|
982
|
|
|
|
|
|
|
catch {close $fd} |
|
983
|
|
|
|
|
|
|
} |
|
984
|
|
|
|
|
|
|
TCL_PRJ_ADD2 |
|
985
|
|
|
|
|
|
|
} ## end of for loop |
|
986
|
0
|
|
|
|
|
|
$single_setup .= << 'TCLSETUP1'; |
|
987
|
|
|
|
|
|
|
create_file .done_setup |
|
988
|
|
|
|
|
|
|
} |
|
989
|
|
|
|
|
|
|
TCLSETUP1 |
|
990
|
0
|
|
|
|
|
|
my $build_code = << 'TCLBUILD'; |
|
991
|
|
|
|
|
|
|
if {$mode_build == 1} then { |
|
992
|
|
|
|
|
|
|
if {[process_run_task "Check Syntax"]} then { |
|
993
|
|
|
|
|
|
|
cleanup_and_exit $projfile $basedir 1 |
|
994
|
|
|
|
|
|
|
} |
|
995
|
|
|
|
|
|
|
if {[process_run_task "Implement Design"]} then { |
|
996
|
|
|
|
|
|
|
cleanup_and_exit $projfile $basedir 1 |
|
997
|
|
|
|
|
|
|
} |
|
998
|
|
|
|
|
|
|
if {[process_run_task "Generate Programming File"]} then { |
|
999
|
|
|
|
|
|
|
cleanup_and_exit $projfile $basedir 1 |
|
1000
|
|
|
|
|
|
|
} |
|
1001
|
|
|
|
|
|
|
create_file .done_build |
|
1002
|
|
|
|
|
|
|
} |
|
1003
|
|
|
|
|
|
|
TCLBUILD |
|
1004
|
|
|
|
|
|
|
|
|
1005
|
0
|
|
|
|
|
|
my $sim_code = << 'TCLSIM0'; |
|
1006
|
|
|
|
|
|
|
if {$mode_simulate == 1} then { |
|
1007
|
|
|
|
|
|
|
TCLSIM0 |
|
1008
|
0
|
|
|
|
|
|
my $view_code = ''; |
|
1009
|
0
|
|
|
|
|
|
for (my $i = 0; $i < scalar @prjs; ++$i) { |
|
1010
|
0
|
|
|
|
|
|
my $tb_prj = $prjs[$i]; |
|
1011
|
0
|
|
|
|
|
|
my $tb_lib = $srclibs[$i]; |
|
1012
|
0
|
|
|
|
|
|
my $tb_top = $toplevels[$i]; |
|
1013
|
0
|
|
|
|
|
|
my $tb_exe = $exes[$i]; |
|
1014
|
0
|
|
|
|
|
|
my $tb_cmd = $cmds[$i]; |
|
1015
|
0
|
|
|
|
|
|
my $tb_wdb = $wdbs[$i]; |
|
1016
|
0
|
|
|
|
|
|
my $tb_log = $tb_exe . '.log'; |
|
1017
|
0
|
|
|
|
|
|
$tb_log =~ s/\.exe//g; |
|
1018
|
0
|
|
|
|
|
|
$sim_code .= << "TCLSIM1"; |
|
1019
|
|
|
|
|
|
|
if {1} then { |
|
1020
|
|
|
|
|
|
|
set tb_prj $tb_prj |
|
1021
|
|
|
|
|
|
|
set tb_lib $tb_lib |
|
1022
|
|
|
|
|
|
|
set tb_top $tb_top |
|
1023
|
|
|
|
|
|
|
set tb_exe $tb_exe |
|
1024
|
|
|
|
|
|
|
set tb_cmd $tb_cmd |
|
1025
|
|
|
|
|
|
|
set tb_wdb $tb_wdb |
|
1026
|
|
|
|
|
|
|
set tb_idx $i |
|
1027
|
|
|
|
|
|
|
set tb_log $tb_log |
|
1028
|
|
|
|
|
|
|
TCLSIM1 |
|
1029
|
0
|
|
|
|
|
|
$sim_code .= << 'TCLSIM2'; |
|
1030
|
|
|
|
|
|
|
# create the simulation executable |
|
1031
|
|
|
|
|
|
|
set topname $tb_lib.$tb_top |
|
1032
|
|
|
|
|
|
|
if {[simulation_create $tb_prj $tb_exe $topname]} then { |
|
1033
|
|
|
|
|
|
|
cleanup_and_exit $projfile $basedir 1 |
|
1034
|
|
|
|
|
|
|
} |
|
1035
|
|
|
|
|
|
|
# create the simulation command file |
|
1036
|
|
|
|
|
|
|
if {[catch {set fd [open $tb_cmd w]} err]} then { |
|
1037
|
|
|
|
|
|
|
puts stderr "ERROR: Unable to open $tb_cmd for writing\n$err" |
|
1038
|
|
|
|
|
|
|
cleanup_and_exit $projfile $basedir 1 |
|
1039
|
|
|
|
|
|
|
} |
|
1040
|
|
|
|
|
|
|
puts $fd "onerror \{resume\}" |
|
1041
|
|
|
|
|
|
|
puts $fd "wave add /" |
|
1042
|
|
|
|
|
|
|
puts $fd "run all" |
|
1043
|
|
|
|
|
|
|
puts $fd "quit -f" |
|
1044
|
|
|
|
|
|
|
catch {close $fd} |
|
1045
|
|
|
|
|
|
|
set path2exe [pwd]/$tb_exe |
|
1046
|
|
|
|
|
|
|
if {[simulation_run $path2exe $tb_cmd $tb_wdb $tb_log]} then { |
|
1047
|
|
|
|
|
|
|
cleanup_and_exit $projfile $basedir 1 |
|
1048
|
|
|
|
|
|
|
} |
|
1049
|
|
|
|
|
|
|
puts stderr "INFO: simulation($tb_idx) complete" |
|
1050
|
|
|
|
|
|
|
} |
|
1051
|
|
|
|
|
|
|
TCLSIM2 |
|
1052
|
0
|
|
|
|
|
|
$view_code .= << "TCLVIEW0"; |
|
1053
|
|
|
|
|
|
|
if {\$mode_view == 1} then { |
|
1054
|
|
|
|
|
|
|
set tb_wdb $tb_wdb |
|
1055
|
|
|
|
|
|
|
TCLVIEW0 |
|
1056
|
0
|
|
|
|
|
|
$view_code .= << 'TCLVIEW1'; |
|
1057
|
|
|
|
|
|
|
if {[simulation_view $tb_wdb]} then { |
|
1058
|
|
|
|
|
|
|
cleanup_and_exit $projfile $basedir 1 |
|
1059
|
|
|
|
|
|
|
} |
|
1060
|
|
|
|
|
|
|
} |
|
1061
|
|
|
|
|
|
|
TCLVIEW1 |
|
1062
|
|
|
|
|
|
|
} ## end of for loop |
|
1063
|
0
|
|
|
|
|
|
$sim_code .= << 'TCLSIM2'; |
|
1064
|
|
|
|
|
|
|
create_file .done_simulate |
|
1065
|
|
|
|
|
|
|
} |
|
1066
|
|
|
|
|
|
|
TCLSIM2 |
|
1067
|
|
|
|
|
|
|
|
|
1068
|
0
|
|
|
|
|
|
my $prog_code .= << 'TCLPROG'; |
|
1069
|
|
|
|
|
|
|
if {$mode_program == 1} then { |
|
1070
|
|
|
|
|
|
|
puts stderr "INFO: will try to program device $device_name" |
|
1071
|
|
|
|
|
|
|
set ipf [pwd]/$projname.ipf |
|
1072
|
|
|
|
|
|
|
set bit_files [glob -nocomplain -tails -directory $builddir *.bit] |
|
1073
|
|
|
|
|
|
|
set cmdfile program_device.cmd |
|
1074
|
|
|
|
|
|
|
if {[program_device $bit_files $ipf $cmdfile]} then { |
|
1075
|
|
|
|
|
|
|
cleanup_and_exit $projfile $basedir 1 |
|
1076
|
|
|
|
|
|
|
} |
|
1077
|
|
|
|
|
|
|
# we should set the {iMPACT Project File} value |
|
1078
|
|
|
|
|
|
|
add_parameter {iMPACT Project File} $ipf |
|
1079
|
|
|
|
|
|
|
puts stderr "INFO: Done programming device $device_name" |
|
1080
|
|
|
|
|
|
|
} |
|
1081
|
|
|
|
|
|
|
TCLPROG |
|
1082
|
0
|
|
|
|
|
|
return << "TCLCODE"; |
|
1083
|
|
|
|
|
|
|
### -- THIS PROGRAM IS AUTO GENERATED -- DO NOT EDIT -- ### |
|
1084
|
|
|
|
|
|
|
$vars |
|
1085
|
|
|
|
|
|
|
$functions |
|
1086
|
|
|
|
|
|
|
$basecode |
|
1087
|
|
|
|
|
|
|
$single_setup |
|
1088
|
|
|
|
|
|
|
$build_code |
|
1089
|
|
|
|
|
|
|
$sim_code |
|
1090
|
|
|
|
|
|
|
$view_code |
|
1091
|
|
|
|
|
|
|
$prog_code |
|
1092
|
|
|
|
|
|
|
# ok now cleanup and exit with 0 |
|
1093
|
|
|
|
|
|
|
cleanup_and_exit \$projfile \$basedir 0 |
|
1094
|
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
TCLCODE |
|
1096
|
|
|
|
|
|
|
} |
|
1097
|
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
1; |
|
1099
|
|
|
|
|
|
|
__END__ |