3359 lines
123 KiB
Perl
Executable File
3359 lines
123 KiB
Perl
Executable File
#!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"
|
|
);
|
|
|
|
# ----------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 <value>]\n";
|
|
print " Mandatory options: \n";
|
|
print " -conf <file> : specify the basic configuration files for fpga_flow\n";
|
|
print " -benchmark <file> : the configuration file contains benchmark file names\n";
|
|
print " -rpt <file> : CSV file consists of data\n";
|
|
print " -N <int> : N-LUT/Matrix\n";
|
|
print " Other Options:\n";
|
|
print " [ General ] \n";
|
|
print " \t-I <int> : Number of inputs of a CLB, mandatory when mpack1 flow is chosen\n";
|
|
print " \t-K <int> : K-LUT, mandatory when standard flow is chosen\n";
|
|
print " \t-M <int> : 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 <int>: turn on the mutli-thread mode, specify the number of threads\n";
|
|
print " \t-multi_task <int>: 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 <float> : specify the default signal probablity of PIs in ACE2.\n";
|
|
print " \t-ace_d <float> : 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 <int> : 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 <float> : turn on routing with <float>* 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 <float>: specify the option signal_density_weight of VPR FPGA SPICE\n";
|
|
print " \t-vpr_fpga_x2p_sim_window_size <float>: specify the option sim_window_size of VPR FPGA SPICE\n";
|
|
print " [ VPR - FPGA-SPICE Extension ] \n";
|
|
print " \t-vpr_fpga_spice <task_file> : turn on SPICE netlists print-out in VPR, specify a task file\n";
|
|
print " \t-vpr_fpga_spice_sim_mt_num <int>: 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 <verilog_path>: 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 <path_to_generate_reports> : 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 <modelsim.ini_path>: 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 = <CONF>))
|
|
{
|
|
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 = <FCONF>))
|
|
{
|
|
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 = <BLIF>)) {
|
|
chomp $line;
|
|
if ($line =~ /^\.latch/) {
|
|
close(BLIF);
|
|
return "seq";
|
|
}
|
|
}
|
|
close(BLIF);
|
|
return "comb";
|
|
}
|
|
|
|
# Check Options
|
|
sub check_opts() {
|
|
# Task 1: min_chan_width <float> > 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 "# C;ean 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 $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 = <MSTATS>)) {
|
|
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 = <MSTATS>)) {
|
|
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 = <BF>)) {
|
|
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 = <VSTATS>)) {
|
|
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 = <VSTATS>)) {
|
|
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 = <VSTATS>)) {
|
|
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 = <VSTATS>)) {
|
|
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 "<config>\n";
|
|
print $XMLFH " <verilog_files>\n";
|
|
print $XMLFH " <verilog_file>$odin2_verilog</verilog_file>\n";
|
|
print $XMLFH " </verilog_files>\n";
|
|
print $XMLFH " <output>\n";
|
|
print $XMLFH " <output_type>blif</output_type>\n";
|
|
print $XMLFH " <output_path_and_name>$odin2_blif_out</output_path_and_name>\n";
|
|
print $XMLFH " <target>\n";
|
|
print $XMLFH " <arch_file>$vpr_arch</arch_file>\n";
|
|
print $XMLFH " </target>\n";
|
|
print $XMLFH " </output>\n";
|
|
print $XMLFH " <optimizations>\n";
|
|
print $XMLFH " <multiply size=\"3\" fixed=\"1\" fracture=\"0\" padding=\"-1\"/>\n";
|
|
print $XMLFH " <memory split_memory_width=\"1\" split_memory_depth=\"$mem_size\"/>\n";
|
|
print $XMLFH " <adder size=\"0\" threshold_size=\"$min_hard_adder_size\"/>\n";
|
|
print $XMLFH " </optimizations>\n";
|
|
print $XMLFH " <debug_outputs>\n";
|
|
print $XMLFH " <debug_output_path>.</debug_output_path>\n";
|
|
print $XMLFH " <output_ast_graphs>1</output_ast_graphs>\n";
|
|
print $XMLFH " <output_netlist_graphs>1</output_netlist_graphs>\n";
|
|
print $XMLFH " </debug_outputs>\n";
|
|
print $XMLFH "</config>\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($ $) {
|
|
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 avoid_clk_option $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 "# <benchmark_name>,<blif_prefix>,<spice_dir>\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) = ("$rpt_dir/$benchmark".".act","$rpt_dir/$benchmark".".blif","$prefix"."ace.log");
|
|
&run_ace_in_flow($prefix, $yosys_blif_out, $act_file, $ace_new_blif, $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";
|
|
|
|
# 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, $ace_new_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);
|