OpenCores
URL https://opencores.org/ocsvn/an-fpga-implementation-of-low-latency-noc-based-mpsoc/an-fpga-implementation-of-low-latency-noc-based-mpsoc/trunk
#!/usr/bin/perl -w use constant::boolean; use strict; use warnings; use FindBin; use lib $FindBin::Bin; use soc; use File::Path; use File::Find::Rule; use File::Copy; use File::Copy::Recursive qw(dircopy); use Cwd 'abs_path'; use Verilog::EditFiles; use List::MoreUtils qw( minmax ); ################ # Compile ################# sub is_capital_sensitive() { my ($cell_layout, $cell, $tree_model, $iter, $data) = @_; my $sensitive = !$tree_model->iter_has_child($iter); $cell->set('sensitive', $sensitive); } sub get_range { my ($board,$self,$porttype,$assignname,$portrange,$portname) =@_; my $box= def_hbox(FALSE,0); my @range=$board->board_get_pin_range($porttype,$assignname); if ($range[0] ne '*undefine*'){ my $content = join(",", @range); my ($min, $max) = minmax @range; if (length($portrange)!=0){ my $range_hsb=gen_combobox_object($self,'compile_pin_range_hsb',$portname,$content,$max,undef,undef); $box->pack_start( $range_hsb, FALSE, FALSE, 0); $box->pack_start(gen_label_in_center(':'),, FALSE, FALSE, 0); } my $range_lsb=gen_combobox_object($self,'compile_pin_range_lsb',$portname,$content,$min,undef,undef); $box->pack_start( $range_lsb, FALSE, FALSE, 0); } return $box; } sub read_top_v_file{ my $top_v=shift; my $board = soc->board_new(); my $vdb=read_verilog_file($top_v); my @modules=sort $vdb->get_modules($top_v); my %Ptypes=get_ports_type($vdb,$modules[0]); my %Pranges=get_ports_rang($vdb,$modules[0]); foreach my $p (sort keys %Ptypes){ my $Ptype=$Ptypes{$p}; my $Prange=$Pranges{$p}; my $type=($Ptype eq "input")? "Input" : ($Ptype eq "output")? 'Output' : 'Bidir'; if ( $Prange ne ''){ my @r=split(":",$Prange); my $a=($r[0]<$r[1])? $r[0] : $r[1]; my $b=($r[0]<$r[1])? $r[1] : $r[0]; for (my $i=$a; $i<=$b; $i++){ $board->board_add_pin ($type,"$p\[$i\]"); } } else {$board->board_add_pin ($type,$p);} } return $board; } sub gen_top_v{ my ($self,$board,$name,$top)=@_; my $top_v=get_license_header("Top.v"); #read port list my $vdb=read_verilog_file($top); my %port_type=get_ports_type($vdb,"${name}_top"); my %port_range=get_ports_rang($vdb,"${name}_top"); my $io=''; my $io_def=''; my $io_assign=''; my %board_io; my $first=1; foreach my $p (sort keys %port_type){ my $porttype=$port_type{$p}; my $portrange=$port_range{$p}; my $assign_type = $self->object_get_attribute('compile_assign_type',$p); my $assign_name = $self->object_get_attribute('compile_pin',$p); my $range_hsb = $self->object_get_attribute('compile_pin_range_hsb',$p); my $range_lsb = $self->object_get_attribute('compile_pin_range_lsb',$p); my $assign="\t"; if (defined $assign_name){ if($assign_name eq '*VCC'){ $assign= (length($portrange)!=0)? '{32{1\'b1}}' : '1\'b1'; } elsif ($assign_name eq '*GND'){ $assign= (length($portrange)!=0)? '{32{1\'b0}}' : '1\'b0'; }elsif ($assign_name eq '*NOCONNECT'){ $assign="\t"; }else{ $board_io{$assign_name}=$porttype; my $range = (defined $range_hsb) ? "[$range_hsb : $range_lsb]" : (defined $range_lsb) ? "[ $range_lsb]" : " "; my $l=(defined $assign_type)? ($assign_type eq 'Direct') ? '' : '~' : ''; $assign="$l $assign_name $range"; } } $io_assign= ($first)? "$io_assign \t .$p($assign)":"$io_assign,\n \t .$p($assign)"; $first=0; } $first=1; foreach my $p (sort keys %board_io){ $io=($first)? "\t$p" : "$io,\n\t$p"; my $dir=$board_io{$p}; my $range; my $type= ($dir eq 'input') ? 'Input' : ($dir eq 'output')? 'Output' : 'Bidir'; my @r= $board->board_get_pin_range($type,$p); if ($r[0] eq '*undefine*'){ $range="\t\t\t"; } else { my ($min, $max) = minmax @r; $range="\t[$max : $min]\t"; } $io_def = "$io_def \t $dir $range $p;\n"; $first=0; } $top_v="$top_v module Top ( $io ); $io_def ${name}_top uut( $io_assign ); endmodule "; my ($fname,$fpath,$fsuffix) = fileparse("$top",qr"\..[^.]*$"); my $board_top_file= "$fpath/Top.v"; save_file($board_top_file,$top_v); } sub select_compiler { my ($self,$name,$top,$target_dir,$end_func)=@_; my $window = def_popwin_size(40,40,"Step 1: Select Compiler",'percent'); my $table = def_table(2, 2, FALSE); my $col=0; my $row=0; my $compilers=$self->object_get_attribute('compile','compilers');#"QuartusII,Vivado,Verilator,Modelsim" my $compiler=gen_combobox_object ($self,'compile','type',$compilers,"QuartusII",undef,undef); $table->attach(gen_label_in_center("Compiler tool"),$col,$col+1,$row,$row+1,'fill','shrink',2,2);$col++; $table->attach($compiler,$col,$col+1,$row,$row+1,'fill','shrink',2,2);$col++; $row++;$col=0; my $old_board_name=$self->object_get_attribute('compile','board'); my $old_compiler=$self->object_get_attribute('compile','type'); my $vendor= ($old_compiler eq "QuartusII")? 'Altera' : 'Xilinx'; #get the list of boards located in "boards/*" folder my @dirs = grep {-d} glob("../boards/$vendor/*"); my ($fpgas,$init); foreach my $dir (@dirs) { my ($name,$path,$suffix) = fileparse("$dir",qr"\..[^.]*$"); $init=$name; $fpgas= (defined $fpgas)? "$fpgas,$name" : "$name"; } my $compiler_options = ($old_compiler eq "QuartusII")? select_board ($self,$name,$top,$target_dir,$vendor): ($old_compiler eq "Vivado" )? select_board ($self,$name,$top,$target_dir,$vendor): ($old_compiler eq "Modelsim" )? select_model_path ($self,$name,$top,$target_dir): ($old_compiler eq "Verilator")? select_parallel_process_num ($self,$name,$top,$target_dir): gen_label_in_center(" "); $table->attach($compiler_options,$col,$col+2,$row,$row+1,'fill','shrink',2,2); $row++; $col=1; my $i; for ($i=$row; $i<5; $i++){ my $temp=gen_label_in_center(" "); $table->attach_defaults ($temp, 0, 1 , $i, $i+1); } $row=$i; $window->add ($table); $window->show_all(); my $next=def_image_button('icons/right.png','_Next',FALSE,1); $table->attach($next,$col,$col+1,$row,$row+1,'shrink','shrink',2,2);$col++; $next-> signal_connect("clicked" => sub{ my $compiler_type=$self->object_get_attribute('compile','type'); if($compiler_type eq "QuartusII" || $compiler_type eq "Vivado"){ $vendor= ($compiler_type eq "QuartusII")? 'Altera' : 'Xilinx'; my $new_board_name=$self->object_get_attribute('compile','board'); if(defined $old_board_name) { if ($old_board_name ne $new_board_name){ remove_pin_assignment($self); my ($fname,$fpath,$fsuffix) = fileparse("$top",qr"\..[^.]*$"); #delete jtag_intfc.sh file unlink "${fpath}../sw/jtag_intfc.sh"; #program_device.sh file unlink "${fpath}../program_device.sh"; } my ($fname,$fpath,$fsuffix) = fileparse("$top",qr"\..[^.]*$"); my $board_top_file= "$fpath/Top.v"; unlink $board_top_file if ($old_board_name ne $new_board_name); } if($new_board_name eq "Add New Board") {add_new_fpga_board($self,$name,$top,$target_dir,$end_func,$vendor);} else {get_pin_assignment($self,$name,$top,$target_dir,$end_func,$vendor);} } elsif($compiler_type eq "Modelsim"){ modelsim_compilation($self,$name,$top,$target_dir,$vendor); }else{#verilator verilator_compilation_win($self,$name,$top,$target_dir,$vendor); } $window->destroy; }); $compiler->signal_connect("changed" => sub{ $compiler_options->destroy; my $new_board_name=$self->object_get_attribute('compile','type'); $compiler_options = ($new_board_name eq "QuartusII")? select_board ($self,$name,$top,$target_dir,"Altera"): ($new_board_name eq "Vivado")? select_board ($self,$name,$top,$target_dir,"Xilinx"): ($new_board_name eq "Modelsim")? select_model_path ($self,$name,$top,$target_dir): ($new_board_name eq "Verilator")? select_parallel_process_num ($self,$name,$top,$target_dir): gen_label_in_center(" "); $table->attach($compiler_options,0,2,1,2,'fill','shrink',2,2); $table->show_all; }); } sub select_board { my ($self,$name,$top,$target_dir,$vendor)=@_; #get the list of boards located in "boards/*" folder my @dirs = grep {-d} glob("../boards/$vendor/*"); my ($fpgas,$init); $fpgas="Add New Board"; foreach my $dir (@dirs) { my ($name,$path,$suffix) = fileparse("$dir",qr"\..[^.]*$"); $fpgas= (defined $fpgas)? "$fpgas,$name" : "$name"; $init="$name"; } my $table = def_table(2, 2, FALSE); my $col=0; my $row=0; my $compiler = ($vendor eq "Altera")? 'quartus' : 'vivado'; my $bin_name = "$compiler bin"; my $env = ($vendor eq "Altera")? "QUARTUS_BIN" : "VIVADO_BIN"; my $Fpga_bin= $ENV{$env}; my $old_board_name=$self->object_get_attribute('compile','board'); $table->attach(gen_label_help("The list of supported boards are obtained from \"mpsoc/boards/$vendor\" path. You can add your boards by adding its required files in aformentioned path. Note that currently Altera and Xilinx FPGAs are supported.",'Targeted Board:'),$col,$col+1,$row,$row+1,'fill','shrink',2,2);$col++; $table->attach(gen_combobox_object ($self,'compile','board',$fpgas,$init,undef,undef),$col,$col+1,$row,$row+1,'fill','shrink',2,2);$row++; my $bin = $self->object_get_attribute('compile',$bin_name); $col=0; $self->object_add_attribute('compile',$bin_name,$Fpga_bin) if (!defined $bin && defined $Fpga_bin); $table->attach(gen_label_help("Path to $vendor/bin directory. You can set a default path as $env environment variable in ~/.bashrc file. e.g: export $env=/home/alireza/$compiler/bin","$env:"),$col,$col+1,$row,$row+1,'fill','shrink',2,2);$col++; $table->attach(get_dir_in_object ($self,'compile',$bin_name,undef,undef,undef),$col,$col+1,$row,$row+1,'fill','shrink',2,2);$row++; return $table; } sub select_model_path { my ($self,$name,$top,$target_dir)=@_; my $table = def_table(2, 2, FALSE); my $col=0; my $row=0; my $bin = $self->object_get_attribute('compile','modelsim_bin'); my $modelsim_bin= $ENV{MODELSIM_BIN}; $col=0; $self->object_add_attribute('compile','modelsim_bin',$modelsim_bin) if (!defined $bin && defined $modelsim_bin); $table->attach(gen_label_help("Path to modelsim/bin directory. You can set a default path as MODELSIM_BIN environment variable in ~/.bashrc file. e.g. export MODELSIM_BIN=/home/alireza/altera/modeltech/bin",'Modelsim bin:'),$col,$col+1,$row,$row+1,'fill','shrink',2,2);$col++; $table->attach(get_dir_in_object ($self,'compile','modelsim_bin',undef,undef,undef),$col,$col+1,$row,$row+1,'fill','shrink',2,2);$row++; return $table; } sub select_parallel_process_num { my ($self,$name,$top,$target_dir)=@_; my $table = def_table(2, 2, FALSE); my $col=0; my $row=0; #get total number of processor in the system my $cmd = "nproc\n"; my $cpu_num=4; my ($stdout,$exit,$stderr)=run_cmd_in_back_ground_get_stdout($cmd); if(length $stderr>1){ #nproc command has failed. set default 4 paralel processor }else { my ($number ) = $stdout =~ /(\d+)/; if (defined $number ){ $cpu_num =$number if ($number > 0 ); } } ($row,$col)= add_param_widget ($self,"Paralle run:" , "cpu_num", 1, 'Spin-button', "1,$cpu_num,1","specify the number of processors the Verilator can use at once to run parallel compilations/simulations", $table,$row,$col,1, 'compile', undef,undef,'vertical'); return $table; } sub select_parallel_thread_num { my ($self,$name,$top,$target_dir)=@_; my $table = def_table(2, 2, FALSE); my $col=0; my $row=0; #get total number of processor in the system my $cmd = "nproc\n"; my $cpu_num=4; my ($stdout,$exit,$stderr)=run_cmd_in_back_ground_get_stdout($cmd); if(length $stderr>1){ #nproc command has failed. set default 4 paralel processor }else { my ($number ) = $stdout =~ /(\d+)/; if (defined $number ){ $cpu_num =$number if ($number > 0 ); } } ($row,$col)= add_param_widget ($self,"Thread run:" , "thread_num", 1, 'Spin-button', "1,$cpu_num,1","specify the number of threads the Verilator can use at once in one simulation", $table,$row,$col,1, 'compile', undef,undef,'vertical'); return $table; } sub remove_pin_assignment{ my $self=shift; $self->object_remove_attribute('compile_pin_pos'); $self->object_remove_attribute('compile_pin'); $self->object_remove_attribute('compile_assign_type'); $self->object_remove_attribute('compile_pin_range_hsb'); $self->object_remove_attribute('compile_pin_range_lsb'); } sub add_new_fpga_board{ my ($self,$name,$top,$target_dir,$end_func,$vendor)=@_; my $window = def_popwin_size(50,80,"Add New $vendor FPGA Board",'percent'); my $table = def_table(2, 2, FALSE); my $scrolled_win=add_widget_to_scrolled_win($table); my $mtable = def_table(10, 10, FALSE); my $next=def_image_button('icons/plus.png','Add'); my $back=def_image_button('icons/left.png','Previous'); $mtable->attach_defaults($scrolled_win,0,10,0,9); $mtable->attach($back,2,3,9,10,'shrink','shrink',2,2) if (defined $name); $mtable->attach($next,8,9,9,10,'shrink','shrink',2,2); my ($Twin,$tview)=create_txview(); my $widgets= ($vendor eq 'Altera')? add_new_altera_fpga_board_widgets($self,$name,$top,$target_dir,$end_func,$vendor): add_new_xilinx_fpga_board_widgets($self,$name,$top,$target_dir,$end_func,$vendor,$tview); my $v1=gen_vpaned($widgets,0.3,$Twin); $table->attach_defaults($v1,0,3,0,2); #$table->attach_defaults( $Twin,0,3,1,2); $back-> signal_connect("clicked" => sub{ $window->destroy; select_compiler($self,$name,$top,$target_dir,$end_func); }); $next-> signal_connect("clicked" => sub{ my $result = ($vendor eq 'Altera')? add_new_altera_fpga_board_files($self,$vendor): add_new_xilinx_fpga_board_files($self,$vendor); if(! defined $result ){ select_compiler($self,$name,$top,$target_dir,$end_func) if (defined $name); $window->destroy; message_dialog("The new board has been added successfully!"); }else { show_info($tview," "); show_colored_info($tview,$result,'red'); } }); if($vendor eq 'Altera'){ my $auto=def_image_button('icons/advance.png','Auto-fill'); set_tip($auto, "Auto-fill JTAG configuration. The board must be powered on and be connected to the PC."); $mtable->attach($auto,5,6,9,10,'shrink','shrink',2,2); $auto-> signal_connect("clicked" => sub{ my $pid; my $hw; my $project_dir = get_project_dir(); my $command= "$project_dir/mpsoc/src_c/jtag/jtag_libusb/list_usb_dev"; add_info($tview,"$command\n"); my ($stdout,$exit,$stderr)=run_cmd_in_back_ground_get_stdout($command); if(length $stderr>1){ add_colored_info($tview,"$stderr\n",'red'); add_colored_info($tview,"$command was not run successfully!\n",'red'); }else { if($exit){ add_colored_info($tview,"$stdout\n",'red'); add_colored_info($tview,"$command was not run successfully!\n",'red'); }else{ add_info($tview,"$stdout\n"); my @a=split /vid=9fb/, $stdout; if(defined $a[1]){ my @b=split /pid=/, $a[1]; my @c=split /\n/, $b[1]; $pid=$c[0]; $self->object_add_attribute('compile','quartus_pid',$pid); add_colored_info($tview,"Detected PID: $pid\n",'blue'); }else{ add_colored_info($tview,"The Altera vendor ID of 9fb is not detected. Make sure You have connected your Altera board to your USB port\n",'red'); return; } } } $command= "$ENV{QUARTUS_BIN}/jtagconfig"; add_info($tview,"$command\n"); ($stdout,$exit,$stderr)=run_cmd_in_back_ground_get_stdout($command); if(length $stderr>1){ add_colored_info($tview,"$stderr\n",'red'); add_colored_info($tview,"$command was not run successfully!\n",'red'); }else { if($exit){ add_colored_info($tview,"$stdout\n",'red'); add_colored_info($tview,"$command was not run successfully!\n",'red'); }else{ add_info($tview,"$stdout\n"); my @a=split /1\)\s+/, $stdout; if(defined $a[1]){ my @b=split /\s+/, $a[1]; $hw=$b[0]; $self->object_add_attribute('compile','quartus_hardware',$hw); add_colored_info($tview,"Detected Hardware: $hw\n",'blue'); my $qsf=$self->object_get_attribute('compile','board_confg_file'); if(!defined $qsf ){ add_colored_info ($tview,"Cannot detect device location in JTAG chin. Please enter the QSF file or fill in manually \n",'red'); }else{ #search for device name in qsf file $qsf=add_project_dir_to_addr($qsf); if (!(-f $qsf)){ add_colored_info($tview, "Error Could not find $qsf file!\n"); return; } my $str=load_file($qsf); my $dw= capture_string_between(' DEVICE ',$str,"\n"); if(defined $dw){ add_colored_info($tview,"Device name in qsf file is: $dw\n",'blue'); @b=split /\n/, $a[1]; #capture device name in JTAG chain my @f=(0); foreach my $c (@b){ my @e=split /\s+/, $c; push(@f,$e[2]) if(defined $e[2]); } my $pos=find_the_most_similar_position($dw ,@f); $self->object_add_attribute('compile','quartus_device',$pos); add_colored_info($tview,"$dw has the most similarity with $f[$pos] in JTAG chain\n",'blue'); }else{ add_colored_info ($tview, "Could not find device name in the $qsf file!\n"); } } }else{ #add_colored_info($tview,"The Altera vendor ID of 9fb is not detected. Make sure You have connected your Altera board to your USB port\n",'red'); } } } $widgets->destroy(); $widgets= add_new_altera_fpga_board_widgets($self,$name,$top,$target_dir,$end_func,$vendor); $v1-> pack1($widgets, TRUE, TRUE); #$table->attach_defaults($widgets,0,3,0,1); $table->show_all(); # my $cmd=" $ENV{'QUARTUS_BIN'}" }); } $window->add ($mtable); $window->show_all(); } sub add_new_xilinx_fpga_board_widgets{ my ($self,$name,$top,$target_dir,$end_func,$vendor,$tview)=@_; my $table = def_table(2, 2, FALSE); my $col=0; my $row=0; my $help1="Your given FPGA Board name. Do not use any space in given name"; my $help2="Path to FPGA board xdc file. In your Xilinx board installation CD or in the Internet, search for a xdc file containing your FPGA device pin assignment constrain)."; my $help3="Path to FPGA_board_top.v file. A Verilog file containing all your FPGA device IO ports."; my $help4="Your Board name (Board PART) e.g. digilentinc.com:arty-z7-20:part0:1.0"; my $help5="Your FPGA device name (PART) e.g. xc7z020clg400-1 "; my $help6="The order number of target device in jtag chain. Run jtag targets after \"connect\" command in xsct terminal to list all available targets."; my $help7="Path to Vivado board files repository. E.g download the repo from https://github.com/Digilent/vivado-boards and save in \$ProNoC_work/toolchain/board_files folder."; my $help8="Hardware device name e.g. xc7z020_1. To find it you can connect your FPGA board to your PC. In tcl terminal run open_hw connect_hw_server open_hw_target get_hw_devices It supposed to show the list of your hardware devices in your FPGA. Select the name represent your FPGA device "; my $repo ="$ENV{PRONOC_WORK}/toolchain/board_files"; $row++; my @info = ( { label=>"FPGA board display name:", param_name=>'fpga_board', type=>"Entry", default_val=>undef, content=>undef, info=>$help1, param_parent=>'compile', ref_delay=> undef}, { label=>"Set board repo:", param_name=>'fpga_board_repo', type=>"DIR_path", default_val=>"$repo", content=>undef, info=>$help7, param_parent=>'compile',ref_delay=>undef}, { label=>"FPGA board part name:", param_name=>'fpga_board_part', type=>"EntryCombo",default_val=>undef, content=>undef, info =>$help4, param_parent=>'compile', ref_delay=> undef}, { label=>"FPGA part name:", param_name=>'fpga_part', type=>"Entry", default_val=>undef, content=>undef, info=>$help5, param_parent=>'compile', ref_delay=> undef}, { label=>"FPGA Hardware device name:", param_name=>'fpga_hw_device', type=>"EntryCombo", default_val=>undef, content=>undef, info=>$help8, param_parent=>'compile', ref_delay=> undef}, { label=>"Target device JTAG chain order number", param_name=>'fpga_board_order', type=>"Spin-button", default_val=>1, content=>"0,256,1", info=>$help6, param_parent=>'compile',ref_delay=>undef}, { label=>'FPGA board xdc file:', param_name=>'board_confg_file', type=>"FILE_path", default_val=>undef, content=>"xdc", info=>$help2, param_parent=>'compile', ref_delay=>undef}, { label=>"FPGA board golden top Verilog file", param_name=>'fpga_board_v', type=>"FILE_path", default_val=>undef, content=>"v", info=>$help3, param_parent=>'compile',ref_delay=>undef}, ); my %widgets; my %rows; foreach my $d (@info) { $rows{$d->{param_name}} =$row; ($row,$col,$widgets{$d->{param_name}})=add_param_widget ($self, $d->{label}, $d->{param_name}, $d->{default_val}, $d->{type}, $d->{content}, $d->{info}, $table,$row,$col,1, $d->{param_parent}, $d->{ref_delay},undef,'vertical'); } my $icon = 'icons/advance.png'; my $search=def_image_button($icon,undef); my $search_board=def_image_button ($icon,undef); my $search_dev=def_image_button ($icon,undef); my $search_chain=def_image_button ($icon,undef); $table->attach($search,4,5,$rows{'fpga_board_part'},$rows{'fpga_board_part'}+1,'fill','shrink',2,2); $table->attach($search_board,4,5,$rows{'fpga_part'},$rows{'fpga_part'}+1,'fill','shrink',2,2); $table->attach($search_dev,4,5,$rows{'fpga_hw_device'},$rows{'fpga_hw_device'}+1,'fill','shrink',2,2); $table->attach($search_chain,4,5,$rows{'fpga_board_order'},$rows{'fpga_board_order'}+1,'fill','shrink',2,2); $search->signal_connect("clicked" => sub{ my $load= show_gif("icons/load.gif"); $table->attach ($load,5, 6, $rows{'fpga_board_part'},$rows{'fpga_board_part'}+ 1,'shrink','shrink',0,0); $table->show_all; my $result= set_xilinx_board_from_repo($self,$tview); update_combo_entry_content($widgets{'fpga_board_part'}, $result); $load->destroy; $table->show_all; }); $search_board->signal_connect("clicked" => sub{ my $load= show_gif("icons/load.gif"); $table->attach ($load,5, 6, $rows{'fpga_part'},$rows{'fpga_part'}+1, 'shrink','shrink',0,0); $table->show_all; my $result= get_xilinx_board_part($self,$tview); $widgets{'fpga_part'}->set_text($result); #print "result = $result\n"; $load->destroy; $table->show_all; }); $search_dev->signal_connect("clicked" => sub{ my $load= show_gif("icons/load.gif"); $table->attach ($load,5, 6, $rows{'fpga_hw_device'},$rows{'fpga_hw_device'}+ 1,'shrink','shrink',0,0); $table->show_all; my $result= get_xilinx_device_names($self,$tview); update_combo_entry_content($widgets{'fpga_hw_device'}, $result); $load->destroy; $table->show_all; }); $search_chain->signal_connect("clicked" => sub{ my $targets = show_all_xilinx_targets($self,$tview); if(!defined $targets){ add_info($tview,"Unable to find the FPGA board target list. Make sure you have connected your FPGA board to your PC first and it is powered on.\n"); return; } my @lines=split(/\r?\n/,$targets); my @list1; my @list2; foreach my $p (@lines){ $p =~ s/^\s+//;#left trim my @words=split(/\s+/,$p); push (@list1,$words[0]); push (@list2,$words[1]); } my $hw = $self->object_get_attribute('compile','fpga_hw_device'); if( !defined $hw){ add_colored_info($tview,"Please define the FPGA hardware device name first!\n",'red'); return; } my $pos = find_the_most_similar_position ($hw ,@list2); add_info($tview,"$hw matched with target $list1[$pos] $list2[$pos] "); $widgets{'fpga_board_order'}->set_value($list1[$pos]); }); return ($row, $col, $table); } sub set_xilinx_board_from_repo{ my ($self,$tview)=@_; my $bin = $self->object_get_attribute('compile',"vivado bin"); my $vivado =(defined $bin)? "${bin}/vivado" : "vivado"; my $result; my $repo= $self->object_get_attribute('compile','fpga_board_repo'); my $tcl= get_project_dir()."/mpsoc/perl_gui/lib/tcl/vivado_get_boards.tcl -tclargs $repo"; my $command = "cd $ENV{PRONOC_WORK}/tmp; $vivado -mode tcl -source $tcl"; add_info($tview,"$command\n"); my $stdout=run_cmd_textview_errors($command,$tview); return if (!defined $stdout); add_info($tview,"$stdout\n"); my @boards=split(/\s+/,$stdout); my $r=0; foreach my $board (@boards){ my @pp=split(':',$board); if(scalar @pp == 4 && $pp[1] =~ /[a-zA-Z]+/) { $r=1; $result= (!defined $result)? "$board" : $result.",$board"; } } add_colored_info($tview,"$stdout\n",'red') if($r==0); return $result; } sub get_xilinx_device_names{ my ($self,$tview)=@_; my $bin = $self->object_get_attribute('compile',"vivado bin"); my $vivado =(defined $bin)? "${bin}/vivado" : "vivado"; my $result; my $repo= $self->object_get_attribute('compile','fpga_board_repo'); my $tcl= get_project_dir()."/mpsoc/perl_gui/lib/tcl/vivado_get_hw_device.tcl -tclargs"; my $command = "cd $ENV{PRONOC_WORK}/tmp; $vivado -mode tcl -source $tcl"; add_info($tview,"$command\n"); my $stdout=run_cmd_textview_errors($command,$tview); if (!defined $stdout){ add_info($tview,"Unable to find the FPGA board devices list. Make sure you have connected your FPGA board to your PC first and it is powered on.\n"); return; } add_info($tview,"$stdout\n"); my $devices = capture_string_between ('\n\*RESULT:',$stdout,"\n"); my @D=split(/\s+/,$devices); return join ',', @D; } sub get_xilinx_board_part{ my ($self,$tview)=@_; my $bin = $self->object_get_attribute('compile',"vivado bin"); my $vivado =(defined $bin)? "${bin}/vivado" : "vivado"; my $result; my $repo= $self->object_get_attribute('compile','fpga_board_repo'); my $board_part= $self->object_get_attribute('compile' ,'fpga_board_part'); if (!defined $board_part ){ add_colored_info($tview,"Please define the FPGA board part name first!\n",'red'); return; } my $tcl= get_project_dir()."/mpsoc/perl_gui/lib/tcl/vivado_get_part.tcl -tclargs $board_part $repo "; my $command = "cd $ENV{PRONOC_WORK}/tmp; $vivado -mode tcl -source $tcl"; add_info($tview,"$command\n"); my $stdout=run_cmd_textview_errors($command,$tview); return if (!defined $stdout); add_info($tview,"$stdout\n"); return capture_string_between ('\n\*RESULT:',$stdout,"\n"); } sub add_new_altera_fpga_board_widgets{ my ($self,$name,$top,$target_dir,$end_func,$vendor)=@_; my $table = def_table(2, 2, FALSE); my $help1="FPGA Board name. Do not use any space in given name"; my $help2="Path to FPGA board qsf file. In your Altra board installation CD or in the Internet search for a QSF file containing your FPGA device name with other necessary global project setting including the pin assignments (e.g DE10_Nano_golden_top.qsf)."; my $help3="Path to FPGA_board_top.v file. In your Altra board installation CD or in the Internet search for a Verilog file containing all your FPGA device IO ports (e.g DE10_Nano_golden_top.v)."; my $help4="FPGA Board USB-Blaster product ID (PID). Power on your FPGA board and connect it to your PC. Then press Auto-fill button to find PID. Optionally you can run mpsoc/ src_c/jtag/jtag_libusb/list_usb_dev to find your USB-Blaster PID. Search for PID of a device having 9fb (altera) Vendor ID (VID)"; my $help5="Power on your FPGA board and connect it to your PC. Then press Auto-fill button to find your hardware name. Optionally you can run \$QUARTUS_BIN/jtagconfig to find your programming hardware name. an example of output from the 'jtagconfig' command: \t 1) ByteBlasterMV on LPT1 \t 090010DD EPXA10 \t 049220DD EPXA_ARM922 or \t 1) DE-SoC [1-3] \t 48A00477 SOCVHP5 \t 02D020DC 5CS(EBA6ES|XFC6c6ES) ByteBlasterMV \& DE-SoC are the programming hardware name."; my $help6="Power on your FPGA board and connect it to your PC. Then press Auto-fill button to find your device location in jtag chain. Optionally you can run \$QUARTUS_BIN/jtagconfig to find your target device location in jtag chain."; my @info = ( { label=>"FPGA Board Name:", param_name=>'fpga_board', type=>"Entry", default_val=>undef, content=>undef, info=>$help1, param_parent=>'compile', ref_delay=> undef}, { label=>'FPGA Board Golden top QSF file:', param_name=>'board_confg_file', type=>"FILE_path", default_val=>undef, content=>"qsf", info=>$help2, param_parent=>'compile', ref_delay=>undef}, { label=>"FPGA Board Golden top Verilog file", param_name=>'fpga_board_v', type=>"FILE_path", default_val=>undef, content=>"v", info=>$help3, param_parent=>'compile',ref_delay=>undef }, ); my @usb = ( { label=>"FPGA Board USB Blaster PID:", param_name=>'quartus_pid', type=>"Entry", default_val=>undef, content=>undef, info=>$help4, param_parent=>'compile', ref_delay=> undef}, { label=>"FPGA Board Programming Hardware Name:", param_name=>'quartus_hardware', type=>"Entry", default_val=>undef, content=>undef, info=>$help5, param_parent=>'compile', ref_delay=> undef}, { label=>"FPGA Board Device location in JTAG chain:", param_name=>'quartus_device', type=>"Spin-button", default_val=>0, content=>"0,100,1", info=>$help6, param_parent=>'compile', ref_delay=> undef}, ); my $col=0; my $row=0; foreach my $d (@info) { ($row,$col)=add_param_widget ($self, $d->{label}, $d->{param_name}, $d->{default_val}, $d->{type}, $d->{content}, $d->{info}, $table,$row,$col,1, $d->{param_parent}, $d->{ref_delay},undef,"vertical"); } my $labl=def_pack_vbox(FALSE, 0,(gen_Hsep(),gen_label_in_center("FPGA Board JTAG Configuration"),gen_Hsep())); $table->attach( $labl,0,3,$row,$row+1,'fill','shrink',2,2); $row++; $col=0; foreach my $d (@usb) { ($row,$col)=add_param_widget ($self, $d->{label}, $d->{param_name}, $d->{default_val}, $d->{type}, $d->{content}, $d->{info}, $table,$row,$col,1, $d->{param_parent}, $d->{ref_delay},undef,"vertical"); } return ($row, $col, $table); } sub add_new_xilinx_fpga_board_files{ my ($self,$vendor)=@_; #check the board name my $board_name=$self->object_get_attribute('compile','fpga_board'); return "Please define the Board Name\n" if(! defined $board_name ); return "Please define the Board Name\n" if(length($board_name) ==0 ); my $r=check_verilog_identifier_syntax($board_name); return "Error in given Board Name: $r\n" if(defined $r ); #check xdc file my $xdc=$self->object_get_attribute('compile','board_confg_file'); return "Please define the xdc file\n" if(!defined $xdc ); $xdc=add_project_dir_to_addr($xdc); #check v file my $top=$self->object_get_attribute('compile','fpga_board_v'); return "Please define the verilog file file\n" if(!defined $top ); $top=add_project_dir_to_addr($top); #check board part my $part=$self->object_get_attribute('compile','fpga_part'); my $board_part=$self->object_get_attribute('compile','fpga_board_part'); return "Please define at least one of FPGA board part or FPGA part names"if(!defined $part && !defined $board_part ); #make board directory my $project_dir = get_project_dir(); my $path="$project_dir/mpsoc/boards/$vendor/$board_name"; mkpath($path,1,01777); return "Error cannot make $path path" if ((-d $path)==0); copy( $xdc,"$path/$board_name.xdc"); copy($top,"$path/$board_name.v"); my $a=$self->object_get_attribute('compile','fpga_board_order'); my $jtag_intfc="#!/bin/bash JTAG_INTFC=\"\$PRONOC_WORK/toolchain/bin/jtag_xilinx_xsct -a $a -b 36\" #it works only for 32-bit jtag data width for 64 pass -b 68 "; save_file ("$path/jtag_intfc.sh",$jtag_intfc); my $bin = $self->object_get_attribute('compile',"vivado bin"); my $hw_dev=$self->object_get_attribute('compile',"fpga_hw_device"); my $repo= $self->object_get_attribute('compile','fpga_board_repo'); my $tcl="proc set_project_properties { } {\n"; if(-d $repo){ $tcl=$tcl."\tset_property \"board_part_repo_paths\" [list \"$repo\"] [current_project]\n"; }else { $tcl=$tcl."\tset_property \"board_part_repo_paths\" [get_property LOCAL_ROOT_DIR [xhub::get_xstores xilinx_board_store]] [current_project]\n" if(defined $board_part); } $tcl=$tcl."\tset_property \"part\" \"$part\" [current_project]\n" if(defined $part); $tcl=$tcl."\tset_property \"board_part\" \"$board_part\" [current_project]\n" if(defined $board_part); $tcl=$tcl."\tset_property \"default_lib\" \"xil_defaultlib\" [current_project]\n}\n"; if (defined $hw_dev){ $tcl=$tcl."\n proc program_board {bit_file} { open_hw connect_hw_server open_hw_target set_property PROGRAM.FILE \$bit_file [get_hw_devices $hw_dev] program_hw_devices [get_hw_devices $hw_dev] refresh_hw_device [get_hw_devices $hw_dev] } "; } save_file ("$path/board_property.tcl",$tcl); $self->object_add_attribute('compile','board',$board_name); return undef; } sub add_new_altera_fpga_board_files{ my ($self,$vendor)=@_; #check the board name my $board_name=$self->object_get_attribute('compile','fpga_board'); return "Please define the Board Name\n" if(! defined $board_name ); return "Please define the Board Name\n" if(length($board_name) ==0 ); my $r=check_verilog_identifier_syntax($board_name); return "Error in given Board Name: $r\n" if(defined $r ); #check qsf file my $qsf=$self->object_get_attribute('compile','board_confg_file'); return "Please define the QSF file\n" if(!defined $qsf ); #check v file my $top=$self->object_get_attribute('compile','fpga_board_v'); return "Please define the verilog file file\n" if(!defined $top ); #check PID my $pid=$self->object_get_attribute('compile','quartus_pid'); return "Please define the PID\n" if(! defined $pid ); return "Please define the PID\n" if(length($pid) ==0 ); #check Hardware name my $hw=$self->object_get_attribute('compile','quartus_hardware'); return "Please define the Hardware Name\n" if(! defined $hw ); return "Please define the Hardware Name\n" if(length($hw) ==0 ); #check Device name name my $dw=$self->object_get_attribute('compile','quartus_device'); return "Please define targeted Device location in JTAG chain. The device location must be larger than zero.\n" if( $dw == 0 ); #make board directory my $project_dir = get_project_dir(); my $path="$project_dir/mpsoc/boards/$vendor/$board_name"; mkpath($path,1,01777); return "Error cannot make $path path" if ((-d $path)==0); #generate new qsf file $qsf=add_project_dir_to_addr($qsf); $top=add_project_dir_to_addr($top); open my $file, "<", $qsf or return "Error Could not open $qsf file in read mode!"; open my $newqsf, ">", "$path/$board_name.qsf" or return "Error Could not create $path/$board_name.qsf file in write mode!"; #remove the lines contain following strings my @p=("TOP_LEVEL_ENTITY","VERILOG_FILE","SYSTEMVERILOG_FILE","VHDL_FILE","AHDL_FILE","PROJECT_OUTPUT_DIRECTORY" ); while (my $line = <$file>){ if ($line =~ /\Q$p[0]\E/ || $line =~ /\Q$p[1]\E/ || $line =~ /\Q$p[2]\E/ || $line =~ /\Q$p[3]\E/ || $line =~ /\Q$p[4]\E/){#dont copy the line contain TOP_LEVEL_ENTITY } else{ print $newqsf $line; } } print $newqsf "\nset_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files\n"; close $newqsf; close $file; copy($top,"$path/$board_name.v"); #generate jtag_intfc.sh open $file, ">", "$path/jtag_intfc.sh" or return "Error: Could not create $path/jtag_intfc.sh file in write mode!"; my $jtag; if($pid eq 6001 || $pid eq 6002 || $pid eq 6003){ $jtag="JTAG_INTFC=\"\$PRONOC_WORK/toolchain/bin/jtag_libusb -a \$PRODUCT_ID\""; }else{ $jtag="JTAG_INTFC=\"\$PRONOC_WORK/toolchain/bin/jtag_quartus_stp -a \$HARDWARE_NAME -b \$DEVICE_NAME\""; } print $file "#!/bin/bash PRODUCT_ID=\"0x$pid\" HARDWARE_NAME=\'$hw *\' DEVICE_NAME=\"\@$dw*\" $jtag "; close $file; #generate program_device.sh open $file, ">", "$path/program_device.sh" or return "Error: Could not create $path/program_device.sh file in write mode!"; print $file "#!/bin/bash #usage: # bash program_device.sh programming_file.sof #programming file #given as an argument: \$1 #Programming mode PROG_MODE=jtag #cable name. Connect the board to ur PC and then run jtagconfig in terminal to find the cable name NAME=\"$hw\" #device name DEVICE=\@$dw".' #programming command if [ -n "${QUARTUS_BIN+set}" ]; then $QUARTUS_BIN/quartus_pgm -m $PROG_MODE -c "$NAME" -o "p;${1}${DEVICE}" else quartus_pgm -m $PROG_MODE -c "$NAME" -o "p;${1}${DEVICE}" fi '; close $file; $self->object_add_attribute('compile','board',$board_name); return undef; } sub get_pin_assignment{ my ($self,$name,$top,$target_dir,$end_func,$vendor)=@_; my $window = def_popwin_size(80,80,"Step 2: Pin Assignment",'percent'); my $table = def_table(2, 2, FALSE); my $scrolled_win = add_widget_to_scrolled_win($table); my $mtable = def_table(10, 10, FALSE); my $next=def_image_button('icons/right.png','Next'); my $back=def_image_button('icons/left.png','Previous'); $mtable->attach_defaults($scrolled_win,0,10,0,9); $mtable->attach($back,2,3,9,10,'shrink','shrink',2,2); $mtable->attach($next,8,9,9,10,'shrink','shrink',2,2); my $board_name=$self->object_get_attribute('compile','board'); #copy board jtag_intfc.sh file my ($fname,$fpath,$fsuffix) = fileparse("$top",qr"\..[^.]*$"); copy("../boards/$vendor/$board_name/jtag_intfc.sh","${fpath}../sw/jtag_intfc.sh"); my $m= $self->object_get_attribute('mpsoc_name',undef); if(defined $m){ # we are compiling a complete NoC-based mpsoc my ($nr,$ne,$router_p,$ref_tops)= get_noc_verilator_top_modules_info($self); for (my $tile_num=0;$tile_num<$ne;$tile_num++){ #print "$tile_num\n"; my ($soc_name,$num)= $self->mpsoc_get_tile_soc_name($tile_num); next if(!defined $soc_name); copy("../boards/$vendor/$board_name/jtag_intfc.sh","${fpath}../sw/tile$tile_num/jtag_intfc.sh"); } } #copy board program_device.sh file copy("../boards/$vendor/$board_name/program_device.sh","${fpath}../program_device.sh"); #get boards pin list my $top_v= "../boards/$vendor/$board_name/$board_name.v"; if(!-f $top_v){ message_dialog("Error: Could not load the board pin list. The $top_v does not exist!",'error'); $window->destroy; } my $board=read_top_v_file($top_v); # Write object file #open(FILE, ">lib/soc/tttttttt") || die "Can not open: $!"; #print FILE Data::Dumper->Dump([\%$board],['board']); #close(FILE) || die "Error closing file: $!"; my @dirs = ('Input', 'Bidir', 'Output'); my %models; foreach my $p (@dirs){ my %pins=$board->board_get_pin($p); $models{$p}=gen_combo_model(\%pins); } my $row=0; my $col=0; my @labels= ('Port Direction','Port Range ','Port name ','Assignment Type','Board Port name ','Board Port Range'); foreach my $p (@labels){ my $l=gen_label_in_left($p); $l->set_markup(" $p "); $table->attach ($l, $col,$col+1, $row, $row+1,'fill','shrink',2,2); $col++ } $row++; #read port list my $vdb=read_verilog_file($top); my %port_type=get_ports_type($vdb,"${name}_top"); my %port_range=get_ports_rang($vdb,"${name}_top"); my %param = $vdb->get_modules_parameters("${name}_top"); foreach my $p (sort keys %port_type){ my $porttype=$port_type{$p}; my $portrange=$port_range{$p}; if (length($portrange)!=0){ #replace parameter with their values my @a= split (/\b/,$portrange); foreach my $l (@a){ my $value=$param{$l}; if(defined $value){ chomp $value; ($portrange=$portrange)=~ s/\b$l\b/$value/g if(defined $param{$l}); # print"($portrange=$portrange)=~ s/\b$l\b/$value/g if(defined $param{$l})\n"; } } my($s1,$s2)=split (":",$portrange); { no warnings 'numeric'; $s1 = eval $s1; $s2 = eval $s2; } $portrange = "[ $portrange ]" ; if(defined $s1 && defined $s2 ){ $portrange = "" if($s1 eq 0 && $s2 eq 0); #the upper and lower range are equal zero so remove it } } my $label1= gen_label_in_left(" $porttype"); my $label2= gen_label_in_left(" $portrange"); my $label3= gen_label_in_left(" $p"); $table->attach($label1, 0,1, $row, $row+1,'fill','shrink',2,2); $table->attach($label2, 1,2, $row, $row+1,'fill','shrink',2,2); $table->attach($label3, 2,3, $row, $row+1,'fill','shrink',2,2); my $assign_type= "Direct,Negate(~)"; if ($porttype eq 'input') { my $assign_combo=gen_combobox_object($self,'compile_assign_type',$p,$assign_type,'Direct',undef,undef); $table->attach( $assign_combo, 3,4, $row, $row+1,'fill','shrink',2,2); } my $type= ($porttype eq 'input') ? 'Input' : ($porttype eq 'output')? 'Output' : 'Bidir'; my $combo= gen_tree_combo($models{$type}); my $saved=$self->object_get_attribute('compile_pin_pos',$p); my $box; my $loc=$row; if(defined $saved) { my @indices=@{$saved}; my $path = TreePath_new_from_indices(@indices); my $iter = $models{$type}->get_iter($path); undef $path; $combo->set_active_iter($iter); $box->destroy if(defined $box); my $text=$self->object_get_attribute('compile_pin',$p); $box=get_range ($board,$self,$type,$text,$portrange,$p); $table->attach($box, 5,6, $loc, $loc+1,'fill','shrink',2,2); } $combo->signal_connect("changed" => sub{ #get and saved new value my $treeiter= $combo->get_active_iter(); my $text = $models{$type}->get_value($treeiter, 0); $self->object_add_attribute('compile_pin',$p,$text); #get and saved value position in model my $treepath = $models{$type}->get_path ($treeiter); my @indices= $treepath->get_indices(); $self->object_add_attribute('compile_pin_pos',$p,\@indices); #update borad port range $box->destroy if(defined $box); $box=get_range ($board,$self,$type,$text,$portrange,$p); $table->attach($box, 5,6, $loc, $loc+1,'fill','shrink',2,2); $table->show_all; }); $table->attach($combo, 4,5, $row, $row+1,'fill','shrink',2,2); $row++; } $next-> signal_connect("clicked" => sub{ $window->destroy; fpga_compilation($self,$board,$name,$top,$target_dir,$end_func,$vendor); }); $back-> signal_connect("clicked" => sub{ $window->destroy; select_compiler($self,$name,$top,$target_dir,$end_func,$vendor); }); $window->add ($mtable); $window->show_all(); } sub fpga_compilation{ my ($self,$board,$name,$top,$target_dir,$end_func,$vendor)=@_; my $run=def_image_button('icons/gate.png','Compile'); my $back=def_image_button('icons/left.png','Previous'); my $regen=def_image_button('icons/refresh.png','Regenerate Top.v'); my $prog=def_image_button('icons/write.png','Program the board'); my ($fname,$fpath,$fsuffix) = fileparse("$top",qr"\..[^.]*$"); my $board_top_file ="${fpath}Top.v"; unless (-e $board_top_file ){ gen_top_v($self,$board,$name,$top) ; } my ($app,$table,$tview,$window) = software_main($fpath,'Top.v'); $table->attach($back,1,2,1,2,'shrink','shrink',2,2); $table->attach($regen,4,5,1,2,'shrink','shrink',2,2); $table->attach ($run,6, 7, 1,2,'shrink','shrink',2,2); $table->attach($prog,9,10,1,2,'shrink','shrink',2,2); $regen-> signal_connect("clicked" => sub{ my $response = yes_no_dialog("Are you sure you want to regenerate the Top.v file? Note that any changes you have made will be lost"); if ($response eq 'yes') { gen_top_v($self,$board,$name,$top); $app->refresh_source("$board_top_file"); } }); $back-> signal_connect("clicked" => sub{ $window->destroy; get_pin_assignment($self,$name,$top,$target_dir,$end_func,$vendor); }); #compile $run-> signal_connect("clicked" => sub{ my $load= show_gif("icons/load.gif"); $table->attach ($load,8, 9, 1,2,'shrink','shrink',2,2); $load->show_all; set_gui_status($self,'save_project',1); $app->ask_to_save_changes(); quartus_run_compile ($self,$app,$tview,$target_dir,$name,$window,$end_func,$vendor) if($vendor eq 'Altera'); xilinx_run_compile ($self,$app,$tview,$target_dir,$name,$window,$end_func,$vendor) if($vendor eq 'Xilinx'); $load->destroy; }); #Programe the board $prog-> signal_connect("clicked" => sub{ quartus_program_the_board($self,$tview,$target_dir,$name,$vendor) if($vendor eq 'Altera'); vivado_program_the_board($self,$tview,$target_dir,$name,$vendor) if($vendor eq 'Xilinx'); }); } sub vivado_program_the_board { my ($self,$tview,$target_dir,$name,$vendor) =@_; my $bit_file="$target_dir/Vivado/xilinx_compile/${name}.runs/impl_1/Top.bit"; unless (-f "$target_dir/Vivado/program_board.tcl"){ #create tcl file my $xpr = "\$tcl_path/xilinx_compile/${name}.xpr"; my $tcl=" #Get tcl shell path relative to current script set tcl_path [file dirname [info script]] set projectName $name source \"\$tcl_path/board_property.tcl\" set projectXpr \"$xpr\" #Open project open_project \$projectXpr program_board \"\$tcl_path/xilinx_compile/${name}.runs/impl_1/Top.bit\" close_project exit "; save_file ("$target_dir/Vivado/program_board.tcl",$tcl); add_info($tview,"File $target_dir/Vivado/program_board.tcl is created\n"); } #check bit file existance unless (-f $bit_file){ add_colored_info($tview,"Could not find $bit_file. Click on project Compile button first and make sure it runs successfully.",'red'); return } #run vivado using program_board.tcl my $error =run_vivado ($self,$target_dir,$tview,"$target_dir/Vivado/program_board.tcl"); add_colored_info($tview,"Board is programmed successfully!\n",'blue') if($error==0); } sub quartus_program_the_board{ my ($self,$tview,$target_dir,$name,$vendor)=@_; my $error = 0; my $sof_file="$target_dir/Quartus/output_files/${name}.sof"; my $bash_file="$target_dir/program_device.sh"; add_info($tview,"Program the board using Quartus_pgm and $sof_file file\n"); #check if the programming file exists unless (-f $sof_file) { add_colored_info($tview,"\tThe $sof_file does not exists! Make sure you have compiled the code successfully.\n", 'red'); $error=1; } #check if the program_device.sh file exists unless (-f $bash_file) { add_colored_info($tview,"\tThe $bash_file does not exist! This file varies depending on your target board and must be available inside mpsoc/boards/$vendor/[board_name].\n", 'red'); $error=1; } return if($error); my $command = "bash $bash_file $sof_file"; add_info($tview,"$command\n"); my ($stdout,$exit,$stderr)=run_cmd_in_back_ground_get_stdout($command); if(length $stderr>1){ add_colored_info($tview,"$stderr\n",'red'); add_colored_info($tview,"Board was not programmed successfully!\n",'red'); }else { if($exit){ add_colored_info($tview,"$stdout\n",'red'); add_colored_info($tview,"Board was not programmed successfully!\n",'red'); }else{ add_info($tview,"$stdout\n"); add_colored_info($tview,"Board is programmed successfully!\n",'blue'); } } } sub quartus_run_compile{ my ($self,$app,$tview,$target_dir,$name,$window,$end_func,$vendor)=@_; my $error = 0; add_info($tview,"CREATE: start creating Quartus project in $target_dir/Quartus folder\n"); mkpath("$target_dir/Quartus",1,01777); #get list of source file add_info($tview," Read the list of all source files $target_dir/src_verilog\n"); my @files = File::Find::Rule->file() ->name( '*.v','*.V','*.sv' ) ->in( "$target_dir/src_verilog" ); #make sure source files have key word 'module' my @sources; foreach my $p (@files){ push (@sources,$p) if(check_file_has_string($p,'endpackage')); } foreach my $p (@files){ push (@sources,$p) if(check_file_has_string($p,'module')); } my $files = join ("\n",@sources); add_info($tview,"$files\n"); #creat project qsf file my $qsf_file="$target_dir/Quartus/${name}.qsf"; save_file ($qsf_file,"# Generated using ProNoC\n"); #append global assignets to qsf file my $board_name=$self->object_get_attribute('compile','board'); my @qsfs = glob("../boards/$vendor/$board_name/*.qsf"); if(!defined $qsfs[0]){ message_dialog("Error: ../boards/$vendor/$board_name folder does not contain the qsf file.!",'error'); $window->destroy; } my $assignment_file = $qsfs[0]; if(-f $assignment_file){ merg_files ($assignment_file,$qsf_file); } my %paths; #add the list of source fils to qsf file my $s="\n\n\n set_global_assignment -name TOP_LEVEL_ENTITY Top\n"; foreach my $p (@sources){ my ($name,$path,$suffix) = fileparse("$p",qr"\..[^.]*$"); $s="$s set_global_assignment -name VERILOG_FILE $p\n" if ($suffix eq ".v"); $s="$s set_global_assignment -name SYSTEMVERILOG_FILE $p\n" if ($suffix eq ".sv"); $paths{$path}=1; } foreach my $p (sort keys %paths){ $s="$s set_global_assignment -name SEARCH_PATH $p\n"; } append_text_to_file($qsf_file,$s); add_info($tview,"\n Qsf file has been created\n"); #start compilation my $Quartus_bin= $self->object_get_attribute('compile','quartus bin'); my @qfiles = ("quartus_map","quartus_fit","quartus_asm","quartus_sta"); foreach my $f (@qfiles){ unless(-f "$Quartus_bin/$f" ){ $error=1; add_colored_info($tview, "$Quartus_bin/$f No such file or directory\n",'red'); last; } } my $run_sh = "#!/bin/bash $Quartus_bin/quartus_map --64bit $name --read_settings_files=on $Quartus_bin/quartus_fit --64bit $name --read_settings_files=on $Quartus_bin/quartus_asm --64bit $name --read_settings_files=on $Quartus_bin/quartus_sta --64bit $name "; save_file("$target_dir/Quartus/run.sh", $run_sh); add_info($tview, "Start Quartus compilation.....\n"); my @compilation_command =( "cd \"$target_dir/Quartus\" \n xterm -e bash -c '$Quartus_bin/quartus_map --64bit $name --read_settings_files=on; echo \$? > status; sleep 1' ", "cd \"$target_dir/Quartus\" \n xterm -e bash -c '$Quartus_bin/quartus_fit --64bit $name --read_settings_files=on; echo \$? > status; sleep 1' ", "cd \"$target_dir/Quartus\" \n xterm -e bash -c '$Quartus_bin/quartus_asm --64bit $name --read_settings_files=on; echo \$? > status; sleep 1' ", "cd \"$target_dir/Quartus\" \n xterm -e bash -c '$Quartus_bin/quartus_sta --64bit $name; echo \$? > status; sleep 1 ' "); foreach my $cmd (@compilation_command){ last if($error); add_info($tview,"$cmd\n"); unlink "$target_dir/Quartus/status"; my ($stdout,$exit,$stderr)=run_cmd_in_back_ground_get_stdout( $cmd); if($exit){ add_colored_info($tview, "$stdout\n",'red') if(defined $stdout); add_colored_info($tview, "$stderr\n",'red') if(defined $stderr); $error=1; last; } open(my $fh, "<$target_dir/Quartus/status") || die "Can not open: $!"; read($fh,my $status,1); close($fh); if("$status" != "0"){ ($stdout,$exit,$stderr)=run_cmd_in_back_ground_get_stdout("cd \"$target_dir/Quartus/output_files/\" \n grep -h \"Error (\" *"); add_colored_info($tview,"$stderr\n",'red') if(defined $stderr); add_colored_info($tview,"$stdout\n",'red'); $error=1; last; } } add_colored_info($tview,"Quartus compilation failed !\n",'red') if($error==1); add_colored_info($tview,"Quartus compilation is done successfully in $target_dir/Quartus!\n", 'blue') if($error==0); if (defined $end_func){ if ($error==0){ $end_func->($self); $window->destroy; }else { message_dialog("Error in Quartus compilation!",'error'); } } } sub xilinx_run_compile{ my ($self,$app,$tview,$target_dir,$name,$window,$end_func,$vendor)=@_; add_info($tview,"CREATE: start creating Vivado project in $target_dir/Vivado\n"); #get list of source file add_info($tview," Read the list of all source files $target_dir/src_verilog\n"); my @files = File::Find::Rule->file() ->name( '*.v','*.V','*.sv' ) ->in( "$target_dir/src_verilog" ); #make sure source files have key word 'module' my @sources; foreach my $p (@files){ push (@sources,$p) if(check_file_has_string($p,'endpackage')); } foreach my $p (@files){ push (@sources,$p) if(check_file_has_string($p,'module')); } my %paths; foreach my $p (@files){ my ($name,$path,$suffix) = fileparse("$p",qr"\..[^.]*$"); #print "$path\n"; my $remove="$target_dir/"; $path =~ s/$remove//; $paths{$path}=1; } my $incdir="set include_dir_list [list"; foreach my $p (sort keys %paths){ $incdir.=" \$Dir/$p"; } $incdir.="]"; my $files = join ("\n",@sources); #add mem initial file to sources my $mem_files=""; my @initial_files = File::Find::Rule->file() ->name( '*.mem') ->in( "$target_dir/sw" ); mkpath("$target_dir/Vivado/xilinx_mem",1,01777) unless -f "$target_dir/Vivado/xilinx_mem"; foreach my $f (@initial_files){ # /home/alireza/work/hca_git/mpsoc_work/SOC/mor1k_soc/sw/RAM/ram0.mif fpr soc # /home/alireza/work/hca_git/mpsoc_work/MPSOC/newAdder/sw/tile0/RAM/ram0.mif fpr mpsoc my @m = split('\/sw\/',$f ); my $d = $m[-1];#take the last file path name after /sw/ $d=~ s/RAM//g; #remove RAM $d=~ s/\///g; #remove / $d = "tile0".$d unless($m[-1]=~/^tile/); #add tile0 to soc copy($f,"$target_dir/Vivado/xilinx_mem/$d"); $mem_files="$mem_files \$tcl_path/xilinx_mem/$d"; } add_info($tview,"HDL sources:\n$files\nMem sources:\n$mem_files\n"); #make tcl file my $tcl=" #Get tcl shell path relative to current script set tcl_path [file dirname [info script]] set Dir \"\$tcl_path/..\" "; $tcl=$tcl."set projectName $name"; $tcl =$tcl." source \"\$tcl_path/board_property.tcl\" #Create output directory and clear contents set outputdir \"\$tcl_path/xilinx_compile\""; $tcl =$tcl.' file mkdir $outputdir set files [glob -nocomplain "$outputdir/*"] if {[llength $files] != 0} { puts "deleting contents of $outputdir" file delete -force {*}[glob -directory $outputdir *]; # clear folder contents } else { puts "$outputdir is empty" } #Create project create_project $projectName $outputdir set_project_properties #add source files to Vivado project '; #get top level port names #get boards pin list my $top_v= "$target_dir/src_verilog/Top.v"; if(!-f $top_v){ message_dialog("Error: Could not load the board pin list. The Top.v does not exist!",'error'); $window->destroy; } my @ports=verilog_file_get_ports_list(read_verilog_file($top_v),"Top"); #get board tcl my $board_name=$self->object_get_attribute('compile','board'); my @tcls= glob("../boards/$vendor/$board_name/*.tcl"); foreach my $f (@tcls){ copy($f,"$target_dir/Vivado"); } #get board xdc my @xdcs= glob("../boards/$vendor/$board_name/*.xdc"); my $i=1; foreach my $f (@xdcs){ my $out=""; #capture file content my $string= load_file($f); my @lines=split('\n',$string); #make sure lines describing the port name are not comment foreach my $l (@lines){ foreach my $p (@ports){ $l=~ s/^\s*#/ /g if($l =~ /^\s*#/ && $l =~ /\[\s*get_ports\s*[{\s]\s*$p[\s\[\]\}]/ );# /\[get_ports\s*{\s*$p[\s\}\[]/); } $out=$out."$l\n"; } my ($fname,$fpath,$fsuffix) = fileparse("$f",qr"\..[^.]*$"); my $xdc_file = "$target_dir/Vivado/$fname.xdc"; #save new xdc file save_file($xdc_file,$out); #add xdc to tcl file $tcl =$tcl."add_files -fileset constrs_1 \$tcl_path/$fname.xdc\n"; $i++; } #internal clock constrain my $clk_xdc=get_clk_constrain_file($self); #save_file ("$target_dir/clk.xdc",$clk_xdc); #$tcl =$tcl."add_files -fileset constrs_1 \$tcl_path/clk.xdc\n"; $tcl =$tcl."add_files "; #add hdl sources foreach my $f (@sources){ my $p =cut_dir_path($f,'src_verilog'); $tcl =$tcl." \$Dir/src_verilog/$p "; } $tcl =$tcl."\n"; $tcl =$tcl."#add memory initial files to Vivado project add_files -norecurse $mem_files" if(length($mem_files)>3); $tcl =$tcl."\n set_property \"top\" \"Top\" [current_fileset]\n"; $tcl =$tcl." update_compile_order -fileset sources_1 #launch synthesis # Make all reset syncron set_property verilog_define {{SYNC_RESET_MODE}} [current_fileset] # include source dirs $incdir set_property include_dirs \$include_dir_list [current_fileset] launch_runs synth_1 wait_on_run synth_1 #Run implementation and generate bitstream set_property STEPS.PHYS_OPT_DESIGN.IS_ENABLED true [get_runs impl_1] launch_runs impl_1 -to_step write_bitstream wait_on_run impl_1 puts \"Implementation done!\" "; $tcl =$tcl."\nexit"; #creat make_project tcl file save_file ("$target_dir/Vivado/make_project.tcl",$tcl); my $error =run_vivado ($self,$target_dir,$tview,"$target_dir/Vivado/make_project.tcl"); add_colored_info($tview,"Vivado compilation is done successfully in $target_dir/Vivado!\n", 'blue') if($error==0); if (defined $end_func){ if ($error==0){ $end_func->($self); $window->destroy; }else { message_dialog("Error in Vivado compilation!",'error'); } } } sub run_vivado { my ($self,$target_dir,$tview,$tcl)=@_; my $error=0; #start compilation my $vivado_bin= $self->object_get_attribute('compile','vivado bin'); add_info($tview, "Start compilation using vivado.....\n"); my @compilation_command =( "cd \"$target_dir/Vivado/\" \n xterm -e bash -c '$vivado_bin/vivado -mode tcl -source $tcl'" ); save_file("$target_dir/Vivado/run.sh", "#!/bin/bash \n $vivado_bin/vivado -mode tcl -source $tcl"); my $log="$target_dir/Vivado/vivado.log"; #unlink $log; foreach my $cmd (@compilation_command){ add_info($tview,"$cmd\n"); my ($stdout,$exit,$stderr)=run_cmd_in_back_ground_get_stdout( $cmd); if($exit){ $error=1; add_colored_info($tview, "$stdout\n",'red') if(defined $stdout); add_colored_info($tview, "$stderr\n",'red') if(defined $stderr); } } #check vivado.log for error my $r; open my $fd, "<" , $log or $r=$!; if(defined $r ) { add_colored_info($tview, "could not open $log to check errors: $r\n",'red'); $error=1; } else{ #check error while (my $line = <$fd>) { chomp $line; if( $line =~ /ERROR:/){ add_colored_info($tview, "$line\n",'red'); $error=1; } } #check warning close($fd); open $fd, "<" , $log; #print "$log\n"; if($error==0){ while (my $line = <$fd>) { chomp $line; if( $line =~ /^\s*WARNING:/){ add_info($tview, "$line\n"); } } } #check critical warning close($fd); open $fd, "<" , $log; #print "$log\n"; if($error==0){ while (my $line = <$fd>) { chomp $line; if( $line =~ /^\s*CRITICAL WARNING:/){ add_colored_info($tview, "$line\n",'green'); } } } close($fd); } return $error; } sub modelsim_compilation{ my ($self,$name,$top,$target_dir,$vendor)=@_; #my $window = def_popwin_size(80,80,"Step 2: Compile",'percent'); my $run=def_image_button('icons/run.png','_run',FALSE,1); my $back=def_image_button('icons/left.png','Previous'); my $regen=def_image_button('icons/refresh.png','Regenerate testbench.v'); #creat modelsim dir my $model="$target_dir/Modelsim"; unlink("$model/model.tcl"); rmtree("$target_dir/rtl_work"); mkpath("$model/rtl_work",1,01777); my ($app,$table,$tview,$window) = software_main("$target_dir/Modelsim",undef); #create testbench.v gen_modelsim_soc_testbench ($self,$name,$top,$target_dir,$tview) unless (-f "$target_dir/Modelsim/testbench.v"); $app->refresh_source("$target_dir/Modelsim/testbench.v"); add_info($tview,"create Modelsim dir in $target_dir\n"); $table->attach($back,1,2,1,2,'shrink','shrink',2,2); $table->attach($regen,4,5,1,2,'shrink','shrink',2,2); $table->attach ($run,9, 10, 1,2,'shrink','shrink',0,0); $regen-> signal_connect("clicked" => sub{ my $response = yes_no_dialog("Are you sure you want to regenerate the testbench.v file? Note that any changes you have made will be lost"); if ($response eq 'yes') { gen_modelsim_soc_testbench ($self,$name,$top,$target_dir,$tview); $app->refresh_source("$target_dir/Modelsim/testbench.v"); } }); $back-> signal_connect("clicked" => sub{ $window->destroy; select_compiler($self,$name,$top,$target_dir); }); #Get the list of all verilog files in src_verilog folder add_info($tview,"Get the list of all Verilog files in src_verilog folder\n"); my @files = File::Find::Rule->file() ->name( '*.v','*.V','*.sv' ) ->in( "$target_dir/src_verilog" ); #get list of all verilog files in src_sim folder my @sim_files = File::Find::Rule->file() ->name( '*.v','*.V','*.sv' ) ->in( "$target_dir/src_sim" ); push (@files, @sim_files); #add testnemch.v push (@files, "$target_dir/Modelsim/testbench.v"); #create a file list my $tt =create_file_list($target_dir,\@files,'modelsim'); save_file("$target_dir/Modelsim/file_list.f", "$tt"); #create modelsim.tcl file my $tcl="#!/usr/bin/tclsh transcript on if {[file exists rtl_work]} { vdel -lib rtl_work -all } vlib rtl_work vmap work rtl_work vlog +acc=rn -F $target_dir/Modelsim/file_list.f vsim -t 1ps -L rtl_work -L work -voptargs=\"+acc\" testbench add wave * view structure view signals run -all "; add_info($tview,"Create model.tcl, run.sh files\n"); save_file ("$model/model.tcl",$tcl); my $modelsim_bin= $self->object_get_attribute('compile','modelsim_bin'); my $cmd="cd $target_dir/Modelsim; rm -Rf rtl_work; $modelsim_bin/vsim -do $model/model.tcl"; save_file ("$model/run.sh",'#!/bin/bash'."\n".$cmd); $run -> signal_connect("clicked" => sub{ set_gui_status($self,'save_project',1); $app->ask_to_save_changes(); add_info($tview,"$cmd\n"); my ($stdout,$exit,$stderr)=run_cmd_in_back_ground_get_stdout($cmd); if(length $stderr>1){ add_colored_info($tview,"$stderr\n","red"); }else { add_info($tview,"$stdout\n"); } }); #$window->show_all(); } # source files : $target_dir/src_verilog # work dir : $target_dir/src_verilog sub create_file_list { my ($target_dir,$files_ref, $platform)=@_; my @ff=@{$files_ref} if(defined $files_ref); my $pakages=""; my $file_list=""; my $include=""; my %paths; my @files = File::Find::Rule->file() ->name( '*.v','*.V','*.sv','*.vh') ->in( @ff ); @ff =uniq( @ff); foreach my $file (@files) { my ($name,$path,$suffix) = fileparse("$file",qr"\..[^.]*$"); #print "$path\n"; my $remove="$target_dir/"; $path =~ s/$remove//; $paths{$path}=1; #put packages at the top of the list if(check_file_has_string($file,'endpackage')){ $pakages.="../${path}${name}$suffix\n" if($platform eq 'modelsim'); $pakages.="./${name}$suffix\n" if($platform eq 'verilator'); } else{ $file_list.= "../${path}${name}$suffix\n"if($platform eq 'modelsim'); $file_list.= "./${name}$suffix\n"if($platform eq 'verilator'); } } foreach my $p (sort keys %paths){ $include.="+incdir+../$p\n"; } return "$include\n$pakages\n$file_list"; } sub verilator_compilation { my ($top_ref,$target_dir,$outtext,$cpu_num)=@_; $cpu_num = 1 if (!defined $cpu_num); my %tops = %{$top_ref}; #creat verilator dir add_info($outtext,"create verilator dir in $target_dir\n"); my $verilator="$target_dir/verilator"; rmtree("$verilator"); mkpath("$verilator",1,01777); my @ff = ("$target_dir/src_verilog"); push (@ff,"$target_dir/src_verilator") if (-d "$target_dir/src_verilator"); push (@ff,"$target_dir/src_sim") if (-d "$target_dir/src_sim"); #create a file list add_info($outtext,"make a file list containig all RTL modules\n"); my $tt =create_file_list($target_dir,\@ff,'verilator'); save_file("$verilator/file_list.f", "$tt"); #check if -Wno-TIMESCALEMOD flag is supported" my $flag=""; # my $cmd ="verilator --version | head -n1 | cut -d\" \" -f2"; # my ($stdout,$exit,$stderr)=run_cmd_in_back_ground_get_stdout($cmd); # my $current_v=$stdout; # $current_v =~ s/[^0-9.]//g; # if (defined $current_v){ # $cmd = "printf \'%s\n\' \"4.0.0\" \"$current_v\" | sort -V | head -n1"; # my ($stdout,$exit,$stderr)=run_cmd_in_back_ground_get_stdout($cmd); # $stdout =~ s/[^0-9.]//g; # if ($stdout eq "4.0.0" ){ # add_info($outtext, "Verilator vesrion $current_v is Greater than or equal to 4.0.0. So compile with -Wno-TIMESCALEMOD flag\n"); # $flag.="-Wno-TIMESCALEMOD"; # }else{ # add_info($outtext, "Verilator vesrion is $current_v\n"); # } # } my $pdir = get_project_dir(); my $tmp = "$pdir/mpsoc/perl_gui/lib/verilog/tmp.v"; my $cmd = "verilator --lint-only $tmp -Wno-TIMESCALEMOD"; my ($stdout,$exit,$stderr)=run_cmd_in_back_ground_get_stdout($cmd); if(length $stderr>1){ #-Wno-TIMESCALEMOD not supported #add_info($outtext,"$stderr\n"); #verilator compain some ignoerabe warnning as error. }else { #add_info($outtext,"compile verilator with -Wno-TIMESCALEMOD\n"); $flag.="-Wno-TIMESCALEMOD"; } #run verilator my $jobs=0; #a counter to limit the number of paralle process my $make_lib=""; $cmd="cd \"$verilator\"; "; my $vrun="#!/bin/bash cd \"$verilator\" "; #my $cmd= "cd \"$verilator/processed_rtl\" \n xterm -e bash -c ' verilator --cc $name.v --profile-cfuncs --prefix \"Vtop\" -O3 -CFLAGS -O3'"; my $length = scalar (keys %tops); foreach my $top (sort keys %tops) { add_colored_info($outtext,"Generate $top Verilator model from $tops{$top} file\n",'green'); $cmd.= "verilator -f ./file_list.f --cc $tops{$top} --prefix \"$top\" $flag -O3 -CFLAGS -O3 & "; $vrun.="verilator -f ./file_list.f --cc $tops{$top} --prefix \"$top\" $flag -O3 -CFLAGS -O3 &\n"; $make_lib.="make lib$jobs &\n"; $jobs++; if( $jobs % $cpu_num == 0 || $jobs == $length){ $vrun.="wait\n"; $make_lib.="wait\n"; $cmd.="wait\n"; add_info($outtext,"$cmd\n"); my ($stdout,$exit,$stderr)=run_cmd_in_back_ground_get_stdout($cmd); if(length $stderr>1){ add_info($outtext,"$stderr\n"); #verilator compain some ignoerabe warnning as error. }else { add_info($outtext,"$stdout\n"); } $cmd="cd \"$verilator\"; "; } } #check if verilator model has been generated foreach my $top (sort keys %tops) { $vrun.=" if ! [ -f $verilator/obj_dir/$top.cpp ]; then echo \"Failed to generate: $verilator/obj_dir/$top.cpp \" exit 1 fi "; if (-f "$verilator/obj_dir/$top.cpp"){#succsess }else { return 0; } } #generate makefile gen_verilator_makefile($top_ref,"$verilator/obj_dir/Makefile"); $vrun.=" echo \"Verilator modules are generated successfully\". cd $verilator/obj_dir/ #run make file $make_lib make sim #done "; save_file ("$verilator/verilate.sh",$vrun); #copy topology connection header files my $project_dir = get_project_dir(); $project_dir= "$project_dir/mpsoc"; my $src_verilator_dir="$project_dir/src_verilator"; my @files = File::Find::Rule->file() ->name( '*.h') ->in( "$src_verilator_dir" ); copy_file_and_folders (\@files,$project_dir,"$verilator/obj_dir/"); return 1; } sub verilator_compilation_win { my ($self,$name,$top,$target_dir,$vendor)=@_; my $window = def_popwin_size(80,80,"Step 2: Compile",'percent'); my $mtable = def_table(10, 10, FALSE); my ($outbox,$outtext)= create_txview(); my $next=def_image_button('icons/run.png','Next'); my $back=def_image_button('icons/left.png','Previous'); my $load= show_gif("icons/load.gif"); $mtable->attach($load,8,9,9,10,'shrink','shrink',2,2); $mtable->attach_defaults ($outbox ,0, 10, 4,9); $mtable->attach($back,2,3,9,10,'shrink','shrink',2,2); $back-> signal_connect("clicked" => sub{ $window->destroy; select_compiler($self,$name,$top,$target_dir); }); $next-> signal_connect("clicked" => sub{ $window->destroy; verilator_testbench($self,$name,$top,$target_dir,$vendor); }); $window->add ($mtable); $window->show_all(); my $result; my $cpu_num = $self->object_get_attribute('compile', 'cpu_num'); my $n= $self->object_get_attribute('soc_name',undef); if(defined $n){ #we are compiling a single tile as SoC my $sw_path = "$target_dir/sw"; my %params = soc_get_all_parameters($self); my $verilator = soc_generate_verilator ($self,$sw_path,"verilator_$n",\%params); my %tops; $tops{"Vtop"}= "--top-module verilator_$n"; my $target_verilator_dr ="$target_dir/src_verilator"; mkpath("$target_verilator_dr",1,01777); save_file ("$target_verilator_dr/verilator_${n}.sv",$verilator); #$tops{"Vtop"}= "--top-module $name"; $result = verilator_compilation (\%tops,$target_dir,$outtext,$cpu_num); $self->object_add_attribute('verilator','libs',\%tops); } else { # we are compiling a complete NoC-based mpsoc $result = gen_mpsoc_verilator_model ($self,$name,$top,$target_dir,$outtext,$cpu_num); } #check if verilator model has been generated if ($result){ add_colored_info($outtext,"Veriator model has been generated successfully!",'blue'); $load->destroy(); $mtable->attach($next,8,9,9,10,'shrink','shrink',2,2); }else { add_colored_info($outtext,"Verilator compilation failed!\n","red"); $load->destroy(); $next->destroy(); } } sub gen_mpsoc_verilator_model{ my ($self,$name,$top,$target_dir,$outtext,$cpu_num)=@_; my $project_dir = get_project_dir(); $project_dir= "$project_dir/mpsoc"; my $src_verilator_dir="$project_dir/src_verilator"; my $target_verilog_dr ="$target_dir/src_verilog"; my $target_verilator_dr ="$target_dir/src_verilator"; my $sw_dir = "$target_dir/sw"; my $src_noc_dir="$project_dir/rtl/src_noc"; mkpath("$target_verilator_dr",1,01777); #copy src_verilator files my @files_list = File::Find::Rule->file() ->name( '*.v','*.V','*.sv' ) ->in( "$src_verilator_dir" ); #make sure source files have key word 'module' my @files; foreach my $p (@files_list){ push (@files,$p) if(check_file_has_string($p,'module')); } copy_file_and_folders (\@files,$project_dir,$target_verilator_dr); #copy src_noc files #my @files2; #push (@files2,$src_noc_dir); #copy_file_and_folders (\@files2,$project_dir,$target_verilog_dr); #create each tile top module my $processors_en=0; my $mpsoc=$self; my $lisence= get_license_header("verilator_tiles"); my $warning=autogen_warning(); my $verilator=$lisence.$warning; # generate NoC parameter file my ($noc_param,$pass_param)=gen_noc_param_v($self); my $noc_param_v= " \`ifdef INCLUDE_PARAM \n \n $noc_param //simulation parameter \n \n \`endif" ; #save_file("$target_verilator_dr/parameter.v",$noc_param_v); my ($nr,$ne,$router_p,$ref_tops)= get_noc_verilator_top_modules_info($self); my %tops = %{$ref_tops}; for (my $tile_num=0;$tile_num<$ne;$tile_num++){ #print "$tile_num\n"; my ($soc_name,$num)= $mpsoc->mpsoc_get_tile_soc_name($tile_num); my $soc=eval_soc($mpsoc,$soc_name,$outtext); my $top=$mpsoc->mpsoc_get_soc($soc_name); my $soc_num= $tile_num; #update core id $soc->object_add_attribute('global_param','CORE_ID',$tile_num); #update NoC param my $nocparam =$mpsoc->object_get_attribute('noc_param',undef); my ($NE, $NR, $RAw, $EAw, $Fw) = get_topology_info($mpsoc); my %y=%{$nocparam}; $y{'EAw'} = $EAw; $y{'RAw'} = $RAw; $y{'Fw'} = $Fw; my @nis=get_NI_instance_list($top); $soc->soc_add_instance_param($nis[0] ,\%y ); my %z; my %param_type= $soc->soc_get_module_param_type($nis[0]); foreach my $p (sort keys %y){ $z{$p}=$param_type{$p}; #"Parameter"; } $soc->soc_add_instance_param_type($nis[0] ,\%z ); my $tile=$tile_num; my $setting=$mpsoc->mpsoc_get_tile_param_setting($tile); my %params; #if ($setting eq 'Custom'){ %params= $top->top_get_custom_soc_param($tile); #}else{ # %params=$top->top_get_default_soc_param(); #} my $sw_path = "$sw_dir/tile$tile_num"; $verilator = $verilator.soc_generate_verilator ($soc,$sw_path,"tile_$tile",\%params); $tops{"Vtile$tile_num"}= "--top-module tile_$tile"; } save_file ("$target_verilator_dr/verilator_tiles.sv",$verilator); my $result = verilator_compilation (\%tops,$target_dir,$outtext,$cpu_num); $self->object_add_attribute('verilator','libs',\%tops); return $result; } sub gen_verilator_soc_testbench { my ($self,$name,$top,$target_dir)=@_; my $verilator="$target_dir/verilator"; my $dir="$verilator/"; my $soc_top= $self->soc_get_top (); my $include='#include #include #include #include '; my @intfcs=$soc_top->top_get_intfc_list(); my %PP; my %rxds; my $top_port_info="IO type\t port_size\t port_name\n"; foreach my $intfc (@intfcs){ my $key= ( $intfc eq 'plug:clk[0]')? 'clk' : ( $intfc eq 'plug:reset[0]')? 'reset': ( $intfc eq 'plug:enable[0]')? 'en' : ( $intfc eq 'socket:RxD_sim[0]')? 'rxd': 'other'; my $key1="${key}1"; my $key0="${key}0"; my @ports=$soc_top->top_get_intfc_ports_list($intfc); foreach my $p (@ports){ my($inst,$range,$type,$intfc_name,$intfc_port)= $soc_top->top_get_port($p); $PP{$key1}= (defined $PP{$key1})? "$PP{$key1} top->$p=1;\n" : "top->$p=1;\n"; $PP{$key0}= (defined $PP{$key0})? "$PP{$key0} top->$p=0;\n" : "top->$p=0;\n"; $top_port_info="$top_port_info $type $range top->$p \n"; } if($key eq 'rxd'){ my @ports=$soc_top->top_get_intfc_ports_list($intfc); foreach my $p (@ports){ my($id,$range,$type,$intfc_name,$intfc_port)= $soc_top->top_get_port($p); my @q =split (/RxD_ready_si/,$p); $rxds{$id}{p}=$q[0] if( defined $q[1]); $rxds{$id}{top}='top' if( defined $q[1]); } } } my ($rxd_info, $rxd_num, $rxd_wr_cal,$rxd_cap_cal, $include1)=rxd_testbench_verilator_gen (\%rxds,$dir); my $include2=""; $include2 .= '#include "RxDsim.h" // Header file for sending charactor to UART from STDIN' if($rxd_num > 0); my $main_c=get_license_header("testbench.cpp"); $main_c="$main_c $include $include1 #include // Defines common routines #include \"Vtop.h\" // From Verilating \"$name.v\" file Vtop *top; $include2 /* $top_port_info */ int reset,clk; unsigned int main_time = 0; // Current simulation time int main(int argc, char** argv) { $rxd_info Verilated::commandArgs(argc, argv); // Remember args top = new Vtop; /******************** * initialize input *********************/ $PP{reset1} $PP{en1} main_time=0; printf(\"Start Simulation\\n\"); while (!Verilated::gotFinish()) { $rxd_cap_cal if ((main_time & 0x3FF)==0) fflush(stdout); // fflush \$dispaly command each 1024 clock cycle if (main_time >= 10 ) { $PP{reset0} } if ((main_time & 1) == 0) { $PP{clk1} // Toggle clock // you can change the inputs and read the outputs here in case they are captured at posedge of clock $rxd_wr_cal }//if else { $PP{clk0} }//else main_time ++; top->eval(); } top->final(); } double sc_time_stamp () { // Called by \$time in Verilog return main_time; } "; save_file("$dir/testbench.cpp",$main_c); } sub eval_soc{ my ($mpsoc,$soc_name,$outtext)=@_; my $path=$mpsoc->object_get_attribute('setting','soc_path'); $path=~ s/ /\\ /g; my $p = "$path/$soc_name.SOC"; my ($soc,$r,$err) = regen_object($p); if ($r){ show_info($outtext,"**Error reading $p file: $err\n"); next; } return $soc; } sub rxd_testbench_verilator_gen { my ($rxds_ref,$dir)=@_; my $rxd_info=''; my $rxd_num=0; my $rxd_func=''; my $rxd_wr_cal=''; my $rxd_cap_cal=''; my $include=''; my %rxds=%{$rxds_ref}; foreach my $rxd (sort keys %rxds){ my $n=$rxds{$rxd}{p}; my $top=$rxds{$rxd}{top}; $rxd_info.="\\t$rxd_num : ${top}_${n}RXD\\n"; $rxd_func.=" // we have a character to send to interface $rxd_num if (sent_table[$rxd_num]!=0 && $top->${n}RxD_ready_sim){ $top->${n}RxD_din_sim=sent_table[$rxd_num]; $top->${n}RxD_wr_sim=1; sent_table[$rxd_num]=0; }else { $top->${n}RxD_wr_sim=0; } "; $rxd_num++; } if($rxd_num>0){ $rxd_func=" #ifndef RXD_SIM_H #define RXD_SIM_H #define RXD_NUM $rxd_num // number of rxd input interfaces char sent_table[RXD_NUM]={0}; unsigned char active_rxd_num=0; void write_char_on_RXD( ) { $rxd_func } int kbhit(void) { struct termios oldt, newt; int ch; int oldf; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); oldf = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); ch = getchar(); tcsetattr(STDIN_FILENO, TCSANOW, &oldt); fcntl(STDIN_FILENO, F_SETFL, oldf); if(ch != EOF) { ungetc(ch, stdin); return 1; } return 0; } void capture_char_on_RXD (){ char c; if(kbhit()){ c=getchar(); if(c=='+'){ active_rxd_num++; if(active_rxd_num>=$rxd_num) active_rxd_num=0; printf(\"The active input interface num is \%u\\n\",active_rxd_num); }else if(c=='-'){ active_rxd_num--; if(active_rxd_num>=$rxd_num) active_rxd_num=($rxd_num-1); printf(\"The active input interface num is \%u\\n\",active_rxd_num); }else{ sent_table[active_rxd_num]=c; } } } #endif "; $include .='#include #include '; $rxd_wr_cal="write_char_on_RXD( );"; $rxd_cap_cal="capture_char_on_RXD( );"; $rxd_info="printf(\"There are total of $rxd_num RXD (UART) interface ports in the top module:\\n${rxd_info}The default interfce is 0. You can switch to different interfaces by pressing + or - key.\\n\");" } my $rxsim_c=get_license_header("RxDsim.h"); $rxsim_c.="$rxd_func"; save_file("$dir/RxDsim.h",$rxsim_c) if($rxd_num > 0); return ($rxd_info, $rxd_num, $rxd_wr_cal,$rxd_cap_cal, $include); } sub gen_verilator_mpsoc_testbench { my ($mpsoc,$name,$top,$target_dir,$tview)=@_; my $verilator="$target_dir/verilator"; my $dir="$verilator/"; my $parameter_h=gen_noc_param_h($mpsoc); my ($nr,$ne,$router_p,$ref_tops,$includ_h)= get_noc_verilator_top_modules_info($mpsoc); $parameter_h.=" #define NE $ne #define NR $nr "; $parameter_h=$parameter_h.$includ_h; my $libh=""; my $inst= ""; my $newinst=""; my $tile_addr=""; my $tile_flit_in=""; my $tile_flit_in_l=""; my $tile_credit=""; my $noc_credit=""; my $noc_flit_in=""; my $noc_flit_in_l=""; my $noc_flit_in_wr=""; my $noc_flit_in_wr_l=""; my $tile_flit_in_wr=""; my $tile_flit_in_wr_l=""; my $tile_eval=""; my $tile_final=""; my $tile_reset=""; my $tile_clk=""; my $tile_en=""; my $top_port_info="IO type\t port_size\t port_name\n"; my $no_connected=''; my %rxds; my $tile_chans=""; my $tmp_reg=''; for (my $endp=0; $endp<$ne;$endp++){ my $e_addr=endp_addr_encoder($mpsoc,$endp); my $router_num = get_connected_router_id_to_endp($mpsoc,$endp); my $r_addr=router_addr_encoder($mpsoc,$router_num); my ($soc_name,$num)= $mpsoc->mpsoc_get_tile_soc_name($endp); if(defined $soc_name) {#we have a conncted tile #get ni instance name my $ni_name; my $soc=eval_soc($mpsoc,$soc_name,$tview); my $soc_top=$soc->object_get_attribute('top_ip',undef); my @intfcs=$soc_top->top_get_intfc_list(); my @instances=$soc->soc_get_all_instances(); foreach my $id (@instances){ my $category = $soc->soc_get_category($id); if ($category eq 'NoC') { $ni_name= $soc->soc_get_instance_name($id); } } $tile_chans.="\ttile_chan_out[$endp] = &tile$endp->ni_chan_out;\n\ttile_chan_in[$endp] = &tile$endp->ni_chan_in;\n"; $libh=$libh."#include \"Vtile${endp}.h\"\n"; $inst=$inst."Vtile${endp}\t*tile${endp};\t // Instantiation of tile${endp}\n"; $newinst = $newinst."\ttile${endp}\t=\tnew Vtile${endp};\n"; $tile_flit_in = $tile_flit_in . "\ttile${endp}->${ni_name}_flit_in = noc->ni_flit_out [${endp}];\n"; $tile_flit_in_l = $tile_flit_in_l . "\t\ttile${endp}->${ni_name}_flit_in[j] = noc->ni_flit_out [${endp}][j];\n"; $tile_credit= $tile_credit."\ttile${endp}->${ni_name}_credit_in= noc->ni_credit_out[${endp}];\n"; $noc_credit= $noc_credit."\tnoc->ni_credit_in[${endp}] = tile${endp}->${ni_name}_credit_out;\n"; $noc_flit_in=$noc_flit_in."\tnoc->ni_flit_in [${endp}] = tile${endp}->${ni_name}_flit_out;\n"; $noc_flit_in_l=$noc_flit_in_l."\t\t\tnoc->ni_flit_in [${endp}][j] = tile${endp}->${ni_name}_flit_out[j];\n"; $noc_flit_in_wr= $noc_flit_in_wr."\tif(tile${endp}->${ni_name}_flit_out_wr) noc->ni_flit_in_wr = noc->ni_flit_in_wr | ((vluint64_t)1<<${endp});\n"; $tile_flit_in_wr=$tile_flit_in_wr."\ttile${endp}->${ni_name}_flit_in_wr= ((noc->ni_flit_out_wr >> ${endp}) & 0x01);\n"; $noc_flit_in_wr_l= $noc_flit_in_wr_l."\tif(tile${endp}->${ni_name}_flit_out_wr) MY_VL_SETBIT_W(noc->ni_flit_in_wr ,${endp});\n"; $tile_flit_in_wr_l=$tile_flit_in_wr_l."\ttile${endp}->${ni_name}_flit_in_wr= (VL_BITISSET_W(noc->ni_flit_out_wr,${endp})>0);\n"; $tile_eval=$tile_eval."\ttile${endp}->eval();\n"; $tile_final=$tile_final."\ttile${endp}->final();\n"; foreach my $intfc (@intfcs){ my $key=($intfc eq 'plug:clk[0]')? 'clk' : ($intfc eq 'plug:reset[0]')? 'reset': ($intfc eq 'plug:enable[0]')? 'en' : ($intfc eq 'socket:RxD_sim[0]')? 'rxd': 'other'; my @ports=$soc_top->top_get_intfc_ports_list($intfc); foreach my $p (@ports){ my($inst,$range,$type,$intfc_name,$intfc_port)= $soc_top->top_get_port($p); $tile_reset=$tile_reset."\t\ttile${endp}->$p=reset;\n" if $key eq 'reset'; $tile_clk=$tile_clk."\t\ttile${endp}->$p=clk;\n" if $key eq 'clk'; $tile_en=$tile_en."\t\ttile${endp}->$p=enable;\n" if $key eq 'en'; ; $top_port_info="$top_port_info $type $range tile${endp}->$p \n"; }#ports if($key eq 'rxd'){ my @ports=$soc_top->top_get_intfc_ports_list($intfc); foreach my $p (@ports){ my($id,$range,$type,$intfc_name,$intfc_port)= $soc_top->top_get_port($p); my @q =split (/RxD_ready_si/,$p); $rxds{$endp.$id}{p}=$q[0] if( defined $q[1]); $rxds{$endp.$id}{top}="tile$endp" if( defined $q[1]); } } }#interface $tile_addr= $tile_addr."\ttile${endp}->${ni_name}_current_r_addr=$r_addr; // noc->er_addr[${endp}];\n"; $tile_addr= $tile_addr."\ttile${endp}->${ni_name}_current_e_addr=$e_addr;\n"; }else{ #this tile is not connected to any ip. the noc input ports will be connected to ground $tmp_reg.="\tunsigned char tmp1 [1024]={0};\n \tunsigned char tmp2 [1024]={0};"; $tile_chans.="\n // Tile:$endp ($e_addr) is not assigned to any ip. Connet coresponding chan to ground.\n"; $tile_chans.="\ttile_chan_out[$endp] = tmp1;\n\ttile_chan_in[$endp] = tmp2;\n"; } } my ($rxd_info, $rxd_num, $rxd_wr_cal,$rxd_cap_cal, $include1)=rxd_testbench_verilator_gen (\%rxds,$dir); my $include2=""; $include2 .= '#include "RxDsim.h" // Header file for sending charactor to UART from STDIN' if($rxd_num > 0); my $main_c=get_license_header("testbench.cpp"); $main_c="$main_c #include #include #include #include $include1 #include // Defines common routines $tmp_reg $libh $inst int reset,clk,enable; #include \"parameter.h\" void * tile_chan_out[NE]; void * tile_chan_in[NE]; #define CHAN_SIZE sizeof(tile0->ni_chan_in) #define conect_r2r(T1,r1,p1,T2,r2,p2) \\ memcpy(&router##T1 [r1]->chan_in[p1] , &router##T2 [r2]->chan_out[p2], CHAN_SIZE ) #define connect_r2gnd(T,r,p)\\ memset(&router##T [r]->chan_in [p],0x00,CHAN_SIZE) #define connect_r2e(T,r,p,e) \\ memcpy(&router##T [r]->chan_in[p], tile_chan_out[e], CHAN_SIZE );\\ memcpy(tile_chan_in[e], &router##T [r]->chan_out[p], CHAN_SIZE ) #include \"topology_top.h\" $include2 /* $top_port_info */ unsigned int main_time = 0; // Current simulation time void connect_clk_reset_en_all(void){ //clk,reset,enable $tile_reset $tile_clk $tile_en connect_routers_reset_clk(); } void sim_eval_all(void){ routers_eval(); $tile_eval } void sim_final_all(void ){ routers_final(); $tile_final } void clk_posedge_event(void) { clk = 1; // Toggle clock // you can change the inputs and read the outputs here in case they are captured at posedge of clock $rxd_wr_cal connect_clk_reset_en_all(); sim_eval_all(); } void clk_negedge_event(void){ clk = 0; topology_connect_all_nodes (); connect_clk_reset_en_all(); sim_eval_all(); } int main(int argc, char** argv) { int i,j,x,y; $rxd_info Verilated::commandArgs(argc, argv); // Remember args Vrouter_new(); // Create instance $newinst /******************** * initialize input *********************/ $tile_chans reset=1; enable=1; topology_init(); $no_connected $tile_addr main_time=0; printf(\"Start Simulation\\n\"); while (!Verilated::gotFinish()) { $rxd_cap_cal if ((main_time & 0x3FF)==0) fflush(stdout); // fflush \$dispaly command each 1024 clock cycle if (main_time >= 10 ) reset=0; clk_posedge_event( ); //The valus of all registers and input ports valuse change @ posedge of the clock. Once clk is deasserted, as multiple modules are connected inside the testbench we need several eval for propogating combinational logic values //between modules when the clock . for (i=0;i<2*(SMART_MAX+1);i++) clk_negedge_event( ); main_time++; }//while // Simulation is done sim_final_all(); } double sc_time_stamp () { // Called by \$time in Verilog return main_time; } "; save_file("$dir/parameter.h",$parameter_h); save_file("$dir/testbench.cpp",$main_c); } sub soc_get_all_parameters { my $soc=shift; my @instances=$soc->soc_get_all_instances(); my %all_param; foreach my $id (@instances){ my $module =$soc->soc_get_module($id); my $category =$soc->soc_get_category($id); my $inst = $soc->soc_get_instance_name($id); my %params = $soc->soc_get_module_param($id); my %params_type = $soc->soc_get_module_param_type($id); my $ip = ip->lib_new (); my @param_order=$soc->soc_get_instance_param_order($id); foreach my $p (sort keys %params){ my $inst_param= "$inst\_$p"; #add instance name to parameter value $params{$p}=add_instantc_name_to_parameters(\%params,$inst,$params{$p}); my ($default,$type,$content,$info,$vfile_param_type,$redefine_param)= $ip->ip_get_parameter($category,$module,$p); $vfile_param_type= "Don't include" if (!defined $vfile_param_type ); if ($vfile_param_type eq "Localparam"){ my $type = $params_type{$p}; $type = "Localparam" if (! defined $type); $vfile_param_type = ($type eq 'Parameter')? "Parameter" : "Localparam"; } #$vfile_param_type= "Parameter" if ($vfile_param_type eq 1); #$vfile_param_type= "Localparam" if ($vfile_param_type eq 0); $all_param{ $inst_param} = $params{ $p} if($vfile_param_type eq "Parameter" || $vfile_param_type eq "Localparam" ); #print"$all_param{ $inst_param} = $params{ $p} if($vfile_param_type eq \"Parameter\" || $vfile_param_type eq \"Localparam\" ); \n"; } } return %all_param; } sub soc_get_all_parameters_order { my $soc=shift; my @instances=$soc->soc_get_all_instances(); my $ip = ip->lib_new (); my @all_order; foreach my $id (@instances){ my $module =$soc->soc_get_module($id); my $category =$soc->soc_get_category($id); my $inst = $soc->soc_get_instance_name($id); my @order = $soc->soc_get_instance_param_order($id); my %params_type = $soc->soc_get_module_param_type($id); foreach my $p ( @order){ my $inst_param= "$inst\_$p"; my ($default,$type,$content,$info,$vfile_param_type,$redefine_param)= $ip->ip_get_parameter($category,$module,$p); $vfile_param_type= "Don't include" if (!defined $vfile_param_type ); if ($vfile_param_type eq "Localparam"){ my $type = $params_type{$p}; $type = "Localparam" if (! defined $type); $vfile_param_type = ($type eq 'Parameter')? "Parameter" : "Localparam"; } #$vfile_param_type= "Parameter" if ($vfile_param_type eq 1); #$vfile_param_type= "Localparam" if ($vfile_param_type eq 0); push(@all_order, $inst_param) if($vfile_param_type eq "Parameter" || $vfile_param_type eq "Localparam" ); } } return @all_order; } sub gen_modelsim_soc_testbench { my ($self,$name,$top,$target_dir,$tview)=@_; my $dir="$target_dir/Modelsim"; my $soc_top= $self->object_get_attribute('top_ip',undef); my @intfcs=$soc_top->top_get_intfc_list(); my %PP; my $top_port_def="// ${name}.v IO definition \n"; my $pin_assign; my $rst_inputs=''; #add functions my $project_dir = get_project_dir(); open my $file1, "<", "$project_dir/mpsoc/perl_gui/lib/verilog/functions.v" or die; my $functions_all=''; while (my $f1 = readline ($file1)) { $functions_all="$functions_all $f1 "; } close($file1); #get parameters my $params_v=""; my $n= $self->object_get_attribute('soc_name',undef); if(defined $n){ #we are compiling a single tile as SoC my $core_id= $self->object_get_attribute('global_param','CORE_ID'); my $sw_loc = $self->object_get_attribute('global_param','SW_LOC'); $params_v="\tlocalparam\tCORE_ID=$core_id; \tlocalparam\tSW_LOC=\"$sw_loc\";\n"; my %params=soc_get_all_parameters($self); my @order= soc_get_all_parameters_order($self); foreach my $p (@order){ add_text_to_string(\$params_v,"\tlocalparam $p = $params{$p};\n") if(defined $params{$p} ); } }else{ # we are simulating a mpsoc $params_v= gen_socs_param($self); } foreach my $intfc (@intfcs){ my $key= ( $intfc eq 'plug:clk[0]')? 'clk' : ( $intfc eq 'plug:reset[0]')? 'reset': ( $intfc eq 'plug:enable[0]')? 'en' : 'other'; my $key1="${key}1"; my $key0="${key}0"; my @ports=$soc_top->top_get_intfc_ports_list($intfc); my $f=1; foreach my $p (@ports){ my($inst,$range,$type,$intfc_name,$intfc_port)= $soc_top->top_get_port($p); $PP{$key1}= (defined $PP{$key1})? "$PP{$key1} $p=1;\n" : "$p=1;\n"; $PP{$key0}= (defined $PP{$key0})? "$PP{$key0} $p=0;\n" : "$p=0;\n"; if (length($range)!=0){ # #replace parameter with their values # # my @a= split (/\b/,$range); # print "a=@a\n"; # foreach my $l (@a){ # my $value=$params{$l}; # if(defined $value){ # chomp $value; # ($range=$range)=~ s/\b$l\b/$value/g if(defined $params{$l}); # print "($range=$range)=~ s/\b$l\b/$value/g if(defined $params{$l}); \n"; # } # } $range = "[ $range ]" ; } if($type eq 'input'){ $top_port_def="$top_port_def reg $range $p;\n" }else{ $top_port_def="$top_port_def wire $range $p;\n" } $pin_assign=(defined $pin_assign)? "$pin_assign,\n\t\t.$p($p)": "\t\t.$p($p)"; $rst_inputs= "$rst_inputs $p=0;\n" if ($key eq 'other' && $type eq 'input' ); } } my $global_localparam=get_golal_param_v(); my $test_v= get_license_header("testbench.v"); my $mpsoc_name=$self->object_get_attribute('mpsoc_name'); #if(defined $mpsoc_name){ if(0){ my $top_ip=ip_gen->top_gen_new(); my $target_dir = "$ENV{'PRONOC_WORK'}/MPSOC/$mpsoc_name"; my $hw_dir = "$target_dir/src_verilog"; my $sw_dir = "$target_dir/sw"; my ($socs_v,$io_short,$io_full,$top_io_short,$top_io_full,$top_io_pass,$href)=gen_socs_v($self,$top_ip,$sw_dir,$tview); my $socs_param= gen_socs_param($self); my $global_localparam=get_golal_param_v(); my ($clk_set, $clk_io_sim,$clk_io_full, $clk_assigned_port)= get_top_clk_setting($self); $test_v.=" $clk_set, $clk_io_sim,$clk_io_full, $clk_assigned_port `timescale 1ns/1ps module testbench; $functions_all $global_localparam $socs_param $top_port_def \t${mpsoc_name} the_${mpsoc_name} ( $top_io_pass \t); /*****************************************************************/ "; } $test_v ="$test_v `timescale 1ns/1ps module testbench; $functions_all $global_localparam $params_v $top_port_def $name uut ( $pin_assign ); //clock defination initial begin forever begin #5 $PP{clk0} #5 $PP{clk1} end end initial begin // reset $name module at the start up $PP{reset1} $PP{en1} $rst_inputs // deasert the reset after 200 ns #200 $PP{reset0} // write your testbench here end endmodule "; save_file("$dir/testbench.v",$test_v); } sub verilator_testbench{ my ($self,$name,$top,$target_dir,$vendor)=@_; my $verilator="$target_dir/verilator"; my $dir="$verilator"; my ($app,$table,$tview,$window) = software_main($dir,'testbench.cpp'); my $n= $self->object_get_attribute('soc_name',undef); if(defined $n){ #we are compiling a single tile as SoC gen_verilator_soc_testbench (@_) if((-f "$dir/testbench.cpp")==0); } else { # we are compiling a complete NoC-based mpsoc gen_verilator_mpsoc_testbench (@_,$tview) if((-f "$dir/testbench.cpp")==0); } #copy makefile #copy("../script/verilator_soc_make", "$verilator/obj_dir/Makefile"); my $make = def_image_button('icons/gen.png','Compile'); my $regen=def_image_button('icons/refresh.png','Regenerate Testbench.cpp'); my $run = def_image_button('icons/run.png','Run'); my $back=def_image_button('icons/left.png','Previous'); $table->attach ($back,1,2,1,2,'shrink','shrink',0,0); $table->attach ($regen,3,4,1,2,'shrink','shrink',0,0); $table->attach ($make,6, 7, 1,2,'shrink','shrink',0,0); $table->attach ($run,9, 10, 1,2,'shrink','shrink',0,0); $back-> signal_connect("clicked" => sub{ $window->destroy; verilator_compilation_win($self,$name,$top,$target_dir,$vendor); }); $regen-> signal_connect("clicked" => sub{ my $response = yes_no_dialog("Are you sure you want to regenerate the testbench.cpp file? Note that any changes you have made will be lost"); if ($response eq 'yes') { my $n= $self->object_get_attribute('soc_name',undef); if(defined $n){ #we are compiling a single tile as SoC gen_verilator_soc_testbench ($self,$name,$top,$target_dir); } else { # we are compiling a complete NoC-based mpsoc gen_verilator_mpsoc_testbench ($self,$name,$top,$target_dir,$tview); } $app->refresh_source("$dir/testbench.cpp"); } }); $make -> signal_connect("clicked" => sub{ $make->hide; my $load= show_gif("icons/load.gif"); $table->attach ($load,8, 9, 1,2,'shrink','shrink',0,0); $table->show_all; $app->ask_to_save_changes(); copy("$dir/testbench.cpp", "$verilator/obj_dir/testbench.cpp"); copy("$dir/parameter.h", "$verilator/obj_dir/parameter.h") if(-f "$dir/parameter.h"); copy("$dir/RxDsim.h", "$verilator/obj_dir/RxDsim.h") if(-f "$dir/RxDsim.h"); my $tops_ref=$self->object_get_attribute('verilator','libs'); my %tops=%{$tops_ref}; my $lib_num=0; my $cpu_num = $self->object_get_attribute('compile', 'cpu_num'); $cpu_num = 1 if (!defined $cpu_num); add_colored_info($tview,"Makefie will use the maximum number of $cpu_num core(s) in parallel for compilation\n",'green'); my $length=scalar (keys %tops); my $cmd=""; foreach my $top (sort keys %tops) { $cmd.= "lib$lib_num & "; $lib_num++; if( $lib_num % $cpu_num == 0 || $lib_num == $length){ $cmd.="wait\n"; run_make_file("$verilator/obj_dir/",$tview,$cmd); $cmd=""; }else { $cmd.=" make "; } } #foreach my $top (sort keys %tops) { # run_make_file("$verilator/obj_dir/",$tview,"lib$lib_num"); # $lib_num++; #} run_make_file("$verilator/obj_dir/",$tview,"sim"); $load->destroy; $make->show_all; }); $run -> signal_connect("clicked" => sub{ my $bin="$verilator/obj_dir/testbench"; if (-f $bin){ my $cmd= "cd \"$verilator/obj_dir/\" \n xterm -e bash -c \"$bin; sleep 5\""; add_info($tview,"$cmd\n"); my ($stdout,$exit,$stderr)=run_cmd_in_back_ground_get_stdout($cmd); if(length $stderr>1){ add_colored_info($tview,"$stderr\n",'red'); }else { add_info($tview,"$stdout\n"); } }else{ add_colored_info($tview,"Cannot find $bin executable binary file! make sure you have compiled the testbench successfully\n", 'red') } }); } 1;

Subversion Repositories an-fpga-implementation-of-low-latency-noc-based-mpsoc

[/] [an-fpga-implementation-of-low-latency-noc-based-mpsoc/] [trunk/] [mpsoc/] [perl_gui/] [lib/] [perl/] [compile.pl] - Blame information for rev 48

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.