#!/usr/bin/perl
# Interpreter (c) 2006, Ward Cunningham, released under GPL v2 or higher
# Architecture & sample code by Harry Porter

my (@r, $pc, $j, @mem, @src);
my ($z, $cy, $s);
my ($a, $b, $c, $d, $m1, $m2, $x, $y) = 0..7;
my $run = 1;
my $alu;

sub i8	{
	return 	substr($_[0],0,1)*128 + 
		substr($_[0],1,1)*64 + 
		substr($_[0],2,1)*32 + 
		substr($_[0],3,1)*16 + 
		substr($_[0],4,1)*8 + 
		substr($_[0],5,1)*4 + 
		substr($_[0],6,1)*2 + 
		substr($_[0],7,1)
}

sub i5	{
	return 	substr($_[0],0,1)*(16+32+64+128) + 
		substr($_[0],1,1)*8 + 
		substr($_[0],2,1)*4 + 
		substr($_[0],3,1)*2 + 
		substr($_[0],4,1);
}

sub r3	{return substr($_[0],0,1)*4 + substr($_[0],1,1)*2 + substr($_[0],2,1);}
sub r2	{return substr($_[0],1,1)*2 + substr($_[0],2,1);}
sub pc2 {return $mem[$pc++]*256 + $mem[$pc++];}
sub b2 	{return (($_[0]>>8)%256, $_[0]%256);}
sub xy	{return $r[6]*256 + $r[7];}

sub alu {
	$z = $_[0]%256==0; 
	$cy = $_[0]>=256; 
	$s = $_[0]%256>=128; 
	$alu=sprintf("%08b",$_[0]%256); 
	return $_[0]%256
}

for (<DATA>) {
	chomp;
	s/¬/~/g;
	next unless /(\s*[01]){16}/;
	my ($a, $b, $c, $d) = /([01]{4})/g;
	$mem[i8("$a$b")] = i8("$c$d");
	$src[i8("$a$b")] = pack("A60",$_);
}

@r[$x, $y] = (221, 179);

fetch:
	print $src[$pc];
	$_ = sprintf ('%08b', $mem[$pc++]);

execute:
	goto clear_ 	if /00(...)\1/;
	goto move_ 	if /00(...)(...)/;
	goto set_8_	if /01(.)(.....)/;
	goto add_	if /1000(.)000/;
	goto inc_	if /1000(.)001/;
	goto and_	if /1000(.)010/;
	goto or_	if /1000(.)011/;
	goto xor_	if /1000(.)100/;
	goto not_	if /1000(.)101/;
	goto shift_	if /1000(.)110/;
	goto load_	if /10010.(..)/;
	goto store_	if /10011.(..)/;
	goto incxy_	if /10110000/;
	goto ret_	if /10100010/;
	goto halt_	if /10101110/;
	goto goto_	if /11100110/;
	goto call_	if /11100111/;
	goto branch_	if /111....0/;
	goto set_16_	if /11....../;
	die "bad op: $_\n";

clear_:	$r[r3($1)] = 0;				goto trace;
move_:	$r[r3($1)] = $r[r3($2)];		goto trace;
set_8_:	$r[$1?$b:$a] = i5($2);			goto trace;
add_:	$r[$1?$d:$a] = alu($r[$b] + $r[$c]);	goto trace;
inc_:	$r[$1?$d:$a] = alu($r[$b] + 1); 	goto trace;
and_:	$r[$1?$d:$a] = alu($r[$b] & $r[$c]); 	goto trace;
or_:	$r[$1?$d:$a] = alu($r[$b] | $r[$c]); 	goto trace;
xor_:	$r[$1?$d:$a] = alu($r[$b] ^ $r[$c]); 	goto trace;
not_:	$r[$1?$d:$a] = alu(~($r[$b])); 		goto trace;
shift_:	$r[$1?$d:$a] = alu($r[$b] << 1); 	goto trace;
load_:	$r[r2($1)] = $mem[pc2()];		goto trace;
store_:	$mem[pc2()] = $r[r2($1)];		goto trace;
incxy_:	@r[$x..$y] = b2(xy()+1);		goto trace;
ret_:	$pc = xy();				goto trace;
halt_:	$pc = 0; $run=0;			goto trace;

goto_:;
call_:;
branch_:;
set_16_:
	@r[$m1..$m2] = b2(pc2())	if /110...../;
	$j = pc2()			if /111...../;
	@r[$x..$y] = b2($pc)		if /11.....1/;
	$pc = $j			if /11.1..../ and $s;
	$pc = $j			if /11..1.../ and !$cy;
	$pc = $j			if /11...1../ and $z;
	$pc = $j			if /11....1./ and !$z;
	goto trace;
		
trace:
	#print map(sprintf('[%08b]',$_),@r);
	print "$alu\n";
	$alu = "";
	goto fetch if $run;
	

__DATA__
0000 0000   0010 1110   M2=X      M2 = X 
0000 0001   0101 1001   A=-7      D = -7 
0000 0010   0001 1000   D=A       . 
0000 0011   0110 0000   B=0       if sign(y)==0 
0000 0100   0001 0111   C=Y       . 
0000 0101   1000 0011   A=B|C     . 
0000 0110   1111 0000   BNEG Loop . 
0000 0111   0000 0000   .         . 
0000 1000   0000 1010   .         . 
0000 1001   0010 1001   M2=B        M2 = 0 
0000 1010   0000 1100 Loop: B=M1  LOOP: 
0000 1011   1000 0110   A=B<<1      Shift M1 left 
0000 1100   0001 0000   C=A         . (noncircular) 
0000 1101   0111 1110   B=1111,1110 . 
0000 1110   1000 0010   A=B&C       . 
0000 1111   0010 0000   M1=A        . 
0001 0000   0000 1101   B=M2        if sign(M2)==1 
0001 0001   1000 0101   A=¬B        . 
0001 0010   1111 0000   BNEG Lab1   . 
0001 0011   0000 0000   .           . 
0001 0100   0001 1000   .           . 
0001 0101   0000 1100   B=M1          M1 = M1 + 1 
0001 0110   1000 0001   A=B+1         . 
0001 0111   0010 0000   M1=A          . 
0001 1000   0000 1101 Lab1: B=M2    Shift M2 left
0001 1001   1000 0110   A=B<<1      . (noncircular) 
0001 1010   0001 0000   C=A         . 
0001 1011   0111 1110   B=1111,1110 . 
0001 1100   1000 0010   A=B&C       . 
0001 1101   0010 1000   M2=A        . 
0001 1110   0000 1111   B=Y         shift Y left 
0001 1111   1000 0110   A=B<<1      . 
0010 0000   0011 1000   Y=A         . 
0010 0001   0000 1111   B=Y         if sign(Y)=1 
0010 0010   1000 0101   A=¬B        . 
0010 0011   1111 0000   BNEG Lab2   . 
0010 0100   0000 0000   .           . 
0010 0101   0011 0000   .           . 
0010 0110   0000 1101   B=M2          M2 = M2 + X 
0010 0111   0001 0110   C=X           . 
0010 1000   1000 0000   A=B+C         . 
0010 1001   0010 1000   M2=A          . 
0010 1010   1110 1000   BNC Lab2      if carry 
0010 1011   0000 0000   .             . 
0010 1100   0011 0000   .             . 
0010 1101   0000 1100   B=M1            M1 = M1 + 1 
0010 1110   1000 0001   A=B+1           . 
0010 1111   0010 0000   M1=A            . 
0011 0000   0000 1011 Lab2: B=D     D = D + 1 
0011 0001   1000 1001   D=B+1       . 
0011 0010   1110 0010   BNZ Loop    if D != 0 
0011 0011   0000 0000   .           .  goto Loop 
0011 0100   0000 1010   .           . 
0011 0101   1010 1110   HALT        Halt