#!/usr/bin/perl # Interpreter (c) 2006, Ward Cunningham, released under GPL v2 or higher # Architecture & sample code by Harry Porter print "Content-Type: text/html\n\n"; my (@r, $pc, $j, @mem, @src); my ($z, $cy, $s); my ($a, $b, $c, $d, $m1, $m2, $x, $y) = 0..7; my @reg = ('a', 'b', 'c', 'd', 'm1', 'm2', 'x', 'y'); my $run = 1; my $cycles; my $alu; read (STDIN, $_, $ENV{CONTENT_LENGTH}); my ($arg, %arg); for (split(/&/, $_)) { s/\+/ /g; s/\%(..)/pack('C', hex($1))/geo; ($_, $arg) = split (/=/, $_, 2); $arg{$_} = $arg; } print <<"";

Harry Porter's Relay Computer

for (0..7) { my $reg = $reg[$_]; my $val = $arg{$reg}; $val =~ s/[^01]//g; $r[$_] = $val = i8($val)%256; $val = sprintf ('%04b %04b', $val/16, $val%16); print <<""; $reg
} $arg{mem} = join('', ) unless $arg{mem}; $_ = $arg{mem}; s/&/&/g; s//>/g; print <<"";

Simulator Ouput


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("%04b %04b",$_[0]/16%16,$_[0]%16); 
	$alu = "$alu";
	return $_[0]%256
}

for (split(/\n/, $arg{mem})) {
	s/\r|\n//g;
	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 and $cycles++ < 10000;
	

__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