tools/as7: added syscalls chmod and chown, added auto-increment
locations, fixed a bug in character input, added several EAE instructions. We now have cp.s, chmod.s and chown.s working.
This commit is contained in:
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
" cat: cat [arg1 arg2 ...]
|
" cat: cat arg1 [arg2 ...]
|
||||||
|
|
||||||
" Load the pointer pointer in 017777 to see if we have any arguments
|
" Load the pointer pointer in 017777 to see if we have any arguments
|
||||||
lac 017777 i
|
lac 017777 i
|
||||||
|
|||||||
+58
-52
@@ -1,77 +1,83 @@
|
|||||||
" chmode
|
" chmod: chmod mode file [file file ...]
|
||||||
|
"
|
||||||
|
" mode is an octal number
|
||||||
|
|
||||||
lac 017777 i
|
lac 017777 i " Have we got any arguments?
|
||||||
sad d4
|
sad d4
|
||||||
jmp error
|
jmp error " No, give an error
|
||||||
|
|
||||||
lac 017777
|
lac 017777
|
||||||
tad d4
|
tad d4 " Skip past argc
|
||||||
dac 8
|
dac 8 " and save the ptr to the octal value at location 8
|
||||||
tad d1
|
tad d1 " Why only 1 here?
|
||||||
dac name
|
dac name " Save the filename pointer
|
||||||
dzm octal
|
dzm octal " Zero the octal value and
|
||||||
dzm nchar
|
dzm nchar " the number of characters
|
||||||
-8
|
-8 " Set c1 to -8 so we can increment up to zero
|
||||||
dac c1
|
dac c1 " and thus count the number of chars in the argument
|
||||||
|
|
||||||
1:
|
1:
|
||||||
lac nchar
|
lac nchar " Get any left-over character from the last loop
|
||||||
dzm nchar
|
dzm nchar " and set nchar to empty now
|
||||||
sza
|
sza " It was already empty, so get a new word
|
||||||
jmp 2f
|
jmp 2f " Not empty, it has the second ASCII value, goto 2f
|
||||||
lac 8 i
|
lac 8 i " Read the next word with two chars in it
|
||||||
lmq
|
lmq " Copy it to MQ
|
||||||
and o177
|
and o177 " Trim off all but the second ASCII value
|
||||||
dac nchar
|
dac nchar " Save it into nchar
|
||||||
lacq
|
lacq " Bring it back from MQ
|
||||||
lrss 9
|
lrss 9 " and shift down the first ASCII value
|
||||||
|
|
||||||
2:
|
2:
|
||||||
sad o40
|
sad o40 " If the character is a space
|
||||||
jmp 3f
|
jmp 3f " don't try to make it part of the octal value
|
||||||
tad om60
|
tad om60 " Not a space, subtract 060 i.e. '0'
|
||||||
lmq
|
lmq " Move it into MQ
|
||||||
lac octal
|
lac octal " Load the octal value up to here
|
||||||
cll; als 3
|
cll; als 3 " Shift it left 3 bits
|
||||||
omq
|
omq " OR in the digit from MQ
|
||||||
dac octal
|
dac octal " and save back in the octal value
|
||||||
|
|
||||||
3:
|
3:
|
||||||
isz c1
|
isz c1 " Is that the last character?
|
||||||
jmp 1b
|
jmp 1b " No, go back and get another one
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
lac 017777 i
|
lac 017777 i " How many arguments left?
|
||||||
sad d8
|
sad d8
|
||||||
sys exit
|
sys exit " None, exit
|
||||||
tad dm4
|
tad dm4 " Subtract 4 to indicate one less argument
|
||||||
dac 017777 i
|
dac 017777 i " and save for next time
|
||||||
lac name
|
lac name " Also move to the next filename
|
||||||
tad d4
|
tad d4
|
||||||
dac name
|
dac name
|
||||||
lac octal
|
lac octal " Set AC to have the new file mode
|
||||||
sys chmode; name:0
|
sys chmod; name:0 " and change the file's mode
|
||||||
sma
|
sma
|
||||||
jmp loop
|
jmp loop " Loop if no error
|
||||||
lac name
|
lac name " We got back -1, error
|
||||||
dac 1f
|
dac 1f " Write out the filename on stdout
|
||||||
lac d1
|
lac d1 " followed by the " ?\n" string
|
||||||
sys write; 1:0; 4
|
sys write; 1:0; 4 " and loop back
|
||||||
lac d1
|
lac d1
|
||||||
sys write; 1f; 2
|
sys write; 1f; 2
|
||||||
jmp loop
|
jmp loop
|
||||||
|
|
||||||
1:
|
1:
|
||||||
040;077012
|
040;077012 " String literal " ?\n"
|
||||||
|
|
||||||
error:
|
error:
|
||||||
lac d1
|
lac d1 " Write " "\n" to stdout and exit
|
||||||
sys write; 1b+1; 1
|
sys write; 1b+1; 1
|
||||||
sys exit
|
sys exit
|
||||||
|
|
||||||
om60: -060
|
d1: 1 " Numeric constants
|
||||||
o40: 040
|
d4: 4
|
||||||
d1: 1
|
|
||||||
d8: 8
|
d8: 8
|
||||||
dm4: -4
|
dm4: -4
|
||||||
d4: 4
|
o40: 040
|
||||||
o177: 0177
|
o177: 0177
|
||||||
|
om60: -060
|
||||||
|
|
||||||
nchar: .=.+1
|
nchar: .=.+1 " Number of characters in the value entered
|
||||||
c1: .=.+1
|
c1: .=.+1
|
||||||
octal: .=.+1
|
octal: .=.+1 " The resulting octal value
|
||||||
|
|||||||
+60
-53
@@ -1,76 +1,83 @@
|
|||||||
" chown
|
" chown: chown uid file [file file ...]
|
||||||
lac 017777 i
|
"
|
||||||
sad d4
|
" uid is an octal number
|
||||||
jmp error
|
|
||||||
|
|
||||||
|
lac 017777 i " Have we got any arguments?
|
||||||
|
sad d4
|
||||||
|
jmp error " No, give an error
|
||||||
lac 017777
|
lac 017777
|
||||||
tad d4
|
tad d4 " Skip past argc
|
||||||
dac 8
|
dac 8 " and save the ptr to the octal value at location 8
|
||||||
tad d1
|
tad d1 " Why only 1 here?
|
||||||
dac name
|
dac name " Save the filename pointer
|
||||||
dzm octal
|
dzm octal " Zero the octal value and
|
||||||
dzm nochar
|
dzm nchar " the number of characters
|
||||||
-8
|
-8 " Set c1 to -8 so we can increment up to zero
|
||||||
dac c1
|
dac c1 " and thus count the number of chars in the argument
|
||||||
|
|
||||||
1:
|
1:
|
||||||
lac nchar
|
lac nchar " Get any left-over character from the last loop
|
||||||
dzm nchar
|
dzm nchar " and set nchar to empty now
|
||||||
sza
|
sza " It was already empty, so get a new word
|
||||||
jmp 2f
|
jmp 2f " Not empty, it has the second ASCII value, goto 2f
|
||||||
lac 8 i
|
lac 8 i " Read the next word with two chars in it
|
||||||
lmq
|
lmq " Copy it to MQ
|
||||||
and o177
|
and o177 " Trim off all but the second ASCII value
|
||||||
dac nchar
|
dac nchar " Save it into nchar
|
||||||
lacq
|
lacq " Bring it back from MQ
|
||||||
lrss 9
|
lrss 9 " and shift down the first ASCII value
|
||||||
|
|
||||||
2:
|
2:
|
||||||
sad o40
|
sad o40 " If the character is a space
|
||||||
jmp 3f
|
jmp 3f " don't try to make it part of the octal value
|
||||||
tad om60
|
tad om60 " Not a space, subtract 060 i.e. '0'
|
||||||
lmq
|
lmq " Move it into MQ
|
||||||
lac octal
|
lac octal " Load the octal value up to here
|
||||||
cll; als 3
|
cll; als 3 " Shift it left 3 bits
|
||||||
omq
|
omq " OR in the digit from MQ
|
||||||
dac octal
|
dac octal " and save back in the octal value
|
||||||
|
|
||||||
3:
|
3:
|
||||||
isz c1
|
isz c1 " Is that the last character?
|
||||||
jmp 1b
|
jmp 1b " No, go back and get another one
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
lac 017777 i
|
lac 017777 i " How many arguments left?
|
||||||
sad d8
|
sad d8
|
||||||
sys exit
|
sys exit " None, exit
|
||||||
tad dm4
|
tad dm4 " Subtract 4 to indicate one less argument
|
||||||
dac 017777 i
|
dac 017777 i " and save for next time
|
||||||
lac name
|
lac name " Also move to the next filename
|
||||||
tad d4
|
tad d4
|
||||||
dac name
|
dac name
|
||||||
lac octal
|
lac octal " Set AC to have the new file mode
|
||||||
sys chowner; name:0
|
sys chown; name:0 " and change the file's owner
|
||||||
sma
|
sma
|
||||||
jmp loop
|
jmp loop " Loop if no error
|
||||||
lac name
|
lac name " We got back -1, error
|
||||||
dac 1f
|
dac 1f " Write out the filename on stdout
|
||||||
lac d1
|
lac d1 " followed by the " ?\n" string
|
||||||
sys write; 1:0; 4
|
sys write; 1:0; 4 " and loop back
|
||||||
lac d1
|
lac d1
|
||||||
sys write; 1f; 2
|
sys write; 1f; 2
|
||||||
jmp loop
|
jmp loop
|
||||||
|
|
||||||
1:
|
1:
|
||||||
040;077012
|
040;077012 " String literal " ?\n"
|
||||||
|
|
||||||
error:
|
error:
|
||||||
lac d1
|
lac d1 " Write " "\n" to stdout and exit
|
||||||
sys write; 1b+1; 1
|
sys write; 1b+1; 1
|
||||||
sys exit
|
sys exit
|
||||||
|
|
||||||
om60: -060
|
d1: 1 " Numeric constants
|
||||||
o40: 040
|
d4: 4
|
||||||
d1: 1
|
|
||||||
d8: 8
|
d8: 8
|
||||||
dm4: -4
|
dm4: -4
|
||||||
d4: 4
|
o40: 040
|
||||||
o177: 0177
|
o177: 0177
|
||||||
|
om60: -060
|
||||||
|
|
||||||
nchar: .=.+1
|
nchar: .=.+1 " Number of characters in the value entered
|
||||||
c1: .=.+1
|
c1: .=.+1
|
||||||
octal: .=.+1
|
octal: .=.+1 " The resulting octal value
|
||||||
|
|||||||
+31
-26
@@ -1,41 +1,46 @@
|
|||||||
" chrm
|
" chrm: chrm dir file [file file ...]
|
||||||
|
"
|
||||||
|
" chdir into the named directory and unlink the files that are in there
|
||||||
|
"
|
||||||
|
" The code depends on a "dd" directory existing which holds the named dir
|
||||||
|
|
||||||
lac 017777
|
lac 017777 " Go to the argc
|
||||||
tad d5
|
tad d5 " Skip past the argc and argv[0]
|
||||||
dac 1f
|
dac 1f " Save argv[1] in the chdir arg below
|
||||||
dac 2f
|
dac 2f " and in the unlink as well? Yes, we skip it
|
||||||
lac 017777 i
|
lac 017777 i " How many arguments do we have?
|
||||||
sad d4
|
sad d4
|
||||||
sys exit
|
sys exit " None, so exit
|
||||||
tad dm4
|
tad dm4 " Subtract 1
|
||||||
dac 017777 i
|
dac 017777 i " and save in the argc
|
||||||
sys chdir; dd
|
|
||||||
sys chdir; 1;0
|
sys chdir; dd " chdir to dd
|
||||||
|
sys chdir; 1;0 " and then into the first argument
|
||||||
1:
|
1:
|
||||||
lac 017777 i
|
lac 017777 i " Any arguments left?
|
||||||
sad d4
|
sad d4
|
||||||
sys exit
|
sys exit " No, exit the program
|
||||||
tad dm4
|
tad dm4 " Subtract 4 from the argc and update it
|
||||||
dac 017777 i
|
dac 017777 i
|
||||||
lac 2f
|
lac 2f " Move up to the next filename
|
||||||
tad d4
|
tad d4
|
||||||
dac 2f
|
dac 2f " and save it in the unlink arg
|
||||||
sys unlink; 2:0
|
sys unlink; 2:0 " Unlink the file
|
||||||
sma
|
sma
|
||||||
jmp 1b
|
jmp 1b " Loop back if the unlink was OK, or issue err
|
||||||
lac 2b
|
lac 2b " Copy the filename pointer below
|
||||||
dac 2f
|
dac 2f
|
||||||
lac d1
|
lac d1 " Write the filename on stdout
|
||||||
sys write; 2:0; 4
|
sys write; 2:0; 4
|
||||||
lac d1
|
lac d1
|
||||||
sys write; 1f; 2
|
sys write; 1f; 2 " Write " ?\n" on stdout
|
||||||
jmp 1b
|
jmp 1b " and loop back
|
||||||
1:
|
|
||||||
040077;012000
|
|
||||||
|
|
||||||
|
1:
|
||||||
|
040077;012000 " String literal " ?\n"
|
||||||
dd:
|
dd:
|
||||||
<dd>;040040;040040;040040
|
<dd>;040040;040040;040040 " Filename dd
|
||||||
d1: 1
|
d1: 1
|
||||||
d4: 4
|
d4: 4
|
||||||
d5: 5
|
d5: 5
|
||||||
dm4: -4
|
dm4: -4
|
||||||
|
|||||||
+65
-58
@@ -1,81 +1,89 @@
|
|||||||
" cp
|
" cp: cp file1 file2 [file3 file4 [file5 file6] ...]
|
||||||
|
"
|
||||||
|
" Copies in pairs: file1 to file2, file3 to file4 etc.
|
||||||
|
|
||||||
|
lac 017777 " Skip past argc and save
|
||||||
|
tad d1 " argv[0] (our name) into name2
|
||||||
|
dac name2 " We will skip past it later
|
||||||
|
|
||||||
lac 017777
|
|
||||||
tad d1
|
|
||||||
dac name2
|
|
||||||
loop:
|
loop:
|
||||||
lac 017777 i
|
lac 017777 i " Any arguments left?
|
||||||
sad d4
|
sad d4
|
||||||
sys exit
|
sys exit " 4 words = no args left, exit
|
||||||
sad d8
|
sad d8 " Do we have 2 args?
|
||||||
jmp unbal
|
jmp unbal " No, an unbalanced set of arguments
|
||||||
tad dm8
|
tad dm8 " Subtract 8 (two args) from the argc
|
||||||
dac 017777 i
|
dac 017777 i " and save it
|
||||||
lac name2
|
lac name2
|
||||||
tad d4
|
tad d4
|
||||||
dac name1
|
dac name1 " Skipping pairs of filenames? not sure
|
||||||
tad d4
|
tad d4
|
||||||
dac name2
|
dac name2
|
||||||
sys open; name1: 0; 0
|
sys open; name1: 0; 0 " Open the input file
|
||||||
spa
|
spa
|
||||||
jmp error
|
jmp error " File open error
|
||||||
lac o17
|
lac o17 " Why load 15 (017) into AC?
|
||||||
sys creat; name2: 0
|
sys creat; name2: 0 " Create the output file
|
||||||
spa
|
spa
|
||||||
jmp error
|
jmp error " File create error
|
||||||
dzm nin
|
dzm nin " Set the number of input words to zero
|
||||||
|
|
||||||
1:
|
1:
|
||||||
lac bufp
|
lac bufp " Set up the base of the upcoming read
|
||||||
tad nin
|
tad nin " to be the buffer + nin so we skip
|
||||||
dac 0f
|
dac 0f " the existing words in the buffer
|
||||||
-1
|
-1
|
||||||
tad nin
|
tad nin " Calculate 1024 - nin, i.e. the number
|
||||||
cma
|
cma " of empty words yet to be filled in the
|
||||||
tad d1024
|
tad d1024 " buffer, and use it as the read count
|
||||||
dac 0f+1
|
dac 0f+1
|
||||||
lac d2
|
lac d2 " Read from fd 2: hard-wired in fd!
|
||||||
sys read; 0:..;..
|
sys read; 0:..;..
|
||||||
sna
|
sna
|
||||||
jmp 2f
|
jmp 2f " No words were read in, go to 2f
|
||||||
tad nin
|
tad nin " Add the number of words read in
|
||||||
dac nin
|
dac nin " to the existing number of words
|
||||||
sad d1024
|
sad d1024
|
||||||
jmp 2f
|
jmp 2f " We do have 1,024 words, go to 2f
|
||||||
jmp 1b
|
jmp 1b " Loop back if we don't have 1,024 words
|
||||||
|
|
||||||
2:
|
2:
|
||||||
lac nin
|
lac nin " Load the number of words in the input buffer
|
||||||
dac 2f
|
dac 2f " Save in the write word count argument
|
||||||
lac d3
|
lac d3 " Write to fd 3: hard-wired out fd!
|
||||||
sys write; buf; 2: 0
|
sys write; buf; 2:0
|
||||||
dzm nin
|
dzm nin " Set nin back to zero
|
||||||
lac 2b
|
lac 2b " Get the write count (updated by sys write)
|
||||||
sad d1024
|
sad d1024 " Did we write the buffer out?
|
||||||
jmp 1b
|
jmp 1b " Yes, we wrote 1,024 words, so loop back
|
||||||
lac d2
|
" to read another buffer's worth
|
||||||
sys close
|
lac d2
|
||||||
|
sys close " Close fd 2 and fd 3
|
||||||
lac d3
|
lac d3
|
||||||
sys close
|
sys close
|
||||||
jmp loop
|
jmp loop " Loop back to deal with the next arguments
|
||||||
error:
|
|
||||||
lac name1
|
error: " File error, print out the name1 on
|
||||||
|
lac name1 " standard output, fd 1 followed by " ?\n"
|
||||||
dac 1f
|
dac 1f
|
||||||
lac d1
|
lac d1
|
||||||
sys write; 1: 0; 4
|
sys write; 1:0; 4
|
||||||
lac d1
|
lac d1
|
||||||
sys write; mes; 1
|
sys write; mes; 1
|
||||||
lac name2
|
lac name2 " Then do the same with name 2
|
||||||
dac 1f
|
dac 1f
|
||||||
lac d1
|
lac d1
|
||||||
sys write; 1: 0; 4
|
sys write; 1: 0; 4
|
||||||
lac d1
|
lac d1
|
||||||
sys write; mes; 2
|
sys write; mes; 2
|
||||||
jmp loop
|
jmp loop " Loop back to deal with the next arguments
|
||||||
|
|
||||||
mes:
|
mes:
|
||||||
040000;077012
|
040000;077012 " String literal: " ?\n"
|
||||||
unbal:
|
|
||||||
lac name2
|
unbal: " We had an unbalanced set of arguments
|
||||||
tad d4
|
lac name2 " so print out the name after name2
|
||||||
|
tad d4 " on standard output followed by " ?\n"
|
||||||
dac 1f
|
dac 1f
|
||||||
lac d1
|
lac d1
|
||||||
sys write; 1: 0; 4
|
sys write; 1: 0; 4
|
||||||
@@ -83,15 +91,14 @@ unbal:
|
|||||||
sys write; mes; 2
|
sys write; mes; 2
|
||||||
sys exit
|
sys exit
|
||||||
|
|
||||||
d1: 1
|
d1: 1 " Numeric constants
|
||||||
|
d2: 2
|
||||||
|
d3: 3
|
||||||
d4: 4
|
d4: 4
|
||||||
d8: 8
|
d8: 8
|
||||||
o17: 017
|
o17: 017
|
||||||
dm8: -8
|
dm8: -8
|
||||||
d3: 3
|
|
||||||
d1024: 1024
|
d1024: 1024
|
||||||
nin: 0
|
nin: 0 " Number of words in the input buffer
|
||||||
bufp: buf
|
bufp: buf " Pointer to the buffer
|
||||||
d2: 2
|
buf: .=.+1024 " Buffer of 1,024 words
|
||||||
|
|
||||||
buf:
|
|
||||||
|
|||||||
+134
-70
@@ -16,7 +16,7 @@ my @Mem; # 8K 18-bit words of main memory
|
|||||||
my @FD; # Array of open filehandles
|
my @FD; # Array of open filehandles
|
||||||
|
|
||||||
# Registers
|
# Registers
|
||||||
my $PC = 0; # Program counter
|
my $PC = 020; # Program counter
|
||||||
my $AC = 0; # Accumulator
|
my $AC = 0; # Accumulator
|
||||||
my $LINK = 0; # Link register, either 0 or LINKMASK
|
my $LINK = 0; # Link register, either 0 or LINKMASK
|
||||||
my $MQ = 0; # MQ register
|
my $MQ = 0; # MQ register
|
||||||
@@ -172,6 +172,14 @@ sub simulate {
|
|||||||
oct("074") => \&opr,
|
oct("074") => \&opr,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
# List of opcodes that DON'T auto-increment
|
||||||
|
# locations 10-17 when we have the indirect bit
|
||||||
|
my %NoIncr = (
|
||||||
|
oct("000") => 1, # cal
|
||||||
|
oct("064") => 1, # eae
|
||||||
|
oct("074") => 1 # opr
|
||||||
|
);
|
||||||
|
|
||||||
# Loop indefinitely
|
# Loop indefinitely
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
@@ -181,6 +189,14 @@ sub simulate {
|
|||||||
my $indirect = ( $instruction >> 13 ) & 1;
|
my $indirect = ( $instruction >> 13 ) & 1;
|
||||||
my $addr = $instruction & MAXADDR;
|
my $addr = $instruction & MAXADDR;
|
||||||
|
|
||||||
|
# Auto-increment locations 010 to 017 if $indirect
|
||||||
|
# and this is an instruction that does increment
|
||||||
|
if ($indirect && ($addr >= 010) && ($addr <= 017) &&
|
||||||
|
!defined($NoIncr{$opcode})) {
|
||||||
|
$Mem[$addr]++;
|
||||||
|
$Mem[$addr] &= MAXINT;
|
||||||
|
}
|
||||||
|
|
||||||
# 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;
|
||||||
|
|
||||||
@@ -212,7 +228,12 @@ sub simulate {
|
|||||||
sub dump_memory {
|
sub dump_memory {
|
||||||
my ( $start, $end, $yeszero ) = @_;
|
my ( $start, $end, $yeszero ) = @_;
|
||||||
foreach my $i ( $start .. $end ) {
|
foreach my $i ( $start .. $end ) {
|
||||||
printf( STDERR "%06o: %06o\n", $i, $Mem[$i] )
|
# Convert the word into possibly two ASCII characters
|
||||||
|
my $c1= ($Mem[$i] >> 9) & 0777;
|
||||||
|
$c1= ($c1 < 0200) ? chr($c1) : " ";
|
||||||
|
my $c2= $Mem[$i] & 0777;
|
||||||
|
$c2= ($c2 < 0200) ? chr($c2) : " ";
|
||||||
|
printf( STDERR "%06o: %06o %s%s\n", $i, $Mem[$i], $c1, $c2)
|
||||||
if ( $yeszero || $Mem[$i] != 0 );
|
if ( $yeszero || $Mem[$i] != 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -239,8 +260,8 @@ sub tad {
|
|||||||
dprintf( "tad AC (value %06o) with addr %06o (%06o)\n",
|
dprintf( "tad AC (value %06o) with addr %06o (%06o)\n",
|
||||||
$AC, $indaddr, $Mem[$indaddr] );
|
$AC, $indaddr, $Mem[$indaddr] );
|
||||||
$AC = $AC + $Mem[$indaddr];
|
$AC = $AC + $Mem[$indaddr];
|
||||||
|
$LINK = ($LINK ^ $AC) & LINKMASK;
|
||||||
$AC = $AC & MAXINT;
|
$AC = $AC & MAXINT;
|
||||||
$LINK = $AC & LINKMASK;
|
|
||||||
$PC++;
|
$PC++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,6 +466,60 @@ sub opr {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Extended arithmetic element instructions
|
||||||
|
sub eae {
|
||||||
|
my ( $instruction, $addr, $indaddr ) = @_;
|
||||||
|
my $step = $instruction & EAESTEP;
|
||||||
|
my $maskedinstr= $instruction & EAEIMASK;
|
||||||
|
|
||||||
|
if ( $maskedinstr == 0660500 ) { # lrss: long right shift, signed
|
||||||
|
# We ignore the MQ as it's not
|
||||||
|
# used by any user-mode programs
|
||||||
|
dprintf( "lrss %06o AC step %d\n", $AC, $step );
|
||||||
|
|
||||||
|
# Save the AC's sign into LINK
|
||||||
|
my $newlink = ( $AC << 1 ) & LINKMASK;
|
||||||
|
$AC = ( ( $LINK | $AC ) >> $step ) & MAXINT;
|
||||||
|
$LINK = $newlink;
|
||||||
|
$PC++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( $maskedinstr == 0660700 ) { # alss: long left shift, signed
|
||||||
|
# We don't fill the lsb with LINK yet
|
||||||
|
dprintf( "alss AC %06o step %d\n", $AC, $step );
|
||||||
|
$AC = ( $AC << $step ) & MAXINT;
|
||||||
|
$PC++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( $maskedinstr == 0640700 ) { # als: long left shift
|
||||||
|
dprintf( "alss AC %06o step %d\n", $AC, $step );
|
||||||
|
$AC = ( $AC << $step ) & MAXINT;
|
||||||
|
$PC++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( $instruction == 0652000 ) { # lmq: load MC from AC
|
||||||
|
dprintf( "lmq AC %06o into MQ\n", $AC);
|
||||||
|
$MQ= $AC;
|
||||||
|
$PC++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( $instruction == 0641002 ) { # lacq: load AC from MQ
|
||||||
|
dprintf( "lacq MQ %06o into AC\n", $MQ);
|
||||||
|
$AC= $MQ;
|
||||||
|
$PC++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( $instruction == 0640002 ) { # lacq: OR AC with MQ
|
||||||
|
dprintf( "omq MQ %06o and AC %06o\n", $MQ, $AC);
|
||||||
|
$AC |= $MQ;
|
||||||
|
$PC++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf( STDERR "PC %06o: Unknown eae instruction %06o\n",
|
||||||
|
$PC, $instruction );
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
# cal: used for system calls
|
# cal: used for system calls
|
||||||
sub cal {
|
sub cal {
|
||||||
my ( $instruction, $addr, $indaddr ) = @_;
|
my ( $instruction, $addr, $indaddr ) = @_;
|
||||||
@@ -457,6 +532,8 @@ sub cal {
|
|||||||
6 => \&sys_creat,
|
6 => \&sys_creat,
|
||||||
9 => \&sys_close,
|
9 => \&sys_close,
|
||||||
14 => \&sys_exit,
|
14 => \&sys_exit,
|
||||||
|
18 => \&sys_chmod,
|
||||||
|
19 => \&sys_chown,
|
||||||
);
|
);
|
||||||
|
|
||||||
# Simulate the syscall. Each syscall updates the $PC
|
# Simulate the syscall. Each syscall updates the $PC
|
||||||
@@ -468,36 +545,6 @@ sub cal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Extended arithmetic element instructions
|
|
||||||
sub eae {
|
|
||||||
my ( $instruction, $addr, $indaddr ) = @_;
|
|
||||||
my $step = $instruction & EAESTEP;
|
|
||||||
$instruction &= EAEIMASK;
|
|
||||||
|
|
||||||
if ( $instruction == 0660500 ) { # lrss: long right shift, signed
|
|
||||||
# We ignore the MQ as it's not
|
|
||||||
# used by any user-mode programs
|
|
||||||
dprintf( "lrss %06o AC step %d\n", $AC, $step );
|
|
||||||
|
|
||||||
# Save the AC's sign into LINK
|
|
||||||
my $newlink = ( $AC << 1 ) & LINKMASK;
|
|
||||||
$AC = ( ( $LINK | $AC ) >> $step ) & MAXINT;
|
|
||||||
$LINK = $newlink;
|
|
||||||
$PC++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ( $instruction == 0660700 ) { # alss: long left shift, signed
|
|
||||||
# We don't fill the lsb with LINK yet
|
|
||||||
dprintf( "alss %06o AC step %d\n", $AC, $step );
|
|
||||||
$AC = ( $AC << $step ) & MAXINT;
|
|
||||||
$PC++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
printf( STDERR "PC %06o: Unknown eae instruction %06o\n",
|
|
||||||
$PC, $instruction );
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
# Exit system call
|
# Exit system call
|
||||||
sub sys_exit {
|
sub sys_exit {
|
||||||
dprintf("exit system call\n");
|
dprintf("exit system call\n");
|
||||||
@@ -558,9 +605,8 @@ sub sys_open {
|
|||||||
# AC is the opened fd on success, or -1 on error
|
# AC is the opened fd on success, or -1 on error
|
||||||
|
|
||||||
# Get the start address of the string
|
# Get the start address of the string
|
||||||
my $start = $Mem[ $PC + 1 ];
|
|
||||||
|
|
||||||
# Convert this to a sensible ASCII filename
|
# Convert this to a sensible ASCII filename
|
||||||
|
my $start = $Mem[ $PC + 1 ];
|
||||||
my $filename = mem2arg($start);
|
my $filename = mem2arg($start);
|
||||||
|
|
||||||
# Choose to open read-only or write-only
|
# Choose to open read-only or write-only
|
||||||
@@ -576,7 +622,7 @@ sub sys_open {
|
|||||||
|
|
||||||
# Creat system call
|
# Creat system call
|
||||||
sub sys_creat {
|
sub sys_creat {
|
||||||
# Open seems to have 1 arguments: PC+1 is a pointer to the filename.
|
# Creat seems to have 1 argument: PC+1 is a pointer to the filename.
|
||||||
# Some programs seem to have a second argument always set to 0.
|
# Some programs seem to have a second argument always set to 0.
|
||||||
# AC is the opened fd on success, or -1 on error
|
# AC is the opened fd on success, or -1 on error
|
||||||
|
|
||||||
@@ -629,7 +675,8 @@ sub sys_read {
|
|||||||
|
|
||||||
my $c1 = getc($FH);
|
my $c1 = getc($FH);
|
||||||
last if ( !defined($c1) ); # No character, leave the loop
|
last if ( !defined($c1) ); # No character, leave the loop
|
||||||
my $c2 = getc($FH) || ""; # No character, make it a NUL
|
my $c2 = getc($FH); # No character, make it a NUL
|
||||||
|
$c2= "" if (!defined($c2));
|
||||||
$Mem[$addr] =
|
$Mem[$addr] =
|
||||||
( ord($c1) << 9 ) | ord($c2); # Pack both into one word
|
( ord($c1) << 9 ) | ord($c2); # Pack both into one word
|
||||||
$count++;
|
$count++;
|
||||||
@@ -642,7 +689,6 @@ sub sys_read {
|
|||||||
|
|
||||||
# Write system call
|
# Write system call
|
||||||
sub sys_write {
|
sub sys_write {
|
||||||
|
|
||||||
# Write seems to have arguments: AC is the file descriptor, PC+1 is
|
# Write seems to have arguments: AC is the file descriptor, PC+1 is
|
||||||
# the pointer to the buffer and PC+2 is the number of words to write
|
# the pointer to the buffer and PC+2 is the number of words to write
|
||||||
|
|
||||||
@@ -677,6 +723,56 @@ sub sys_write {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Chmod system call
|
||||||
|
sub sys_chmod {
|
||||||
|
# Chmod gets the permission bits in AC and a pointer
|
||||||
|
# to the file's name in PC+1. s2.s has these instruction for chmod:
|
||||||
|
# lac u.ac; and o17 so only the lowest 4
|
||||||
|
# bits are the permission bits that can be set.
|
||||||
|
# I'm going to guess these (from v1 chmod manual):
|
||||||
|
# 01 write for non-owner
|
||||||
|
# 02 read for non-owner
|
||||||
|
# 04 write for owner
|
||||||
|
# 10 read for owner
|
||||||
|
my $mode;
|
||||||
|
$mode|= 0002 if ($AC & 01);
|
||||||
|
$mode|= 0004 if ($AC & 02);
|
||||||
|
$mode|= 0220 if ($AC & 04);
|
||||||
|
$mode|= 0440 if ($AC & 010);
|
||||||
|
|
||||||
|
my $start = $Mem[ $PC + 1 ];
|
||||||
|
my $filename = mem2arg($start);
|
||||||
|
dprintf( "chmod %06o file %s\n", $mode, $filename);
|
||||||
|
|
||||||
|
# Do the chmod on the file
|
||||||
|
my $result= chmod($mode, $filename);
|
||||||
|
|
||||||
|
# Set AC to -1 if no files were changed, else 0
|
||||||
|
$AC= ($result == 0) ? MAXINT : 0;
|
||||||
|
$PC += 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Chown system call
|
||||||
|
sub sys_chown {
|
||||||
|
# Chown gets the numeric user-id in AC and a pointer
|
||||||
|
# to the file's name in PC+1.
|
||||||
|
# Get the start address of the string
|
||||||
|
# Convert this to a sensible ASCII filename
|
||||||
|
my $start = $Mem[ $PC + 1 ];
|
||||||
|
my $filename = mem2arg($start);
|
||||||
|
dprintf( "chown file %s to uid %06o\n", $filename, $AC);
|
||||||
|
|
||||||
|
|
||||||
|
# Do the chown, leave group-id untouched. Get number of files changed
|
||||||
|
my $result= chown($AC, -1, $filename);
|
||||||
|
|
||||||
|
# Set AC to -1 if no files were changed, else 0
|
||||||
|
$AC= ($result == 0) ? MAXINT : 0;
|
||||||
|
$PC += 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
# Convert an 18-bit word into two ASCII characters and return them.
|
# Convert an 18-bit word into two ASCII characters and return them.
|
||||||
# Don't return NUL characters
|
# Don't return NUL characters
|
||||||
sub word2ascii {
|
sub word2ascii {
|
||||||
@@ -709,38 +805,6 @@ sub mem2arg {
|
|||||||
return ($result);
|
return ($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Given the address of a word in memory, interpret that location
|
|
||||||
# and those following as a NUL-terminated ASCII string and return
|
|
||||||
# a copy of this string
|
|
||||||
# XXX: not sure if I still need this.
|
|
||||||
sub mem2string {
|
|
||||||
my $addr = shift;
|
|
||||||
my $result = "";
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
|
|
||||||
# Stop when the address leave the 8K word address space
|
|
||||||
return ($result) if ( $addr > MAXADDR );
|
|
||||||
|
|
||||||
# Stop when the value there is zero
|
|
||||||
my $word = $Mem[$addr];
|
|
||||||
return ($result) if ( $word == 0 );
|
|
||||||
|
|
||||||
# Get the top ASCII character, return if NUL
|
|
||||||
my $c1 = ( $word >> 9 ) & 0177;
|
|
||||||
return ($result) if ( $c1 == 0 );
|
|
||||||
$result .= chr($c1);
|
|
||||||
|
|
||||||
# Get the bottom ASCII character, return if NUL
|
|
||||||
my $c2 = $word & 0177;
|
|
||||||
return ($result) if ( $c2 == 0 );
|
|
||||||
$result .= chr($c2);
|
|
||||||
|
|
||||||
# Move up to the next address
|
|
||||||
$addr++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Print out debug messages
|
# Print out debug messages
|
||||||
sub dprintf {
|
sub dprintf {
|
||||||
printf( STDERR @_ ) if ( ($debug) || ($singlestep) );
|
printf( STDERR @_ ) if ( ($debug) || ($singlestep) );
|
||||||
|
|||||||
Reference in New Issue
Block a user