mirror of
https://github.com/DoctorWkt/pdp7-unix.git
synced 2026-04-15 16:19:44 +00:00
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:
111
tools/a7out
111
tools/a7out
@@ -27,11 +27,12 @@ if ( ( @ARGV > 0 ) && ( $ARGV[0] eq "-d" ) ) {
|
||||
}
|
||||
|
||||
# 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
|
||||
# and simulate it
|
||||
load_code( $ARGV[0] );
|
||||
load_code( shift(@ARGV) );
|
||||
set_arguments(@ARGV);
|
||||
simulate();
|
||||
exit(0);
|
||||
|
||||
@@ -67,6 +68,62 @@ sub load_code {
|
||||
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
|
||||
sub simulate {
|
||||
|
||||
@@ -74,6 +131,7 @@ sub simulate {
|
||||
my %Oplist = (
|
||||
oct("004") => \&dac,
|
||||
oct("020") => \&lac,
|
||||
oct("034") => \&tad,
|
||||
oct("060") => \&jmp,
|
||||
oct("070") => \&iot,
|
||||
oct("074") => \&special,
|
||||
@@ -123,7 +181,7 @@ sub lac {
|
||||
# Deposit AC
|
||||
sub dac {
|
||||
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 )
|
||||
if ($debug);
|
||||
if ($indirect) {
|
||||
@@ -134,6 +192,20 @@ sub dac {
|
||||
$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
|
||||
sub jmp {
|
||||
my ( $instruction, $indirect, $addr ) = @_;
|
||||
@@ -153,15 +225,20 @@ sub special {
|
||||
exit(1);
|
||||
}
|
||||
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;
|
||||
return;
|
||||
}
|
||||
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;
|
||||
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 );
|
||||
exit(1);
|
||||
}
|
||||
@@ -237,14 +314,13 @@ sub sys_open {
|
||||
if ( open( my $FH, "<", $filename ) ) {
|
||||
|
||||
# Find a place in the @FD array to store this filehandle. 99 is arbitrary
|
||||
my $fd;
|
||||
foreach $fd ( 0 .. 99 ) {
|
||||
foreach my $fd ( 0 .. 99 ) {
|
||||
if ( !defined( $FD[$fd] ) ) {
|
||||
$FD[$fd] = $FH;
|
||||
$AC = $fd;
|
||||
last;
|
||||
}
|
||||
}
|
||||
$AC = $fd;
|
||||
return;
|
||||
} else {
|
||||
# No filehandle, so it's an error
|
||||
@@ -393,3 +469,22 @@ sub mem2string {
|
||||
$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);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
" Simple cat program: echo stdin to stdout until no more words to read
|
||||
|
||||
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
|
||||
lac d0
|
||||
sys read; buf; 5
|
||||
@@ -15,15 +22,81 @@ main:
|
||||
" Write 5 words from the buffer to stdout
|
||||
lac d1
|
||||
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:
|
||||
" 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
|
||||
d1: 1
|
||||
fd: 0 " fd of the open file
|
||||
|
||||
" Input buffer for read
|
||||
buf: 0; 0; 0; 0; 0
|
||||
|
||||
Reference in New Issue
Block a user