#!/usr/bin/perl

use strict;
use integer;

my $o;
my $infile;
my $outfile;
my $patchfile;
my $length;
while (defined($o = shift @ARGV)) {
    if ($o =~ /^-/) {
	if ($o eq '-o') {
	    $outfile = shift @ARGV;
	} elsif ($o eq '-p') {
	    $patchfile = shift @ARGV;
	} elsif ($o eq '-l') {
	    $length = shift @ARGV;
	} else {
	    last;		# Error
	}
    } else {
	$infile = $o;
	last;
    }
}

if (!defined($infile) || scalar @ARGV) {
    die "Usage: $0 [-o outfile][-p patchfile][-l length] infile\n";
}

sub nextblock($$$) {
    my($block,$len,$limit) = @_;

    my $bytes = $block;

    if (defined($limit) && $limit - $len < $bytes) {
	$bytes = $limit - $len;
    }
    return $bytes;
}

open(my $in, '<', $infile) or die "$0: $infile: $!\n";
binmode $in;
my $data;
my $sum = 0;
my $len = 0;
my $blocklen;
while (($blocklen = nextblock(4096, $len, $length)) &&
       read($in, $data, $blocklen) == $blocklen) {
    foreach my $w (unpack("V*", $data)) {
	$sum = ($sum + $w) & 0xffffffff;
    }
    $len += $blocklen;
}
close($in);

if (defined($outfile)) {
    my $out;
    if ($outfile =~ /^-?$/) {
	open($out, '>&', \*STDOUT);
    } else {
	open($out, '>', $outfile);
    }
    die "$0: $outfile: $!\n" unless defined($out);

    my $outfile_c = uc($outfile) || 'SDRAM_SUM_H';
    $outfile_c =~ s/[\W_]+/_/g;

    print  $out "#ifndef $outfile_c\n";
    print  $out "#define $outfile_c\n";
    printf $out "#define SDRAM_SUM 0x%08x\n", $sum;
    print  $out "#endif\n";

    close($out);
}

if (defined($patchfile)) {
    my $pf;
    open($pf, '+<', $patchfile) or die "$0: $patchfile: $!\n";
    binmode $pf;

    seek($pf, 8, 0) or die "$0: $patchfile: $!\n";
    print $pf pack("V", $sum);
    close($pf);
}