#!usr/bin/perl -w # use the strict mode use strict; # Use the Shell enviornment #use Shell; # Use the time use Time::gmtime; # Use switch module #use Switch; use File::Path; use Cwd; use FileHandle; # Multi-thread support use threads; use threads::shared; # Date my $mydate = gmctime(); # Current Path my $cwd = getcwd(); # Global Variants # input Option Hash my %opt_h; my $opt_ptr = \%opt_h; # configurate file hash my %conf_h; my $conf_ptr = \%conf_h; # reports has my %rpt_h; my $rpt_ptr = \%rpt_h; # Benchmarks my @benchmark_names; my %benchmarks; my $benchmarks_ptr = \%benchmarks; my $verilog_benchmark; # Supported flows my @supported_flows = ("standard", "vtr_mccl", "mccl", "mig_mccl", "mpack2", "mpack1", "vtr", "vtr_standard", "yosys_vpr"); my %selected_flows; # Configuration file keywords list # Category for conf file. # main category : 1st class my @mctgy; # sub category : 2nd class my @sctgy; # Initialize these categories @mctgy = ("dir_path", "flow_conf", "csv_tags", ); # refer to the keywords of dir_path @{$sctgy[0]} = ("script_base", "benchmark_dir", "yosys_path", "odin2_path", "cirkit_path", "abc_mccl_path", "abc_path", "abc_with_bb_support_path", "mpack1_path", "m2net_path", "mpack2_path", "vpr_path", "rpt_dir", "ace_path", ); # refer to the keywords of flow_type @{$sctgy[1]} = ("flow_type", "vpr_arch", "mpack2_arch", "m2net_conf", "mpack1_abc_stdlib", "power_tech_xml", ); # refer to the keywords of csv_tags @{$sctgy[2]} = ("mpack1_tags", "mpack2_tags", "vpr_tags", "vpr_power_tags" ); my $clock_name = "avoid_clk_option"; # ----------Subrountines------------# # Print TABs and strings sub tab_print($ $ $) { my ($FILE,$str,$num_tab) = @_; my ($my_tab) = (" "); for (my $i = 0; $i < $num_tab; $i++) { print $FILE "$my_tab"; } print $FILE "$str"; } # Create paths if it does not exist. sub generate_path($) { my ($mypath) = @_; if (!(-e "$mypath")) { mkpath "$mypath"; print "Path($mypath) does not exist...Create it.\n"; } return 1; } # Print the usage sub print_usage() { print "Usage:\n"; print " fpga_flow [-options ]\n"; print " Mandatory options: \n"; print " -conf : specify the basic configuration files for fpga_flow\n"; print " -benchmark : the configuration file contains benchmark file names\n"; print " -rpt : CSV file consists of data\n"; print " -N : N-LUT/Matrix\n"; print " Other Options:\n"; print " [ General ] \n"; print " \t-I : Number of inputs of a CLB, mandatory when mpack1 flow is chosen\n"; print " \t-K : K-LUT, mandatory when standard flow is chosen\n"; print " \t-M : M-Matrix, mandatory when mpack1 flow is chosen\n"; print " \t-power : run power estimation oriented flow\n"; print " \t-black_box_ace: run activity estimation with black box support. It increase the power.\n"; print " \t-remove_designs: remove all the old results.\n"; print " \t-multi_thread : turn on the mutli-thread mode, specify the number of threads\n"; print " \t-multi_task : turn on the mutli-task mode\n"; print " \t-parse_results_only : only parse the flow results and write CSV report.\n"; print " \t-debug : debug mode\n"; print " \t-help : print usage\n"; print " [ ODIN II ] \n"; print " \t-min_hard_adder_size: min. size of hard adder in carry chain defined in Arch XML.(Default:1)\n"; print " \t-mem_size: size of memory, mandatory when VTR/VTR_MCCL/VTR_MIG_MCCL flow is chosen\n"; print " \t-odin2_carry_chain_support: turn on the carry_chain support only valid for VTR_MCCL/VTR_MIG_MCCL flow \n"; print " [ ABC ] \n"; print " \t-abc_scl : run ABC optimization for sequential circuits, mandatory when VTR flow is selected.\n"; print " \t-abc_verilog_rewrite : run ABC to convert a blif netlist to a Verilog netlist.\n"; print " [ ACE ] \n"; print " \t-ace_p : specify the default signal probablity of PIs in ACE2.\n"; print " \t-ace_d : specify the default signal density of PIs in ACE2.\n"; print " [ VPR - Original Version ] \n"; print " \t-vpr_timing_pack_off : turn off the timing-driven pack for vpr.\n"; print " \t-vpr_place_clb_pin_remap: turn on place_clb_pin_remap in VPR.\n"; print " \t-vpr_max_router_iteration : specify the max router iteration in VPR.\n"; print " \t-vpr_route_breadthfirst : use the breadth-first routing algorithm of VPR.\n"; print " \t-min_route_chan_width : turn on routing with * min_route_chan_width.\n"; print " \t-fix_route_chan_width : turn on routing with a fixed route_chan_width, defined in benchmark configuration file.\n"; print " [ VPR - FPGA-X2P Extension ] \n"; print " \t-vpr_fpga_x2p_rename_illegal_port : turn on renaming illegal ports option of VPR FPGA SPICE\n"; print " \t-vpr_fpga_x2p_signal_density_weight : specify the option signal_density_weight of VPR FPGA SPICE\n"; print " \t-vpr_fpga_x2p_sim_window_size : specify the option sim_window_size of VPR FPGA SPICE\n"; print " [ VPR - FPGA-SPICE Extension ] \n"; print " \t-vpr_fpga_spice : turn on SPICE netlists print-out in VPR, specify a task file\n"; print " \t-vpr_fpga_spice_sim_mt_num : specify the option sim_mt_num of VPR FPGA SPICE\n"; print " \t-vpr_fpga_spice_print_component_tb : print component-level testbenches in VPR FPGA SPICE\n"; print " \t-vpr_fpga_spice_print_grid_tb : print Grid-level testbenches in VPR FPGA SPICE\n"; print " \t-vpr_fpga_spice_print_top_tb : print full-chip testbench in VPR FPGA SPICE\n"; print " \t-vpr_fpga_spice_leakage_only : turn on leakage_only mode in VPR FPGA SPICE\n"; print " \t-vpr_fpga_spice_parasitic_net_estimation_off : turn off parasitic_net_estimation in VPR FPGA SPICE\n"; print " \t-vpr_fpga_spice_testbench_load_extraction_off : turn off testbench_load_extraction in VPR FPGA SPICE\n"; print " [ VPR - FPGA-Verilog Extension ] \n"; print " \t-vpr_fpga_verilog : turn on Verilog Generator of VPR FPGA SPICE\n"; print " \t-vpr_fpga_verilog_dir : provide the path where generated verilog files will be written\n"; print " \t-vpr_fpga_verilog_include_timing : turn on printing delay specification in Verilog files\n"; print " \t-vpr_fpga_verilog_include_signal_init : turn on printing signal initialization in Verilog files\n"; print " \t-vpr_fpga_verilog_print_autocheck_top_testbench: turn on printing autochecked top-level testbench for Verilog Generator of VPR FPGA SPICE\n"; print " \t-vpr_fpga_verilog_formal_verification_top_netlist : turn on printing formal top Verilog files\n"; print " \t-vpr_fpga_verilog_include_icarus_simulator : Add syntax and definition required to use Icarus Verilog simulator\n"; print " \t-vpr_fpga_verilog_print_user_defined_template : \n"; print " \t-vpr_fpga_verilog_print_report_timing_tcl : Generate tcl script useful for timing report generation\n"; print " \t-vpr_fpga_verilog_report_timing_rpt_path : Specify path for report timing\n"; print " \t-vpr_fpga_verilog_print_sdc_pnr : Generate sdc file to constraint Hardware P&R\n"; print " \t-vpr_fpga_verilog_print_sdc_analysis : Generate sdc file to do STA\n"; print " \t-vpr_fpga_verilog_print_top_tb : turn on printing top-level testbench for Verilog Generator of VPR FPGA SPICE\n"; print " \t-vpr_fpga_verilog_print_input_blif_tb : turn on printing testbench for input blif file in Verilog Generator of VPR FPGA SPICE\n"; print " \t-vpr_fpga_verilog_print_modelsim_autodeck : turn on printing modelsim simulation script\n"; print " [ VPR - FPGA-Bitstream Extension ] \n"; print " \t-vpr_fpga_bitstream_generator: turn on FPGA-SPICE bitstream generator\n"; exit(1); return 1; } sub spot_option($ $) { my ($start,$target) = @_; my ($arg_no,$flag) = (-1,"unfound"); for (my $iarg = $start; $iarg < $#ARGV+1; $iarg++) { if ($ARGV[$iarg] eq $target) { if ("found" eq $flag) { print "Error: Repeated Arguments!(IndexA: $arg_no,IndexB: $iarg)\n"; &print_usage(); } else { $flag = "found"; $arg_no = $iarg; } } } # return the arg_no if target is found # or return -1 when target is missing return $arg_no; } # Specify in the input list, # 1. Option Name # 2. Whether Option with value. if yes, choose "on" # 3. Whether Option is mandatory. If yes, choose "on" sub read_opt_into_hash($ $ $) { my ($opt_name,$opt_with_val,$mandatory) = @_; # Check the -$opt_name my ($opt_fact) = ("-".$opt_name); my ($cur_arg) = (0); my ($argfd) = (&spot_option($cur_arg,"$opt_fact")); if ($opt_with_val eq "on") { if (-1 != $argfd) { if ($ARGV[$argfd+1] =~ m/^-/) { print "The next argument cannot start with '-'!\n"; print "it implies an option!\n"; } else { $opt_ptr->{"$opt_name\_val"} = $ARGV[$argfd+1]; $opt_ptr->{"$opt_name"} = "on"; } } else { $opt_ptr->{"$opt_name"} = "off"; if ($mandatory eq "on") { print "Mandatory option: $opt_fact is missing!\n"; &print_usage(); } } } else { if (-1 != $argfd) { $opt_ptr->{"$opt_name"} = "on"; } else { $opt_ptr->{"$opt_name"} = "off"; if ($mandatory eq "on") { print "Mandatory option: $opt_fact is missing!\n"; &print_usage(); } } } return 1; } # Read options sub opts_read() { # if no arguments detected, print the usage. if (-1 == $#ARGV) { print "Error : No input arguments!\n"; print "Help desk:\n"; &print_usage(); exit(1); } # Read in the options my ($cur_arg,$arg_found); $cur_arg = 0; print "Analyzing your options...\n"; # Read the options with internal options my $argfd; # Check help fist $argfd = &spot_option($cur_arg,"-help"); if (-1 != $argfd) { print "Help desk:\n"; &print_usage(); } # Then Check the debug with highest priority $argfd = &spot_option($cur_arg,"-debug"); if (-1 != $argfd) { $opt_ptr->{"debug"} = "on"; } else { $opt_ptr->{"debug"} = "off"; } # Check mandatory options # Check the -conf # Read Opt into Hash(opt_ptr) : "opt_name","with_val","mandatory" &read_opt_into_hash("conf","on","on"); &read_opt_into_hash("benchmark","on","on"); &read_opt_into_hash("rpt","on","on"); &read_opt_into_hash("N","on","on"); &read_opt_into_hash("K","on","off"); &read_opt_into_hash("I","on","off"); &read_opt_into_hash("M","on","off"); &read_opt_into_hash("power","off","off"); &read_opt_into_hash("vpr_place_clb_pin_remap","off","off"); &read_opt_into_hash("black_box_ace","off","off"); &read_opt_into_hash("remove_designs","off","off"); &read_opt_into_hash("abc_scl","off","off"); &read_opt_into_hash("abc_verilog_rewrite","off","off"); &read_opt_into_hash("ace_p","on","off"); &read_opt_into_hash("ace_d","on","off"); &read_opt_into_hash("vpr_timing_pack_off","off","off"); &read_opt_into_hash("vpr_route_breadthfirst","off","off"); &read_opt_into_hash("min_route_chan_width","on","off"); &read_opt_into_hash("fix_route_chan_width","off","off"); &read_opt_into_hash("vpr_max_router_iteration","on","off"); &read_opt_into_hash("multi_task","on","off"); &read_opt_into_hash("multi_thread","on","off"); &read_opt_into_hash("parse_results_only","off","off"); # VTR/VTR_MCCL/VTR_MIG_MCCL flow options # Read Opt into Hash(opt_ptr) : "opt_name","with_val","mandatory" &read_opt_into_hash("min_hard_adder_size","on","off"); &read_opt_into_hash("mem_size","on","off"); &read_opt_into_hash("odin2_carry_chain_support","off","off"); # FPGA-SPICE options # Read Opt into Hash(opt_ptr) : "opt_name","with_val","mandatory" &read_opt_into_hash("vpr_fpga_spice","on","off"); &read_opt_into_hash("vpr_fpga_x2p_rename_illegal_port","off","off"); &read_opt_into_hash("vpr_fpga_x2p_signal_density_weight","on","off"); &read_opt_into_hash("vpr_fpga_x2p_sim_window_size","on","off"); &read_opt_into_hash("vpr_fpga_spice_sim_mt_num","on","off"); &read_opt_into_hash("vpr_fpga_spice_print_component_tb","off","off"); &read_opt_into_hash("vpr_fpga_spice_print_grid_tb","off","off"); &read_opt_into_hash("vpr_fpga_spice_print_top_tb","off","off"); &read_opt_into_hash("vpr_fpga_spice_leakage_only","off","off"); &read_opt_into_hash("vpr_fpga_spice_parasitic_net_estimation_off","off","off"); &read_opt_into_hash("vpr_fpga_spice_testbench_load_extraction_off","off","off"); &read_opt_into_hash("vpr_fpga_verilog","off","off"); &read_opt_into_hash("vpr_fpga_verilog_print_top_tb","off","off"); &read_opt_into_hash("vpr_fpga_verilog_print_input_blif_tb","off","off"); &read_opt_into_hash("vpr_fpga_bitstream_generator","off","off"); # AA add for update &read_opt_into_hash("vpr_fpga_verilog_print_autocheck_top_testbench","off","off"); &read_opt_into_hash("vpr_fpga_verilog_dir","on","off"); &read_opt_into_hash("vpr_fpga_verilog_print_modelsim_autodeck","on","off"); &read_opt_into_hash("vpr_fpga_verilog_include_timing","off","off"); &read_opt_into_hash("vpr_fpga_verilog_include_signal_init","off","off"); &read_opt_into_hash("vpr_fpga_verilog_formal_verification_top_netlist","off","off"); &read_opt_into_hash("vpr_fpga_verilog_include_icarus_simulator","off","off"); &read_opt_into_hash("vpr_fpga_verilog_print_report_timing_tcl","off","off"); &read_opt_into_hash("vpr_fpga_verilog_report_timing_rpt_path","on","off"); &read_opt_into_hash("vpr_fpga_verilog_print_sdc_pnr","off","off"); &read_opt_into_hash("vpr_fpga_verilog_print_sdc_analysis","off","off"); &read_opt_into_hash("vpr_fpga_verilog_print_user_defined_template","off","off"); &print_opts(); return 1; } # List the options sub print_opts() { print "List your options\n"; while(my ($key,$value) = each(%opt_h)) {print "$key : $value\n";} return 1; } # Read each line and ignore the comments which starts with given arg # return the valid information of line sub read_line($ $) { my ($line,$com) = @_; my @chars; if (defined($line)) { @chars = split/$com/,$line; if (!($line =~ m/[\w\d]/)) {$chars[0] = undef;} if ($line =~ m/^\s*$com/) {$chars[0] = undef;} } else {$chars[0] = undef;} if (defined($chars[0])) { $chars[0] =~ s/^(\s+)//g; $chars[0] =~ s/(\s+)$//g; } return $chars[0]; } # Check each keywords has been defined in configuration file sub check_keywords_conf() { for (my $imcg = 0; $imcg<$#mctgy+1; $imcg++) { for (my $iscg = 0; $iscg<$#{$sctgy[$imcg]}+1; $iscg++) { if (defined($conf_ptr->{$mctgy[$imcg]}->{$sctgy[$imcg]->[$iscg]}->{val})) { if ("on" eq $opt_ptr->{debug}) { print "Keyword($mctgy[$imcg],$sctgy[$imcg]->[$iscg]) = "; print "$conf_ptr->{$mctgy[$imcg]}->{$sctgy[$imcg]->[$iscg]}->{val}"; print "\n"; } } else {die "Error: Keyword($mctgy[$imcg],$sctgy[$imcg]->[$iscg]) is missing!\n";} } } return 1; } # Read the configuration file sub read_conf() { # Read in these key words my ($line,$post_line); my @equation; my $cur = "unknown"; open (CONF, "< $opt_ptr->{conf_val}") or die "Fail to open $opt_ptr->{conf_val}!\n"; print "Reading $opt_ptr->{conf_val}...\n"; while(defined($line = )) { chomp $line; $post_line = &read_line($line,"#"); if (defined($post_line)) { if ($post_line =~ m/\[(\w+)\]/) {$cur = $1;} elsif ("unknown" eq $cur) { die "Error: Unknown tags for this line!\n$post_line\n"; } else { $post_line =~ s/\s//g; @equation = split /=/,$post_line; $conf_ptr->{$cur}->{$equation[0]}->{val} = $equation[1]; } } } # Check these key words print "Read complete!\n"; &check_keywords_conf(); print "Checking these keywords..."; print "Successfully\n"; close(CONF); return 1; } sub read_benchmarks() { # Read in file names my ($line,$post_line,$cur); $cur = 0; open (FCONF,"< $opt_ptr->{benchmark_val}") or die "Fail to open $opt_ptr->{benchmark_val}!\n"; print "Reading $opt_ptr->{benchmark_val}...\n"; while(defined($line = )) { chomp $line; $post_line = &read_line($line,"#"); if (defined($post_line)) { $post_line =~ s/\s+//g; my @tokens = split(",",$post_line); # first is the benchmark name, #the second is the channel width, if applicable if ($tokens[0]) { $benchmark_names[$cur] = $tokens[0]; } else { die "ERROR: invalid definition for benchmarks!\n"; } $benchmarks_ptr->{"$benchmark_names[$cur]"}->{fix_route_chan_width} = $tokens[1]; $cur++; } } print "Benchmarks(total $cur):\n"; foreach my $temp(@benchmark_names) {print "$temp\n";} close(FCONF); return 1; } # Input program path is like "~/program_dir/program_name" # We split it from the scalar sub split_prog_path($) { my ($prog_path) = @_; my @path_elements = split /\//,$prog_path; my ($prog_dir,$prog_name); $prog_name = $path_elements[$#path_elements]; $prog_dir = $prog_path; $prog_dir =~ s/$prog_name$//g; return ($prog_dir,$prog_name); } sub check_blif_type($) { my ($blif) = @_; my ($line); open (BLIF, "< $blif") or die "Fail to open $blif!\n"; while(defined($line = )) { chomp $line; if ($line =~ /^\.latch/) { close(BLIF); return "seq"; } } close(BLIF); return "comb"; } # Check Options sub check_opts() { # Task 1: min_chan_width > 1 if (("on" eq $opt_ptr->{min_route_chan_width}) &&(1. > $opt_ptr->{min_route_chan_width_val})) { die "ERROR: Invalid -min_chan_width, should be at least 1.0!\n"; } # Task 2: check mandatory option when flow mpack1 is chosen if ("on" eq $selected_flows{"mpack1"}->{flow_status}) { if ("off" eq $opt_ptr->{M}) { die "ERROR: Option -M should be specified when flow mpack1 is selected!\n"; } if ("off" eq $opt_ptr->{I}) { die "ERROR: Option -I should be specified when flow mpack1 is selected!\n"; } } # Task 3: check mandatory options when flow vtr is chosen if ("on" eq $selected_flows{"vtr"}->{flow_status}) { if ("off" eq $opt_ptr->{mem_size}) { die "ERROR: Option -mem_size should be specified when flow vtr is selected\n"; } if ("off" eq $opt_ptr->{K}) { die "ERROR: Option -K should be specified when flow vtr is selected\n"; } if ("off" eq $opt_ptr->{abc_scl}) { die "ERROR: Option -abc_scl should be specified when flow vtr is selected\n"; } } # Task 3: check mandatory options when flow vtr_standard or standard is chosen if (("on" eq $selected_flows{"standard"}->{flow_status}) ||("on" eq $selected_flows{"vtr_standard"}->{flow_status})) { if ("off" eq $opt_ptr->{K}) { die "ERROR: Option -K should be specified when flow vtr_standard|standard is selected\n"; } } } # Run ABC with standard library mapping sub run_abc_libmap($ $ $) { my ($bm,$blif_out,$log) = @_; # Get ABC path my ($abc_dir,$abc_name) = &split_prog_path($conf_ptr->{dir_path}->{abc_path}->{val}); chdir $abc_dir; my ($mpack1_stdlib) = ($conf_ptr->{flow_conf}->{mpack1_abc_stdlib}->{val}); # Run MPACK ABC my ($abc_seq_optimize) = (""); if (("on" eq $opt_ptr->{abc_scl})&&("seq" eq &check_blif_type($bm))) { ($abc_seq_optimize) = ("scl -l;"); } # !!! For standard library, we cannot use sweep ??? system("./$abc_name -c \"read_blif $bm; resyn2; read_library $mpack1_stdlib; $abc_seq_optimize map -v; write_blif $blif_out; quit;\" > $log"); chdir $cwd; } # Rewrite the verilog after optimization sub run_rewrite_verilog($ $ $ $ $) { my ($blif, $path, $benchmark, $bm, $log) = @_; my ($new_verilog) = "$path/$benchmark".".v"; my ($cmd_log) = ($log); $cmd_log =~ s/\.log$/_rewrite_verilog\.ys/; # Get Yosys path my ($yosys_dir,$yosys_name) = &split_prog_path($conf_ptr->{dir_path}->{yosys_path}->{val}); print "Entering $yosys_dir\n"; chdir $yosys_dir; my ($lut_num) = $opt_ptr->{K_val}; # Create yosys synthesize script my ($YOSYS_CMD_FH) = (FileHandle->new); if ($YOSYS_CMD_FH->open("> $cmd_log")) { print "INFO: auto generating cmds for Yosys ($cmd_log) ...\n"; } else { die "ERROR: fail to auto generating cmds for Yosys ($cmd_log) ...\n"; } # Output the standard format (refer to VTR_flow script) print $YOSYS_CMD_FH "# Yosys rewriting verilog script for $bm\n"; print $YOSYS_CMD_FH "read_blif $blif\n"; print $YOSYS_CMD_FH "write_verilog $new_verilog\n"; close($YOSYS_CMD_FH); # # Create a local copy for the commands system("./$yosys_name $cmd_log > $log"); if (!(-e $new_verilog)) { die "ERROR: Yosys fail at rewriting benchmark $bm.\n"; } print "Leaving $yosys_dir\n"; chdir $cwd; return ($new_verilog); } # Run yosys synthesis with ABC LUT mapping sub run_yosys_fpgamap($ $ $ $) { my ($bm, $bm_path, $blif_out, $log) = @_; my ($cmd_log) = ($log); $cmd_log =~ s/log$/ys/; # Get Yosys path my ($yosys_dir,$yosys_name) = &split_prog_path($conf_ptr->{dir_path}->{yosys_path}->{val}); print "Entering $yosys_dir\n"; chdir $yosys_dir; my ($lut_num) = $opt_ptr->{K_val}; # Create yosys synthesize script my ($YOSYS_CMD_FH) = (FileHandle->new); if ($YOSYS_CMD_FH->open("> $cmd_log")) { print "INFO: auto generating cmds for Yosys ($cmd_log) ...\n"; } else { die "ERROR: fail to auto generating cmds for Yosys ($cmd_log) ...\n"; } # Output the standard format (refer to VTR_flow script) print $YOSYS_CMD_FH "# Yosys synthesis script for $bm\n"; print $YOSYS_CMD_FH "# read Verilog \n"; print $YOSYS_CMD_FH "read_verilog -nolatches $bm_path\n"; print $YOSYS_CMD_FH "\n"; print $YOSYS_CMD_FH "# Technology mapping\n"; print $YOSYS_CMD_FH "hierarchy -top $bm\n"; print $YOSYS_CMD_FH "proc\n"; print $YOSYS_CMD_FH "techmap -D NO_LUT -map +/adff2dff.v\n"; print $YOSYS_CMD_FH "\n"; print $YOSYS_CMD_FH "# Synthesis\n"; print $YOSYS_CMD_FH "synth -top $bm -flatten\n"; print $YOSYS_CMD_FH "clean\n"; print $YOSYS_CMD_FH "\n"; print $YOSYS_CMD_FH "# LUT mapping \n"; print $YOSYS_CMD_FH "abc -lut $lut_num\n"; print $YOSYS_CMD_FH "\n"; print $YOSYS_CMD_FH "# Check \n"; print $YOSYS_CMD_FH "synth -run check\n"; print $YOSYS_CMD_FH "\n"; print $YOSYS_CMD_FH "# Clean and output blif \n"; print $YOSYS_CMD_FH "opt_clean -purge\n"; print $YOSYS_CMD_FH "write_blif $blif_out\n"; close($YOSYS_CMD_FH); # # Create a local copy for the commands system("./$yosys_name -s $cmd_log > $log"); if (!(-e $blif_out)) { die "ERROR: Fail Yosys for benchmark $bm.\n"; } print "Leaving $yosys_dir\n"; chdir $cwd; } # Run ABC by FPGA-oriented synthesis sub run_abc_fpgamap($ $ $) { my ($bm,$blif_out,$log) = @_; my ($cmd_log) = ($log."cmd"); # Get ABC path my ($abc_dir,$abc_name) = &split_prog_path($conf_ptr->{dir_path}->{abc_path}->{val}); print "Entering $abc_dir\n"; chdir $abc_dir; my ($lut_num) = $opt_ptr->{K_val}; # Before we run this blif, identify it is a combinational or sequential my ($abc_seq_optimize) = (""); if (("on" eq $opt_ptr->{abc_scl})&&("seq" eq &check_blif_type($bm))) { ($abc_seq_optimize) = ("scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;"); } my ($fpga_synthesis_method) = ("if"); #my ($fpga_synthesis_method) = ("fpga"); # my ($dump_verilog) = (""); if ("on" eq $opt_ptr->{abc_verilog_rewrite}) { $dump_verilog = "write_verilog $bm.v"; } # Run FPGA ABC #`csh -cx './$abc_name -c \"read $bm; resyn2; $fpga_synthesis_method -K $lut_num; $abc_seq_optimize $abc_seq_optimize sweep; write_blif $blif_out; quit\" > $log'`; my ($ABC_CMD_FH) = (FileHandle->new); if ($ABC_CMD_FH->open("> $cmd_log")) { print "INFO: auto generating cmds for ABC ($cmd_log) ...\n"; } else { die "ERROR: fail to auto generating cmds for ABC ($cmd_log) ...\n"; } # Output the standard format (refer to VTR_flow script) print $ABC_CMD_FH "read $bm; resyn; resyn2; $fpga_synthesis_method -K $lut_num; $abc_seq_optimize write_blif $blif_out; $dump_verilog; quit\n"; close($ABC_CMD_FH); # # Create a local copy for the commands system("./$abc_name -F $cmd_log > $log"); if (!(-e $blif_out)) { die "ERROR: Fail ABC for benchmark $bm.\n"; } if (("on" eq $opt_ptr->{abc_verilog_rewrite})&&(!(-e "$bm.v"))) { die "ERROR: ABC verilog rewrite failed for benchmark $bm!\n"; } print "Leaving $abc_dir\n"; chdir $cwd; } # Run ABC by FPGA-oriented synthesis sub run_abc_bb_fpgamap($ $ $) { my ($bm,$blif_out,$log) = @_; # Get ABC path my ($abc_dir,$abc_name) = &split_prog_path($conf_ptr->{dir_path}->{abc_with_bb_support_path}->{val}); my ($lut_num) = $opt_ptr->{K_val}; # Before we run this blif, identify it is a combinational or sequential my ($abc_seq_optimize) = (""); if (("on" eq $opt_ptr->{abc_scl})&&("seq" eq &check_blif_type($bm))) { ($abc_seq_optimize) = ("scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;"); } my ($fpga_synthesis_method) = ("if"); #my ($fpga_synthesis_method) = ("fpga"); # my ($dump_verilog) = (""); if ("on" eq $opt_ptr->{abc_verilog_rewrite}) { $dump_verilog = "write_verilog $bm.v"; } chdir $abc_dir; # Run FPGA ABC system("./$abc_name -c \"read $bm; resyn; resyn2; $fpga_synthesis_method -K $lut_num; $abc_seq_optimize sweep; write_hie $bm $blif_out; $dump_verilog; quit;\" > $log"); if (!(-e $blif_out)) { die "ERROR: Fail ABC_with_bb_support for benchmark $bm.\n"; } if (("on" eq $opt_ptr->{abc_verilog_rewrite})&&(!(-e "$bm.v"))) { die "ERROR: ABC verilog rewrite failed for benchmark $bm!\n"; } chdir $cwd; } # Run ABC Carry-chain premapping by FPGA-oriented synthesis sub run_abc_mccl_fpgamap($ $ $) { my ($bm,$blif_out,$log) = @_; # Get ABC path my ($abc_mccl_dir,$abc_mccl_name) = &split_prog_path($conf_ptr->{dir_path}->{abc_mccl_path}->{val}); my ($abc_bb_dir,$abc_bb_name) = &split_prog_path($conf_ptr->{dir_path}->{abc_with_bb_support_path}->{val}); my ($lut_num) = $opt_ptr->{K_val}; # Before we run this blif, identify it is a combinational or sequential my ($abc_seq_optimize) = (""); if (("on" eq $opt_ptr->{abc_scl})&&("seq" eq &check_blif_type($bm))) { ($abc_seq_optimize) = ("scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;"); } my ($fpga_synthesis_method) = ("if"); #my ($fpga_synthesis_method) = ("fpga"); # Name the intermediate file my ($fadds_blif, $interm_blif) = ($blif_out, $blif_out); $fadds_blif =~ s/\.blif$/_fadds.blif/; $interm_blif =~ s/\.blif$/_interm.blif/; my ($min_chain_length) = (4); my ($mccl_opt_A, $mccl_opt_B, $mccl_opt_S) = (3, 3, 2); chdir $abc_mccl_dir; print "INFO: entering abc_mccl directory: $abc_mccl_dir \n"; # Run ABC three times: # 1st time: run abc_with_mccl: read the $bm and do carry-chain detection system("./$abc_mccl_name -c \"read $bm; strash; &get; &fadds -nv -N $min_chain_length; \&getspec; \&put; wfadds $fadds_blif; quit;\" > $log.ccdetect"); # Repeat chdir for multi-thread supporting! chdir $abc_mccl_dir; print "INFO: entering abc_mccl directory: $abc_mccl_dir \n"; # 2nd time: run abc_with_mccl: read the $fadds_blif and do carry-chain LUT premapping system("./$abc_mccl_name -c \"read $fadds_blif; resyn; resyn2; mccl -A $mccl_opt_A -B $mccl_opt_B -S $mccl_opt_S -K $lut_num -O 1 -r -o $interm_blif; quit;\" > $log.mccl"); chdir $abc_bb_dir; print "INFO: entering abc_with_bb_support directory: $abc_bb_dir \n"; # 3rd time: run abc_with_bb_support: read the pre-processed blif and do cleanup and recover system("./$abc_bb_name -c \"read $interm_blif; $abc_seq_optimize sweep; write_hie $interm_blif $blif_out; quit;\" > $log"); if (!(-e $blif_out)) { die "ERROR: Fail ABC_mccl_FPGA_mapping for benchmark $bm.\n"; } chdir $cwd; } # Run ABC MIG Carry-chain premapping by FPGA-oriented synthesis sub run_abc_mig_mccl_fpgamap($ $ $) { my ($bm,$blif_out,$log) = @_; # Get ABC path my ($abc_mig_mccl_dir,$abc_mig_mccl_name) = &split_prog_path($conf_ptr->{dir_path}->{cirkit_path}->{val}); my ($abc_mccl_dir,$abc_mccl_name) = &split_prog_path($conf_ptr->{dir_path}->{abc_mccl_path}->{val}); my ($abc_bb_dir,$abc_bb_name) = &split_prog_path($conf_ptr->{dir_path}->{abc_with_bb_support_path}->{val}); my ($lut_num) = $opt_ptr->{K_val}; # Before we run this blif, identify it is a combinational or sequential my ($abc_seq_optimize) = (""); if (("on" eq $opt_ptr->{abc_scl})&&("seq" eq &check_blif_type($bm))) { ($abc_seq_optimize) = ("scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;"); } my ($fpga_synthesis_method) = ("if"); #my ($fpga_synthesis_method) = ("fpga"); # Name the intermediate file my ($fadds_blif, $interm_blif) = ($bm, $bm); $fadds_blif =~ s/\.blif$/_fadds.blif/; $interm_blif =~ s/\.blif$/_interm.blif/; my ($min_chain_length) = (4); my ($mccl_opt_A, $mccl_opt_B, $mccl_opt_S) = (3, 3, 2); chdir $abc_mccl_dir; print "INFO: entering abc_mig_mccl directory: $abc_mccl_dir \n"; # Run ABC three times: # 1st time: run abc_with_mig_mccl: read the $bm and do carry-chain detection # TODO: unfinished!!!! system("./$abc_mig_mccl_name -c \"readv $bm; chains -C ; quit;\" > $log.ccdetect"); # Repeat chdir for multi-thread supporting! chdir $abc_mccl_dir; print "INFO: entering abc_mccl directory: $abc_mccl_dir \n"; # 2nd time: run abc_with_mccl: read the $fadds_blif and do carry-chain LUT premapping system("./$abc_mccl_name -c \"read $fadds_blif; resyn; resyn2; mccl -A $mccl_opt_A -B $mccl_opt_B -S $mccl_opt_S -K $lut_num -O 1 -r -o $interm_blif; quit;\" > $log.mccl"); chdir $abc_bb_dir; print "INFO: entering abc_with_bb_support directory: $abc_bb_dir \n"; # 3rd time: run abc_with_bb_support: read the pre-processed blif and do cleanup and recover system("./$abc_bb_name -c \"read $interm_blif; $abc_seq_optimize sweep; write_hie $interm_blif $blif_out; quit;\" > $log"); if (!(-e $blif_out)) { die "ERROR: Fail ABC_mccl_FPGA_mapping for benchmark $bm.\n"; } chdir $cwd; } sub run_mpack1p5($ $ $ $ $) { my ($blif_in,$blif_prefix,$matrix_size,$cell_size,$log) = @_; # Get MPACK path my ($mpack1_dir,$mpack1_name) = &split_prog_path($conf_ptr->{dir_path}->{mpack1_path}->{val}); chdir $mpack1_dir; # Run MPACK system("./$mpack1_name $blif_in $blif_prefix -matrix_depth $matrix_size -matrix_width $matrix_size -cell_size $cell_size > $log"); chdir $cwd; } sub run_mpack2($ $ $ $ $ $ $) { my ($blif_in,$blif_out,$mpack2_arch,$net,$stats,$vpr_arch,$log) = @_; # Get MPACK path my ($mpack2_dir,$mpack2_name) = &split_prog_path($conf_ptr->{dir_path}->{mpack2_path}->{val}); chdir $mpack2_dir; #my ($ble_arch) = ($conf_ptr->{flow_conf}->{mpack_ble_arch}->{val}); # Run MPACK system("./$mpack2_name -blif $blif_in -mpack_blif $blif_out -net $net -ble_arch $mpack2_arch -stats $stats -vpr_arch $vpr_arch > $log"); chdir $cwd; } # Extract Mpack2 stats sub extract_mpack2_stats($ $ $) { my ($tag,$bm,$mstats) = @_; my ($line); my @keywords = split /\|/,$conf_ptr->{csv_tags}->{mpack2_tags}->{val}; open (MSTATS, "< $mstats") or die "ERROR: Fail to open $mstats!\n"; while(defined($line = )) { chomp $line; $line =~ s/\s//g; foreach my $tmp(@keywords) { $tmp =~ s/\s//g; if ($line =~ m/$tmp\s*([0-9E\-\+.]+)/i) { $rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$opt_ptr->{K_val}}->{$tmp} = $1; } } } close(MSTATS); } # Extract Mpack1 stats sub extract_mpack1_stats($ $ $) { my ($tag,$bm,$mstats) = @_; my ($line); my @keywords = split /\|/,$conf_ptr->{csv_tags}->{mpack1_tags}->{val}; open (MSTATS, "< $mstats") or die "ERROR: Fail to open $mstats!\n"; while(defined($line = )) { chomp $line; $line =~ s/\s//g; foreach my $tmp(@keywords) { $tmp =~ s/\s//g; if ($line =~ m/$tmp\s*([0-9E\-\+.]+)/i) { $rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$opt_ptr->{M_val}}->{$tmp} = $1; } } } close(MSTATS); } # Black Box blif for ACE sub black_box_blif($ $) { my ($blif_in,$blif_out) = @_; my ($line); open (BF, "< $blif_in") or die "Fail to open $blif_in!\n"; open (NBF, "> $blif_out") or die "Fail to open $blif_out!\n"; while(defined($line = )) { chomp $line; my @components; if ($line =~ m/^\.names/) { @components = split /\s+/,$line; $line = ".subckt CELL "; for (my $i=1; $i < ($opt_ptr->{K_val}+1); $i++) { my $i1 = $i - 1; if ($i < $#components) { $line = $line."I[$i1]=$components[$i] "; } else { $line = $line."I[$i1]=unconn "; } } $line = $line."O[0]=$components[$#components] "; } print NBF "$line\n"; } # definition of Black box print NBF "\n"; print NBF ".model CELL\n"; print NBF ".inputs "; for (my $i=0; $i < $opt_ptr->{K_val}; $i++) { print NBF "I[$i] "; } print NBF "\n"; print NBF ".outputs O[0]\n"; print NBF ".blackbox\n"; print NBF ".end\n"; close(BF); close(NBF); } # Extract VPR Power Esti sub extract_vpr_power_esti($ $ $ $) { my ($tag,$ace_vpr_blif,$bm,$type) = @_; my ($line,$tmp,$line_num); my @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_power_tags}->{val}; my ($vpr_power_stats) = $ace_vpr_blif; $line_num = 0; $vpr_power_stats =~ s/blif$/power/; open (VSTATS, "< $vpr_power_stats") or die "Fail to open $vpr_power_stats!\n"; while(defined($line = )) { chomp $line; $line_num++; if ($line =~ m/^Total/i) { my @power_info = split /\s+/,$line; if ($#power_info < 3) { print "Error: (vpr_power_stats:$vpr_power_stats)ilegal definition at LINE[$line_num]!\n"; die "Format should be [tag] [Power] [Proposition] [Dynamic Proposition] [Method](Optional)\n"; } if ($power_info[3] > 1) { die "Error: (vpr_power_stats:$vpr_power_stats)Dynamic Power Proposition should not be greater than 1 at LINE[$line_num]!\n"; } $rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{power}->{total} = $power_info[1]; $rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{power}->{dynamic} = $power_info[1]*$power_info[3]; $rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{power}->{leakage} = $power_info[1]*(1-$power_info[3]); next; } $line =~ s/\s//g; foreach my $tmpkw(@keywords) { $tmp = $tmpkw; $tmp =~ s/\s//g; $tmp =~ s/\(/\\\(/g; $tmp =~ s/\)/\\\)/g; #print "$tmp\n"; if ($line =~ m/$tmp\s*([0-9E\-+.]+)/i) { $rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{power}->{$tmpkw} = $1; my @tempdata = split /\./,$rpt_ptr->{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{power}->{$tmpkw}; $rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{power}->{$tmpkw} = join('.',$tempdata[0],$tempdata[1]); $rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{power}->{$tmpkw} =~ s/0$//; } } } close(VSTATS); } # Extract AAPack stats sub extract_aapack_stats($ $ $ $ $) { my ($tag,$bm,$vstats,$type,$keywords) = @_; my ($line,$tmp); open (VSTATS, "< $vstats") or die "Fail to open $vstats!\n"; while(defined($line = )) { chomp $line; #$line =~ s/\s//g; foreach my $tmpkw(@{$keywords}) { $tmp = $tmpkw; $tmp =~ s/\(/\\\(/g; $tmp =~ s/\)/\\\)/g; if ($line =~ m/\s*([0-9E\-+.]+)\s+of\s+type\s+$tmpkw/i) { $rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{$tmpkw} = $1; $rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{$tmpkw} =~ s/\.$//; } } } close(VSTATS); } # Extract min_channel_width VPR stats sub extract_min_chan_width_vpr_stats($ $ $ $ $ $) { my ($tag,$bm,$vstats,$type,$min_route_chan_width,$parse_results) = @_; my ($line,$tmp, $min_chan_width, $chan_width_tag); my @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_tags}->{val}; if ("on" eq $min_route_chan_width) { $tmp = "Best routing used a channel width factor of"; $chan_width_tag = "min_route_chan_width"; } else { $tmp = "Circuit successfully routed with a channel width factor of"; $chan_width_tag = "fix_route_chan_width"; } $tmp =~ s/\s//g; open (VSTATS, "< $vstats") or die "ERROR: Fail to open $vstats!\n"; while(defined($line = )) { chomp $line; if (($line =~ m/\s+([0-9]+)\s+of\s+type\s+names/i) &&(1 == $parse_results)) { $rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{LUTs} = $1; $rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{LUTs} =~ s/\.$//; } $line =~ s/\s//g; if ($line =~ m/$tmp\s*([0-9E\-+.]+)/i) { $min_chan_width = $1; $min_chan_width =~ s/\.$//; if (1 == $parse_results) { $rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{$chan_width_tag} = $min_chan_width; } } } close(VSTATS); return $min_chan_width; } # Extract VPR stats sub extract_vpr_stats($ $ $ $) { my ($tag,$bm,$vstats,$type) = @_; my ($line,$tmp); my @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_tags}->{val}; open (VSTATS, "< $vstats") or die "Fail to open $vstats!\n"; while(defined($line = )) { chomp $line; if ($line =~ m/\s+([0-9]+)\s+of\s+type\s+names/i) { $rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{LUTs} = $1; $rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{LUTs} =~ s/\.$//; } $line =~ s/\s//g; foreach my $tmpkw(@keywords) { $tmp = $tmpkw; $tmp =~ s/\s//g; $tmp =~ s/\(/\\\(/g; $tmp =~ s/\)/\\\)/g; #print "$tmp\n"; if ($line =~ m/$tmp\s*([0-9E\-+.]+)/i) { $rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{$tmpkw} = $1; $rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{$tmpkw} =~ s/\.$//; } } } close(VSTATS); } sub gen_odin2_config_xml($ $ $ $ $ $) { my ($config_xml, $odin2_verilog, $odin2_blif_out, $vpr_arch, $mem_size, $min_hard_adder_size) = @_; # Open a filehandle my ($XMLFH) = (FileHandle->new); if ($XMLFH->open("> $config_xml")) { print "INFO: auto generating configuration XML for ODIN_II($config_xml) ...\n"; } else { die "ERROR: fail to auto generate configuration XML for ODIN_II($config_xml) ...\n"; } # Output the standard format (refer to VTR_flow script) print $XMLFH "\n"; print $XMLFH " \n"; print $XMLFH " $odin2_verilog\n"; print $XMLFH " \n"; print $XMLFH " \n"; print $XMLFH " blif\n"; print $XMLFH " $odin2_blif_out\n"; print $XMLFH " \n"; print $XMLFH " $vpr_arch\n"; print $XMLFH " \n"; print $XMLFH " \n"; print $XMLFH " \n"; print $XMLFH " \n"; print $XMLFH " \n"; print $XMLFH " \n"; print $XMLFH " \n"; print $XMLFH " \n"; print $XMLFH " .\n"; print $XMLFH " 1\n"; print $XMLFH " 1\n"; print $XMLFH " \n"; print $XMLFH "\n"; close($XMLFH); } sub run_odin2($ $ $) { my ($config_xml, $carry_chain_support, $log) = @_; my ($odin2_dir, $odin2_name) = &split_prog_path($conf_ptr->{dir_path}->{odin2_path}->{val}); my ($options) = (""); if ("on" eq $carry_chain_support) { $options = $options." -Z"; } chdir $odin2_dir; system("./$odin2_name -c $config_xml $options > $log"); chdir $cwd; } sub run_pro_blif_3arg($ $ $) { my ($abc_blif_out_bak, $abc_blif_out, $initial_blif) = @_; my ($pro_blif_path) = ($conf_ptr->{dir_path}->{script_base}->{val}); $pro_blif_path =~ s/\/$//g; $pro_blif_path = $pro_blif_path . "/pro_blif.pl"; `perl $pro_blif_path -i $abc_blif_out_bak -o $abc_blif_out -initial_blif $initial_blif`; if (!(-e $abc_blif_out)) { die "ERROR: Fail pro_blif.pl for benchmark $abc_blif_out.\n"; } return; } sub run_pro_blif($ $) { my ($abc_blif_out_bak, $abc_blif_out) = @_; my ($pro_blif_path) = ($conf_ptr->{dir_path}->{script_base}->{val}); $pro_blif_path =~ s/\/$//g; $pro_blif_path = $pro_blif_path . "/pro_blif.pl"; `perl $pro_blif_path -i $abc_blif_out_bak -o $abc_blif_out`; if (!(-e $abc_blif_out)) { die "ERROR: Fail pro_blif.pl for benchmark $abc_blif_out.\n"; } return; } # Run Acitivity Estimation sub run_ace($ $ $ $) { my ($mpack_vpr_blif,$act_file,$ace_new_blif,$log) = @_; my ($ace_dir,$ace_name) = &split_prog_path($conf_ptr->{dir_path}->{ace_path}->{val}); my ($ace_customized_opts) = (""); if ("on" eq $opt_ptr->{ace_d}) { $ace_customized_opts .= " -d $opt_ptr->{ace_d_val}"; } if ("on" eq $opt_ptr->{ace_p}) { $ace_customized_opts .= " -p $opt_ptr->{ace_p_val}"; } print "Entering $ace_dir\n"; chdir $ace_dir; system("./$ace_name -b $mpack_vpr_blif -o $act_file -n $ace_new_blif -c $clock_name $ace_customized_opts >> $log"); if (!(-e $ace_new_blif)) { die "ERROR: Fail ACE for benchmark $mpack_vpr_blif.\n"; } print "Leaving $ace_dir\n"; chdir $cwd; } sub run_std_vpr($ $ $ $ $ $ $ $ $) { my ($blif,$bm,$arch,$net,$place,$route,$fix_chan_width,$log,$act_file) = @_; my ($vpr_dir,$vpr_name) = &split_prog_path($conf_ptr->{dir_path}->{vpr_path}->{val}); chdir $vpr_dir; my ($power_opts); if ("on" eq $opt_ptr->{power}) { $power_opts = "--power --activity_file $act_file --tech_properties $conf_ptr->{flow_conf}->{power_tech_xml}->{val}"; } else { $power_opts = ""; } my ($packer_opts) = (""); if ("on" eq $opt_ptr->{vpr_timing_pack_off}) { $packer_opts = "--timing_driven_clustering off"; } my ($chan_width_opt) = (""); if (($fix_chan_width > 0)||($fix_chan_width == 0)) { $chan_width_opt = "-route_chan_width $fix_chan_width"; } # FPGA SPICE options my ($vpr_spice_opts) = (""); if (("on" eq $opt_ptr->{power})&&("on" eq $opt_ptr->{vpr_fpga_spice})) { $vpr_spice_opts = "--fpga_spice"; if ("on" eq $opt_ptr->{vpr_fpga_x2p_signal_density_weight}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_x2p_signal_density_weight $opt_ptr->{vpr_fpga_x2p_signal_density_weight_val}"; } if ("on" eq $opt_ptr->{vpr_fpga_x2p_sim_window_size}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_x2p_sim_window_size $opt_ptr->{vpr_fpga_x2p_sim_window_size_val}"; } if ("on" eq $opt_ptr->{vpr_fpga_spice_sim_mt_num}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_spice_sim_mt_num $opt_ptr->{vpr_fpga_spice_sim_mt_num_val}"; } if ("on" eq $opt_ptr->{vpr_fpga_spice_print_component_tb}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_spice_print_lut_testbench"; $vpr_spice_opts = $vpr_spice_opts." --fpga_spice_print_hardlogic_testbench"; $vpr_spice_opts = $vpr_spice_opts." --fpga_spice_print_pb_mux_testbench"; $vpr_spice_opts = $vpr_spice_opts." --fpga_spice_print_cb_mux_testbench"; $vpr_spice_opts = $vpr_spice_opts." --fpga_spice_print_sb_mux_testbench"; } if ("on" eq $opt_ptr->{vpr_fpga_spice_print_grid_tb}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_spice_print_grid_testbench"; $vpr_spice_opts = $vpr_spice_opts." --fpga_spice_print_cb_testbench"; $vpr_spice_opts = $vpr_spice_opts." --fpga_spice_print_sb_testbench"; } if ("on" eq $opt_ptr->{vpr_fpga_spice_print_top_tb}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_spice_print_top_testbench"; } if ("on" eq $opt_ptr->{vpr_fpga_spice_leakage_only}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_spice_leakage_only"; } if ("on" eq $opt_ptr->{vpr_fpga_spice_parasitic_net_estimation_off}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_spice_parasitic_net_estimation off"; } if ("on" eq $opt_ptr->{vpr_fpga_spice_testbench_load_extraction_off}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_spice_testbench_load_extraction off"; } } # FPGA Verilog options if (("on" eq $opt_ptr->{power})&&("on" eq $opt_ptr->{vpr_fpga_verilog})) { $vpr_spice_opts = $vpr_spice_opts." --fpga_verilog"; if ("on" eq $opt_ptr->{vpr_fpga_verilog_dir}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_verilog_dir $opt_ptr->{vpr_fpga_verilog_dir_val}"; } if ("on" eq $opt_ptr->{vpr_fpga_verilog_print_top_tb}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_verilog_print_top_testbench"; } if ("on" eq $opt_ptr->{vpr_fpga_verilog_print_input_blif_tb}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_verilog_print_input_blif_testbench"; } if ("on" eq $opt_ptr->{vpr_fpga_verilog_print_autocheck_top_testbench}) { if($verilog_benchmark eq undef){ $vpr_spice_opts = $vpr_spice_opts." --fpga_verilog_print_autocheck_top_testbench $conf_ptr->{dir_path}->{benchmark_dir}->{val}"."/$bm/$bm.v"; } else { $vpr_spice_opts = $vpr_spice_opts." --fpga_verilog_print_autocheck_top_testbench $verilog_benchmark"; } } if ("on" eq $opt_ptr->{vpr_fpga_verilog_include_timing}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_verilog_include_timing"; } if ("on" eq $opt_ptr->{vpr_fpga_verilog_include_signal_init}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_verilog_include_signal_init"; } if ("on" eq $opt_ptr->{vpr_fpga_verilog_formal_verification_top_netlist}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_verilog_print_formal_verification_top_netlist"; } if ("on" eq $opt_ptr->{vpr_fpga_verilog_print_modelsim_autodeck}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_verilog_print_modelsim_autodeck $opt_ptr->{vpr_fpga_verilog_print_modelsim_autodeck_val}"; } if ("on" eq $opt_ptr->{vpr_fpga_verilog_include_icarus_simulator}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_verilog_include_icarus_simulator"; } if ("on" eq $opt_ptr->{vpr_fpga_verilog_print_report_timing_tcl}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_verilog_print_report_timing_tcl"; } if ("on" eq $opt_ptr->{vpr_fpga_verilog_report_timing_rpt_path}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_verilog_report_timing_rpt_path $opt_ptr->{vpr_fpga_verilog_report_timing_rpt_path_val}"; } if ("on" eq $opt_ptr->{vpr_fpga_verilog_print_sdc_pnr}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_verilog_print_sdc_pnr"; } if ("on" eq $opt_ptr->{vpr_fpga_verilog_print_user_defined_template}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_verilog_print_user_defined_template"; } if ("on" eq $opt_ptr->{vpr_fpga_verilog_print_sdc_analysis}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_verilog_print_sdc_analysis"; } } # FPGA Bitstream Generator Options if ("on" eq $opt_ptr->{vpr_fpga_bitstream_generator}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_bitstream_generator"; } if (("on" eq $opt_ptr->{vpr_fpga_x2p_rename_illegal_port}) || ("on" eq $opt_ptr->{vpr_fpga_spice}) || ("on" eq $opt_ptr->{vpr_fpga_verilog})) { $vpr_spice_opts = $vpr_spice_opts." --fpga_x2p_rename_illegal_port"; } my ($other_opt) = (""); if ("on" eq $opt_ptr->{vpr_place_clb_pin_remap}) { $other_opt = "--place_clb_pin_remap "; } if ("on" eq $opt_ptr->{vpr_route_breadthfirst}) { $other_opt .= "--router_algorithm breadth_first "; } if ("on" eq $opt_ptr->{vpr_max_router_iteration}) { $other_opt .= "--max_router_iterations $opt_ptr->{vpr_max_router_iteration_val} "; } system("./$vpr_name $arch $blif --net_file $net --place_file $place --route_file $route --full_stats --nodisp $power_opts $packer_opts $chan_width_opt $vpr_spice_opts $other_opt > $log"); chdir $cwd; } sub run_vpr_route($ $ $ $ $ $ $ $ $) { my ($blif,$bm,$arch,$net,$place,$route,$fix_chan_width,$log,$act_file) = @_; my ($vpr_dir,$vpr_name) = &split_prog_path($conf_ptr->{dir_path}->{vpr_path}->{val}); chdir $vpr_dir; my ($power_opts); if ("on" eq $opt_ptr->{power}) { $power_opts = "--power --activity_file $act_file --tech_properties $conf_ptr->{flow_conf}->{power_tech_xml}->{val}"; } else { $power_opts = ""; } my ($chan_width_opt) = (""); if (($fix_chan_width > 0)||($fix_chan_width == 0)) { $chan_width_opt = "-route_chan_width $fix_chan_width"; } my ($vpr_spice_opts) = (""); if (("on" eq $opt_ptr->{power})&&("on" eq $opt_ptr->{vpr_fpga_spice})) { $vpr_spice_opts = "--fpga_spice"; if ("on" eq $opt_ptr->{vpr_fpga_spice_print_cbsbtb}) { $vpr_spice_opts = $vpr_spice_opts." --print_spice_cb_mux_testbench"; $vpr_spice_opts = $vpr_spice_opts." --print_spice_sb_mux_testbench"; } if ("on" eq $opt_ptr->{vpr_fpga_spice_print_pbtb}) { $vpr_spice_opts = $vpr_spice_opts." --print_spice_pb_mux_testbench"; $vpr_spice_opts = $vpr_spice_opts." --print_spice_lut_testbench"; $vpr_spice_opts = $vpr_spice_opts." --print_spice_hardlogic_testbench"; } if ("on" eq $opt_ptr->{vpr_fpga_spice_print_gridtb}) { $vpr_spice_opts = $vpr_spice_opts." --print_spice_grid_testbench"; } if ("on" eq $opt_ptr->{vpr_fpga_spice_print_toptb}) { $vpr_spice_opts = $vpr_spice_opts." --print_spice_top_testbench"; } if ("on" eq $opt_ptr->{vpr_fpga_spice_leakage_only}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_spice_leakage_only"; } if ("on" eq $opt_ptr->{vpr_fpga_spice_parasitic_net_estimation_off}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_spice_parasitic_net_estimation_off"; } } if ("on" eq $opt_ptr->{vpr_fpga_verilog}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_verilog"; if ("on" eq $opt_ptr->{vpr_fpga_x2p_rename_illegal_port}) { $vpr_spice_opts = $vpr_spice_opts." --fpga_x2p_rename_illegal_port"; } } my ($other_opt) = (""); if ("on" eq $opt_ptr->{vpr_max_router_iteration}) { $other_opt .= "--max_router_iterations $opt_ptr->{vpr_max_router_iteration_val} "; } if ("on" eq $opt_ptr->{vpr_route_breadthfirst}) { $other_opt .= "--router_algorithm breadth_first "; } system("./$vpr_name $arch $blif --route --blif_file $blif --net_file $net --place_file $place --route_file $route --full_stats --nodisp $power_opts $chan_width_opt $vpr_spice_opts $other_opt > $log"); chdir $cwd; } sub run_mpack1_vpr($ $ $ $ $ $ $) { my ($blif,$arch,$net,$place,$route,$log,$act_file) = @_; my ($vpr_dir,$vpr_name) = &split_prog_path($conf_ptr->{dir_path}->{vpr_path}->{val}); my ($power_opts) = (""); if ("on" eq $opt_ptr->{power}) { $power_opts = "--power --activity_file $act_file --tech_properties $conf_ptr->{flow_conf}->{power_tech_xml}->{val}"; } chdir $vpr_dir; system("./$vpr_name $arch $blif --net_file $net --place_file $place --route_file $route --place --route --full_stats --nodisp $power_opts > $log"); chdir $cwd; } sub run_mpack2_vpr($ $ $ $ $ $ $) { my ($blif,$arch,$net,$place,$route,$min_chan_width,$log) = @_; my ($vpr_dir,$vpr_name) = &split_prog_path($conf_ptr->{dir_path}->{vpr_path}->{val}); my ($power_opts) = (""); if ("on" eq $opt_ptr->{power}) { # $power_opts = "--power --activity_file $act_file --tech_properties $conf_ptr->{flow_conf}->{power_tech_xml}->{val}"; } my ($chan_width_opt) = (""); if (($min_chan_width > 0)||($min_chan_width == 0)) { $min_chan_width = int($min_chan_width*1.2); if (0 != $min_chan_width%2) { $min_chan_width += 1; } $chan_width_opt = "-route_chan_width $min_chan_width"; } chdir $vpr_dir; system("./$vpr_name $arch $blif --net_file $net --place_file $place --route_file $route --place --route --full_stats --nodisp $power_opts $chan_width_opt > $log"); chdir $cwd; } sub run_aapack($ $ $ $) { my ($blif,$arch,$net,$aapack_log) = @_; my ($vpr_dir,$vpr_name) = &split_prog_path($conf_ptr->{dir_path}->{vpr_path}->{val}); chdir $vpr_dir; system("./$vpr_name $arch $blif --net_file $net --pack --timing_analysis off --nodisp > $aapack_log"); chdir $cwd; } sub run_m2net_pack_arch($ $ $ $ $ $) { my ($m2net_conf,$mpack1_rpt,$pack_arch,$N,$I,$m2net_pack_arch_log) = @_; my ($m2net_dir,$m2net_name) = &split_prog_path($conf_ptr->{dir_path}->{m2net_path}->{val}); chdir $m2net_dir; system("perl $m2net_name -conf $m2net_conf -mpack1_rpt $mpack1_rpt -mode pack_arch -N $N -I $I -arch_file_pack $pack_arch > $m2net_pack_arch_log"); chdir $cwd; } sub run_m2net_m2net($ $ $ $ $) { my ($m2net_conf,$mpack1_rpt,$aapack_net,$vpr_net,$vpr_arch,$N,$I,$m2net_m2net_log) = @_; my ($m2net_dir,$m2net_name) = &split_prog_path($conf_ptr->{dir_path}->{m2net_path}->{val}); chdir $m2net_dir; my ($power_opt) = (""); if ("on" eq $opt_ptr->{power}) { $power_opt = "-power"; } system("perl $m2net_name -conf $m2net_conf -mpack1_rpt $mpack1_rpt -mode m2net -N $N -I $I -net_file_in $aapack_net -net_file_out $vpr_net -arch_file_vpr $vpr_arch $power_opt > $m2net_m2net_log"); chdir $cwd; } sub run_cirkit_mig_mccl_map($ $ $) { my ($bm,$blif_out,$log) = @_; my ($bm_aig, $bm_v) = ($blif_out, $blif_out); my ($abc_cmd_log, $cirkit_cmd_log) = ($blif_out, $blif_out); $bm_aig =~ s/blif$/aig/; $bm_v =~ s/blif$/v/; $abc_cmd_log =~ s/\.blif$/_abc.cmd/g; $cirkit_cmd_log =~ s/\.blif$/_cirkit.cmd/g; # Get ABC path my ($abc_dir,$abc_name) = &split_prog_path($conf_ptr->{dir_path}->{abc_path}->{val}); # Get Cirkit path my ($cirkit_dir,$cirkit_name) = &split_prog_path($conf_ptr->{dir_path}->{cirkit_path}->{val}); my ($lut_num) = $opt_ptr->{K_val}; # Before we run this blif, identify it is a combinational or sequential my ($abc_seq_optimize) = (""); if (("on" eq $opt_ptr->{abc_scl})&&("seq" eq &check_blif_type($bm))) { ($abc_seq_optimize) = ("scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;scleanup;"); } my ($fpga_synthesis_method) = ("if"); #my ($fpga_synthesis_method) = ("fpga"); my ($ABC_CMD_FH) = (FileHandle->new); if ($ABC_CMD_FH->open("> $abc_cmd_log")) { print "INFO: auto generating cmds for ABC ($abc_cmd_log) ...\n"; } else { die "ERROR: fail to auto generating cmds for ABC ($abc_cmd_log) ...\n"; } # Output the standard format (refer to VTR_flow script) print $ABC_CMD_FH "read_blif $bm; strash; write $bm_aig; quit;\n"; close($ABC_CMD_FH); # Run ABC to rewrite blif to AIG in verilog format chdir $abc_dir; system("./$abc_name -F $abc_cmd_log > $log"); if (!(-e $bm_aig)) { die "ERROR: Fail ABC for benchmark $bm.\n"; } my ($CIRKIT_CMD_FH) = (FileHandle->new); if ($CIRKIT_CMD_FH->open("> $cirkit_cmd_log")) { print "INFO: auto generating cmds for Cirkit ($cirkit_cmd_log) ...\n"; } else { die "ERROR: fail to auto generating cmds for Cirkit ($cirkit_cmd_log) ...\n"; } # Output the standard format (refer to VTR_flow script) print $CIRKIT_CMD_FH "read_aiger $bm_aig; xmglut -k 4; write_verilog -x $bm_v; read_verilog -x --as_mig $bm_v; fpga --blif_name $blif_out; quit;\n"; close($CIRKIT_CMD_FH); chdir $cirkit_dir; # Run FPGA ABC system("./$cirkit_name -f $cirkit_cmd_log >> $log"); if (!(-e $blif_out)) { die "ERROR: Fail Cirkit for benchmark $bm.\n"; } chdir $cwd; } sub init_fpga_spice_task($) { my ($task_file) = @_; my ($task_dir_path, $task_filename) = &split_prog_path($task_file); &generate_path($task_dir_path); # Open the task file handler my ($TASKFH) = (FileHandle->new); if ($TASKFH->open("> $task_file")) { print "Initializing FPGA SPICE task file($task_file)...\n"; } else { die "ERROR: fail to create task file ($task_file)!\n"; } print $TASKFH "# FPGA SPICE TASKs to run\n"; print $TASKFH "# Task line format:\n"; print $TASKFH "# ,,\n"; # Close the file handler close($TASKFH); } # Print a line into task file which contains task info of FPGA SPICE. sub output_fpga_spice_task($ $ $ $) { my ($task_file, $benchmark, $blif_name, $rpt_dir) = @_; my ($blif_path, $blif_prefix, $spice_dir); # Open the task file handler my ($TASKFH) = (FileHandle->new); if ($TASKFH->open(">> $task_file")) { } else { die "ERROR: fail to generate a line for task($benchmark) in task file ($task_file) ...\n"; } ($blif_path,$blif_prefix) = &split_prog_path($blif_name); $blif_prefix =~ s/\.blif$//; $spice_dir = $rpt_dir; $spice_dir =~ s/\/$//; $spice_dir = $spice_dir."/spice_netlists/"; # Output a line print $TASKFH "# TaskInfo: $benchmark\n"; print $TASKFH "$benchmark,$blif_prefix,$spice_dir\n"; # Close the file handler close($TASKFH); } sub run_ace_in_flow($ $ $ $ $ $ $) { my ($prefix, $abc_blif_out, $act_file,$ace_new_blif,$ace_log) = @_; if ("on" eq $opt_ptr->{power}) { if ("on" eq $opt_ptr->{black_box_ace}) { my ($tmp_blif) = ($prefix."_ace_new.blif"); &black_box_blif($abc_blif_out,$tmp_blif); &run_ace($tmp_blif,$act_file,$ace_new_blif ,$ace_log); } else { &run_ace($abc_blif_out,$act_file,$ace_new_blif,$ace_log); } #&run_pro_blif($ace_new_blif, $abc_blif_out); } if (("on" eq $opt_ptr->{power})&&(!(-e $act_file))) { die "ERROR: Fail ACE2 for benchmark $act_file.\n"; } } sub run_vpr_in_flow($ $ $ $ $ $ $ $ $ $ $ $) { my ($tag, $benchmark,$benchmark_file, $abc_blif_out, $vpr_arch, $act_file, $vpr_net, $vpr_place, $vpr_route, $vpr_log, $vpr_reroute_log, $parse_results) = @_; if ("on" eq $opt_ptr->{min_route_chan_width}) { &run_std_vpr($abc_blif_out,$benchmark,$vpr_arch,$vpr_net,$vpr_place,$vpr_route,-1,$vpr_log.".min_chan_width",$act_file); # Get the Minimum channel width my ($min_chan_width) = (&extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log.".min_chan_width",$opt_ptr->{K_val}, $opt_ptr->{min_route_chan_width}, $parse_results)); $min_chan_width = int($min_chan_width*$opt_ptr->{min_route_chan_width_val}); if (0 != $min_chan_width%2) { $min_chan_width += 1; } # Remove previous route results if (-e $vpr_route) { `rm $vpr_route`; } # Keep increase min_chan_width until route success # Extract data from VPR stats #&run_std_vpr($abc_blif_out,$benchmark,$vpr_arch,$vpr_net,$vpr_place,$vpr_route,$min_chan_width,$vpr_log,$act_file); while (1) { &run_vpr_route($abc_blif_out,$benchmark,$vpr_arch,$vpr_net,$vpr_place,$vpr_route,$min_chan_width,$vpr_reroute_log,$act_file); # TODO: Only run the routing stage if (-e $vpr_route) { print "INFO: try route_chan_width($min_chan_width) success!\n"; last; #Jump out } else { print "INFO: try route_chan_width($min_chan_width) failed! Retry with +2...\n"; $min_chan_width += 2; } } if (1 == $parse_results) { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val}, "off", $parse_results); &extract_vpr_stats($tag,$benchmark,$vpr_log.".min_chan_width",$opt_ptr->{K_val}); &extract_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val}); } } elsif ("on" eq $opt_ptr->{fix_route_chan_width}) { my ($fix_chan_width) = ($benchmarks_ptr->{$benchmark_file}->{fix_route_chan_width}); # Remove previous route results if (-e $vpr_route) { `rm $vpr_route`; } # Keep increase min_chan_width until route success &run_std_vpr($abc_blif_out,$benchmark,$vpr_arch,$vpr_net,$vpr_place,$vpr_route,$fix_chan_width,$vpr_log,$act_file); while (1) { # TODO: Only run the routing stage if (-e $vpr_route) { print "INFO: try route_chan_width($fix_chan_width) success!\n"; last; #Jump out } else { print "INFO: try route_chan_width($fix_chan_width) failed! Retry with +2...\n"; $fix_chan_width += 2; &run_vpr_route($abc_blif_out,$benchmark,$vpr_arch,$vpr_net,$vpr_place,$vpr_route,$fix_chan_width,$vpr_reroute_log,$act_file); } } # Extract data from VPR stats if (1 == $parse_results) { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}, "off", $parse_results); &extract_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}); if (-e $vpr_reroute_log) { &extract_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val}); } } } else { &run_std_vpr($abc_blif_out,$benchmark,$vpr_arch,$vpr_net,$vpr_place,$vpr_route,-1,$vpr_log,$act_file); if (!(-e $vpr_route)) { die "ERROR: Route Fail for $abc_blif_out!\n"; } # Get the Minimum channel width my ($min_chan_width) = (&extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val},"on",$parse_results)); if (1 == $parse_results) { &extract_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}); } } # Extract data from VPR Power stats if (("on" eq $opt_ptr->{power}) &&(1 == $parse_results)) { &extract_vpr_power_esti($tag,$abc_blif_out,$benchmark,$opt_ptr->{K_val}); } return; } sub run_mig_mccl_flow($ $ $ $) { my ($tag,$benchmark_file,$vpr_arch, $parse_results) = @_; my ($benchmark, $rpt_dir,$prefix); my ($cirkit_bm,$cirkit_blif_out,$cirkit_log,$cirkit_blif_out_bak); $benchmark = $benchmark_file; $benchmark =~ s/\.blif$//g; # Run Standard flow $rpt_dir = "$conf_ptr->{dir_path}->{rpt_dir}->{val}"."/$benchmark/$tag"; &generate_path($rpt_dir); $cirkit_bm = "$conf_ptr->{dir_path}->{benchmark_dir}->{val}"."/$benchmark".".blif"; $prefix = "$rpt_dir/$benchmark\_"."K$opt_ptr->{K_val}\_"."N$opt_ptr->{N_val}\_"; $cirkit_blif_out = "$prefix"."cirkit.blif"; $cirkit_blif_out_bak = "$prefix"."cirkit_bak.blif"; $cirkit_log = "$prefix"."cirkit.log"; my ($act_file,$ace_new_blif,$ace_log) = ("$prefix"."ace.act","$prefix"."ace.blif","$prefix"."ace.log"); my ($vpr_net,$vpr_place,$vpr_route,$vpr_reroute_log,$vpr_log); $vpr_net = "$prefix"."vpr.net"; $vpr_place = "$prefix"."vpr.place"; $vpr_route = "$prefix"."vpr.route"; $vpr_log = "$prefix"."vpr.log"; $vpr_reroute_log = "$prefix"."vpr_reroute.log"; &run_cirkit_mig_mccl_map($cirkit_bm,$cirkit_blif_out,$cirkit_log); if (!(-e $cirkit_blif_out)) { die "ERROR: Fail Cirkit for benchmark $cirkit_blif_out.\n"; } #`perl pro_blif.pl -i $abc_blif_out_bak -o $abc_blif_out`; #if (!(-e $abc_blif_out)) { # die "ERROR: Fail pro_blif.pl for benchmark $abc_blif_out.\n"; #} &run_ace_in_flow($prefix, $cirkit_blif_out, $act_file, $ace_new_blif, $ace_log); &run_vpr_in_flow($tag, $benchmark, $benchmark_file, $cirkit_blif_out, $vpr_arch, $act_file, $vpr_net, $vpr_place, $vpr_route, $vpr_log, $vpr_reroute_log, $parse_results); return; } # Run Yosys-VPR flow sub run_yosys_vpr_flow($ $ $ $ $) { my ($tag,$benchmark_file,$vpr_arch,$flow_enhance, $parse_results) = @_; my ($benchmark, $rpt_dir, $prefix); my ($yosys_bm,$yosys_blif_out,$yosys_log,$yosys_blif_out_bak); my @tokens = split('/', $benchmark_file); $benchmark = $tokens[0]; # Prepare for the output folder $rpt_dir = "$conf_ptr->{dir_path}->{rpt_dir}->{val}"."/$benchmark/$tag"; &generate_path($rpt_dir); # Run Yosys flow $yosys_bm = "$conf_ptr->{dir_path}->{benchmark_dir}->{val}"."/$benchmark_file"; $prefix = "$rpt_dir/$benchmark\_"."K$opt_ptr->{K_val}\_"."N$opt_ptr->{N_val}\_"; $yosys_blif_out = "$prefix"."yosys.blif"; $yosys_log = "$prefix"."yosys.log"; &run_yosys_fpgamap($benchmark, $yosys_bm, $yosys_blif_out, $yosys_log); # Files for ace my ($act_file,$ace_new_blif,$ace_log, $corrected_ace_blif) = ("$rpt_dir/$benchmark".".act","$rpt_dir/$benchmark"."ace.blif","$prefix"."ace.log","$rpt_dir/$benchmark".".blif"); &run_ace_in_flow($prefix, $yosys_blif_out, $act_file, $ace_new_blif, $ace_log); &run_pro_blif_3arg($ace_new_blif, $corrected_ace_blif, $yosys_blif_out); # Files for VPR my ($vpr_net,$vpr_place,$vpr_route,$vpr_reroute_log,$vpr_log); $vpr_net = "$prefix"."vpr.net"; $vpr_place = "$prefix"."vpr.place"; $vpr_route = "$prefix"."vpr.route"; $vpr_log = "$prefix"."vpr.log"; $vpr_reroute_log = "$prefix"."vpr_reroute.log"; # Need to add a regenation of the verilog from the optimized blif -> write verilog from blif + correct the name of the verilog for the testbench $verilog_benchmark = &run_rewrite_verilog($ace_new_blif, $rpt_dir, $benchmark, $benchmark, $yosys_log); &run_vpr_in_flow($tag, $benchmark, $benchmark_file, $corrected_ace_blif, $vpr_arch, $act_file, $vpr_net, $vpr_place, $vpr_route, $vpr_log, $vpr_reroute_log, $parse_results); return; } # Parse Yosys-VPR flow sub parse_yosys_vpr_flow_results($ $ $ $) { my ($tag,$benchmark_file,$vpr_arch,$flow_enhance) = @_; my ($benchmark, $rpt_dir, $prefix); my ($yosys_bm,$yosys_blif_out,$yosys_log,$yosys_blif_out_bak); my @tokens = split('/', $benchmark_file); $benchmark = $tokens[0]; # Prepare for the output folder $rpt_dir = "$conf_ptr->{dir_path}->{rpt_dir}->{val}"."/$benchmark/$tag"; &generate_path($rpt_dir); # Run Yosys flow $yosys_bm = "$conf_ptr->{dir_path}->{benchmark_dir}->{val}"."/$benchmark_file"; $prefix = "$rpt_dir/$benchmark\_"."K$opt_ptr->{K_val}\_"."N$opt_ptr->{N_val}\_"; $yosys_blif_out = "$rpt_dir/$benchmark".".blif"; $yosys_log = "$prefix"."yosys.log"; # Files for ace my ($act_file,$ace_new_blif,$ace_log) = ("$prefix"."ace.act","$prefix"."ace.blif","$prefix"."ace.log"); # Files for VPR my ($vpr_net,$vpr_place,$vpr_route,$vpr_reroute_log,$vpr_log); $vpr_net = "$prefix"."vpr.net"; $vpr_place = "$prefix"."vpr.place"; $vpr_route = "$prefix"."vpr.route"; $vpr_log = "$prefix"."vpr.log"; $vpr_reroute_log = "$prefix"."vpr_reroute.log"; if ("on" eq $opt_ptr->{min_route_chan_width}) { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log.".min_chan_width",$opt_ptr->{K_val},"on",1); &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val},"off",1); &extract_vpr_stats($tag,$benchmark,$vpr_log.".min_chan_width",$opt_ptr->{K_val}); &extract_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val}); } elsif ("on" eq $opt_ptr->{fix_route_chan_width}) { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val},"off",1); &extract_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}); if (-e $vpr_reroute_log) { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val},"off",1); &extract_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val}); } } else { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val},"on",1); &extract_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}); } # Extract data from VPR Power stats if ("on" eq $opt_ptr->{power}) { &extract_vpr_power_esti($tag,$yosys_blif_out,$benchmark,$opt_ptr->{K_val}); } # TODO: HOW TO DEAL WITH SPICE NETLISTS??? # Output a file contain information of SPICE Netlists if ("on" eq $opt_ptr->{vpr_fpga_spice}) { &output_fpga_spice_task("$opt_ptr->{vpr_fpga_spice_val}"."_$tag.txt", $benchmark, $yosys_blif_out, $rpt_dir); } return; } sub run_standard_flow($ $ $ $ $) { my ($tag,$benchmark_file,$vpr_arch,$flow_enhance, $parse_results) = @_; my ($benchmark, $rpt_dir,$prefix); my ($abc_bm,$abc_blif_out,$abc_log,$abc_blif_out_bak); my ($mpack_blif_out,$mpack_stats,$mpack_log); my ($vpr_net,$vpr_place,$vpr_route,$vpr_reroute_log,$vpr_log); $benchmark = $benchmark_file; $benchmark =~ s/\.blif$//g; # Run Standard flow $rpt_dir = "$conf_ptr->{dir_path}->{rpt_dir}->{val}"."/$benchmark/$tag"; &generate_path($rpt_dir); $abc_bm = "$conf_ptr->{dir_path}->{benchmark_dir}->{val}"."/$benchmark".".blif"; $prefix = "$rpt_dir/$benchmark\_"."K$opt_ptr->{K_val}\_"."N$opt_ptr->{N_val}\_"; $abc_blif_out = "$prefix"."abc.blif"; $abc_blif_out_bak = "$prefix"."abc_bak.blif"; $abc_log = "$prefix"."abc.log"; my ($act_file,$ace_new_blif,$ace_log) = ("$prefix"."ace.act","$prefix"."ace.blif","$prefix"."ace.log"); $vpr_net = "$prefix"."vpr.net"; $vpr_place = "$prefix"."vpr.place"; $vpr_route = "$prefix"."vpr.route"; $vpr_log = "$prefix"."vpr.log"; $vpr_reroute_log = "$prefix"."vpr_reroute.log"; if ("abc_black_box" eq $flow_enhance) { my ($pre_abc_blif) = ("$prefix"."pre_abc.blif"); &run_pro_blif($abc_bm, $pre_abc_blif); &run_abc_bb_fpgamap($pre_abc_blif,$abc_blif_out_bak,$abc_log); } elsif ("classic" eq $flow_enhance) { &run_abc_fpgamap($abc_bm,$abc_blif_out_bak,$abc_log); } &run_pro_blif($abc_blif_out_bak, $abc_blif_out); &run_ace_in_flow($prefix, $abc_blif_out, $act_file, $ace_new_blif, $ace_log); &run_vpr_in_flow($tag, $benchmark, $benchmark_file, $abc_blif_out, $vpr_arch, $act_file, $vpr_net, $vpr_place, $vpr_route, $vpr_log, $vpr_reroute_log, $parse_results); return; } sub parse_standard_flow_results($ $ $ $) { my ($tag,$benchmark_file,$vpr_arch,$flow_enhance) = @_; my ($rpt_dir,$prefix); my ($abc_bm,$abc_blif_out,$abc_log); my ($mpack_blif_out,$mpack_stats,$mpack_log); my ($vpr_net,$vpr_place,$vpr_route,$vpr_reroute_log,$vpr_log); my ($benchmark) = ($benchmark_file); $benchmark =~ s/\.blif$//g; # Run Standard flow $rpt_dir = "$conf_ptr->{dir_path}->{rpt_dir}->{val}"."/$benchmark/$tag"; &generate_path($rpt_dir); $abc_bm = "$conf_ptr->{dir_path}->{benchmark_dir}->{val}"."/$benchmark".".blif"; $prefix = "$rpt_dir/$benchmark\_"."K$opt_ptr->{K_val}\_"."N$opt_ptr->{N_val}\_"; $abc_blif_out = "$prefix"."abc.blif"; $abc_log = "$prefix"."abc.log"; if ("abc_black_box" eq $flow_enhance) { rename $abc_blif_out,"$abc_blif_out".".bak"; } elsif ("classic" eq $flow_enhance) { } my ($act_file,$ace_new_blif,$ace_log) = ("$prefix"."ace.act","$prefix"."ace.blif","$prefix"."ace.log"); $vpr_net = "$prefix"."vpr.net"; $vpr_place = "$prefix"."vpr.place"; $vpr_route = "$prefix"."vpr.route"; $vpr_log = "$prefix"."vpr.log"; $vpr_reroute_log = "$prefix"."vpr_reroute.log"; if ("on" eq $opt_ptr->{min_route_chan_width}) { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log.".min_chan_width",$opt_ptr->{K_val},"on",1); &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val},"off",1); &extract_vpr_stats($tag,$benchmark,$vpr_log.".min_chan_width",$opt_ptr->{K_val}); &extract_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val}); } elsif ("on" eq $opt_ptr->{fix_route_chan_width}) { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val},"off",1); &extract_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}); if (-e $vpr_reroute_log) { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val},"off",1); &extract_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val}); } } else { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val},"on",1); &extract_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}); } # Extract data from VPR Power stats if ("on" eq $opt_ptr->{power}) { &extract_vpr_power_esti($tag,$abc_blif_out,$benchmark,$opt_ptr->{K_val}); } # TODO: HOW TO DEAL WITH SPICE NETLISTS??? # Output a file contain information of SPICE Netlists if ("on" eq $opt_ptr->{vpr_fpga_spice}) { &output_fpga_spice_task("$opt_ptr->{vpr_fpga_spice_val}"."_standard.txt", $benchmark, $abc_blif_out, $rpt_dir); } return; } sub run_mpack2_flow($ $ $ $) { my ($tag,$benchmark_file,$mpack2_arch,$parse_results) = @_; my ($rpt_dir,$prefix); my ($abc_bm,$abc_blif_out,$abc_log,$abc_blif_out_bak); my ($mpack2_blif_out,$mpack2_vpr_net,$mpack2_stats,$mpack2_log,$mpack2_vpr_arch); my ($vpr_place,$vpr_route,$vpr_reroute_log,$vpr_log,$act_file); # Check necessary options if (!($opt_ptr->{N_val})) { die "ERROR: (mpack2_flow) -N should be specified!\n"; } if (!($opt_ptr->{K_val})) { die "ERROR: (mpack2_flow) -K should be specified!\n"; } my ($benchmark) = ($benchmark_file); $benchmark =~ s/\.blif$//g; # Run MPACK2-oriented flow $rpt_dir = "$conf_ptr->{dir_path}->{rpt_dir}->{val}"."/$benchmark/$tag"; &generate_path($rpt_dir); $abc_bm = "$conf_ptr->{dir_path}->{benchmark_dir}->{val}"."/$benchmark".".blif"; $prefix = "$rpt_dir/$benchmark\_"."K$opt_ptr->{K_val}\_"."N$opt_ptr->{N_val}\_"; $abc_blif_out = "$prefix"."abc.blif"; $abc_blif_out_bak = "$prefix"."abc_bak.blif"; $abc_log = "$prefix"."abc.log"; # RUN ABC #&run_abc_libmap($abc_bm,"$abc_blif_out\.bak",$abc_log); &run_abc_fpgamap($abc_bm,$abc_blif_out_bak,$abc_log); # Pre-process the blif netlist #`perl convert_blif.pl -i $abc_blif_out\.bak -o $abc_blif_out\.conv`; `perl pro_blif.pl -i $abc_blif_out_bak -o $abc_blif_out`; # RUN MPACK2 $mpack2_blif_out = "$prefix"."mpack2.blif"; $mpack2_vpr_net = "$prefix"."mpack2.net"; $mpack2_stats = "$prefix"."mpack2.stats"; $mpack2_log = "$prefix"."mpack2.log"; $mpack2_vpr_arch = "$prefix"."mpack2_vpr_arch.xml"; &run_mpack2($abc_blif_out,$mpack2_blif_out,$mpack2_arch,$mpack2_vpr_net,$mpack2_stats,$mpack2_vpr_arch,$mpack2_log); # Extract data from MPACK stats if (1 == $parse_results) { &extract_mpack2_stats($tag,$benchmark,$mpack2_stats); } # RUN VPR $vpr_place = "$prefix"."vpr.place"; $vpr_route = "$prefix"."vpr.route"; $vpr_log = "$prefix"."vpr.log"; $vpr_reroute_log = "$prefix"."vpr_reroute.log"; if ("on" eq $opt_ptr->{min_route_chan_width}) { &run_mpack2_vpr($mpack2_blif_out,$mpack2_vpr_arch,$mpack2_vpr_net,$vpr_place,$vpr_route,-1,$vpr_log.".min_chan_width"); # Get the Minimum channel width my ($min_chan_width) = (&extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log.".min_chan_width",$opt_ptr->{K_val}, $opt_ptr->{min_route_chan_width}, $parse_results)); $min_chan_width = int($min_chan_width*$opt_ptr->{min_route_chan_width_val}); if (0 != $min_chan_width%2) { $min_chan_width += 1; } # Remove previous route results `rm $vpr_route`; # Keep increase min_chan_width until route success # Extract data from VPR stats while (1) { &run_vpr_route($mpack2_blif_out,$benchmark,$mpack2_vpr_arch,$mpack2_vpr_net,$vpr_place,$vpr_route,$min_chan_width,$vpr_reroute_log,$act_file); if (-e $vpr_route) { print "INFO: try route_chan_width($min_chan_width) Success!\n"; last; #Jump out } else { print "INFO: try route_chan_width($min_chan_width) failed! Retry with +2...\n"; $min_chan_width += 2; } } # Extract data from VPR stats if (1 == $parse_results) { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val}, "off", $parse_results); &extract_vpr_stats($tag,$benchmark,$vpr_log.".min_chan_width",$opt_ptr->{K_val}); &extract_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val}); } } elsif ("on" eq $opt_ptr->{fix_route_chan_width}) { my ($fix_chan_width) = ($benchmarks_ptr->{$benchmark_file}->{fix_route_chan_width}); # Remove previous route results if (-e $vpr_route) { `rm $vpr_route`; } # Keep increase min_chan_width until route success # Extract data from VPR stats &run_mpack2_vpr($mpack2_blif_out,$mpack2_vpr_arch,$mpack2_vpr_net,$vpr_place,$vpr_route,$fix_chan_width,$vpr_log); while (1) { if (-e $vpr_route) { print "INFO: try route_chan_width($fix_chan_width) success!\n"; last; #Jump out } else { print "INFO: try route_chan_width($fix_chan_width) failed! Retry with +2...\n"; $fix_chan_width += 2; &run_vpr_route($mpack2_blif_out,$benchmark,$mpack2_vpr_arch,$mpack2_vpr_net,$vpr_place,$vpr_route,$fix_chan_width,$vpr_reroute_log,$act_file); } } if (1 == $parse_results) { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}, "off", $parse_results); &extract_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}); if (-e $vpr_reroute_log) { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val}, "off", $parse_results); &extract_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val}); } } } else { &run_mpack2_vpr($mpack2_blif_out,$mpack2_vpr_arch,$mpack2_vpr_net,$vpr_place,$vpr_route,-1,$vpr_log); if (!(-e $vpr_route)) { die "ERROR: Route Fail for $mpack2_blif_out!\n"; } my ($min_chan_width) = (&extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}, $parse_results)); # Extract data from VPR stats if (1 == $parse_results) { &extract_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}); } } return; } sub parse_mpack2_flow_results($ $ $) { my ($tag,$benchmark_file,$mpack2_arch) = @_; my ($rpt_dir,$prefix); my ($abc_bm,$abc_blif_out,$abc_log); my ($mpack2_blif_out,$mpack2_vpr_net,$mpack2_stats,$mpack2_log,$mpack2_vpr_arch); my ($vpr_place,$vpr_route,$vpr_reroute_log,$vpr_log); # Check necessary options if (!($opt_ptr->{N_val})) { die "ERROR: (mpack2_flow) -N should be specified!\n"; } if (!($opt_ptr->{K_val})) { die "ERROR: (mpack2_flow) -K should be specified!\n"; } my ($benchmark) = ($benchmark_file); $benchmark =~ s/\.blif$//g; # Run MPACK2-oriented flow $rpt_dir = "$conf_ptr->{dir_path}->{rpt_dir}->{val}"."/$benchmark/$tag"; &generate_path($rpt_dir); $abc_bm = "$conf_ptr->{dir_path}->{benchmark_dir}->{val}"."/$benchmark".".blif"; $prefix = "$rpt_dir/$benchmark\_"."K$opt_ptr->{K_val}\_"."N$opt_ptr->{N_val}\_"; $abc_blif_out = "$prefix"."abc.blif"; $abc_log = "$prefix"."abc.log"; # Pre-process the blif netlist # RUN MPACK2 $mpack2_blif_out = "$prefix"."mpack2.blif"; $mpack2_vpr_net = "$prefix"."mpack2.net"; $mpack2_stats = "$prefix"."mpack2.stats"; $mpack2_log = "$prefix"."mpack2.log"; $mpack2_vpr_arch = "$prefix"."mpack2_vpr_arch.xml"; # Extract data from MPACK stats &extract_mpack2_stats($tag,$benchmark,$mpack2_stats); # RUN VPR $vpr_place = "$prefix"."vpr.place"; $vpr_route = "$prefix"."vpr.route"; $vpr_log = "$prefix"."vpr.log"; $vpr_reroute_log = "$prefix"."vpr_reroute.log"; if ("on" eq $opt_ptr->{min_route_chan_width}) { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log.".min_chan_width",$opt_ptr->{K_val},"on",1); &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val},"off",1); &extract_vpr_stats($tag,$benchmark,$vpr_log.".min_chan_width",$opt_ptr->{K_val}); &extract_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val}); } elsif ("on" eq $opt_ptr->{fix_route_chan_width}) { &extract_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}); if (-e $vpr_reroute_log) { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val},"off",1); &extract_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val}); } else { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val},"off",1); } &extract_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}); } else { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}, "on", 1); &extract_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}); } return; } sub run_mpack1_flow($ $ $) { my ($tag,$benchmark_file, $parse_results) = @_; my ($rpt_dir,$prefix); my ($abc_bm,$abc_blif_out,$abc_log); my ($vpr_net,$vpr_place,$vpr_route,$vpr_log); my ($I_val,$M_val,$N_val) = ($opt_ptr->{I_val},$opt_ptr->{M_val},$opt_ptr->{N_val}); my ($m2net_conf) = ($conf_ptr->{flow_conf}->{m2net_conf}->{val}); my ($cell_size) = (2); if ($I_val) { } else { $I_val = int($cell_size*$M_val*($N_val+1)/2); print "INFO: I isn't defined. Auto-sized to 2*M*(N+1)/2 = $I_val\n"; } my ($benchmark) = ($benchmark_file); $benchmark =~ s/\.blif$//g; # Run MPACK1-oriented flow $rpt_dir = "$conf_ptr->{dir_path}->{rpt_dir}->{val}"."/$benchmark/$tag"; &generate_path($rpt_dir); $abc_bm = "$conf_ptr->{dir_path}->{benchmark_dir}->{val}"."/$benchmark".".blif"; $prefix = "$rpt_dir/$benchmark\_"."M$M_val\_"."N$N_val\_"; $abc_blif_out = "$prefix"."abc.blif"; $abc_log = "$prefix"."abc.log"; &run_abc_libmap($abc_bm,"$abc_blif_out\.bak",$abc_log); `perl pro_blif.pl -i "$abc_blif_out\.bak" -o $abc_blif_out`; my ($mpack1_pack_blif_out) = ("$prefix"."_matrix.blif"); my ($mpack1_vpr_blif_out) = ("$prefix"."_formatted.blif"); my ($mpack1_rpt) = ("$prefix"."_mapped.net"); my ($mpack1_log) = ("$prefix"."mpack1p5.log"); &run_mpack1p5("$abc_blif_out","$prefix",$M_val,$cell_size,$mpack1_log); # Extract data from MPACK stats if (1 == $parse_results) { &extract_mpack1_stats($tag,$benchmark,$mpack1_log); } # Generate Architecture XML my ($aapack_arch) = ("$prefix"."aapack_arch.xml"); my ($m2net_pack_arch_log) = ("$prefix"."m2net_pack_arch.log"); &run_m2net_pack_arch($m2net_conf,$mpack1_rpt,$aapack_arch,$N_val,$I_val,$m2net_pack_arch_log); # Run AAPACK my ($aapack_log) = ("$prefix"."aapack.log"); my ($aapack_net) = ("$prefix"."aapack.net"); &run_aapack($mpack1_pack_blif_out,$aapack_arch,$aapack_net,$aapack_log); my @aapack_stats = ("MATRIX"); if (1 == $parse_results) { &extract_aapack_stats($tag,$benchmark,$aapack_log,$M_val,\@aapack_stats); } $vpr_net = "$prefix"."mpack.net"; $vpr_place = "$prefix"."vpr.place"; $vpr_route = "$prefix"."vpr.route"; $vpr_log = "$prefix"."vpr.log"; # Run m2net.pl my ($vpr_arch) = ("$prefix"."vpr_arch.xml"); my ($m2net_m2net_log) = ("$prefix"."m2net_m2net.log"); &run_m2net_m2net($m2net_conf,$mpack1_rpt,$aapack_net,$vpr_net,$vpr_arch,$N_val,$I_val,$m2net_m2net_log); my ($act_file,$ace_new_blif,$ace_log) = ("$prefix"."ace.act","$prefix"."ace_new.blif","$prefix"."ace.log"); # Turn on Power Estimation and Run ace if ("on" eq $opt_ptr->{power}) { &run_ace($mpack1_vpr_blif_out,$act_file,$ace_new_blif,$ace_log); } &run_mpack1_vpr($mpack1_vpr_blif_out,$vpr_arch,$vpr_net,$vpr_place,$vpr_route,$vpr_log,$act_file); if (!(-e $vpr_route)) { die "ERROR: Route Fail for $mpack1_vpr_blif_out!\n"; } # Extract data from VPR stats if (1 == $parse_results) { &extract_vpr_stats($tag,$benchmark,$vpr_log,$M_val); } if (("on" eq $opt_ptr->{power}) &&(1 == $parse_results)) { &extract_vpr_power_esti($tag,$mpack1_vpr_blif_out,$benchmark,$M_val); } } sub parse_mpack1_flow_results($ $) { my ($tag,$benchmark_file) = @_; my ($rpt_dir,$prefix); my ($abc_bm,$abc_blif_out,$abc_log); my ($vpr_net,$vpr_place,$vpr_route,$vpr_log); my ($I_val,$M_val,$N_val) = ($opt_ptr->{I_val},$opt_ptr->{M_val},$opt_ptr->{N_val}); my ($m2net_conf) = ($conf_ptr->{flow_conf}->{m2net_conf}->{val}); my ($cell_size) = (2); if ($I_val) { } else { $I_val = int($cell_size*$M_val*($N_val+1)/2); print "INFO: I isn't defined. Auto-sized to 2*M*(N+1)/2 = $I_val\n"; } my ($benchmark) = ($benchmark_file); $benchmark =~ s/\.blif$//g; # Run MPACK1-oriented flow $rpt_dir = "$conf_ptr->{dir_path}->{rpt_dir}->{val}"."/$benchmark/$tag"; &generate_path($rpt_dir); $abc_bm = "$conf_ptr->{dir_path}->{benchmark_dir}->{val}"."/$benchmark".".blif"; $prefix = "$rpt_dir/$benchmark\_"."M$M_val\_"."N$N_val\_"; $abc_blif_out = "$prefix"."abc.blif"; $abc_log = "$prefix"."abc.log"; my ($mpack1_pack_blif_out) = ("$prefix"."_matrix.blif"); my ($mpack1_vpr_blif_out) = ("$prefix"."_formatted.blif"); my ($mpack1_rpt) = ("$prefix"."_mapped.net"); my ($mpack1_log) = ("$prefix"."mpack1p5.log"); # Extract data from MPACK stats &extract_mpack1_stats($tag,$benchmark,$mpack1_log); # Generate Architecture XML my ($aapack_arch) = ("$prefix"."aapack_arch.xml"); my ($m2net_pack_arch_log) = ("$prefix"."m2net_pack_arch.log"); # Run AAPACK my ($aapack_log) = ("$prefix"."aapack.log"); my ($aapack_net) = ("$prefix"."aapack.net"); my @aapack_stats = ("MATRIX"); &extract_aapack_stats($tag,$benchmark,$aapack_log,$M_val,\@aapack_stats); $vpr_net = "$prefix"."mpack.net"; $vpr_place = "$prefix"."vpr.place"; $vpr_route = "$prefix"."vpr.route"; $vpr_log = "$prefix"."vpr.log"; # Run m2net.pl my ($vpr_arch) = ("$prefix"."vpr_arch.xml"); my ($m2net_m2net_log) = ("$prefix"."m2net_m2net.log"); my ($act_file,$ace_new_blif,$ace_log) = ("$prefix"."ace.act","$prefix"."ace_new.blif","$prefix"."ace.log"); # Extract data from VPR stats &extract_vpr_stats($tag,$benchmark,$vpr_log,$M_val); if ("on" eq $opt_ptr->{power}) { &extract_vpr_power_esti($tag,$mpack1_vpr_blif_out,$benchmark,$M_val); } } sub run_vtr_flow($ $ $ $) { my ($tag,$benchmark_file,$vpr_arch,$parse_results) = @_; my ($rpt_dir,$prefix); my ($min_hard_adder_size, $mem_size, $odin2_verilog, $odin2_config, $odin2_log); my ($abc_bm,$abc_blif_out,$abc_log,$abc_blif_out_bak); my ($vpr_net,$vpr_place,$vpr_route,$vpr_reroute_log,$vpr_log); # The input of VTR flow is verilog file my ($benchmark) = ($benchmark_file); $benchmark =~ s/\.v$//g; # Run Verilog To Routiing flow $rpt_dir = "$conf_ptr->{dir_path}->{rpt_dir}->{val}"."/$benchmark/$tag"; &generate_path($rpt_dir); # ODIN II output blif $odin2_verilog = "$conf_ptr->{dir_path}->{benchmark_dir}->{val}"."/$benchmark".".v"; $prefix = "$rpt_dir/$benchmark\_"."K$opt_ptr->{K_val}\_"."N$opt_ptr->{N_val}\_"; # ODIN II config XML $odin2_config = "$prefix"."odin2_config.xml"; $odin2_log = "$prefix"."odin2.log"; # ODIN II output blif $abc_bm = "$prefix"."odin2.blif"; # ABC II output blif $abc_blif_out = "$prefix"."abc.blif"; $abc_blif_out_bak = "$prefix"."abc_bak.blif"; $abc_log = "$prefix"."abc.log"; # Initialize min_hard_adder_size $min_hard_adder_size = 1; # Default value if ("on" eq $opt_ptr->{min_hard_adder_size}) { if (1 > $opt_ptr->{min_hard_adder_size_val}) { die "ERROR: Invalid min_hard_adder_size($opt_ptr->{min_hard_adder_size})!Should be no less than 1!"; } else { $min_hard_adder_size = $opt_ptr->{min_hard_adder_size_val}; } } # TODO: Initialize the mem_size by parsing the ARCH XML? if ("on" eq $opt_ptr->{mem_size}) { $mem_size = $opt_ptr->{mem_size_val}; } else { die "ERROR: -mem_size is mandatory when vtr flow is chosen!\n"; } # Auto-generate a configuration XML for ODIN2 &gen_odin2_config_xml($odin2_config, $odin2_verilog, $abc_bm, $vpr_arch, $mem_size, $min_hard_adder_size); # RUN ODIN II &run_odin2($odin2_config, "off", $odin2_log); if (!(-e $abc_bm)) { die "ERROR: Fail ODIN II for benchmark $benchmark.\n"; } # RUN ABC &run_abc_bb_fpgamap($abc_bm,$abc_blif_out_bak,$abc_log); &run_pro_blif($abc_blif_out_bak, $abc_blif_out); # Run ABC my ($act_file,$ace_new_blif,$ace_log) = ("$prefix"."ace.act","$prefix"."ace.blif","$prefix"."ace.log"); &run_ace_in_flow($prefix, $abc_blif_out,$act_file,$ace_new_blif,$ace_log); $vpr_net = "$prefix"."vpr.net"; $vpr_place = "$prefix"."vpr.place"; $vpr_route = "$prefix"."vpr.route"; $vpr_log = "$prefix"."vpr.log"; $vpr_reroute_log = "$prefix"."vpr_reroute.log"; # Run VPR &run_vpr_in_flow($tag, $benchmark, $benchmark_file, $abc_blif_out, $vpr_arch, $act_file, $vpr_net, $vpr_place, $vpr_route, $vpr_log, $vpr_reroute_log, $parse_results); return; } sub parse_vtr_flow_results($ $ $) { my ($tag,$benchmark,$vpr_arch) = @_; my ($min_hard_adder_size, $mem_size, $odin2_verilog, $odin2_config, $odin2_log); my ($rpt_dir,$prefix); my ($abc_bm,$abc_blif_out,$abc_log); my ($mpack_blif_out,$mpack_stats,$mpack_log); my ($vpr_net,$vpr_place,$vpr_route,$vpr_reroute_log,$vpr_log); $benchmark =~ s/\.v$//g; # Run Standard flow $rpt_dir = "$conf_ptr->{dir_path}->{rpt_dir}->{val}"."/$benchmark/$tag"; &generate_path($rpt_dir); # ODIN II output blif $odin2_verilog = "$conf_ptr->{dir_path}->{benchmark_dir}->{val}"."/$benchmark".".v"; $prefix = "$rpt_dir/$benchmark\_"."K$opt_ptr->{K_val}\_"."N$opt_ptr->{N_val}\_"; # ODIN II config XML $odin2_config = "$prefix"."odin2_config.xml"; $odin2_log = "$prefix"."odin2.log"; # ODIN II output blif $abc_bm = "$prefix"."odin2.blif"; # ABC output blif $abc_blif_out = "$prefix"."abc.blif"; $abc_log = "$prefix"."abc.log"; rename $abc_blif_out,"$abc_blif_out".".bak"; my ($act_file,$ace_new_blif,$ace_log) = ("$prefix"."ace.act","$prefix"."ace.blif","$prefix"."ace.log"); $vpr_net = "$prefix"."vpr.net"; $vpr_place = "$prefix"."vpr.place"; $vpr_route = "$prefix"."vpr.route"; $vpr_log = "$prefix"."vpr.log"; $vpr_reroute_log = "$prefix"."vpr_reroute.log"; if ("on" eq $opt_ptr->{min_route_chan_width}) { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log.".min_chan_width",$opt_ptr->{K_val},"on",1); &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val},"off",1); &extract_vpr_stats($tag,$benchmark,$vpr_log.".min_chan_width",$opt_ptr->{K_val}); &extract_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val}); } elsif ("on" eq $opt_ptr->{fix_route_chan_width}) { &extract_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}); if (-e $vpr_reroute_log) { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val},"off",1); &extract_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val}); } else { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val},"off",1); } } else { &extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}, "on", 1); &extract_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val}); } # Extract data from VPR Power stats if ("on" eq $opt_ptr->{power}) { &extract_vpr_power_esti($tag,$abc_blif_out,$benchmark,$opt_ptr->{K_val}); } # TODO: HOW TO DEAL WITH SPICE NETLISTS??? # Output a file contain information of SPICE Netlists if ("on" eq $opt_ptr->{vpr_fpga_spice}) { &output_fpga_spice_task("$opt_ptr->{vpr_fpga_spice_val}"."_vtr.txt", $benchmark, $abc_blif_out, $rpt_dir); } return; } # VTR_MCCL_flow: # Differences from vtr_flow: # 1. Need to turn off the carry-chain support for ODIN II # 2. Use Carry-chain detection and Carry-chain LUTs pre-mapping in ABC scripts sub run_vtr_mccl_flow($ $ $ $) { my ($tag,$benchmark_file,$vpr_arch,$parse_results) = @_; my ($rpt_dir,$prefix); my ($min_hard_adder_size, $mem_size, $odin2_verilog, $odin2_config, $odin2_log); my ($abc_bm,$abc_blif_out,$abc_log,$abc_blif_out_bak); my ($vpr_net,$vpr_place,$vpr_route,$vpr_reroute_log,$vpr_log); my ($odin2_carry_chain_support) = ("on"); # The input of VTR flow is verilog file my ($benchmark) = ($benchmark_file); $benchmark =~ s/\.v$//g; # Run Verilog To Routiing flow $rpt_dir = "$conf_ptr->{dir_path}->{rpt_dir}->{val}"."/$benchmark/$tag"; &generate_path($rpt_dir); # ODIN II output blif $odin2_verilog = "$conf_ptr->{dir_path}->{benchmark_dir}->{val}"."/$benchmark".".v"; $prefix = "$rpt_dir/$benchmark\_"."K$opt_ptr->{K_val}\_"."N$opt_ptr->{N_val}\_"; # ODIN II config XML $odin2_config = "$prefix"."odin2_config.xml"; $odin2_log = "$prefix"."odin2.log"; # ODIN II output blif $abc_bm = "$prefix"."odin2.blif"; # ABC II output blif $abc_blif_out = "$prefix"."abc.blif"; $abc_blif_out_bak = "$prefix"."abc_bak.blif"; $abc_log = "$prefix"."abc.log"; # Initialize min_hard_adder_size $min_hard_adder_size = 1; # Default value if ("on" eq $opt_ptr->{min_hard_adder_size}) { if (1 > $opt_ptr->{min_hard_adder_size_val}) { die "ERROR: Invalid min_hard_adder_size($opt_ptr->{min_hard_adder_size})!Should be no less than 1!"; } else { $min_hard_adder_size = $opt_ptr->{min_hard_adder_size_val}; } } # TODO: Initialize the mem_size by parsing the ARCH XML? if ("on" eq $opt_ptr->{mem_size}) { $mem_size = $opt_ptr->{mem_size_val}; } else { die "ERROR: -mem_size is mandatory when vtr flow is chosen!\n"; } # Auto-generate a configuration XML for ODIN2 &gen_odin2_config_xml($odin2_config, $odin2_verilog, $abc_bm, $vpr_arch, $mem_size, $min_hard_adder_size); if ("on" eq $opt_ptr->{odin2_carry_chain_support}) { $odin2_carry_chain_support = ("on"); } # RUN ODIN II &run_odin2($odin2_config, $odin2_carry_chain_support, $odin2_log); if (!(-e $abc_bm)) { die "ERROR: Fail ODIN II for benchmark $benchmark.\n"; } # RUN ABC &run_abc_mccl_fpgamap($abc_bm,$abc_blif_out_bak,$abc_log); &run_pro_blif($abc_blif_out_bak, $abc_blif_out); # Run ACE my ($act_file,$ace_new_blif,$ace_log) = ("$prefix"."ace.act","$prefix"."ace.blif","$prefix"."ace.log"); &run_ace_in_flow($prefix,i $abc_blif_out,$act_file,$ace_new_blif,$ace_log); $vpr_net = "$prefix"."vpr.net"; $vpr_place = "$prefix"."vpr.place"; $vpr_route = "$prefix"."vpr.route"; $vpr_log = "$prefix"."vpr.log"; $vpr_reroute_log = "$prefix"."vpr_reroute.log"; # Run VPR &run_vpr_in_flow($tag, $benchmark, $benchmark_file, $abc_blif_out, $vpr_arch, $act_file, $vpr_net, $vpr_place, $vpr_route, $vpr_log, $vpr_reroute_log, $parse_results); return; } sub run_mccl_flow($ $ $ $ $) { my ($tag,$benchmark_file,$vpr_arch,$flow_enhance, $parse_results) = @_; my ($benchmark, $rpt_dir,$prefix); my ($abc_bm,$abc_blif_out,$abc_log,$abc_blif_out_bak); my ($mpack_blif_out,$mpack_stats,$mpack_log); my ($vpr_net,$vpr_place,$vpr_route,$vpr_reroute_log,$vpr_log); $benchmark = $benchmark_file; $benchmark =~ s/\.v$//g; # We use verilog format in mccl # Run Standard flow $rpt_dir = "$conf_ptr->{dir_path}->{rpt_dir}->{val}"."/$benchmark/$tag"; &generate_path($rpt_dir); $abc_bm = "$conf_ptr->{dir_path}->{benchmark_dir}->{val}"."/$benchmark".".v"; $prefix = "$rpt_dir/$benchmark\_"."K$opt_ptr->{K_val}\_"."N$opt_ptr->{N_val}\_"; $abc_blif_out = "$prefix"."abc.blif"; $abc_blif_out_bak = "$prefix"."abc_bak.blif"; $abc_log = "$prefix"."abc.log"; # RUN ABC &run_abc_mccl_fpgamap($abc_bm,$abc_blif_out_bak,$abc_log); &run_pro_blif($abc_blif_out_bak, $abc_blif_out); # Run ACE my ($act_file,$ace_new_blif,$ace_log) = ("$prefix"."ace.act","$prefix"."ace.blif","$prefix"."ace.log"); &run_ace_in_flow($prefix,i $abc_blif_out,$act_file,$ace_new_blif,$ace_log); $vpr_net = "$prefix"."vpr.net"; $vpr_place = "$prefix"."vpr.place"; $vpr_route = "$prefix"."vpr.route"; $vpr_log = "$prefix"."vpr.log"; $vpr_reroute_log = "$prefix"."vpr_reroute.log"; # Run VPR &run_vpr_in_flow($tag, $benchmark, $benchmark_file, $abc_blif_out, $vpr_arch, $act_file, $vpr_net, $vpr_place, $vpr_route, $vpr_log, $vpr_reroute_log, $parse_results); return; } sub run_benchmark_selected_flow($ $ $) { my ($flow_type,$benchmark, $parse_results) = @_; if ($flow_type eq "standard") { &run_standard_flow("standard",$benchmark,$conf_ptr->{flow_conf}->{vpr_arch}->{val},"classic", $parse_results); } elsif ($flow_type eq "mpack2") { &run_mpack2_flow("mpack2",$benchmark,$conf_ptr->{flow_conf}->{mpack2_arch}->{val}, $parse_results); } elsif ($flow_type eq "mpack1") { &run_mpack1_flow("mpack1",$benchmark, $parse_results); } elsif ($flow_type eq "vtr_standard") { &run_standard_flow("vtr_standard",$benchmark,$conf_ptr->{flow_conf}->{vpr_arch}->{val},"abc_black_box", $parse_results); } elsif ($flow_type eq "vtr") { &run_vtr_flow("vtr",$benchmark,$conf_ptr->{flow_conf}->{vpr_arch}->{val}, $parse_results); } elsif ($flow_type eq "vtr_mccl") { &run_vtr_mccl_flow("vtr_mccl",$benchmark,$conf_ptr->{flow_conf}->{vpr_arch}->{val}, $parse_results); } elsif ($flow_type eq "mccl") { &run_mccl_flow("mccl",$benchmark,$conf_ptr->{flow_conf}->{vpr_arch}->{val}, $parse_results); } elsif ($flow_type eq "mig_mccl") { &run_mig_mccl_flow("mig_mccl",$benchmark,$conf_ptr->{flow_conf}->{vpr_arch}->{val}, $parse_results); } elsif ($flow_type eq "yosys_vpr") { &run_yosys_vpr_flow("yosys_vpr",$benchmark,$conf_ptr->{flow_conf}->{vpr_arch}->{val}, "classic", $parse_results); } else { die "ERROR: unsupported flow type ($flow_type) is chosen!\n"; } return; } sub parse_benchmark_selected_flow($ $) { my ($flow_type,$benchmark) = @_; if ($flow_type eq "standard") { &parse_standard_flow_results("standard",$benchmark,$conf_ptr->{flow_conf}->{vpr_arch}->{val},"classic"); } elsif ($flow_type eq "mpack2") { &parse_mpack2_flow_results("mpack2",$benchmark,$conf_ptr->{flow_conf}->{mpack2_arch}->{val}); } elsif ($flow_type eq "mpack1") { &parse_mpack1_flow_results("mpack1",$benchmark); } elsif ($flow_type eq "vtr_standard") { &parse_standard_flow_results("vtr_standard",$benchmark,$conf_ptr->{flow_conf}->{vpr_arch}->{val},"abc_black_box"); } elsif ($flow_type eq "vtr") { &parse_vtr_flow_results("vtr", $benchmark, $conf_ptr->{flow_conf}->{vpr_arch}->{val}); } elsif ($flow_type eq "vtr_mccl") { &parse_vtr_flow_results("vtr_mccl", $benchmark, $conf_ptr->{flow_conf}->{vpr_arch}->{val}); } elsif ($flow_type eq "mccl") { &parse_standard_flow_results("mccl", $benchmark, $conf_ptr->{flow_conf}->{vpr_arch}->{val}, "abc_black_box"); } elsif ($flow_type eq "mig_mccl") { &parse_standard_flow_results("mig_mccl", $benchmark, $conf_ptr->{flow_conf}->{vpr_arch}->{val}, "abc_black_box"); } elsif ($flow_type eq "yosys_vpr") { &parse_yosys_vpr_flow_results("yosys_vpr",$benchmark,$conf_ptr->{flow_conf}->{vpr_arch}->{val},"abc_black_box"); } else { die "ERROR: unsupported flow type ($flow_type) is chosen!\n"; } } # Run EDA flow sub run_flows() { my @flows = split('\|',$conf_ptr->{flow_conf}->{flow_type}->{val}); # Run Benchmark one by one foreach my $benchmark(@benchmark_names) { foreach my $flow_to_run(@flows) { if (("off" eq $selected_flows{$flow_to_run}->{flow_status}) ||("done" eq $selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{status})) { next; } print "FLOW TO RUN: $flow_to_run, Benchmark: $benchmark\n"; &run_benchmark_selected_flow($flow_to_run,$benchmark, 0); # Mark finished benchmarks $selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{status} = "done"; } } &parse_flows_benchmarks_results(); } # Run EDA flow with multi task support sub multitask_run_flows() { my @flows = split('\|',$conf_ptr->{flow_conf}->{flow_type}->{val}); # Run Benchmark one by one foreach my $benchmark(@benchmark_names) { foreach my $flow_to_run(@flows) { if (("off" eq $selected_flows{$flow_to_run}->{flow_status}) ||("running" eq $selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{status}) ||("done" eq $selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{status})) { next; } print "FLOW TO RUN: $flow_to_run, Benchmark: $benchmark\n"; # Mutli thread push if ("on" eq $opt_ptr->{multi_task}) { my $pid = fork(); if (defined $pid) { if ($pid) { $selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{status} = "running"; &run_benchmark_selected_flow($flow_to_run,$benchmark, 1); # Mark finished benchmarks $selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{status} = "done"; } else { exit; } } else { print "INFO: fail to create a thread for "; print "FLOW TO RUN: $flow_to_run, Benchmark: $benchmark\n"; print "Relauch later...\n"; } } else { &run_benchmark_selected_flow($flow_to_run,$benchmark, 1); # Mark finished benchmarks $selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{status} = "done"; } } } return; } # Run EDA flow with multi thread support sub multithread_run_flows($) { my ($num_threads) = @_; my @flows = split('\|',$conf_ptr->{flow_conf}->{flow_type}->{val}); # Evaluate include threads ok my ($can_use_threads) = (eval 'use threads; 1'); if (!($can_use_threads)) { die "ERROR: cannot use threads package in Perl! Please check the installation of package...\n"; } # Lauch threads up to the limited number of threads number if ($num_threads < 2) { $num_threads = 2; } my ($num_thread_running) = (0); # Iterate until all the tasks has been assigned, finished while (1 != &check_all_flows_all_benchmarks_done()) { foreach my $benchmark(@benchmark_names) { foreach my $flow_to_run(@flows) { # Bypass unselected flows or finished job if (("off" eq $selected_flows{$flow_to_run}->{flow_status}) ||("done" eq $selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{status})) { next; } # Check if the thread is still not start, running, or finished. my ($thr_id) = ($selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{thread_id}); if ($thr_id) { # Check if there is any error if ($thr_id->error()) { die "Thread(ID:$thr_id) exit abnormally!\n"; } # We have a thread id, check running or finished if ($thr_id->is_running()) { # Update status $selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{status} = "running"; } if ($thr_id->is_joinable()) { $num_thread_running--; $thr_id->join(); # Join the thread results # Update status $selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{status} = "done"; print "FLOW: $flow_to_run, Benchmark: $benchmark, Finished!\n"; print "INFO: current running thread number = $num_thread_running.\n"; &print_jobs_status(); } } else { # Not start a thread for this task, if (($num_thread_running == $num_threads) ||($num_thread_running > $num_threads)) { next; } #if there are still threads available, we try to start one # Mutli thread push my $thr_new = threads->create(\&run_benchmark_selected_flow,$flow_to_run,$benchmark, 0); # We have a valid thread... if ($thr_new) { print "INFO: a new thread is lauched!\n"; print "FLOW RUNNING: $flow_to_run, Benchmark: $benchmark\n"; # Check if it is running... if ($thr_new->is_running()) { $selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{status} = "running"; $selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{thread_id} = $thr_new; $num_thread_running++; print "INFO: current running thread number = $num_thread_running.\n"; &print_jobs_status(); } # Check if it is detached... if ($thr_new->is_joinable()) { # Mark finished benchmarks $num_thread_running--; $thr_new->join(); # Join the thread results $selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{status} = "done"; print "FLOW: $flow_to_run, Benchmark: $benchmark, Finished!\n"; print "INFO: current running thread number = $num_thread_running.\n"; &print_jobs_status(); } } else { # Fail to create a new thread, wait... print "INFO: Fail to alloc a new thread, wait...!"; } } } } } &print_jobs_status(); &parse_flows_benchmarks_results(); return; } sub parse_flows_benchmarks_results() { # Parse all the results foreach my $benchmark(@benchmark_names) { foreach my $flow_to_run(@supported_flows) { # Bypass unselected flows or finished job if (("on" eq $selected_flows{$flow_to_run}->{flow_status}) &&("done" eq $selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{status})) { &parse_benchmark_selected_flow($flow_to_run, $benchmark); } } } return; } sub print_jobs_status() { my ($num_jobs_running, $num_jobs_to_run, $num_jobs_finish, $num_jobs) = (0, 0, 0, 0); foreach my $benchmark(@benchmark_names) { foreach my $flow_to_run(@supported_flows) { if ("on" eq $selected_flows{$flow_to_run}->{flow_status}) { # Count the number of jobs $num_jobs++; # Count to do jobs if ("off" eq $selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{status}) { $num_jobs_to_run++; next; } # Count running jobs if ("running" eq $selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{status}) { $num_jobs_running++; next; } # Count finished jobs if ("done" eq $selected_flows{$flow_to_run}->{benchmarks}->{$benchmark}->{status}) { $num_jobs_finish++; next; } } } } if ($num_jobs == ($num_jobs_running + $num_jobs_finish + $num_jobs_to_run)) { print "Jobs Progress: (Finish rate = ".sprintf("%.2f",100*$num_jobs_finish/$num_jobs) ."%)\n"; print "Total No. of Jobs: $num_jobs.\n"; print "No. of Running Jobs: $num_jobs_running.\n"; print "No. of Finished Jobs: $num_jobs_finish.\n"; print "No. of To Run Jobs: $num_jobs_to_run.\n"; } else { print "Internal problem: num_jobs($num_jobs) != num_jobs_running($num_jobs_running)\n"; print " +num_jobs_finish($num_jobs_finish)\n"; die " +num_jobs_to_run($num_jobs_to_run)\n"; } return; } sub check_all_flows_all_benchmarks_done() { my ($all_done) = (1); foreach my $flow_to_run(@supported_flows) { if ("off" eq $selected_flows{$flow_to_run}->{flow_status}) { next; } if (1 != &check_flow_all_benchmarks_done($flow_to_run)) { $all_done = 0; last; } } return $all_done; } sub check_flow_all_benchmarks_done($) { my ($flow_name) = @_; my ($all_done) = (0); # If this flow has not been chosen, return 0 if ("off" eq $selected_flows{$flow_name}->{flow_status}) { return $all_done; } elsif ("on" eq $selected_flows{$flow_name}->{flow_status}) { $all_done = 1; } # Check if every benchmark has finished in this flow. foreach my $bm(@benchmark_names) { if ("done" ne $selected_flows{$flow_name}->{benchmarks}->{$bm}->{status}) { $all_done = 0; last; } } return $all_done; } sub gen_csv_rpt_vtr_flow($ $) { my ($tag,$CSVFH) = @_; my ($tmp,$ikw,$tmpkw); my @keywords; my ($K_val,$N_val) = ($opt_ptr->{K_val},$opt_ptr->{N_val}); # Print out Standard Stats First print $CSVFH "$tag"; print $CSVFH ",LUTs"; if ("on" eq $opt_ptr->{min_route_chan_width}) { print $CSVFH ",min_route_chan_width"; print $CSVFH ",fix_route_chan_width"; } elsif ("on" eq $opt_ptr->{fix_route_chan_width}) { print $CSVFH ",fix_route_chan_width"; } else { print $CSVFH ",min_route_chan_width"; } @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_tags}->{val}; #foreach $tmpkw(@keywords) { for($ikw=0; $ikw < ($#keywords+1); $ikw++) { print $CSVFH ",$keywords[$ikw]"; } if ("on" eq $opt_ptr->{power}) { @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_power_tags}->{val}; #foreach $tmpkw(@keywords) { for($ikw=0; $ikw < ($#keywords+1); $ikw++) { print $CSVFH ",$keywords[$ikw]"; } print $CSVFH ",Total Power,Total Dynamic Power,Total Leakage Power"; } print $CSVFH "\n"; # Check log/stats one by one foreach $tmp(@benchmark_names) { $tmp =~ s/\.v$//g; print $CSVFH "$tmp"; print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{LUTs}"; if ("on" eq $opt_ptr->{min_route_chan_width}) { print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{min_route_chan_width}"; print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{fix_route_chan_width}"; } elsif ("on" eq $opt_ptr->{fix_route_chan_width}) { print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{fix_route_chan_width}"; } else { print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{min_route_chan_width}"; } #foreach $tmpkw(@keywords) { @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_tags}->{val}; for($ikw=0; $ikw < ($#keywords+1); $ikw++) { $tmpkw = $keywords[$ikw]; $tmpkw =~ s/\s//g; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{$keywords[$ikw]}"; } if ("on" eq $opt_ptr->{power}) { @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_power_tags}->{val}; for($ikw=0; $ikw < ($#keywords+1); $ikw++) { $tmpkw = $keywords[$ikw]; $tmpkw =~ s/\s//g; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{$keywords[$ikw]}"; } print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{total}"; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{dynamic}"; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{leakage}"; } print $CSVFH "\n"; } } sub gen_csv_rpt_yosys_vpr_flow($ $) { my ($tag,$CSVFH) = @_; my ($tmp,$ikw,$tmpkw); my @keywords; my ($K_val,$N_val) = ($opt_ptr->{K_val},$opt_ptr->{N_val}); # Print out Standard Stats First print $CSVFH "$tag"; print $CSVFH ",LUTs"; if ("on" eq $opt_ptr->{min_route_chan_width}) { print $CSVFH ",min_route_chan_width"; print $CSVFH ",fix_route_chan_width"; } elsif ("on" eq $opt_ptr->{fix_route_chan_width}) { print $CSVFH ",fix_route_chan_width"; } else { print $CSVFH ",min_route_chan_width"; } @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_tags}->{val}; #foreach $tmpkw(@keywords) { for($ikw=0; $ikw < ($#keywords+1); $ikw++) { print $CSVFH ",$keywords[$ikw]"; } if ("on" eq $opt_ptr->{power}) { @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_power_tags}->{val}; #foreach $tmpkw(@keywords) { for($ikw=0; $ikw < ($#keywords+1); $ikw++) { print $CSVFH ",$keywords[$ikw]"; } print $CSVFH ",Total Power,Total Dynamic Power,Total Leakage Power"; } print $CSVFH "\n"; # Check log/stats one by one foreach $tmp(@benchmark_names) { my @tokens = split('/', $tmp); $tmp = $tokens[0]; print $CSVFH "$tmp"; print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{LUTs}"; if ("on" eq $opt_ptr->{min_route_chan_width}) { print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{min_route_chan_width}"; print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{fix_route_chan_width}"; } elsif ("on" eq $opt_ptr->{fix_route_chan_width}) { print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{fix_route_chan_width}"; } else { print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{min_route_chan_width}"; } #foreach $tmpkw(@keywords) { @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_tags}->{val}; for($ikw=0; $ikw < ($#keywords+1); $ikw++) { $tmpkw = $keywords[$ikw]; $tmpkw =~ s/\s//g; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{$keywords[$ikw]}"; } if ("on" eq $opt_ptr->{power}) { @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_power_tags}->{val}; for($ikw=0; $ikw < ($#keywords+1); $ikw++) { $tmpkw = $keywords[$ikw]; $tmpkw =~ s/\s//g; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{$keywords[$ikw]}"; } print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{total}"; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{dynamic}"; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{leakage}"; } print $CSVFH "\n"; } } sub gen_csv_rpt_standard_flow($ $) { my ($tag,$CSVFH) = @_; my ($tmp,$ikw,$tmpkw); my @keywords; my ($K_val,$N_val) = ($opt_ptr->{K_val},$opt_ptr->{N_val}); # Print out Standard Stats First print $CSVFH "$tag"; print $CSVFH ",LUTs"; if ("on" eq $opt_ptr->{min_route_chan_width}) { print $CSVFH ",min_route_chan_width"; print $CSVFH ",fix_route_chan_width"; } elsif ("on" eq $opt_ptr->{fix_route_chan_width}) { print $CSVFH ",fix_route_chan_width"; } else { print $CSVFH ",min_route_chan_width"; } @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_tags}->{val}; #foreach $tmpkw(@keywords) { for($ikw=0; $ikw < ($#keywords+1); $ikw++) { print $CSVFH ",$keywords[$ikw]"; } if ("on" eq $opt_ptr->{power}) { @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_power_tags}->{val}; #foreach $tmpkw(@keywords) { for($ikw=0; $ikw < ($#keywords+1); $ikw++) { print $CSVFH ",$keywords[$ikw]"; } print $CSVFH ",Total Power,Total Dynamic Power,Total Leakage Power"; } print $CSVFH "\n"; # Check log/stats one by one foreach $tmp(@benchmark_names) { $tmp =~ s/\.blif$//g; print $CSVFH "$tmp"; print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{LUTs}"; if ("on" eq $opt_ptr->{min_route_chan_width}) { print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{min_route_chan_width}"; print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{fix_route_chan_width}"; } elsif ("on" eq $opt_ptr->{fix_route_chan_width}) { print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{fix_route_chan_width}"; } else { print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{min_route_chan_width}"; } #foreach $tmpkw(@keywords) { @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_tags}->{val}; for($ikw=0; $ikw < ($#keywords+1); $ikw++) { $tmpkw = $keywords[$ikw]; $tmpkw =~ s/\s//g; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{$keywords[$ikw]}"; } if ("on" eq $opt_ptr->{power}) { @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_power_tags}->{val}; for($ikw=0; $ikw < ($#keywords+1); $ikw++) { $tmpkw = $keywords[$ikw]; $tmpkw =~ s/\s//g; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{$keywords[$ikw]}"; } print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{total}"; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{dynamic}"; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{leakage}"; } print $CSVFH "\n"; } } sub gen_csv_rpt_mpack2_flow($ $) { my ($tag,$CSVFH) = @_; my ($tmp,$ikw,$tmpkw); my @keywords; my ($K_val,$N_val) = ($opt_ptr->{K_val},$opt_ptr->{N_val}); # Print out Mpack stats Second print $CSVFH "$tag"; if ("on" eq $opt_ptr->{min_route_chan_width}) { print $CSVFH ",min_route_chan_width"; print $CSVFH ",fix_route_chan_width"; } elsif ("on" eq $opt_ptr->{fix_route_chan_width}) { print $CSVFH ",fix_route_chan_width"; } else { print $CSVFH ",min_route_chan_width"; } @keywords = split /\|/,$conf_ptr->{csv_tags}->{mpack2_tags}->{val}; #foreach $tmpkw(@keywords) { for($ikw=0; $ikw < ($#keywords+1); $ikw++) { print $CSVFH ",$keywords[$ikw]"; } @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_tags}->{val}; #foreach $tmpkw(@keywords) { for($ikw=0; $ikw < ($#keywords+1); $ikw++) { print $CSVFH ",$keywords[$ikw]"; } if ("on" eq $opt_ptr->{power}) { @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_power_tags}->{val}; #foreach $tmpkw(@keywords) { for($ikw=0; $ikw < ($#keywords+1); $ikw++) { print $CSVFH ",$keywords[$ikw]"; } print $CSVFH ",Total Power,Total Dynamic Power,Total Leakage Power"; } print $CSVFH "\n"; # Check log/stats one by one foreach $tmp(@benchmark_names) { $tmp =~ s/\.blif$//g; print $CSVFH "$tmp"; if ("on" eq $opt_ptr->{min_route_chan_width}) { print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{min_route_chan_width}"; print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{fix_route_chan_width}"; } elsif ("on" eq $opt_ptr->{fix_route_chan_width}) { print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{fix_route_chan_width}"; } else { print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{min_route_chan_width}"; } #foreach $tmpkw(@keywords) { @keywords = split /\|/,$conf_ptr->{csv_tags}->{mpack2_tags}->{val}; for($ikw=0; $ikw < ($#keywords+1); $ikw++) { $tmpkw = $keywords[$ikw]; $tmpkw =~ s/\s//g; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{$keywords[$ikw]}"; } @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_tags}->{val}; for($ikw=0; $ikw < ($#keywords+1); $ikw++) { $tmpkw = $keywords[$ikw]; $tmpkw =~ s/\s//g; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{$keywords[$ikw]}"; } if ("on" eq $opt_ptr->{power}) { @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_power_tags}->{val}; for($ikw=0; $ikw < ($#keywords+1); $ikw++) { $tmpkw = $keywords[$ikw]; $tmpkw =~ s/\s//g; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{$keywords[$ikw]}"; } print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{total}"; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{dynamic}"; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{leakage}"; } print $CSVFH "\n"; } } sub gen_csv_rpt_mpack1_flow($ $) { my ($tag,$CSVFH) = @_; my ($tmp,$ikw,$tmpkw); my @keywords; my ($N_val,$M_val) = ($opt_ptr->{N_val},$opt_ptr->{M_val}); # Print out Mpack stats Second print $CSVFH "$tag"; print $CSVFH ",MATRIX"; @keywords = split /\|/,$conf_ptr->{csv_tags}->{mpack_tags}->{val}; for($ikw=0; $ikw < ($#keywords+1); $ikw++) { print $CSVFH ",$keywords[$ikw]"; } @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_tags}->{val}; #foreach $tmpkw(@keywords) { for($ikw=0; $ikw < ($#keywords+1); $ikw++) { print $CSVFH ",$keywords[$ikw]"; } # Print Power Tags @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_power_tags}->{val}; #foreach $tmpkw(@keywords) { for($ikw=0; $ikw < ($#keywords+1); $ikw++) { print $CSVFH ",$keywords[$ikw]"; } print $CSVFH ",Total Power,Total Dynamic Power, Total Leakage Power"; print $CSVFH "\n"; # Check log/stats one by one foreach $tmp(@benchmark_names) { $tmp =~ s/\.blif$//g; print $CSVFH "$tmp"; #foreach $tmpkw(@keywords) { print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$M_val}->{MATRIX}"; @keywords = split /\|/,$conf_ptr->{csv_tags}->{mpack_tags}->{val}; for($ikw=0; $ikw < ($#keywords+1); $ikw++) { $tmpkw = $keywords[$ikw]; $tmpkw =~ s/\s//g; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$M_val}->{$keywords[$ikw]}"; } @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_tags}->{val}; for($ikw=0; $ikw < ($#keywords+1); $ikw++) { $tmpkw = $keywords[$ikw]; $tmpkw =~ s/\s//g; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$M_val}->{$keywords[$ikw]}"; } # Print Power Results @keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_power_tags}->{val}; for($ikw=0; $ikw < ($#keywords+1); $ikw++) { $tmpkw = $keywords[$ikw]; $tmpkw =~ s/\s//g; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$M_val}->{power}->{$keywords[$ikw]}"; } print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$M_val}->{power}->{total}"; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$M_val}->{power}->{dynamic}"; print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$M_val}->{power}->{leakage}"; print $CSVFH "\n"; } } sub init_selected_flows() { # For each flow type, mark the status to off foreach my $flow_type(@supported_flows) { $selected_flows{$flow_type}->{flow_status} = "off"; # For each benchmark, init the status to "off" foreach my $benchmark(@benchmark_names) { $selected_flows{$flow_type}->{benchmarks}->{$benchmark}->{status} = "off"; $selected_flows{$flow_type}->{benchmarks}->{$benchmark}->{thread_id} = undef; } } } sub mark_selected_flows() { # Mark what flows are selected my @flows = split('\|',$conf_ptr->{flow_conf}->{flow_type}->{val}); foreach my $flow_type(@flows) { if (exists $selected_flows{$flow_type}->{flow_status}) { $selected_flows{$flow_type}->{flow_status} = "on"; print "INFO: FLOW TYPE: $flow_type is turned $selected_flows{$flow_type}->{flow_status}\n"; # Initial FPGA SPICE TASK FILE if ("on" eq $opt_ptr->{vpr_fpga_spice}) { &init_fpga_spice_task($opt_ptr->{vpr_fpga_spice_val}."_$flow_type.txt"); } } else { die "ERROR: flow_type: $flow_type is not supported!\n"; } } } sub mark_flows_benchmarks() { foreach my $flow_type(@supported_flows) { if ("on" eq $selected_flows{$flow_type}->{flow_status}) { # For each benchmark, init the status to "off" foreach my $benchmark(@benchmark_names) { $selected_flows{$flow_type}->{benchmarks}->{$benchmark}->{status} = "done"; } } } } sub gen_csv_rpt($) { my ($csv_file) = @_; my ($csv_dir_path, $csv_filename) = &split_prog_path($csv_file); &generate_path($csv_dir_path); # Open a filehandle my ($CSVFH) = (FileHandle->new); if ($CSVFH->open("> $csv_file")) { print "INFO: writing CSV report ($csv_file) ...\n"; } else { die "ERROR: fail to create CSV report ($csv_file) ...\n"; } foreach my $flow_type(@supported_flows) { if ($selected_flows{$flow_type}->{flow_status} eq "on") { # Print the report only all the benchmarks in this flow finished if ($flow_type eq "standard") { if (1 == &check_flow_all_benchmarks_done("standard")) { print "INFO: writing standard flow results ...\n"; &gen_csv_rpt_standard_flow("standard",$CSVFH); } } elsif ($flow_type eq "mpack2") { if (1 == &check_flow_all_benchmarks_done("mpack2")) { print "INFO: writing mpack2 flow results ...\n"; &gen_csv_rpt_mpack2_flow("mpack2",$CSVFH); } } elsif ($flow_type eq "mpack1") { if (1 == &check_flow_all_benchmarks_done("mpack1")) { print "INFO: writing mpack1 flow results ...\n"; &gen_csv_rpt_mpack1_flow("mpack1",$CSVFH); } } elsif ($flow_type eq "vtr_standard") { if (1 == &check_flow_all_benchmarks_done("vtr")) { print "INFO: writing vtr flow results ...\n"; &gen_csv_rpt_standard_flow("vtr_standard",$CSVFH); } } elsif ($flow_type eq "vtr") { if (1 == &check_flow_all_benchmarks_done("vtr")) { print "INFO: writing vtr flow results ...\n"; &gen_csv_rpt_vtr_flow("vtr",$CSVFH); } } elsif ($flow_type eq "vtr_mccl") { if (1 == &check_flow_all_benchmarks_done("vtr_mccl")) { print "INFO: writing vtr_mccl flow results ...\n"; &gen_csv_rpt_standard_flow("vtr_mccl",$CSVFH); } } elsif ($flow_type eq "mccl") { if (1 == &check_flow_all_benchmarks_done("mccl")) { print "INFO: writing mccl flow results ...\n"; &gen_csv_rpt_standard_flow("mccl",$CSVFH); } } elsif ($flow_type eq "mig_mccl") { if (1 == &check_flow_all_benchmarks_done("mig_mccl")) { print "INFO: writing mig_mccl flow results ...\n"; &gen_csv_rpt_standard_flow("mig_mccl",$CSVFH); } } elsif ($flow_type eq "yosys_vpr") { if (1 == &check_flow_all_benchmarks_done("yosys_vpr")) { print "INFO: writing yosys_vpr flow results ...\n"; &gen_csv_rpt_yosys_vpr_flow("yosys_vpr",$CSVFH); } } else { die "ERROR: flow_type: $flow_type is not supported!\n"; } } } close($CSVFH); } sub remove_designs() { if ("on" eq $opt_ptr->{remove_designs}) { `rm -rf $conf_ptr->{dir_path}->{rpt_dir}->{val}`; } } sub plan_run_flows() { if ("on" eq $opt_ptr->{multi_task}) { &multitask_run_flows(); } elsif (("on" eq $opt_ptr->{multi_thread}) &&($opt_ptr->{multi_thread_val} > 1) &&(0 < $#benchmark_names)) { &multithread_run_flows($opt_ptr->{multi_thread_val}); } else { if ("on" eq $opt_ptr->{multi_thread}) { print "INFO: multi_thread is selected but only 1 processor can be used or 1 benchmark to run...\n"; print "INFO: switch to single thread mode.\n"; } &run_flows(); } } # Main Program sub main() { &opts_read(); &read_conf(); &read_benchmarks(); &init_selected_flows(); &mark_selected_flows(); &check_opts(); if ("on" eq $opt_ptr->{parse_results_only}) { &mark_flows_benchmarks(); &parse_flows_benchmarks_results(); } else { &remove_designs(); &plan_run_flows(); } &gen_csv_rpt($opt_ptr->{rpt_val}); } &main(); exit(0);