#!/usr/bin/perl

use strict;
use integer;

our %consts;

require '../iodevs.conf';

my $ramaddr    = $consts{'SDRAM_ADDR'};
my $flashcmd   = 0xabc80046;
my $flashpfx   = 0xabc80fed;
my $maxdatalen = 16 << 20;

my($svfload, $rptfile, $binfile, $svffile) = @ARGV;

open(my $in, '<', $rptfile)
    or die "$0: $rptfile: $!\n";

my @vjif;

while (defined(my $l = <$in>)) {
    my @lf = split(/\s*\;\s*/, $l);

    if ($lf[8] =~ /\|vjtag\:vjtag\|/) {
	@vjif = @lf;
    }
}
close($in);

# [0] - blank
# [1] - instance index
# [2] - auto index
# [3] - index changed
# [4] - IR width
# [5] - VIR base address
# [6] - USER1 DR length
# [7] - VIR capture command
# [8] - hierarchial entity name

my $virbits  = $vjif[6];
my $virbase  = hex $vjif[5];
my $vircap   = hex $vjif[7];

open(my $bin, '<', $binfile)
    or die "$0: $binfile: $!\n";
binmode($bin);
my $bindata;
my $binlen = read($bin, $bindata, $maxdatalen);
close($bin);

open(my $svf, '>', $svffile)
        or die "$0: $svffile: $!\n";

# SVF file for the transient load image
open(my $in, '<', $svfload)
    or die "$0: $svfload: $!\n";
while (defined(my $l = <$in>)) {
    print $svf $l;
}
close($in);

sub print_bitstring($$$) {
    my($svf, $len, $data) = @_;

    my $lenbytes = ($len+7) >> 3;

    if (length($data) < $lenbytes) {
	$data = ("\0" x ($len - $lenbytes)) . $data;
    }

    my $b = -1 - (length($data)-$lenbytes);
    my $bytes = 0;
    while ($len > 7) {
	printf $svf "%02X", unpack("C", substr($data, $b--, 1));
	if (!(++$bytes & 63)) {
	    print $svf "\n\t";
	}
	$len -= 8;
    }

    if ($len) {
	my $lb = unpack("C", substr($data, $b--, 1));
	$lb &= (1 << $len)-1;
	printf $svf "%0".(($len+3)>>2)."X", $lb;
    }
}

sub virt_sir($$) {
    my($svf, $cmd) = @_;

    print $svf "SIR 10 TDI (00E);\n";
    printf $svf "SDR %d TDI (", $virbits;
    print_bitstring($svf, $virbits, pack("V", $virbase | $cmd));
    print $svf ");\n";
    print $svf "SIR 10 TDI (00C);\n";
}

# Set address command
my $ramaddr = 0x40000000;

virt_sir($svf, 0x12);
printf $svf "SDR 32 TDI (%08X);\n", $ramaddr;

# Write data to SDRAM
virt_sir($svf, 0x16);
# Prepend ABC80FED synchronization word
$bindata = pack("V", $flashpfx) . $bindata;
# Pad to a full 32-bit word (the JTAG command writes full 32-bit words only)
$bindata .= "\0" x ((4 - (length($bindata) & 3)) & 3);
my $binbits = length($bindata) << 3;
printf $svf "SDR %d\n   TDI (", $binbits;
print_bitstring($svf, $binbits, $bindata);
print $svf ");\n";

# Trigger flash command to firmware
virt_sir($svf, 0x1a);
printf $svf "SDR 32 TDI (%08X);\n", $flashcmd;

# Idle JTAG
print $svf "SIR 10 TDI (3FF);\n";
print $svf "STATE IDLE;\n";