1
0
mirror of https://github.com/livingcomputermuseum/pdp7-unix.git synced 2026-04-28 21:07:45 +00:00
This commit is contained in:
Tom Everett
2016-03-03 19:18:13 -07:00
18 changed files with 731 additions and 447 deletions

View File

@@ -9,6 +9,7 @@ utilities:
$(AS) -o bin/chmod src/cmd/chmod.s
$(AS) -o bin/chown src/cmd/chown.s
$(AS) -o bin/chrm src/cmd/chrm.s
$(AS) -o bin/ls src/other/wktls.s
clean:
rm -f bin/*

View File

@@ -1,15 +1,19 @@
# pdp7-unix
This is a project to resurrect Unix on the PDP-7 from a scan of the original
assembly code done by Norman Wilson.
Right now the scans are in the Unix Archive at
This is a project to resurrect Unix on the PDP-7 from scans of the original assembly
code done by Norman Wilson. The scans of PDP-7 Unix are in the Unix Archive at
http://www.tuhs.org/Archive/PDP-11/Distributions/research/McIlroy_v0/
as the files 0*.pdf. We now need to convert these to machine-readable
assembly code, write tools such as an assembler, a filesystem creation tool,
and write from scratch missing things like a shell, ls etc.
as the files 0*.pdf.
Update early March 2016: We've written an assembler, most of a user-mode
simulator and commented several source files. We now have these utilities
running: cat, cp, chmod, chown, chrm and ls.
Things to do: write a filesystem creation tool, write a shell, write the
missing utilities, try to bring the system up on a PDP-7 system. We have
a real PDP-7 and SimH as target platforms.
The code in the original scans are (c) Novell who own the rights to the Unix
source code. Everything that didn't come from the scanned pages are GPLv3.
source code. Everything that didn't come from the scanned files is GPLv3.
scans holds the unmodified OCR versions of the scanned files
@@ -17,6 +21,8 @@ src/cmd holds the modified source code of the user-mode programs
src/sys holds the modified source code of the kernel
src/other holds PDP-7 source code which did not come from the scanned files
tools holds the source for the tools written to assist the project
misc holds miscellaneous notes and information

View File

@@ -247,11 +247,11 @@ call:
isz 8
-1
tad sp
sad B
sad 8
skp
jmp 1b
lac ap i
img
lmq
lac dp
dac ap i
lac ap

View File

@@ -54,7 +54,7 @@ floop1:
tad d4
dac name
sys open; name; ..; 0
sys open; name: ..; 0
spa
jmp ferror
dac fi
@@ -189,7 +189,7 @@ ferror:
sys write; 1:..; 4
lac d1
sys write; 1f; 1
fmp floop1
jmp floop1
1: 077012
hangup:

View File

@@ -62,7 +62,7 @@ floop1:
tad d4
dac name
sys open; name; ..; 0
sys open; name: ..; 0
spa
jmp ferror
dac fi
@@ -72,7 +72,7 @@ ferror:
lac name
dac 1f
lac d1
sys write; 1;..; 4
sys write; 1:..; 4
lac d1
sys write; 1f; 1
jmp floop1
@@ -134,7 +134,7 @@ bksp:
jmp cloop
cret:
czm col
dzm col
jmp cloop
pass2:
@@ -278,6 +278,7 @@ hangup:
abort:
lac d1
sys write; m2; m2s
jmp stop
nofiles:
lac d1
@@ -342,7 +343,7 @@ gcard: 0
isz gcard
sna
jmp gcard i
irss 9
lrss 9
sad o45
jmp 1f
jms putc

View File

@@ -59,7 +59,7 @@ trace: 0
jmp stop
jmp trace i
itrace: 0
dtrace: 0
lac pc
dac 8
lac 8 i

View File

@@ -8,7 +8,7 @@ start:
fetch:
lac pc i
imq
lmq
and o17777
dac addr
ecla lls 4
@@ -79,7 +79,7 @@ bor:
jmp fetch
band:
lac t2 i
lac t1 i
and t2 i
dac t4 i
jmp fetch
@@ -185,7 +185,7 @@ consop:
tad d1
dac sp i
isz sp
iac addr
lac addr
dac sp i
isz sp
jmp fetch
@@ -206,13 +206,13 @@ mcall:
dac t2
-1
tad t2 i
imq
lmq
lac dp
dac t1 i
lac t1
dac dp
isz t1
iac pc
lac pc
dac t1 i
lacq
dac pc
@@ -247,11 +247,11 @@ call:
isz 8
-1
tad sp
sad B
sad 8
skp
jmp 1b
lac ap i
img
lmq
lac dp
dac ap i
lac ap
@@ -364,24 +364,24 @@ unaop:
jmp . i
uadr; umin; uind; unot
badr:
uadr:
lac t1
dac t3 i
jmp fetch
bmin:
umin:
-1
tad t1 i
cma
dac t3 i
jmp fetch
bind:
uind:
lac t1 i
dac t2 i
jmp fetch
bnot:
unot:
lac t1 i
sna cla
lac d1
@@ -412,22 +412,22 @@ s = n+a
t = s+a
u = t+a
x = u+a
f = x+a
y = x+a
d1: 1
dm1: -1
dm2: -2
o17777: 017777
:1: 0
:2: 0
:3: 0
:4: 0
:ddr: 0
t1: 0
t2: 0
t3: 0
t4: 0
addr: 0
pc = 017
sp: stack
dp: stack
ip: stack
ap: stack
stack: 0

View File

@@ -2,7 +2,7 @@
lac 017777 i
sad d8
skp
skp
sys exit
lac 017777
tad d5
@@ -12,13 +12,16 @@
dac fo
law 017
sys creat; scrname
spa; jms error
spa
jms error
dac fso
sys open; scrname; 0
spa; jms error
spa
jms error
dac fsi
sys chdir; dd
spa; jms error
spa
jms error
lac d1
sys write; pass1; 1
law fsobuf
@@ -31,12 +34,14 @@
dac dirp
dzm fsloc
sys open; dotdot; 0
spa; jms error
spa
jms error
dac fd
jms readdir; dotdot
law statbuf
sys status; dotdot; dotdot
spa; jms error
spa
jms error
lac statbuf+12 " i index
dac dirp i
isz dirp
@@ -75,13 +80,15 @@ loop:
sys read; scrname; 4
law statbuf
sys status; dotdot; scrname
spa; jms error
spa
jms error
lac statbuf+0 " flags
and o20
sna
jmp 2f
jmp 2f
sys open; scrname; 0
spa; jms error
spa
jms error
dac fd
jms readdir; scrname
lac ddfilp i
@@ -109,7 +116,7 @@ loop:
dzm fflg
law fbuf
dac i2
r1
-1
tad nfiles
cma
dac c2
@@ -118,19 +125,19 @@ loop:
lac c1
tad d501
sad i2 i
skp
skp
jmp 3f
-1
tad i1
dac i3
iac i3 i
lac i3 i
dac c3
law fbuf
dac i3
0:
lac i3 i
sad c3
jmp 0f
jmp 0f
isz i3
isz i3
jmp 0b
@@ -159,14 +166,15 @@ loop:
lac nlinkt
sad nlinka
skp
skp
jms fishy
dzm nlinka
law 012
jms putc
law statbuf
sys status; scrname; dd
spa; jms error
spa
jms error
-1
tad statbuf+9
cma
@@ -188,7 +196,7 @@ loop:
isz i2
lac i2
sad i1 i
skp
skp
jmp .+3
isz i1
isz i1
@@ -199,7 +207,7 @@ loop:
jmp 1b
lac nlinkt
sad nlinka
skp
skp
jms fishy
sys chdir; system
@@ -267,9 +275,10 @@ readdir: 0
jms copyz; buf; 64
lac fd
sys read; buf; 64
spa; jms error
spa
jms error
sna
jmp 4f
jmp 4f
-8
dac c1
law buf
@@ -277,7 +286,7 @@ readdir: 0
1:
lac i1 i
sna
jmp 3f
jmp 3f
isz nfiles
dac filp i
@@ -292,7 +301,8 @@ readdir: 0
dac .+4
law statbuf
sys status; 5:..; ..
spa; jms error
spa
jms error
jms longout
lac i1
tad d1
@@ -316,7 +326,7 @@ readdir: 0
isz fsopt
law fsobuf+64
sad fsopt
skp
skp
jmp 3f
lac fso
sys write; fsobuf; 64
@@ -365,7 +375,8 @@ octal: 0
lac octal i
dac c
1:
ecla llss 3
" ecla llss 3
llss 3
tad o60
jms putc
isz c
@@ -401,10 +412,10 @@ copyz: 0
done:
lac noc
sna
sys exit
sys exit
and d1
sna cla
jmp 1f
jmp 1f
jms putc
jmp done
1:

59
src/other/wktls.s Normal file
View File

@@ -0,0 +1,59 @@
" Warren's version of ls. Simply print out the names in the current directory
main:
sys open; curdir; 0 " Open up the currect directory
spa
sys exit " Unable, so die now
dac fd " Save the fd
fileloop:
" Read 64 words into the buffer from the input file
lac fd
sys read; buf; 64
spa " Skip if result was >= 0
jmp fileend " 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 count
lac ibufptr " Point bufptr at the base of the buffer
dac bufptr
" Each directory entry is eight words. We need to print out
" the filename which is in words 2 to 5.
printloop:
isz bufptr " Move up to the filename
lac d1
sys write; bufptr:0; 4 " Write a filename out to stdout
lac d1
sys write; newline; 1 " followed by a newline
lac bufptr " Add 7 to the bufptr
tad d7
dac bufptr
-8
tad count " Decrement the count of words by 8
dac count
sza " Anything left in the buffer to print?
jmp printloop " Yes, stuff left to print
jmp fileloop " Nothing in the buffer, try reading some more
fileend:
" Close the open file descriptor and exit
lac fd
sys close
sys exit
curdir: <. 040; 040040; 040040; 040040 " i.e. "."
newline: 012000
fd: 0
d1: 1 " stdout fd
d7: 7
count: 0
" Input buffer for read
ibufptr: buf " Constant pointer to the buffer
buf: .=.+64

View File

@@ -3,22 +3,22 @@
.. = 0
t = 0
orig:
hlt
jmp pibreak
hlt " overwritten with interrupt return addr
jmp pibreak " dispatch to interrupt processing
. = orig+7
-1
-1 " only ever set (to -1): never read?!
. = orig+020
1f
iof
dac u.ac
lac 020
dac 1f
. = orig+020 " syscall (CAL) processing
1f " addr for "CAL I": store return here on "CAL"
iof " interrupts off
dac u.ac " save user AC
lac 020 " save user return addr
dac 1f " save as if "CAL I"
lac 1f-1
dac 020
lac u.ac
jmp 1f+1
dac 020 " restore location 20
lac u.ac " restore user AC
jmp 1f+1 " join "CAL I" processing
1f
1: 0
iof " interrupts off
@@ -49,7 +49,7 @@ orig:
jmp .. i " dispatch system call
. = orig+0100
jmp coldentry
jmp coldentry " here to start kernel
jms halt
okexit:
@@ -64,9 +64,9 @@ sysexit: " common system call exit code
jms dskio; 07000 " save to disk?
1:
dzm .insys " clear "in system call" flag
jms chkint
skp
jmp .save " dump core??
jms chkint " pending interrupt?
skp " no
jmp .save " yes: dump core
jms copy; u.rq+2; 10; 6 " restore auto-index locations 10-15
lac u.rq+1 " restore auto-index location 9
dac 9
@@ -77,6 +77,7 @@ sysexit: " common system call exit code
lac u.ac " restore AC register
jmp u.rq+8 i " return to user
" scheduler / idle loop
swap: 0
ion
1:
@@ -84,49 +85,49 @@ swap: 0
jmp 1f
jms lookfor; 1 " in/ready
skp
jmp 1b
dzm maxquant
jmp 1b " loop until a process becomes ready
dzm maxquant " here with in/ready (self?)
jmp 3f
1:
dac 9f+t
jms lookfor; 2 " in/notready
1: " here with out/ready process
dac 9f+t " save process pointer (swapped out) in t0
jms lookfor; 2 " in/notready " find a swapped in process to swap out?
jmp 1f
jms lookfor; 1 " in/ready
jmp 1f
jmp 2f
1:
lac swap
dac u.swapret
dac u.swapret " return to scheduler when swapped back
iof
lac o200000
lac o200000 " change status to swapped out
tad u.ulistp i
dac u.ulistp i
ion
jms dskswap; 07000
jms dskswap; 07000 " swap process out
lac u.dspbuf
sna
jmp 2f
law dspbuf
jms movdsp
2:
iof
lac o600000
iof " disable interrupts
lac o600000 " change status (1->7?)
tad 9f+t i
dac 9f+t i
ion
jms dskswap; 06000
lac u.swapret
dac swap
lac o20
ion " enable interrupts
jms dskswap; 06000 " read process in?
lac u.swapret " set our return addr
dac swap " to saved return addr
lac o20 " reset maxquant to 16 ticks
dac maxquant
lac u.dspbuf
sza
sza " using display?
"** 01-s1.pdf page 4
jms movdsp
jms movdsp " yes.
3:
dzm uquant
dzm uquant " no. reset process tick count
iof
jmp swap i
jmp swap i " return
t = t+1
swp: " system call dispatch table
@@ -138,12 +139,18 @@ swp: " system call dispatch table
swn:
.-swp-1 i " count of system calls, plus indirect!
" AC/ new value for intflg (non-zero to ignore interrupt char)
" sys intrp
.intrp:
lac u.ac
dac u.intflg
jmp okexit
.sysloc: " "sysloc": syscall to return system addresses
" syscall to retrieve system addresses (data & routines!!)
" AC/ index (1..17)
" sys sysloc
" AC/ address (or -1 on bad index)
.sysloc:
lac u.ac
and o17777
jms betwen; d1; locn
@@ -154,7 +161,7 @@ swn:
dac u.ac
jmp sysexit
locsw: " table of system data structures for "sysloc" call
locsw: " table of system addresses for sysloc
lac .
iget; inode; userdata; sysdata; copy; copyz; betwen; dskrd
dskwr; dskbuf; dpdata; namei; pbsflgs; alloc; free; dspdata
@@ -162,34 +169,41 @@ locsw: " table of system data structures for "sysloc" call
locn:
.-locsw-1
" check if interrupt for user
" checks .int1 and .int2 (contain i-number of interrupt source)
" call:
" .insys/ 0
" jms chkint
" no: no interrupt, or intflg set (discards interupt)
" yes: PI off, .insys set
chkint: 0
lac .insys
sza
jmp chkint i
lac .int1
sna
jmp 1f
sad u.ofiles+2
jmp 2f
sza " in system?
jmp chkint i " yes: return
lac .int1 " get inumber of interrupt1 source?
sna " zero?
jmp 1f " yes: skip stdin check
sad u.ofiles+2 " non-zero: compare to stdin inumber
jmp 2f " same
1:
lac .int2
sna
jmp chkint i
sad u.ofiles+2
skp
jmp chkint i
dzm .int2
lac .int2 " get inum of interrupt 2 source?
sna " zero?
jmp chkint i " yes: return
sad u.ofiles+2 " non-zero: compare to stdin inumber
skp " match!
jmp chkint i " no match: return
dzm .int2 " clear int2 source
jmp 1f
2:
dzm .int1
dzm .int1 " clear int1 source
1:
"** 01-s1.pdf page 5
lac u.intflg
sza
jmp chkint i
lac u.intflg " get user intflg
sza " zero?
jmp chkint i " no: ignore
-1
dac .insys
ion
isz chkint
dac .insys " set "in system" flag
ion " enable interrupts
isz chkint " give skip return
jmp chkint i

View File

@@ -190,36 +190,39 @@
"** 01-s1.pdf page 10
jmp okexit
" open system call
" sys open; filename_ptr; flags (0 for read, 1 for write)
" returns w/ "fd" in AC (or -1 if not found)
.open:
jms arg
dac 0f
jms arg
sza
lac d1
sna
lac d2 " mode bit 2 (read?)
jms arg " get filename
dac 0f " save for namei
jms arg " get flags
sza " zero (read)
lac d1 " no: get write mode bit
sna " non-zero (write)?
lac d2 " no: get read mode bot
dac mode " save for access call
lac u.cdir
jms namei; 0:0
jms error
jms iget
jms access
lac i.flags
and o20
sna
jmp open1
lac mode
and d1
sna
jmp open1
lac u.uid
sma
jms error
jmp open1
lac u.cdir " get current working directory
jms namei; 0:0 " search for file
jms error " error: return -1
jms iget " load inode
jms access " check access (may return w/ error to user)
lac i.flags " get file flags
and o20 " get directory bit
sna " is directory?
jmp open1 " no, join common code
lac mode " get access mode
and d1 " get write bit
sna " write access?
jmp open1 " no, continue
lac u.uid " yes: get uid?
sma " negative? (-1 is superuser)
jms error " no: return error
jmp open1 " yes: join common code
.creat:
lac d1 " mode bit 1 (write?)
dac mode " save for access call
lac d1 " mode bit 1 (write)
dac mode " save for access call
jms arg
dac .+2
jms copy; ..; name; 4
@@ -241,12 +244,12 @@
jmp open1
1:
jms access
lac u.ac
and o17
lac u.ac " get access bits from user AC (zero for lock!)
and o17 " mask to permissions
jms icreat
open1:
jms fassign
jms error
open1: " common exit for open/creat
jms fassign " assign fd slot
jms error " none free, return -1
jmp sysexit
"** 01-s1.pdf page 11
@@ -275,63 +278,67 @@ open1:
and d1
sza
jms error
lac i.flags
and o40
sna
jmp 1f
iof
lac ii
tad swr
lac i.flags " get inode flags
and o40 " get special file bit
sna " special?
jmp 1f " no
iof " yes: disable interrupts
lac ii " get i number
tad swr " get read routine table addr
dac .+1
jmp .. i
jmp .. i " dispatch to read routine
1:
lac u.base
dac 1f+1
lac u.count
dac 1f+2
lac f.badd
lac u.base " get user base
dac 1f+1 " save as iread base
lac u.count " get user count
dac 1f+2 " save as iread count
lac f.badd " get file offset
1:
jms iread; ..; ..
jmp exitrw
" write system call:
" AC/ fd
" sys write; buffer; count
" AC/ count or -1 on error
.write:
jms arg
and o17777
dac u.base
jms arg
dac u.count
tad u.base
jms betwen; u.base; o17777
jms error
dac u.limit
jms finac
lac f.flags
and d1
sna
jms error
lac i.flags
and o40
jms arg " pick up buffer
and o17777 " mask to addr
dac u.base " save as I/O base
jms arg " pick up count
dac u.count " save as count
tad u.base " add base (get limit)
jms betwen; u.base; o17777 " check between base and end of memory
jms error " no: error
dac u.limit " yes: save as limit
jms finac " get fnode with fd from user AC
lac f.flags " get open file table flags
and d1 " open for write?
sna " yes, skip
jms error " no: error
lac i.flags " get inode flags
and o40 " get special bit?
"** 01-s1.pdf page 12
sna
jmp 1f
iof
lac ii
tad sww
sna " special?
jmp 1f " no
iof " special file (device node)
lac ii " get i number
tad sww " get write routine
dac .+1
jmp .. i
jmp .. i " dispatch to write routine
1: " here with regular file
lac u.base " get base
dac 1f+1 " save as iwrite arg 1
lac u.count " get count
dac 1f+2 " save as iwrite 2
lac f.badd " get fd offset
1:
lac u.base
dac 1f+1
lac u.count
dac 1f+2
lac f.badd
1:
jms iwrite; ..; ..
jms iwrite; ..; .. " write to file
exitrw:
dac u.ac
exitrw: " common exit for read/write system calls
dac u.ac " save return in user AC
tad f.badd
dac f.badd
jms iput
jms fput
jmp sysexit
dac f.badd " update file offset
jms iput " release inode
jms fput " release fnode
jmp sysexit " return to user

View File

@@ -1,15 +1,21 @@
"** 01-s1.pdf page 14
" s3
" search for user (process)
" call:
" jms searchu; worker_routine_addr
" worker called with copy of a process table entry in "lu"
" can return directly (from caller of searchu)
" index location 8 points to next process table entry
searchu: 0
lac searchu i
dac 9f+t+1
-mnproc
dac 9f+t
law ulist-1
dac 8
lac searchu i " fetch argument
dac 9f+t+1 " in t1
-mnproc " loop counter
dac 9f+t " in t0
law ulist-1 " ulist ptr
dac 8 " in index 8
1:
lac 8 i
lac 8 i " copy ulist entry to lu
dac lu
lac 8 i
dac lu+1
@@ -17,86 +23,96 @@ searchu: 0
dac lu+2
lac 8 i
dac lu+3
jms 9f+t+1 i
isz 9f+t
jmp 1b
isz searchu
jms 9f+t+1 i " call argument as subroutine
isz 9f+t " returned: loop done?
jmp 1b " no, do it again
isz searchu " skip argument
jmp searchu i
t = t+2
" look for a process with matching status
" jms lookfor; status
" found: ulist ptr in AC
" not found
lookfor: 0
jms searchu; 1f
isz lookfor
isz lookfor
isz lookfor " skip argument
isz lookfor " give skip return
jmp lookfor i
1: 0
1: 0 " worker called by searchu
lac lu
rtl; rtl; and o7
sad lookfor i
skp
jmp 1b i
rtl; rtl; and o7 " bits 0:2 of lu
sad lookfor i " match argument?
skp " yes
jmp 1b i " no, return, keep going
-3
tad 8
tad 8 " roll index 8 back to this entry
and o17777
isz lookfor
jmp lookfor i
isz lookfor " skip lookfor argument
jmp lookfor i " non-skip return
" fork system call:
" sys fork
" return at +1 in parent, child pid in AC
" return at +2 in child, parent pid in AC
.fork:
jms lookfor; 0 " not-used
jms lookfor; 0 " not-used " find an unused process slot
skp
jms error
dac 9f+t
isz uniqpid
jms error " none found- return error
dac 9f+t " save ulist ptr in t0
isz uniqpid " generate new pid
lac uniqpid
dac u.ac
dac u.ac " return in child pid in AC
law sysexit
dac u.swapret
lac o200000
dac u.swapret " return from system call when swapped back in
lac o200000 " change process status to out/ready (1->3)
tad u.ulistp i
dac u.ulistp i
jms dskswap; 07000
lac 9f+t
dac u.ulistp
lac o100000
jms dskswap; 07000 " swap parent out
lac 9f+t " get unused ulist slot back
dac u.ulistp " set ulist pointer
lac o100000 " mark child in/notready? (3->2)
xor u.ulistp i
dac u.ulistp i
lac u.pid
lac u.pid " get old (parent) pid
"** 01-s1.pdf page 15
dac u.ac
dac u.ac " return parent pid in AC
lac uniqpid
dac u.pid
isz 9f+t
dac 9f+t i
isz u.rq+8
dzm u.intflg
jmp sysexit
dac u.pid " set child pid
isz 9f+t " advance to second word in process table
dac 9f+t i " set pid in process table
isz u.rq+8 " give skip return
dzm u.intflg " clear int flag
jmp sysexit " return in child process
t= t+1
badcal:
clon
badcal: " bad (unimplemented) system call
clon " clear any pending clock interrupt?
-1
dac 7
.save:
lac d1
dac 7 " set location 7 to -1?!
" fall into "save" system call
" Ken says save files could be resumed, and used for checkpointing!
.save: " "sys save" system call
lac d1 " get inode 1 (core file?)
jms iget
cla
jms iwrite; 4096; 4096
jms iwrite; userdata; 64
jms iwrite; 4096; 4096 " dump core
jms iwrite; userdata; 64 " and user area
jms iput
.exit:
lac u.dspbuf
sna
jmp .+3
law dspbuf
jms movdsp
sna " process using display?
jmp .+3 " no
law dspbuf " yes
jms movdsp " move display
jms awake
lac u.ulistp i
and o77777
and o77777 " mark process table entry free
dac u.ulistp i
isz u.ulistp
dzm u.ulistp i
jms swap
dzm u.ulistp i " clear pid in process table
jms swap " find a new process to run
.rmes:
jms awake
@@ -124,25 +140,28 @@ badcal:
t = t+1
"** 01-s1.pdf page 16
" smes system call
" AC/ pid
" sys smes
.smes:
lac u.ac
sna spa
jms error
jms searchu; 1f
lac u.ac " get pid from user AC
sna spa " >0?
jms error " no: error
jms searchu; 1f " search for process
law 2
tad u.ulistp
dac 9f+t
dzm 9f+t i
jms error
1: 0
lac lu+1
sad u.ac
skp
jmp 1b i
lac lu+2
sad dm1
jmp 1f
lac o100000
1: 0 " worker for searchu
lac lu+1 " get pid
sad u.ac " match?
skp " yes
jmp 1b i " no
lac lu+2 " get mailbox
sad dm1 " -1?
jmp 1f " yes
lac o100000 " no: increment process status
tad u.ulistp i
dac u.ulistp i
law 2
@@ -177,19 +196,19 @@ t = t+1
awake: 0
jms searchu; 1f
jmp awake i
1: 0
lac u.pid
sad lu+2
skp
jmp 1b i
1: 0 " searchu worker
lac u.pid " get caller pid
sad lu+2 " match process table entry?
skp " yes
jmp 1b i " no, return
-3
tad 8
dac 9f+t
tad 8 " get pointer to pid in process table??
dac 9f+t " save in t0
"** 01-s1.pdf page 17
lac o700000
lac o700000 " set high bits
tad 9f+t i
dac 9f+t i
jmp 1b i
jmp 1b i " return from worker
t = t+1
swr:
@@ -200,15 +219,16 @@ sww:
.halt: jms halt
" read routine for ttyin special file
rttyi:
jms chkint1
lac d1
jms getchar
jmp 1f
and o177
jms betwen; o101; o132
skp
tad o40
jms betwen; o101; o132 " upper case?
skp " no
tad o40 " yes: convert to lower
alss 9
jmp passone
1:
@@ -216,6 +236,7 @@ rttyi:
jms swap
jmp rttyi
" write routine for ttyout special file
wttyo:
jms chkint1
jms forall
@@ -243,6 +264,7 @@ wttyo:
jms swap
jmp wttyo
" read routine for (display) "keyboard" special file
rkbdi:
jms chkint1
lac d3
@@ -282,6 +304,7 @@ rkbdi:
jms swap
jmp rkbdi
" write routine for (graphic) "display" special file
wdspo:
jms chkint1
jms forall
@@ -292,6 +315,7 @@ wdspo:
jmp wdspo
" read routine for paper tape reader special file
rppti:
lac d4
jms getchar
@@ -307,6 +331,7 @@ rppti:
jmp rppti
"** 01-s1.pdf page 19
" write routine for paper tape punch special file
wppto:
jms forall
sna
@@ -331,6 +356,7 @@ wppto:
jms swap
jmp wppto
" common exit for special file
passone:
sad o4000
jmp okexit

View File

@@ -1,7 +1,7 @@
"** 01-s1.pdf page 21
" s4
" allocate a free disk block
" allocate a free disk block for a file (data or indirect)
alloc: 0
-1
tad s.nfblks
@@ -92,11 +92,14 @@ betwen: 0
cma " complement (AC-high)
spa sna " AC-high <= 0?
1:
isz betwen " no: give happy return
isz betwen " no: give happy (skip) return
lacq " restore ~AC
cma " restore AC
jmp betwen i " return w/o skip
" copy memory
" call:
" jms copy; src; dest; count
copy: 0
-1
tad copy i
@@ -118,21 +121,24 @@ copy: 0
jmp 1b
jmp copy i
" copy zeroes (clear memory)
" call:
" jms copyz; pointer; count
copyz: 0
-1
tad copyz i
dac 8
isz copyz
tad copyz i " get call PC
dac 8 " save in index (pre-increments)
isz copyz " skip pointer
-1
tad copyz i
cma
dac 9f+t
isz copyz
tad copyz i " get count-1
cma " get negative count
dac 9f+t " save in t0
isz copyz " skip count
1:
dzm 8 i
isz 9f+t
jmp 1b
jmp copyz i
dzm 8 i " zero word
isz 9f+t " done?
jmp 1b " no: loop
jmp copyz i " return
t = t+1
putchar: 0
@@ -281,6 +287,8 @@ dskrd: 0
jms collapse
jmp dskrd i
" write a file block (data, inode or indirect)
" AC/ block
dskwr: 0
jms betwen; d2; d7999
jms halt
@@ -292,7 +300,6 @@ dskwr: 0
jmp dskwr i
t = t+3
" called with:
" AC/ block
" jms dskio; dsld_bits
dskio: 0
@@ -354,11 +361,11 @@ dsktrans: 0
t = t+1
halt: 0
isz 9f+t
isz 9f+t " spin for a while (process interrupts)
jmp .-1
iof
hlt
jms copy; law; 4096; 4096
hlt; jmp .-1
iof " disable interrupts
hlt " halt
jms copy; law; 4096; 4096 " continued: copy system up to user memory?
hlt; jmp .-1 " halt for good
t = t+1

View File

@@ -1,75 +1,86 @@
"** 01-s1.pdf page 28
" s5
" read/write a process from/to swap space
" call:
" AC/ first word of process table
" jms dskswap; DSLD bits
dskswap: 0
cll; als 3
dac 9f+t
jms dsktrans; -64; userdata; 9f+t; dskswap
lac 9f+t
tad o20
dac 9f+t
jms dsktrans; -4096; 4096; 9f+t; dskswap
isz dskswap
jmp dskswap i
cll; als 3 " get process disk address
dac 9f+t " save in t0
jms dsktrans; -64; userdata; 9f+t; dskswap " read/write user area
lac 9f+t " get swap addr back
tad o20 " advance by 16??
dac 9f+t " save
jms dsktrans; -4096; 4096; 9f+t; dskswap " read/write user memory
isz dskswap " skip bits
jmp dskswap i " return
t = t+1
access: 0
lac i.flags
lmq
lac u.uid
spa
jmp access i
sad i.uid
lrs 2
lacq
and mode " mode from system call
sza
jmp access i
jms error
lmq " save in MQ
lac u.uid " get user id
spa " negative?
jmp access i " yes: super user, return
sad i.uid " compare to file owner
lrs 2 " same: shift flags down two
lacq " get flags back
and mode " mode from system call
sza " access allowed?
jmp access i " yes: return
jms error " no: return error from system call
fassign: 0
-10
dac 9f+t
-10 " loop count
dac 9f+t " in t0
1:
lac 9f+t
tad d10
jms fget
lac 9f+t " get count
tad d10 " turn into fd
jms fget " fetch open file into "fnode"
jms halt " will not happen
lac f.flags
sma
jmp 1f
isz 9f+t
lac f.flags " get fnode flags
sma " sign bit set (active)?
jmp 1f " no: free
isz 9f+t " increment loop count & loop until zero
jmp 1b
jmp fassign i
1:
lac mode
xor o400000
dac f.flags
lac ii
dac f.i
lac mode " get mode from system call
xor o400000 " set sign bit
dac f.flags " save in fnode
lac ii " get i-number
dac f.i " save in fnode
lac 9f+t
tad d10
dac u.ac
dzm f.badd
jms fput
isz fassign
tad d10 " get fd
dac u.ac " return in user AC
dzm f.badd " clear file offset in fnode
jms fput " copy fnode back into u.ofiles
isz fassign " give skip return
jmp fassign i
t = t+1
" load fnode (open file entry) from u.ofiles
" AC/ user fd
" jms fget
" bad fd
" return with fnode set
fget: 0
jms betwen; d0; d9
jmp fget i
cll; mul; 3
jms betwen; d0; d9 " fd 0..9?
jmp fget i " no, return
cll; mul; 3 " multiply by three
lacq
"** 01-s1.pdf page 29
tad ofilesp
dac 9f+t
dac .+2
jms copy; ..; fnode; 3
isz fget
tad ofilesp " get pointer into u.ofiles
dac 9f+t " save in t0
dac .+2 " save as copy source
jms copy; ..; fnode; 3 " copy to "fnode"
isz fget " give skip return
jmp fget i
" copy fnode back to u.ofiles
" uses temp value set by "fget"
" (fget and fput calls must be paired)
fput: 0
lac 9f+t
dac .+3

View File

@@ -255,34 +255,37 @@ pget: 0
t = t+3
iwrite: 0
dac 9f+t
lac iwrite
dac 9f+t " save arg in t0
lac iwrite " load return address
"** 01-s1.pdf page 38
dac iread
lac cskp
dac iwrite
dac iread " save as iread return addr
lac cskp " load skip instruction
dac iwrite " save as iwrite instruction
jmp 1f
" iread from file referenced by loaded inode
" AC/ file offset
" jms iread; addr; count
iread: 0
dac 9f+t
lac cnop
dac iwrite
dac 9f+t " save offset in t0
lac cnop " get nop
dac iwrite " save as iwrite instruction
1:
-1
tad iread i
dac 10
tad iread i " get word before return addr
dac 10 " store in index 10 & 11
dac 11
isz iread
lac iread i
dac 9f+t+1
isz iread
isz iread " increment return addr
lac iread i " load addr
dac 9f+t+1 " save in t1
isz iread " increment return addr
lac o70000
xct iwrite
lac i.size
xct iwrite " skip if write
lac i.size " read: get file size
cma
tad 9f+t
tad 9f+t " add offset
cma
jms betwen; d0; 9f+t+1
lac 9f+t+1
@@ -336,6 +339,11 @@ cskp:
jmp 1b
t = t+4
" system call helper
" AC/ fd
" jms finac
" return with: fnode and inode loaded
" or makes error return to user
finac: 0
lac u.ac
jms fget
@@ -347,6 +355,7 @@ finac: 0
jms iget
jmp finac i
" update inode file size with value in AC
dacisize: 0
dac i.size
jms iput

View File

@@ -1,8 +1,9 @@
"** 01-s1.pdf page 41
" s7
pibreak: " priority interrupt processing "chain"
dac .ac "** CROSSED OUT....
pibreak: " priority interrupt break processing "chain"
dac .ac " save interrupt AC
"** CROSSED OUT....
dpsf
jmp 1f
@@ -36,11 +37,13 @@ pibreak: " priority interrupt processing "chain"
isz uquant " increment user quantum counter
"** written: ttydelay -> ttyd1
"** written: ttyrestart -> ttyres1
" referenced in iread:
cnop:
nop
-1
dac 7
clon
dac 7 " set location 7 to -1
clon " enable clock interrupts, reset flag
lac ttydelay
spa
isz ttydelay
@@ -103,16 +106,16 @@ dsprestart:
rlpd
jmp piret
1: ksf
jmp 1f
1: ksf " (TTY) keyboard flag set?
jmp 1f " no
lac ttydelay
sma
isz ttydelay
krb
dac char
sad o375
jmp intrp1
krb " read keyboard buffer
dac char " save in char
sad o375 " interrupt char ('}'?)
jmp intrp1 " yes
lac d1
jms putchar
dzm char
@@ -172,14 +175,15 @@ ttyrestart: 0
dac sfiles+1
jmp ttyrestart i "** written arrow up 2 copies
1: sck "** BEGIN CROSSED OUT
jmp 1f
"** BEGIN CROSSED OUT
1: sck " Graphic-2 keyboard flag set?
jmp 1f " no.
cck
lck
cck " yes: clear flag
lck " read character
dac char
sad o33
jmp intrp2
sad o33 " code 33 (ESCAPE?)
jmp intrp2 " yes: mark interrupt
lac d3
jms putchar
nop
@@ -188,8 +192,8 @@ ttyrestart: 0
dac sfiles+2
jmp piret
1: rsf
jmp 1f
1: rsf " paper tape ready?
jmp 1f " no
"** 01-s1.pdf page 44
@@ -235,12 +239,12 @@ ttyrestart: 0
dac sfiles+3
jmp piret
1: psf
jmp 1f
1: psf " paper tape ready?
jmp 1f " no
pcf
pcf " clear ptp flag
lac d5
jms getchar
jms getchar " get next char
jmp .+3
psa
jmp piret
@@ -249,11 +253,12 @@ ttyrestart: 0
dac sfiles+4
jmp piret
1: spb "** BEGIN CROSSED OUT
jmp 1f
"** BEGIN CROSSED OUT
1: spb " graphic 2 push button flag set?
jmp 1f " no
cpb
lpb
cpb " clear push button flag
lpb " load push button value
dac pbsflgs+1
"** 01-s1.pdf page 45
@@ -269,8 +274,8 @@ ttyrestart: 0
wbl
jmp piret "** END CROSSED OUT
1: crsf
jmp 1f
1: crsf " card reader flag set?
jmp 1f " no
crrb
dac crchar
@@ -278,14 +283,14 @@ ttyrestart: 0
dac crread
jmp piret
1: crrb
1: crrb " read card reader buffer??
piret:
lac 0
ral
lac .ac
ion
jmp 0 i
piret: " return from priority interrupt
lac 0 " get LINK/PC
ral " restore LINK
lac .ac " restore AC
ion " reenable interrupts
jmp 0 i " return from interrupt
wakeup: 0
dac 9f+t
@@ -325,9 +330,9 @@ putcr: 0
cla
jmp putcr i
intrp1:
lac d6
dac .int1
intrp1: " here with keyboard interrupt
lac d6 " get keyboard special device number
dac .int1 " save as interrupt source
lac d1
jms getchar
skp

View File

@@ -8,14 +8,15 @@ dspbsz = 270
ndskbs = 4
" flags
.insys: 0
.int1: 0
.int2: 0
.ac: 0
.savblk: 0
.dsptm: 0
.dskb: 0
.dske: 0
" interupt flags
.insys: 0 " "in system"
.int1: 0 " inode for interrupt 1
.int2: 0 " inode for interrupt 2
.ac: 0 " saved AC from interrupt
.savblk: 0 " set by system call, cleared by disk i/o
.dsptm: 0 " display restart countdown (10 ticks)
.dskb: 0 " set on disk interrupt
.dske: 0 " status from disk interrupt
" pointers
tadu: tad ulist
@@ -110,25 +111,25 @@ dspbuf:
.=.+30
coldentry:
dzm 0100 " not re-entrant
caf
ion
clon
law 3072
caf " clear all flags
ion " enable interrupts
clon " clear clock flag
law 3072 " initialize display....
wcga
jms dspinit
law dspbuf
jms movdsp
cla
cla " read system block from disk
jms dskio; 06000
jms copy; dskbuf; sysdata; ulist-sysdata
lac d3
jms copy; dskbuf; sysdata; ulist-sysdata " copy to system data
lac d3 " look for "init" in default directory
jms namei; initf
jms halt
"** 01-s1.pdf page 50
jms iget
cla
jms iread; 4096; 4096
jmp 4096
jms iread; 4096; 4096 " read in "init"
jmp 4096 " start process 1
. = dspbuf+dspbsz+3
dskbuf = 07700
dskbs: .=.+65+65+65+65
@@ -144,9 +145,9 @@ name: .=.+4
lnkaddr: .=.+1
char: .=.+1
dskaddr: .=.+1
uniqpid: 1
lu: .=.+4
sfiles: .=.+10
uniqpid: 1 " pid generator
lu: .=.+4 " user (process) table entry copy
sfiles: .=.+10 " wait addresses for special files
dpdata:
dpstat: .=.+1
dpread: .=.+1
@@ -158,12 +159,24 @@ dspdata:
crdata:
crread: .=.+1
crchar: .=.+1
sysdata:
s.nxfblk: .=.+1
s.nfblks: .=.+1 " number of free blocks
s.fblks: .=.+10 " free block numbers
s.uniq: .=.+1 " next unique value
s.tim: .=.+2 " (up)time(?) in 60Hz ticks (low, high)
sysdata: " system data 64 words saved to disk
s.nxfblk: .=.+1 " pointer to next free block??
s.nfblks: .=.+1 " number of free blocks (in fblks?)
s.fblks: .=.+10 " cached free block numbers
s.uniq: .=.+1 " next unique value
s.tim: .=.+2 " (up?)time in 60Hz ticks (low, high)
" process table
" first word
" bits 0:2 -- status
" 0: free slot
" 1: in/ready
" 2: in/notready
" 3: out/ready
" 4: out/notready??
" bits 3:17 -- disk swap address/8
" second word: process pid
" third word: used for smes/rmes
" fourth word: ??
ulist:
0131000;1;0;0
0031040;0;0;0
@@ -175,31 +188,34 @@ ulist:
0031340;0;0;0
0031400;0;0;0
0031440;0;0;0
userdata:
userdata: " "ustruct" (swappable)
u.ac: 0 " user AC
u.mq: 0 " user MQ
u.rq: .=.+9 " user 010-017
u.rq: .=.+9 " user 010-017, user PC
u.uid: -1 " user id
u.pid: 1 " process id
u.cdir: 3 " connected directory (inode number?)
u.ulistp: ulist
u.swapret: 0
u.base: 0
u.count: 0
u.ulistp: ulist " pointer to process table entry
u.swapret: 0 " kernel routine to resume at after swap in
u.base: 0 " start of user buffer
u.count: 0 " size of user buffer
"** 01-s1.pdf page 51
u.limit: 0
u.ofiles: .=.+30
u.limit: 0 " end of user buffer
u.ofiles: .=.+30 " open files (10 "fnode" entries)
u.dspbuf: 0
u.intflg: 1
.=userdata+64
ii: .=.+1
inode:
ii: .=.+1 " number of i-node in inode:
inode: " disk inode in memory:
i.flags: .=.+1 " inode flags
" 400000 free?? (checked/toggled by icreat)
" 200000 large file
" 000040 special? (checked by read/write)
" 000040 special device (indicated by inum)?
" 000020 directory
" 000017 can be changed by chmod.
" 000010 owner read
" 000004 owner write
" 000002 world read
" 000001 world write
i.dskps: .=.+7 " disk block pointers (indirect if "large file")
i.uid: .=.+1 " owner
i.nlks: .=.+1 " link count
@@ -212,8 +228,11 @@ dnode: " directory entry:
d.name: .=.+4 " name (space padded)
d.uniq: .=.+1 " unique number from directory inode
. = dnode+8
fnode:
f.flags: .=.+1
f.badd: .=.+1
f.i: 0
fnode: " open file entry
f.flags: .=.+1 " see below
f.badd: .=.+1 " offset
f.i: 0 " file i-number
" f.flags:
" 400000 in use
" 000002 read
" 000001 write

View File

@@ -485,15 +485,25 @@ sub eae {
$PC++;
return;
}
if ( $maskedinstr == 0660700 ) { # alss: long left shift, signed
# We don't fill the lsb with LINK yet
if ( $maskedinstr == 0660700 ) { # alss: AC left shift, signed
dprintf( "alss AC %06o step %d\n", $AC, $step );
$AC = ( $AC << $step ) & MAXINT;
$LINK = ( $AC << 1 ) & LINKMASK;
$PC++;
return;
}
if ( $maskedinstr == 0640700 ) { # als: long left shift
dprintf( "alss AC %06o step %d\n", $AC, $step );
if ( $maskedinstr == 0660600 ) { # llss: long left shift, signed
dprintf( "llss AC %06o step %d\n", $AC, $step );
foreach my $i (1 .. $step) {
my $MQmsb= ($MQ & SIGN) ? 1 : 0;
$AC= (($AC << 1) | $MQmsb) & MAXINT;
$MQ= (($MQ << 1) | (($LINK) ? 1 : 0)) & MAXINT;
}
$PC++;
return;
}
if ( $maskedinstr == 0640700 ) { # als: AC left shift
dprintf( "als AC %06o step %d\n", $AC, $step );
$AC = ( $AC << $step ) & MAXINT;
$PC++;
return;
@@ -551,7 +561,7 @@ sub cal {
# 22 badcal
# 23 capt
# 24 rele
# 25 status
25 => \&sys_status,
# 26 badcal
27 => \&sys_smes,
28 => \&sys_rmes,
@@ -653,12 +663,55 @@ sub sys_close {
return;
}
# Open something which could be a file or a directory
# Convert directories into files. Return the file handle.
sub opensomething {
my ($readorwrite, $filename )= @_;
my $tempfile= "/tmp/a7out.$$";
my $FH;
# If this is not a directory, simply open and return the FH
if (! -d $filename) {
open( $FH, $readorwrite, $filename ) || return(undef);
return($FH);
}
# It's a directory. The on-disk format for this was:
# d.i: .=.+1 " inode number
# d.name: .=.+4 " name (space padded)
# d.uniq: .=.+1 " unique number from directory inode
# followed by two unused words
# The code creates a temporary file and fills in the i-node numbers
# and space padded filenames from the directory. The file is closed
# opened read-only and unlinked, and the open filehandle is returned.
opendir(my $dh, $filename) || return(undef);
open( $FH, ">", $tempfile) || return(undef);
dprintf("Converting directory $filename\n");
my @list= sort(readdir($dh));
foreach my $name (@list) {
# Get the file's i-node number
my (undef,$inode)= stat($name);
# ARGH! For now we are still read/writing ASCII files, so there's
# no way to represent a proper 18-bit value. For now I'll pad
# with spaces to create the record
printf( $FH " %-8s ", substr( $name, 0, 8 ) );
}
closedir($dh);
close($FH);
open( $FH, "<", $tempfile) || return(undef);
unlink($tempfile);
return($FH);
}
# Common code for creat and open
sub creatopen {
my ($filename, $readorwrite)= @_;
# Open the file
if ( open( my $FH, $readorwrite, $filename ) ) {
my $FH= opensomething($readorwrite, $filename );
if ( $FH ) {
# Find a place in the @FD array to store this filehandle.
# 99 is arbitrary
@@ -914,6 +967,61 @@ sub sys_time {
return;
}
# Status system call
sub sys_status {
# This seems to called as follows:
# law statbuf
# sys status; scrname; dd
# but I can't tell if PC+1 or PC+2 holds the filename pointer.
# For now, I'll use PC+1. $AC seems to hold the pointer to the statbuf
# which, as far as we can tell is:
# word 0: permission bits
# words 1-7: disk block pointers
# word 8: user-id
# word 9: number of links
# word 10: size in words
# word 11: uniq, I have no idea what this is.
# The permission bits are:
# 200000 large file, bigger than 4096 words
# 000020 directory
# 000010 owner read
# 000004 owner write
# 000002 user write
# 000001 user write
# Get the start address of the string
# Convert this to a sensible ASCII filename
my $start = $Mem[ $PC + 1 ];
my $filename = mem2arg($start);
dprintf( "status file %s statbuf %06o\n", $filename, $AC );
# Get the file's details
my (undef,undef,$mode,$nlink,$uid,undef,undef,$size)= stat($filename);
# Set up the statbuf if we got a result
if ($nlink) {
$Mem[ $AC+8 ]= $uid & MAXINT;
$Mem[ $AC+9 ]= $nlink & MAXINT;
$Mem[ $AC+10 ]= $size & MAXINT; # Yes, I know, not words
my $perms=0;
$perms= 01 if ($mode & 02); # World writable
$perms|= 02 if ($mode & 04); # World readable
$perms|= 04 if ($mode & 0200); # Owner writable
$perms|= 010 if ($mode & 0400); # Owner readable
$perms|= 020 if ( -d $filename); # Directory
$perms|= 0200000 if ($size > 4096); # Large file
$Mem[ $AC ] = $perms;
# Set AC to zero as we got something, else return -1
$AC= 0;
} else {
$AC= MAXINT;
}
$PC += 3;
return;
}
# Convert an 18-bit word into two ASCII characters and return them.
# Don't return NUL characters
sub word2ascii {