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__ |