#!/usr/bin/perl -w
# $Id: ti_w11 1103 2019-01-04 13:18:54Z mueller $
#
# Copyright 2013-2019 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
# License disclaimer see License.txt in $RETROBASE directory
#
#  Revision History:
# Date         Rev Version  Comment
# 2019-01-04  1103   1.4.3  add -ar,-n4d (ddr versions)
# 2017-06-25   916   1.4.2  add -c7 (cmoda7 support)
# 2017-01-08   843   1.4.1  allow -tuD,.... for Digilent autodetect; add -bn4d
# 2016-12-31   834   1.4    use rw11::shell by default; add -ns to suppress it
# 2016-06-18   776   1.3.5  use ti_rri --tout now
# 2016-03-20   748   1.3.4  BUGFIX: add portsel oob for -fx;
#                           use 120 sec timeout for simulation; add -ll,-dl,-tl
# 2016-03-18   745   1.3.3  add arty support, add -fx
# 2015-11-01   712   1.3.2  use sb_cntl pin 12 for tmu; add -ghw option
# 2015-05-14   680   1.3.1  use now -f1,-f1e,-f2,-f2e (fx now f1e)
# 2015-04-13   667   1.3    rename -fu->-fc, add -f2,-fx; setup good defaults
# 2015-01-02   640   1.2.2  BUGFIX: allow 'M' unit in baud rates
# 2014-12-23   619   1.2.1  use -fifo tbw option for test bench starts
# 2014-07-13   570   1.2    BUGFIX: split options args into ti_rri opts and cmds
# 2013-05-05   516   1.1    renamed to ti_w11
# 2013-04-26   510   1.0    Initial version (derived from dorri)
#

use 5.14.0;                                 # require Perl 5.14 or higher
use strict;                                 # require strict checking
use FileHandle;

autoflush STDOUT 1;             # autoflush, so nothing lost on exec later

my $sysbase = "$ENV{RETROBASE}/rtl/sys_gen/w11a";

my $opt_dry;
my $opt_b;
my $opt_ns;
my $opt_io = '';
my $opt_f  = '';
my $opt_ll = '2';
my $opt_dl = '';
my $opt_tl = '';
my $opt_to = '';
my $opt_tmu;
my $opt_ghw;
my $tirri;
my $val_term;
my $val_tb_s3   = "tbw $sysbase/s3board/tb/tb_w11a_s3 -fifo";
my $val_tb_n2   = "tbw $sysbase/nexys2/tb/tb_w11a_n2 -fifo";
my $val_tb_n3   = "tbw $sysbase/nexys3/tb/tb_w11a_n3 -fifo";
my $val_tb_b3   = "tbw $sysbase/basys3/tb/tb_w11a_b3 -fifo";
my $val_tb_n4   = "tbw $sysbase/nexys4/tb/tb_w11a_n4 -fifo";
my $val_tb_bn4  = "tbw $sysbase/nexys4_bram/tb/tb_w11a_br_n4 -fifo";
my $val_tb_bn4d = "tbw $sysbase/nexys4d_bram/tb/tb_w11a_br_n4d -fifo";
my $val_tb_n4d  = "tbw $sysbase/nexys4d/tb/tb_w11a_n4d -fifo";
my $val_tb_bar  = "tbw $sysbase/arty_bram/tb/tb_w11a_br_arty -fifo";
my $val_tb_ar   = "tbw $sysbase/arty/tb/tb_w11a_arty -fifo";
my $val_tb_c7   = "tbw $sysbase/cmoda7/tb/tb_w11a_c7 -fifo";
my $val_tb;
my $val_e;

my @arglist;

#
# process ti_w11 options
#
while (scalar(@ARGV)) {
  my $curarg = $ARGV[0];

  if ($curarg =~ m{^-dry$} ) {		    # -dry
    $opt_dry = 1;
    shift @ARGV;

  } elsif ($curarg =~ m{^-b$} ) {	    # -b
    $opt_b = 1;
    shift @ARGV;

  } elsif ($curarg =~ m{^-ns$} ) {	    # -ns
    $opt_ns = 1;
    shift @ARGV;

  } elsif ($curarg =~ m{^-tmu$} ) {	    # -tmu
    $opt_tmu = 1;
    shift @ARGV;

  } elsif ($curarg =~ m{^-ghw$} ) {	    # -ghw
    $opt_ghw = 1;
    shift @ARGV;

  } elsif ($curarg =~ m{^-s3$} ) {	    # -s3 (use -f2 by default)
    $opt_io = 'f';
    $opt_f  = '2';
    $val_tb = $val_tb_s3;
    shift @ARGV;

  } elsif ($curarg =~ m{^-n2$} ) {	    # -n2 (use -fc by default)
    $opt_io = 'f';
    $opt_f  = 'c';
    $val_tb = $val_tb_n2;
    shift @ARGV;

  } elsif ($curarg =~ m{^-n3$} ) {	    # -n3 (use -fc by default)
    $opt_io = 'f';
    $opt_f  = 'c';
    $val_tb = $val_tb_n3;
    shift @ARGV;

  } elsif ($curarg =~ m{^-b3$} ) {	    # -b3 (use -fx by default)
    $opt_io = 'f';
    $opt_f  = 'x';
    $val_tb = $val_tb_b3;
    shift @ARGV;

  } elsif ($curarg =~ m{^-n4$} ) {	    # -n4 (prim serport fine)
    $opt_io = 'f';
    $opt_f  = '1';
    $val_tb = $val_tb_n4;
    shift @ARGV;

  } elsif ($curarg =~ m{^-bn4$} ) {	    # -bn4 (prim serport fine)
    $opt_io = 'f';
    $opt_f  = '1';
    $val_tb = $val_tb_bn4;
    shift @ARGV;

  } elsif ($curarg =~ m{^-bn4d$} ) {	    # -bn4d (prim serport fine)
    $opt_io = 'f';
    $opt_f  = '1';
    $val_tb = $val_tb_bn4d;
    shift @ARGV;

  } elsif ($curarg =~ m{^-n4d$} ) {	    # -n4d (prim serport fine)
    $opt_io = 'f';
    $opt_f  = '1';
    $val_tb = $val_tb_n4d;
    shift @ARGV;

  } elsif ($curarg =~ m{^-bar$} ) {	    # -bar (use -fx by default)
    $opt_io = 'f';
    $opt_f  = 'x';
    $val_tb = $val_tb_bar;
    shift @ARGV;

  } elsif ($curarg =~ m{^-ar$} ) {	    # -ar (use -fx by default)
    $opt_io = 'f';
    $opt_f  = 'x';
    $val_tb = $val_tb_ar;
    shift @ARGV;

  } elsif ($curarg =~ m{^-c7$} ) {	    # -c7 (use -fx by default)
    $opt_io = 'f';
    $opt_f  = 'x';
    $val_tb = $val_tb_c7;
    shift @ARGV;

  } elsif ($curarg =~ m{^-f(c|x|1|1x|2|2x)$} ) { # -f..
    $opt_f = $1;
    shift @ARGV;

  } elsif ($curarg =~ m{^-t([su])(\d+|D),?} ) {	# -t[su]...
    my $devnam = ($1 eq 's') ? '/dev/ttyS' : '/dev/ttyUSB';
    my $devnum = $2;
    my ($dev,$baud,$opt1,$opt2) = split /,/,$curarg;
    $baud  = '115k' unless defined $baud;

    if ($baud !~ m{^\d*[kM]?$}) {
      print STDERR "ti_w11-E: invalid format of -ts or -tu option\n";
      exit 1;
    }

    $opt_io = 't';
    $val_term = sprintf '%s%s,%s', $devnam, $devnum, $baud;
    $val_term .= ",$opt1" if defined $opt1;
    $val_term .= ",$opt2" if defined $opt2;
    shift @ARGV;

  } elsif ($curarg =~ m{^-u$} )  {          # -u
    $opt_io = 'u';
    shift @ARGV;

  } elsif ($curarg =~ m{^-e$} ) {	    # -e <file>
    print STDERR "ti_w11-W: multiple -e options, only last taken\n"
      if defined $val_e;
    shift @ARGV;
    if (scalar(@ARGV) == 0 || $ARGV[0] =~ m{^-}) {
      print STDERR "ti_w11-E: no file name after -e option\n";
      exit 1;
    } else {
      $val_e = shift @ARGV;
      if (not -r $val_e) {
	print STDERR "ti_w11-E: file '$val_e' not found\n";
	exit 1;
      }
    }
  } elsif ($curarg =~ m{^-ll(\d)$} ) {	    # -ll<n>  (setup --logl)
    $opt_ll = $1;
    shift @ARGV;
  } elsif ($curarg =~ m{^-dl(\d)$} ) {	    # -dl<n>  (setup --dmpl)
    $opt_dl = $1;
    shift @ARGV;
  } elsif ($curarg =~ m{^-tl(\d)$} ) {	    # -tl<n>  (setup --tiol)
    $opt_tl = $1;
    shift @ARGV;
  } else {
    last;
  }
}

#
# process remaining arguments, separate ti_rri options and commands
#

# handle options (all starting with -)
my @tiopts;
while (scalar(@ARGV)) {
  last unless $ARGV[0] =~ m{^--};
  push @tiopts, shift @ARGV;
}

# handle comands
my @ticmds;
while (scalar(@ARGV)) {
  my $curarg = shift @ARGV;
  if ($curarg =~ m{^@(.*)$} && ! -r $1) {
    print STDERR "ti_w11-E: file '$1' not found\n";
    exit 1;
  }
  push @ticmds,$curarg;
}

#
# check that either -(s3|n2|n3|n4|bn4) or -t or -u given
# setup options for either case
#

if ($opt_io eq 'f') {
  my $fifoopts = ",noinit";                 # fifo always with deferred init
  $fifoopts .= ",xon" if $opt_f =~ m/x$/;
  push @arglist, "--fifo=$fifoopts";
  my $run_opts = "";
  if ($opt_ghw) {
    my $ghw_stem = "ti_w11";
    $ghw_stem = $1 if ($val_tb =~ m|^.*\s+.*/(\w*)\s+|); # get stem of tb file
    $run_opts .= " --wave=${ghw_stem}.ghw";
  }
  push @arglist, "--run=${val_tb}${run_opts}";
} elsif ($opt_io eq 't') {
  push @arglist, "--term=$val_term";
} elsif ($opt_io eq 'u') {
  push @arglist, '--cuff';
} else {
  print STDERR "ti_w11-E: neither -(s3|n2|...) nor -t,-u specified\n";
  print_usage();
  exit 1;
}

# setup timeout
if ($opt_io eq 'f') {
  $opt_to = '120.';                   # 120 sec timeout for simulation
}

#
# setup all other ti_rri options
#

push @arglist, "--logl=${opt_ll}";
push @arglist, "--dmpl=${opt_dl}" if $opt_dl ne '';
push @arglist, "--tiol=${opt_tl}" if $opt_tl ne '';
push @arglist, "--tout=${opt_to}" if $opt_to ne '';
push @arglist, '--int' unless $opt_b;
push @arglist, '--pack=rw11';
push @arglist, @tiopts;                     # add options from ARGV
push @arglist, '--';

#
# actions prior to first exec
#   setup tmu ect
#   setup access path --> handle -f options
#
if ($opt_io eq 'f') {
  if ($opt_tmu) {
    push @arglist, 'rlc oob -sbcntl 12   1';
  }
  if ($opt_f eq 'c') {
    push @arglist, 'rlc oob -sbdata  8 0x4'; # portsel = 0100 -> fx2
    push @arglist, 'rlc oob -sbdata 16 0x4'; # swi     = 0100 -> fx2
  } elsif ($opt_f eq 'x') {
    push @arglist, 'rlc oob -sbdata  8 0x2'; # portsel = 0010 -> 1st ser XON
  } elsif ($opt_f eq '1x') {
    push @arglist, 'rlc oob -sbdata  8 0x2'; # portsel = 0010 -> 1st ser XON
    push @arglist, 'rlc oob -sbdata 16 0x2'; # swi     = 0010 -> 1st ser XON
  } elsif ($opt_f eq '2') {
    push @arglist, 'rlc oob -sbdata  8 0x1'; # portsel = 0001 -> 2nd ser
    push @arglist, 'rlc oob -sbdata 16 0x1'; # swi     = 0001 -> 2nd ser
  } elsif ($opt_f eq '2x') {
    push @arglist, 'rlc oob -sbdata  8 0x3'; # portsel = 0011 -> 2nd ser XON
    push @arglist, 'rlc oob -sbdata 16 0x3'; # swi     = 0011 -> 2nd ser XON
  }
}

#
# --fifo always uses deferred init, so add a rlc init after the oob's
#
push @arglist, 'rlc init' if $opt_io eq 'f';

#
# initialize w11 cpu system
#
push @arglist, 'rw11::setup_sys';

#
# start w11 shell
#
unless ($opt_ns) {
  push @arglist, 'rw11::shell_start';
}

#
# handle -e option
#

if (defined $val_e) {
  if ($val_e =~ m/\.mac$/) {
    push @arglist, "cpu0 ldasm -file $val_e -sym ldasm_sym -lst ldasm_lst";
  } else {
    push @arglist, "cpu0 ldabs $val_e";
  }
  push @arglist, 'cpu0 cp -stapc 0200';
}

push @arglist, @ticmds;                     # add commands from ARGV

#
# find ti_rri executable
#

$tirri=`which ti_rri`;
chomp $tirri;
if ($tirri eq '' || ! -e $tirri) {
  print STDERR "ti_w11-E: failed to locate ti_rri\n";
  exit 1;
}

#
# print command line
#
if (1) {
  print 'ti_rri ', join (' ', map {(m{\s}) ? "\"$_\"" : $_} @arglist) , "\n";
}

#
# if dry run, stop here
#
exit 0 if $opt_dry;
#
# and do it
#
exec $tirri, @arglist
  or die "failed to exec: $!";

exit 1;

# ----------------------------------------------------------------------------
sub print_usage {
  print "usage: ti_w11 <setup options> <ti_rri opts and cmds>...\n";
  print "  setup options for ghdl simulation runs:\n";
  print "    -c7       start tb_w11a_c7 simulation (default: -fx)\n";
  print "    -b3       start tb_w11a_b3 simulation (default: -fx)\n";
  print "    -n4       start tb_w11a_n4 simulation\n";
  print "    -bn4      start tb_w11a_br_n4 simulation\n";
  print "    -bar      start tb_w11a_br_arty simulation (default: -fx)\n";
  print "    -n3       start tb_w11a_n3 simulation (default: -fc)\n";
  print "    -n2       start tb_w11a_n2 simulation (default: -fc)\n";
  print "    -s3       start tb_w11a_s3 simulation (default: -f2)\n";
  print "    -f..      simulation communication options\n";
  print "      -fc       use fx2 data path (cuff)\n";
  print "      -fx       use 1st serport with hardwired xon\n";
  print "      -f1       use 1st serport\n";
  print "      -f1x      use 1st serport with switched xon\n";
  print "      -f2       use 2nd serport (fusp)\n";
  print "      -f2x      use 2nd serport with switched xon\n";
  print "    -tmu      activate trace and monitoring unit\n";
  print "    -ghw      activate ghdl wave dump with --wave=<stem>.ghw\n";
  print "  setup options for FPGA connects:\n";
  print "    -u        use --cuff connect\n";
  print "    -t..      use --term connect\n";
  print "      -ts*[,opts]   use /dev/ttyS*   (* = device number)\n";
  print "      -tu*[,opts]   use /dev/ttyUSB* (* = device number or 'D')\n";
  print "                    opts can be ',break', ',xon'\n";
  print "  common options:\n";
  print "    -ll<n>    set rlink logging level to <n> (using --logl=<n>)\n";
  print "    -dl<n>    set rlink dump level to <n> (using --dmpl=<n>)\n";
  print "    -tl<n>    set rlink trace level to <n> (using --tiol=<n>)\n";
  print "    -b        batch mode\n";
  print "    -ns       don't start w11 shell\n";
  print "    -e <file> load and execute file\n";
  print "                file type '.mac': on the fly compile with asm-11\n";
  print "                any other file type: assume lda format\n";
  print "\n";
  print "  either one of -s3,-n2,-n3,-b3,-n4,-bn4  must be given -> sim run\n";
  print "  or one of -t or -u must be given            -> fpga run\n";
}
