1 |
34 |
alirezamon |
#! /usr/bin/perl -w
|
2 |
|
|
use Glib qw/TRUE FALSE/;
|
3 |
|
|
use strict;
|
4 |
|
|
use warnings;
|
5 |
|
|
use soc;
|
6 |
|
|
#use ip;
|
7 |
|
|
#use interface;
|
8 |
|
|
#use POSIX 'strtol';
|
9 |
|
|
|
10 |
|
|
use File::Path;
|
11 |
|
|
use File::Find::Rule;
|
12 |
|
|
use File::Copy;
|
13 |
|
|
use File::Copy::Recursive qw(dircopy);
|
14 |
|
|
use Cwd 'abs_path';
|
15 |
|
|
use Verilog::EditFiles;
|
16 |
|
|
|
17 |
|
|
use Gtk2;
|
18 |
|
|
#use Gtk2::Pango;
|
19 |
|
|
|
20 |
|
|
use List::MoreUtils qw( minmax );
|
21 |
|
|
|
22 |
|
|
|
23 |
|
|
|
24 |
|
|
################
|
25 |
|
|
# Comile
|
26 |
|
|
#################
|
27 |
|
|
|
28 |
|
|
|
29 |
|
|
|
30 |
|
|
sub is_capital_sensitive()
|
31 |
|
|
{
|
32 |
|
|
my ($cell_layout, $cell, $tree_model, $iter, $data) = @_;
|
33 |
|
|
my $sensitive = !$tree_model->iter_has_child($iter);
|
34 |
|
|
$cell->set('sensitive', $sensitive);
|
35 |
|
|
}
|
36 |
|
|
|
37 |
|
|
sub gen_combo_model{
|
38 |
|
|
my $ref=shift;
|
39 |
|
|
my %inputs=%{$ref};
|
40 |
|
|
my $store = Gtk2::TreeStore->new('Glib::String');
|
41 |
|
|
for my $i (sort { $a cmp $b} keys %inputs ) {
|
42 |
|
|
my $iter = $store->append(undef);
|
43 |
|
|
|
44 |
|
|
$store->set($iter, 0, $i);
|
45 |
|
|
for my $capital (sort { $a cmp $b} keys %{$inputs{$i}}) {
|
46 |
|
|
my $iter2 = $store->append($iter);
|
47 |
|
|
$store->set($iter2, 0, $capital);
|
48 |
|
|
}
|
49 |
|
|
}
|
50 |
|
|
return $store;
|
51 |
|
|
|
52 |
|
|
}
|
53 |
|
|
|
54 |
|
|
sub gen_tree_combo{
|
55 |
|
|
my $model=shift;
|
56 |
|
|
my $combo = Gtk2::ComboBox->new_with_model($model);
|
57 |
|
|
my $renderer = Gtk2::CellRendererText->new();
|
58 |
|
|
$combo->pack_start($renderer, TRUE);
|
59 |
|
|
$combo->set_attributes($renderer, "text", 0);
|
60 |
|
|
$combo->set_cell_data_func($renderer, \&is_capital_sensitive);
|
61 |
|
|
return $combo;
|
62 |
|
|
|
63 |
|
|
}
|
64 |
|
|
|
65 |
|
|
sub get_range {
|
66 |
|
|
my ($board,$self,$porttype,$assignname,$portrange,$portname) =@_;
|
67 |
|
|
my $box= def_hbox(FALSE,0);
|
68 |
|
|
my @range=$board->board_get_pin_range($porttype,$assignname);
|
69 |
|
|
|
70 |
|
|
|
71 |
|
|
if ($range[0] ne '*undefine*'){
|
72 |
|
|
my $content = join(",", @range);
|
73 |
|
|
my ($min, $max) = minmax @range;
|
74 |
|
|
if (length($portrange)!=0){
|
75 |
|
|
my $range_hsb=gen_combobox_object($self,'compile_pin_range_hsb',$portname,$content,$max,undef,undef);
|
76 |
|
|
$box->pack_start( $range_hsb, FALSE, FALSE, 0);
|
77 |
|
|
$box->pack_start(gen_label_in_center(':'),, FALSE, FALSE, 0);
|
78 |
|
|
}
|
79 |
|
|
|
80 |
|
|
my $range_lsb=gen_combobox_object($self,'compile_pin_range_lsb',$portname,$content,$min,undef,undef);
|
81 |
|
|
$box->pack_start( $range_lsb, FALSE, FALSE, 0);
|
82 |
|
|
|
83 |
|
|
}
|
84 |
|
|
return $box;
|
85 |
|
|
|
86 |
|
|
}
|
87 |
|
|
|
88 |
|
|
|
89 |
|
|
sub read_csv_file{
|
90 |
|
|
my $file=shift;
|
91 |
|
|
open(my $fh, "<$file") || die "Cannot open:$file; $!";
|
92 |
|
|
|
93 |
|
|
my $board = soc->board_new();
|
94 |
|
|
#read header format
|
95 |
|
|
|
96 |
|
|
my $header;
|
97 |
|
|
|
98 |
|
|
while (my $line= <$fh>){
|
99 |
|
|
chomp $line;
|
100 |
|
|
$line=remove_all_white_spaces($line);
|
101 |
|
|
#print "l:$line\n";
|
102 |
|
|
if(length ( $line)!=0){
|
103 |
|
|
if ($line !~ /\#/) {
|
104 |
|
|
$header= $line;
|
105 |
|
|
last;
|
106 |
|
|
}
|
107 |
|
|
|
108 |
|
|
|
109 |
|
|
}
|
110 |
|
|
|
111 |
|
|
}
|
112 |
|
|
|
113 |
|
|
my @headers = split (',',$header);
|
114 |
|
|
my $pin_name_col = get_scolar_pos('To',@headers);
|
115 |
|
|
if(!defined $pin_name_col){
|
116 |
|
|
message_dialog("Error: $file file has an unsupported format!");
|
117 |
|
|
return $board;
|
118 |
|
|
}
|
119 |
|
|
my $direction_col = get_scolar_pos('Direction',@headers);
|
120 |
|
|
|
121 |
|
|
close $fh;
|
122 |
|
|
|
123 |
|
|
#save pins
|
124 |
|
|
open( $fh, "<$file") || die "Cannot open:$file; $!";
|
125 |
|
|
|
126 |
|
|
|
127 |
|
|
while (my $line= <$fh>){
|
128 |
|
|
chomp $line;
|
129 |
|
|
my @fileds = split (',',$line);
|
130 |
|
|
my $to = $fileds[$pin_name_col];
|
131 |
|
|
my $direction = (defined $direction_col )? $fileds[$direction_col] : 'Unknown';
|
132 |
|
|
if(defined $direction && length($to)!=0){
|
133 |
|
|
if ($direction eq 'Input' || $direction eq 'Output' || $direction eq 'Bidir'){
|
134 |
|
|
$board->board_add_pin ($fileds[1],$to);
|
135 |
|
|
}elsif($direction eq 'Unknown'){
|
136 |
|
|
$board->board_add_pin ('Input',$to);
|
137 |
|
|
$board->board_add_pin ('Output',$to);
|
138 |
|
|
$board->board_add_pin ('Bidir',$to);
|
139 |
|
|
|
140 |
|
|
}
|
141 |
|
|
}
|
142 |
|
|
|
143 |
|
|
}
|
144 |
|
|
close $fh;
|
145 |
|
|
return $board;
|
146 |
|
|
}
|
147 |
|
|
|
148 |
|
|
|
149 |
|
|
|
150 |
|
|
|
151 |
|
|
sub gen_top_v{
|
152 |
|
|
my ($self,$board,$name,$top)=@_;
|
153 |
|
|
|
154 |
|
|
my $top_v=get_license_header("Top.v");
|
155 |
|
|
#read port list
|
156 |
|
|
my $vdb=read_verilog_file($top);
|
157 |
|
|
my %port_type=get_ports_type($vdb,"${name}_top");
|
158 |
|
|
my %port_range=get_ports_rang($vdb,"${name}_top");
|
159 |
|
|
|
160 |
|
|
|
161 |
|
|
my $io='';
|
162 |
|
|
my $io_def='';
|
163 |
|
|
my $io_assign='';
|
164 |
|
|
my %board_io;
|
165 |
|
|
my $first=1;
|
166 |
|
|
foreach my $p (sort keys %port_type){
|
167 |
|
|
my $porttype=$port_type{$p};
|
168 |
|
|
my $portrange=$port_range{$p};
|
169 |
|
|
my $assign_type = $self->object_get_attribute('compile_assign_type',$p);
|
170 |
|
|
my $assign_name = $self->object_get_attribute('compile_pin',$p);
|
171 |
|
|
my $range_hsb = $self->object_get_attribute('compile_pin_range_hsb',$p);
|
172 |
|
|
my $range_lsb = $self->object_get_attribute('compile_pin_range_lsb',$p);
|
173 |
|
|
my $assign="\t";
|
174 |
|
|
if (defined $assign_name){
|
175 |
|
|
if($assign_name eq '*VCC'){
|
176 |
|
|
$assign= (length($portrange)!=0)? '{32{1\'b1}}' : '1\'b1';
|
177 |
|
|
} elsif ($assign_name eq '*GND'){
|
178 |
|
|
$assign= (length($portrange)!=0)? '{32{1\'b0}}' : '1\'b0';
|
179 |
|
|
}elsif ($assign_name eq '*NOCONNECT'){
|
180 |
|
|
$assign="\t";
|
181 |
|
|
|
182 |
|
|
}else{
|
183 |
|
|
|
184 |
|
|
$board_io{$assign_name}=$porttype;
|
185 |
|
|
|
186 |
|
|
|
187 |
|
|
my $range = (defined $range_hsb) ? "[$range_hsb : $range_lsb]" :
|
188 |
|
|
(defined $range_lsb) ? "[ $range_lsb]" : " ";
|
189 |
|
|
my $l=(defined $assign_type)?
|
190 |
|
|
($assign_type eq 'Direct') ? '' : '~' : '';
|
191 |
|
|
$assign="$l $assign_name $range";
|
192 |
|
|
|
193 |
|
|
|
194 |
|
|
}
|
195 |
|
|
}
|
196 |
|
|
$io_assign= ($first)? "$io_assign \t .$p($assign)":"$io_assign,\n \t .$p($assign)";
|
197 |
|
|
$first=0;
|
198 |
|
|
}
|
199 |
|
|
$first=1;
|
200 |
|
|
foreach my $p (sort keys %board_io){
|
201 |
|
|
$io=($first)? "\t$p" : "$io,\n\t$p";
|
202 |
|
|
my $dir=$board_io{$p};
|
203 |
|
|
my $range;
|
204 |
|
|
my $type= ($dir eq 'input') ? 'Input' :
|
205 |
|
|
($dir eq 'output')? 'Output' : 'Bidir';
|
206 |
|
|
my @r= $board->board_get_pin_range($type,$p);
|
207 |
|
|
if ($r[0] eq '*undefine*'){
|
208 |
|
|
$range="\t\t\t";
|
209 |
|
|
} else {
|
210 |
|
|
my ($min, $max) = minmax @r;
|
211 |
|
|
$range="\t[$max : $min]\t";
|
212 |
|
|
}
|
213 |
|
|
$io_def = "$io_def \t $dir $range $p;\n";
|
214 |
|
|
$first=0;
|
215 |
|
|
|
216 |
|
|
}
|
217 |
|
|
$top_v="$top_v
|
218 |
|
|
module Top (
|
219 |
|
|
$io
|
220 |
|
|
);
|
221 |
|
|
$io_def
|
222 |
|
|
|
223 |
|
|
${name}_top uut(
|
224 |
|
|
$io_assign
|
225 |
|
|
);
|
226 |
|
|
|
227 |
|
|
|
228 |
|
|
endmodule
|
229 |
|
|
";
|
230 |
|
|
my ($fname,$fpath,$fsuffix) = fileparse("$top",qr"\..[^.]*$");
|
231 |
|
|
my $board_top_file= "$fpath/Top.v";
|
232 |
|
|
save_file($board_top_file,$top_v);
|
233 |
|
|
}
|
234 |
|
|
|
235 |
|
|
|
236 |
|
|
|
237 |
|
|
|
238 |
|
|
|
239 |
|
|
|
240 |
|
|
|
241 |
|
|
|
242 |
|
|
|
243 |
|
|
|
244 |
|
|
sub select_compiler {
|
245 |
|
|
my ($self,$name,$top,$target_dir)=@_;
|
246 |
|
|
my $window = def_popwin_size(40,40,"Step 1: Select Compiler",'percent');
|
247 |
|
|
#get the list of boards located in "boards/*" folder
|
248 |
|
|
my @dirs = grep {-d} glob("./lib/boards/*");
|
249 |
|
|
my ($fpgas,$init);
|
250 |
|
|
foreach my $dir (@dirs) {
|
251 |
|
|
my ($name,$path,$suffix) = fileparse("$dir",qr"\..[^.]*$");
|
252 |
|
|
$init=$name;
|
253 |
|
|
$fpgas= (defined $fpgas)? "$fpgas,$name" : "$name";
|
254 |
|
|
}
|
255 |
|
|
my $table = def_table(2, 2, FALSE);
|
256 |
|
|
my $col=0;
|
257 |
|
|
my $row=0;
|
258 |
|
|
|
259 |
|
|
my $compiler=gen_combobox_object ($self,'compile','type',"QuartusII,Verilator,Modelsim","QuartusII",undef,undef);
|
260 |
|
|
$table->attach(gen_label_in_center("Compiler tool"),$col,$col+1,$row,$row+1,'fill','shrink',2,2);$col++;
|
261 |
|
|
$table->attach($compiler,$col,$col+1,$row,$row+1,'fill','shrink',2,2);$col++;
|
262 |
|
|
$row++;$col=0;
|
263 |
|
|
|
264 |
|
|
|
265 |
|
|
|
266 |
|
|
my $old_board_name=$self->object_get_attribute('compile','board');
|
267 |
|
|
my $old_compiler=$self->object_get_attribute('compile','type');
|
268 |
|
|
my $compiler_options = ($old_compiler eq "QuartusII")? select_board ($self,$name,$top,$target_dir):
|
269 |
|
|
($old_compiler eq "Modelsim")? select_model_path ($self,$name,$top,$target_dir):
|
270 |
|
|
gen_label_in_center(" ");
|
271 |
|
|
$table->attach($compiler_options,$col,$col+2,$row,$row+1,'fill','shrink',2,2); $row++;
|
272 |
|
|
|
273 |
|
|
$col=1;
|
274 |
|
|
my $i;
|
275 |
|
|
for ($i=$row; $i<5; $i++){
|
276 |
|
|
|
277 |
|
|
my $temp=gen_label_in_center(" ");
|
278 |
|
|
$table->attach_defaults ($temp, 0, 1 , $i, $i+1);
|
279 |
|
|
}
|
280 |
|
|
$row=$i;
|
281 |
|
|
|
282 |
|
|
|
283 |
|
|
$window->add ($table);
|
284 |
|
|
$window->show_all();
|
285 |
|
|
my $next=def_image_button('icons/right.png','Next');
|
286 |
|
|
$table->attach($next,$col,$col+1,$row,$row+1,'shrink','shrink',2,2);$col++;
|
287 |
|
|
$next-> signal_connect("clicked" => sub{
|
288 |
|
|
my $compiler_type=$self->object_get_attribute('compile','type');
|
289 |
|
|
if($compiler_type eq "QuartusII"){
|
290 |
|
|
my $new_board_name=$self->object_get_attribute('compile','board');
|
291 |
|
|
if(defined $old_board_name) {
|
292 |
|
|
remove_pin_assignment($self) if ($old_board_name ne $new_board_name);
|
293 |
|
|
my ($fname,$fpath,$fsuffix) = fileparse("$top",qr"\..[^.]*$");
|
294 |
|
|
my $board_top_file= "$fpath/Top.v";
|
295 |
|
|
unlink $board_top_file if ($old_board_name ne $new_board_name);
|
296 |
|
|
|
297 |
|
|
|
298 |
|
|
}
|
299 |
|
|
|
300 |
|
|
get_pin_assignment($self,$name,$top,$target_dir);
|
301 |
|
|
}elsif($compiler_type eq "Modelsim"){
|
302 |
|
|
modelsim_compilation($self,$name,$top,$target_dir);
|
303 |
|
|
|
304 |
|
|
}else{#verilator
|
305 |
|
|
verilator_compilation($self,$name,$top,$target_dir);
|
306 |
|
|
|
307 |
|
|
}
|
308 |
|
|
|
309 |
|
|
$window->destroy;
|
310 |
|
|
|
311 |
|
|
});
|
312 |
|
|
|
313 |
|
|
$compiler->signal_connect("changed" => sub{
|
314 |
|
|
$compiler_options->destroy;
|
315 |
|
|
my $new_board_name=$self->object_get_attribute('compile','type');
|
316 |
|
|
$compiler_options = ($new_board_name eq "QuartusII")? select_board ($self,$name,$top,$target_dir):
|
317 |
|
|
($new_board_name eq "Modelsim")? select_model_path ($self,$name,$top,$target_dir):
|
318 |
|
|
gen_label_in_center(" ");
|
319 |
|
|
$table->attach($compiler_options,0,2,1,2,'fill','shrink',2,2);
|
320 |
|
|
$table->show_all;
|
321 |
|
|
|
322 |
|
|
});
|
323 |
|
|
|
324 |
|
|
}
|
325 |
|
|
|
326 |
|
|
|
327 |
|
|
|
328 |
|
|
|
329 |
|
|
|
330 |
|
|
sub select_board {
|
331 |
|
|
my ($self,$name,$top,$target_dir)=@_;
|
332 |
|
|
|
333 |
|
|
#get the list of boards located in "boards/*" folder
|
334 |
|
|
my @dirs = grep {-d} glob("./lib/boards/*");
|
335 |
|
|
my ($fpgas,$init);
|
336 |
|
|
foreach my $dir (@dirs) {
|
337 |
|
|
my ($name,$path,$suffix) = fileparse("$dir",qr"\..[^.]*$");
|
338 |
|
|
$init=$name;
|
339 |
|
|
$fpgas= (defined $fpgas)? "$fpgas,$name" : "$name";
|
340 |
|
|
}
|
341 |
|
|
my $table = def_table(2, 2, FALSE);
|
342 |
|
|
my $col=0;
|
343 |
|
|
my $row=0;
|
344 |
|
|
|
345 |
|
|
|
346 |
|
|
my $old_board_name=$self->object_get_attribute('compile','board');
|
347 |
|
|
$table->attach(gen_label_help("The list of supported boards are obtained from \"perl_gui/lib/boards/\" path. You can add your boards by adding its required files in aformentioned path. Note that currently only Altera FPGAs are supported. For boards from other vendors, you need to directly use their own compiler and call $name.v file in your top level module.",'Targeted Board:'),$col,$col+1,$row,$row+1,'fill','shrink',2,2);$col++;
|
348 |
|
|
$table->attach(gen_combobox_object ($self,'compile','board',$fpgas,$init,undef,undef),$col,$col+1,$row,$row+1,'fill','shrink',2,2);$row++;
|
349 |
|
|
|
350 |
|
|
my $bin = $self->object_get_attribute('compile','quartus_bin');
|
351 |
|
|
my $Quartus_bin= $ENV{QUARTUS_BIN};
|
352 |
|
|
$col=0;
|
353 |
|
|
$self->object_add_attribute('compile','quartus_bin',$ENV{QUARTUS_BIN}) if (!defined $bin && defined $Quartus_bin);
|
354 |
|
|
$table->attach(gen_label_help("Path to quartus/bin directory. You can set a default path as QUARTUS_BIN envirement variable in ~/.bashrc file.
|
355 |
|
|
e.g: export QUARTUS_BIN=/home/alireza/altera/13.0sp1/quartus/bin",'Quartus bin:'),$col,$col+1,$row,$row+1,'fill','shrink',2,2);$col++;
|
356 |
|
|
$table->attach(get_dir_in_object ($self,'compile','quartus_bin',undef,undef,undef),$col,$col+1,$row,$row+1,'fill','shrink',2,2);$row++;
|
357 |
|
|
|
358 |
|
|
return $table;
|
359 |
|
|
|
360 |
|
|
}
|
361 |
|
|
|
362 |
|
|
sub select_model_path {
|
363 |
|
|
my ($self,$name,$top,$target_dir)=@_;
|
364 |
|
|
|
365 |
|
|
|
366 |
|
|
my $table = def_table(2, 2, FALSE);
|
367 |
|
|
my $col=0;
|
368 |
|
|
my $row=0;
|
369 |
|
|
|
370 |
|
|
|
371 |
|
|
|
372 |
|
|
|
373 |
|
|
my $bin = $self->object_get_attribute('compile','modelsim_bin');
|
374 |
|
|
my $modelsim_bin= $ENV{MODELSIM_BIN};
|
375 |
|
|
$col=0;
|
376 |
|
|
$self->object_add_attribute('compile','modelsim_bin',$modelsim_bin) if (!defined $bin && defined $modelsim_bin);
|
377 |
|
|
$table->attach(gen_label_help("Path to modelsim/bin directory. You can set a default path as MODELSIM_BIN envirement variable in ~/.bashrc file.
|
378 |
|
|
e.g. export MODELSIM_BIN=/home/alireza/altera/modeltech/bin",'Modelsim bin:'),$col,$col+1,$row,$row+1,'fill','shrink',2,2);$col++;
|
379 |
|
|
$table->attach(get_dir_in_object ($self,'compile','modelsim_bin',undef,undef,undef),$col,$col+1,$row,$row+1,'fill','shrink',2,2);$row++;
|
380 |
|
|
|
381 |
|
|
return $table;
|
382 |
|
|
|
383 |
|
|
}
|
384 |
|
|
|
385 |
|
|
|
386 |
|
|
sub remove_pin_assignment{
|
387 |
|
|
my $self=shift;
|
388 |
|
|
$self->object_remove_attribute('compile_pin_pos');
|
389 |
|
|
$self->object_remove_attribute('compile_pin');
|
390 |
|
|
$self->object_remove_attribute('compile_assign_type');
|
391 |
|
|
$self->object_remove_attribute('compile_pin_range_hsb');
|
392 |
|
|
$self->object_remove_attribute('compile_pin_range_lsb');
|
393 |
|
|
}
|
394 |
|
|
|
395 |
|
|
|
396 |
|
|
sub get_pin_assignment{
|
397 |
|
|
my ($self,$name,$top,$target_dir)=@_;
|
398 |
|
|
my $window = def_popwin_size(80,80,"Step 2: Pin Assignment",'percent');
|
399 |
|
|
|
400 |
|
|
my $table = def_table(2, 2, FALSE);
|
401 |
|
|
my $scrolled_win = new Gtk2::ScrolledWindow (undef, undef);
|
402 |
|
|
$scrolled_win->set_policy( "automatic", "automatic" );
|
403 |
|
|
$scrolled_win->add_with_viewport($table);
|
404 |
|
|
|
405 |
|
|
|
406 |
|
|
my $mtable = def_table(10, 10, FALSE);
|
407 |
|
|
|
408 |
|
|
my $next=def_image_button('icons/right.png','Next');
|
409 |
|
|
my $back=def_image_button('icons/left.png','Previous');
|
410 |
|
|
|
411 |
|
|
|
412 |
|
|
$mtable->attach_defaults($scrolled_win,0,10,0,9);
|
413 |
|
|
$mtable->attach($back,2,3,9,10,'shrink','shrink',2,2);
|
414 |
|
|
$mtable->attach($next,8,9,9,10,'shrink','shrink',2,2);
|
415 |
|
|
|
416 |
|
|
|
417 |
|
|
|
418 |
|
|
|
419 |
|
|
|
420 |
|
|
#get boards pin list
|
421 |
|
|
my $board_name=$self->object_get_attribute('compile','board');
|
422 |
|
|
my @csv_file = glob("./lib/boards/$board_name/*.csv");
|
423 |
|
|
if(!defined $csv_file[0]){
|
424 |
|
|
message_dialog("Error: ./lib/boards/$board_name folder does not contain the csv file.!");
|
425 |
|
|
$window->destroy;
|
426 |
|
|
}
|
427 |
|
|
my $board=read_csv_file($csv_file[0]);
|
428 |
|
|
|
429 |
|
|
# Write object file
|
430 |
|
|
#open(FILE, ">lib/soc/tttttttt") || die "Can not open: $!";
|
431 |
|
|
#print FILE Data::Dumper->Dump([\%$board],['board']);
|
432 |
|
|
#close(FILE) || die "Error closing file: $!";
|
433 |
|
|
|
434 |
|
|
my @dirs = ('Input', 'Bidir', 'Output');
|
435 |
|
|
my %models;
|
436 |
|
|
foreach my $p (@dirs){
|
437 |
|
|
my %pins=$board->board_get_pin($p);
|
438 |
|
|
$models{$p}=gen_combo_model(\%pins);
|
439 |
|
|
|
440 |
|
|
}
|
441 |
|
|
|
442 |
|
|
my $row=0;
|
443 |
|
|
my $col=0;
|
444 |
|
|
my @lables= ('Port Direction','Port Range ','Port name ','Assigment Type','Board Port name ','Board Port Range');
|
445 |
|
|
foreach my $p (@lables){
|
446 |
|
|
my $l=gen_label_in_left($p);
|
447 |
|
|
$l->set_markup("<b> $p </b>");
|
448 |
|
|
$table->attach ($l, $col,$col+1, $row, $row+1,'fill','shrink',2,2);
|
449 |
|
|
$col++
|
450 |
|
|
}
|
451 |
|
|
$row++;
|
452 |
|
|
|
453 |
|
|
|
454 |
|
|
#read port list
|
455 |
|
|
my $vdb=read_verilog_file($top);
|
456 |
|
|
my %port_type=get_ports_type($vdb,"${name}_top");
|
457 |
|
|
my %port_range=get_ports_rang($vdb,"${name}_top");
|
458 |
|
|
my %param = $vdb->get_modules_parameters("${name}_top");
|
459 |
|
|
|
460 |
|
|
foreach my $p (sort keys %port_type){
|
461 |
|
|
my $porttype=$port_type{$p};
|
462 |
|
|
my $portrange=$port_range{$p};
|
463 |
|
|
|
464 |
|
|
if (length($portrange)!=0){
|
465 |
|
|
#replace parameter with their values
|
466 |
|
|
my @a= split (/\b/,$portrange);
|
467 |
|
|
foreach my $l (@a){
|
468 |
|
|
my $value=$param{$l};
|
469 |
|
|
if(defined $value){
|
470 |
|
|
chomp $value;
|
471 |
|
|
($portrange=$portrange)=~ s/\b$l\b/$value/g if(defined $param{$l});
|
472 |
|
|
}
|
473 |
|
|
}
|
474 |
|
|
$portrange = "[ $portrange ]" ;
|
475 |
|
|
}
|
476 |
|
|
|
477 |
|
|
my $label1= gen_label_in_left(" $porttype");
|
478 |
|
|
my $label2= gen_label_in_left(" $portrange");
|
479 |
|
|
my $label3= gen_label_in_left(" $p");
|
480 |
|
|
|
481 |
|
|
$table->attach($label1, 0,1, $row, $row+1,'fill','shrink',2,2);
|
482 |
|
|
$table->attach($label2, 1,2, $row, $row+1,'fill','shrink',2,2);
|
483 |
|
|
$table->attach($label3, 2,3, $row, $row+1,'fill','shrink',2,2);
|
484 |
|
|
|
485 |
|
|
my $assign_type= "Direct,Negate(~)";
|
486 |
|
|
if ($porttype eq 'input') {
|
487 |
|
|
my $assign_combo=gen_combobox_object($self,'compile_assign_type',$p,$assign_type,'Direct',undef,undef);
|
488 |
|
|
$table->attach( $assign_combo, 3,4, $row, $row+1,'fill','shrink',2,2);
|
489 |
|
|
}
|
490 |
|
|
|
491 |
|
|
my $type= ($porttype eq 'input') ? 'Input' :
|
492 |
|
|
($porttype eq 'output')? 'Output' : 'Bidir';
|
493 |
|
|
|
494 |
|
|
my $combo= gen_tree_combo($models{$type});
|
495 |
|
|
my $saved=$self->object_get_attribute('compile_pin_pos',$p);
|
496 |
|
|
my $box;
|
497 |
|
|
my $loc=$row;
|
498 |
|
|
if(defined $saved) {
|
499 |
|
|
my @indices=@{$saved};
|
500 |
|
|
my $path = Gtk2::TreePath->new_from_indices(@indices);
|
501 |
|
|
my $iter = $models{$type}->get_iter($path);
|
502 |
|
|
undef $path;
|
503 |
|
|
$combo->set_active_iter($iter);
|
504 |
|
|
$box->destroy if(defined $box);
|
505 |
|
|
my $text=$self->object_get_attribute('compile_pin',$p);
|
506 |
|
|
$box=get_range ($board,$self,$type,$text,$portrange,$p);
|
507 |
|
|
$table->attach($box, 5,6, $loc, $loc+1,'fill','shrink',2,2);
|
508 |
|
|
}
|
509 |
|
|
|
510 |
|
|
|
511 |
|
|
|
512 |
|
|
|
513 |
|
|
$combo->signal_connect("changed" => sub{
|
514 |
|
|
|
515 |
|
|
#get and saved new value
|
516 |
|
|
my $treeiter= $combo->get_active_iter();
|
517 |
|
|
my $text = $models{$type}->get_value($treeiter, 0);
|
518 |
|
|
$self->object_add_attribute('compile_pin',$p,$text);
|
519 |
|
|
#get and saved value position in model
|
520 |
|
|
my $treepath = $models{$type}->get_path ($treeiter);
|
521 |
|
|
my @indices= $treepath->get_indices();
|
522 |
|
|
$self->object_add_attribute('compile_pin_pos',$p,\@indices);
|
523 |
|
|
#update borad port range
|
524 |
|
|
$box->destroy if(defined $box);
|
525 |
|
|
$box=get_range ($board,$self,$type,$text,$portrange,$p);
|
526 |
|
|
$table->attach($box, 5,6, $loc, $loc+1,'fill','shrink',2,2);
|
527 |
|
|
$table->show_all;
|
528 |
|
|
|
529 |
|
|
});
|
530 |
|
|
|
531 |
|
|
$table->attach($combo, 4,5, $row, $row+1,'fill','shrink',2,2);
|
532 |
|
|
|
533 |
|
|
|
534 |
|
|
|
535 |
|
|
|
536 |
|
|
|
537 |
|
|
|
538 |
|
|
|
539 |
|
|
$row++;
|
540 |
|
|
|
541 |
|
|
}
|
542 |
|
|
$next-> signal_connect("clicked" => sub{
|
543 |
|
|
|
544 |
|
|
$window->destroy;
|
545 |
|
|
quartus_compilation($self,$board,$name,$top,$target_dir);
|
546 |
|
|
|
547 |
|
|
});
|
548 |
|
|
$back-> signal_connect("clicked" => sub{
|
549 |
|
|
|
550 |
|
|
$window->destroy;
|
551 |
|
|
select_compiler($self,$name,$top,$target_dir);
|
552 |
|
|
|
553 |
|
|
});
|
554 |
|
|
|
555 |
|
|
|
556 |
|
|
$window->add ($mtable);
|
557 |
|
|
$window->show_all();
|
558 |
|
|
}
|
559 |
|
|
|
560 |
|
|
|
561 |
|
|
|
562 |
|
|
|
563 |
|
|
|
564 |
|
|
sub quartus_compilation{
|
565 |
|
|
my ($self,$board,$name,$top,$target_dir)=@_;
|
566 |
|
|
my $run=def_image_button('icons/run.png','run');
|
567 |
|
|
my $back=def_image_button('icons/left.png','Previous');
|
568 |
|
|
my $regen=def_image_button('icons/refresh.png','Regenerate Top.v');
|
569 |
|
|
|
570 |
|
|
|
571 |
|
|
my ($fname,$fpath,$fsuffix) = fileparse("$top",qr"\..[^.]*$");
|
572 |
|
|
my $board_top_file ="${fpath}Top.v";
|
573 |
|
|
unless (-e $board_top_file ){
|
574 |
|
|
gen_top_v($self,$board,$name,$top) ;
|
575 |
|
|
}
|
576 |
|
|
|
577 |
|
|
my ($app,$table,$tview,$window) = software_main($fpath,'Top.v');
|
578 |
|
|
$table->attach($back,1,2,1,2,'shrink','shrink',2,2);
|
579 |
|
|
$table->attach($regen,4,5,1,2,'shrink','shrink',2,2);
|
580 |
|
|
$table->attach ($run,9, 10, 1,2,'shrink','shrink',0,0);
|
581 |
|
|
|
582 |
|
|
|
583 |
|
|
$regen-> signal_connect("clicked" => sub{
|
584 |
|
|
my $dialog = Gtk2::MessageDialog->new (my $window,
|
585 |
|
|
'destroy-with-parent',
|
586 |
|
|
'question', # message type
|
587 |
|
|
'yes-no', # which set of buttons?
|
588 |
|
|
"Are you sure you want to regenaret the Top.v file? Note that any changes you have made will be lost");
|
589 |
|
|
my $response = $dialog->run;
|
590 |
|
|
if ($response eq 'yes') {
|
591 |
|
|
gen_top_v($self,$board,$name,$top);
|
592 |
|
|
$app->load_source("$board_top_file");
|
593 |
|
|
}
|
594 |
|
|
$dialog->destroy;
|
595 |
|
|
|
596 |
|
|
});
|
597 |
|
|
|
598 |
|
|
|
599 |
|
|
|
600 |
|
|
$back-> signal_connect("clicked" => sub{
|
601 |
|
|
|
602 |
|
|
$window->destroy;
|
603 |
|
|
get_pin_assignment($self,$name,$top,$target_dir);
|
604 |
|
|
|
605 |
|
|
});
|
606 |
|
|
|
607 |
|
|
|
608 |
|
|
#compile
|
609 |
|
|
$run-> signal_connect("clicked" => sub{
|
610 |
|
|
set_gui_status($self,'save_project',1);
|
611 |
|
|
$app->do_save();
|
612 |
|
|
my $error = 0;
|
613 |
|
|
add_info(\$tview,"CREATE: start creating Quartus project in $target_dir\n");
|
614 |
|
|
|
615 |
|
|
#get list of source file
|
616 |
|
|
add_info(\$tview," Read the list of all source files $target_dir/src_verilog\n");
|
617 |
|
|
my @files = File::Find::Rule->file()
|
618 |
|
|
->name( '*.v','*.V','*.sv' )
|
619 |
|
|
->in( "$target_dir/src_verilog" );
|
620 |
|
|
|
621 |
|
|
#make sure source files have key word 'module'
|
622 |
|
|
my @sources;
|
623 |
|
|
foreach my $p (@files){
|
624 |
|
|
push (@sources,$p) if(check_file_has_string($p,'module'));
|
625 |
|
|
}
|
626 |
|
|
my $files = join ("\n",@sources);
|
627 |
|
|
add_info(\$tview,"$files\n");
|
628 |
|
|
|
629 |
|
|
#creat project qsf file
|
630 |
|
|
my $qsf_file="$target_dir/${name}.qsf";
|
631 |
|
|
save_file ($qsf_file,"# Generated using ProNoC\n");
|
632 |
|
|
|
633 |
|
|
#append global assignets to qsf file
|
634 |
|
|
my $board_name=$self->object_get_attribute('compile','board');
|
635 |
|
|
my @qsfs = glob("./lib/boards/$board_name/*.qsf");
|
636 |
|
|
if(!defined $qsfs[0]){
|
637 |
|
|
message_dialog("Error: ./lib/boards/$board_name folder does not contain the qsf file.!");
|
638 |
|
|
$window->destroy;
|
639 |
|
|
}
|
640 |
|
|
|
641 |
|
|
|
642 |
|
|
my $assignment_file = $qsfs[0];
|
643 |
|
|
|
644 |
|
|
if(-f $assignment_file){
|
645 |
|
|
merg_files ($assignment_file,$qsf_file);
|
646 |
|
|
}
|
647 |
|
|
|
648 |
|
|
|
649 |
|
|
#add the list of source fils to qsf file
|
650 |
|
|
my $s="\n\n\n set_global_assignment -name TOP_LEVEL_ENTITY Top\n";
|
651 |
|
|
foreach my $p (@sources){
|
652 |
|
|
my ($name,$path,$suffix) = fileparse("$p",qr"\..[^.]*$");
|
653 |
|
|
$s="$s set_global_assignment -name VERILOG_FILE $p\n" if ($suffix eq ".v");
|
654 |
|
|
$s="$s set_global_assignment -name SYSTEMVERILOG_FILE $p\n" if ($suffix eq ".sv");
|
655 |
|
|
|
656 |
|
|
}
|
657 |
|
|
append_text_to_file($qsf_file,$s);
|
658 |
|
|
add_info(\$tview,"\n Qsf file has been created\n");
|
659 |
|
|
|
660 |
|
|
#start compilation
|
661 |
|
|
my $Quartus_bin= $self->object_get_attribute('compile','quartus_bin');;
|
662 |
|
|
add_info(\$tview, "Start Quartus compilation.....\n");
|
663 |
|
|
my @compilation_command =(
|
664 |
|
|
"cd \"$target_dir/\" \n xterm -e sh -c '$Quartus_bin/quartus_map --64bit $name --read_settings_files=on; echo \$? > status' ",
|
665 |
|
|
"cd \"$target_dir/\" \n xterm -e sh -c '$Quartus_bin/quartus_fit --64bit $name --read_settings_files=on; echo \$? > status' ",
|
666 |
|
|
"cd \"$target_dir/\" \n xterm -e sh -c '$Quartus_bin/quartus_asm --64bit $name --read_settings_files=on; echo \$? > status' ",
|
667 |
|
|
"cd \"$target_dir/\" \n xterm -e sh -c '$Quartus_bin/quartus_sta --64bit $name;echo \$? > status' ");
|
668 |
|
|
|
669 |
|
|
foreach my $cmd (@compilation_command){
|
670 |
|
|
add_info(\$tview,"$cmd\n");
|
671 |
|
|
unlink "$target_dir/status";
|
672 |
|
|
my ($stdout,$exit)=run_cmd_in_back_ground_get_stdout( $cmd);
|
673 |
|
|
open(my $fh, "<$target_dir/status") || die "Can not open: $!";
|
674 |
|
|
read($fh,my $status,1);
|
675 |
|
|
close($fh);
|
676 |
|
|
if("$status" != "0"){
|
677 |
|
|
($stdout,$exit)=run_cmd_in_back_ground_get_stdout("cd \"$target_dir/output_files/\" \n grep -h \"Error (\" *");
|
678 |
|
|
add_colored_info(\$tview,"$stdout\n Quartus compilation failed !\n",'red');
|
679 |
|
|
$error=1;
|
680 |
|
|
last;
|
681 |
|
|
}
|
682 |
|
|
}
|
683 |
|
|
add_colored_info(\$tview,"Quartus compilation is done successfully in $target_dir!\n", 'blue') if($error==0);
|
684 |
|
|
|
685 |
|
|
|
686 |
|
|
});
|
687 |
|
|
|
688 |
|
|
|
689 |
|
|
|
690 |
|
|
|
691 |
|
|
|
692 |
|
|
|
693 |
|
|
|
694 |
|
|
|
695 |
|
|
}
|
696 |
|
|
|
697 |
|
|
|
698 |
|
|
|
699 |
|
|
|
700 |
|
|
|
701 |
|
|
|
702 |
|
|
sub modelsim_compilation{
|
703 |
|
|
my ($self,$name,$top,$target_dir)=@_;
|
704 |
|
|
#my $window = def_popwin_size(80,80,"Step 2: Compile",'percent');
|
705 |
|
|
|
706 |
|
|
|
707 |
|
|
my $run=def_image_button('icons/run.png','run');
|
708 |
|
|
my $back=def_image_button('icons/left.png','Previous');
|
709 |
|
|
my $regen=def_image_button('icons/refresh.png','Regenerate testbench.v');
|
710 |
|
|
#create testbench.v
|
711 |
|
|
gen_modelsim_soc_testbench ($self,$name,$top,$target_dir) if ((-f "$target_dir/src_verilog/testbench.v")==0);
|
712 |
|
|
|
713 |
|
|
|
714 |
|
|
|
715 |
|
|
my ($app,$table,$tview,$window) = software_main("$target_dir/src_verilog",'testbench.v');
|
716 |
|
|
$table->attach($back,1,2,1,2,'shrink','shrink',2,2);
|
717 |
|
|
$table->attach($regen,4,5,1,2,'shrink','shrink',2,2);
|
718 |
|
|
$table->attach ($run,9, 10, 1,2,'shrink','shrink',0,0);
|
719 |
|
|
|
720 |
|
|
|
721 |
|
|
|
722 |
|
|
$regen-> signal_connect("clicked" => sub{
|
723 |
|
|
my $dialog = Gtk2::MessageDialog->new (my $window,
|
724 |
|
|
'destroy-with-parent',
|
725 |
|
|
'question', # message type
|
726 |
|
|
'yes-no', # which set of buttons?
|
727 |
|
|
"Are you sure you want to regenaret the testbench.v file? Note that any changes you have made will be lost");
|
728 |
|
|
my $response = $dialog->run;
|
729 |
|
|
if ($response eq 'yes') {
|
730 |
|
|
gen_modelsim_soc_testbench ($self,$name,$top,$target_dir);
|
731 |
|
|
$app->load_source("$target_dir/src_verilog/testbench.v");
|
732 |
|
|
}
|
733 |
|
|
$dialog->destroy;
|
734 |
|
|
|
735 |
|
|
});
|
736 |
|
|
|
737 |
|
|
|
738 |
|
|
|
739 |
|
|
|
740 |
|
|
|
741 |
|
|
|
742 |
|
|
$back-> signal_connect("clicked" => sub{
|
743 |
|
|
|
744 |
|
|
$window->destroy;
|
745 |
|
|
select_compiler($self,$name,$top,$target_dir);
|
746 |
|
|
|
747 |
|
|
});
|
748 |
|
|
|
749 |
|
|
|
750 |
|
|
#creat modelsim dir
|
751 |
|
|
add_info(\$tview,"creat Modelsim dir in $target_dir\n");
|
752 |
|
|
my $model="$target_dir/Modelsim";
|
753 |
|
|
rmtree("$model");
|
754 |
|
|
mkpath("$model/rtl_work",1,01777);
|
755 |
|
|
|
756 |
|
|
#create modelsim.tcl file
|
757 |
|
|
my $tcl="#!/usr/bin/tclsh
|
758 |
|
|
|
759 |
|
|
|
760 |
|
|
transcript on
|
761 |
|
|
if {[file exists rtl_work]} {
|
762 |
|
|
vdel -lib rtl_work -all
|
763 |
|
|
}
|
764 |
|
|
vlib rtl_work
|
765 |
|
|
vmap work rtl_work
|
766 |
|
|
";
|
767 |
|
|
|
768 |
|
|
#Get the list of all verilog files in src_verilog folder
|
769 |
|
|
add_info(\$tview,"Get the list of all verilog files in src_verilog folder\n");
|
770 |
|
|
my @files = File::Find::Rule->file()
|
771 |
|
|
->name( '*.v','*.V','*.sv' )
|
772 |
|
|
->in( "$target_dir/src_verilog" );
|
773 |
|
|
#make sure source files have key word 'module'
|
774 |
|
|
my @sources;
|
775 |
|
|
foreach my $p (@files){
|
776 |
|
|
my ($name,$path,$suffix) = fileparse("$p",qr"\..[^.]*$");
|
777 |
|
|
if(check_file_has_string($p,'module')){
|
778 |
|
|
if ($suffix eq ".sv"){$tcl=$tcl."vlog -sv -work work +incdir+$path \{$p\}\n";}
|
779 |
|
|
else {$tcl=$tcl."vlog -vlog01compat -work work +incdir+$path \{$p\}\n";}
|
780 |
|
|
}
|
781 |
|
|
}
|
782 |
|
|
|
783 |
|
|
$tcl="$tcl
|
784 |
|
|
vsim -t 1ps -L rtl_work -L work -voptargs=\"+acc\" testbench
|
785 |
|
|
|
786 |
|
|
add wave *
|
787 |
|
|
view structure
|
788 |
|
|
view signals
|
789 |
|
|
run -all
|
790 |
|
|
";
|
791 |
|
|
|
792 |
|
|
save_file ("$model/run.tcl",$tcl);
|
793 |
|
|
$run -> signal_connect("clicked" => sub{
|
794 |
|
|
set_gui_status($self,'save_project',1);
|
795 |
|
|
$app->do_save();
|
796 |
|
|
my $modelsim_bin= $self->object_get_attribute('compile','modelsim_bin');
|
797 |
|
|
my $cmd="cd $target_dir; $modelsim_bin/vsim -do $model/run.tcl";
|
798 |
|
|
my ($stdout,$exit,$stderr)=run_cmd_in_back_ground_get_stdout($cmd);
|
799 |
|
|
if(length $stderr>1){
|
800 |
|
|
add_info(\$tview,"$stderr\n");
|
801 |
|
|
}else {
|
802 |
|
|
add_info(\$tview,"$stdout\n");
|
803 |
|
|
}
|
804 |
|
|
|
805 |
|
|
});
|
806 |
|
|
|
807 |
|
|
#$window->show_all();
|
808 |
|
|
}
|
809 |
|
|
|
810 |
|
|
|
811 |
|
|
|
812 |
|
|
|
813 |
|
|
sub verilator_compilation {
|
814 |
|
|
my ($self,$name,$top,$target_dir)=@_;
|
815 |
|
|
my $window = def_popwin_size(80,80,"Step 2: Compile",'percent');
|
816 |
|
|
my $mtable = def_table(10, 10, FALSE);
|
817 |
|
|
my ($outbox,$outtext)= create_text();
|
818 |
|
|
add_colored_tag($outtext,'red');
|
819 |
|
|
add_colored_tag($outtext,'blue');
|
820 |
|
|
my $next=def_image_button('icons/run.png','Next');
|
821 |
|
|
my $back=def_image_button('icons/left.png','Previous');
|
822 |
|
|
|
823 |
|
|
|
824 |
|
|
$mtable->attach_defaults ($outbox ,0, 10, 4,9);
|
825 |
|
|
$mtable->attach($back,2,3,9,10,'shrink','shrink',2,2);
|
826 |
|
|
$mtable->attach($next,8,9,9,10,'shrink','shrink',2,2);
|
827 |
|
|
|
828 |
|
|
|
829 |
|
|
|
830 |
|
|
$back-> signal_connect("clicked" => sub{
|
831 |
|
|
|
832 |
|
|
$window->destroy;
|
833 |
|
|
select_compiler($self,$name,$top,$target_dir);
|
834 |
|
|
|
835 |
|
|
});
|
836 |
|
|
$next-> signal_connect("clicked" => sub{
|
837 |
|
|
|
838 |
|
|
$window->destroy;
|
839 |
|
|
verilator_testbench($self,$name,$top,$target_dir);
|
840 |
|
|
|
841 |
|
|
});
|
842 |
|
|
|
843 |
|
|
#creat verilator dir
|
844 |
|
|
add_info(\$outtext,"creat verilator dir in $target_dir\n");
|
845 |
|
|
my $verilator="$target_dir/verilator";
|
846 |
|
|
rmtree("$verilator/rtl_work");
|
847 |
|
|
rmtree("$verilator/processed_rtl");
|
848 |
|
|
mkpath("$verilator/rtl_work/",1,01777);
|
849 |
|
|
mkpath("$verilator/processed_rtl/",1,01777);
|
850 |
|
|
|
851 |
|
|
|
852 |
|
|
#copy all verilog files in rtl_work folder
|
853 |
|
|
add_info(\$outtext,"Copy all verilog files in rtl_work folder\n");
|
854 |
|
|
my @files = File::Find::Rule->file()
|
855 |
|
|
->name( '*.v','*.V','*.sv' )
|
856 |
|
|
->in( "$target_dir/src_verilog" );
|
857 |
|
|
foreach my $file (@files) {
|
858 |
|
|
copy($file,"$verilator/rtl_work/");
|
859 |
|
|
}
|
860 |
|
|
|
861 |
|
|
#"split all verilog modules in separate files"
|
862 |
|
|
add_info(\$outtext,"split all verilog modules in separate files\n");
|
863 |
|
|
my $split = Verilog::EditFiles->new
|
864 |
|
|
(outdir => "$verilator/processed_rtl",
|
865 |
|
|
translate_synthesis => 0,
|
866 |
|
|
celldefine => 0,
|
867 |
|
|
);
|
868 |
|
|
$split->read_and_split(glob("$verilator/rtl_work/*.v"));
|
869 |
|
|
$split->read_and_split(glob("$verilator/rtl_work/*.sv"));
|
870 |
|
|
$split->write_files();
|
871 |
|
|
|
872 |
|
|
#run verilator
|
873 |
|
|
#my $cmd= "cd \"$verilator/processed_rtl\" \n xterm -e sh -c ' verilator --cc $name.v --profile-cfuncs --prefix \"Vtop\" -O3 -CFLAGS -O3'";
|
874 |
|
|
my $cmd= "cd \"$verilator/processed_rtl\" \n verilator --cc $name.v --profile-cfuncs --prefix \"Vtop\" -O3 -CFLAGS -O3";
|
875 |
|
|
add_info(\$outtext,"$cmd\n");
|
876 |
|
|
my ($stdout,$exit,$stderr)=run_cmd_in_back_ground_get_stdout($cmd);
|
877 |
|
|
if(length $stderr>1){
|
878 |
|
|
add_info(\$outtext,"$stderr\n");
|
879 |
|
|
}else {
|
880 |
|
|
add_info(\$outtext,"$stdout\n");
|
881 |
|
|
}
|
882 |
|
|
|
883 |
|
|
#check if verilator model has been generated
|
884 |
|
|
if (-f "$verilator/processed_rtl/obj_dir/Vtop.cpp"){
|
885 |
|
|
add_colored_info(\$outtext,"Veriator model has been generated successfully!",'blue');
|
886 |
|
|
}else {
|
887 |
|
|
add_colored_info(\$outtext,"Verilator compilation failed!\n","red");
|
888 |
|
|
$next->destroy();
|
889 |
|
|
}
|
890 |
|
|
|
891 |
|
|
|
892 |
|
|
|
893 |
|
|
|
894 |
|
|
$window->add ($mtable);
|
895 |
|
|
$window->show_all();
|
896 |
|
|
|
897 |
|
|
|
898 |
|
|
|
899 |
|
|
}
|
900 |
|
|
|
901 |
|
|
sub gen_verilator_soc_testbench {
|
902 |
|
|
my ($self,$name,$top,$target_dir)=@_;
|
903 |
|
|
my $verilator="$target_dir/verilator";
|
904 |
|
|
my $dir="$verilator/";
|
905 |
|
|
my $soc_top= $self->soc_get_top ();
|
906 |
|
|
my @intfcs=$soc_top->top_get_intfc_list();
|
907 |
|
|
my %PP;
|
908 |
|
|
my $top_port_info="IO type\t port_size\t port_name\n";
|
909 |
|
|
foreach my $intfc (@intfcs){
|
910 |
|
|
my $key= ( $intfc eq 'plug:clk[0]')? 'clk' :
|
911 |
|
|
( $intfc eq 'plug:reset[0]')? 'reset':
|
912 |
|
|
( $intfc eq 'plug:enable[0]')? 'en' : 'other';
|
913 |
|
|
my $key1="${key}1";
|
914 |
|
|
my $key0="${key}0";
|
915 |
|
|
|
916 |
|
|
my @ports=$soc_top->top_get_intfc_ports_list($intfc);
|
917 |
|
|
foreach my $p (@ports){
|
918 |
|
|
my($inst,$range,$type,$intfc_name,$intfc_port)= $soc_top->top_get_port($p);
|
919 |
|
|
$PP{$key1}= (defined $PP{$key1})? "$PP{$key1} top->$p=1;\n" : "top->$p=1;\n";
|
920 |
|
|
$PP{$key0}= (defined $PP{$key0})? "$PP{$key0} top->$p=0;\n" : "top->$p=0;\n";
|
921 |
|
|
$top_port_info="$top_port_info $type $range top->$p \n";
|
922 |
|
|
}
|
923 |
|
|
|
924 |
|
|
|
925 |
|
|
}
|
926 |
|
|
my $main_c=get_license_header("testbench.cpp");
|
927 |
|
|
$main_c="$main_c
|
928 |
|
|
#include <stdlib.h>
|
929 |
|
|
#include <stdio.h>
|
930 |
|
|
#include <unistd.h>
|
931 |
|
|
#include <string.h>
|
932 |
|
|
#include <verilated.h> // Defines common routines
|
933 |
|
|
#include \"Vtop.h\" // From Verilating \"$name.v\" file
|
934 |
|
|
|
935 |
|
|
Vtop *top;
|
936 |
|
|
/*
|
937 |
|
|
$top_port_info
|
938 |
|
|
*/
|
939 |
|
|
|
940 |
|
|
int reset,clk;
|
941 |
|
|
unsigned int main_time = 0; // Current simulation time
|
942 |
|
|
|
943 |
|
|
int main(int argc, char** argv) {
|
944 |
|
|
Verilated::commandArgs(argc, argv); // Remember args
|
945 |
|
|
top = new Vtop;
|
946 |
|
|
|
947 |
|
|
/********************
|
948 |
|
|
* initialize input
|
949 |
|
|
*********************/
|
950 |
|
|
|
951 |
|
|
$PP{reset1}
|
952 |
|
|
$PP{en1}
|
953 |
|
|
main_time=0;
|
954 |
|
|
printf(\"Start Simulation\\n\");
|
955 |
|
|
while (!Verilated::gotFinish()) {
|
956 |
|
|
|
957 |
|
|
if (main_time >= 10 ) {
|
958 |
|
|
$PP{reset0}
|
959 |
|
|
}
|
960 |
|
|
|
961 |
|
|
|
962 |
|
|
if ((main_time & 1) == 0) {
|
963 |
|
|
$PP{clk1} // Toggle clock
|
964 |
|
|
// you can change the inputs and read the outputs here in case they are captured at posedge of clock
|
965 |
|
|
|
966 |
|
|
|
967 |
|
|
|
968 |
|
|
}//if
|
969 |
|
|
else
|
970 |
|
|
{
|
971 |
|
|
$PP{clk0}
|
972 |
|
|
|
973 |
|
|
|
974 |
|
|
|
975 |
|
|
}//else
|
976 |
|
|
|
977 |
|
|
|
978 |
|
|
main_time ++;
|
979 |
|
|
top->eval();
|
980 |
|
|
}
|
981 |
|
|
top->final();
|
982 |
|
|
}
|
983 |
|
|
|
984 |
|
|
double sc_time_stamp () { // Called by \$time in Verilog
|
985 |
|
|
return main_time;
|
986 |
|
|
}
|
987 |
|
|
";
|
988 |
|
|
save_file("$dir/testbench.cpp",$main_c);
|
989 |
|
|
|
990 |
|
|
|
991 |
|
|
|
992 |
|
|
}
|
993 |
|
|
|
994 |
|
|
|
995 |
|
|
sub gen_modelsim_soc_testbench {
|
996 |
|
|
my ($self,$name,$top,$target_dir)=@_;
|
997 |
|
|
my $dir="$target_dir/src_verilog";
|
998 |
|
|
my $soc_top= $self->object_get_attribute('top_ip',undef);
|
999 |
|
|
my @intfcs=$soc_top->top_get_intfc_list();
|
1000 |
|
|
my %PP;
|
1001 |
|
|
my $top_port_def="// ${name}.v IO definition \n";
|
1002 |
|
|
my $pin_assign;
|
1003 |
|
|
my $rst_inputs='';
|
1004 |
|
|
|
1005 |
|
|
#read port list
|
1006 |
|
|
my $vdb=read_verilog_file($top);
|
1007 |
|
|
my %param = $vdb->get_modules_parameters("${name}_top");
|
1008 |
|
|
|
1009 |
|
|
|
1010 |
|
|
|
1011 |
|
|
|
1012 |
|
|
|
1013 |
|
|
|
1014 |
|
|
foreach my $intfc (@intfcs){
|
1015 |
|
|
my $key= ( $intfc eq 'plug:clk[0]')? 'clk' :
|
1016 |
|
|
( $intfc eq 'plug:reset[0]')? 'reset':
|
1017 |
|
|
( $intfc eq 'plug:enable[0]')? 'en' : 'other';
|
1018 |
|
|
my $key1="${key}1";
|
1019 |
|
|
my $key0="${key}0";
|
1020 |
|
|
|
1021 |
|
|
my @ports=$soc_top->top_get_intfc_ports_list($intfc);
|
1022 |
|
|
my $f=1;
|
1023 |
|
|
foreach my $p (@ports){
|
1024 |
|
|
my($inst,$range,$type,$intfc_name,$intfc_port)= $soc_top->top_get_port($p);
|
1025 |
|
|
|
1026 |
|
|
$PP{$key1}= (defined $PP{$key1})? "$PP{$key1} $p=1;\n" : "$p=1;\n";
|
1027 |
|
|
$PP{$key0}= (defined $PP{$key0})? "$PP{$key0} $p=0;\n" : "$p=0;\n";
|
1028 |
|
|
|
1029 |
|
|
|
1030 |
|
|
if (length($range)!=0){
|
1031 |
|
|
#replace parameter with their values
|
1032 |
|
|
my @a= split (/\b/,$range);
|
1033 |
|
|
foreach my $l (@a){
|
1034 |
|
|
my $value=$param{$l};
|
1035 |
|
|
if(defined $value){
|
1036 |
|
|
chomp $value;
|
1037 |
|
|
($range=$range)=~ s/\b$l\b/$value/g if(defined $param{$l});
|
1038 |
|
|
}
|
1039 |
|
|
}
|
1040 |
|
|
$range = "[ $range ]" ;
|
1041 |
|
|
}
|
1042 |
|
|
|
1043 |
|
|
|
1044 |
|
|
|
1045 |
|
|
if($type eq 'input'){
|
1046 |
|
|
$top_port_def="$top_port_def reg $range $p;\n"
|
1047 |
|
|
}else{
|
1048 |
|
|
$top_port_def="$top_port_def wire $range $p;\n"
|
1049 |
|
|
}
|
1050 |
|
|
$pin_assign=(defined $pin_assign)? "$pin_assign,\n\t\t.$p($p)": "\t\t.$p($p)";
|
1051 |
|
|
$rst_inputs= "$rst_inputs $p=0;\n" if ($key eq 'other' && $type eq 'input' );
|
1052 |
|
|
}
|
1053 |
|
|
|
1054 |
|
|
|
1055 |
|
|
}
|
1056 |
|
|
|
1057 |
|
|
my $test_v= get_license_header("testbench.v");
|
1058 |
|
|
|
1059 |
|
|
$test_v ="$test_v
|
1060 |
|
|
|
1061 |
|
|
`timescale 1ns/1ps
|
1062 |
|
|
|
1063 |
|
|
module testbench;
|
1064 |
|
|
|
1065 |
|
|
$top_port_def
|
1066 |
|
|
|
1067 |
|
|
|
1068 |
|
|
$name uut (
|
1069 |
|
|
$pin_assign
|
1070 |
|
|
);
|
1071 |
|
|
|
1072 |
|
|
//clock defination
|
1073 |
|
|
initial begin
|
1074 |
|
|
forever begin
|
1075 |
|
|
#5 $PP{clk0}
|
1076 |
|
|
#5 $PP{clk1}
|
1077 |
|
|
end
|
1078 |
|
|
end
|
1079 |
|
|
|
1080 |
|
|
|
1081 |
|
|
|
1082 |
|
|
initial begin
|
1083 |
|
|
// reset $name module at the start up
|
1084 |
|
|
$PP{reset1}
|
1085 |
|
|
$PP{en1}
|
1086 |
|
|
$rst_inputs
|
1087 |
|
|
// deasert the reset after 200 ns
|
1088 |
|
|
#200
|
1089 |
|
|
$PP{reset0}
|
1090 |
|
|
|
1091 |
|
|
// write your testbench here
|
1092 |
|
|
|
1093 |
|
|
|
1094 |
|
|
|
1095 |
|
|
|
1096 |
|
|
end
|
1097 |
|
|
|
1098 |
|
|
endmodule
|
1099 |
|
|
";
|
1100 |
|
|
save_file("$dir/testbench.v",$test_v);
|
1101 |
|
|
|
1102 |
|
|
|
1103 |
|
|
|
1104 |
|
|
}
|
1105 |
|
|
|
1106 |
|
|
sub verilator_testbench{
|
1107 |
|
|
my ($self,$name,$top,$target_dir)=@_;
|
1108 |
|
|
my $verilator="$target_dir/verilator";
|
1109 |
|
|
my $dir="$verilator";
|
1110 |
|
|
gen_verilator_soc_testbench (@_) if((-f "$dir/testbench.cpp")==0);
|
1111 |
|
|
#copy makefile
|
1112 |
|
|
copy("../script/verilator_soc_make", "$verilator/processed_rtl/obj_dir/Makefile");
|
1113 |
|
|
|
1114 |
|
|
|
1115 |
|
|
my ($app,$table,$tview,$window) = software_main($dir,'testbench.cpp');
|
1116 |
|
|
|
1117 |
|
|
|
1118 |
|
|
my $make = def_image_button('icons/gen.png','Compile');
|
1119 |
|
|
my $regen=def_image_button('icons/refresh.png','Regenerate Testbench.cpp');
|
1120 |
|
|
my $run = def_image_button('icons/run.png','Run');
|
1121 |
|
|
my $back=def_image_button('icons/left.png','Previous');
|
1122 |
|
|
|
1123 |
|
|
$table->attach ($back,1,2,1,2,'shrink','shrink',0,0);
|
1124 |
|
|
$table->attach ($regen,3,4,1,2,'shrink','shrink',0,0);
|
1125 |
|
|
$table->attach ($make,7, 8, 1,2,'shrink','shrink',0,0);
|
1126 |
|
|
$table->attach ($run,9, 10, 1,2,'shrink','shrink',0,0);
|
1127 |
|
|
|
1128 |
|
|
$back-> signal_connect("clicked" => sub{
|
1129 |
|
|
|
1130 |
|
|
$window->destroy;
|
1131 |
|
|
verilator_compilation($self,$name,$top,$target_dir);
|
1132 |
|
|
|
1133 |
|
|
});
|
1134 |
|
|
|
1135 |
|
|
$regen-> signal_connect("clicked" => sub{
|
1136 |
|
|
my $dialog = Gtk2::MessageDialog->new (my $window,
|
1137 |
|
|
'destroy-with-parent',
|
1138 |
|
|
'question', # message type
|
1139 |
|
|
'yes-no', # which set of buttons?
|
1140 |
|
|
"Are you sure you want to regenaret the testbench.cpp file? Note that any changes you have made will be lost");
|
1141 |
|
|
my $response = $dialog->run;
|
1142 |
|
|
if ($response eq 'yes') {
|
1143 |
|
|
gen_verilator_soc_testbench ($self,$name,$top,$target_dir);
|
1144 |
|
|
$app->load_source("$dir/testbench.cpp");
|
1145 |
|
|
}
|
1146 |
|
|
$dialog->destroy;
|
1147 |
|
|
|
1148 |
|
|
});
|
1149 |
|
|
|
1150 |
|
|
|
1151 |
|
|
$make -> signal_connect("clicked" => sub{
|
1152 |
|
|
$app->do_save();
|
1153 |
|
|
copy("$dir/testbench.cpp", "$verilator/processed_rtl/obj_dir/testbench.cpp");
|
1154 |
|
|
run_make_file("$verilator/processed_rtl/obj_dir/",$tview);
|
1155 |
|
|
|
1156 |
|
|
});
|
1157 |
|
|
|
1158 |
|
|
$run -> signal_connect("clicked" => sub{
|
1159 |
|
|
my $bin="$verilator/processed_rtl/obj_dir/testbench";
|
1160 |
|
|
if (-f $bin){
|
1161 |
|
|
my $cmd= "cd \"$verilator/processed_rtl/obj_dir/\" \n xterm -e sh -c $bin";
|
1162 |
|
|
add_info(\$tview,"$cmd\n");
|
1163 |
|
|
my ($stdout,$exit,$stderr)=run_cmd_in_back_ground_get_stdout($cmd);
|
1164 |
|
|
if(length $stderr>1){
|
1165 |
|
|
add_colored_info(\$tview,"$stderr\n",'red');
|
1166 |
|
|
}else {
|
1167 |
|
|
add_info(\$tview,"$stdout\n");
|
1168 |
|
|
}
|
1169 |
|
|
|
1170 |
|
|
}else{
|
1171 |
|
|
add_colored_info(\$tview,"Cannot find $bin executable binary file! make sure you have compiled the testbench successfully\n", 'red')
|
1172 |
|
|
}
|
1173 |
|
|
|
1174 |
|
|
});
|
1175 |
|
|
|
1176 |
|
|
|
1177 |
|
|
}
|
1178 |
|
|
|
1179 |
|
|
|
1180 |
|
|
1;
|