I've added tad and sza to the a7out simulator, and I also added some

code to place command-line arguments into the simulated memory. I'm
trying to write my own version of cat so I can compare mine to the
real one. Right now there's a bug when simplecat has two arguments.
Zero and one arguments are OK! Saving so I have a backup before proceeding.
This commit is contained in:
Warren Toomey
2016-02-26 20:56:31 +10:00
parent b8550475b0
commit 8f8cc64d10
2 changed files with 178 additions and 10 deletions
+103 -8
View File
@@ -27,11 +27,12 @@ if ( ( @ARGV > 0 ) && ( $ARGV[0] eq "-d" ) ) {
} }
# Check the arguments # Check the arguments
die("Usage: $0 [-d] a.outfile\n") if ( @ARGV != 1 ); die("Usage: $0 [-d] a.outfile [arg1 arg2 ...]\n") if ( @ARGV < 1 );
# Load the a.out file into memory # Load the a.out file into memory
# and simulate it # and simulate it
load_code( $ARGV[0] ); load_code( shift(@ARGV) );
set_arguments(@ARGV);
simulate(); simulate();
exit(0); exit(0);
@@ -67,6 +68,62 @@ sub load_code {
close($IN); close($IN);
} }
### Copy the arguments into the PDP-7 memory space, and build
### an array of pointers to these arguments. Build a pointer
### at 017777 that points at the array.
###
### At the moment, this is NOT what PDP-7 Unix uses, but it's
### a start and it will help us to grok the real thing.
###
### For now, assume abc, def and ghi are stored in memory.
### The layout of the pointers and strings would be:
###
### +-------+
### | |
### | +-----|---------+
### | | | |
### | | +---|---------|---------+
### | | | | | |
### | | | V V V
### |o|o|o|0|<ab>|<c 0|<de>|<f 0|<gh>|<i 0|o|
### ^ |
### | |
### +-------------------------------------+
### 0 0 0 0 0 0 0 0 0 0 0
### 1 1 1 1 1 1 1 1 1 1 1
### 7 7 7 7 7 7 7 7 7 7 7
### 7 7 7 7 7 7 7 7 7 7 7
### 6 6 6 7 7 7 7 7 7 7 7
### 5 6 7 0 1 2 3 4 5 6 7
###
sub set_arguments {
# No arguments, set the 017777 pointer to 017776 which is NULL
if (@ARGV==0) {
$Mem[ 017777 ] = 017776;
print( STDERR "No arguments, so NULL 017777 pointer\n") if ($debug);
return;
}
# Count the number of words to store each string and its pointer
my $wordcount=1; # 1 as we count the NULL pointer at end of array
my $argcount= @ARGV;
foreach my $arg (@ARGV) {
# +1 before /2 to allow for the NUL character at end of string
# += +1 to include the pointer to the string
$wordcount += 1 + ( (length($arg) +1)/2);
}
my $arraybase= 017777 - $wordcount;
my $stringbase= $arraybase + $argcount + 1; # include NULL pointer
$Mem[ 017777 ] = $arraybase;
# Now copy each string into memory and initialise the pointer
foreach my $arg (@ARGV) {
$Mem[$arraybase++]= $stringbase;
$stringbase= string2mem($arg, $stringbase);
}
}
### Simulate the machine code loaded into memory ### Simulate the machine code loaded into memory
sub simulate { sub simulate {
@@ -74,6 +131,7 @@ sub simulate {
my %Oplist = ( my %Oplist = (
oct("004") => \&dac, oct("004") => \&dac,
oct("020") => \&lac, oct("020") => \&lac,
oct("034") => \&tad,
oct("060") => \&jmp, oct("060") => \&jmp,
oct("070") => \&iot, oct("070") => \&iot,
oct("074") => \&special, oct("074") => \&special,
@@ -123,7 +181,7 @@ sub lac {
# Deposit AC # Deposit AC
sub dac { sub dac {
my ( $instruction, $indirect, $addr ) = @_; my ( $instruction, $indirect, $addr ) = @_;
printf( STDERR "PC %06o: dac AC (value %08o) into %05o into AC\n", printf( STDERR "PC %06o: dac AC (value %08o) into %05o\n",
$PC, $AC, $addr ) $PC, $AC, $addr )
if ($debug); if ($debug);
if ($indirect) { if ($indirect) {
@@ -134,6 +192,20 @@ sub dac {
$PC++; $PC++;
} }
# Add to AC
sub tad {
my ( $instruction, $indirect, $addr ) = @_;
printf( STDERR "PC %06o: tac AC (value %08o) from addr %05o\n",
$PC, $AC, $addr )
if ($debug);
if ($indirect) {
$AC += $Mem[ $Mem[$addr] & 017777 ];
} else {
$AC+= $Mem[$addr];
}
$PC++;
}
# Jump # Jump
sub jmp { sub jmp {
my ( $instruction, $indirect, $addr ) = @_; my ( $instruction, $indirect, $addr ) = @_;
@@ -153,15 +225,20 @@ sub special {
exit(1); exit(1);
} }
if ( $instruction == 0741100 ) { # spa: skip on positive AC if ( $instruction == 0741100 ) { # spa: skip on positive AC
printf( STDERR "PC %06o: spa\n", $PC ) if ($debug); printf( STDERR "PC %06o: spa AC %06o\n", $PC, $AC ) if ($debug);
$PC += ( $AC >= 0 ) ? 2 : 1; $PC += ( $AC >= 0 ) ? 2 : 1;
return; return;
} }
if ( $instruction == 0741200 ) { # sna: skip on non-zero AC if ( $instruction == 0741200 ) { # sna: skip on non-zero AC
printf( STDERR "PC %06o: sna\n", $PC ) if ($debug); printf( STDERR "PC %06o: sna AC %06o\n", $PC, $AC ) if ($debug);
$PC += ( $AC != 0 ) ? 2 : 1; $PC += ( $AC != 0 ) ? 2 : 1;
return; return;
} }
if ( $instruction == 0740200 ) { # sza: skip on zero AC
printf( STDERR "PC %06o: sza AC %06o\n", $PC, $AC ) if ($debug);
$PC += ( $AC == 0 ) ? 2 : 1;
return;
}
printf( STDERR "PC %06o: unknown instruction %08o\n", $PC, $instruction ); printf( STDERR "PC %06o: unknown instruction %08o\n", $PC, $instruction );
exit(1); exit(1);
} }
@@ -237,14 +314,13 @@ sub sys_open {
if ( open( my $FH, "<", $filename ) ) { if ( open( my $FH, "<", $filename ) ) {
# Find a place in the @FD array to store this filehandle. 99 is arbitrary # Find a place in the @FD array to store this filehandle. 99 is arbitrary
my $fd; foreach my $fd ( 0 .. 99 ) {
foreach $fd ( 0 .. 99 ) {
if ( !defined( $FD[$fd] ) ) { if ( !defined( $FD[$fd] ) ) {
$FD[$fd] = $FH; $FD[$fd] = $FH;
$AC = $fd;
last; last;
} }
} }
$AC = $fd;
return; return;
} else { } else {
# No filehandle, so it's an error # No filehandle, so it's an error
@@ -393,3 +469,22 @@ sub mem2string {
$addr++; $addr++;
} }
} }
# Given a string and the address of a word in memory, copy
# the string into memory starting at that address and NUL
# terminate the string. Return the first address after the string.
#
# We will go off the end of the string: suppress warnings
no warnings ('substr');
sub string2mem {
my ($str, $base)= @_;
# <= length so we go off the end and insert a NUL
for (my $i=0; $i <= length($str); $i += 2) {
my $c1= substr($str, $i, 1) || "";
my $c2= substr($str, $i+1, 1) || "";
#printf("Saving %06o to %05o\n", (ord($c1) << 9 ) | ord($c2), $base);
$Mem[$base++]= (ord($c1) << 9 ) | ord($c2);
}
return($base);
}
+75 -2
View File
@@ -1,6 +1,13 @@
" Simple cat program: echo stdin to stdout until no more words to read " Simple cat program: echo stdin to stdout until no more words to read
main: main:
" Load the pointer pointer in 017777 to see if we have any arguments
lac 017777 i
sza " No args, so copy stdin to stdout
jmp catfiles
" This section copies from standard input to standard output
stdinout:
" Read 5 words into the buffer from stdin " Read 5 words into the buffer from stdin
lac d0 lac d0
sys read; buf; 5 sys read; buf; 5
@@ -15,15 +22,81 @@ main:
" Write 5 words from the buffer to stdout " Write 5 words from the buffer to stdout
lac d1 lac d1
sys write; buf; 1:0 sys write; buf; 1:0
jmp main
error: " and loop back for more words to read
jmp stdinout
" This section opens files, and copies their contents to standard output
catfiles:
" We start with AC pointing to an argument. Save it at label 1f
dac 1f
" Open the file and get the fd into AC
sys open; 1:0; 0; 0
spa
jmp noopen " Bad fd, exit with an error message
dac fd " Save the file descriptor
fileloop:
" Read 5 words into the buffer from the input file
lac fd
sys read; buf; 5
spa " Skip if result was >= 0
jmp error " Result was -ve, so error result
sna " Skip if result was >0
jmp fileend " Result was zero, so nothing left to read
" Save the count of words read in
dac 1f
" Write 5 words from the buffer to stdout
lac d1
sys write; buf; 1:0
" and loop back for more words to read
jmp fileloop
fileend:
" Close the open file descriptor
lac fd
sys close
" Load and increment the 017777 pointer
lac 017777
tad d1
dac 017777
" Load the pointer pointer in 017777 to see if we have any more arguments
lac 017777 i
sna " No args, so end the program
jmp end
jmp catfiles " Otherwise loop back to cat this file
end: end:
" exit " exit
sys exit sys exit
noopen:
" Print an "err open" string and exit
lac d1
sys write; noopenstr; 5
sys exit
noopenstr:
<er>;<r 040;<op>;<en>;012000
error:
" Print an "err read" string and exit
lac d1
sys write; noreadstr; 5
sys exit
noreadstr:
<er>;<r 040;<re>;<ad>;012000
d0: 0 d0: 0
d1: 1 d1: 1
fd: 0 " fd of the open file
" Input buffer for read " Input buffer for read
buf: 0; 0; 0; 0; 0 buf: 0; 0; 0; 0; 0