mirror of
https://github.com/DoctorWkt/pdp7-unix.git
synced 2026-01-25 03:37:23 +00:00
Merge branch 'master' of https://github.com/DoctorWkt/pdp7-unix
This commit is contained in:
commit
e9c8aae876
@ -148,6 +148,7 @@ init: 0
|
||||
dac fname
|
||||
-1
|
||||
dac eofflg
|
||||
jms nextfil
|
||||
jms ioinit
|
||||
dzm savchr
|
||||
dzm comflg
|
||||
|
||||
250
src/other/pbsh.s
250
src/other/pbsh.s
@ -1,53 +1,73 @@
|
||||
" -*-fundamental-*-
|
||||
" sh -- a shell
|
||||
" pbsh -- a shell
|
||||
" started by p budne 3/4/2016
|
||||
" with code from cat.s, init.s, and looking at the v1 (pdp-11) shell
|
||||
" with code from init.s, cat.s and looking at the v1 (pdp-11) shell
|
||||
|
||||
" XXX cat.s seems to write error output on fd 8
|
||||
" In particular, the newline/newcom/newarg/newchar processing loop(s)
|
||||
" are copied from the v1 shell:
|
||||
" redirection must occur at the start of a name (after whitespace)
|
||||
|
||||
start:
|
||||
" XXX take command line argument (script file to open), suppress prompt??
|
||||
" NOTE!!! v0 init.s doesn't set up the argv at the top of memory,
|
||||
" so the v0 shell may not have taken command line arguments!!!
|
||||
" if non-interactive, "dzm prompt", jump to newcom
|
||||
" includes ';' and '&' (unknown if available in v0 shell)
|
||||
" does NOT (yet) include quoting (backslash or single quote)
|
||||
" no "globbing" (performed by /etc/glob in v1 shell)
|
||||
|
||||
interactive:
|
||||
-1
|
||||
" v0 cat.s seems to write error output on fd 8, *BUT* shell doesn't
|
||||
" know what device is on stdout (passed by init, and init doesn't pass
|
||||
" fd 8), and there isn't a "dup" call, nor does init appear to be an
|
||||
" "indirect" device like /dev/tty, nor does init make an equivalent link!!
|
||||
|
||||
" Arguments for new processes are located at the end of memory.
|
||||
" Location 17777 points to a word with the argument count (argc),
|
||||
" followed by blocks of four words with (filename) arguments.
|
||||
" Currently leave room for ONLY maxargs items.
|
||||
maxargs=8
|
||||
|
||||
" v1 shell expects "-" as argument from init or login, will read
|
||||
" filename passed as argument. *BUT* v0 init.s doesn't set up the
|
||||
" argv at the top of memory, so the v0 shell may not have taken
|
||||
" command line arguments!!!
|
||||
|
||||
lac d1
|
||||
sys intrp " make shell uninterruptable
|
||||
sys getuid
|
||||
sma " <0?
|
||||
jmp newline " no, a mundane
|
||||
jmp newline " no
|
||||
lac hash " yes: superuser
|
||||
dac prompt " change prompt
|
||||
|
||||
newline:
|
||||
lac d1; sys write; prompt; 1 " output prompt
|
||||
jms rline " read line into ibuf
|
||||
lac iipt
|
||||
dac ipt
|
||||
newcom:
|
||||
dzm char " clear saved char
|
||||
dzm infile " clear input redirect file name
|
||||
dzm outfile " clear output redirect file name
|
||||
lac iopt " reset output pointer
|
||||
lac iopt " reset output buffer pointer
|
||||
dac opt
|
||||
dac nextarg
|
||||
|
||||
" reset high memory
|
||||
dzm argc " clear arg count
|
||||
lac argcptr
|
||||
lac argcptr " (re) set arg pointer
|
||||
dac argptr
|
||||
dzm argv0 " clear out argv0 for chdir comparison
|
||||
dzm argv0+1
|
||||
dzm argv0+2
|
||||
|
||||
" NOTE! behavior copied from v1 shell!!!
|
||||
" "improvements" here may be non-historic!!
|
||||
newarg:
|
||||
-8 " save 8 chars
|
||||
dac bcount
|
||||
dzm redirect
|
||||
dzm redirect " clear redirect flag
|
||||
|
||||
lac opt " save start for print (TEMP)
|
||||
dac nextarg
|
||||
|
||||
jms blank " skip whitespace
|
||||
jms delim " newline?
|
||||
jms delim " command sep?
|
||||
jmp eol " yes
|
||||
sad lt " input redirect?
|
||||
jmp redirin
|
||||
@ -59,19 +79,18 @@ redirin: " saw <
|
||||
dac redirect " flag redirect
|
||||
lac infilep
|
||||
dac opt
|
||||
jmp newchar " v1 behavior? no whitespace eater
|
||||
jmp newchar
|
||||
|
||||
redirout: " saw >
|
||||
dac redirect " flag redirect
|
||||
lac outfilep
|
||||
dac opt
|
||||
" v1 behavior? no whitespace eater!
|
||||
" fall
|
||||
|
||||
newchar:
|
||||
jms getc
|
||||
sad o40 " space?
|
||||
jmp ws " yes
|
||||
jmp eoname " yes
|
||||
jms delim
|
||||
jmp eoname
|
||||
3: jms putc " save
|
||||
@ -81,22 +100,16 @@ newchar:
|
||||
" here after 8 chars: discard until terminator seen
|
||||
discard:
|
||||
jms getc
|
||||
dac char
|
||||
sad o4
|
||||
jmp eof
|
||||
jms delim " end of line?
|
||||
jmp eoname
|
||||
sad o40
|
||||
jmp eoname
|
||||
jmp discard
|
||||
|
||||
" here with EOF in command: process command?
|
||||
eof:
|
||||
sys exit " quit, for now?
|
||||
|
||||
" name ended (short) with whitespace or newline
|
||||
" name ended (short) with whitespace or delim
|
||||
" pad out last name to 8 with spaces
|
||||
ws:
|
||||
" XXX check if ANYTHING read
|
||||
eoname:
|
||||
dac char " save terminator
|
||||
1: lac o40
|
||||
jms putc " no: copy into argv
|
||||
@ -104,9 +117,7 @@ ws:
|
||||
jmp 1b
|
||||
|
||||
" saw end of name
|
||||
eoname:
|
||||
dac char
|
||||
lac redirect
|
||||
2: lac redirect
|
||||
sza
|
||||
jmp 2f " last name was a redirect file, skip increment
|
||||
|
||||
@ -126,10 +137,10 @@ eoname:
|
||||
jms delim
|
||||
jmp eol
|
||||
|
||||
-maxargs
|
||||
tad argc
|
||||
sza
|
||||
jmp newarg
|
||||
lac argc
|
||||
sad maxargwords
|
||||
skp
|
||||
jmp newarg
|
||||
|
||||
" too many args, (complain?). for now eat rest of line
|
||||
4: jms getc
|
||||
@ -160,69 +171,66 @@ eol:
|
||||
jmp changedir
|
||||
|
||||
1:
|
||||
" comment these out to test "exec"
|
||||
" comment these out to test "exec" w/o fork
|
||||
sys fork
|
||||
jmp parent
|
||||
|
||||
" here in child
|
||||
lac d2; sys close " close fd 2
|
||||
sys unlink; exectemp " remove temp file
|
||||
sys open; argv0; 0 " try cwd (no link required)
|
||||
sma
|
||||
jmp 1f
|
||||
jmp cmderr
|
||||
|
||||
" try to link binary from "system" directory to "exectemp" file
|
||||
" sys unlink; exectemp " remove old temp file, if any
|
||||
" sys link; system; argv0; exectemp
|
||||
" spa
|
||||
" jmp notsys
|
||||
" jmp cmderr
|
||||
" sys open; exectemp; 0
|
||||
" spa
|
||||
" jmp error
|
||||
" jmp cmderr
|
||||
" dac cmdfd
|
||||
" sys unlink; exectemp
|
||||
" jmp 1f
|
||||
"notsys: " not found in "system"
|
||||
|
||||
sys open; argv0; 0 " try cwd
|
||||
spa
|
||||
jmp cmderr
|
||||
" skp
|
||||
|
||||
1: dac cmdfd " save command file descriptor
|
||||
cla " check for input redirection
|
||||
sad infile
|
||||
jmp 1f
|
||||
sad infile " input redirct?
|
||||
jmp 1f " no
|
||||
sys close " close fd 0
|
||||
sys open; infile; 0 " open redirected
|
||||
spa sna
|
||||
jmp inerror
|
||||
jmp inerror
|
||||
cla
|
||||
1: sad outfile
|
||||
jmp exec
|
||||
1: sad outfile " output redirec?
|
||||
jmp exec " no
|
||||
lac d1; sys close " close fd 1
|
||||
lac o17
|
||||
sys creat; outfile " open output redirect
|
||||
lac o17; sys creat; outfile " open output redirect
|
||||
spa
|
||||
jmp outerror
|
||||
jmp outerror
|
||||
|
||||
" here to "exec" file open on fd 2, adapted from init.s
|
||||
" here to "exec" file open on cmdfd, adapted from init.s
|
||||
exec:
|
||||
law boot-1 " Get source addr
|
||||
dac 8 " set up index 8 (pre-increments)
|
||||
dac 8 " set up index (pre-increments)
|
||||
law bootloc-1 " Copy "boot" code into high memory
|
||||
dac 9 " set up index 9 (pre-increments)
|
||||
dac 9 " set up index
|
||||
-bootlen " isz loop count for bootstrap copy
|
||||
dac bootcount
|
||||
1: lac 8 i
|
||||
dac 9 i
|
||||
isz bootcount " can only do this once!
|
||||
jmp 1b
|
||||
lac cmdfd " get fd for the executable
|
||||
lmq " Save the fd into MQ
|
||||
jmp bootloc " and then jump to the code
|
||||
|
||||
" copied up to bootloc in high memory (below argc)
|
||||
boot:
|
||||
lac d2 " Load fd 2 (the opened executable)
|
||||
lmq " Save the fd into MQ
|
||||
sys read; userbase; userlen " read executable in
|
||||
lacq " Get the fd back and close the file
|
||||
sys close
|
||||
sys close " close command file
|
||||
jmp userbase " and jump to the beginning of the executable
|
||||
bootlen=.-boot " length of bootstrap
|
||||
|
||||
bootcount: -bootlen " isz loop count for bootstrap copy
|
||||
|
||||
" error in child process:
|
||||
inerror: " error opening input redirection
|
||||
lac infilep
|
||||
@ -236,7 +244,7 @@ error: " error in child: filename pointer in AC
|
||||
dac 1f " save filename to complain about
|
||||
lac d1; sys write; 1: 0; 4
|
||||
lac d1; sys write; qmnl; 1
|
||||
lac d2; sys close
|
||||
lac d2; sys close " close executable, if any
|
||||
sys exit
|
||||
|
||||
" chdir command: executed in shell process
|
||||
@ -306,46 +314,48 @@ delim: 0
|
||||
isz delim " ran the gauntlet: skip home
|
||||
jmp delim i
|
||||
|
||||
" from cat.s
|
||||
" get character from ibuf
|
||||
getc: 0
|
||||
lac ipt " Load pointer to next word in the buffer
|
||||
sad eipt
|
||||
jmp 1f " end of the buffer, so read more
|
||||
dac 2f " Save the pointer
|
||||
add o400000 " flip MSB, increment pointer on overflow
|
||||
dac ipt
|
||||
ral " Move the msb into the link register
|
||||
lac 2f i " Load the word from the buffer
|
||||
szl " Skip if second character in word
|
||||
lrss 9 " first char: shift down the top character
|
||||
and o177 " Keep the lowest 7 bits
|
||||
sna
|
||||
jmp getc+1 " Skip a NUL characters and read another one
|
||||
jmp getc i " Return the character from the subroutine
|
||||
lac ipt i " fetch char
|
||||
isz ipt " increment pointer
|
||||
jmp getc i
|
||||
|
||||
" from init.s rline: read line from tty into ibuf
|
||||
" (store one character per word)
|
||||
rline: 0
|
||||
law ibuf-1 " Store ibuf pointer in location 8
|
||||
dac 8
|
||||
1:
|
||||
cla " Buffer is empty, read another 64 characters
|
||||
sys read; ibuf; 64
|
||||
sna
|
||||
jmp 1f " No characters were read in
|
||||
tad iipt " Add the word count to the base of the buffer
|
||||
dac eipt " and store in the end buffer pointer
|
||||
lac iipt " Reset the ipt to the base of the buffer
|
||||
dac ipt
|
||||
jmp getc+1 " and loop back to get one character
|
||||
1:
|
||||
lac o4 " No character, return with ctrl-D
|
||||
jmp getc i " return from subroutine
|
||||
cla; sys read; char; 1 " Read in one character from stdin
|
||||
sna " read ok?
|
||||
sys exit " EOF: quit
|
||||
lac char
|
||||
lrss 9 " Get it and shift down 9 bits
|
||||
sad o100 " '@' (kill) character?
|
||||
jmp rline+1 " yes: start from scratch
|
||||
sad o43 " '#' (erase) character?
|
||||
jmp 2f " yes: handle below
|
||||
|
||||
dac 8 i " Store the character in the buffer
|
||||
sad o12 " Newline?
|
||||
jmp rline i " yes: return
|
||||
jmp 1b " no: keep going
|
||||
2:
|
||||
law ibuf-1 " # handling. Do nothing if at start of the buffer
|
||||
sad 8
|
||||
jmp 1b " and loop back
|
||||
-1
|
||||
tad 8 " Otherwise, move the pointer in location 8 back one
|
||||
dac 8
|
||||
jmp 1b " and loop back
|
||||
|
||||
putc: 0
|
||||
and o177 " Keep the lowest 7 bits and save into 2f+1
|
||||
dac 2f+1
|
||||
lac opt " Save the pointer to the empty buffer
|
||||
dac 2f " position to 2f
|
||||
add o400000 " Flip the msb and save back into opt
|
||||
dac opt " This also has the effect of incrementing
|
||||
" the opt pointer every second addition!
|
||||
|
||||
lac opt " get output buffer pos
|
||||
dac 2f " save
|
||||
add o400000 " Flip the msb (advance) and save back into opt
|
||||
dac opt
|
||||
spa " If the bit was set, we already have one
|
||||
jmp 1f " character at 2f+1. If no previous character,
|
||||
lac 2f i " merge the old and new character together
|
||||
@ -358,11 +368,7 @@ putc: 0
|
||||
dac 2f i " Save the word into the buffer
|
||||
jmp putc i " No, so return (more room still in the buffer)
|
||||
|
||||
2: 0;0 " Current input and output word pointers
|
||||
ipt: 0 " Current input buffer base
|
||||
eipt: 0 " Pointer to end of data read in input buffer
|
||||
iipt: ibuf
|
||||
ibuf: .=.+64
|
||||
2: 0;0 " pointer, char
|
||||
|
||||
" literals
|
||||
d1: 1
|
||||
@ -371,10 +377,12 @@ o4:d4: 4
|
||||
o12: 012 " newline
|
||||
o17: 017
|
||||
o40: 040 " space
|
||||
o43: 043 " #
|
||||
o46: 046 " ampersand
|
||||
o73: 046 " semi
|
||||
o74:lt: 074 " <
|
||||
o76:gt: 076 " >
|
||||
o100: 0100 " @
|
||||
o177: 0177 " 7-bit (ASCII) mask
|
||||
o400000: 0400000 " MSB
|
||||
|
||||
@ -396,29 +404,34 @@ star: <*> "
|
||||
toomany: <to>;<o> ;<ma>;<ny>;< a>;<rg>;<s 012
|
||||
ltoomany=.-toomany
|
||||
|
||||
" ################ variables
|
||||
|
||||
prompt: <@> " v1 prompt
|
||||
pid: 0 " "other" pid
|
||||
char: 0 " white space char
|
||||
redirect: 0 " last file was a redirect (lt or gt)
|
||||
bcount: 0 " byte counter for current filename
|
||||
delimchar: 0 " character that terminated line
|
||||
|
||||
iopt:argv0p: argv0 " initial value for nextarg, opt
|
||||
nextarg: 0 " next slot in argv to fill
|
||||
opt: 0 " "output pointer" (may point to in/outfile)
|
||||
maxargwords: maxargs+maxargs+maxargs+maxargs
|
||||
argcptr: argc
|
||||
|
||||
infilep: infile
|
||||
outfilep: outfile
|
||||
|
||||
iipt: ibuf
|
||||
iopt:argv0p: argv0 " initial value for nextarg, opt
|
||||
|
||||
" ################ variables
|
||||
|
||||
prompt: <@ 040 " v1 prompt!
|
||||
|
||||
redirect: .=.+1 " last file was a redirect (lt or gt)
|
||||
nextarg: .=.+1 " next slot in argv to fill
|
||||
bcount: .=.+1 " byte counter for current filename
|
||||
opt: .=.+1 " "output pointer" (may point to in/outfile or into argv)
|
||||
delimchar: .=.+1 " character that terminated line
|
||||
char: .=.+1 " char that terminated word
|
||||
|
||||
outfile: .=.+4 " buffer for output redirect file name
|
||||
infile: .=.+4 " buffer for input redirect file name
|
||||
pid: .=.+1 " "other" pid
|
||||
cmdfd: .=.+1 " fd for executable
|
||||
bootcount: .=.+1 " loop count for "boot" copy
|
||||
|
||||
argcptr: argc
|
||||
|
||||
" leave room for maxargs items of 4 words each
|
||||
maxargs=8
|
||||
ipt: .=.+1 " input buf pointer
|
||||
ibuf: " input line stored here, one character per word
|
||||
|
||||
userbase=010000 " user starts at 4K
|
||||
argptr=017777 " last word points to argc + argv data
|
||||
@ -431,4 +444,3 @@ argv0=argc+1
|
||||
bootloc=argc-bootlen " location of bootstrap
|
||||
|
||||
userlen=bootloc-userbase " max executable
|
||||
|
||||
|
||||
434
src/other/sh.s
434
src/other/sh.s
@ -1,434 +0,0 @@
|
||||
" -*-fundamental-*-
|
||||
" sh -- a shell
|
||||
" started by p budne 3/4/2016
|
||||
" with code from cat.s, init.s, and looking at the v1 (pdp-11) shell
|
||||
|
||||
" XXX cat.s seems to write error output on fd 8
|
||||
|
||||
start:
|
||||
" XXX take command line argument (script file to open), suppress prompt??
|
||||
" NOTE!!! v0 init.s doesn't set up the argv at the top of memory,
|
||||
" so the v0 shell may not have taken command line arguments!!!
|
||||
" if non-interactive, "dzm prompt", jump to newcom
|
||||
|
||||
interactive:
|
||||
-1
|
||||
sys intrp " make shell uninterruptable
|
||||
sys getuid
|
||||
sma " <0?
|
||||
jmp newline " no, a mundane
|
||||
lac hash " yes: superuser
|
||||
dac prompt " change prompt
|
||||
|
||||
newline:
|
||||
lac d1; sys write; prompt; 1 " output prompt
|
||||
newcom:
|
||||
dzm char " clear saved char
|
||||
dzm infile " clear input redirect file name
|
||||
dzm outfile " clear output redirect file name
|
||||
lac iopt " reset output pointer
|
||||
dac opt
|
||||
dac nextarg
|
||||
|
||||
" reset high memory
|
||||
dzm argc " clear arg count
|
||||
lac argcptr
|
||||
dac argptr
|
||||
dzm argv0 " clear out argv0 for chdir comparison
|
||||
dzm argv0+1
|
||||
dzm argv0+2
|
||||
|
||||
newarg:
|
||||
-8 " save 8 chars
|
||||
dac bcount
|
||||
dzm redirect
|
||||
|
||||
lac opt " save start for print (TEMP)
|
||||
dac nextarg
|
||||
|
||||
jms blank " skip whitespace
|
||||
jms delim " newline?
|
||||
jmp eol " yes
|
||||
sad lt " input redirect?
|
||||
jmp redirin
|
||||
sad gt " output redirect?
|
||||
jmp redirout
|
||||
jmp 3f
|
||||
|
||||
redirin: " saw <
|
||||
dac redirect " flag redirect
|
||||
lac infilep
|
||||
dac opt
|
||||
jmp newchar " v1 behavior? no whitespace eater
|
||||
|
||||
redirout: " saw >
|
||||
dac redirect " flag redirect
|
||||
lac outfilep
|
||||
dac opt
|
||||
" v1 behavior? no whitespace eater!
|
||||
" fall
|
||||
|
||||
newchar:
|
||||
jms getc
|
||||
sad o40 " space?
|
||||
jmp ws " yes
|
||||
jms delim
|
||||
jmp eoname
|
||||
3: jms putc " save
|
||||
isz bcount " loop unless full
|
||||
jmp newchar
|
||||
|
||||
" here after 8 chars: discard until terminator seen
|
||||
discard:
|
||||
jms getc
|
||||
dac char
|
||||
sad o4
|
||||
jmp eof
|
||||
jms delim " end of line?
|
||||
jmp eoname
|
||||
sad o40
|
||||
jmp eoname
|
||||
jmp discard
|
||||
|
||||
" here with EOF in command: process command?
|
||||
eof:
|
||||
sys exit " quit, for now?
|
||||
|
||||
" name ended (short) with whitespace or newline
|
||||
" pad out last name to 8 with spaces
|
||||
ws:
|
||||
dac char " save terminator
|
||||
1: lac o40
|
||||
jms putc " no: copy into argv
|
||||
isz bcount " loop until full
|
||||
jmp 1b
|
||||
|
||||
" saw end of name
|
||||
eoname:
|
||||
dac char
|
||||
lac redirect
|
||||
sza
|
||||
jmp 2f " last name was a redirect file, skip increment
|
||||
|
||||
lac argc " increment argc
|
||||
tad d4
|
||||
dac argc
|
||||
lac nextarg
|
||||
tad d4 " advance nextarg
|
||||
dac nextarg
|
||||
|
||||
2:
|
||||
dzm redirect " clear redirect flag
|
||||
lac nextarg
|
||||
dac opt
|
||||
|
||||
lac char
|
||||
jms delim
|
||||
jmp eol
|
||||
|
||||
-maxargs
|
||||
tad argc
|
||||
sza
|
||||
jmp newarg
|
||||
|
||||
" too many args, (complain?). for now eat rest of line
|
||||
4: jms getc
|
||||
jms delim
|
||||
skp
|
||||
jmp 4b
|
||||
lac d1; sys write; toomany; ltoomany
|
||||
jmp newline
|
||||
|
||||
" here at end of line
|
||||
eol:
|
||||
sad delimchar " save eol character
|
||||
lac argc " check for empty command line
|
||||
sna " get anything?
|
||||
jmp 2f " no, go back for another
|
||||
|
||||
" check for built-in "chdir" command
|
||||
lac argv0
|
||||
sad chdirstr
|
||||
skp
|
||||
jmp 1f
|
||||
lac argv0+1
|
||||
sad chdirstr+1
|
||||
skp
|
||||
jmp 1f
|
||||
lac argv0+2
|
||||
sad chdirstr+2
|
||||
jmp changedir
|
||||
|
||||
1:
|
||||
" comment these out to test "exec"
|
||||
sys fork
|
||||
jmp parent
|
||||
|
||||
" here in child
|
||||
lac d2; sys close " close fd 2
|
||||
sys unlink; exectemp " remove temp file
|
||||
|
||||
" try to link binary from "system" directory to "exectemp" file
|
||||
" sys link; system; argv0; exectemp
|
||||
" spa
|
||||
" jmp notsys
|
||||
" sys open; exectemp; 0
|
||||
" spa
|
||||
" jmp error
|
||||
" sys unlink; exectemp
|
||||
" jmp 1f
|
||||
"notsys: " not found in "system"
|
||||
|
||||
sys open; argv0; 0 " try cwd
|
||||
spa
|
||||
jmp cmderr
|
||||
|
||||
cla " check for input redirection
|
||||
sad infile
|
||||
jmp 1f
|
||||
sys close " close fd 0
|
||||
sys open; infile; 0 " open redirected
|
||||
spa sna
|
||||
jmp inerror
|
||||
cla
|
||||
1: sad outfile
|
||||
jmp exec
|
||||
lac d1; sys close " close fd 1
|
||||
lac o17
|
||||
sys creat; outfile " open output redirect
|
||||
spa
|
||||
jmp outerror
|
||||
|
||||
" here to "exec" file open on fd 2, adapted from init.s
|
||||
exec:
|
||||
law boot-1 " Get source addr
|
||||
dac 8 " set up index 8 (pre-increments)
|
||||
law bootloc-1 " Copy "boot" code into high memory
|
||||
dac 9 " set up index 9 (pre-increments)
|
||||
1: lac 8 i
|
||||
dac 9 i
|
||||
isz bootcount " can only do this once!
|
||||
jmp 1b
|
||||
jmp bootloc " and then jump to the code
|
||||
|
||||
" copied up to bootloc in high memory (below argc)
|
||||
boot:
|
||||
lac d2 " Load fd 2 (the opened executable)
|
||||
lmq " Save the fd into MQ
|
||||
sys read; userbase; userlen " read executable in
|
||||
lacq " Get the fd back and close the file
|
||||
sys close
|
||||
jmp userbase " and jump to the beginning of the executable
|
||||
bootlen=.-boot " length of bootstrap
|
||||
|
||||
bootcount: -bootlen " isz loop count for bootstrap copy
|
||||
|
||||
" error in child process:
|
||||
inerror: " error opening input redirection
|
||||
lac infilep
|
||||
jmp error
|
||||
outerror: " error opening new stdout (stdout closed!)
|
||||
lac outfilep
|
||||
skp
|
||||
cmderr: " error opening command
|
||||
lac argv0p
|
||||
error: " error in child: filename pointer in AC
|
||||
dac 1f " save filename to complain about
|
||||
lac d1; sys write; 1: 0; 4
|
||||
lac d1; sys write; qmnl; 1
|
||||
lac d2; sys close
|
||||
sys exit
|
||||
|
||||
" chdir command: executed in shell process
|
||||
changedir:
|
||||
" XXX check if argc == 4 (no directories) and complain??
|
||||
lac argv0p
|
||||
skp
|
||||
1: lac 0f " increment argvp
|
||||
tad d4
|
||||
sad 0f
|
||||
-4 " decrement argc
|
||||
tad argc
|
||||
dac argc
|
||||
sna " done?
|
||||
jmp 2f " yes: join parent code
|
||||
sys chdir; 0:0
|
||||
sma " error?
|
||||
jmp 1b " no: look for another directory
|
||||
|
||||
" chdir call failed
|
||||
lac 0b
|
||||
dac 0f
|
||||
lac d1; sys write; 0:0; 4
|
||||
lac d1; sys write; qmnl; 1
|
||||
jmp 2f " join parent code
|
||||
|
||||
" here in parent, child pid in AC
|
||||
parent:
|
||||
" https://www.bell-labs.com/usr/dmr/www/hist.html
|
||||
" The message facility was used as follows: the parent shell, after
|
||||
" creating a process to execute a command, sent a message to the new
|
||||
" process by smes; when the command terminated (assuming it did not
|
||||
" try to read any messages) the shell's blocked smes call returned an
|
||||
" error indication that the target process did not exist. Thus the
|
||||
" shell's smes became, in effect, the equivalent of wait.
|
||||
dac pid
|
||||
lac delimchar
|
||||
sad o46 " ampersand?
|
||||
jmp newcom " yes: go back without wait
|
||||
lac pid
|
||||
sys smes " hang until child exits
|
||||
2: lac delimchar
|
||||
sad o73 " semi?
|
||||
jmp newcom " yes: look for another command w/o prompt
|
||||
jmp newline " no: output prompt
|
||||
|
||||
" ================
|
||||
" subroutines
|
||||
|
||||
" eat spaces
|
||||
" v1 routine name:
|
||||
blank: 0
|
||||
1: jms getc
|
||||
sad o40
|
||||
jmp 1b
|
||||
jmp blank i
|
||||
|
||||
" give skip return if AC *NOT* a command delimiter
|
||||
" v1 routine name:
|
||||
delim: 0
|
||||
sad o12 " newline
|
||||
jmp delim i
|
||||
sad o46 " ampersand
|
||||
jmp delim i
|
||||
sad o73 " semi
|
||||
jmp delim i
|
||||
isz delim " ran the gauntlet: skip home
|
||||
jmp delim i
|
||||
|
||||
" from cat.s
|
||||
getc: 0
|
||||
lac ipt " Load pointer to next word in the buffer
|
||||
sad eipt
|
||||
jmp 1f " end of the buffer, so read more
|
||||
dac 2f " Save the pointer
|
||||
add o400000 " flip MSB, increment pointer on overflow
|
||||
dac ipt
|
||||
ral " Move the msb into the link register
|
||||
lac 2f i " Load the word from the buffer
|
||||
szl " Skip if second character in word
|
||||
lrss 9 " first char: shift down the top character
|
||||
and o177 " Keep the lowest 7 bits
|
||||
sna
|
||||
jmp getc+1 " Skip a NUL characters and read another one
|
||||
jmp getc i " Return the character from the subroutine
|
||||
|
||||
1:
|
||||
cla " Buffer is empty, read another 64 characters
|
||||
sys read; ibuf; 64
|
||||
sna
|
||||
jmp 1f " No characters were read in
|
||||
tad iipt " Add the word count to the base of the buffer
|
||||
dac eipt " and store in the end buffer pointer
|
||||
lac iipt " Reset the ipt to the base of the buffer
|
||||
dac ipt
|
||||
jmp getc+1 " and loop back to get one character
|
||||
1:
|
||||
lac o4 " No character, return with ctrl-D
|
||||
jmp getc i " return from subroutine
|
||||
|
||||
putc: 0
|
||||
and o177 " Keep the lowest 7 bits and save into 2f+1
|
||||
dac 2f+1
|
||||
lac opt " Save the pointer to the empty buffer
|
||||
dac 2f " position to 2f
|
||||
add o400000 " Flip the msb and save back into opt
|
||||
dac opt " This also has the effect of incrementing
|
||||
" the opt pointer every second addition!
|
||||
|
||||
spa " If the bit was set, we already have one
|
||||
jmp 1f " character at 2f+1. If no previous character,
|
||||
lac 2f i " merge the old and new character together
|
||||
xor 2f+1
|
||||
jmp 3f " and go to the "save it in buffer" code
|
||||
1:
|
||||
lac 2f+1 " Move the character up into the top half
|
||||
alss 9
|
||||
3:
|
||||
dac 2f i " Save the word into the buffer
|
||||
jmp putc i " No, so return (more room still in the buffer)
|
||||
|
||||
2: 0;0 " Current input and output word pointers
|
||||
ipt: 0 " Current input buffer base
|
||||
eipt: 0 " Pointer to end of data read in input buffer
|
||||
iipt: ibuf
|
||||
ibuf: .=.+64
|
||||
|
||||
" literals
|
||||
d1: 1
|
||||
d2: 2
|
||||
o4:d4: 4
|
||||
o12: 012 " newline
|
||||
o17: 017
|
||||
o40: 040 " space
|
||||
o46: 046 " ampersand
|
||||
o73: 046 " semi
|
||||
o74:lt: 074 " <
|
||||
o76:gt: 076 " >
|
||||
o177: 0177 " 7-bit (ASCII) mask
|
||||
o400000: 0400000 " MSB
|
||||
|
||||
hash: <#> " superuser prompt
|
||||
qmnl: <? 012 " question mark, newline
|
||||
|
||||
system:
|
||||
<sy>;<st>;<em>; 040040
|
||||
|
||||
exectemp:
|
||||
<ex>;<ec>;<te>;<mp> " temporary link for file being exec'ed
|
||||
|
||||
chdirstr:
|
||||
<ch>;<di>;<r 040
|
||||
|
||||
" TEMP FOR DEBUG:
|
||||
star: <*> "
|
||||
|
||||
toomany: <to>;<o> ;<ma>;<ny>;< a>;<rg>;<s 012
|
||||
ltoomany=.-toomany
|
||||
|
||||
" ################ variables
|
||||
|
||||
prompt: <@> " v1 prompt
|
||||
pid: 0 " "other" pid
|
||||
char: 0 " white space char
|
||||
redirect: 0 " last file was a redirect (lt or gt)
|
||||
bcount: 0 " byte counter for current filename
|
||||
delimchar: 0 " character that terminated line
|
||||
|
||||
iopt:argv0p: argv0 " initial value for nextarg, opt
|
||||
nextarg: 0 " next slot in argv to fill
|
||||
opt: 0 " "output pointer" (may point to in/outfile)
|
||||
|
||||
infilep: infile
|
||||
outfilep: outfile
|
||||
|
||||
outfile: .=.+4 " buffer for output redirect file name
|
||||
infile: .=.+4 " buffer for input redirect file name
|
||||
|
||||
argcptr: argc
|
||||
|
||||
" leave room for maxargs items of 4 words each
|
||||
maxargs=8
|
||||
|
||||
userbase=010000 " user starts at 4K
|
||||
argptr=017777 " last word points to argc + argv data
|
||||
argc=argptr-maxargs-maxargs-maxargs-maxargs-1 " argc followed by argv
|
||||
|
||||
" arguments in 4 word blocks follow argc
|
||||
argv0=argc+1
|
||||
|
||||
" "bootstrap" (reads executable into userbase) JUST below argc
|
||||
bootloc=argc-bootlen " location of bootstrap
|
||||
|
||||
userlen=bootloc-userbase " max executable
|
||||
|
||||
10
src/sys/s3.s
10
src/sys/s3.s
@ -356,12 +356,12 @@ wppto:
|
||||
jms swap
|
||||
jmp wppto
|
||||
|
||||
" common exit for special file
|
||||
" common exit for special file input
|
||||
passone:
|
||||
sad o4000
|
||||
jmp okexit
|
||||
dac u.base i
|
||||
lac d1
|
||||
sad o4000 " CTRL/D?
|
||||
jmp okexit " yes: return zero
|
||||
dac u.base i " no: save for user
|
||||
lac d1 " return 1
|
||||
dac u.ac
|
||||
jmp sysexit
|
||||
|
||||
|
||||
@ -114,7 +114,7 @@ dsprestart:
|
||||
isz ttydelay
|
||||
krb " read keyboard buffer
|
||||
dac char " save in char
|
||||
sad o375 " interrupt char ('}'?)
|
||||
sad o375 " interrupt char (TTY ALT MODE?)
|
||||
jmp intrp1 " yes
|
||||
lac d1
|
||||
jms putchar
|
||||
|
||||
@ -14,7 +14,7 @@ while (1) {
|
||||
my $result= read($IN, my $three, 3);
|
||||
last if ($result != 3); # Not enough bytes read
|
||||
my ($b1, $b2, $b3)= unpack("CCC", $three);
|
||||
my $word= (($b1 & 077) << 12) | ($b2 << 6) | $b3;
|
||||
my $word= (($b1 & 077) << 12) | (($b2 & 077) << 6) | ($b3 & 077);
|
||||
|
||||
my $c1= ($word >> 9) & 0777;
|
||||
$c1= ($c1 < 0200) ? chr($c1) : " ";
|
||||
|
||||
74
tools/a7out
74
tools/a7out
@ -81,6 +81,18 @@ sub load_code {
|
||||
|
||||
# Open up the PDP-7 executable file
|
||||
open( my $IN, "<", $filename ) || die("Unable to open $filename: $!\n");
|
||||
my $c = getc($IN);
|
||||
seek $IN, 0, 0;
|
||||
if ((ord($c) & 0300) == 0200) { # handle "binary paper tape" format
|
||||
my $addr = 010000; # user programs loaded at 4K mark
|
||||
while ($addr <= 017777) {
|
||||
my $result = read_word($IN);
|
||||
last if ($result == -1);
|
||||
$Mem[$addr++] = $result;
|
||||
}
|
||||
close($IN);
|
||||
return;
|
||||
}
|
||||
while (<$IN>) {
|
||||
chomp;
|
||||
|
||||
@ -98,6 +110,18 @@ sub load_code {
|
||||
close($IN);
|
||||
}
|
||||
|
||||
### read a word from a file in paper tape binary format
|
||||
### return -1 on EOF
|
||||
sub read_word {
|
||||
my $F = shift;
|
||||
# Convert three bytes into one 18-bit word
|
||||
return -1 if ( read( $F, my $three, 3 ) != 3 ); # Not enough bytes read
|
||||
my ( $b1, $b2, $b3 ) = unpack( "CCC", $three );
|
||||
return ((($b1 & 077) << 12 ) |
|
||||
(($b2 & 077) << 6 ) |
|
||||
($b3 & 077));
|
||||
}
|
||||
|
||||
### Copy the arguments into the PDP-7 memory space, and build
|
||||
### an array of pointers to these arguments. Build a pointer
|
||||
### at MAXADDR that points at the array.
|
||||
@ -711,16 +735,19 @@ sub sys_fork {
|
||||
return;
|
||||
}
|
||||
|
||||
# Smes system call. Because we fake rmes with wait(),
|
||||
# there is no need for sms. When the child does
|
||||
# sys exit, that's going to wake wait() up and do the
|
||||
# rmes anyway.
|
||||
# shell depends on smes hanging while child process exists
|
||||
# https://www.bell-labs.com/usr/dmr/www/hist.html
|
||||
# The message facility was used as follows: the parent shell, after
|
||||
# creating a process to execute a command, sent a message to the new
|
||||
# process by smes; when the command terminated (assuming it did not
|
||||
# try to read any messages) the shell's blocked smes call returned an
|
||||
# error indication that the target process did not exist. Thus the
|
||||
# shell's smes became, in effect, the equivalent of wait.
|
||||
sub sys_smes {
|
||||
|
||||
# For now, do nothing
|
||||
dprintf("smes system call\n");
|
||||
waitpid($AC,0);
|
||||
dprintf("smes returning error\n");
|
||||
$AC = -1;
|
||||
$PC += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
# Rmes system call. We simply call wait and
|
||||
@ -927,34 +954,35 @@ sub sys_read {
|
||||
# Read each word in
|
||||
my $FH = $FD[$fd];
|
||||
$count = 0;
|
||||
my $tty = -t $FH;
|
||||
if (-t $FH) { # TTY?
|
||||
my $char = getc($FH); # use Term::ReadKey for 'cbreak' mode??
|
||||
if (defined($char)) {
|
||||
$Mem[$start] = ord($char) << 9; # only ever returns one char
|
||||
$AC = 1;
|
||||
}
|
||||
else {
|
||||
$AC = 0; # EOF
|
||||
}
|
||||
return;
|
||||
}
|
||||
foreach my $addr ( $start .. $end ) {
|
||||
|
||||
if ( $ISBINARY[$fd] ) {
|
||||
# Convert three bytes into one 18-bit word
|
||||
my $result = read( $FH, my $three, 3 );
|
||||
last if ( $result != 3 ); # Not enough bytes read
|
||||
my ( $b1, $b2, $b3 ) = unpack( "CCC", $three );
|
||||
$Mem[$addr] = ((($b1 & 077) << 12 ) |
|
||||
(($b2 & 077) << 6 ) |
|
||||
($b3 & 077));
|
||||
my $result = read_word($FH);
|
||||
last if ($result == -1);
|
||||
$Mem[$addr] = $result;
|
||||
$count++;
|
||||
}
|
||||
else {
|
||||
# Convert two ASCII characters into one 18-bit word
|
||||
my $c1 = getc($FH);
|
||||
my $c2;
|
||||
last if ( !defined($c1) ); # No character, leave the loop
|
||||
my $word = ord($c1) << 9;
|
||||
if ( !$tty || $c1 ne "\n") {
|
||||
$c2 = getc($FH);
|
||||
if (defined($c2)) {
|
||||
$word |= ord($c2);
|
||||
}
|
||||
}
|
||||
my $c2 = getc($FH);
|
||||
$word |= ord($c2) if (defined($c2));
|
||||
$Mem[$addr] = $word;
|
||||
$count++;
|
||||
last if ($tty && (($c1 && ($c1 eq "\n")) || ($c2 &&($c2 eq "\n"))));
|
||||
} # ascii
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user