OpenFPGA/fpga_flow/scripts/m2net.pl

1355 lines
52 KiB
Perl

#!usr/bin/perl -w
# Perl Script to convert MPACK1 netlist for VPR and generate architecture file
# 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;
# 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;
# Matrix informations
my %mclusters;
my ($mclusters_ptr) = (\%mclusters);
# Configuration file keywords list
# Category for conf file.
# main category : 1st class
my @mctgy;
# sub category : 2nd class
my @sctgy;
# Initialize these categories
@mctgy = ("arch_model",
"arch_device",
"arch_complexblocks",
);
# refer to the keywords of arch_model
@{$sctgy[0]} = ("matrix_model_name",
"matrix_inport_name",
"matrix_outport_name",
"cell_model_name",
"cell_inport_name",
"cell_outport_name",
);
# refer to the keywords of arch_device
# Support uni-directional routing architecture and
# single type segment only
@{$sctgy[1]} = ("R_minW_nmos",
"R_minW_pmos",
"ipin_mux_trans_size",
"C_ipin_cblock",
"T_ipin_cblock",
"grid_logic_tile_area",
"mux_R",
"mux_Cin",
"mux_Cout",
"mux_Tdel",
"mux_trans_size",
"mux_buf_size",
"segment_length",
"segment_Rmetal",
"segment_Cmetal",
"local_interconnect_C_wire",
"clock_buffer_size",
"clock_C_wire",
);
# refer to the keywords of arch_complexblocks
@{$sctgy[2]} = (#"io_capacity", should be automatically optimized as 2*sqrt(N)
"CLB_logic_equivalent",
#"matrix_name",
#"matrix_cell_name",
"matrix_delay",
"cell_delay",
"dff_tsetup",
"dff_tclk2q",
"mux2to1_delay", # Delay of a 2:1 multiplexer, script can estimate N:1 multiplexer
"cell_dynamic_power",
"cell_static_power",
);
my ($SiNW_area_ratio) = (1.5);
# ----------Subrountines------------#
# Print TABs
sub print_tabs($ $)
{
my ($num_tab,$FILE) = @_;
my ($my_tab) = (" ");
for (my $i = 0; $i < $num_tab; $i++) {
print $FILE "$my_tab";
}
}
# 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 " perl m2net.pl [-options <value>]\n";
print " Mandatory options: \n";
print " -conf : specify the basic configuration files for m2net\n";
print " -mpack1_rpt : MPACK1 report file\n";
print " -mode <pack_arch|m2net> : select mode\n";
print " 1. pack_arch : only output XML architecture file for AApack\n";
print " 2. m2net : output XML architecture file for VPR, convert *.net file for VPR\n";
print " -N : Number of MCluster inside a CLB\n";
print " -I : Number of input of a CLB\n";
#print " -rpt : m2net running log\n";
print " Mandatory options for -mode pack_arch:\n";
print " -arch_file_pack : filename of output XML format architecture file for AAPack\n";
print " Mandatory options for -mode m2net:\n";
print " -net_file_in : filename of input *.net file from AAPack\n";
print " -net_file_out : filename of output *.net file for VPR\n";
print " -arch_file_vpr : filename of output XML format architecture file for VPR\n";
print " Other Options:\n";
print " -power : add power estimation information to VPR ARCH XML\n";
print " -debug : debug mode\n";
print " -help : print usage\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 "Try: -help for usage.\n";
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";
}
# Read Opt into Hash(opt_ptr) : "opt_name","with_val","mandatory"
# Check mode first
&read_opt_into_hash("mode","on","on");
# Check mandatory options
&read_opt_into_hash("conf","on","on"); # Check -conf
&read_opt_into_hash("mpack1_rpt","on","on"); # Check -mpack1_rpt
&read_opt_into_hash("N","on","on"); # Check -N
&read_opt_into_hash("I","on","on"); # Check -I
#&read_opt_into_hash("rpt","on","on"); # Check -rpt
# Check mandatory options by mode selected
if ("pack_arch" eq $opt_ptr->{"mode_val"}) {
&read_opt_into_hash("arch_file_pack","on","on"); # Check -arch_file_mpack
}
elsif ("m2net" eq $opt_ptr->{"mode_val"}) {
&read_opt_into_hash("arch_file_vpr","on","on"); # Check -arch_file_vpr
&read_opt_into_hash("net_file_in","on","on"); # Check -net_file_in
&read_opt_into_hash("net_file_out","on","on"); # Check -net_file_out
}
else {
print "Error: unknown mode!\n";
print "Help desk:\n";
&print_usage();
}
&read_opt_into_hash("power","off","off"); # Check -power
&opts_echo();
return 1;
}
# List the options
sub opts_echo()
{
print "Echo 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}!\n";
print "Reading $opt_ptr->{conf_val}...";
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 "complete!\n";
print "Checking these keywords...";
&check_keywords_conf();
print "Successfully\n";
close(CONF);
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);
}
# Read MPACK1 Report
# Determine matrix width, matrix height
# Determine matrix internal connections
# Store pack information for each cell
sub read_mpack1_rpt()
{
# Read in these key words
my ($line,$post_line,$line_no);
my ($layer_line_cnt,$mcluster_line_cnt,$mcluster_cnt);
my ($checking_layer,$checking_mclusters,$expected_layer_line_no,$expected_mcluster_line_no) = (0,0,-1,-1);
my ($x,$y);
my @split_line;
# Define keywords
my ($matrix_width,$matrix_depth,$cell_size,$layer,$layer_matrix,$mcluster,$mcluster_cell,$unconn,$conn,$open_net,$end,$mcluster_num) = ("matrix_width","matrix_depth","cell_size","layer_detailed","X","MCluster","cell","unconn","conn","open","end","mclusters_number");
open (MRPT, "< $opt_ptr->{mpack1_rpt_val}") or die "Fail to open mpack1_rpt: $opt_ptr->{mpack1_rpt_val}!\n";
print "Reading $opt_ptr->{mpack1_rpt_val}...";
$line_no = 0;
$mcluster_cnt = 0;
while(defined($line = <MRPT>))
{
chomp $line;
$post_line = &read_line($line,"#");
$line_no = $line_no + 1;
if (defined($post_line))
{
# Remove all spaces...
$post_line =~ s/\s//g;
# This case should not happen!
if ((1 == $checking_layer)&&(1 == $checking_mclusters)) {
die "Error: checking_layer and checking_mclusters both turn on!\n";
}
# TODO List:
if ((0 == $checking_layer)&&(0 == $checking_mclusters)) {
# Check Width
if ($post_line =~ m/^$matrix_width/) {
undef @split_line;
@split_line = split /=/,$post_line;
# Double check
if ($matrix_width eq $split_line[0]) {
$mclusters_ptr->{matrix_width} = $split_line[1];
next;
}
else {
print "Warning:Invalid definition for matrix width at LINE[$line_no]!\n";
}
}
# Check Depth
if ($post_line =~ m/^$matrix_depth/) {
undef @split_line;
@split_line = split /=/,$post_line;
# Double check
if ($matrix_depth eq $split_line[0]) {
$mclusters_ptr->{matrix_depth} = $split_line[1];
next;
}
else {
print "Warning:Invalid definition for matrix depth at LINE[$line_no]!\n";
}
}
# Check cell_size
if ($post_line =~ m/^$cell_size/) {
undef @split_line;
@split_line = split /=/,$post_line;
# Double check
if ($cell_size eq $split_line[0]) {
$mclusters_ptr->{cell_size} = $split_line[1];
next;
}
else {
print "Warning:Invalid definition for cell size at LINE[$line_no]!\n";
}
}
# Check defined MCluster Number
if ($post_line =~ m/^$mcluster_num/) {
undef @split_line;
@split_line = split /=/,$post_line;
# Double check
if ($mcluster_num eq $split_line[0]) {
$mclusters_ptr->{MCluster_num} = $split_line[1];
next;
}
else {
print "Warning:Invalid definition for $mcluster_num at LINE[$line_no]!\n";
}
}
# Check layer
# TODO: We should check layer should only defined ONCE!!!
if ($post_line =~ m/^$layer/) {
$checking_layer = 1;
# Clear Counter
$layer_line_cnt = 0;
# Check valid expected_layer_line_no
$expected_layer_line_no = $mclusters_ptr->{matrix_width}*($mclusters_ptr->{matrix_depth}-1)*$mclusters_ptr->{cell_size};
if (($expected_layer_line_no < 1)&&(1 != $mclusters_ptr->{matrix_width}*$mclusters_ptr->{matrix_depth})) {
die "Error: Invalid expected_layer_line_no($expected_layer_line_no)!\nProbably caused by missing definition of $matrix_width, $matrix_depth, $cell_size before defining $layer...\n";
}
next;
}
# Check MClusters
if ($post_line =~ m/^$mcluster/) {
$checking_mclusters = 1;
# Clear Counter
$mcluster_line_cnt = 0;
# Check valid expected_mcluster_line_no
$expected_mcluster_line_no = $mclusters_ptr->{matrix_width}*$mclusters_ptr->{matrix_depth};
if ($expected_mcluster_line_no < 1) {
die "Error: Invalid expected_mcluster_line_no($expected_mcluster_line_no)!\nProbably caused by missing definition of $matrix_width, $matrix_depth, $cell_size before defining $mcluster...\n";
}
next;
}
}
# Layer FSM
if (1 == $checking_layer) {
# Check expected_layer_line_no
if ($expected_layer_line_no < $layer_line_cnt) {
die "Error: expected_layer_line_no($expected_layer_line_no) unmatch layer_line_cnt($layer_line_cnt)! Missing information for layer definition!\n";
}
if ($post_line =~ m/^$end/) {
$checking_layer = 0;
# Check expected_layer_line_no
if ($expected_layer_line_no != $layer_line_cnt) {
die "Error: expected_layer_line_no($expected_layer_line_no) unmatch layer_line_cnt($layer_line_cnt)! Missing information for layer definition!\n";
}
next;
}
if ($post_line =~ m/^$layer_matrix/) {
undef @split_line;
my ($pin) = ("I");
#@split_line = split /=/,$post_line;
# Get layer x,y, and double check
if ($post_line =~ m/^$layer_matrix\[(\d+)\]\.$pin\[(\d+)\]=(\d+)/) {
# Record des_idx, pin_idx, src_idx
my ($des_idx,$pin_idx,$src_idx) = ($1,$2,$3);
# Record X and Y
my ($des_y,$des_x) = (($des_idx)%($mclusters_ptr->{matrix_width}),int($des_idx/$mclusters_ptr->{matrix_width}));
my ($src_y,$src_x) = (($src_idx)%($mclusters_ptr->{matrix_width}),int($src_idx/$mclusters_ptr->{matrix_width}));
# Check X range. Should be 0 < X < matrix_depth
if (0 == $des_x) {
print "Warning: there is no need to define zero layer at LINE[$line_no]!\n";
next;
}
if ((0 > $des_x)||($des_x > ($mclusters_ptr->{matrix_depth}-1))) {
die "Error: Invalid des_x($des_x) in LINE[$line_no]!\n";
}
# Check Y range. Should be 0 <= Y < matrix_width
if ((0 > $des_y)||($des_y > ($mclusters_ptr->{matrix_width}-1))) {
die "Error: Invalid des_y($des_y) in LINE[$line_no]!\n";
}
# Check X range. Should be 0 < X < matrix_depth
if ((0 > $src_x)||($src_x > ($mclusters_ptr->{matrix_depth}-1))) {
die "Error: Invalid src_x($src_x) in LINE[$line_no]!\n";
}
# Check Y range. Should be 0 <= Y < matrix_width
if ((0 > $src_y)||($src_y > ($mclusters_ptr->{matrix_width}-1))) {
die "Error: Invalid src_y($src_y) in LINE[$line_no]!\n";
}
$mclusters_ptr->{"arch"}->{"cell[$des_x][$des_y]"}->{"I[$pin_idx]"} = $src_y;
# Check matrix content, chomp the last "," and length should be matrix_width
#$split_line[1] =~ s/,$//; # Chomp last ","
#my @tmp = split /,/,$split_line[1];
#if ($#tmp != ($mclusters_ptr->{matrix_width}-1)) {
# die "Error: Invalid length of cross-connectivity matrix!\n";
#}
#my $j = 0;
#for (my $i=0; $i<$mclusters_ptr->{matrix_width}; $i++) {
# Valid $tmp[$i] is either 0 or 1
# if ((0 != $tmp[$i])&&(1 != $tmp[$i])) {
# die "Error: Invalid value of cross-connectivity matrix at LINE[$line_no]!\n";
# }
# if (1 == $tmp[$i]) {
# $mclusters_ptr->{"arch"}->{"cell[$x][$y]"}->{"I[$j]"} = $i;
# $j = $j + 1;
# }
#}
# Check $j (number of input)
#if ($j != $mclusters_ptr->{cell_size}) {
# die "Error: cross-connectivity matrix exceeds cell_size at LINE[$line_no]!\n";
#}
$layer_line_cnt = $layer_line_cnt + 1;
}
else {
print "Warning: Invalid definition of $layer_matrix in $layer at LINE($line_no)!\n";
}
}
next;
}
# Mcluster FSM
if (1 == $checking_mclusters) {
# Check expected_mcluster_line_no
if ($expected_mcluster_line_no < $mcluster_line_cnt) {
die "Error: expected_mcluster_line_no($expected_mcluster_line_no) unmatch mcluster_line_cnt($mcluster_line_cnt)! Missing information for MCluster definition!\n";
}
if ($post_line =~ m/^$end/) {
$checking_mclusters = 0;
# Check expected_mcluster_line_no
if ($expected_mcluster_line_no != $mcluster_line_cnt) {
die "Error: expected_mcluster_line_no($expected_mcluster_line_no) unmatch mcluster_line_cnt($mcluster_line_cnt)! Missing information for MCluster definition!\n";
}
# Incremental Mcluster counter
$mcluster_cnt = $mcluster_cnt + 1;
next;
}
if ($post_line =~ m/^$mcluster_cell/) {
undef @split_line;
@split_line = split /=/,$post_line;
# Get layer x,y, and double check
if ($split_line[0] =~ m/^$mcluster_cell\[(\d+)\]\[(\d+)\]/) {
# Record X and Y
($x,$y) = ($1,$2);
# Check X range. Should be 0 <= X < matrix_depth
if ((0 > $x)||($x > ($mclusters_ptr->{matrix_depth}-1))) {
die "Error: Invalid x($x) in LINE[$line_no]!\n";
}
# Check Y range. Should be 0 <= Y < matrix_width
if ((0 > $y)||($y > ($mclusters_ptr->{matrix_width}-1))) {
die "Error: Invalid y($y) in LINE[$line_no]!\n";
}
# Check matrix content, chomp the last "," and length should be matrix_width
$split_line[1] =~ s/,$//; # Chomp last ","
my @tmp = split /,/,$split_line[1];
if ($#tmp != ($mclusters_ptr->{cell_size})) {
die "Error: Invalid length of MCluster cell definition at LINE[$line_no]!\n";
}
for (my $i=0; $i<$mclusters_ptr->{cell_size}; $i++) {
# Valid $tmp[$i] is either $unconn or $conn
if (($unconn ne $tmp[$i])&&($conn ne $tmp[$i])) {
die "Error: Invalid value of MCluster cell definition at LINE[$line_no]!\n";
}
$mclusters_ptr->{"MCluster$mcluster_cnt"}->{"cell[$x][$y]"}->{"I[$i]"} = $tmp[$i];
}
$mclusters_ptr->{"MCluster$mcluster_cnt"}->{"cell[$x][$y]"}->{"net"} = $tmp[$mclusters_ptr->{cell_size}];
$mcluster_line_cnt = $mcluster_line_cnt + 1;
}
else {
print "Warning: Invalid definition of $mcluster_cell in $mcluster at LINE($line_no)!\n";
}
}
next;
}
}
}
print "complete!\n";
# Check mcluster_number match
if ($mcluster_cnt != $mclusters_ptr->{MCluster_num}) {
die "Error: Mismatch!(Expect $mclusters_ptr->{MCluster_num} MClusters, Actual $mcluster_cnt)\n";
}
close(MRPT);
# Update Number of MClusters
#$mclusters_ptr->{MCluster_num} = $mcluster_cnt;
print "Number of MCluster: $mclusters_ptr->{MCluster_num}\n";
return 1;
}
# Print models for AApack Architecture
sub gen_arch_models_pack()
{
my ($minput_num,$moutput_num) = ($mclusters_ptr->{cell_size}*$mclusters_ptr->{matrix_width},$mclusters_ptr->{matrix_width});
print FARCH " <models>\n";
print FARCH " <model name=\"$conf_ptr->{arch_model}->{matrix_model_name}->{val}\">\n";
print FARCH " <input_ports>\n";
print FARCH " <port name=\"$conf_ptr->{arch_model}->{matrix_inport_name}->{val}\"/>\n";
print FARCH " </input_ports>\n";
print FARCH " <output_ports>\n";
print FARCH " <port name=\"$conf_ptr->{arch_model}->{matrix_outport_name}->{val}\"/>\n";
print FARCH " </output_ports>\n";
print FARCH " </model>\n";
print FARCH " </models>\n";
}
sub gen_arch_device()
{
my ($power_buf_size,$power_mux_trans_size);
($power_buf_size) = ($conf_ptr->{arch_device}->{mux_buf_size}->{val}/$SiNW_area_ratio);
($power_mux_trans_size) = ($conf_ptr->{arch_device}->{mux_trans_size}->{val}/$SiNW_area_ratio);
print FARCH " <layout auto=\"1.0\"/>\n";
print FARCH " <device>\n";
print FARCH " <sizing R_minW_nmos=\"$conf_ptr->{arch_device}->{R_minW_nmos}->{val}\" R_minW_pmos=\"$conf_ptr->{arch_device}->{R_minW_pmos}->{val}\" ipin_mux_trans_size=\"$conf_ptr->{arch_device}->{ipin_mux_trans_size}->{val}\"/>\n";
print FARCH " <timing C_ipin_cblock=\"$conf_ptr->{arch_device}->{C_ipin_cblock}->{val}\" T_ipin_cblock=\"$conf_ptr->{arch_device}->{T_ipin_cblock}->{val}\"/>\n";
print FARCH " <area grid_logic_tile_area=\"$conf_ptr->{arch_device}->{grid_logic_tile_area}->{val}\"/>\n";
print FARCH " <sram area=\"9\"/>\n";
print FARCH " <chan_width_distr>\n";
print FARCH " <io width=\"1.0\"/>\n";
print FARCH " <x distr=\"uniform\" peak=\"1.0\"/>\n";
print FARCH " <y distr=\"uniform\" peak=\"1.0\"/>\n";
print FARCH " </chan_width_distr>\n";
print FARCH " <switch_block type=\"wilton\" fs=\"3\"/>\n";
print FARCH " </device>\n";
print FARCH " <switchlist>\n";
print FARCH " <switch type=\"mux\" name=\"0\" R=\"$conf_ptr->{arch_device}->{mux_R}->{val}\" Cin=\"$conf_ptr->{arch_device}->{mux_Cin}->{val}\" Cout=\"$conf_ptr->{arch_device}->{mux_Cout}->{val}\" Tdel=\"$conf_ptr->{arch_device}->{mux_Tdel}->{val}\" mux_trans_size=\"$conf_ptr->{arch_device}->{mux_trans_size}->{val}\" buf_size=\"$conf_ptr->{arch_device}->{mux_buf_size}->{val}\" power_buf_size=\"$power_buf_size\"/>\n";
print FARCH " </switchlist>\n";
print FARCH " <segmentlist>\n";
print FARCH " <segment freq=\"1.0\" length=\"$conf_ptr->{arch_device}->{segment_length}->{val}\" type=\"unidir\" Rmetal=\"$conf_ptr->{arch_device}->{segment_Rmetal}->{val}\" Cmetal=\"$conf_ptr->{arch_device}->{segment_Cmetal}->{val}\">\n";
print FARCH " <mux name=\"0\"/>\n";
print FARCH " <sb type=\"pattern\">";
for (my $i=0; $i<($conf_ptr->{arch_device}->{segment_length}->{val}+1); $i++) {
print FARCH "1 ";
}
print FARCH "</sb>\n";
print FARCH " <cb type=\"pattern\">";
for (my $i=0; $i<$conf_ptr->{arch_device}->{segment_length}->{val}; $i++) {
print FARCH "1 ";
}
print FARCH "</cb>\n";
print FARCH " </segment>\n";
print FARCH " </segmentlist>\n";
}
sub gen_arch_complexblocks_io()
{
my ($io_optimal) = int(2*sqrt($opt_ptr->{N_val}*$mclusters_ptr->{matrix_width})+0.5);
# Print I/O pad first(Constraint of VPR 7)
print FARCH " <pb_type name=\"io\" capacity=\"$io_optimal\">\n";
print FARCH " <input name=\"outpad\" num_pins=\"1\"/>\n";
print FARCH " <output name=\"inpad\" num_pins=\"1\"/>\n";
print FARCH " <clock name=\"clock\" num_pins=\"1\"/>\n";
print FARCH " <mode name=\"inpad\">\n";
print FARCH " <pb_type name=\"inpad\" blif_model=\".input\" num_pb=\"1\">\n";
print FARCH " <output name=\"inpad\" num_pins=\"1\"/>\n";
print FARCH " </pb_type>\n";
print FARCH " <interconnect>\n";
print FARCH " <direct name=\"inpad\" input=\"inpad.inpad\" output=\"io.inpad\">\n";
print FARCH " <delay_constant max=\"4.243e-11\" in_port=\"inpad.inpad\" out_port=\"io.inpad\"/>\n";
print FARCH " </direct>\n";
print FARCH " </interconnect>\n";
print FARCH " </mode>\n";
print FARCH " <mode name=\"outpad\">\n";
print FARCH " <pb_type name=\"outpad\" blif_model=\".output\" num_pb=\"1\">\n";
print FARCH " <input name=\"outpad\" num_pins=\"1\"/>\n";
print FARCH " </pb_type>\n";
print FARCH " <interconnect>\n";
print FARCH " <direct name=\"outpad\" input=\"io.outpad\" output=\"outpad.outpad\">\n";
print FARCH " <delay_constant max=\"1.394e-11\" in_port=\"io.outpad\" out_port=\"outpad.outpad\"/>\n";
print FARCH " </direct>\n";
print FARCH " </interconnect>\n";
print FARCH " </mode>\n";
print FARCH " <fc default_in_type=\"frac\" default_in_val=\"0.15\" default_out_type=\"frac\" default_out_val=\"0.10\"/>\n";
print FARCH " <pinlocations pattern=\"custom\">\n";
print FARCH " <loc side=\"left\">io.outpad io.inpad io.clock</loc>\n";
print FARCH " <loc side=\"top\">io.outpad io.inpad io.clock</loc>\n";
print FARCH " <loc side=\"right\">io.outpad io.inpad io.clock</loc>\n";
print FARCH " <loc side=\"bottom\">io.outpad io.inpad io.clock</loc>\n";
print FARCH " </pinlocations>\n";
print FARCH " <gridlocations>\n";
print FARCH " <loc type=\"perimeter\" priority=\"10\"/>\n";
print FARCH " </gridlocations>\n";
if ("on" eq $opt_ptr->{power}) {
print FARCH " <power method=\"ignore\"/>\n";
}
print FARCH " </pb_type>\n";
# I/O pad print over
print FARCH "\n";
}
sub gen_arch_complexblocks_dffs()
{
# Print DFFs
print FARCH " <pb_type name=\"ff\" blif_model=\".latch\" num_pb=\"$mclusters_ptr->{matrix_width}\" class=\"flipflop\">\n";
print FARCH " <input name=\"D\" num_pins=\"1\" port_class=\"D\"/>\n";
print FARCH " <output name=\"Q\" num_pins=\"1\" port_class=\"Q\"/>\n";
print FARCH " <clock name=\"clk\" num_pins=\"1\" port_class=\"clock\"/>\n";
print FARCH " <T_setup value=\"$conf_ptr->{arch_complexblocks}->{dff_tsetup}->{val}\" port=\"ff.D\" clock=\"clk\"/>\n";
print FARCH " <T_clock_to_Q max=\"$conf_ptr->{arch_complexblocks}->{dff_tclk2q}->{val}\" port=\"ff.Q\" clock=\"clk\"/>\n";
print FARCH " </pb_type>\n";
print FARCH "\n";
}
# Print Complex Block for Matrix Marco
sub gen_arch_complexblocks_matrix_marco()
{
my ($mcluster_input_num,$mcluster_output_num);
$mcluster_input_num = $mclusters_ptr->{matrix_width}*$mclusters_ptr->{cell_size};
$mcluster_output_num = $mclusters_ptr->{matrix_width};
# Print Matrix Marco Pb_type
print FARCH " <pb_type name=\"matrix\" blif_model=\".subckt $conf_ptr->{arch_model}->{matrix_model_name}->{val}\" num_pb=\"1\">\n";
print FARCH " <input name=\"$conf_ptr->{arch_model}->{matrix_inport_name}->{val}\" num_pins=\"$mcluster_input_num\"/>\n";
print FARCH " <output name=\"$conf_ptr->{arch_model}->{matrix_outport_name}->{val}\" num_pins=\"$mcluster_output_num\"/>\n";
print FARCH " <delay_matrix type=\"max\" in_port=\"matrix.$conf_ptr->{arch_model}->{matrix_inport_name}->{val}\" out_port=\"matrix.$conf_ptr->{arch_model}->{matrix_outport_name}->{val}\">\n";
for (my $i=0; $i<$mcluster_input_num; $i++) {
print FARCH " ";
for (my $j=0; $j<$mcluster_output_num; $j++) {
print FARCH "$conf_ptr->{arch_complexblocks}->{matrix_delay}->{val} ";
}
print FARCH "\n";
}
print FARCH " </delay_matrix>\n";
print FARCH " </pb_type>\n";
}
# Print Complex Blocks for CLB, only for AAPack
sub gen_arch_complexblocks_clb_pack()
{
my ($clb_input_num,$clb_output_num);
my ($mcluster_input_num,$mcluster_output_num);
$mcluster_input_num = $mclusters_ptr->{matrix_width}*$mclusters_ptr->{cell_size};
$mcluster_output_num = $mclusters_ptr->{matrix_width};
$clb_input_num = $opt_ptr->{I_val};
$clb_output_num = $opt_ptr->{N_val}*$mclusters_ptr->{matrix_width};
# Print CLB general information
print FARCH " <pb_type name=\"clb\">\n";
print FARCH " <input name=\"I\" num_pins=\"$clb_input_num\" equivalent=\"$conf_ptr->{arch_complexblocks}->{CLB_logic_equivalent}->{val}\"/>\n";
print FARCH " <output name=\"O\" num_pins=\"$clb_output_num\" equivalent=\"false\"/>\n";
print FARCH " <clock name=\"clk\" num_pins=\"1\"/>\n";
# Print Sub Complex Block "BLE"
print FARCH " <pb_type name=\"mble\" num_pb=\"$opt_ptr->{N_val}\">\n";
print FARCH " <input name=\"I\" num_pins=\"$mcluster_input_num\"/>\n";
print FARCH " <output name=\"O\" num_pins=\"$mcluster_output_num\"/>\n";
print FARCH " <clock name=\"clk\" num_pins=\"1\"/>\n";
&gen_arch_complexblocks_matrix_marco();
&gen_arch_complexblocks_dffs();
# Print interconnections for BLE
my ($ff_idx) = ($mcluster_output_num-1);
print FARCH " <interconnect>\n";
# Clock
print FARCH " <complete name=\"mble_clks\" input=\"mble.clk\" output=\"ff[$ff_idx:0].clk\"/>\n";
print FARCH " <direct name=\"mble_direct\" input=\"mble.I\" output=\"matrix.$conf_ptr->{arch_model}->{matrix_inport_name}->{val}\"/>\n";
print FARCH " <direct name=\"mble_ff\" input=\"matrix.$conf_ptr->{arch_model}->{matrix_outport_name}->{val}\" output=\"ff[$ff_idx:0].D\"/>\n";
for (my $i=0; $i<$mclusters_ptr->{matrix_width}; $i++) {
print FARCH " <mux name=\"mux_ff\[$i\]\" input=\"ff\[$i\].Q matrix.$conf_ptr->{arch_model}->{matrix_outport_name}->{val}\[$i\]\" output=\"mble.O\[$i\]\">\n";
print FARCH " <delay_constant max=\"$conf_ptr->{arch_complexblocks}->{mux2to1_delay}->{val}\" in_port=\"ff[$i].Q matrix.$conf_ptr->{arch_model}->{matrix_outport_name}->{val}\[$i\]\" out_port=\"mble.O\[$i\]\"/>\n";
print FARCH " </mux>\n";
}
print FARCH " </interconnect>\n";
print FARCH " </pb_type>\n";
# Print interconnection for CLB
my ($crossbar_delay) = ($conf_ptr->{arch_complexblocks}->{mux2to1_delay}->{val}*int(log($clb_input_num+$opt_ptr->{N_val}*$mcluster_output_num-1)/log(2)+1));
my ($mble_idx) = ($opt_ptr->{N_val}-1);
print FARCH " <interconnect>\n";
# Crossbar
print FARCH " <complete name=\"crossbar\" input=\"clb.I mble[$mble_idx:0].O\" output=\"mble.I\">\n";
print FARCH " <delay_constant max=\"$crossbar_delay\" in_port=\"clb.I mble[$mble_idx:0].O\" out_port=\"mble.I\"/>\n";
print FARCH " </complete>\n";
# Clock
print FARCH " <complete name=\"clb_clks\" input=\"clb.clk\" output=\"mble[$mble_idx:0].clk\"/>\n";
print FARCH " <direct name=\"clb_direct\" input=\"mble[$mble_idx:0].O\" output=\"clb.O\"/>\n";
print FARCH " </interconnect>\n";
print FARCH " <fc default_in_type=\"frac\" default_in_val=\"0.15\" default_out_type=\"frac\" default_out_val=\"0.10\"/>\n";
print FARCH " <pinlocations pattern=\"spread\"/>\n";
print FARCH " <gridlocations>\n";
print FARCH " <loc type=\"fill\" priority=\"1\"/>\n";
print FARCH " </gridlocations>\n";
print FARCH " </pb_type>\n";
print FARCH "\n";
}
# Print Complex Blocks for AAPack usage
sub gen_arch_complexblocks_pack()
{
print FARCH " <complexblocklist>\n";
# Print I/O pad first
&gen_arch_complexblocks_io();
# Print Matrix-based Pb_type
&gen_arch_complexblocks_clb_pack();
print FARCH " </complexblocklist>\n";
}
sub gen_arch_pack()
{
my ($line,$post_line,$line_no);
print "Generating Architecture XML($opt_ptr->{arch_file_pack_val}) for AAPack...";
open (FARCH, "> $opt_ptr->{arch_file_pack_val}") or die "Fail to open arch_pack: $opt_ptr->{arch_file_pack_val}!\n";
print FARCH "<!-- VPR7 Architecture for AAPack-->\n";
print FARCH "<!-- Designed for MPACK1 -->\n";
print FARCH "<!-- Author : Xifan TANG -->\n";
print FARCH "<!-- EPFL LSI -->\n";
print FARCH "<!-- Date: $mydate -->\n";
print FARCH "<!-- I = $opt_ptr->{I_val} -->\n";
print FARCH "<!-- N = $opt_ptr->{N_val} -->\n";
print FARCH "<!-- Matrix Width = $mclusters_ptr->{matrix_width} -->\n";
print FARCH "<!-- Matrix Depth = $mclusters_ptr->{matrix_depth} -->\n";
print FARCH "<!-- cell_size = $mclusters_ptr->{cell_size} -->\n";
print FARCH "<architecture>\n";
# Write <Models>
&gen_arch_models_pack();
# Write <Devices>
&gen_arch_device();
# Write <ComplexBlocks>
&gen_arch_complexblocks_pack();
print FARCH "</architecture>\n";
close(FARCH);
print "Complete.\n";
}
# Print models for VPR Architecture
sub gen_arch_models_vpr()
{
my ($minput_num,$moutput_num) = ($mclusters_ptr->{cell_size},1);
print FARCH " <models>\n";
print FARCH " <model name=\"$conf_ptr->{arch_model}->{cell_model_name}->{val}\">\n";
print FARCH " <input_ports>\n";
print FARCH " <port name=\"$conf_ptr->{arch_model}->{cell_inport_name}->{val}\"/>\n";
print FARCH " </input_ports>\n";
print FARCH " <output_ports>\n";
print FARCH " <port name=\"$conf_ptr->{arch_model}->{cell_outport_name}->{val}\"/>\n";
print FARCH " </output_ports>\n";
print FARCH " </model>\n";
print FARCH " </models>\n";
}
# Print Complex Block for Matrix Cells
sub gen_arch_complexblocks_matrix_cells()
{
my ($num_cell) = ($mclusters_ptr->{matrix_width}*$mclusters_ptr->{matrix_depth});
# Print Matrix Cell Pb_type
print FARCH " <pb_type name=\"cell\" blif_model=\".subckt $conf_ptr->{arch_model}->{cell_model_name}->{val}\" num_pb=\"$num_cell\">\n";
print FARCH " <input name=\"$conf_ptr->{arch_model}->{cell_inport_name}->{val}\" num_pins=\"$mclusters_ptr->{cell_size}\"/>\n";
print FARCH " <output name=\"$conf_ptr->{arch_model}->{cell_outport_name}->{val}\" num_pins=\"1\"/>\n";
print FARCH " <delay_matrix type=\"max\" in_port=\"cell.$conf_ptr->{arch_model}->{cell_inport_name}->{val}\" out_port=\"cell.$conf_ptr->{arch_model}->{cell_outport_name}->{val}\">\n";
for (my $i=0; $i<$mclusters_ptr->{cell_size}; $i++) {
print FARCH " ";
print FARCH "$conf_ptr->{arch_complexblocks}->{cell_delay}->{val} ";
print FARCH "\n";
}
print FARCH " </delay_matrix>\n";
if ("on" eq $opt_ptr->{power}) {
print FARCH " <power method=\"absolute\">\n";
print FARCH " <dynamic_power power_per_instance=\"$conf_ptr->{arch_complexblocks}->{cell_dynamic_power}->{val}\"/>\n";
print FARCH " <static_power power_per_instance=\"$conf_ptr->{arch_complexblocks}->{cell_static_power}->{val}\"/>\n";
print FARCH " </power>\n";
}
print FARCH " </pb_type>\n";
}
# Print Complex Blocks for CLB, only for VPR
sub gen_arch_complexblocks_clb_vpr()
{
my ($clb_input_num,$clb_output_num);
my ($mcluster_input_num,$mcluster_output_num);
$mcluster_input_num = $mclusters_ptr->{matrix_width}*$mclusters_ptr->{cell_size};
$mcluster_output_num = $mclusters_ptr->{matrix_width};
$clb_input_num = $opt_ptr->{I_val};
$clb_output_num = $opt_ptr->{N_val}*$mclusters_ptr->{matrix_width};
# Print CLB general information
print FARCH " <pb_type name=\"clb\">\n";
print FARCH " <input name=\"I\" num_pins=\"$clb_input_num\" equivalent=\"$conf_ptr->{arch_complexblocks}->{CLB_logic_equivalent}->{val}\"/>\n";
print FARCH " <output name=\"O\" num_pins=\"$clb_output_num\" equivalent=\"false\"/>\n";
print FARCH " <clock name=\"clk\" num_pins=\"1\"/>\n";
# Print Sub Complex Block "BLE"
print FARCH " <pb_type name=\"mble\" num_pb=\"$opt_ptr->{N_val}\">\n";
print FARCH " <input name=\"I\" num_pins=\"$mcluster_input_num\"/>\n";
print FARCH " <output name=\"O\" num_pins=\"$mcluster_output_num\"/>\n";
print FARCH " <clock name=\"clk\" num_pins=\"1\"/>\n";
print FARCH " <pb_type name=\"matrix\" num_pb=\"1\">\n";
print FARCH " <input name=\"$conf_ptr->{arch_model}->{matrix_inport_name}->{val}\" num_pins=\"$mcluster_input_num\"/>\n";
print FARCH " <output name=\"$conf_ptr->{arch_model}->{matrix_outport_name}->{val}\" num_pins=\"$mcluster_output_num\"/>\n";
&gen_arch_complexblocks_matrix_cells();
print FARCH " <interconnect>\n";
# Print Interconnection Scheme(Internal Matrix), cell[$i][$j], $i->row $j->column
for (my $i=0; $i<$mclusters_ptr->{matrix_depth}; $i++) {
for (my $j=0; $j<$mclusters_ptr->{matrix_width}; $j++) {
my ($cell_num) = ($i*$mclusters_ptr->{matrix_width} + $j);
for (my $k=0; $k<$mclusters_ptr->{cell_size}; $k++) {
if (0 == $i) {
my ($input_idx) = ($j*$mclusters_ptr->{cell_size}+$k);
print FARCH " <direct name=\"cell[$i][$j]_input[$k]\" input=\"matrix.$conf_ptr->{arch_model}->{matrix_inport_name}->{val}\[$input_idx\]\" output=\"cell[$cell_num].$conf_ptr->{arch_model}->{cell_inport_name}->{val}\[$k\]\"/>\n";
}
else {
my ($pred_idx) = ($mclusters_ptr->{"arch"}->{"cell[$i][$j]"}->{"I[$k]"}+($i-1)*$mclusters_ptr->{matrix_width});
print FARCH " <direct name=\"cell[$i][$j]_input[$k]\" input=\"cell[$pred_idx].$conf_ptr->{arch_model}->{cell_outport_name}->{val}\" output=\"cell[$cell_num].$conf_ptr->{arch_model}->{cell_inport_name}->{val}\[$k\]\"/>\n";
}
}
}
}
# Print Output direct interconnections, cells.O -> matrix.O
for (my $j=0; $j<$mclusters_ptr->{matrix_width}; $j++) {
my ($last_layer) = ($mclusters_ptr->{matrix_depth}-1);
my ($pred_idx) = ($mclusters_ptr->{matrix_width}*$last_layer + $j);
print FARCH " <direct name=\"matrix_output[$j]\" input=\"cell[$pred_idx].$conf_ptr->{arch_model}->{cell_outport_name}->{val}\" output=\"matrix.$conf_ptr->{arch_model}->{matrix_outport_name}->{val}\[$j\]\"/>\n";
}
print FARCH " </interconnect>\n";
print FARCH " </pb_type>\n";
&gen_arch_complexblocks_dffs();
# Print interconnections for BLE
my ($ff_idx) = ($mcluster_output_num-1);
print FARCH " <interconnect>\n";
# Clock
print FARCH " <complete name=\"mble_clks\" input=\"mble.clk\" output=\"ff[$ff_idx:0].clk\"/>\n";
print FARCH " <direct name=\"mble_direct\" input=\"mble.I\" output=\"matrix.$conf_ptr->{arch_model}->{matrix_inport_name}->{val}\"/>\n";
print FARCH " <direct name=\"mble_ff\" input=\"matrix.$conf_ptr->{arch_model}->{matrix_outport_name}->{val}\" output=\"ff[$ff_idx:0].D\"/>\n";
# Print MUX for DFFs
for (my $i=0; $i<$mclusters_ptr->{matrix_width}; $i++) {
my ($cur_cell_idx) = ($i+$mclusters_ptr->{matrix_width}*($mclusters_ptr->{matrix_depth}-1));
print FARCH " <mux name=\"mux_ff[$i]\" input=\"ff[$i].Q matrix.O[$i]\" output=\"mble.O[$i]\">\n";
print FARCH " <delay_constant max=\"$conf_ptr->{arch_complexblocks}->{mux2to1_delay}->{val}\" in_port=\"ff[$i].Q matrix.O[$i]\" out_port=\"mble.O[$i]\"/>\n";
print FARCH " </mux>\n";
}
print FARCH " </interconnect>\n";
print FARCH " </pb_type>\n";
# Print interconnection for CLB
my ($crossbar_delay) = ($conf_ptr->{arch_complexblocks}->{mux2to1_delay}->{val}*int(log($clb_input_num+$opt_ptr->{N_val}*$mcluster_output_num-1)/log(2)+1));
my ($mble_idx) = ($opt_ptr->{N_val}-1);
print FARCH " <interconnect>\n";
# Crossbar
print FARCH " <complete name=\"crossbar\" input=\"clb.I mble[$mble_idx:0].O\" output=\"mble.I\">\n";
print FARCH " <delay_constant max=\"$crossbar_delay\" in_port=\"clb.I mble[$mble_idx:0].O\" out_port=\"mble.I\"/>\n";
print FARCH " </complete>\n";
# Clock
print FARCH " <complete name=\"clb_clks\" input=\"clb.clk\" output=\"mble[$mble_idx:0].clk\"/>\n";
print FARCH " <direct name=\"clb_direct\" input=\"mble[$mble_idx:0].O\" output=\"clb.O\"/>\n";
print FARCH " </interconnect>\n";
print FARCH " <fc default_in_type=\"frac\" default_in_val=\"0.15\" default_out_type=\"frac\" default_out_val=\"0.10\"/>\n";
print FARCH " <pinlocations pattern=\"spread\"/>\n";
print FARCH " <gridlocations>\n";
print FARCH " <loc type=\"fill\" priority=\"1\"/>\n";
print FARCH " </gridlocations>\n";
#print FARCH " <power method=\"auto-size\">\n";
#print FARCH " </power>\n";
print FARCH " </pb_type>\n";
print FARCH "\n";
}
# Print Complex Blocks for VPR usage
sub gen_arch_complexblocks_vpr()
{
print FARCH " <complexblocklist>\n";
# Print I/O pad first
&gen_arch_complexblocks_io();
# Print Matrix-based Pb_type
&gen_arch_complexblocks_clb_vpr();
print FARCH " </complexblocklist>\n";
}
sub gen_arch_vpr()
{
my ($line,$post_line,$line_no);
print "Generating Architecture XML($opt_ptr->{arch_file_vpr_val}) for VPR 7...";
open (FARCH, "> $opt_ptr->{arch_file_vpr_val}") or die "Fail to open arch_vpr: $opt_ptr->{arch_file_vpr_val}!\n";
print FARCH "<!-- VPR7 Architecture for VPR-->\n";
print FARCH "<!-- Designed for MPACK1 -->\n";
print FARCH "<!-- Author : Xifan TANG -->\n";
print FARCH "<!-- EPFL LSI -->\n";
print FARCH "<!-- Date: $mydate -->\n";
print FARCH "<!-- I = $opt_ptr->{I_val} -->\n";
print FARCH "<!-- N = $opt_ptr->{N_val} -->\n";
print FARCH "<!-- Matrix Width = $mclusters_ptr->{matrix_width} -->\n";
print FARCH "<!-- Matrix Depth = $mclusters_ptr->{matrix_depth} -->\n";
print FARCH "<!-- cell_size = $mclusters_ptr->{cell_size} -->\n";
print FARCH "<architecture>\n";
# Write <Models>
&gen_arch_models_vpr();
# Write <Devices>
&gen_arch_device();
# Write <ComplexBlocks>
&gen_arch_complexblocks_vpr();
if ("on" eq $opt_ptr->{power}) {
my ($power_buf_size,$power_mux_trans_size);
($power_buf_size) = ($conf_ptr->{arch_device}->{mux_buf_size}->{val}/$SiNW_area_ratio);
($power_mux_trans_size) = ($conf_ptr->{arch_device}->{mux_trans_size}->{val}/$SiNW_area_ratio);
print FARCH " <power>\n";
print FARCH " <local_interconnect C_wire=\"$conf_ptr->{arch_device}->{local_interconnect_C_wire}->{val}\"/>\n";
print FARCH " <mux_transistor_size mux_transistor_size=\"$power_mux_trans_size\"/>\n";
print FARCH " </power>\n";
print FARCH " <clocks>\n";
print FARCH " <clock buffer_size=\"$conf_ptr->{arch_device}->{clock_buffer_size}->{val}\" C_wire=\"$conf_ptr->{arch_device}->{clock_C_wire}->{val}\"/>\n";
print FARCH " </clocks>\n";
}
print FARCH "</architecture>\n";
close(FARCH);
print "Complete\n";
}
sub gen_net_vpr()
{
my ($mytab) = (" ");
my %net_map;
my ($net_map_ptr) = (\%net_map);
my ($line);
my ($state,$next_state,$mcluster_index) = ("ST_NORMAL","ST_NORMAL",-1);
my ($nets);
print "Building Hash mapping nets names to MCluster Index...\n";
# 1. Build a hash map net names to MCluster index
for (my $i=0; $i<$mclusters_ptr->{MCluster_num}; $i++) {
my (@net_names);
for (my $j=0; $j<$mclusters_ptr->{matrix_width}; $j++) {
my ($last_layer) = ($mclusters_ptr->{matrix_depth}-1);
$net_names[$j] = $mclusters_ptr->{"MCluster$i"}->{"cell[$last_layer][$j]"}->{net};
}
my ($nets) = join($mytab,@net_names);
$nets = $nets.$mytab;
#print "DEBUG: NETs($nets)\n";
$net_map_ptr->{"$nets"}->{"Mcluster_index"} = $i;
}
print "Generating Net_file_VPR ($opt_ptr->{net_file_out_val}) from Net_file_AAPACK ($opt_ptr->{net_file_in_val})...";
# 2. Replace Part of *.net format file
# Open net_file_in, read-only
open (FNETI, "< $opt_ptr->{net_file_in_val}") or die "Fail to open input *net formate file: $opt_ptr->{net_file_in_val}!\n";
# Open net_file_out, write-only
open (FNETO, "> $opt_ptr->{net_file_out_val}") or die "Fail to open output *net formate file: $opt_ptr->{net_file_out_val}!\n";
# Copy & Paste from FNETI to FNETO
$state = "ST_NORMAL";
while (defined($line = <FNETI>)) {
chomp $line;
# States : ST_NORMAL, ST_SKIP_INPUTS, ST_MODIFY_OUTPUTS, ST_SKIP_CLOCK
# ST_NORAML: Try to match instance = "matrix"
# ST_SKIP_INPUTS: We got matched "matrix", skip the <inputs>
# ST_MODIFT_OUTPUTS: We got matched "matrix and skip the <inputs>, modify <outputs>
# ST_SKIP_CLOCK: We got matched matrix, skip <inputs> and modify <outputs>, skip <clock> and add subblocks
if ("ST_NORMAL" eq $state) {
# Regular expression to match block name="" instance=""
if ($line =~ m/block(\s+)name(\s*)=(\s*)\"([\w\d\[\]\_\-\&\^\;]+)\"(\s+)instance(\s*)=(\s*)\"([\w\d\[\]\_\-\&\^\;]+)\"/) {
my ($name,$instance) = ($4,$8);
# Change state only when name != open
# Replace the outputs of instance = matrix
if (("open" ne $name)&&($instance =~ m/matrix/)) {
# Inside a matrix, skip inputs, switch to state = ST_SKIP_INPUTS
print FNETO " ";
print FNETO "<block name=\"$name\" instance=\"$instance\" mode=\"matrix\">\n";
$next_state = "ST_SKIP_INPUTS";
next;
}
}
print FNETO "$line\n";
}
elsif ("ST_SKIP_INPUTS" eq $state) {
# Match <inputs>, DEBUG
if (($line =~ m/\<inputs\>/)&&("on" eq $opt_ptr->{debug})) {
print "DEBUG: Match <inputs>\n";
}
# Match </inputs>
if ($line =~ m/\<\/inputs\>/) {
$next_state = "ST_MODIFY_OUTPUTS";
$mcluster_index = -1;
}
print FNETO "$line\n";
}
elsif ("ST_MODIFY_OUTPUTS" eq $state) {
my ($line_copy) = ($line);
# Determine the index of MCluster by comparing net_names!
# Match <port name=""> net_names </port>
if ($line_copy =~ m/<port(\s+)name(\s*)=(\s*)\"$conf_ptr->{arch_model}->{matrix_outport_name}->{val}\">([\d\w\_\s\-\^\&\;\[\]]+)<\/port>/) {
($nets) = ($4);
}
$line_copy = $line;
# Match </outputs> and print modified outputs
if ($line_copy =~ m/\<\/outputs\>/) {
my ($format_nets);
$next_state = "ST_SKIP_CLOCK";
# Check Valid MCluster_index
my @net_names = split /\s+/,$nets;
for (my $i = 0; $i < ($#net_names+1); $i++) {
$format_nets = $format_nets."$net_names[$i]$mytab";
}
if (exists($net_map_ptr->{"$format_nets"}->{"Mcluster_index"})) {
$mcluster_index = $net_map_ptr->{"$format_nets"}->{"Mcluster_index"};
}
else {
die "Error: Invalid Net names($format_nets)\n";
}
print FNETO " ";
print FNETO "<outputs>\n";
my ($last_layer) = ($mclusters_ptr->{matrix_depth}-1);
print FNETO " <port name=\"O\">";
for (my $i = 0; $i < $mclusters_ptr->{matrix_width}; $i++) {
my ($pred_idx) = ($mclusters_ptr->{matrix_width}*$last_layer + $i);
print FNETO "cell[$pred_idx].$conf_ptr->{arch_model}->{cell_outport_name}->{val}\-\>matrix_output[$i] ";
}
print FNETO "</port>\n";
print FNETO " ";
print FNETO "</outputs>\n";
print FNETO " ";
print FNETO "<clocks>\n";
print FNETO " ";
print FNETO "</clocks>\n";
}
}
elsif ("ST_SKIP_CLOCK" eq $state) {
# Match <clocks> and print subblocks
if ($line =~ m/\<\/clocks\>/) {
$next_state = "ST_NORMAL";
# Check mcluster_index
if (-1 == $mcluster_index) {
die "Error: Invalid mcluster index: $mcluster_index!\n";
}
# Print subblocks
my ($num_cell) = ($mclusters_ptr->{matrix_width}*$mclusters_ptr->{matrix_depth});
for (my $i = 0; $i < $mclusters_ptr->{matrix_depth}; $i++) {
for (my $j = 0; $j < $mclusters_ptr->{matrix_width}; $j++) {
my ($cell_idx) = $i*$mclusters_ptr->{matrix_width} + $j;
# Fill block_name and instance_name
my ($block_name,$instance_name) = ($mclusters_ptr->{"MCluster$mcluster_index"}->{"cell[$i][$j]"}->{net},"cell[$cell_idx]");
print FNETO " ";
print FNETO "<block name=\"$block_name\" instance=\"$instance_name\">\n";
# Check if this block has been used.
if ("open" ne $block_name) {
# Print Input Ports, Output Ports, ignore clocks
print FNETO " ";
print FNETO " <inputs>\n";
print FNETO " ";
print FNETO " <port name=\"$conf_ptr->{arch_model}->{cell_inport_name}->{val}\">";
for (my $k = 0; $k < $mclusters_ptr->{cell_size}; $k++) {
if ("unconn" eq $mclusters_ptr->{"MCluster$mcluster_index"}->{"cell[$i][$j]"}->{"I[$k]"}) {
print FNETO "open ";
}
elsif (0 == $i) {
my ($tmp_idx) = ($j*$mclusters_ptr->{cell_size}+$k);
print FNETO "matrix[0].I[$tmp_idx]\-\>cell[$i][$j]_input[$k] ";
}
else {
my ($pred_idx) = ($mclusters_ptr->{"arch"}->{"cell[$i][$j]"}->{"I[$k]"}+($i-1)*$mclusters_ptr->{matrix_width});
print FNETO "cell[$pred_idx].$conf_ptr->{arch_model}->{cell_outport_name}->{val}\-\>cell[$i][$j]_input[$k] ";
}
}
print FNETO "</port>\n";
print FNETO " ";
print FNETO " </inputs>\n";
print FNETO " ";
print FNETO " <outputs>\n";
print FNETO " ";
print FNETO " <port name=\"$conf_ptr->{arch_model}->{cell_outport_name}->{val}\">";
print FNETO "$block_name ";
print FNETO "</port>\n";
print FNETO " ";
print FNETO " </outputs>\n";
print FNETO " ";
print FNETO " <clocks>\n";
print FNETO " ";
print FNETO " </clocks>\n";
}
print FNETO " ";
print FNETO "</block>\n";
}
}
}
}
$state = $next_state;
if ("on" eq $opt_ptr->{debug}) {
print "DEBUG: Current State=$state\n";
}
}
# Close files
close(FNETI);
close(FNETO);
#print "Generate Net_file_VPR \($opt_ptr->{net_file_out_val}\) from Net_file_AAPACK \($opt_ptr->{net_file_in_val}\) Complete\n";
print "Complete\n";
}
# Main Program
sub main()
{
# Read Options. All options stored in opt_ptr
&opts_read();
# Read basic configuration file. All confs stored in conf_ptr
&read_conf();
# Read mpack report file
&read_mpack1_rpt();
# Complete tasks according to selected mode
if ("pack_arch" eq $opt_ptr->{"mode_val"}) {
# Generate Architecture XML for AAPack
&gen_arch_pack();
}
elsif ("m2net" eq $opt_ptr->{"mode_val"}) {
# Generate Architecture XML for VPR
&gen_arch_vpr();
# Generate Net for VPR
&gen_net_vpr();
}
else {
die "Error: Invalid mode selected!\n";
}
}
&main();
exit(0);