#!/usr/bin/perl

$PDDAT = 0x10010310;
$PDDATS = 0x10010314;
$PDDATC = 0x10010318;
$PDFUNC = 0x10010348;
$PDDIR = 0x10010360;
$PDDIRS = 0x10010364;
$PDDIRC = 0x10010368;

$bit{"DAT2"} = 12;
$bit{"DAT3"} = 13;
$bit{"CMD"} = 8;
$bit{"VDD"} = 2;
$bit{"CLK"} = 9;
$bit{"DAT0"} = 10;
$bit{"DAT1"} = 11;


sub poke
{
	local ($a, $v) = @_;

	return unless $v;
	$c = sprintf("ssh jlime poke 0x%0x 0x%0x", $a, $v & $mask);
#print STDERR "$c\n";
	system($c);
}


sub peek
{
	local ($a) = @_;

	$c = sprintf("ssh jlime poke 0x%x", $a);
#print STDERR "$c\n";
	return hex(`$c`);
}


$mask = 0;
for (values %bit) {
	$mask |= 1 << $_;
}
&poke($PDFUNC, $mask);

$dat = 1 << $bit{"VDD"};
$dir = $dat;
&poke($PDDATS, $dat);
&poke($PDDATC, $mask ^ $dat);
&poke($PDDIRS, $dir);
&poke($PDDIRC, $mask ^ $dir);

while (<>) {
	print STDERR;
	chop;
	s/#.*//;
	next if /^\s*$/;
	if (/^\S+,(\S+,)*\S+/) {
		@pos = ();
		for (split /,/) {
			die "unknown bit \"$_\"" unless defined $bit{$_};
			push(@pos, $_);
		}
	} elsif (/^(\S+)=(\S+)\s*/) {
		die "unknown bit \"$2\"" unless defined $bit{$2};
		die "bit \"$1\" is already defined" if defined $bit{$1};
		$bit{$1} = $bit{$2};
	} elsif (/^echo\s+/) {
		print "$'\n";
	} elsif (/^show\s*$/) {
		$tdir = &peek($PDDIR);
		$tdat = &peek($PDDAT);
		for (@pos) {
			$v = 1 << $bit{$_};
			print "$_($bit{$_})=",
			    $tdir & $v ? $tdat & $v ? "1" : "0" : "Z", " ";
		}
		print "\n";
	} elsif (/^wait\s+([01-]+)\s*$/) {
		$m = 0;
		$c = 0;
		@p = @pos;
		$s = $1;
		while (length $s) {
			die "out of bits" unless @p;
			$v = 1 << $bit[shift @p];
			if ($s =~ /^0/) {
				$m |= $v;
			} elsif ($s =~ /^1/) {
				$m |= $v;
				$c |= $v;
			}
			$s = substr($s, 1);
		}
# @@@ to do
	} elsif (/^sleep\s+(\d+|\d*\.\d*)\s*$/) {
		select(undef, undef, undef, $1);
	} elsif (/^([-01zZ]+)\s*$/) {
		@p = @pos;
		($tdir, $tdat) = ($dir, $dat);
		$s = $1;
		while (length $s) {
			die "out of bits" unless @p;
			$v = 1 << $bit{shift @p};
			if ($s =~ /^0/) {
				$tdir |= $v;
				$tdat &= ~$v;
			} elsif ($s =~ /^1/) {
				$tdir |= $v;
				$tdat |= $v;
			} elsif ($s =~ /^[zZ]/) {
				$tdir &= ~$v;
			}
			$s = substr($s, 1);
		}
		&poke($PDDATS, $tdat & ~$dat);
		&poke($PDDATC, ~$tdat & $dat);
		&poke($PDDIRS, $tdir & ~$dir);
		&poke($PDDIRC, ~$tdir & $dir);
		($dir, $dat) = ($tdir, $tdat);
	} else {
		die "unrecognized command \"$_\"";
	}
}
