#!/usr/bin/perl
#
# Copyright (c) 2006-2007 Salvador E. Tropea <salvador en inti.gov.ar>
# Copyright (c) 2006-2007 Instituto Nacional de Tecnología Industrial
#
# Based on code:
# Copyright (c) 2005 Juan Pablo D. Borgna <jpborgna en inti gov ar>
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; version 2.
# 
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
# 
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#  02111-1307, USA
# 
# Este script invoca a bit2svf y jtag para programar el contenido de
# un archivo bit en un dispositivo Xilinx.
#
# Basado en el script original de Juan Pablo D. Borgna
#
#

use Getopt::Long;
use File::Basename;

print "jbit - bit2svf/jtag short cut - v2.1\n";
print "Copyright (c) 2006-2007 Salvador E. Tropea/INTI\n\n";

GetOptions(
 'skip=s'  => \$skip,
 'length=s' => \$len,
 'help'     => \&help);

if (scalar(@ARGV)!=2)
  {
   print "You must specify two arguments\n\n";
   help();
  }

$bitfile=@ARGV[0];

# Seteos por defecto
$jtag="/usr/bin/jtag";
$bit2svf="/usr/bin/bit2svf";
$svft=@ARGV[1];
$temp=`mktemp -t bit2svf.XXXXXX`;
chomp($temp);
$temp_r=`mktemp -t jbit.XXXXXX`;
chomp($temp_r);

$device="ppdev";
$location="/dev/parport0";
$cable_type="DLC5";

if ($skip)
  {
   $skip=$1*(1<<20) if ($skip=~/(\d+)M/i);
   $skip=$1*(1<<10) if ($skip=~/(\d+)k/i);
   $skip="--skip=$skip";
  }
if ($len)
  {
   $len=$1*(1<<20) if ($len=~/(\d+)M/i);
   $len=$1*(1<<10) if ($len=~/(\d+)k/i);
   $len="--length=$len";
  }

# Leer seteos de ~/.jbitrc
$jbitrc=$ENV{'HOME'}.'/.jbitrc';
if (-e $jbitrc)
  {
   print "Configuration from $jbitrc:\n";
   open(FIL,"<$jbitrc") or die "Error opening $jbitrc";
   while ($a=<FIL>)
     {
      unless ($a=~/^\#/ or $a=~/^\s*$/)
        {
         if ($a=~/^(\S+)\s*=\s*\"?([^\"\n]*)\"?$/)
           {
            $var=uc($1);
            $val=$2;
            if ($val=~/^\$(\d)$/)
              {
               $val=$ARGV[$1-1];
              }
            print "$var -> \"$val\"\n";
            if ($var eq 'JTAG')
              {
               $jtag=$val;
              }
            elsif ($var eq 'BIT2SVF')
              {
               $bit2svf=$val;
              }
            elsif ($var eq 'SVFT')
              {
               $svft=$val;
              }
            elsif ($var eq 'TEMP')
              {
               #$temp=$val;
               print "TEMP is obsolete!!!\n";
              }
            elsif ($var eq 'DEVICE')
              {
               $device=$val;
              }
            elsif ($var eq 'LOCATION')
              {
               $location=$val;
              }
            elsif ($var eq 'CABLE_TYPE')
              {
               $cable_type=$val;
              }
            elsif ($var eq 'PARTNUM')
              {
               $partnum=$val;
               print "PARTNUM is obsolete!!!\n";
              }
            else
              {
               die "Unknown variable $var";
              }
           }
         else
           {
            die "Error parsing $jbitrc:\n$a";
           }
        }
     }
   close(FIL);
   print "\n";
  }
else
  {
   print "No personal configuration '$jbitrc'\n";
  }

# Compuebo la existencia de todo lo necesario
die "Can't find JTAG in $jtag" unless -e $jtag;
die "Can't find bit2svf in $bit2svf" unless -e $bit2svf;
die "Missing file: $bitfile" unless -e $bitfile;

# Creo el .svf
print "Creating temporary file $temp ...\n<--------- $bit2svf $skip $len $bitfile $temp $svft\n";
die "Error creating temporary file $temp"
    if system("$bit2svf $skip $len $bitfile $temp $svft");
print "<--------- end of bit2svf\n\n";

# Buscar que posición tiene en la cadena
print "Analyzing JTAG chain using $jtag ...\n";
open(FIL,"|$jtag > $temp_r") or die;
print FIL "cable $device $location $cable_type\n";
print FIL "detect\n";
print FIL "quit\n";
close FIL;
$ndev=0;
$devs=0;
$partnum=-1;
open(FIL,"<$temp_r") or die;
while ($a=<FIL>)
  {
   if ($a=~/Chain length: (\d+)/)
     {
      $devs=$1;
      print "Devices in the chain: $devs\n";
     }
   elsif ($a=~/Part:\s+(\S+)$/)
     {
      $dev=uc($1);
      print "$ndev: $dev ";
      if ($svft eq $dev)
        {
         print "<--";
         $partnum=$ndev;
        }
      print "\n";
      $ndev++;
     }
  }
close(FIL);
die "Can't find any device in the chain, consult $temp_r"
    unless $devs;
die "Can't find $svft in the chain" unless $partnum!=-1;
print "Device number in the chain: $partnum\n\n";

# Ejecutarlo
print "Transferring $temp using $jtag ...\n<--------- jtag\n";
open(FIL,"|$jtag") or die;
print FIL "cable $device $location $cable_type\n";
print FIL "detect\n";
print FIL "part $partnum\n";
print FIL "svf $temp\n";
print FIL "quit\n";
close FIL;
print "<--------- fin de jtag\n\n";

# Clean-up
print "Cleaning temporary files ... ($temp $temp_r)\n";
`rm -f $temp $temp_r`;
print "Have a nice day :-)\n";


sub help
{
 my $me=basename($0);

 print <<END;
$me is a program to configure Xilinx devices using JTAG.

Usage:
  jbit [OPTIONS] file.bit DEVICE

Options:
  --skip=value          Skip bits the bitstream
  --length=value        Limit the bitstream length
  --help                This text

file.bit is the file containing the bitstream.
DEVICE is the name of the device to configure.

END
 exit 1;
}
