tools/a7out: Add the law instruction and change some numeric literals to

named constants.
This commit is contained in:
Warren Toomey
2016-02-27 15:24:01 +10:00
parent feb4bdbaff
commit ea11773db7
+31 -26
View File
@@ -20,8 +20,8 @@ my $LINK; # Link register
my $MQ; # MQ register my $MQ; # MQ register
# Constants # Constants
my $MAXINT = 0777777; # Biggest unsigned integer use constant MAXINT => 0777777; # Biggest unsigned integer
my $MAXADDR = 017777; # Largest memory address use constant MAXADDR => 017777; # Largest memory address
### Main program ### ### Main program ###
@@ -47,7 +47,7 @@ sub load_code {
my $filename = shift; my $filename = shift;
# Fill all the 8K words in memory with zeroes # Fill all the 8K words in memory with zeroes
foreach my $i ( 0 .. $MAXADDR ) { foreach my $i ( 0 .. MAXADDR ) {
$Mem[$i] = 0; $Mem[$i] = 0;
} }
@@ -77,15 +77,15 @@ sub load_code {
### Copy the arguments into the PDP-7 memory space, and build ### Copy the arguments into the PDP-7 memory space, and build
### an array of pointers to these arguments. Build a pointer ### an array of pointers to these arguments. Build a pointer
### at $MAXADDR that points at the array. ### at MAXADDR that points at the array.
### ###
### Each argument string is four words long and space padded if the ### Each argument string is four words long and space padded if the
### string is not eight characters long. These are stored below ### string is not eight characters long. These are stored below
### address $MAXADDR. Below this is the count of words in the strings. ### address MAXADDR. Below this is the count of words in the strings.
### Address $MAXADDR points at the word count. Graphically (for two arguments): ### Address MAXADDR points at the word count. Graphically (for two arguments):
### ###
### +------------+ ### +------------+
### +--| | Location 017777 ($MAXADDR) ### +--| | Location 017777 (MAXADDR)
### | +------------+ ### | +------------+
### | |............| ### | |............|
### | |............| argv[2] ### | |............| argv[2]
@@ -107,10 +107,10 @@ sub set_arguments {
my $argc= scalar(@ARGV); my $argc= scalar(@ARGV);
# We now know that argc will appear in memory # We now know that argc will appear in memory
# 4*argc +1 below location $MAXADDR # 4*argc +1 below location MAXADDR
# Set argc to the number of words # Set argc to the number of words
my $addr= $MAXADDR - (4*$argc+1); my $addr= MAXADDR - (4*$argc+1);
$Mem[ $MAXADDR ] = $addr; $Mem[ MAXADDR ] = $addr;
$Mem[ $addr++ ] = $argc*4; $Mem[ $addr++ ] = $argc*4;
# Now start saving the arguments # Now start saving the arguments
@@ -149,12 +149,12 @@ sub simulate {
my $instruction = $Mem[$PC]; my $instruction = $Mem[$PC];
my $opcode = ( $instruction >> 12 ) & 074; my $opcode = ( $instruction >> 12 ) & 074;
my $indirect = ( $instruction >> 13 ) & 1; my $indirect = ( $instruction >> 13 ) & 1;
my $addr = $instruction & $MAXADDR; my $addr = $instruction & MAXADDR;
# Work out what any indirect address would be # Work out what any indirect address would be
my $indaddr= ($indirect) ? $Mem[$addr] & $MAXADDR : $addr; my $indaddr= ($indirect) ? $Mem[$addr] & MAXADDR : $addr;
#dprintf( "PC %06o: instr %06o, op %03o, ind %o, addr %06o ind %06o\n", dprintf( "PC %06o: instr %06o, op %03o, ind %o, addr %06o ind %06o\n",
# $PC, $instruction, $opcode, $indirect, $addr, $indaddr ); $PC, $instruction, $opcode, $indirect, $addr, $indaddr );
# Simulate the instruction. Each subroutine updates the $PC # Simulate the instruction. Each subroutine updates the $PC
if ( defined( $Oplist{$opcode} ) ) { if ( defined( $Oplist{$opcode} ) ) {
@@ -169,7 +169,7 @@ sub simulate {
# Debug code: dump memory contents # Debug code: dump memory contents
sub dump_memory { sub dump_memory {
foreach my $i ( 0 .. $MAXADDR ) { foreach my $i ( 0 .. MAXADDR ) {
printf( STDERR "%06o: %06o\n", $i, $Mem[$i] ) if ( $Mem[$i] != 0 ); printf( STDERR "%06o: %06o\n", $i, $Mem[$i] ) if ( $Mem[$i] != 0 );
} }
} }
@@ -197,7 +197,7 @@ sub tad {
my ( $instruction, $addr, $indaddr ) = @_; my ( $instruction, $addr, $indaddr ) = @_;
dprintf( "PC %06o: tad AC (value %06o) from addr %05o\n", dprintf( "PC %06o: tad AC (value %06o) from addr %05o\n",
$PC, $AC, $indaddr ); $PC, $AC, $indaddr );
$AC= ($AC + $Mem[$indaddr]) & $MAXINT; $AC= ($AC + $Mem[$indaddr]) & MAXINT;
$PC++; $PC++;
} }
@@ -229,7 +229,7 @@ sub special {
if ( $instruction == 0741100 ) { # spa: skip on positive AC if ( $instruction == 0741100 ) { # spa: skip on positive AC
dprintf( "PC %06o: spa AC %06o\n", $PC, $AC ); dprintf( "PC %06o: spa AC %06o\n", $PC, $AC );
# Because we are dealing with 18 bits, compare the range # Because we are dealing with 18 bits, compare the range
$PC += ( ($AC >= 0) && ($AC < 0400000) ) ? 2 : 1; $PC += ( ($AC >= 0) && ($AC <= MAXINT) ) ? 2 : 1;
return; return;
} }
if ( $instruction == 0741200 ) { # sna: skip on non-zero AC if ( $instruction == 0741200 ) { # sna: skip on non-zero AC
@@ -242,6 +242,11 @@ sub special {
$PC += ( $AC == 0 ) ? 2 : 1; $PC += ( $AC == 0 ) ? 2 : 1;
return; return;
} }
if ( ($instruction >= 0760000) && ($instruction <= MAXINT) ) { # law: load word into AC
dprintf( "PC %06o: law %06o into AC\n", $PC, $instruction);
$AC = $instruction;
$PC++; return;
}
printf( STDERR "PC %06o: unknown instruction %06o\n", $PC, $instruction ); printf( STDERR "PC %06o: unknown instruction %06o\n", $PC, $instruction );
exit(1); exit(1);
} }
@@ -287,7 +292,7 @@ sub sys_close {
# That filehandle is not open, set an error -1 in octal # That filehandle is not open, set an error -1 in octal
if ( !defined( $FD[$fd] ) ) { if ( !defined( $FD[$fd] ) ) {
dprint( "close: fd $fd is not open\n"); dprint( "close: fd $fd is not open\n");
$AC = 0777777; $AC = MAXINT;
return; return;
} }
close( $FD[$fd] ); close( $FD[$fd] );
@@ -328,7 +333,7 @@ sub sys_open {
} else { } else {
# No filehandle, so it's an error # No filehandle, so it's an error
dprintf( "open failed: $!\n"); dprintf( "open failed: $!\n");
$AC = 0777777; $AC = MAXINT;
return; return;
} }
} }
@@ -344,7 +349,7 @@ sub sys_read {
my $fd = $AC; my $fd = $AC;
my $start = $Mem[ $PC + 1 ]; my $start = $Mem[ $PC + 1 ];
my $count = $Mem[ $PC + 2 ]; my $count = $Mem[ $PC + 2 ];
my $end = ($start + $count - 1) & $MAXADDR; my $end = ($start + $count - 1) & MAXADDR;
die("sys_read: bad start/end addresses $start $end\n") if ($end < $start); die("sys_read: bad start/end addresses $start $end\n") if ($end < $start);
dprintf( "PC %06o: read: %d words into %o from fd %d\n", dprintf( "PC %06o: read: %d words into %o from fd %d\n",
$PC, $count, $start, $fd ); $PC, $count, $start, $fd );
@@ -355,7 +360,7 @@ sub sys_read {
# That filehandle is not open, set an error -1 in octal # That filehandle is not open, set an error -1 in octal
if ( !defined( $FD[$fd] ) ) { if ( !defined( $FD[$fd] ) ) {
dprint( "read: fd $fd is not open\n"); dprint( "read: fd $fd is not open\n");
$AC = 0777777; $AC = MAXINT;
return; return;
} }
@@ -377,7 +382,7 @@ sub sys_read {
my $line = <$FH>; my $line = <$FH>;
last if ( !defined($line) ); # No line, leave the loop last if ( !defined($line) ); # No line, leave the loop
chomp($line); chomp($line);
$Mem[$addr] = oct($line) & 0777777; $Mem[$addr] = oct($line) & MAXINT;
$count++; $count++;
} }
} }
@@ -397,7 +402,7 @@ sub sys_write {
my $fd = $AC; my $fd = $AC;
my $start = $Mem[ $PC + 1 ]; my $start = $Mem[ $PC + 1 ];
my $count = $Mem[ $PC + 2 ]; my $count = $Mem[ $PC + 2 ];
my $end = ($start + $count - 1) & $MAXADDR; my $end = ($start + $count - 1) & MAXADDR;
die("sys_write: bad start/end addresses $start $end\n") if ($end < $start); die("sys_write: bad start/end addresses $start $end\n") if ($end < $start);
dprintf( "PC %06o: write: %d words from %o to fd %d\n", dprintf( "PC %06o: write: %d words from %o to fd %d\n",
$PC, $count, $start, $fd ); $PC, $count, $start, $fd );
@@ -408,7 +413,7 @@ sub sys_write {
# That filehandle is not open, set an error -1 in octal # That filehandle is not open, set an error -1 in octal
if ( !defined( $FD[$fd] ) ) { if ( !defined( $FD[$fd] ) ) {
dprint( "write: fd $fd is not open\n"); dprint( "write: fd $fd is not open\n");
$AC = 0777777; $AC = MAXINT;
return; return;
} }
@@ -451,7 +456,7 @@ sub mem2arg {
foreach (1 .. 4) { foreach (1 .. 4) {
# Stop if the address leave the 8K word address space # Stop if the address leave the 8K word address space
last if ( $addr > $MAXADDR ); last if ( $addr > MAXADDR );
my $word = $Mem[$addr++]; my $word = $Mem[$addr++];
my $c1 = ( $word >> 9 ) & 0177; my $c1 = ( $word >> 9 ) & 0177;
my $c2 = $word & 0177; my $c2 = $word & 0177;
@@ -472,7 +477,7 @@ sub mem2string {
while (1) { while (1) {
# Stop when the address leave the 8K word address space # Stop when the address leave the 8K word address space
return ($result) if ( $addr > $MAXADDR ); return ($result) if ( $addr > MAXADDR );
# Stop when the value there is zero # Stop when the value there is zero
my $word = $Mem[$addr]; my $word = $Mem[$addr];