Research V1 development origin/Research-V1-Snapshot-Development
authorKen Thompson <ken@research.uucp>
Tue, 20 Jun 1972 10:00:00 +0000 (05:00 -0500)
committerKen Thompson <ken@research.uucp>
Tue, 20 Jun 1972 10:00:00 +0000 (05:00 -0500)
Work on file u4.s
Work on file init.s
Work on file u2.s
Work on file u3.s
Work on file u7.s
Work on file ux.s
Work on file u8.s
Work on file sh.s
Work on file u5.s
Work on file u1.s
Work on file u6.s
Work on file u0.s
Work on file u9.s

Co-Authored-By: Dennis Ritchie <dmr@research.uucp>
Synthesized-from: v1/sys

13 files changed:
init.s [new file with mode: 0644]
sh.s [new file with mode: 0644]
u0.s [new file with mode: 0644]
u1.s [new file with mode: 0644]
u2.s [new file with mode: 0644]
u3.s [new file with mode: 0644]
u4.s [new file with mode: 0644]
u5.s [new file with mode: 0644]
u6.s [new file with mode: 0644]
u7.s [new file with mode: 0644]
u8.s [new file with mode: 0644]
u9.s [new file with mode: 0644]
ux.s [new file with mode: 0644]

diff --git a/init.s b/init.s
new file mode 100644 (file)
index 0000000..5f39d9b
--- /dev/null
+++ b/init.s
@@ -0,0 +1,169 @@
+/ init -- process control initialization
+
+mount = 21.
+
+       sys     intr; 0 / turn off interrupts
+       sys     quit; 0
+       cmp     csw,$73700 / single user?
+       bne     1f / no
+help:
+       clr     r0 / yes
+       sys     close / close current read
+       mov     $1,r0 / and write
+       sys     close / files
+       sys     open; ctty; 0 / open control tty
+       sys     open; ctty; 1 / for read and write
+       sys     exec; shell; shellp / execute shell
+       br      help / keep trying
+1:
+       mov     $'0,r1 / prepare to change
+1 :
+       movb    r1,tapx+8 / mode of dec tape drive x, where
+       sys     chmod; tapx; 17 / x=0 to 7, to read/write by owner or
+       inc     r1 / non-owner mode
+       cmp     r1,$'8 / finished?
+       blo     1b / no
+       sys     mount; rk0; usr / yes, root file on mounted rko5
+                               / disk ls /usr
+       sys     creat; utmp; 16 / truncate /tmp/utmp
+       sys     close / close it
+       movb    $'x,zero+8. / put identifier in output buffer
+       jsr     pc,wtmprec / go to write accting info
+       mov     $itab,r1 / address of table to r1
+
+/ create shell processes
+
+1:
+       mov     (r1)+,r0 / 'x, x=0, 1... to r0
+       beq     1f / branch if table end
+       movb    r0,ttyx+8 / put symbol in ttyx
+       jsr     pc,dfork / go to make new init for this ttyx
+       mov     r0,(r1)+ / save child id in word offer '0, '1,...etc.
+       br      1b / set up next child
+
+/ wait for process to die
+
+1:
+       sys     wait / wait for user to terminate process
+       mov     $itab,r1 / initialize for search
+
+/ search for process id
+
+2:
+       tst     (r1)+ / bump r1 to child id location
+       beq     1b / ? something silly
+       cmp     r0,(r1)+ / which process has terminated
+       bne     2b / not this one
+
+/ take name out of utmp
+
+       sub     $4, r1 / process is found, point x' to 'x
+                      / for it
+       mov     r1,-(sp) / save address on stack
+       mov     (r1),r1 / move 'x to r1
+       sub     $'0,r1 / remove zone bits from character
+       asl     r1 / generate proper
+       asl     r1 / offset
+       asl     r1 / for
+       asl     r1 / seek
+       mov     r1,0f / move it to offset loc for seek
+       mov     $zero,r1
+2:
+       clr     (r1)+ / ccear-
+       cmp     r1,$zero+16. / output buffer
+       blo     2b / area
+       sys     open; utmp; 1 / open file for writing
+       bes     2f / if can't open, create user anyway
+       mov     r0,r1 / save file desc
+       sys     seek; 0:..; 0 / move to proper pointer position
+       mov     r1,r0 / not required
+       sys     write; zero; 16. / zero this position in
+       mov     r1,r0 / restore file descriptor
+       sys     close / close file
+
+/ re-create user process
+
+2:
+       mov     (sp)+,r1 / restore 'x to r1
+       mov     (r1)+,r0 / move it to r0
+       movb    r0,ttyx+8 / get correct ttyx
+       movb    r0,zero+8 / move identifier to output buffer
+       jsr     pc,wtmprec / go to write accting into
+       jsr     pc,dfork / fork
+       mov     r0,(r1)+ / save id of child
+       br      1b / go to wait for next process end
+
+dfork:
+       mov     r1,r2
+       sub     $itab+2,r2 / left over
+       asl     r2 / from previous
+       asl     r2 / version of code
+       mov     r2,offset
+       sys     fork
+               br 1f / to new copy of init
+       bes     dfork / try again
+       rts     pc / return
+1 :
+       sys     quit; 0 / new init turns off
+       sys     intr; 0 / interrupts
+       sys     chown; ttyx; 0 / change owner to super user
+       sys     chmod; ttyx; 15 / changemode to read/write owner,
+                               / write non-owner
+       sys     open; ttyx; 0 / open this ttyx for reading
+                             / and wait until someone calls
+       bes     help1 / branch if trouble
+       sys     open; ttyx; 1 / open this ttyx for writing after
+                             / user call
+       bes     help1 / branch if trouble
+       sys     exec; getty; gettyp / getty types <login> and
+                                   / executes login which logs user
+                                   / in and executes sh-
+       sys     exit / HELP!
+
+help1:
+       jmp     help / trouble
+
+wtmprec:
+       sys     time / get time
+       mov     ac,zero+10. / more to output
+       mov     mq,zero+12. / buffer
+       sys     open; wtmp; 1 / open accounting file
+       bes     2f
+       mov     r0,r2 / save file descriptor
+       sys     seek; 0; 2 / move pointer to end of file
+       mov     r2,r0 / not required
+       sys     write; zero; 16. / write accting info
+       mov     r2,r0 / restore file descriptor
+       sys     close / close file
+2:
+       rts     pc
+
+ctty:  </dev/tty\0>
+shell: </bin/sh\0>
+shellm:        <-\0>
+tapx:  </dev/tapx\0>
+rk0:   </dev/rk0\0>
+utmp:  </tmp/utmp\0>
+wtmp:  </tmp/wtmp\0>
+ttyx:  </dev/ttyx\0>
+getty: </etc/getty\0>
+usr:   </usr\0>
+       .even
+
+shellp:        shellm
+       0
+gettyp:        getty
+       0
+itab:
+       '0; ..
+       '1; ..
+       '2; ..
+       '3; ..
+       '4; ..
+       '5; ..
+       '6; ..
+       '7; ..
+       0
+
+offset:        .=.+2
+zero:  .=.+8; .=.+6; .=.+2
diff --git a/sh.s b/sh.s
new file mode 100644 (file)
index 0000000..63a1c79
--- /dev/null
+++ b/sh.s
@@ -0,0 +1,386 @@
+/ sh -- command interpreter
+       mov     sp,r5
+       mov     r5,shellarg / save orig sp in shellarg
+       cmpb    *2(r5),$'- / was this sh calleZd by init or loginx~
+       bne     2f / no
+       sys     intr; 0 / yes, turn off interrupts
+       sys     quit; 0
+2:
+       sys     getuid / who is user
+       tst     r0 / is it superuser
+       bne     2f / no
+       movb    $'#,at / yes, set new prompt symbol
+2:
+       cmp     (r5),$1 / tty input?
+       ble     newline / yes, call with '-(or with no command
+                       / file name)
+       clr     r0 / no, set ttv
+       sys     close / close it
+       mov     4(r5),0f / get new file name
+       sys     open; 0:..; 0 / open it
+       bec     1f / branch if no error
+       jsr     r5,error / error in file name
+               <Input not found\n\0>; .even
+       sys     exit
+1:
+       clr     at / clear prompt character, if reading non-tty
+                  / input file
+newline:
+       tst     at / is there a prompt symbol
+       beq     newcom / no
+       mov     $1,r0 / yes
+       sys     write; at; 2. / print prompt
+newcom:
+       mov     shellarg,sp /
+       mov     $parbuf,r3 / initialize command list area
+       mov     $parp,r4 / initialize command list pointers
+       clr     infile / initialize alternate input
+       clr     outfile / initialize alternate output
+       clr     glflag / initialize global flag
+newarg:
+       jsr     pc,blank / squeeze out leading blanks
+       jsr     r5,delim / is new character a ; \n or &
+               br 2f / yes
+       mov     r3,-(sp) / no, push arg pointer onto stack
+       cmp     r0,$'< / new input file?
+       bne     1f / no
+       mov     (sp),infile / yes, save arg pointer
+       clr     (sp) / clear pointer
+       br      3f
+1:
+       cmp     r0,$'> / new output file?
+       bne     newchar / no
+       mov     (sp),outfile / yes, save arg pointer
+       clr     (sp) / clear pointer
+       br      3f
+newchar:
+       cmp     $' ,r0 / is character a blank
+       beq     1f / branch if it is (blank as arg separator)
+       cmp     $'\n+200,r0 / treat \n preceded by \
+       beq     1f / as blank
+       jsr     pc,putc / put this character in parbuf list
+3:
+       jsr     pc,getc / get next character
+       jsr     r5,delim / is char a ; \n or &,
+               br 1f / yes
+       br      newchar / no, start new character tests
+1:
+       clrb    (r3)+ / end name with \0 when read blank, or
+                     / delim
+       mov     (sp)+,(r4)+ / move arg ptr to parp location
+       bne     1f / if (sp)=0, in file or out file points to arg
+       tst     -(r4) / so ignore dummy (0), in pointer list
+1:
+       jsr     r5,delim / is char a ; \n or &.
+               br 2f / yes
+       br      newarg / no, start newarg processing
+2:
+       clr     (r4) / \n, &, or ; takes to here (end of arg list)
+                    / after 'delim' call
+       mov     r0,-(sp) / save delimter in stack
+       jsr     pc,docom / go to exec command in parbuf
+       cmpb    (sp),$'& / get a new command without wait?
+       beq     newcom / yes
+       tst     r1 / was chdir just executed or line ended with
+                  / ampersand?
+       beq     2f / yes
+1:
+       sys     wait / no, wait for new process to terminate
+                    / command executed)
+       bcs     2f / no, children not previously waited for
+       cmp     r0,r1 / is this my child
+       bne     1b
+2:
+       cmp     (sp),$'\n / was delimiter a new line
+       beq     newline / yes
+       br      newcom / no, pick up next command
+docom:
+       sub     $parp,r4 / out arg count in r4
+       bne     1f / any arguments?
+       clr     r1 / no, line ended with ampersand
+       rts     pc / return from call
+1:
+       jsr     r5,chcom; qchdir / is command chdir?
+               br 2f / command not chdir
+       cmp     r4,$4 / prepare to exec chdir, 4=arg count x 2
+       beq     3f
+       jsr     r5,error / go to print error
+               <Arg count\n\0>; .even
+       br      4f
+3:
+       mov     parp+2,0f / more directory name to sys coll
+       sys     chdir; 0:0 / exec chdir
+       bec     4f / no error exit
+       jsr     r5,error / go to print error
+               <Bad directory\n\0>; .even / this diagnostic
+4:
+       clr     r1 / set r1 to zero to dkip wait
+       rts     pc / and return
+2:
+       jsr     r5,chcom; glogin / is command login?
+               br 2f / not loqin, go to fork
+       sys     exec; parbuf; parp / exec login
+       sys     exec; binpb; parp / or /bin/login
+2: / no error return??
+       sys     fork / generate sh child process for command
+               br newproc / exec command with new process
+       bec     1f / no error exit, old orocess
+       jsr     r5,error / go to print error
+               <Try again\n\0>; .even / this diaonostic
+       jmp     newline / and return for next try
+1:
+       mov     r0,r1 / save id of child sh
+       rts     pc / return to "jsr pc, docom" call in parent sh
+
+error:
+       movb    (r5)+,och / pick up diagnostic character
+       beq     1f / 0 is end of line
+       mov     $1,r0 / set for tty output
+       sys     write; och; 1 / print it
+       br      error / continue to get characters
+1:
+       inc     r5 / inc r5 to point to return
+       bic     $1,r5 / make it even
+       clr     r0 / set for input
+       rts     r5
+
+       sys     seek; 0; 2 / exit from runcom. skip to end of
+                          / input file
+chcom: / has no effect if tty input
+       mov     (r5)+,r1 / glogin gchdir r1, bump r5
+       mov     $parbuf,r2 / command address  r2 'login'
+1:
+       movb     (r1)+,r0 / is this command 'chdir'
+       cmpb    (r2)+,r0 / compare command name byte with 'login'
+                        / or 'chdir'
+       bne     1f / doesn't compare
+       tst     r0 / is this
+       bne     1b / end of names
+       tst     (r5)+ / yes, bump r5 again to execute login
+                     / chdir
+1:
+       rts     r5 / no, return to exec command
+
+putc:
+       cmp     r0,$'' / single quote?
+       beq     1f / yes
+       cmp     r0,$'" / double quote
+       beq     1f / yes
+       bic     $!177,r0 / no, remove 200, if present
+       movb    r0,(r3)+ / store character in parbuf
+       rts     pc
+1:
+       mov     r0,-(sp) / push quote mark onto stack
+1:
+       jsr     pc,getc / get a quoted character
+       cmp     r0,$'\n / is it end or line
+       bne     2f / no
+       jsr     r5,error / yes, indicate missing quote mark
+               <"' imbalance\n\0>; .even
+       jmp     newline / ask for new line
+2:
+       cmp     r0,(sp) / is this closing quote mark
+       beq     1f / yes
+       bic     $!177,r0 / no, strip off 200 if present
+       movb    r0,(r3)+ / store quoted character in parbuf
+       br      1b / continue
+1:
+       tst     (sp)+ / pop quote mark off stack
+       rts     pc / return
+
+/ thp`e new process
+
+newproc:
+       mov     infile,0f / move pointer to new file name
+       beq     1f / branch if no alternate read file given
+       tstb    *0f
+       beq     3f / branch if no file name miven
+       clr     r0 / set tty input file name
+       sys     close / close it
+       sys     open; 0:..; 0 / open new input file for reading
+       bcc     1f / branch if input file ok
+3:
+       jsr     r5,error / file not ok, print error
+               <Input file\n\0>; .even / this diagnostic
+       sys     exit / terminate this process and make parent sh
+1:
+       mov     outfile,r2 / more pointer to new file name
+       beq     1f / branch if no alternate write file
+       cmpb    (r2),$'> / is > at beqinninrg of file name?
+       bne     4f / branch if it isn't
+       inc     r2 / yes, increment pointer
+       mov     r2,0f
+       sys     open; 0:..; 1 / open file for writing
+       bec     3f / if no error
+4:
+       mov     r2,0f
+       sys     creat; 0:..; 17 / create new file with this name
+       bec     3f / branch if no error
+2:
+       jsr     r5,error
+               <Output file\n\0>; .even
+       sys     exit
+3:
+       sys     close / close the new write file
+       mov     r2,0f / move new name to open
+       mov     $1,r0 / set ttv file name
+       sys     close / close it
+       sys     open; 0:..; 1 / open new output file, it now has
+                             / file descriptor 1
+       sys     seek; 0; 2 / set pointer to current end of file
+1:
+       tst     glflag / was *, ? or [ encountered?
+       bne     1f / yes
+       sys     exec; parbuf; parp / no, execute this commend
+       sys     exec; binpb; parp / or /bin/this command
+2:
+       sys     stat; binpb; inbuf / if can't execute does it
+                                  / exist?
+       bes     2f / branch if it doesn't
+       mov     $shell,parp-2 / does exist, not executable
+       mov     $binpb,parp / so it must be
+       sys     exec; shell; parp-2 / a command file, get it with
+                                   / sh /bin/x (if x name of file)
+2:
+       jsr     r5,error / a return for exec is the diagnostic
+               <No command\n\0>; .even
+       sys     exit
+1:
+       mov     $glob,parp-2 / prepare to process *,?
+       sys     exec; glob; parp-2 / execute modified command
+       br      2b
+
+delim:
+       cmp     r0,$'\n / is character a newline
+       beq     1f
+       cmp     r0,$'& / is it &
+       beq     1f / yes
+       cmp     r0,$'; / is it ;
+       beq     1f / yes
+       cmp     r0,$'? / is it ?
+       beq     3f
+       cmp     r0,$'* / is it *
+       beq     3f
+       cmp     r0,$'[ / is it beginning of character string
+                      / (for glob)
+       bne     2f
+3:
+       inc     glflag / ? or * or [ set flag
+2:
+       tst     (r5)+ / bump to process all except \n,;,&
+1:
+       rts     r5
+
+blank:
+       jsr     pc,getc / get next character
+       cmp     $' ,r0 / leading blanks
+       beq     blank / yes, 'squeeze out'
+       cmp     r0,$200+'\n / new-line preceded by \ is translated
+       beq     blank / into blank
+       rts     pc
+getc:
+       tst     param / are we substituting for $n
+       bne     2f/ yes
+       mov     inbufp,r1 / no, move normal input pointer to r1
+       cmp     r1,einbuf / end of input line?
+       bne     1f / no
+       jsr     pc,getbuf / yes, put next console line in buffer
+       br      getc
+1:
+       movb    (r1)+,r0 / move byte from input buffer to r0
+       mov     r1,inbufp / increment routine
+       bis     escap,r0 / if last character was \ this adds
+                        / 200 to current character
+       clr     escap / clear, so escap normally zero
+       cmp     r0,$'\\ / note that \\ is equal \ in as
+       beq     1f
+       cmp     r0,$'$ / is it $
+       beq     3f / yes
+       rts     pc / no
+1:
+       mov     $200,escap / mark presence of \ in command line
+       br      getc / get next character
+2:
+       movb    *param,r0 / pick up substitution character put in
+                         / r0
+       beq     1f / if end of substitution arg, branch
+       inc     param / if not end, set for next character
+       rts     pc / return as though character in ro is normal
+                  / input
+1:
+       clr     param / unset substitution pointer
+       br      getc / get next char in normal input
+3:
+       jsr     pc,getc / get digit after $
+       sub     $'0,r0 / strip off zone bits
+       cmp     r0,$9. / compare with digit 9 
+       blos    1f / less than or equal 9
+       mov     $9.,r0 / if larger than 9, force 9
+1:
+       mov     shellarg,r1 / get pointer to stack for
+                           / this call of shell
+       inc     r0 / digit +1
+       cmp     r0,(r1) / is it less than # of args in this call
+       bge     getc / no, ignore it. so this $n is not replaced
+       asl     r0 / yes, multiply by 2 (to skip words)
+       add     r1,r0 / form pointer to arg pointer (-2)
+       mov     2(r0),param / move arg pointer to param
+       br      getc / go to get substitution arg for $n
+getbuf:
+       mov     $inbuf,r0 / move input buffer address
+       mov     r0,inbufp / to input buffer pointer
+       mov     r0,einbuf / and initialize pointer to end of
+                         / character string
+       dec     r0 / decrement pointer so can utilize normal
+                  / 100p starting at 1f
+       mov     r0,0f / initialize address for reading 1st char
+1:
+       inc     0f / this routine filles inbuf with line from
+                  / console - if there is cnc
+       clr     r0 / set for tty input
+       sys     read; 0:0; 1 / read next char into inbuf
+       bcs     xit1 / error exit
+       tst     r0 / a zero input is end of file
+       beq     xit1 / exit
+       inc     einbuf / eventually einbuf points to \n
+                      / (+1) of this line
+       cmp     0b,$inbuf+256. / have we exceeded input buffer size
+       bhis    xit1 / if so, exit assume some sort of binary
+       cmpb    *0b,$'\n / end of line?
+       bne     1b / no, go to get next char
+       rts     pc / yes, return
+
+xit1:
+       sys     exit
+
+quest:
+       <?\n>
+
+at:
+       <@ >
+
+qchdir:
+       <chdir\0>
+glogin:
+       <login\0>
+shell:
+       </bin/sh\0>
+glob:
+       </etc/glob\0>
+binpb:
+       </bin/>
+parbuf: .=.+1000.
+       .even
+param: .=.+2
+glflag:        .=.+2
+infile: .=.+2 
+outfile:.=.+2
+       .=.+2 / room for glob
+parp:  .=.+200.
+inbuf: .=.+256.
+escap: .=.+2
+inbufp: .=.+2
+einbuf:        .=.+2
+och:   .=.+2
+shellarg:.=.+2
+
diff --git a/u0.s b/u0.s
new file mode 100644 (file)
index 0000000..43f7d1a
--- /dev/null
+++ b/u0.s
@@ -0,0 +1,532 @@
+/ u0 -- unix
+
+cold = 0 
+orig = 0 . / orig = 0. relocatable
+
+rkda = 177412 / disk address reg            rk03/rk11
+rkds = 177400 / driv status reg             rk03/rk11
+rkcs = 177404 / control status reg          rk03/rk11
+rcsr = 174000 / receiver status reg         dc-11
+rcbr = 174002 / receiver buffer reg         dc-11
+tcsr = 174004 / xmtr status reg             dc-11
+tcbr = 174006 / xmtr buffer reg             dc-11
+tcst = 177340 / dec tape control status     tc11/tu56
+tccm = 177342 / dec tape command reg        tc11/tu56
+tcwc = 177344 /          word count         tc11/tu56
+tcba = 177346 /          bus addr           tc11/tu56
+tcdt = 177350 /          data reg           tc11/tu56
+dcs  = 177460 / drum control status         rf11/rs11
+dae  = 177470 / drum address extension      rf11/rs11
+lks  = 177546 / clock status reg            kw11-l
+prs  = 177550 / papertape reader status     pc11
+prb  = 177552 /                  buffer     pc11
+pps  = 177554 /            punch status     pc11
+ppb  = 177556 /            punch buffer     pc11
+/lps = 177514   line printer status         (future)
+/lpb = 177516   line printer buffer         (future)
+tks  = 177560 / console read status         asr-33
+tkb  = 177562 /         read buffer         asr-33
+tps  = 177564 /         punch status        asr-33
+tpb  = 177566 /         punch buffer        asr-33
+ps   = 177776 / processor status
+
+fpsym = 0   / define fpsym even though we cannot use it
+.. = 0 .    / ensure a.out starts at location 0, not 040000
+
+halt = 0
+wait = 1
+rti  = 2
+
+nproc = 16. / number of processes
+nfiles = 50.
+ntty = 8+1
+nbuf = 6
+ .if cold / ignored if cold = 0
+nbuf = 2
+.endif
+
+core = orig+40000  / specifies beginning of user's core
+ecore = core+40000 / specifies end of user's core (4096 words)
+
+/      4;4     init by copy
+/      unkni;0 " error
+/      fpsym;0 " illg in tr
+       unkni;0 / trace and trap (see Sec. B.1 page  )
+       unkni;0 / trap
+       panic;0 / pwr
+       rtssym;0 / emt
+       sysent;0 / sys
+ . = orig+60
+       ttyi;240 / interrupt vector tty in       ; processor level 5
+       ttyo;240 / interrupt vector tty out
+       ppti;240 /                  punch papertape in
+       ppto;240 /                  punch papertape out
+       clock;340 / clock interrupt vector       ; processor level 7
+ . = orig+200
+/     lpto; 240  line printer interrupt     ; processor level 5 (future)
+ . = orig+204
+       drum;300 / drum interrupt         ; processor level 6
+ . = orig+214
+       tape;300 / dec tape interrupt
+       disk;300 / rk03 interrupt
+ . = orig+300
+       0*4+trcv; 240; 0*4+txmt; 240 / dc11 input,output interrupt vectors
+       1*4+trcv; 240; 1*4+txmt; 240
+       2*4+trcv; 240; 2*4+txmt; 240
+       3*4+trcv; 240; 3*4+txmt; 240
+       4*4+trcv; 240; 4*4+txmt; 240
+       5*4+trcv; 240; 5*4+txmt; 240
+       6*4+trcv; 240; 6*4+txmt; 240
+       7*4+trcv; 240; 7*4+txmt; 240
+
+ . = orig+400
+/ copy in transfer vectors
+
+       mov    $ecore,sp / put pointer to ecore in the stack pointer
+       jsr    r0,copyz; 0; 14 / clear locations 0 to 14 in core
+       mov    $4,r0
+       clr    r1
+       mov    r0,(r1)+ / put value of 4 into location 0
+       mov    r0,(r1)+ / put value of 4 into location 2
+       mov    $unkni,(r1)+ / put value of unkni into location 4;
+                            / time out, bus error
+       clr    (r1)+ / put value of 0 into location 6
+       mov    $fpsym,(r1)+ / put value of fpsym into location 10
+       clr    (r1)+ / put value of 0 into location 12
+/ clear core
+       .if cold / ignored if cold = 0
+       halt / halt before initializing rf file system; user has
+             / last chance to reconsider
+       .endif
+
+       jsr    r0,copyz; systm; ecore / clear locations systm to ecore
+       mov    $s.chrgt+2,clockp / intialize clockp
+/ allocate tty buffers; see H.0 for description
+       mov    $buffer,r0
+       mov    $tty+6,r1
+1:
+       mov    r0,(r1)
+       add    $140.,r0 / tty buffers are 140. bytes long
+       add    $8,r1
+       cmp    r1,$tty+[ntty*8] / has a buffer been assigned for each tty
+       blo    1b
+
+/ allocate disk buffers; see H.0 for description
+
+       mov    $bufp,r1
+1:
+       mov    r0,(r1)+
+       add    $8,r0
+       mov    r0,-2(r0)             / bus address
+       mov    $-256.,-4(r0)         / word count
+       add    $512.,r0              / buffer space
+       cmp    r1,$bufp+nbuf+nbuf
+       blo    1b
+       mov    $sb0,(r1)+            / I/O queue entry drum
+       mov    $sb1,(r1)+ / I/O queue entry disk (mounted device)
+       mov    $swp,(r1)+ / I/O queue entry core image being swapped
+       mov    $[systm-inode]\/2,sb0+4 / sets up initial buffers per
+                                       / format given in
+       mov    $systm,sb0+6 / memory map
+       mov    $-512.,sb1+4
+       mov    $_mount,sb1+6
+       mov    $user,swp+6
+
+/ set devices to interrupt
+
+       mov    $100,*$lks / put 100 into clock status register;
+                           / enables clock interrupt
+
+/ set up time out subroutines
+
+       mov    $touts,r0
+       mov    $startty,(r0)+ / if toutt = 0 call startty
+       mov    $pptito,(r0)+ / if toutt+1 = 0 call pptito
+       tst    (r0)+ / add 2 to r0
+       mov    $ntty-1,r1
+1 :
+       mov    $xmtto,(r0)+ / if toutt+2 thru toutt+2+ntty=0 call xmtto
+       dec    r1
+       bne    1b
+
+/ free all character blocks; see H.0 for description
+
+       mov    $510.,r2
+       mov    $-1,r1
+1:
+       jsr    r0,put
+       sub    $2,r2
+       bgt    1b
+
+/ set up drum swap addresses; see H.0 for description
+
+       mov    $1024.-64.,r1 / highest drum address; high 64 blks allocated
+                              / to UNIX
+       mov    $p.dska,r2 / p.dska contains disk addresses for processes
+1 :
+       sub    $33.,r1 / 33 blocks per process, allows 16K per process
+       mov    r1,(r2)+
+       cmp    r2,$p.dska+nproc+nproc
+       bne    1b
+
+/ free rest of drum
+
+       .if cold
+       mov    $128.,systm / initialize word 1 of drum superblock image;
+                           / number of bytes in free storage map=128.
+       mov    $64.,systm+2+128. / init. wd 66. of superblock image; # of
+                                 / bytes in i-node map=64.
+1:
+       dec    r1 / r1=687.,...,34.
+       jsr    r0,free / free block 'r1', i.e., set bit 'r1' in free
+                       / storage map in core
+       cmp    r1,$34. / first drum address not in i list
+       bgt    1b / if block 34 has been freed, zero i list
+
+/ zero i list
+
+1:
+       dec    r1 / r1=33.,...,1
+       jsr    r0,clear / zero block 'r1' on fixed head disk
+       tst    r1
+       bgt    1b / if blocks 33,...,1 have all been zeroed, done.
+       .endif
+
+/ make current program a user
+
+       mov    $41.,r0 / rootdir set to 41 and never changed
+       mov    r0,rootdir / rootdir is i-number of root directory
+       mov    r0,u.cdir / u.cdir is i-number of process current directory
+       mov    $1,r0
+       movb   r0,u.uno / set process table index for this process to 1
+       mov    r0,mpid / initialize mpid to 1
+       mov    r0,p.pid / p.pid identifies process
+       movb   r0,p.stat / process status = 1 i.e., active
+                         /                = 0 free
+       .if cold         /                = 2 waiting for a child to die
+                         /                = 3 terminated but not yet waited
+                         /                  for
+
+/ initialize inodes for special files (inodes 1 to 40.)
+
+       mov    $40.,r1 / set r1=i-node-number 40.
+1:
+       jsr    r0,iget / read i-node 'r1' from disk into inode area of
+                       / core and write modified inode out (if any)
+       mov    $100017,i.flgs / set flags in core image of inode to indi-
+                              / cate allocated, read (owner, non-owner),
+                              / write (owner, non-owner)
+       movb   $1,i.nlks / set no. of links = 1
+       movb   $1,i.uid / set user id of owner = 1
+       jsr    r0,setimod / set imod=1 to indicate i-node modified, also
+                          / stuff time of modification into i-node
+       dec    r1 / next i-node no. = present i-node no.-1
+       bgt    1b / has i-node 1 been initialized; no, branch
+
+/ initialize i-nodes r1.,...,47. and write the root device, binary, etc.,
+/ directories onto fixed head disk. user temporary, initialization prog.
+
+       mov    $idata,r0 / r0=base addr. of assembled directories.
+       mov    $u.off,u.fofp / pointer to u.off in u.fofp (holds file
+                             / offset)
+1:
+       mov    (r0)+,r1/r1=41.,...,47; "0" in the assembled directory
+                       / header signals last
+       beq    1f      / assembled directory has been written onto drum
+       jsr    r0,imap / locate the inode map bit for i-node 'r1'
+       bisb   mq,(r2) / set the bit to indicate the i-node is not
+                       / available
+       jsr    r0,iget / read inode 'r1' from disk into inode area of
+                       / core and write modified i-node on drum (if any)
+       mov    (r0)+,i.flgs / set flags in core image of inode from
+                            / assembled directories header
+       movb   (r0)+,i.nlks / set no. of links from header
+       movb   (r0)+,i.uid / set user id of owner from header
+       jsr    r0,setimod / set imod=1 to indicate inode modified; also,
+                          / stuff time of modification into i-node
+       mov    (r0)+,u.count / set byte count for write call equal to
+                             / size of directory
+       mov    r0,u.base / set buffer address for write to top of directory
+       clr    u.off / clear file offset used in 'seek' and 'tell'
+       add    u.count,r0 / r0 points to the header of the next directory
+       jsr    r0,writei / write the directory and i-node onto drum
+       br     1b / do next directory
+       .endif
+
+/ next 2 instructions not executed during cold boot.
+       bis    $2000,sb0 / sb0 I/O queue entry for superblock on drum;
+                         / set bit 10 to 1
+       jsr    r0,ppoke / read drum superblock
+1:
+       tstb   sb0+1 / has I/O request been honored (for drum)?
+       bne    1b / no, continue to idle.
+1:
+       decb   sysflg / mormally sysflag=0, indicates executing in system
+       sys    exec; 2f; 1f / generates trap interrupt; trap vector =
+                            / sysent; 0
+       br     panic / execute file/etc/init
+
+1:
+       2f;0
+2:
+       </etc/init\0> / UNIX looks for strings term, noted by nul\0
+
+panic:
+       clr    ps
+1:
+       dec    $0
+       bne    1b
+       dec    $5
+       bne    1b
+       jmp    *$173700 / rom loader address
+rtssym:
+       mov    r0,-(sp)
+       mov    r1,-(sp)
+       mov    4(sp),r0
+       mov    -(r0),r0
+       bic    $!7,r0
+       asl    r0
+       jmp    *1f(r0)
+1:
+       0f;1f;2f;3f;4f;5f;badrts;7f
+0:
+       mov    2(sp),r0
+       br     1f
+2:
+       mov    r2,r1
+       br     1f
+3:
+       mov    r3,r1
+       br     1f
+4:
+       mov    r4,r1
+       br     1f
+5:
+       mov     r5,r1
+       br     1f
+7:
+       mov    8.(sp),r1
+1:
+       cmp    r1,$core
+       blo    badrts
+       cmp    r1,$ecore
+       bhis   badrts
+       bit    $1,r1
+       bne    badrts
+       tst    (r1)
+       beq    badrts
+       add    $1f,r0
+       mov    r0,4(sp)
+       mov    (sp)+,r1
+       mov    (sp)+,r0
+       rti
+1:
+       rts    r0
+       rts    r1
+       rts    r2
+       rts    r3
+       rts    r4
+       rts    r5
+       rts    sp
+       rts    pc
+
+badrts:
+       mov    (sp)+,r1
+       mov    (sp)+,r0
+rpsym:
+       jmp    unkni
+
+       .if cold
+
+idata:
+
+/ root
+
+       41.
+       140016
+       .byte 7,1
+       9f-.-2
+       41.
+       <..\0\0\0\0\0\0>
+       41.
+       <.\0\0\0\0\0\0\0>
+       42.
+       <dev\0\0\0\0\0>
+       43.
+       <bin\0\0\0\0\0>
+       44.
+       <etc\0\0\0\0\0>
+       45.
+       <usr\0\0\0\0\0>
+       46.
+       <tmp\0\0\0\0\0>
+9:
+
+/ device directory
+
+       42.
+       140016
+       .byte 2,1
+       9f-.-2
+       41.
+       <..\0\0\0\0\0\0>
+       42.
+       <.\0\0\0\0\0\0\0>
+       01.
+       <tty\0\0\0\0\0>
+       02.
+       <ppt\0\0\0\0\0>
+       03.
+       <mem\0\0\0\0\0>
+       04.
+       <rf0\0\0\0\0\0>
+       05.
+       <rk0\0\0\0\0\0>
+       06.
+       <tap0\0\0\0\0>
+       07.
+       <tap1\0\0\0\0>
+       08.
+       <tap2\0\0\0\0>
+       09.
+       <tap3\0\0\0\0> 
+       10.
+       <tap4\0\0\0\0>
+       11.
+       <tap5\0\0\0\0>
+       12.
+       <tap6\0\0\0\0>
+       13.
+       <tap7\0\0\0\0>
+       14.
+       <tty0\0\0\0\0>
+       15.
+       <tty1\0\0\0\0>
+       16.
+       <tty2\0\0\0\0>
+       17.
+       <tty3\0\0\0\0>
+       18.
+       <tty4\0\0\0\0>
+       19.
+       <tty5\0\0\0\0>
+       20.
+       <tty6\0\0\0\0>
+       21.
+       <tty7\0\0\0\0>
+       22.
+       <lpr\0\0\0\0\0>
+       01.
+       <tty8\0\0\0\0> / really tty
+9:
+
+/ binary directory
+
+       43.
+       140016
+       .byte 2,3
+       9f-.-2
+       41.
+       <..\0\0\0\0\0\0>
+       43.
+       <.\0\0\0\0\0\0\0>
+9:
+
+/ etcetra directory
+
+       44.
+       140016
+       .byte 2,3
+       9f-.-2
+       41.
+       <..\0\0\0\0\0\0>
+       44.
+       <.\0\0\0\0\0\0\0>
+       47.
+       <init\0\0\0\0>
+9:
+
+/ user directory
+
+       45.
+       140016
+       .byte 2,1
+       9f-.-2
+       41.
+       <..\0\0\0\0\0\0>
+       45.
+       <.\0\0\0\0\0\0\0>
+9:
+
+/ temporary directory
+
+       46.
+       140017
+       .byte 2,1
+       9f-.-2
+       41.
+       <..\0\0\0\0\0\0>
+       46.
+       <.\0\0\0\0\0\0\0>
+9:
+
+/ initialization program
+
+       47.
+       100036
+       .byte 1,3
+       9f-.-2
+8:
+       sys    break; 0
+       sys    open; 6f-8b+core; 0
+       mov    r0,r1
+       sys    seek; 65.; 0
+1:
+       mov    r1,r0
+       sys    read; 9f-8b+core; 512.
+       mov    9f,r5            / size
+       beq    1f
+       sys    creat; 9f-8b+core+4; 0
+       mov    r0,r2
+       movb   9f+2,0f
+       sys    chmod; 9f-8b+core+4; 0:..
+       movb   9f+3,0f
+       sys    chown; 9f-8b+core+4; 0:..
+2:
+       tst    r5
+       beq    2f
+       mov    r1,r0
+       sys    read; 9f-8b+core; 512.
+       mov    $512.,0f
+       cmp    r5,$512.
+       bhi    3f
+       mov    r5,0f
+3:
+       mov    r2,r0
+       sys    write; 9f-8b+core; 0:..
+       sub    r0,r5
+       br     2b
+2:
+       mov    r2,r0
+       sys    close
+       br     1b
+1:
+       mov    r1,r0
+       sys    close
+       sys    exec; 5f-8b+core; 4f-8b+core
+       sys    exit
+4:
+       5f-8b+core; 0
+5:
+       </etc/init\0>
+6:
+       </dev/tap0\0>
+       .even
+9:
+
+/ end of initialization data
+
+       0
+
+       .endif
+
diff --git a/u1.s b/u1.s
new file mode 100644 (file)
index 0000000..13091fb
--- /dev/null
+++ b/u1.s
@@ -0,0 +1,534 @@
+/ u1 -- unix
+
+unkni: / used for all system calls
+sysent:
+       incb    sysflg / indicate a system routine is
+       beq     1f / in progress
+       jmp     panic / called if trap inside system
+1:
+       mov     $s.syst+2,clockp
+       mov     r0,-(sp) / save user registers
+       mov     sp,u.r0 / pointer to bottom of users stack in u.r0
+       mov     r1,-(sp)
+       mov     r2,-(sp)
+       mov     r3,-(sp)
+       mov     r4,-(sp)
+       mov     r5,-(sp)
+       mov     ac,-(sp) / "accumulator" register for extended
+                        / arithmetic unit
+       mov     mq,-(sp) / "multiplier quotient" register for the
+                        / extended arithmetic unit
+       mov     sc,-(sp) / "step count" register for the extended
+                        / arithmetic unit
+       mov     sp,u.sp / u.sp points to top of users stack
+       mov     18.(sp),r0 / store pc in r0
+       mov     -(r0),r0 / sys inst in r0      10400xxx
+       sub     $sys,r0 / get xxx code
+       asl     r0 / multiply by 2 to jump indirect in bytes
+       cmp     r0,$2f-1f / limit of table (35) exceeded
+       bhis    badsys / yes, bad system call
+       bic     $341,20.(sp) / set users processor priority to 0 and clear
+                            / carry bit
+       jmp     *1f(r0) / jump indirect thru table of addresses
+                       / to proper system routine.
+1:
+       sysrele / 0
+       sysexit / 1
+       sysfork / 2
+       sysread / 3
+       syswrite / 4
+       sysopen / 5
+       sysclose / 6
+       syswait / 7
+       syscreat / 8
+       syslink / 9
+       sysunlink / 10
+       sysexec / 11
+       syschdir / 12
+       systime / 13
+       sysmkdir / 14
+       syschmod / 15
+       syschown / 16
+       sysbreak / 17
+       sysstat / 18
+       sysseek / 19
+       systell / 20
+       sysmount / 21
+       sysumount / 22
+       syssetuid / 23
+       sysgetuid / 24
+       sysstime / 25
+       sysquit / 26
+       sysintr / 27
+       sysfstat / 28
+       sysemt / 29
+       sysmdate / 30
+       sysstty / 31
+       sysgtty / 32
+       sysilgins / 33
+2:
+
+error:
+       mov     u.sp,r1
+       bis     $1,20.(r1) / set c bit in processor status word below
+                          / users stack
+
+sysret:
+       tstb    u.bsys / is a process about to be terminated because
+       bne     sysexit / of an error? yes, go to sysexit
+       mov     u.sp,sp / no point stack to users stack
+       clr     r1 / zero r1 to check last mentioned i-node
+       jsr     r0,iget / if last mentioned i-node has been modified
+                       / it is written out
+       tstb    smod / has the super block been modified
+       beq     1f / no, 1f
+       clrb    smod / yes, clear smod
+       bis     $1000,sb0 / set write bit in I/O queue for super block
+                         / output
+       jsr     r0,ppoke / write out modified super block to disk
+1:
+       tstb    mmod / has the super block for the dismountable file
+                    / system
+       beq     1f / been modified?  no, 1f
+       clrb    mmod / yes, clear mmod
+       movb    mntd,sb1 / set the I/O queue
+       bis     $1000,sb1 / set write bit in I/O queue for detached sb
+       jsr     r0,ppoke / write it out to its device
+1:
+       tstb    uquant / is the time quantum 0?
+       bne     1f / no, don't swap it out
+
+sysrele:
+       jsr     r0,tswap / yes, swap it out
+1:
+       mov     (sp)+,sc / restore user registers
+       mov     (sp)+,mq
+       mov     (sp)+,ac
+       mov     (sp)+,r5
+       mov     (sp)+,r4
+       mov     (sp)+,r3
+       mov     (sp)+,r2
+       mov     (sp)+,r1
+       mov     (sp)+,r0
+       mov     $s.chrgt+2,clockp
+       decb    sysflg / turn system flag off
+       jsr     r0,isintr / is there an interrupt from the user
+               br intract / yes, output gets flushed, take interrupt
+                          / action
+       rti     / no return from interrupt
+
+badsys:
+       incb    u.bsys / turn on the user's bad-system flag
+       mov     $3f,u.namep / point u.namep to "core\0\0"
+       jsr     r0,namei / get the i-number for the core image file
+               br 1f / error
+       neg     r1 / negate the i-number to open the core image file
+                  / for writing
+       jsr     r0,iopen / open the core image file
+       jsr     r0,itrunc / free all associated blocks
+       br      2f
+1:
+       mov     $17,r1 / put i-node mode (17) in r1
+       jsr     r0,maknod / make an i-node
+       mov     u.dirbuf,r1 / put i-nodes number in r1
+2:
+       mov     $core,u.base / move address core to u.base
+       mov     $ecore-core,u.count / put the byte count in u.count
+       mov     $u.off,u.fofp / more user offset to u.fofp
+       clr     u.off / clear user offset
+       jsr     r0,writei / write out the core image to the user
+       mov     $user,u.base / pt. u.base to user
+       mov     $64.,u.count / u.count = 64
+       jsr     r0,writei / write out all the user parameters
+       neg     r1 / make i-number positive
+       jsr     r0,iclose / close the core image file
+       br      sysexit /
+3:
+       <core\0\0>
+
+sysexit: / terminate process
+       clr     u.intr / clear interrupt control word
+       clr     r1 / clear r1
+1: / r1 has file descriptor (index to u.fp list)  Search the whole list
+       jsr     r0,fclose / close all files the process opened
+               br .+2 / ignore error return
+       inc     r1 / increment file descriptor
+       cmp     r1,$10. / end of u.fp list?
+       blt     1b / no, go back
+       movb    u.uno,r1 / yes, move dying process's number to r1
+       clrb     p.stat-1(r1) / free the process
+       asl     r1 / use r1 for index into the below tables
+       mov     p.pid-2(r1),r3 / move dying process's name to r3
+       mov     p.ppid-2(r1),r4 / move its parents name to r4
+       clr     r2
+       clr     r5 / initialize reg
+1: / find children of this dying process, if they are zombies, free them
+       add     $2,r2 / search parent process table for dying process's name
+       cmp     p.ppid-2(r2),r3 / found it?
+       bne     3f / no
+       asr     r2 / yes, it is a parent
+       cmpb    p.stat-1(r2),$3 / is the child of this dying process a
+                               / zombie
+       bne     2f / no
+       clrb    p.stat-1(r2) / yes, free the child process
+2:
+       asl     r2
+3: / search the process name table for the dying process's parent
+       cmp     p.pid-2(r2),r4 / found it?
+       bne     3f / no
+       mov     r2,r5 / yes, put index to p.pid table (parents
+                     / process # x2) in r5
+3:
+       cmp     r2,$nproc+nproc / has whole table been searched?
+       blt     1b / no, go back
+       mov     r5,r1 / yes, r1 now has parents process # x2
+       beq     2f / no parent has been found. The process just dies
+       asr     r1 / set up index to p.stat
+       movb    p.stat-1(r1),r2 / move status of parent to r2
+       beq     2f / if its been freed, 2f
+       cmp     r2,$3 / is parent a zombie?
+       beq     2f / yes, 2f
+       movb    u.uno,r3 / move dying process's number to r3
+       movb    $3,p.stat-1(r3) / make the process a zombie
+       cmp     r2,$2 / is the parent waiting for this child to die
+       bne     2f / yes, notify parent not to wait any more
+       decb    p.stat-1(r1) / awaken it by putting it (parent)
+       mov     $runq+4,r2 / on the runq
+       jsr     r0, putlu
+2: / the process dies
+       clrb    u.uno / put zero as the process number, so "swap" will
+       jsr     r0,swap / overwrite process with another process
+       0       / and thereby kill it; halt?
+
+intract: / interrupt action
+       cmp     *(sp),$rti / are you in a clock interrupt?
+       bne     1f / no, 1f
+       cmp     (sp)+,(sp)+ / pop clock pointer
+1: / now in user area
+       mov     r1,-(sp) / save r1
+       mov     u.ttyp,r1 / pointer to tty buffer in control-to r1
+       cmpb    6(r1),$177 / is the interrupt char equal to "del"
+       beq     1f / yes, 1f
+       clrb    6(r1) / no, clear the byte (must be a quit character)
+       mov     (sp)+,r1 / restore r1
+       clr     u.quit / clear quit flag
+       bis     $20,2(sp) / set trace for quit (sets t bit of ps-trace trap)
+       rti               / return from interrupt
+1: / interrupt char = del
+       clrb    6(r1) / clear the interrupt byte in the buffer
+       mov     (sp)+,r1 / restore r1
+       cmp     u.intr,$core / should control be transferred to loc core?
+       blo     1f
+       jmp     *u.intr / user to do rti yes, transfer to loc core
+1:
+       sys     1 / exit
+
+syswait: / wait for a process to die
+       movb    u.uno,r1 / put parents process number in r1
+       asl     r1 / x2 to get index into p.pid table
+       mov     p.pid-2(r1),r1 / get the name of this process
+       clr     r2
+       clr     r3 / initialize reg 3
+1:
+       add     $2,r2 / use r2 for index into p.ppid table / search table
+                     / of parent processes for this process name
+       cmp     p.ppid-2(r2),r1 / r2 will contain the childs process number
+       bne     3f / branch if no match of parent process name
+       inc     r3 / yes, a match, r3 indicates number of children
+       asr     r2 / r2/2 to get index to p.stat table
+       cmpb    p.stat-1(r2),$3 / is the child process a zombie?
+       bne     2f / no, skip it
+       clrb    p.stat-1(r2) / yes, free it
+       asl     r2 / r2x2 to get index into p.pid table
+       mov     p.pid-2(r2),*u.r0 / put childs process name in (u.r0)
+       br      sysret1 / return cause child is dead
+2:
+       asl     r2 / r2x2 to get index into p.ppid table
+3:
+       cmp     r2,$nproc+nproc / have all processes been checked?
+       blt     1b / no, continue search
+       tst     r3 / one gets here if there are no children or children
+                  / that are still active
+       beq     error1 / there are no children, error
+       movb    u.uno,r1 / there are children so put parent process number
+                        / in r1
+       incb    p.stat-1(r1) / it is waiting for other children to die
+       jsr     r0,swap / swap it out, because it's waiting
+       br      syswait / wait on next process
+
+error1:
+       jmp     error / see 'error' routine
+sysret1:
+       jmp     sysret / see 'sysret' routine
+
+sysfork: / create a new process
+       clr     r1
+1: / search p.stat table for unused process number
+       inc     r1
+       tstb    p.stat-1(r1) / is process active, unused, dead
+       beq     1f / it's unused so branch
+       cmp     r1,$nproc / all processes checked
+       blt     1b / no, branch back
+       add     $2,18.(sp) / add 2 to pc when trap occured, points
+                          / to old process return
+       br      error1 / no room for a new process
+1:
+       movb    u.uno,-(sp) / save parent process number
+       movb    r1,u.uno / set child process number to r1
+       incb    p.stat-1(r1) / set p.stat entry for child process to
+                            / active status
+       mov     u.ttyp,r2 / put pointer to parent process' control tty
+                         / buffer in r2
+       beq     2f / branch, if no such tty assigned
+       clrb    6(r2) / clear interrupt character in tty buffer
+2:
+       mov     $runq+4,r2
+       jsr     r0,putlu / put child process on lowest priority run queue
+       asl     r1 / multiply r1 by 2 to get index into p.pid table
+       inc     mpid / increment m.pid; get a new process name
+       mov     mpid,p.pid-2(r1) / put new process name in child process'
+                                / name slot
+       movb    (sp),r2 / put parent process number in r2
+       asl     r2 / multiply by 2 to get index into below tables
+       mov     p.pid-2(r2),r2 / get process name of parent process
+       mov     r2,p.ppid-2(r1) / put parent process name in parent
+                               / process slot for child
+       mov     r2,*u.r0 / put parent process name on stack at location
+                        / where r0 was saved
+       mov     $sysret1,-(sp) /
+       mov     sp,u.usp / contents of sp at the time when user is
+                        / swapped out
+       mov     $sstack,sp / point sp to swapping stack space
+       jsr     r0,wswap / put child process out on drum
+       jsr     r0,unpack / unpack user stack
+       mov     u.usp,sp / restore user stack pointer
+       tst     (sp)+ / bump stack pointer
+       movb    (sp)+,u.uno / put parent process number in u.uno
+       mov     mpid,*u.r0 / put child process name on stack where r0
+                          / was saved
+       add     $2,18.(sp) / add 2 to pc on stack; gives parent
+                          / process return
+       clr     r1
+1: / search u.fp list to find the files opened by the parent process
+       movb    u.fp(r1),r2 / get an open file for this process
+       beq     2f / file has not been opened by parent, so branch
+       asl     r2 / multiply by 8
+       asl     r2 / to get index into fsp table
+       asl     r2
+       incb    fsp-2(r2) / increment number of processes using file,
+                         / because child will now be using this file
+2:
+       inc     r1 / get next open file
+       cmp     r1,$10. / 10. files is the maximum number which can be
+                       / opened
+       blt     1b / check next entry
+       br      sysret1
+
+sysread:
+       jsr     r0,rw1 / get i-number of file to be read into r1
+       tst     r1 / negative i-number?
+       ble     error1 / yes, error 1 to read it should be positive
+       jsr     r0,readi / read data into core
+       br      1f
+
+syswrite:
+       jsr     r0,rw1 / get i-number in r1 of file to write
+        tst    r1 / positive i-number ?
+        bge    error1 / yes, error 1 negative i-number means write
+        neg    r1 / make it positive
+        jsr    r0,writei / write data
+1:
+        mov    u.nread,*u.r0 / put no. of bytes transferred into (u.r0)
+        br     sysret1
+
+rw1:
+        jsr    r0,arg; u.base / get buffer pointer
+        jsr    r0,arg; u.count / get no. of characters
+        mov    *u.r0,r1 / put file descriptor (index to u.fp table) in r1
+        jsr    r0,getf / get i-number of the file in r1
+        rts    r0
+
+sysopen:
+        jsr    r0,arg2 / get sys args into u.namep and on stack
+        jsr    r0,namei / i-number of file in r1
+        br     error2 / file not found
+        tst    (sp) / is mode = 0 (2nd arg of call; 0 means, open for read)
+        beq    1f / yes, leave i-number positive
+        neg    r1 / open for writing so make i-number negative
+1:
+        jsr    r0,iopen / open file whose i-number is in r1
+        tst    (sp)+ / pop the stack and test the mode
+        beq    op1 / is open for read op1
+
+op0:
+        neg    r1 / make i-number positive if open for writing
+op1:
+        clr    r2 / clear registers
+        clr    r3
+1: / scan the list of entries in fsp table
+        tstb   u.fp(r2) / test the entry in the u.fp list
+        beq    1f / if byte in list is 0 branch
+        inc    r2 / bump r2 so next byte can be checked
+        cmp    r2,$10. / reached end of list?
+        blt    1b / no, go back
+        br     error2 / yes, error (no files open)
+1:
+        tst    fsp(r3) / scan fsp entries
+        beq    1f / if 0 branch
+        add    $8.,r3 / add 8 to r3 to bump it to next entry mfsp table
+        cmp    r3,$[nfiles*8.] / done scanning
+        blt    1b / no, back
+        br     error2 / yes, error
+1: / r2 has index to u.fp list; r3, has index to fsp table
+        mov    r1,fsp(r3) / put i-number of open file into next available
+        mov    cdev,fsp+2(r3) / entry in fsp table, put # of device in
+                              / next word
+        clr    fsp+4(r3)
+        clr    fsp+6(r3) / clear the next two words
+        asr    r3
+        asr    r3 / divide by 8 to get number of the fsp entry-1
+        asr    r3
+        inc    r3 / add 1 to get fsp entry number
+        movb   r3,u.fp(r2) / move entry number into next available slot
+                           / in u.fp list
+        mov    r2,*u.r0 / move index to u.fp list into r0 loc on stack
+        br     sysret2
+
+error2:
+        jmp    error / see 'error' routine
+sysret2:
+        jmp    sysret / see 'sysret' routine
+
+syscreat: / name; mode
+        jsr    r0,arg2 / put file name in u.namep put mode on stack
+        jsr    r0,namei / get the i-number
+               br  2f / if file doesn't exist 2f
+        neg    r1 / if file already exists make i-number negative
+                  / (open for writing)
+        jsr    r0,iopen /
+        jsr    r0,itrunc / truncate to 0 length
+        br     op0
+2: / file doesn't exist
+        mov    (sp)+,r1 / put the mode in r1
+        bic    $!377,r1 / clear upper byte
+        jsr    r0,maknod / make an i-node for this file
+        mov    u.dirbuf,r1 / put i-number for this new file in r1
+        br     op0 / open the file
+
+sysmkdir: / make a directory
+        jsr    r0,arg2 / point u.namep to the file name
+        jsr    r0,namei / get the i-number
+               br .+4 / if file not found branch around error
+        br     error2 / directory already exists (error)
+        tstb   u.uid / is user the super user
+        bne    error2 / no, not allowed
+        mov    (sp)+,r1 / put the mode in r1
+        bic    $!317,r1 / all but su and ex
+        bis    $40000,r1 / directory flag
+        jsr    r0,maknod / make the i-node for the directory
+        br     sysret2 /
+
+sysclose: / close the file
+        mov    *u.r0,r1 / move index to u.fp list into r1
+        jsr    r0,fclose / close the file
+               br error2 / unknown file descriptor
+        br     sysret2
+
+sysemt:
+        jsr    r0,arg; 30 / put the argument of the sysemt call in loc 30
+        cmp    30,$core / was the argument a lower address than core
+        blo    1f / yes, rtssym
+        cmp    30,$ecore / no, was it higher than "core" and less than
+                         / "ecore"
+        blo    2f / yes, sysret2
+1:
+        mov    $rtssym,30
+2:
+        br     sysret2
+sysilgins: / calculate proper illegal instruction trap address
+        jsr    r0,arg; 10 / take address from sysilgins call     , put
+                          / it in loc 8.,
+        cmp    10,$core / making it the illegal instruction trap address
+        blo    1f / is the address a user core address?  yes, go to 2f
+        cmp    10,$ecore
+        blo    2f
+1:
+        mov    $fpsym,10 / no, make 'fpsum' the illegal instruction trap
+                         / address for the system
+2:
+        br     sysret2 / return to the caller via 'sysret'
+
+sysmdate: / change the modification time of a file
+        jsr    r0,arg; u.namep / point u.namep to the file name
+        jsr    r0,namei / get its i-number
+               br error2 / no, such file
+        jsr    r0,iget / get i-node into core
+        cmpb   u.uid,i.uid / is user same as owner
+        beq    1f / yes
+        tstb   u.uid / no, is user the super user
+        bne    error2 / no, error
+1:
+        jsr    r0,setimod / fill in modification data, time etc.
+        mov    4(sp),i.mtim / move present time to
+        mov    2(sp),i.mtim+2 / modification time
+        br     sysret2
+
+sysstty: / set mode of typewriter; 3 consequtive word arguments
+        jsr    r0,_gtty / r1 will have offset to tty block, r2 has source
+        mov    r2,-(sp)
+        mov    r1,-(sp) / put r1 and r2 on the stack
+1: / flush the clist wait till typewriter is quiescent
+        mov    (sp),r1 / restore r1 to tty block offset
+        movb   tty+3(r1),0f / put cc offset into getc argument
+        mov    $240,*$ps / set processor priority to 5
+        jsr    r0,getc; 0:../ put character from clist in r1
+               br .+4 / list empty, skip branch
+        br     1b / get another character until list is empty
+        mov    0b,r1 / move cc offset to r1
+        inc    r1 / bump it for output clist
+        tstb   cc(r1) / is it 0
+        beq    1f / yes, no characters to output
+        mov    r1,0f / no, put offset in sleep arg
+        jsr    r0,sleep; 0:.. / put tty output process to sleep
+        br     1b / try to calm it down again
+1:
+        mov    (sp)+,r1
+        mov    (sp)+,r2 / restore registers
+        mov    (r2)+,r3 / put reader control status in r3
+        beq    1f / if 0, 1f
+        mov    r3,rcsr(r1) / move r.c. status to reader control status
+                           / register
+1:
+        mov    (r2)+,r3 / move pointer control status to r3
+        beq    1f / if 0 1f
+        mov    r3,tcsr(r1) / move p.c. status to printer control status reg
+1:
+        mov    (r2)+,tty+4(r1) / move to flag byte of tty block
+        jmp     sysret2 / return to user
+
+sysgtty: / get status of typewriter; 3 consequtive word arguments
+        jsr    r0,_gtty / r1 will have offset to tty block, r2 has
+                       / destination
+        mov    rcsr(r1),(r2)+ / put reader control status in 1st word
+                              / of dest
+        mov    tcsr(r1),(r2)+ / put printer control status in 2nd word
+                              / of dest
+        mov    tty+4(r1),(r2)+ / put mode in 3rd word
+        jmp    sysret2 / return to user
+
+_gtty:
+        jsr    r0,arg; u.off / put first arg in u.off
+        mov    *u.r0,r1 / put file descriptor in r1
+        jsr    r0,getf / get the i-number of the file
+        tst    r1 / is it open for reading
+        bgt    1f / yes
+        neg    r1 / no, i-number is negative, so make it positive
+1:
+        sub    $14.,r1 / get i-number of tty0
+        cmp    r1,$ntty-1 / is there such a typewriter
+        bhis   error9 / no, error
+        asl    r1 / 0%2
+        asl    r1 / 0%4 / yes
+        asl    r1 / 0%8 / multiply by 8 so r1 points to tty block
+        mov    u.off,r2 / put argument in r2
+        rts    r0 / return
diff --git a/u2.s b/u2.s
new file mode 100644 (file)
index 0000000..4001856
--- /dev/null
+++ b/u2.s
@@ -0,0 +1,585 @@
+/ u2 -- unix
+
+syslink: / name1, name2
+       jsr     r0,arg2 / u.namep has 1st arg u.off has 2nd
+       jsr     r0,namei / find the i-number associated with the 1st 
+                         / path name
+       br      error9 / cannot be found
+       jsr     r0,iget / get the i-node into core
+       mov     (sp)+,u.namep / u.namep points to 2nd name
+       mov     r1,-(sp) / put i-number of name1 on the stack (a link
+                        / to this file is to be created)
+       mov     cdev,-(sp) / put i-nodes device on the stack
+       jsr     r0,isdir / is it a directory
+       jsr     r0,namei / no, get i-number of name2
+               br .+4   / not found so r1-i-number of current directory
+                        /              ii = i-number of current directory
+       br      error9 / file already exists., error
+       cmp     (sp)+,cdev / u.dirp now points to end of current directory
+       bne     error9
+       mov     (sp),u.dirbuf / i-number of name1 into u.dirbuf
+       jsr     r0,mkdir / make directory entry for name2 in current 
+                         /directory
+       mov     (sp)+,r1 / r1 has i-number of name1
+       jsr     r0,iget / get i-node into core
+       incb    i.nlks / add 1 to its number of links
+       jsr     r0,setimod / set the i-node modified flag
+       
+sysret9:
+       jmp     sysret / see 'sysret' routine
+error9:
+       jmp     error / see 'error' routine
+
+isdir: / if the i-node whose i-number is in r1 is a directory there is an
+       / error unless super user made the call
+       tstb    u.uid / super user
+       beq     1f / yes, don't care
+       mov     ii,-(sp) / put current i-number on stack
+       jsr     r0,iget / get i-node into core (i-number in r1)
+       bit     $40000,i.flgs / is it a directory
+       bne     error9 / yes, error
+       mov     (sp)+,r1 / no, put current i-number in r1 (ii)
+       jsr     r0,iget / get it back in
+1:
+       rts     r0
+
+sysunlink: / name - remove link name
+       jsr     r0,arg; u.namep / u.namep points to name
+       jsr     r0,namei / find the i-number associated with the path name
+               br error9 / not found
+       mov     r1,-(sp) / put its i-number on the stack
+       jsr     r0,isdir / is it a directory
+       clr     u.dirbuf / no, clear the location that will get written
+                       / into the i-number portion of the entry
+       sub     $10.,u.off / move u.off back 1 directory entry
+       jsr     r0,wdir / free the directory entry
+       mov     (sp)+,r1 / get i-number back
+       jsr     r0,iget / get i-node
+       jsr     r0,setimod / set modified flag
+       decb    i.nlks / decrement the number of links
+       bgt     sysret9 / if this was not the last link to file return
+       jsr     r0,anyi / if it was, see if anyone has it open.  Then
+                       / free contents of file and destroy it.
+       br      sysret9
+
+mkdir:
+       jsr     r0,copyz; u.dirbuf+2; u.dirbuf+10. / clear this
+       mov     u.namep,r2 / r2 points to name of directory entry
+       mov     $u.dirbuf+2,r3 / r3 points to u.dirbuf+2
+1: / put characters in the directory name in u.dirbuf+2 - u.dirbuf+10
+       movb     (r2)+,r1 / move character in name to r1
+       beq     1f / if null, done
+       cmp     r1,$'/ / is it a "/"?
+       beq     error9 / yes, error
+       cmp     r3,$u.dirbuf+10. / have we reached the last slot for
+                                / a char?
+       beq     1b / yes, go back
+       movb    r1,(r3)+ / no, put the char in the u.dirbuf
+       br      1b / get next char
+1:
+       mov     u.dirp,u.off / pointer to empty current directory slot to 
+                            /u.off
+                            
+wdir:
+       mov     $u.dirbuf,u.base / u.base points to created file name
+       mov     $10.,u.count / u.count = 10
+       mov     ii,r1 / r1 has i-number of current directory
+       jsr     r0,access; 1 / get i-node and set its file up for writing
+       jsr     r0,writei / write into directory
+       rts     r0
+       
+sysexec:
+       jsr     r0,arg2 / arg0 in u.namep,arg1 on top of stack
+       jsr     r0,namei / namei returns i-number of file named in 
+                        / sysexec call in r1
+               br error9
+       jsr     r0,iget / get i-node for file to be executed
+       bit     $20,i.flgs / is file executable
+       beq     error9
+       jsr     r0,iopen / gets i-node for file with i-number given in 
+                        / r1 (opens file)
+       bit     $40,i.flgs / test user id on execution bit
+       beq     1f
+       tstb    u.uid / test user id
+       beq     1f / super user
+       movb    i.uid,u.uid / put user id of owner of file as process 
+                           / user id
+1:
+       mov     (sp)+,r5 / r5 now contains address of list of pointers to 
+                        / arguments to be passed
+       mov     $1,u.quit / u.quit determines handling of quits;
+                         / u.quit = 1 take quit
+       mov     $1,u.intr / u.intr determines handling of interrupts;
+                         / u.intr = 1 take interrupt
+       mov     $rtssym,30 / emt trap vector set to take system routine
+       mov     $fpsym,*10 / reserved instruction trap vector set to take 
+                          / system routine
+       mov     $sstack,sp / stack space used during swapping
+       mov     r5,-(sp) / save arguments pointer on stack
+       mov     $ecore,r5 / r5 has end of core
+       mov     $core,r4 / r4 has start of users core
+       mov     r4,u.base / u.base has start of users core
+       mov     (sp),r2 / move arguments list pointer into r2
+1:
+       tst     (r2)+ / argument char = "nul"
+       bne     1b
+       tst     -(r2) / decrement r2 by 2; r2 has addr of end of arguent 
+                     / pointer list
+1: / move arguments to bottom of users core
+       mov     -(r2),r3 / (r3) last non zero argument ptr
+       cmp     r2,(sp) / is r2 = beginning of argument ptr list
+       blo     1f / branch to 1f when all arguments are moved
+2:
+       tstb    (r3)+
+       bne     2b / scan argument for \0 (nul)
+2:
+       movb    -(r3),-(r5) / move argument char by char starting at 
+                           / "ecore"
+       cmp     r3,(r2) / moved all characters in this argument
+       bhi     2b / branch 2b if not
+       mov     r5,(r4)+ / move r5 into top of users core; r5 has 
+                        / pointer to nth arg
+       br      1b / string
+1:
+       clrb    -(r5)
+       bic     $1,r5 / make r5 even, r5 points to last word of argument 
+                     / strings
+       mov     $core,r2
+1: / move argument pointers into core following argument strings
+       cmp     r2,r4
+       bhis    1f / branch to 1f when all pointers are moved
+       mov     (r2)+,-(r5)
+       br      1b
+1:
+       sub     $core,r4 / gives number of arguments *2
+       asr     r4 / divide r4 by 2 to calculate the number of args stored
+       mov     r4,-(r5) / save number of arguments ahead of the argument 
+                        / pointers
+       clr     -(r5) / popped into ps when rti in sysrele is executed
+       mov     $core,-(r5) / popped into pc when rti in sysrele 
+                           / is executed
+       mov     r5,0f / load second copyz argument
+       tst     -(r5) / decrement r5
+       mov     r5,u.r0 /
+       sub     $16.,r5 / skip 8 words
+       mov     r5,u.sp / assign user stack pointer value, effectively
+                       / zeroes all regs when sysrele is executed
+       jsr     r0,copyz; core; 0:0 / zero user's core
+       clr     u.break
+       mov     r5,sp / point sp to user's stack
+       mov     $14,u.count
+       mov     $u.off,u.fofp
+       clr     u.off / set offset in file to be read to zero
+       jsr     r0,readi / read in first six words of user's file, starting 
+                        / at $core
+       mov     sp,r5 / put users stack address in r5
+       sub     $core+40.,r5 / subtract $core +40, from r5 (leaves
+                            / number of words less 26 available for
+                            / program in user core
+       mov     r5,u.count /
+
+       / 0407 binary support added may 2008.
+       br      1f
+bsz:   0       / XXX is there a reg that I can use over a call to readi?
+1:
+       cmp     core,$407
+       bne     e407
+       add     $4,u.off / skip last two header words
+       mov     $core,r4
+       mov     r4,u.base / continue reading at core.
+       mov     core+2,r5
+       add     core+4,r5 / r5 = text+data size
+       mov     core+6,bsz / save bss size, we're going to overwrite core
+       / XXX fix me, I dont quite understand what to do here or
+       / what is done in the similar code below e407:
+       / cmp   r5, u.count / see if theres enough room
+       / bgt   1f
+       mov     r5,u.count / read text+data into core
+       jsr     r0,readi
+       mov     u.nread,u.break / break = core + nread + bss
+       add     $core,u.break
+       add     bsz,u.break
+       jsr     r0,iclose
+       br      sysret3
+e407:
+       / end 0407 support
+
+       cmp     core,$405 / br .+14 is first instruction if file is
+                         / standard a.out format
+       bne     1f / branch, if not standard format
+       mov     core+2,r5 / put 2nd word of users program in r5; number of
+                         / bytes in program text
+       sub     $14,r5 / subtract 12
+       cmp     r5,u.count /
+       bgt     1f / branch if r5 greater than u.count
+       mov     r5,u.count
+       jsr     r0,readi / read in rest of user's program text
+       add     core+10,u.nread / add size of user data area to u.nread
+       br      2f
+1:
+       jsr     r0,readi / read in rest of file
+2:
+       mov     u.nread,u.break / set users program break to end of 
+                               / user code
+       add     $core+14,u.break / plus data area
+       jsr     r0,iclose / does nothing
+       br      sysret3 / return to core image at $core
+       
+sysfstat: / set status of open file
+       jsr     r0,arg; u.off / put buffer address in u.off
+       mov     u.off,-(sp) / put buffer address on the stack
+       mov     *u.r0,r1 / put file descriptor in r1
+       jsr     r0,getf / get the files i-number
+       tst     r1 / is it 0?
+       beq     error3 / yes, error
+       bgt     1f / if i-number is negative (open for writing)
+       neg     r1 / make it positive, then branch
+       br      1f / to 1f
+       
+sysstat: / ; name of file; buffer - get files status
+       jsr     r0,arg2 / get the 2 arguments
+       jsr     r0,namei / get the i-number for the file
+               br error3 / no such file, error
+1:
+       jsr     r0,iget / get the i-node into core
+       mov     (sp)+,r3 / move u.off to r3 (points to buffer)
+       mov     r1,(r3)+ / put i-number in 1st word of buffer
+       mov     $inode,r2 / r2 points to i-node
+1:
+       mov     (r2)+,(r3)+ / move rest of i-node to buffer
+       cmp     r2,$inode+32 / done?
+       bne     1b / no, go back
+       br      sysret3 / return through sysret
+       
+error3:
+       jmp     error / see 'error' routine
+sysret3:
+       jmp     sysret / see 'sysret' routine
+
+getf: / get the device number and the i-number of an open file
+       cmp     r1,$10. / user limited to 10 open files
+       bhis    error3 / u.fp is table of users open files, index in 
+                      / fsp table
+       movb    u.fp(r1),r1 / r1 contains number of entry in fsp table
+       beq     1f / if its zero return
+       asl     r1
+       asl     r1 / multiply by 8 to get index into fsp table entry
+       asl     r1
+       add     $fsp-4,r1 / r1 is pointing at the 3rd word in the fsp entry
+       mov     r1,u.fofp / save address of 3rd word in fsp entry in u.fofp
+       mov     -(r1),cdev / remove the device number  cdev
+       mov     -(r1),r1 / and the i-number  r1
+1:
+       rts     r0
+
+namei:
+       mov     u.cdir,r1 / put the i-number of current directory in r1
+       mov     u.cdev,cdev / device number for users directory into cdev
+       cmpb    *u.namep,$'/ / is first char in file name a /
+       bne     1f
+       inc     u.namep / go to next char
+       mov     rootdir,r1 / put i-number of rootdirectory in r1
+       clr     cdev / clear device number
+1:
+       tstb    *u.namep / is the character in file name a nul
+       beq     nig / yes, end of file name reached; branch to "nig"
+1:
+       jsr     r0,access; 2 / get i-node with i-number r1
+       bit     $40000,i.flgs / directory i-node?
+       beq     error3 / no, got an error
+       mov     i.size,u.dirp / put size of directory in u.dirp
+       clr     u.off / u.off is file offset used by user
+       mov     $u.off,u.fofp / u.fofp is a pointer to the offset portion 
+                             / of fsp entry
+2:
+       mov     $u.dirbuf,u.base / u.dirbuf holds a file name copied from 
+                                / a directory
+       mov     $10.,u.count / u.count is byte count for reads and writes
+       jsr     r0,readi / read 10. bytes of file with i-number (r1);
+                        / i.e. read a directory entry
+       tst     u.nread
+       ble     nib / gives error return
+       tst     u.dirbuf /
+       bne     3f / branch when active directory entry (i-node word in 
+                  / entry non zero)
+       mov     u.off,u.dirp
+       sub     $10.,u.dirp
+       br      2b
+3:
+       mov     u.namep,r2 / u.namep points into a file name string
+       mov     $u.dirbuf+2,r3 / points to file name of directory entry
+3:
+       movb    (r2)+,r4 / move a character from u.namep string into r4
+       beq     3f / if char is nul, then the last char in string has been 
+                  / moved
+       cmp     r4,$'/ / is char a </>
+       beq     3f
+       cmp     r3,$u.dirbuf+10. / have I checked all 8 bytes of file name
+       beq     3b
+       cmpb    (r3)+,r4 / compare char in u.namep string to file name 
+                        / char read from
+       beq     3b / directory; branch if chars match
+       br      2b / file names do not match go to next directory entry
+3:
+       cmp     r3,$u.dirbuf+10. / if equal all 8 bytes were matched
+       beq     3f
+       tstb    (r3)+ /
+       bne     2b
+3:
+       mov     r2,u.namep / u.namep points to char following a / or nul
+       mov     u.dirbuf,r1 / move i-node number in directory entry to r1
+       tst     r4 / if r4 = 0 the end of file name reached, if r4 = </>
+                  / then go to next directory
+       bne     1b
+
+nig:
+       tst     (r0)+ / gives non-error return
+nib:
+       rts     r0
+
+syschdir: / makes the directory specified in the argument the current 
+         / directory
+       jsr     r0,arg; u.namep / u.namep points to path name
+       jsr     r0,namei / find its i-number
+               br error3
+       jsr     r0,access; 2 / get i-node into core
+       bit     $40000,i.flgs / is it a directory?
+       beq     error3 / no error
+       mov     r1,u.cdir / move i-number to users current directory
+       mov     cdev,u.cdev / move its device to users current device
+       br      sysret3
+       
+isown:
+       jsr     r0,arg2 / u.namep points to file name
+       jsr     r0,namei / get its i-number
+               br error3
+       jsr     r0,iget / get i-node into core
+       tstb    u.uid / super user?
+       beq     1f / yes, branch
+       cmpb    i.uid,u.uid / no, is this the owner of the file
+       beq     1f / yes
+       jmp     error3 / no, error
+1:
+       jsr     r0,setimod / indicates i-node has been modified
+       mov     (sp)+,r2 / mode is put in r2 (u.off put on stack with 
+                        / 2nd arg)
+       rts     r0
+
+syschmod: / name; mode
+       jsr     r0,isown / get the i-node and check user status
+       bit     $40000,i.flgs / directory?
+       beq     2f / no
+       bic     $60,r2 / su & ex / yes, clear set user id and 
+                                / executable modes
+2:
+       movb    r2,i.flgs / move remaining mode to i.flgs
+       br      1f
+
+syschown: / name; owner
+       jsr     r0,isown / get the i-node and check user status
+       tstb    u.uid / super user
+       beq     2f / yes, 2f
+       bit     $40,i.flgs / no, set userid on execution?
+       bne     3f / yes error, could create Trojan Horses
+2:
+       movb    r2,i.uid / no, put the new owners id in the i-node
+1:
+       jmp     sysret4
+3:
+       jmp     error
+
+arg:
+       mov     u.sp,r1
+       mov     *18.(r1),*(r0)+ / put argument of system call into 
+                               / argument of arg2
+       add     $2,18.(r1) / point pc on stack to next system argument
+       rts     r0
+       
+arg2:
+       jsr     r0,arg; u.namep / u.namep contains value of first arg in 
+                               / sys call
+       jsr     r0,arg; u.off / u.off contains value of second arg in 
+                             / sys call
+       mov     r0,r1 / r0 points to calling routine
+       mov     (sp),r0 / put operation code back in r0
+       mov     u.off,(sp) / put pointer to second argument on stack
+       jmp     (r1) / return to calling routine
+
+systime: / get time of year
+       mov     s.time,4(sp)
+       mov     s.time+2,2(sp) / put the present time on the stack
+       br      sysret4
+
+sysstime: / set time
+       tstb    u.uid / is user the super user
+       bne     error4 / no, error
+       mov     4(sp),s.time
+       mov     2(sp),s.time+2 / set the system time
+       br      sysret4
+       
+sysbreak: / set the program break
+       mov     u.break,r1 / move users break point to r1
+       cmp     r1,$core / is it the same or lower than core?
+       blos    1f / yes, 1f
+       cmp     r1,sp / is it the same or higher than the stack?
+       bhis    1f / yes, 1f
+       bit     $1,r1 / is it an odd address
+       beq     2f / no, its even
+       clrb    (r1)+ / yes, make it even
+2: / clear area between the break point and the stack
+       cmp     r1,sp / is it higher or same than the stack
+       bhis    1f / yes, quit
+       clr     (r1)+ / clear word
+       br      2b / go back
+1:
+       jsr     r0,arg; u.break / put the "address" in u.break (set new 
+                               / break point)
+       br      sysret4 / br sysret
+       
+maknod: / r1 contains the mode
+       bis     $100000,r1 / allocate flag set
+       mov     r1,-(sp) / put mode on stack
+       mov     ii,r1 / move current i-number to r1
+       jsr     r0,access; 1 / get its i-node into core
+       mov     r1,-(sp) / put i-number on stack
+       mov     $40.,r1 / r1 = 40
+1: / scan for a free i-node (next 4 instructions)
+       inc     r1 / r1 = r1 + 1
+       jsr     r0,imap / get byte address and bit position in inode map in 
+                       / r2 & m
+       bitb    mq,(r2) / is the i-node active
+       bne     1b / yes, try the next one
+       bisb    mq,(r2) / no, make it active (put a 1 in the bit map)
+       jsr     r0,iget / get i-node into core
+       tst     i.flgs / is i-node already allocated
+       blt     1b / yes, look for another one
+       mov     r1,u.dirbuf / no, put i-number in u.dirbuf
+       mov     (sp)+,r1 / get current i-number back
+       jsr     r0,iget / get i-node in core
+       jsr     r0,mkdir / make a directory entry in current directory
+       mov     u.dirbuf,r1 / r1 = new inode number
+       jsr     r0,iget / get it into core
+       jsr     r0,copyz; inode; inode+32. / 0 it out
+       mov     (sp)+,i.flgs / fill flags
+       movb    u.uid,i.uid / user id
+       movb    $1,i.nlks / 1 link
+       mov     s.time,i.ctim / time created
+       mov     s.time+2,i.ctim+2 / time modified
+       jsr     r0,setimod / set modified flag
+       rts     r0 / return
+       
+sysseek: / moves read write pointer in an fsp entry
+       jsr     r0,seektell / get proper value in u.count
+       add     u.base,u.count / add u.base to it
+       mov     u.count,*u.fofp / put result into r/w pointer
+       br      sysret4
+       
+systell: / get the r/w pointer
+       jsr     r0,seektell
+       br      error4
+       
+error4:
+       jmp     error / see 'error' routine
+sysret4:
+       jmp     sysret / see 'sysret' routine
+       
+seektell:
+       jsr     r0,arg; u.base / puts offset in u.base
+       jsr     r0,arg; u.count / put ptr name in u.count
+       mov     *u.r0,r1 / file descriptor in r1 (index in u.fp list)
+       jsr     r0,getf / u.fofp points to 3rd word in fsp entry
+       mov     r1,-(sp) / r1 has i-number of file, put it on the stack
+       beq     error4 / if i-number is 0, not active so error
+       bgt     .+4 / if its positive jump
+       neg     r1 / if not make it positive
+       jsr     r0,iget / get its i-node into core
+       cmp     u.count,$1 / is ptr name =1
+       blt     2f / no its zero
+       beq     1f / yes its 1
+       mov     i.size,u.count /  put number of bytes in file in u.count
+       br      2f
+1: / ptr name =1
+       mov     *u.fofp,u.count / put offset in u.count
+2: / ptrname =0
+       mov     (sp)+,r1 / i-number on stack  r1
+       rts     r0
+       
+sysintr: / set interrupt handling
+       jsr     r0,arg; u.intr / put the argument in u.intr
+       br      1f / go into quit routine
+sysquit:
+       jsr     r0,arg; u.quit / put argument in u.quit
+1:
+       mov     u.ttyp,r1 / move pointer to control tty buffer to r1
+       beq     sysret4 / return to user
+       clrb    6(r1) / clear the interrupt character in the tty buffer
+       br      sysret4 / return to user
+       
+syssetuid: / set process id
+       movb    *u.r0,r1 / move process id (number) to r1
+       cmpb    r1,u.ruid / is it equal to the real user id number
+       beq     1f / yes
+       tstb    u.uid / no, is current user the super user?
+       bne     error4 / no, error
+1:
+       movb    r1,u.uid / put process id in u.uid
+       movb     r1,u.ruid / put process id in u.ruid
+       br      sysret4 / system return
+       
+sysgetuid:
+       movb    u.ruid,*u.r0 / move the real user id to (u.r0)
+       br      sysret4 / systerm return, sysret
+       
+fclose:
+       mov     r1,-(sp) / put r1 on the stack (it contains the index 
+                        / to u.fp list)
+       jsr     r0,getf / r1 contains i-number, cdev has device =, u.fofp 
+                       / points to 3rd word of fsp entry
+       tst     r1 / is inumber 0?
+       beq     1f / yes, i-node not active so return
+       tst     (r0)+ / no, jump over error return
+       mov     r1,r2 / move i-number to r2
+       mov     (sp),r1 / restore value of r1 from the stack which is 
+                       / index to u.fp
+       clrb    u.fp(r1) / clear that entry in the u.fp list
+       mov     u.fofp,r1 / r1 points to 3rd word in fsp entry
+       decb    2(r1) / decrement the number of processes that have opened 
+                     / the file
+       bge     1f / if all processes haven't closed the file, return
+       mov     r2,-(sp) / put r2 on the stack (i-number)
+       clr     -4(r1) / clear 1st word of fsp entry
+       tstb    3(r1) / has this file been deleted
+       beq     2f / no, branch
+       mov     r2,r1 / yes, put i-number back into r1
+       jsr     r0,anyi / free all blocks related to i-number
+                       / check if file appears in fsp again
+2:
+       mov     (sp)+,r1 / put i-number back into r1
+       jsr     r0,iclose / check to see if its a special file
+1:
+       mov     (sp)+,r1 / put index to u.fp back into r1
+       rts     r0
+       
+anyi: / r1 contains an i-number
+       mov     $fsp,r2 / move start of fsp table to r2
+1:
+       cmp     r1,(r2) / do i-numbers match?
+       beq     1f / yes, 1f
+       neg     r1 / no complement r1
+       cmp     r1,(r2) / do they match now?
+       beq     1f / yes, transfer
+                  / i-numbers do not match
+       add     $8,r2 / no, bump to next entry in fsp table
+       cmp     r2,$fsp+[nfiles*8] / are we at last entry in the table
+       blt     1b / no, check next entries i-number
+       tst     r1 / yes, no match
+       bge     .+4
+       neg     r1 / make i-number positive
+       jsr     r0,imap / get address of allocation bit in the i-map in r2
+       bicb    mq,(r2) / clear bit for i-node in the imap
+       jsr     r0,itrunc / free all blocks related to i-node
+       clr     i.flgs / clear all flags in the i-node
+       rts     r0 / return
+1: / i-numbers match
+       incb    7(r2) / increment upper byte of the 4th word
+       rts     r0 / in that fsp entry (deleted flag of fsp entry)
diff --git a/u3.s b/u3.s
new file mode 100644 (file)
index 0000000..3aecda7
--- /dev/null
+++ b/u3.s
@@ -0,0 +1,181 @@
+/ u3 -- unix
+
+tswap:
+       movb    u.uno,r1 / move users process number to r1
+       mov     $runq+4,r2 / move lowest priority queue address to r2
+       jsr     r0,putlu / create link from last user on Q to u.uno's user
+swap:
+       mov     $300,*$ps / processor priority = 6
+       mov     $runq,r2 / r2 points to runq table
+1: / search runq table for highest priority process
+       tst     (r2)+ / are there any processes to run in this Q entry
+       bne     1f / yes, process 1f
+       cmp     r2,$runq+6 / if zero compare address to end of table
+       bne     1b / if not at end, go back
+       jsr     r0,idle; s.idlet+2 / wait for interrupt; all queues
+                                  / are empty
+       br      swap
+1:
+       tst     -(r2) / restore pointer to right Q entry
+       mov     r2,u.pri / set present user to this run queue
+       movb    (r2)+,r1 / move 1st process in queue to r1
+       cmpb    r1,(r2)+ / is there only 1 process in this Q to be run
+       beq     1f / yes
+       tst     -(r2) / no, pt r2 back to this Q entry
+       movb    p.link-1(r1),(r2) / move next process in line into
+                                 / run queue
+       br      2f
+1:
+       clr     -(r2) / zero the entry; no processes on the Q
+2: / write out core to appropriate disk area and read in new process if
+   / required
+       clr     *$ps / clear processor status
+       cmpb    r1,u.uno / is this process the same as the process in core?
+       beq     2f / yes, don't have to swap
+       mov     r0,-(sp) / no, write out core; save r0 (address in rout.
+                        / that called swap)
+       mov     sp,u.usp / save stack pointer
+       mov     $sstack,sp / move swap stack pointer to the stack pointer
+       mov     r1,-(sp) / put r1 (new process #) on the stack
+       tstb    u.uno / is the process # = 0
+       beq     1f / yes, kill process by overwriting
+       jsr     r0,wswap / write out core to disk
+1: 
+       mov     (sp)+,r1 / restore r1 to new process number
+       jsr     r0,rswap / read new process into core
+       jsr     r0,unpack / unpack the users stack from next to his program
+                         / to its normal
+       mov     u.usp,sp / location; restore stack pointer to new process
+                        / stack
+       mov     (sp)+,r0 / put address of where the process that just got
+                        / swapped in, left off., i.e., transfer control
+                        / to new process
+2:
+       movb    $30.,uquant / initialize process time quantum
+       rts     r0 / return
+
+wswap:
+       mov     *$30,u.emt / determines handling of emts
+       mov     *$10,u.ilgins / determines handling of illegal instructions
+       mov     u.break,r2 / put process program break address in r2
+       inc     r2 / add 1 to it 
+       bic     $1,r2 / make it even
+       mov     r2,u.break / set break to an even location
+       mov     u.usp,r3 / put users stack pter at moment of swap in r3
+       cmp     r2,$core / is u.break less than $core
+       blos    2f / yes
+       cmp     r2,r3 / no, is (u.break) greater than stack pointer
+       bhis    2f / yes
+1:
+       mov     (r3)+,(r2)+ / no, pack stack next to users program
+       cmp     r3,$ecore / has stack reached end of core
+       bne     1b / no, keep packing
+       br      1f / yes
+2: 
+       mov     $ecore,r2 / put end of core in r2 
+1:
+       sub     $user,r2 / get number of bytes to write out (user up
+                        / to end of stack gets written out)
+       neg     r2 / make it negative
+       asr     r2 / change bytes to words (divide by 2)
+       mov     r2,swp+4 / word count
+       movb    u.uno,r1 / move user process number to r1
+       asl     r1 / x2 for index
+       mov     r2,p.break-2(r1) / put negative of word count into the
+                                       / p.break table
+       mov     p.dska-2(r1),r1 / move disk address of swap area for
+                               / process to r1
+       mov     r1,swp+2 / put processes dska address in swp +2 (block
+                        / number)
+       bis     $1000,swp / set it up to write (set bit 9)
+       jsr     r0,ppoke / write process out on swap area of disk
+1:
+       tstb    swp+1 / is lt done writing?
+       bne     1b / no, wait
+       rts     r0 / yes, return to swap
+
+rswap:
+       asl     r1 / process number x2 for index
+       mov     p.break-2(r1), swp+4 / word count
+       mov     p.dska-2(r1),swp+2 / disk address
+       bis     $2000,swp / read
+       jsr     r0,ppoke / read it in 
+1:
+       tstb    swp+1 / done
+       bne     1b / no, wait for bit 15 to clear (inhibit bit)
+       mov     u.emt,*$30 / yes move these
+       mov     u.ilgins,*$10 / back
+       rts     r0 / return
+
+unpack: / move stack back to its normal place
+       mov     u.break,r2 / r2 points to end of user program
+
+       cmp     r2,$core / at beginning of user program yet?
+       blos    2f / yes, return
+       cmp     r2,u.usp / is break_above the "stack pointer before
+                        / swapping"
+       bhis    2f / yes, return
+       mov     $ecore,r3 / r3 points to end of core
+       add     r3,r2
+       sub     u.usp,r2 / end of users stack is in r2
+1:
+       mov     -(r2),-(r3) / move stack back to its normal place
+       cmp     r2,u.break / in core
+       bne     1b
+2:
+       rts     r0
+
+putlu: / r1 = user process no.; r2 points to lowest priority queue
+       tstb    (r2)+ / is queue empty?
+       beq     1f / yes, branch
+       movb    (r2),r3 / no, save the "last user" process number in r3
+       movb    r1,p.link-1(r3) / put pointer to user on "last users" link
+       br      2f /
+1:
+       movb    r1,-1(r2) / user is only user; put process no. at beginning
+                         / and at end
+2: 
+       movb    r1,(r2) / user process in r1 is now the last entry on
+                       / the queue
+       dec     r2 / restore r2
+       rts     r0
+
+copyz:
+       mov     r1,-(sp) / put r1 on stack
+       mov     r2,-(sp) / put r2 on stack
+       mov     (r0)+,r1
+       mov     (r0)+,r2
+1:
+       clr     (r1)+ / clear all locations between r1 and r2
+       cmp     r1,r2 
+       blo     1b
+       mov     (sp)+,r2 / restore r2
+       mov     (sp)+,r1 / restore r1
+       rts     r0 
+
+idle:
+       mov     *$ps,-(sp) / save ps on stack
+       clr     *$ps / clear ps
+       mov     clockp,-(sp) / save clockp on stack
+       mov     (r0)+,clockp / arg to idle in clockp
+       1 / wait for interrupt
+       mov      (sp)+,clockp / restore clockp, ps
+       mov     (sp)+,*$ps
+       rts     r0
+
+clear:
+       jsr       r0,wslot / get an I/O buffer set bits 9 and 15 in first
+                          / word of I/O queue r5 points to first data word
+       
+       
+                               / in buffer
+       mov     $256.,r3
+1: 
+       clr     (r5)+ / zero data word in buffer
+       dec     r3
+       bgt     1b / branch until all data words in buffer are zero
+       jsr     r0,dskwr / write zeroed buffer area out onto physical
+                         / block specified
+       rts     r0 / in r1
+
+
diff --git a/u4.s b/u4.s
new file mode 100644 (file)
index 0000000..e23aa6b
--- /dev/null
+++ b/u4.s
@@ -0,0 +1,337 @@
+/ u4 -- unix
+
+setisp:
+       mov     r1,-(sp)
+       mov     r2,-(sp)
+       mov     r3,-(sp)
+       mov     clockp,-(sp)
+       mov     $s.syst+2,clockp
+       jmp     (r0)
+
+clock: / interrupt from 60 cycle clock
+       mov     r0,-(sp) / save r0
+       tst     *$lks / restart clock?
+       mov     $s.time+2,r0 / increment the time of day
+       inc     (r0)
+       bne     1f
+       inc     -(r0)
+1:
+       mov     clockp,r0 / increment appropriate time category
+       inc     (r0)
+       bne     1f
+       inc     -(r0)
+1:
+       mov     $uquant,r0 / decrement user time quantum
+       decb    (r0)
+       bge     1f / if less than 0
+       clrb    (r0) / make it 0
+1: / decrement time out counts return now if priority was not 0
+       cmp     4(sp),$200 / ps greater than or equal to 200
+       bge     2f / yes, check time outs
+       tstb    (r0) / no, user timed out?
+       bne     1f / no
+       cmpb    sysflg,$-1 / yes, are we outside the system?
+       bne     1f / no, 1f
+       mov     (sp)+,r0 / yes, put users r0 in r0
+       sys     0 / sysrele
+       rti
+2: / priority is high so just decrement time out counts
+       mov     $toutt,r0 / r0 points to beginning of time out table
+2:
+       tstb    (r0) / is the time out?
+       beq     3f / yes, 3f (get next entry)
+       decb    (r0) / no, decrement the time
+       bne     3f / isit zero now?
+       incb    (r0) / yes, increment the time
+3:
+       inc     r0 / next entry
+       cmp     r0,$touts / end of toutt table?
+       blo     2b / no, check this entry
+       mov     (sp)+,r0 / yes, restore r0
+       rti / return from interrupt
+1: / decrement time out counts; if 0 call subroutine
+       mov     (sp)+,r0 / restore r0
+       mov     $240,*$ps / set processor priority to 5
+       jsr     r0,setisp / save registers
+       mov     $touts-toutt-1,r0 / set up r0 as index to decrement thru
+                                 / the table
+1:
+       tstb    toutt(r0) / is the time out for this entry
+       beq     2f / yes
+       decb    toutt(r0) / no, decrement the time
+       bne     2f / is the time 0, now
+       asl     r0 / yes, 2 x r0 to get word index for tout entry
+       jsr     r0,*touts(r0) / go to appropriate routine specified in this
+       asr     r0 / touts entry; set r0 back to toutt index
+2:
+       dec     r0 / set up r0 for next entry
+       bge     1b / finished? , no, go back
+       br      retisp / yes, restore registers and do a rti
+ttyi: / console tty input interrupt routine
+       jsr     r0,setisp / save reg r1, r2, r3
+       mov     *$tkb,r1 / r1 = char in tty reader buffer
+       inc     *$tks / set the reader enable bit
+       bic     $!177,r1 / clear upper 9 bits of the character (strip off
+                        / 8th bit of char)
+       cmp     r1,$'a-40 / is character upper case A,..., upper case Z.
+                         / note that
+       blt     1f / lower case a is represented by 141, upper case by
+       cmp     r1,$'z-40 / 101; and lower case z by 172, upper
+                         / case Z by 132.
+       bgt     1f / if not upper case, branch
+       add     $40,r1 / if upper case, calculate the representation of its
+                      / lower case counter part
+1:
+       cmp     r1,$175 / char = "}"? Note: may be quit char (fs)
+       beq     2f / yes 2f
+       cmp     r1,$177 / char = "del" ?
+       beq     2f / yes, 2f
+       jsr     r0,putc; 0 / put char in r1 on clist entry
+               br 1f
+       movb    r1,ttyoch / put char in ttyoch
+       jsr     r0,startty / load char in tty output data buffer
+       cmp     r1,$4 / r1 = "eot"
+       beq     1f / yes, 1f
+       cmp     r1,$12 / r1 = "lf"
+       beq     1f / yes 1f
+       cmpb    cc+0,$15. / are there less than 15 chars on the input list
+       blo     retisp / yes, return
+1:
+       jsr     r0,wakeup; runq; 0 / no, wakeup the input process
+       br      retisp / return
+2: / r1 = "}" or "delete" to get here
+       mov     tty+[ntty*8]-8+6,r2 / move console tty buffer address to r2
+       beq     2f / if 0, wakeall
+       movb    r1,6(r2) / move "}" or del into "interrupt char"
+                        / byte of buffer
+2:
+       jsr     r0,wakeall / wakeup all sleeping processes
+       br      retisp / return
+       
+       
+wakeall:
+       mov     $39.,0f / flll arg2 of wakeup call wlth 39
+1:
+       jsr     r0,wakeup; runq+4; 0:.. / wakeup the processes in the
+       dec     0b                      / wait list; decrement arg2
+       bge     1b / if not done, go back
+       rts     r0
+
+ttyo: / console typewriter output interrupt routine
+       jsr     r0,setisp / save registers
+       jsr     r0,startty / put a char on the console tty output buffer
+       br      retisp / restore registers
+
+retisp:
+       mov     (sp)+,clockp / pop values before interrupt off the stack
+       mov     (sp)+,r3
+       mov     (sp)+,r2
+       mov     (sp)+,r1
+       mov     (sp)+,r0
+       rti     / return from interrupt
+
+ppti: / paper tape lnput interrupt routine
+       jsr     r0,setisp / save registers
+       movb    pptiflg,r1 / place "pptiflg" in r1
+       jmp     *1f(r1) / jump to location speclfled by value of "pptiflg"
+1:
+       retisp / file not open
+       1f / file just opened
+       2f / file normal
+       retisp / file not closed
+
+1: / file just opened
+       tstb    *$prs+1 / is error bit set in prs
+       bge     1f / no
+       jsr     r0,pptito / place 10 in toutt entry for ppt input
+       br      retisp
+1:
+       movb    $4,pptiflg / change "pptiflg" to indicate file "normal"
+2:
+       jsr     r0,wakeup; runq+2; 2 / wakeup process for ppt input entry
+                                    / in wlist
+       tstb    *$prs+1 / is error bit set
+       blt     1f / yes
+       mov     *$prb,r1 / place contents ppt read buffer in r1
+       jsr     r0,putc; 2 / place character in clist area for ppt input
+               br .+2 / temp / if no space in clist character lost
+       cmpb    cc+2,$50. / character count in clist area for ppt lnput
+                         / greater than or equal to 50
+       bhis    retisp / yes
+       inc     *$prs / no, set reader enable bit in prs
+       br      retisp
+1:
+       movb    $6,pptiflg / set pptiflg to 6 to indicate error bit set
+       br      retisp
+
+/lpto:
+       
+       
+/      jsr     r0,setisp
+/      jsr     r0,starlpt
+/      br      retisp
+ppto: / paper tape output interrupt routine
+       jsr r0,setisp / save registers
+       jsr r0,starppt / get next character from clist, and output
+       / if possible
+       br retisp / pop register values from stack
+
+/ starlpt:
+/       cmpb   cc+5.,$100.
+/       bhi    1f
+/       jsr    r0,wakeup; runq+2; 5
+/1:
+/       tstb   *$lps
+/       bge    1f
+/       jsr    r0,getc; 5
+/              br 1f
+/       mov    r1,*$lpb
+/       br     starlpt
+/1:
+/       rts    r0
+
+startty: / start or restart console tty output
+       cmpb    cc+1,$5.
+       bhi     1f / branch to 1f when character count on tty (? input,
+                  / output) list is greater than 5.
+       jsr     r0,wakeup; runq+2; 1
+1:
+       tstb    *$tps / test console output ready bit
+       bge     2f / branch if ready bit is clear
+       tstb    toutt+0 / is toutt for console a zero
+       bne     2f / if not; branch to 2f
+       movb    ttyoch,r1 / put character to be output in r1
+       bne     1f
+       jsr     r0,getc; 1 / if char is nul, get a char from console
+                          / output list
+               br 2f / if console output list is empty, branch to 2f
+1:
+       clrb    ttyoch
+       mov     r1,*$tpb / put character in console output register
+       cmp     r1,$12 / is char a line feed
+       bne     1f
+       movb    $15,ttyoch / put a cr in ttyoch
+1:
+       cmp     r1,$11 / char = ht
+       bne     1f
+       movb    $15.,toutt+0 / set time out to 15 clock tics
+1:
+       cmp     r1,$15 / char = cr
+       bne     2f
+       movb    $15.,toutt+0 / set time out to 15 clock ticks
+2:
+       rts     r0
+pptito: / paper tape input touts subrouting
+       cmpb    pptiflg,$2 / does "pptiflg" indicate file just opened
+       bne     1f / no, do nothing pyf
+       movb    $10.,toutt+1 / yes, place 10 in tout entry for tty input
+       tstb    *$prs+1 / is error bit set
+       blt     1f / yes, return
+       inc     *$prs / no, set read enable bit
+1:
+       rts     r0
+
+starppt: / start ppt output
+       cmpb    cc+3,$10. / is character count for ppt output greater
+                         / than 10.
+       bhi     1f / yes, branch
+       jsr     r0,wakeup; runq+2; 3 / no, wakeup process in wlist
+                                    / entry for ppt input
+1:
+       tstb    *$pps / is ready bit set in punch status word
+       bge     1f / no, branch
+       jsr     r0,getc; 3 / yes, get next char in clist for pptout and
+                                 / place in r1
+       br      1f / if none, branch
+       mov     r1,*$ppb / place character in ppt buffer
+1:
+       rts r0
+
+wakeup: / wakeup processes waiting for an event by linking them to the
+       / queue
+       mov     r1,-(sp) / put char on stack
+       mov     (r0)+,r2 / r2 points to a queue
+       mov     (r0)+,r3 / r3 = wait channel number
+       movb    wlist(r3),r1 / r1 contains process number in that wait
+                            / channel that was sleeping
+       beq     2f / if 0 return, nothing to wakeup
+       cmp     r2,u.pri / is runq greater than or equal to users process
+                               / priority
+       bhis    1f / yes, don't set time quantum to zero
+       clrb    uquant / time quantum = 0
+1:
+       clrb    wlist(r3) / zero wait channel entry
+       jsr     r0,putlu / create a link from the last user on the Q
+                        / to this process number that got woken
+2:
+       mov     (sp)+,r1 / restore r1
+       rts     r0
+
+sleep: / wait for event
+       jsr     r0,isintr / check to see if interrupt or quit from user
+               br 2f / something happened / yes, his interrupt so return
+                     / to user
+       mov     (r0)+,r1 / put number of wait channel in r1
+       movb    wlist(r1),-(sp) / put old process number in there, on
+                               / the stack
+       movb    u.uno,wlist(r1) / put process number of process to put
+                              / to sleep in there
+       mov     cdev,-(sp) / nothing happened in isintr so
+       jsr     r0,swap / swap out process that needs to sleep
+       mov     (sp)+,cdev / restore device
+       jsr     r0,isintr / check for interrupt of new process
+               br      2f / yes, return to new user
+       movb    (sp)+,r1 / no, r1 = old process number that was originally
+                        / on the wait channel
+       beq     1f / if 0 branch
+       mov     $runq+4,r2 / r2 points to lowest priority queue
+       mov     $300,*$ps / processor priority = 6
+       jsr     r0,putlu / create link to old process number
+       clr     *$ps / clear the status; process priority = 0
+1:
+       rts     r0 / return
+2:
+       jmp     sysret / return to user
+
+isintr:
+       mov     r1,-(sp) / put number of wait channel on the stack
+       mov     r2,-(sp) / save r2
+       mov     u.ttyp,r1 / r1 = pointer to buffer of process control
+                         / typewriter
+       beq     1f / if 0, do nothing except skip return
+       movb    6(r1),r1 / put interrupt char in the tty buffer in r1
+       beq     1f / if its 0 do nothing except skip return
+       cmp     r1,$177 / is interrupt char = delete?
+       bne     3f / no, so it must be a quit (fs)
+       tst     u.intr / yes, value of u.intr determines handling
+                      / of interrupts
+       bne     2f / if not 0, 2f. If zero do nothing.
+1:
+       tst     (r0)+ / bump r0 past system return (skip)
+4:
+       mov     (sp)+,r2 / restore r1 and r2
+       mov     (sp)+,r1
+       rts     r0
+3: / interrupt char = quit (fs)
+       tst     u.quit / value of u.quit determines handling of quits
+       beq     1b / u.quit = 0 means do nothing
+2: / get here because either u.intr <> 0 or u.qult <> O
+       mov     $tty+6,r1 / move pointer to tty block into r1
+1: / find process control tty entry in tty block
+       cmp     (r1),u.ttyp / is this the process control tty buffer?
+       beq     1f / block found go to 1f
+       add     $8,r1 / look at next tty block
+       cmp     r1,$tty+[ntty*8]+6 / are we at end of tty blocks
+       blo     1b / no
+       br      4b / no process control tty found so go to 4b
+1:
+       mov     $240,*$ps / set processor priority to 5
+       movb    -3(r1),0f / load getc call argument; character llst
+                          / identifier
+       inc     0f / increment
+1:
+       jsr     r0,getc; 0:.. / erase output char list for control
+               br 4b / process tty. This prevents a line of stuff
+                     / being typed out after you hit the interrupt
+                     / key
+       br      1b
diff --git a/u5.s b/u5.s
new file mode 100644 (file)
index 0000000..26dd206
--- /dev/null
+++ b/u5.s
@@ -0,0 +1,323 @@
+/ u5 -- unix
+
+mget:
+       mov     *u.fofp,mq / file offset in mq
+       clr     ac / later to be high sig
+       mov     $-8,lsh   / divide ac/mq by 256.
+       mov     mq,r2
+       bit     $10000,i.flgs / lg/sm is this a large or small file
+       bne     4f / branch for large file
+       bit     $!17,r2
+       bne     3f / branch if r2 greater than or equal to 16
+       bic     $!16,r2 / clear all bits but bits 1,2,3
+       mov     i.dskp(r2),r1 / r1 has physical block number
+       bne     2f / if physical block num is zero then need a new block
+                  / for file
+       jsr     r0,alloc / allocate a new block
+       mov     r1,i.dskp(r2) / physical block number stored in i-node
+       jsr     r0,setimod / set inode modified byte (imod)
+       jsr     r0,clear / zero out disk/drum block just allocated
+2:
+       rts     r0
+3: / adding on block which changes small file to a large file
+       jsr     r0,alloc / allocate a new block for this file; block number
+                        /in r1
+       jsr     r0,wslot / set up I/O buffer for write, r5 points to first
+                        / data word in buffer
+       mov     $8.,r3 / next 6 instructions transfer old physical block
+                      / pointers
+       mov     $i.dskp,r2 / into new indirect block for the new large file
+1:
+       mov     (r2),(r5)+
+       clr     (r2)+
+       dec     r3
+       bgt     1b
+       mov     $256.-8.,r3 / clear rest of data buffer
+1:
+       clr     (r5)+
+       dec     r3
+       bgt     1b
+       jsr     r0,dskwr / write new indirect block on disk
+       mov     r1,i.dskp / put pointer to indirect block in i-node
+       bis     $10000,i.flgs / set large file bit in i.flgs word of i-node
+       jsr     r0,setimod / set i-node modified flag
+       br      mget
+4: / large file
+       mov     $-8,lsh / divide byte number by 256.
+       bic     $!776,r2 / zero all bits but 1,2,3,4,5,6,7,8; gives offset
+                        / in indirect block
+       mov     r2,-(sp) / save on stack
+       mov     mq,r2 / calculate offset in i-node for pointer to proper
+                             / indirect block
+       bic     $!16,r2
+       mov     i.dskp(r2),r1
+       bne     2f / if no indirect block exists
+       jsr     r0,alloc / allocate a new block
+       mov     r1,i.dskp(r2) / put block number of new block in i-node
+       jsr     r0,setimod / set i-node modified byte
+       jsr     r0,clear / clear new block
+2:
+       jsr     r0,dskrd / read in indirect block
+       mov     (sp)+,r2 / get offset
+       mov     r1,-(sp) / save block number of indirect block on stack
+       add     r5,r2 / r5 points to first word in indirect block, r2
+                     / points to location of inter
+       mov     (r2),r1 / put physical block no of block in file
+                       / sought in r1
+       bne     2f / if no block exists
+       jsr     r0,alloc / allocate a new block
+       mov     r1,(r2) / put new block number into proper location in
+                       / indirect block
+       mov     (sp)+,r1 / get block number of indirect block
+       mov     (r2),-(sp) / save block number of new block
+       jsr     r0,wslot
+       jsr     r0,dskwr / write newly modified indirect block back out
+                        / on disk
+       mov     (sp),r1 / restore block number of new block
+       jsr     r0,clear / clear new block
+2:
+       tst     (sp)+ / bump stack pointer
+       rts     r0
+
+alloc:
+       mov     r2,-(sp) / save r2, r3 on stack
+       mov     r3,-(sp)
+       mov     $systm,r2 / start of inode and free storage map for drum
+       tst     cdev
+       beq     1f / drum is device
+       mov     $_mount,r2 / disk or tape is device, start of inode and free
+                         / storage map
+1:
+       mov     (r2)+,r1 / first word contains number of bytes in free
+                        / storage map
+       asl     r1 / multiply r1 by eight gives, number of blocks in device
+       asl     r1
+       asl     r1
+       mov     r1,-(sp) / save # of blocks in device on stack
+       clr     r1 / r1 contains bit count of free storage map
+1:
+       mov     (r2)+,r3 / word of free storage map in r3
+       bne     1f / branch if any free blocks in this word
+       add     $16.,r1
+       cmp     r1 ,(sp) / have we examined all free storage bytes
+       blo     1b
+       jmp     panic / found no free storage
+1:
+       asr     r3 / find a free block
+       bcs     1f / branch when free block found; bit for block k is in
+                  / byte k/8 / in bit k (mod 8)
+       inc     r1 / increment bit count in bit k (mod8)
+       br      1b
+1:
+       tst     (sp)+ / bump sp
+       jsr     r0,3f / have found a free block
+       bic     r3,(r2) / set bit for this block i.e. assign block
+       br      2f
+
+free:
+       mov     r2,-(sp) / save r2, r3
+       mov     r3,-(sp)
+       jsr     r0,3f / set up bit mask and word no. in free storage map
+                     / for block
+       bis     r3,(r2) / set free storage block bit; indicates free block
+2:
+       mov     (sp)+,r3 / restore r2, r3
+       mov     (sp)+,r2
+       tst     cdev / cdev = 0, block structured, drum; cdev = 1
+                    / mountable device
+       bne     1f
+       incb    smod / set super block modified for drum
+       rts     r0
+1:
+       incb    mmod / set super block modified for mountable device
+       rts     r0
+3:
+       mov     r1,r2 / block number, k, = 1
+       bic     $!7,r2 / clear all bits but 0,1,2; r2 = (k) mod (8)
+       clr     r3
+       bisb    2f(r2),r3 / use mask to set bit in r3 corresponding to
+                         / (k) mod 8
+       mov     r1,r2 / divide block number by 16
+       asr     r2
+       asr     r2
+       asr     r2
+       asr     r2
+       bcc     1f / branch if bit 3 in r1 was 0 i.e., bit for block is in
+                  / lower half of word
+       swab    r3 / swap bytes in r3; bit in upper half of word in free
+                  / storage map
+1:
+       asl     r2 / multiply block number by 2; r2 = k/8
+       add     $systm+2,r2 / address of word of free storage map for drum
+                           / with block bit in it
+       tst     cdev
+       beq     1f / cdev = 0 indicates device is drum
+       add     $_mount-systm,r2 / address of word of free storage map for
+                               / mountable device with bit of block to be
+                               / freed
+1:
+       rts     r0 / return to 'free'
+2:
+       .byte   1,2,4,10,20,40,100,200 / masks for bits 0,...,7
+
+access:
+       jsr     r0,iget / read in i-node for current directory (i-number
+                       / passed in r1)
+       mov     i.flgs,r2
+       cmpb    i.uid,u.uid / is user same as owner of file
+       bne     1f / no, then branch
+       asrb    r2 / shift owner read write bits into non owner
+                  / read/write bits
+       asrb    r2
+1:
+       bit     r2,(r0)+ / test read-write flags against argument in
+                        / access call
+       bne     1f
+       tstb    u.uid
+       beq     1f
+       jmp     error
+1:
+       rts     r0
+
+setimod:
+       movb    $1,imod / set current i-node modified bytes
+       mov     s.time,i.mtim / put present time into file modified time
+       mov     s.time+2,i.mtim+2
+       rts     r0
+
+imap: / get the byte that has the allocation bit for the i-number contained
+      / in r1
+       mov     $1,mq / put 1 in the mq
+       mov     r1,r2 / r2 now has i-number whose byte in the map we
+                     / must find
+       sub     $41.,r2 / r2 has i-41
+       mov     r2,r3 / r3 has i-41
+       bic     $!7,r3 / r3 has (i-41) mod 8 to get the bit position
+       mov     r3,lsh / move the 1 over (i-41) mod 8 positions to the left
+                      / to mask the correct bit
+       asr     r2
+       asr     r2
+       asr     r2 / r2 has (i-41) base 8 of the byte no. from the start of
+                  / the map
+       mov     r2,-(sp) / put (i-41) base 8 on the stack
+       mov     $systm,r2 / r2 points to the in-core image of the super
+                         / block for drum
+       tst     cdev / is the device the disk
+       beq     1f / yes
+       add     $_mount-systm,r2 / for mounted device, r2 points to 1st word
+                               / of its super block
+1:
+       add     (r2)+,(sp) / get byte address of allocation bit
+       add     (sp)+,r2 / ?
+       add     $2,r2 / ?
+       rts     r0
+
+iget:
+       cmp     r1,ii / r1 = i-number of current flle
+       bne     1f
+       cmp     idev,cdev / is device number of i-node = current device
+       beq     2f
+1:
+       tstb    imod / has i-node of current file been modified i.e.,
+                    / imod set
+       beq     1f
+       clrb    imod / if it has, we must write the new i-node out on disk
+       mov     r1,-(sp)
+       mov     cdev,-(sp)
+       mov     ii,r1
+       mov     idev,cdev
+       jsr     r0,icalc; 1
+       mov     (sp)+,cdev
+       mov     (sp)+,r1
+1:
+       tst     r1 / is new i-number non zero
+       beq     2f / branch if r1=0
+       tst     cdev / is the current device number non zero (i.e., device
+                    / =/ drum)
+       bne     1f / branch 1f cdev =/ 0
+       cmp     r1,mnti / mnti is the i-number of the cross devlce
+                        / file (root directory of mounted devlce)
+       bne     1f
+       mov     mntd,cdev / make mounted device the current device
+       mov     rootdir,r1
+1:
+       mov     r1,ii
+       mov     cdev,idev
+       jsr     r0,icalc; 0 / read in i-node ii
+2:
+       mov     ii,r1
+       rts     r0
+
+icalc: / i-node i is located in block (i+31.)/16. and begins 32.*
+       / (i+31)mod16 bytes from its start
+       add     $31.,r1 / add 31. to i-number
+       mov     r1,-(sp) / save i+31. on stack
+       asr     r1 / divide by 16.
+       asr     r1
+       asr     r1
+       asr     r1 / r1 contains block number of block in which
+                  / i-node exists
+       jsr     r0,dskrd / read in block containing i-node i.
+       tst     (r0)
+       beq     1f / branch to wslot when argument in icalc call = 1
+       jsr     r0,wslot / set up data buffer for write (will be same buffer
+                        / as dskrd got)
+1:
+       bic     $!17,(sp) / zero all but last 4 bits; gives (i+31.) mod 16
+       mov     (sp)+,mq / calculate offset in data buffer; 32.*(i+31.)mod16
+       mov     $5,lsh / for i-node i.
+       add     mq,r5 / r5 points to first word in i-node i.
+       mov     $inode,r1 / inode is address of first word of current i-node
+       mov     $16.,r3
+       tst     (r0)+ / branch to 2 fwhen argument in icalc call = 0
+       beq     2f / r0 now contains proper return address for rts r0
+1:
+       mov     (r1)+,(r5)+ / over write old i-node
+       dec     r3
+       bgt     1b
+       jsr     r0,dskwr / write inode out on device
+       rts     r0
+2:
+       mov     (r5)+,(r1)+ / read new i-node into "inode" area of core
+       dec     r3
+       bgt     2b
+       rts     r0
+
+itrunc:
+       jsr     r0,iget
+       mov     $i.dskp,r2 / address of block pointers in r2
+1:
+       mov     (r2)+,r1 / move physical block number into r1
+       beq     5f
+       mov     r2,-(sp)
+       bit     $10000,i.flgs / test large file bit?
+       beq     4f / if clear, branch
+       mov     r1,-(sp) / save block number of indirect block
+       jsr     r0,dskrd / read in block, 1st data word pointed to by r5
+       mov     $256.,r3 / move word count into r3
+2:
+       mov     (r5)+,r1 / put 1st data word in r1; physical block number
+       beq     3f / branch if zero
+       mov     r3,-(sp) / save r3, r5 on stack
+       mov     r5,-(sp)
+       jsr     r0,free / free block in free storage map
+       mov     (sp)+,r5
+       mov     (sp)+,r3
+3:
+       dec     r3 / decrement word count
+       bgt     2b / branch if positive
+       mov     (sp)+,r1 / put physical block number of indirect block
+4:
+       jsr     r0,free / free indirect block
+       mov     (sp)+,r2
+5:
+       cmp     r2,$i.dskp+16.
+       bne     1b / branch until all i.dskp entries check
+       bic     $10000,i.flgs / clear large file bit
+       clr     i.size / zero file size
+       jsr     r0,copyz; i.dskp; i.dskp+16. / zero block pointers
+       jsr     r0,setimod / set i-node modified flag
+       mov     ii,r1
+       rts     r0
+
+
diff --git a/u6.s b/u6.s
new file mode 100644 (file)
index 0000000..b13b278
--- /dev/null
+++ b/u6.s
@@ -0,0 +1,298 @@
+/ u6 -- unix
+
+readi:
+       clr     u.nread / accumulates number of bytes transmitted
+       tst     u.count / is number of bytes to be read greater than 0
+       bgt     1f / yes, branch
+       rts     r0 / no, nothing to read; return to caller
+1:
+       mov     r1,-(sp) / save i-number on stack
+       cmp     r1,$40. / want to read a special file (i-nodes 1,...,40 are
+                   / for special files)
+       ble     1f / yes, branch
+       jmp     dskr / no, jmp to dskr; read file with i-node number (r1)
+                    / starting at byte ((u.fofp)), read in u.count bytes
+1:
+       asl     r1 / multiply inode number by 2
+       jmp     *1f-2(r1)
+1:
+       rtty / tty; r1=2
+       rppt / ppt; r1=4
+       rmem / mem; r1=6
+       rrf0 / rf0
+       rrk0 / rk0
+       rtap / tap0
+       rtap / tap1
+       rtap / tap2
+       rtap / tap3
+       rtap / tap4
+       rtap / tap5
+       rtap / tap6
+       rtap / tap7
+       rcvt / tty0
+       rcvt / tty1
+       rcvt / tty2
+       rcvt / tty3
+       rcvt / tty4
+       rcvt / tty5
+       rcvt / tty6
+       rcvt / tty7
+       rcrd/ crd
+
+rtty: / read from console tty
+       mov     tty+[8*ntty]-8+6,r5 / r5 is the address of the 4th word of
+                                   / of the control and status block
+       tst     2(r5) / for the console tty; this word points to the console
+                     / tty buffer
+       bne     1f / 2nd word of console tty buffer contains number
+                  / of chars. Is this number non-zero?
+       jsr     r0,canon; ttych / if 0, call 'canon' to get a line
+                           / (120 chars.)
+1:
+       tst     2(r5) / is the number of characters zero
+       beq     ret1 / yes, return to caller via 'ret1'
+       movb    *4(r5),r1 / no, put character in r1
+       inc     4(r5) / 3rd word of console tty buffer points to byte which
+                     / contains the next char.
+       dec     2(r5) / decrement the character count
+       jsr     r0,passc / move the character to core (user)
+       br      1b / get next character
+
+ret1:
+       jmp     ret / return to caller via 'ret'
+
+rppt: / read paper tape
+       jsr     r0,pptic / gets next character in clist for ppt input and
+                        / places
+               br ret / it in r1; if there 1s no problem with reader, it
+                      / also enables read bit in prs
+       jsr     r0,passc / place character in users buffer area
+       br      rppt
+
+rmem: / transfer characters from memory to a user area of core
+       mov     *u.fofp,r1 / save file offset which points to the char to
+                          / be transferred to user
+       inc     *u.fofp / increment file offset to point to 'next' char in
+                       / memory file
+       movb    (r1),r1 / get character from memory file, put it in r1
+       jsr     r0,passc / move this character to the next byte of the
+                        / users core area
+       br       rmem / continue
+1:
+rcrd:
+       jmp     error / see 'error' routine
+
+dskr:
+       mov     (sp),r1 / i-number in r1
+       jsr     r0,iget / get i-node (r1) into i-node section of core
+       mov     i.size,r2 / file size in bytes in r2
+       sub     *u.fofp,r2 / subtract file offset
+       blos    ret
+       cmp     r2,u.count / are enough bytes left in file to carry out read
+       bhis    1f
+       mov     r2,u.count / no, just read to end of file
+1 :
+       jsr     r0,mget / returns physical block number of block in file
+                       / where offset points
+       jsr     r0,dskrd / read in block, r5 points to 1st word of data in
+                        / buffer
+       jsr     r0,sioreg
+2:
+       movb    (r2)+,(r1)+ / move data from buffer into working core
+                           / starting at u.base
+       dec     r3
+       bne     2b / branch until proper number of bytes are transferred
+       tst     u.count / all bytes read off disk
+       bne     dskr
+       br      ret
+
+passc:
+       movb    r1,*u.base / move a character to the next byte of the
+                          / users buffer
+       inc     u.base / increment the pointer to point to the next byte
+                      / in users buffer
+       inc     u.nread / increment the number of bytes read
+       dec     u.count / decrement the number of bytes to be read
+       bne     1f / any more bytes to read?; yes, branch
+       mov     (sp)+,r0 / no, do a non-local return to the caller of
+                        / 'readi' by:
+ret: / (1) pop the return address off the stack into r0
+       mov     (sp)+,r1 / (2) pop the i-number off the stack into r1
+1:
+       clr     *$ps / clear processor status
+       rts     r0 / return to address currently on top of stack
+
+writei:
+       clr     u.nread / clear the number of bytes transmitted during
+                       / read or write calls
+       tst     u.count / test the byte count specified by the user
+       bgt     1f / any bytes to output; yes, branch
+       rts     r0 / no, return - no writing to do
+1:
+       mov     r1 ,-(sp) / save the i-node number on the stack
+       cmp     r1,$40. / does the i-node number indicate a special file?
+       bgt     dskw / no, branch to standard file output
+       asl     r1 / yes, calculate the index into the special file
+       jmp     *1f-2(r1) / jump table and jump to the appropriate routine
+1:
+       wtty    / tty
+       wppt    / ppt
+       wmem    / mem
+       wrf0    / rf0
+       wrk0    / rk0
+       wtap    / tap0
+       wtap    / tap1
+       wtap    / tap2
+       wtap    / tap3
+       wtap    / tap4
+       wtap    / tap5
+       wtap    / tap6
+       wtap    / tap7
+       xmtt    / tty0
+       xmtt    / tty1
+       xmtt    / tty2
+       xmtt    / tty3
+       xmtt    / tty4
+       xmtt    / tty5
+       xmtt    / tty6
+       xmtt    / tty7
+/      w1pr / lpr
+
+wtty:
+       jsr     r0,cpass / get next character from user buffer area; if
+                        / none go to return address in syswrite
+       tst     r1 / is character = null
+       beq     wtty / yes, get next character
+1 :
+       mov     $240,*$ps / no, set processor priority to five
+       cmpb    cc+1,$20. / is character count for console tty greater
+                         / than 20
+       bhis    2f / yes; branch to put process to sleep
+       jsr     r0,putc; 1 / find place in freelist to assign to console
+                          / tty and
+               br 2f / place character in list; if none available
+                     / branch to put process to sleep
+       jsr     r0,startty / attempt to output character on tty
+       br      wtty
+2:
+       mov     r1,-(sp) / place character on stack
+       jsr     r0,sleep; 1 / put process to sleep
+       mov     (sp)+,r1 / remove character from stack
+       br      1b / try again to place character in clist and output
+
+wppt:
+       jsr     r0,cpass / get next character from user buffer area,
+                        / if none return to writei's calling routine
+       jsr     r0,pptoc / output character on ppt
+       br      wppt
+/wlpr:
+/      jsr     r0,cpass
+/      cmp     r0,$'a
+/      blo     1f
+/      cmp     r1,$'z
+/      bhi     1f
+/      sub     $40,r1
+/1:
+/      jsr     r0,lptoc
+/      br      wlpr
+
+wmem: / transfer characters from a user area of core to memory file
+       jsr     r0,cpass / get next character from users area of core and
+                        / put it in r1
+       mov     r1,-(sp) / put character on the stack
+       mov     *u.fofp,r1 / save file offset in r1
+       inc     *u.fofp / increment file offset to point to next available
+                       / location in file
+       movb    (sp)+,(r1) / pop char off stack, put in memory loc assigned
+                          / to it
+       br      wmem / continue
+1:
+       jmp     error / ?
+
+dskw: / write routine for non-special files
+       mov     (sp),r1 / get an i-node number from the stack into r1
+       jsr     r0,iget / write i-node out (if modified), read i-node 'r1'
+                       / into i-node area of core
+       mov      *u.fofp,r2 / put the file offset [(u.off) or the offset in
+                           / the fsp entry for this file] in r2
+       add      u.count,r2 / no. of bytes to be written + file offset is
+                           / put in r2
+       cmp      r2,i.size / is this greater than the present size of
+                          / the file?
+       blos     1f / no, branch
+        mov    r2,i.size / yes, increase the f11e size to file offset +
+                          / no. of data bytes
+        jsr    r0,setimod / set imod=1 (i.e., core inode has been
+                          / modified), stuff tlme of modification into
+                          / core image of i-node
+1:
+       jsr     r0,mget / get the block no. in which to write the next data
+                       / byte
+       bit     *u.fofp,$777 / test the lower 9 bits of the file offset
+       bne     2f / if its non-zero, branch; if zero, file offset = 0,
+                  / 512, 1024,...(i.e., start of new block)
+       cmp     u.count,$512. / if zero, is there enough data to fill an
+                             / entire block? (i.e., no. of
+       bhis    3f / bytes to be written greater than 512.? Yes, branch.
+                  / Don't have to read block
+2: / in as no past info. is to be saved (the entire block will be
+   / overwritten).
+       jsr     r0,dskrd / no, must retain old info.. Hence, read block 'r1'
+                        / into an I/O buffer
+3:
+       jsr     r0,wslot / set write and inhibit bits in I/O queue, proc.
+                        / status=0, r5 points to 1st word of data
+       jsr     r0,sioreg / r3 = no. of bytes of data, r1 = address of data,
+                         / r2 points to location in buffer in which to
+                         / start writing data
+2:
+       movb    (r1 )+,(r2)+ / transfer a byte of data to the I/O buffer
+       dec     r3 / decrement no. of bytes to be written
+       bne     2b / have all bytes been transferred? No, branch
+       jsr     r0,dskwr / yes, write the block and the i-node
+       tst     u.count / any more data to write?
+       bne     1b / yes, branch
+       jmp     ret / no, return to the caller via 'ret'
+
+cpass: / get next character from user area of core and put it in r1
+       tst     u.count / have all the characters been transferred (i.e.,
+                       / u.count, # of chars. left
+       beq     1f / to be transferred = 0?) yes, branch
+       dec     u.count / no, decrement u.count
+       movb    *u.base,r1 / take the character pointed to by u.base and
+                          / put it in r1
+       inc     u.nread / increment no. of bytes transferred
+       inc     u.base / increment the buffer address to point to the
+       rts     r0 / next byte
+1: 
+       mov     (sp)+,r0 / put return address of calling routine into r0
+       mov     (sp)+,r1 / i-number in r1
+       rts     r0 / non-local return
+
+sioreg:
+       mov     *u.fofp,r2 / file offset (in bytes) is moved to r2
+       mov     r2,r3 / and also to r3
+       bis     $177000,r3 / set bits 9,...,15. of file offset in r3
+       bic     $!777,r2 / calculate file offset mod 512.
+       add     r5,r2 / r2 now points to 1st byte in system buffer where
+                     / data is to be placed
+       mov     u.base,r1 / address of data is in r1
+       neg     r3 / 512 - file offset (mod512.) in r3 (i.e., the number
+                  / of free bytes in the file block
+       cmp     r3,u.count / compare this with the number of data bytes to
+                          / be written to the file
+       blos    2f / if less than branch. Use the number of free bytes
+                  / in the file block as the number to be written
+       mov     u.count,r3 / if greater than, use the number of data bytes
+                          / as the number to be written
+2:
+       add     r3,u.nread / r3 + number of bytes xmitted during write is
+                          / put into u.nread
+       sub     r3,u.count / u.count = no. of bytes that still must be
+                          / written or read
+       add     r3,u.base /  u.base points to the 1st of the remaining data
+                         / bytes
+       add     r3,*u.fofp / new file offset = number of bytes done + old
+                          / file offset
+       rts     r0
+
diff --git a/u7.s b/u7.s
new file mode 100644 (file)
index 0000000..234db72
--- /dev/null
+++ b/u7.s
@@ -0,0 +1,446 @@
+/ u7 -- unix
+
+canon:
+        mov    r5,r1 / move tty buffer address to r1
+        add    $10.,r1 / add 10 to get start of data
+        mov    r1,4(r5) / canp = 10(r5) / move buffer addr + 10 to 3rd
+                        / word in buffer (char. pointer)
+        clr    2(r5) / ncan / clear 2nd word in buffer, 0 char. count
+1:
+        jsr    r0,*(r0) / jump to arg get char off Q of characters, sleep
+                        / if none
+        jsr    r0,cesc; 100 / test for @ (kill line)
+               br canon / character was @ so start over
+        jsr    r0,cesc; 43 / test for # (erase last char. typed)
+               br 1b / character was #, go back
+        cmp    r1,$4 / is char eot?
+        beq    1f / yes, reset and return
+        movb   r1,*4(r5) / no, move char to address in 3rd word of buffer
+                         / (char. pointer)
+        inc    2(r5) / increment 2nd word (char. count)
+        inc    4(r5) / increment 3rd word (char. pointer)
+        cmp    r1,$'\n / is char = newline
+        beq    1f / yes, 1f
+        cmp    2(r5),$120. / is byte count greater than or equal to 120
+        bhis   1f / yes, 1f
+        br     1b / no, get another char off the Q
+1: / get here if line is full, a new line has been received or an eot
+   / has been received
+        mov    r5,r1 / move buffer address to r1
+        add    $10.,r1 / add 10
+        mov    r1,4(r5) / canp = 10(r5) / reset char pointer
+        tst    (r0)+ / skip over argument
+        rts    r0 / return
+
+cesc: / test for erase or kill char
+        cmp    r1,(r0)+ / char in r1 = erase or kill character?
+        bne    1f / no, skip return
+        tst    2(r5) / yes, is char. count = 0
+        beq    2f / yes, don't skip return
+        dec    2(r5) / no, decrement char count
+        dec    4(r5) / decrement character pointer
+        cmpb   *4(r5),$'\\/ was previous character a "\"
+        bne    2f / no, don't skip
+1:
+        tst    (r0)+ / yes, skip
+2:
+        rts    r0 / return
+
+ttych: / get characters from Q of characters inputted to tty
+        mov    $240,*$ps / set processor priority to 5
+        jsr    r0,getc; 0 / takes char. off clist and puts it in r1
+               br 1f / list is empty, go to sleep
+        clr    *$ps / clear process priority
+        rts    r0 / return
+1: / list is empty
+        mov    r5,-(sp) / save r5
+        jsr    r0,sleep; 0 / put process to sleep in input wait channel
+        mov    (sp)+,r5 / restore r5
+        br     ttych / try again
+
+pptic: / paper tape input control
+        mov    $240,*$ps / set processor priority to five
+        cmpb   cc+2,$30. / is character count for paper tape input in
+                         / clist greater than or equal to 30
+        bhis   1f / yes, branch
+        bit    *$prs,$104200 / is there either an error, an unread char
+                             / in buffer, or reader busy
+        bne    1f / yes, don't enable reader
+        inc    *$prs / set reader enable bit
+1:
+        jsr    r0,getc; 2 / get next character in clist for ppt input and
+               br 1f / place in r1; if no char in clist for ppt input
+                     / branch
+        tst    (r0)+ / pop stack so that return will be four locations past
+                     / subroutine call
+2:
+        clr    *$ps / set process priority equal to zero
+        rts    r0 / return
+1:                                                     
+        cmpb   pptiflg,$6 / does pptiflg indicate file "not closed"
+        beq    2b / yes, return to calling routine at instruction
+                  / immediately following jsr
+        jsr    r0,sleep; 2 / no, all characters to be read in not yet in
+                           / clist, put process to sleep
+        br     pptic
+
+pptoc: / paper tape output control
+        mov    $240,*$ps / set processor priority to five
+        cmpb   cc+3,$50. / is character count for paper tape output in
+                         / clist greater than or equal to 50
+        bhis   1f / yes
+        jsr    r0,putc; 3 / find place in freelist to assign ppt output
+                          / and place
+               br 1f / character in list; if none available branch to put
+                     / process to sleep
+        jsr    r0,starppt / try to output character
+        clr    *$ps / clear processor priority
+        rts    r0 / return
+1:
+        mov    r1,-(sp) / place character on stack
+        jsr    r0,sleep; 3 / put process to sleep
+        mov    (sp)+,r1 / place character in r1
+        br     pptoc / try again to place character in clist and output
+
+/lptoc: / line printer output control
+/       mov    $240,*$ps / set processor priority to five
+/       cmpb   cc+5,$200. / is character count for printer greater than or
+                          / equal to 200
+/       bhis   1f / yes
+/       jsr    r0,putc; 5 / find place in freelist to assign to printer
+                          / and place
+
+               br 1f / char in list, if none available branch to put
+                     / process to sleep
+/       jsr    r0,starlpt / try to output character
+/       clr    *$ps / set processor priority = 0
+/       rts    r0 / return
+/1:
+/       mov    r1,-(sp) / place character on stack
+/       jsr    r0,sleep; 5 / put process to sleep
+/       mov    (sp)+,r1 / place character on stack
+/       br     lptoc
+
+getc: / get a character off character list
+        mov    (r0)+,r1 / put argument in getc call in r1 (char list id)
+        jsr    r0,get
+               br 1f / empty char list return
+        decb   cc(r1) / decrement number of char in char list
+        mov    $-1,r1 / load minus 1 in r1
+        jsr    r0,put / put char back on free list
+        movb   clist-2(r2),r1 / put char in r1
+        tst    (r0)+ / bump r0 for non blank char list return
+1:
+        rts    r0
+
+putc:
+        mov    r1,-(sp) / save char on stack
+        mov    $-1,r1 / put free list list id in r1
+        jsr    r0,get / take char off free list / clist slot taken
+                      / identified by r2
+               br 1f / branch when no chars in free list
+        mov    (r0)+,r1 / put putc call arg in r1 (i.e., list identifier)
+        incb   cc(r1) / increment character count for list (r1)
+        jsr    r0,put / put clist entry on list
+        movb   (sp),clist-2(r2) / put character in new entry
+1:
+        tst    (r0)+
+        mov    (sp)+,r1
+        rts    r0
+
+get:
+        movb   cf+1(r1),r2 / move current first char offset to r2
+        beq    2f / no characters in char list
+        tst    (r0)+ / bump r0, second return
+        cmpb   r2,cl+1(r1) / r2 equal to last char offset
+        beq    1f / yes, (i.e., entire char list scanned), branch to 1f
+        bic    $!377,r2 / clear bits 8-15 in r2
+        asl    r2 / multiply r2 by 2 to get offset in clist
+        movb   clist-1(r2),cf+1(r1) / move next char in list pointer to
+                                    / first char offset ptr
+        br     2f
+1:
+        clrb   cf+1(r1) / clear first char clist offset
+        clrb   cl+1(r1) / clear last char clist offset
+        bic    $!377,r2 / zero top half of r2
+        asl    r2 / multiply r2 by 2
+2:
+        rts    r0
+
+put:
+        asr    r2 / divide r2 by 2; r2 is offset in clist
+        mov    r2,-(sp) / save r2 on stack
+        movb   cl+1(r1),r2 / move offset of last char in list (r1) into r2
+        beq    1f / offset = 0 then go to 1f (i.e., start a new list)
+        bic    $!377,r2 / zero top half of r2
+        asl    r2 / multiply offset by 2, r2 now has offset in clist
+        movb   (sp),clist-1(r2) / link new list entry to current last
+                                / entry in list (r1)
+        br     2f
+1:
+        movb   (sp),cf+1(r1) / put new list entry offset into first char
+                             / offset of list (r1)
+2:
+        mov    (sp)+,r2 / pop stack into r2; offset of new list
+                        / entry in r2
+        movb   r2,cl+1(r1) / make new list entry the last entry in list
+                           / (r1)
+        asl    r2 / multiply r2 by 2; r2 has clist offset for new
+                  / list entry
+        rts    r0
+
+iopen: / open file whose i-number is in r1
+        tst    r1 / write or read access?
+        blt    2f / write, go to 2f
+        jsr    r0,access; 2 / get inode into core with read access
+        cmp    r1,$40. / is it a special file
+        bgt    3f / no. 3f
+        mov    r1,-(sp) / yes, figure out
+        asl    r1
+        jmp    *1f-2(r1) / which one and transfer to it
+1:
+        otty   / tty
+        oppt   / ppt
+        sret   / mem
+        sret    / rf0
+        sret   / rk0
+        sret   / tap0
+        sret   / tap1
+        sret   / tap2
+        sret   / tap3
+        sret   / tap4
+        sret   / tap5
+        sret   / tap6
+        sret   / tap7
+        ocvt   / tty0
+        ocvt   / tty1
+        ocvt   / tty2
+        ocvt   / tty3
+        ocvt   / tty4
+        ocvt   / tty5
+        ocvt   / tty6
+        ocvt   / tty7
+        error / crd
+
+2: / check open write access
+        neg   r1 / make inode number positive
+        jsr    r0,access; 1 / get inode in 0 core
+        bit    $40000,i.flgs / is it a directory?
+        bne    2f / yes, transfer (error)
+        cmp    r1,$40. / no, is it a special file?
+        bgt    3f / no, return
+        mov    r1,-(sp) / yes
+        asl    r1
+        jmp    *1f-2(r1) / figure out which special file it is
+                         / and transfer
+1:
+        otty   / tty
+        leadr  / ppt
+        sret   / mem
+        sret   / rf0
+        sret / rk0
+        sret   / tap0
+        sret   / tap1
+        sret   / tap2
+        sret   / tap3
+        sret   / tap4
+        sret   / tap5
+        sret   / tap6
+        sret   / tap7
+        ocvt   / tty0
+        ocvt   / tty1
+        ocvt   / tty2
+        ocvt   / tty3
+        ocvt   / tty4
+        ocvt   / tty5
+        ocvt   / tty6
+        ocvt   / tty7
+/       ejec / lpr
+
+otty: / open console tty for reading or writing
+        mov    $100,*$tks / set interrupt enable bit (zero others) in
+                          / reader status reg
+        mov    $100,*$tps / set interrupt enable bit (zero others) in
+                          / punch status reg
+        mov    tty+[ntty*8]-8+6,r5 / r5 points to the header of the
+                                   / console tty buffer
+        incb   (r5) / increment the count of processes that opened the
+                    / console tty
+        tst    u.ttyp / is there a process control tty (i.e., has a tty
+                      / buffer header
+        bne    sret / address been loaded into u.ttyp yet)?  yes, branch
+        mov    r5,u.ttyp / no, make the console tty the process control
+                         / tty
+        br     sret / ?
+
+sret:
+        clr    *$ps / set processor priority to zero
+        mov    (sp)+,r1 / pop stack to r1
+3:
+        rts    r0
+
+oppt: / open paper tape for reading or writing
+        mov    $100,*$prs / set reader interrupt enable bit
+        tstb   pptiflg / is file already open
+        bne    2f / yes, branch
+1:
+        mov    $240,*$ps / no, set processor priority to 5
+        jsr    r0,getc; 2 / remove all entries in clist
+               br .+4 / for paper tape input and place in free list
+        br     1b
+        movb   $2,pptiflg / set pptiflg to indicate file just open
+        movb   $10.,toutt+1 / place 10 in paper tape input tout entry
+        br     sret
+2:
+        jmp    error / file already open
+
+iclose: / close file whose i-number is in r1
+        tst    r1 / test i-number
+        blt    2f / if neg., branch
+        cmp    r1,$40. / is it a special file
+        bgt    3b / no, return
+        mov    r1,-(sp) / yes, save r1 on stack
+        asl    r1
+        jmp    *1f-2(r1) / compute jump address and transfer
+1:
+        ctty   / tty
+        cppt   / ppt
+        sret   / mem
+        sret   / rf0
+        sret   / rk0
+        sret   / tap0
+        sret   / tap1
+        sret   / tap2
+        sret   / tap3
+        sret   / tap4
+        sret   / tap5
+        sret   / tap6
+        sret   / tap7
+        ccvt   / tty0
+        ccvt   / tty1
+        ccvt   / tty2
+        ccvt   / tty3
+        ccvt   / tty4
+        ccvt   / tty5
+        ccvt   / tty6
+        ccvt   / tty7
+        error / crd
+
+2: / negative i-number
+        neg    r1 / make it positive
+        cmp    r1,$40. / is it a special file
+        bgt    3b / no. return
+        mov    r1,-(sp)
+        asl    r1 / yes. compute jump address and transfer
+        jmp    *1f-2(r1)
+1:
+        ctty   / tty
+        leadr  / ppt
+        sret   / mem
+        sret   / rf0
+        sret   / rk0
+        sret   / tap0
+        sret   / tap1
+        sret   / tap2
+        sret   / tap3
+        sret   / tap4
+        sret   / tap5
+        sret   / tap6
+        sret   / tap7
+        ccvt   / tty0
+        ccvt   / tty1
+        ccvt   / tty2
+        ccvt   / tty3
+        ccvt   / tty4
+        ccvt   / tty5
+        ccvt   / tty6
+        ccvt   / tty7
+/       ejec / lpr
+
+ctty: / close console tty
+        mov    tty+[ntty*8]-8+6,r5 / point r5 to the console tty buffer
+        decb   (r5) / dec number of processes using console tty
+        br     sret / return via sret
+
+cppt: / close paper tape
+        clrb   pptiflg / set pptiflg to indicate file not open
+1:
+        mov    $240,*$ps /set process or priority to 5
+        jsr    r0,getc; 2 / remove all ppt input entries from clist
+                          / and assign to free list
+               br sret
+        br     1b
+
+/ejec:
+/       mov    $100,*$lps / set line printer interrupt enable bit
+/       mov    $14,r1 / 'form feed' character in r1 (new page).
+/       jsr    r0,lptoc / space the printer to a new page
+/       br     sret / return to caller via 'sret'
+
+leadr: / produce paper tape leader
+        mov    $100,*$pps / set paper tape punch interrupt enable
+        mov    $100.,-(sp) / 101. characters of 'nul' will be output as
+                           / leader
+1:
+        clr    r1 / r1 contains a 'nul' character
+        jsr    r0,pptoc / output the 'nul' character
+        dec    (sp)
+        bge    1b / last leader character output?  no, branch
+        tst    (sp)+ / bump stack pointer
+        br     sret / return to caller via 'sret'
+
+sysmount: / mount file system; args special; name
+
+        jsr    r0,arg2 / get arguments special and name
+        tst    mnti / is the i-number of the cross device file zero?
+        bne    errora / no, error
+        jsr    r0,getspl / get special files device number in r1
+        mov    (sp)+,u.namep / put the name of file to be placed on the
+                             / device
+        mov    r1,-(sp) / save the device number
+        jsr    r0,namei / get the i-number of the file
+               br errora
+        mov    r1,mnti / put it in mnti
+1:
+        tstb   sb1+1 / is 15th bit of I/O queue entry for dismountable
+                     / device set?
+        bne    1b / (inhibit bit) yes, skip writing
+        mov    (sp),mntd / no, put the device number in mntd
+        movb   (sp),sb1 / put the device number in the lower byte of the
+                        / I/O queue entry
+        mov    (sp)+,cdev / put device number in cdev
+        bis    $2000,sb1 / set the read bit
+        jsr    r0,ppoke / read in entire file system
+1:
+        tstb   sb1+1 / done reading?
+        bne    1b / no, wait
+        br     sysreta / yes
+
+sysumount: / special dismount file system
+        jsr    r0,arg; u.namep / point u.namep to special
+        jsr    r0,getspl / get the device number in r1
+        cmp    r1,mntd / is it equal to the last device mounted?
+        bne    errora / no error
+1:
+        tstb   sb1+1 / yes, is the device still doing I/O (inhibit
+                     / bit set)?
+        bne    1b / yes, wait
+        clr    mntd / no, clear these
+        clr    mnti
+        br     sysreta / return
+
+getspl: / get device number from a special file name
+        jsr    r0,namei / get the i-number of the special file
+               br errora / no such file
+        sub    $4,r1 / i-number-4 rk=1,tap=2+n
+        ble    errora / less than 0?  yes, error
+        cmp    r1,$9. / greater than 9  tap 7
+        bgt    errora / yes, error
+        rts    r0 / return with device number in r1
+
+errora:
+        jmp    error / see 'error' routine
+
+sysreta:
+        jmp    sysret / see 'sysret' routine
+
diff --git a/u8.s b/u8.s
new file mode 100644 (file)
index 0000000..9ef7cc6
--- /dev/null
+++ b/u8.s
@@ -0,0 +1,463 @@
+/ u8 -- unix
+
+rtap: / read from the dec tape
+       asr     r1 / divide the i-number by 2
+       sub     $4.,r1 / (i-number/2)-4  r1
+       mov     r1,cdev / cdev now has device number
+       jsr     r0,bread; 578. / read in block thats in *u.fofp
+
+wtap:
+       asr     r1 / divide i-number by 2
+       sub     $4.,r1 / r1 = i-number minus 4
+       mov     r1,cdev / this is used as the device number
+       jsr     r0,bwrite; 578. / write block (u.fofp) on dec tape
+                               / Maximum
+
+rrk0:
+       mov     $1,cdev / set current device to i., disk
+       jsr     r0,bread; 4872. / read block from disk (maximum block
+                               / number allowed on device is 4872.)
+                               / - (u.fofp) contains block number
+
+wrk0:
+       mov     $1,cdev / set current device to 1; disk
+       jsr     r0,bwrite; 4872. / write block (u.fofp) on disk
+
+rrf0:
+       clr     cdev / set current device to 0., fixed head disk
+       jsr     r0,bread; 1024. / read block (u.fofp) from fixed head
+                               / disk (max. block number allowed on
+                               / device is 1024.)
+
+wrf0:
+       clr     cdev / set current device to 0., fixed head disk
+       jsr     r0,bwrite; 1024. / write block '(u.fofp)' on fixed head
+                                / disk
+
+bread: / read a block from a block structured device
+       jsr     r0,tstdeve / error on special file I/O (only works on
+                          / tape)
+       mov     *u.fofp,r1 / move block number to r1
+       mov     $2.-cold,-(sp) / "2-cold" to stack
+1:
+       cmp     r1,(r0) / is this block # greater than or equal to
+                       / maximum block # allowed on device
+       bhis    1f / yes, 1f (error)
+       mov     r1,-(sp) / no, put block # on stack
+       jsr     r0,preread / read in the block into an I/O buffer
+       mov     (sp)+,r1 / return block # to r1
+       inc     r1 / bump block # to next consecutive block
+       dec     (sp) / "2-1-cold" on stack
+       bgt     1b / 2-1-cold = 0?  No, go back and read in next block
+1:
+       tst     (sp)+ / yes, pop stack to clear off cold calculation
+       mov     *u.fofp,r1 / restore r1 to initial value of the
+                          / block #
+       cmp     r1,(r0)+ / block # greater than or equal to maximum
+                               / block number allowed
+       bhis    error10 / yes, error
+       inc     *u.fofp / no, *u.fofp has next block number
+       jsr     r0,preread / read in the block whose number is in r1
+       bis     $40000,(r5) / set bit 14 of the 1st word of the I/O
+                                  / buffer
+1:
+       bit     $22000,(r5) / are 10th and 13th bits set (read bits)
+       beq     1f / no
+       cmp     cdev,$1 / disk or drum?
+       ble     2f / yes
+       tstb    uquant / is the time quantum = 0?
+       bne     2f / no, 2f
+       mov     r5,-(sp) / yes, save r5 (buffer address)
+       jsr     r0,sleep; 31. / put process to sleep in channel 31 (tape)
+       mov     (sp)+,r5 / restore r5
+       br      1b / go back
+2: / drum or disk
+       jsr     r0,idle; s.wait+2 / wait
+       br      1b
+1: / 10th and 13th bits not set
+       bic     $40000,(r5) / clear bit 14
+       jsr     r0,tstdeve / test device for error (tape)
+       add     $8,r5 / r5 points to data in I/O buffer
+       jsr     r0,dioreg / do bookkeeping on u.count etc.
+1: / r5 points to beginning of data in I/O buffer, r2 points to beginning
+   / of users data
+       movb    (r5)+,(r2)+ / move data from the I/O buffer
+       dec     r3 / to the user's area in core starting at u.base
+       bne     1b
+       tst     u.count / done
+       beq     1f / yes, return
+       tst     -(r0) / no, point r0 to the argument again
+       br      bread / read some more
+1:
+       mov     (sp)+,r0 / jump to routine that called readi
+       jmp     ret
+
+bwrite: / write on block structured device
+       jsr     r0,tstdeve / test the device for an error
+       mov     *u.fofp,r1 / put the block number in r1
+       cmp     r1,(r0)+ / does block number exceed maximum allowable #
+       bhis    error10 / yes, error
+       inc     *u.fofp / no, increment block number
+       jsr     r0,wslot / get an I/O buffer to write into
+       jsr     r0,dioreg / do the necessary bookkeeping
+1: / r2 points to the users data; r5 points to the I/O buffers data area
+       movb    (r2)+,(r5)+ / ; r3, has the byte count
+       dec     r3 / area to the I/O buffer
+       bne     1b
+       jsr     r0,dskwr / write it out on the device
+       tst     u.count / done
+       beq     1f / yes, 1f
+       tst     -(r0) / no, point r0 to the argument of the call
+       br      bwrite / go back and write next block
+1:
+       mov     (sp)+,r0 / return to routine that called writei
+       jmp     ret
+tstdeve: / check whether permanent error has occured on special file
+         / I/O
+       mov     cdev,r1 / only works on tape; r1 has device #
+       tstb    deverr(r1) / test error bit of device
+       bne     1f / error
+       rts     r0 / device okay
+1:
+       clrb    deverr(r1) / clear error
+
+error10:
+       jmp     error / see 'error' routine
+
+dioreg:
+       mov     u.count,r3 / move char count to r3
+       cmp     r3,$512. / more than 512. char?
+       blos    1f / no, branch
+       mov     $512.,r3 / yes, just take 512.
+1:
+       mov     u.base,r2 / put users base in r2
+       add     r3,u.nread / add the number to be read to u.nread
+       sub     r3,u.count / update count
+       add     r3,u.base / update base
+       rts     r0 / return
+
+preread:
+       jsr     r0,bufaloc / get a free I/O buffer (r1 has block number)
+       br      1f / branch if block already in a I/O buffer
+       bis     $2000,(r5) / set read bit (bit 100 in I/O buffer)
+       jsr     r0,poke / perform the read
+1:
+       clr     *$ps / ps = 0
+       rts     r0
+
+dskrd:
+       jsr     r0,bufaloc / shuffle off to bufaloc; get a free I/O buffer
+               br 1f
+       bis     $2000,(r5) / set bit 10 of word 1 of I/O queue entry
+                          / for buffer
+       jsr     r0,poke / just assigned in bufaloc, bit 10=1 says read
+1:
+       clr     *$ps
+       bit     $22000,(r5) / if either bits 10, or 13 are 1; jump to idle
+       beq     1f
+       jsr     r0,idle; s.wait+2
+       br      1b
+1:
+       add     $8,r5 / r5 points to first word of data in block just read
+                     / in
+       rts     r0
+
+wslot:
+       jsr     r0,bufaloc / get a free I/O buffer; pointer to first
+               br 1f / word in buffer in r5
+1:
+       bit     $22000,(r5) / check bits 10, 13 (read, waiting to read)
+                                  / of I/O queue entry
+       beq     1f / branch if 10, 13 zero (i.e., not reading, or waiting
+                         / to read)
+       jsr     r0,idle; s.wait+2 / if buffer is reading or writing to read,
+                                        / idle
+       br      1b / till finished
+1:
+       bis     $101000,(r5) / set bits 9, 15 in 1st word of I/O queue
+                            / (write, inhibit bits)
+       clr     *$ps / clear processor status
+       add     $8,r5 / r5 points to first word in data area for this
+                            / block
+       rts     r0
+
+dskwr:
+       bic     $100000,*bufp / clear bit 15 of I/O queue entry at
+                             / bottom of queue
+
+ppoke:
+       mov     $340,*$ps
+       jsr     r0,poke
+       clr     *$ps
+       rts     r0
+poke:
+       mov     r1,-(sp)
+       mov     r2,-(sp)
+       mov     r3,-(sp)
+       mov     $bufp+nbuf+nbuf+6,r2 / r2 points to highest priority I/O
+                                    / queue pointer
+1:
+       mov     -(r2),r1 / r1 points to an I/O queue entry
+       bit     $3000,(r1) / test bits 9 and 10 of word 1 of I/O queue
+                          / entry
+       beq     2f / branch to 2f if both are clear
+       bit     $130000,(r1) / test bits 12, 13, and 15
+       bne     2f / branch if any are set
+       movb    (r1),r3 / get device id
+       tstb    deverr(r3) / test for errors on this device
+       beq     3f / branch if no errors
+       mov     $-1,2(r1) / destroy associativity
+       clrb    1(r1) / do not do I/O
+       br      2f
+3:
+       cmpb    r3,$1 / device id = 1; device is disk
+       blt     prf / device id = 0; device is drum
+       bgt     ptc / device id greater than or equal to 1; device is
+                          / dec tape
+       bit     $2,active / test disk busy bit
+       bne     2f / branch if bit is set
+       bis     $2,active / set disk busy bit
+       mov     r1,rkap / rkap points to current I/O queue entry for disk
+       mov     2(r1),mq / put physical block number in mq
+       mov     $12.,div / divide physical block number by 12.
+       mov     $rkda+2,r3 /
+       mov     ac,-(sp) / put remainder from divide on stack; gives
+                        / sector number
+       mov     $4,lsh / shift quotient 4 bits, to align with cyl and surf
+                      / bits in rkda
+       bis     mq,(sp) / or mq with sector; gives total disk address
+       br      3f
+prf: / drum
+       bit     $1,active / test drum busy bit
+       bne     2f / branch if bit is set
+       bis     $1,active / set drum busy bit
+       mov     r1,rfap / rfap points to current I/O queue entry for drum
+       mov     $dae+2,r3
+       clr     -(sp)
+       movb    2(r1),1(sp) / move low byte of physical block number into
+                           / high byte of stack
+       clr     -(sp) / word
+       movb    3(r1),(sp) / move high byte of physical block number into
+                          / low byte of stack
+       mov     (sp)+,-(r3) / load dae with high byte of physical block
+                           / number
+3:
+       mov     (sp)+,-(r3) / load rkda register; load dar register
+       mov     6(r1),-(r3) / load bus address register
+       mov     4(r1),-(r3) / load word count register
+       mov     $103,-(sp) / 103 indicates write operation when loaded
+                          / in csr
+       bit     $2000,(r1) / if bit 10 of word 1 of I/O queue entry is
+                          / a one
+       beq     3f / then read operation is indicated
+       mov     $105,(sp) / 105 indicates read operation
+3:
+       mov     (sp)+,-(r3) / load csr with interrupt enabled, command, go
+       br      seta
+ptc: / tape I/O
+       bit     $4,active
+       bne     2f
+       mov     tccm,r3
+       swab    r3
+       bic     $!7,r3
+       add     $2,r3
+       cmpb    r3,(r1)
+       beq     3f
+       movb    $1,tccm / stop transport if not same unit
+3:
+       bis     $4,active
+       mov     r1,tcap
+       mov     $20.,tcerrc
+       mov     $tape1,tcstate
+       movb    (r1),r3 / device
+       sub     $2,r3 / now unit
+       swab    r3
+       bis     $103,r3 / now rbn,for,unit,ie
+       mov     r3,tccm
+ seta: / I/O queue bookkeeping; set read/write waiting bits.
+       mov     (r1),r3 / move word 1 of I/O queue entry into r3
+       bic     $!3000,r3 / clear all bits except 9 and 10
+       bic     $3000,(r1) / clear only bits 9 and 10
+       rol     r3
+       rol     r3
+       rol     r3
+       bis     r3,(r1) / or old value of bits 9 and 10 with bits 12
+                              / and 13
+2:
+       cmp     r2,$bufp / test to see if entire I/O queue has been
+                        / scanned
+       bhi    1b
+       mov    (sp)+,r3
+       mov    (sp)+,r2
+       mov    (sp)+,r1
+       rts    r0
+
+bufaloc:
+       mov    r2,-(sp) / save r2 on stack
+       mov    $340,*$ps / set processor priority to 7
+1:
+       clr    -(sp) / vacant buffer
+       mov    $bufp,r2 / bufp contains pointers to I/O queue entrys
+                       / in buffer area
+2:
+       mov    (r2)+,r5 / move pointer to word 1 of an I/O queue entry
+                       / into r5
+       bit    $173000,(r5) / lock+keep+active+outstanding
+       bne    3f / branch when any of bits 9,10,12,13,14,15 are set
+                        / (i.e., buffer busy)
+       mov    r2,(sp) / save pointer to last non-busy buffer found
+                             / points to word 2 of I/O queue entry)
+3:
+       cmpb   (r5),cdev / is device in I/O queue entry same as current
+                        / device
+       bne    3f
+       cmp    2(r5),r1 / is block number in I/O queue entry, same as
+                              / current block number
+       bne    3f
+       tst    (sp)+ / bump stack pointer
+       br     1f / use this buffer
+3:
+       cmp    r2,$bufp+nbuf+nbuf
+       blo    2b / go to 2b if r2 less than bufp+nbuf+nbuf (all
+                 / buffers not checked)
+       mov    (sp)+,r2 / once all bufs are examined move pointer to
+                              / last free block
+       bne    2f / if (sp) is non zero, i.e., if a free buffer is
+                        / found branch to 2f
+       jsr    r0,idle; s.wait+2 / idle if no free buffers
+       br     1b
+2:
+       tst    (r0)+ / skip if warmed over buffer
+1:
+       mov    -(r2),r5 / put pointer to word 1 of I/O queue entry in r5
+       movb   cdev,(r5) / put current device number in I/O queue entry
+       mov    r1,2(r5) / move block number into word 2 of I/O queue
+/ entry
+1:
+       cmp     r2,$bufp / bump all entrys in bufp and put latest assigned
+       blos    1f / buffer on the top (this makes if the lowest priority)
+       mov     -(r2),2(r2) / job for a particular device
+       br      1b
+1:
+       mov     r5,(r2)
+       mov     (sp)+,r2 / restore r2
+       rts     r0
+
+tape: / dec tape interrupt
+       jsr     r0,setisp / save registers and clockp on stack
+       mov     tcstate,r3 / put state of dec tape in r3
+       jsr     r0,trapt; tccm; tcap; 4 / busy bit
+       mov     r3,pc / device control status register
+       / if no errors, go to device state (an address)
+
+taper: / dec tape error
+       dec     tcerrc / decrement the number of errors
+       bne     1f / if more than 1 branch
+       movb    1(r2),r3 / r2+1 points to command register upper byte
+       bic     $!7,r3 / clear all but bits 8-10 (Unit Selection)
+       incb    deverr+2(r3) / set error bit for this tape unit
+       br      tape3
+1: / more than 1 error
+       bit     $4000,(r2) / direction of tape
+       beq     1f / if forward go to 1f
+       bic     $4000,(r2) / reverse, set to forward
+       mov     $tape1,tcstate / put tape 1 in the state
+       br      0f
+1: / put tape in reverse
+       bis     $4000,(r2) / set tape to reverse direction
+       mov     $tape2,tcstate / put tape 2 as the state
+0:
+       bis     $4,active / check active bit of tape
+       movb    $103,(r2) / set read function and interrupt enable
+       br      4f / go to retisp
+tape1: / read bn forward
+       mov     $tcdt,r0 / move address of data register to r0
+       cmp     (r0),2(r1) / compare block addresses
+       blt     0b / if lt, keep moving
+       bgt     taper / if gt, reverse
+       mov     6(r1),-(r0) / put bus address in tcba
+       mov     4(r1),-(r0) / put word count in tcwc
+       mov     $115,-(sp) / put end interrupt enable
+       bit     $20000,(r1) / is "waiting to read bit" of I/O queue set?
+       beq     1f / no,  1f
+       mov     $105,(sp) / yes, put and interrupt enable
+1:
+       movb    (sp)+,(r2) / move function into command register (tccm)
+       bis     $4,active / set active bit
+       mov     $tape3,tcstate / get ready for I/O transfer
+       br      4f / go to retisp (rti)
+
+tape2: / read bn bakasswards
+       mov     tcdt,r0 / r0 has contents of data register
+       add     $3,r0 / overshoot
+       cmp     r0,2(r1)
+       bgt     0b / if gt keep reading
+       br      taper / else reverse
+
+tape3: / I/O transfer
+       bic     $30000,(r1) / clear bits 12 and 13 of I/O queue entry
+       jsr     r0,poke / do the I/O
+       bit     $4,active / still busy see if pick up r-ahead, w-behind
+       bne     1f / yes
+       movb    $1,(r2) / no, indicate too bad
+1:
+       jsr     r0,wakeup; runq; 31. / wait up
+       br      4f / retisp
+
+drum: / interrupt handler
+       jsr     r0,setisp / save r1,r2,r3, and clockp on the stack
+       jsr     r0,trapt; dcs; rfap; 1 / check for stray interrupt or
+                                      / error
+               br 3f / no, error
+       br      2f / error
+
+disk:
+       jsr     r0,setisp / save r1,r2,r3, and clockp on the stack
+       jmp     *$0f
+0:
+       jsr     r0,trapt; rkcs; rkap; 2
+                      br 3f / no, errors
+       mov     $115,(r2) / drive reset, errbit was set
+       mov     $1f,0b-2 / next time jmp *$0f is executed jmp will be
+                        / to 1f
+       br      4f
+1:
+       bit     $20000,rkcs
+       beq     4f / wait for seek complete
+       mov     $0b,0b-2
+       mov     rkap,r1
+2:
+       bit     $3000,(r1) / are bits 9 or 10 set in the 1st word of
+                          / the disk buffer
+       bne     3f / no, branch ignore error if outstanding
+       inc     r1
+       asr     (r1)
+       asr     (r1)
+       asr     (r1) / reissue request
+       dec     r1
+3:
+       bic     $30000,(r1) / clear bits 12 and 13 in 1st word of buffer
+       mov     ac,-(sp)
+       mov     mq,-(sp) / put these on the stack
+       mov     sc,-(sp)
+       jsr     r0,poke
+       mov     (sp)+,sc
+       mov     (sp)+,mq / pop them off stack
+       mov     (sp)+,ac
+4:
+       jmp     retisp / u4-3
+
+trapt:                                   / r2 points to the
+       mov     (r0)+,r2 / device control register
+       mov     *(r0)+,r1 / transaction pointer points to buffer
+       tst     (sp)+
+       tstb    (r2) / is ready bit of dcs set?
+       bge     4b / device still active so branch
+       bit     (r0),active / was device busy?
+       beq     4b / no, stray interrupt
+       bic     (r0)+,active / yes, set active to zero
+       tst     (r2) / test the err(bit is) of dcs
+       bge     2f / if no error jump to 2f
+       tst     (r0)+ / skip on error
+ 2:
+       jmp     (r0)
diff --git a/u9.s b/u9.s
new file mode 100644 (file)
index 0000000..7fc5998
--- /dev/null
+++ b/u9.s
@@ -0,0 +1,412 @@
+/ u9 -- unix
+
+trcv:
+       jsr     r0,1f
+       jsr     r0,1f
+       jsr     r0,1f
+       jsr     r0,1f
+       jsr     r0,1f
+       jsr     r0,1f
+       jsr     r0,1f
+       jsr     r0,1f
+1:
+       mov     r1,-(sp)
+       mov     r2,-(sp)
+       mov     r3,-(sp)
+       mov     clockp,-(sp)
+       mov     $s.syst+2,clockp
+       sub     $trcv+4,r0 / 0%4 / calculate offset for tty causing
+       asl     r0 / 0%8 / this interrupt
+       mov     rcsr(r0),r2
+       mov     rcbr(r0),r1
+       tst     r2
+       blt     1f / error
+       tst     tty+6(r0)
+       beq     1f
+       bit     $40,r2 / parity
+       bne     3f / branch if set
+       tstb    tty+4(r0)
+       blt     4f / 37 parity not allowed
+       br      2f
+3:
+       bitb    $100,tty+4(r0)
+       beq     2f / non-37 parity not allowed
+4:
+       bic     $!177,r1
+       bit     $40,tty+4(r0)
+       bne     3f / raw
+       cmp     r1,$177
+       beq     5f
+       cmp     r1,$34
+       bne     3f
+5:
+       mov     tty+6(r0),r0
+       beq     2f
+       movb    r1,6(r0) / interrupt or quit
+       jsr     r0,wakeall
+       br      2f
+3:
+       cmp     r1,$15 / or
+       bne     3f
+       bit     $20,tty+4(r0)
+       beq     3f
+       mov     $12,r1
+3:
+       bitb    $4,tty+4(r0)
+       beq     3f
+       cmp     r1,$'A
+       blo     3f
+       cmp     r1,$'Z
+       bhi     3f
+       add     $40,r1
+3:
+       movb    tty+3(r0),0f
+       jsr     r0,putc; 0:.. / put char on input clist
+               br 2f
+       bitb    $10,tty+4(r0) / echo
+       bne     4f / branch echo bit set
+       cmp     r1,$12
+       bne     3f
+       bitb    $20,tty+4(r0) / cr
+       beq     3f
+4:
+       cmp     r1,$4 / is char input an eot
+       beq     1f
+       mov     r1,-(sp) / put char on stack
+       movb    tty+3(r0),0f
+       inc     0f
+       jsr     r0,putc; 0:.. / put char just input on output clist
+               br .+2
+       jsr     r0,starxmt
+       mov     (sp)+,r1
+3:
+       bitb    $40,tty+4(r0) / raw
+       bne     1f / branch if raw bit set
+       cmp     r1,$12
+       beq     1f
+       movb    tty+3(r0),r1
+       cmpb    cc(r1),$15.
+       blo     2f
+1:
+       movb    tty+3(r0),0f
+       jsr     r0,wakeup; runq; 0:.. / call wakeup for process
+2:
+       jmp     retisp  
+txmt:
+       jsr     r0,1f
+       jsr     r0,1f
+       jsr     r0,1f
+       jsr     r0,1f
+       jsr     r0,1f
+       jsr     r0,1f
+       jsr     r0,1f
+       jsr     r0,1f
+1:
+       mov     r1,-(sp)
+       mov     r2,-(sp)
+       mov     r3,-(sp)
+       mov     clockp,-(sp)
+       mov     $s.syst+2,clockp
+       sub     $txmt+4,r0 / 0%4 / offset in cc
+       asl     r0 / 0%8
+       jsr     r0,starxmt
+       jmp     retisp
+
+xmtto:
+       mov     r0,-(sp)
+       mov     2(sp),r0 / 0%2+6
+       sub     $6,r0
+       asl     r0
+       asl     r0 / 0%8
+       jsr     r0,starxmt
+       mov     (sp)+,r0
+       rts     r0
+
+starxmt:
+       mov     (sp),r1 / 0%8 r1 contains 8xtty number
+       movb    tty+3(r1),r1 / place contents of 4th byte of "tty"
+                            / buf in r1 (cc,cf,cl offset)
+       cmpb    cc+1(r1),$10. / is char count for tty output greater
+                             / than or equal to 10
+       bhi     1f / yes
+       mov     r1,0f / no, make offset an arg of "wakeup"
+       inc     0f / increment arg of wakeup
+       jsr     r0,wakeup; runq+2; 0:.. / wakeup process identified
+                                       / by wlist
+1: / entry specified by argument in 0:
+       mov     (sp),r1 / 0%8 / r1 contains tty number
+       asr     r1
+       asr     r1
+       asr     r1 / 0%1 r1 contains tty number
+       tstb    toutt+3(r1) / is tout entry for tty output = 0
+       bne     1f / no, return to calling routine
+       mov     (sp),r2 / yes, place (8xtty number) into r2
+       tstb    tcsr(r2) / does tty's tcsr register = 0 (is ready
+                        / bit = 0)
+       bge     1f / yes, return to calling routine
+       movb    tty+2(r2),r1 / no, place third byte of "tty" buf
+                            / into r1 (char left over after lf)
+       clrb    tty+2(r2) / clear third byte
+       tst     r1 / is third byte = 0
+       bne     3f / no, r1 contains a non nul character
+       movb    tty+3(r2),0f / yes, make byte 4 arg of "getc"
+       inc     0f / increment arg to make it tty output list of
+                  / clist
+       jsr     r0,getc; 0:.. / obtain next character in clist for tty
+                             / out and place in r1
+               br 1f / if no entry in clist to be output, return to
+                     / calling routine
+3:
+       bic     $!177,r1 / zero out bits 7-15 of r1
+       movb    partab(r1),r3 / move "partab" entry (identified by
+                             / r1) into r3
+       bge     3f / if entry is greater than or equal to 0 (digit
+                  / 2, far left digit = 0) branch
+       bisb    200,r1 / if entry is less than 0 add 128 to ASCII
+                      / code for char to be output
+       bic     $!177,r3 / to make it teletype code and then clear
+                        / bits 7-15 of r3
+
+3:
+       mov     (sp),r2 / r2 contains 8xtty number
+       bit     $4,rcsr(r2) / is carrier present for tty
+       beq     starxmt / no carrier flush
+       mov     r1,-(sp) / yes, place character to be output on stack
+       cmp     r1,$11 / is character "ht"
+       bne     3f / no
+       bitb    $2,tty+4(r2) / is tab to space flag for tty set
+                            / (bit 1 of byte 5 in "tty" buffer area)
+       beq     3f / no
+       mov     $240,(sp) / yes, change character to space
+3:
+       mov     (sp)+,tcbr(r2) / place char to be output in tty output
+                              / buffer
+       add     $tty+1,r2 / place addr of 2nd byte of "tty" buf
+       jmp     1f-2(r3) / area in r2 (which is the column count) and
+                        / then
+       incb    (r2) / normal / jmp to location determined by digits
+                    / 0 and 1 of character's entry in "partab" which
+                    / is now in r3
+1:     rts     r0 / non-printing
+       br      1f / bs  
+       br      2f / nl (line feed)  
+       br      3f / tab (horizontal tab)
+       br      4f / vert (vertical tab)
+       br      5f / cr
+
+1:
+       decb    (r2) / col decrement column count in byte 2 of "tty"
+                    / area
+       bge     1f / if count >=0 return to calling routine
+       clrb    (r2) / col set column count = 0
+       br      1f
+2:
+       bit     $1,r1 / is bit 0 of ASCII char = 1 (char = lf)
+       bne     2f / yes
+       bitb    $20,3(r2) / cr flag is bit 4 of 5th byte of "tty"
+                         / area = 1
+       beq     2f / no (only lf to be handled)
+       movb    $15,1(r2) / place "cr" in 3rd byte of "tty" area
+                         / (character leftover after "lf" )
+2:
+       movb    (r2),r3 / place present column count in r3
+       beq     1f / return to calling routine if count = 0
+       clrb    (r2) / col clear column count
+       asr     r3
+       asr     r3
+       asr     r3
+       asr     r3 / delay = col/16
+       add     $3,r3 / start to determine tout entry for tty output
+       br      2f
+3:
+       bitb    $2,3(r2) / is bit 1 of 5th byte of "tty" area = 1
+                        / (tab to space bit set)
+       beq     3f / no
+       incb    (r2) / increment column count
+       bitb    $7,(r2) / are bits 0, 1 and 2 set at col 0%8
+       beq     1f / no
+       movb    $11,1(r2) / yes, place ht in another tab next time
+       br      1f / 3rd byte of tty area (character left over after
+                  / "lf")
+3:
+       movb    (r2),r3 / place column count in r3
+       bisb    $7,(r2) / make bits 0, 1 and 2 of column count = 1
+       incb    (r2) / increment column count
+       bis     $!7,r3 / clear bits 3-15 of r3
+       neg     r3 / delay = dcol start to determine tout entry for
+                  / tty out
+       br      2f / by neg r3
+4:
+       mov     $176.,r3 / delay = lots start to determine tout entry
+       br      2f
+5:
+       mov     $10.,r3 / cr delay 160ms for tn300 start to determine
+                       / tout
+       clrb    (r2) / set column count = 0 entry
+2:
+       add     $5,r3 / time for this char,increment value for tout
+                    / entry by 5
+       mov     (sp),r2 / 0%8 r2 contains 8xtty number
+       asr     r2
+       asr     r2
+       asr     r2 / 0%1 r2 contains tty number
+       movb    r3,toutt+3(r2) / place value for tout entry into tout
+                              / table
+1:
+       rts     r0 / return
+
+partab:        / contains 3 digits for each character; digit 2 is used
+       / to determine if 200 is to added to ASCII code digits 0
+       / and 1 are used to determine value for jump table.
+       .byte 002,202,202,002,202,002,002,202
+       .byte 204,010,006,212,012,214,202,002
+       .byte 202,002,002,202,002,202,202,002
+       .byte 002,202,202,002,202,002,002,202
+       .byte 200,000,000,200,000,200,200,000
+       .byte 000,200,200,000,200,000,000,200
+       .byte 000,200,200,000,200,000,000,200
+       .byte 200,000,000,200,000,200,200,000
+       .byte 200,000,000,200,000,200,200,000
+       .byte 000,200,200,000,200,000,000,200
+       .byte 000,200,200,000,200,000,000,200
+       .byte 200,000,000,200,000,200,200,000
+       .byte 000,200,200,000,200,000,000,200
+       .byte 200,000,000,200,000,200,200,000
+       .byte 200,000,000,200,000,200,200,000
+       .byte 000,200,200,000,200,000,000,202
+
+xmtt:
+       jsr     r0,cpass / get next character from user buffer area
+       tst     r1 / is character nul
+       beq     xmtt / yes, get next character
+1:
+       mov     $240,*$ps / set processor priority equal to 5
+       mov     (sp),r2 / r2 contains i node number of file
+       asl     r2 / 0%2+28 / multlply inode number by 2
+       sub     $21.,r2 / 0%2+7 / subtract 21 from 2x inumber to
+                       / get cc, cf, cl offset
+       mov     r2,0f / make offset arg of putc
+       cmpb    cc(r2),$50. / is char count for device greater than
+                           / or equal to 50
+       bhis    2f / yes
+       jsr     r0,putc; 0:.. / find location in freelist to assign to
+                             / device and
+               br 2f / place char in list, if none available branch
+                     / to put process to sleep
+       mov     r0,-(sp) / place calling routines return address on
+                        / stack
+       mov     0b,r0 / place offset into cc, cl and cf tables in r0
+       sub     $7,r0 / subtract seven from offset
+       asl     r0 / multiply by 2
+       asl     r0 / 0%8 / multiply by 2 (r0 contains 8xtty number)
+       jsr     r0,starxmt / attempt to output character
+       mov     (sp)+,r0 / pop stack
+       br      xmtt / get next character
+2:
+       mov     r1,-(sp) / place character on stack
+       mov     0b,0f / make offset into cc, cf, cl table arg of
+                     / sleep (identifies location in wlist)
+       jsr     r0,sleep; 0:.. / put process to sleep
+       mov     (sp)+,r1 / remove character from stack
+       br      1b / try again
+
+rcvt: / read tty
+       sub     $28.,r1 / 0%2 r1 contains 2xtty number
+       asl     r1
+       asl     r1 / r1 contains 8xtty number
+       mov     r1,-(sp)
+       mov     tty+6(r1),r5 / r5 contains address of 4th word in
+                            / tty area
+       tst     2(r5) / is char count = 0
+       bne     1f / no
+       bitb    $40,tty+4(r1) / raw flag set?
+       beq     2f / no
+       tst     -(sp) / yes, decrement sp
+       jsr     r0,rcvch / get character from clist
+       tst     (sp)+ / increment sp
+       mov     (sp)+,r2 / r2 contains 8xtty number
+       bitb    $4,rcsr(r2) / is carrier detect bit on
+       beq     3f / no
+       jsr     r0,passc / yes, place character in users buffer area
+3:
+       jmp     ret
+2:
+       jsr     r0,canon; rcvch / process a line of characters in
+                               / clist and place results in tty buffer
+                               / area
+1:
+       tst     (sp)+ / increment sp
+1:
+       tst     2(r5) / is char count for tty buffer = 0
+       beq     1f / yes
+       movb    *4(r5),r1 / no, move character pointer to r1
+       inc     4(r5) / increment character pointer
+       dec     2(r5) / decrement character count
+       jsr     r0,passc / place character, whose address is in
+                        / r1, in
+       br      1b / user buffer area. Then get next character.
+1:
+       jmp     ret
+
+rcvch:
+       mov     4(sp),r2 / 0%8 r2 contains 8xtty number
+       mov     $4,r1
+       bit     r1,rcsr(r2) / is carrier detection bit on
+       bne     1f / yes
+       bic     $1,rcsr(r2) / no, clear data terminal ready bit
+       rts     r0
+1:
+       movb    tty+3(r2),0f / make cc offset arg for "getc"
+       mov     $240,*$ps / set processor priority = 5
+       jsr     r0,getc; 0:.. / get next character off clist
+               br 2f / clist empty
+       clr     *$ps / set processor priority = 0
+       rts     r0
+2:
+       mov     0b,0f / make "getc" arg an arg for "sleep"
+       mov     r5,-(sp) / save tty buffer address on stack
+       jsr     r0,sleep; 0:..
+       mov     (sp)+,r5
+       br      rcvch
+
+ocvt:
+       sub     $28.,r1 / 0%2 calculate tty table offset
+       mov     r1 ,r2
+       asl     r1 / 0%4
+       asl     r1 / 0%8
+       mov     r1,-(sp)
+       add     $6,r2 / calculate clist id  clist offset
+       movb    r2,tty+3(r1) / put clist id in tty table
+1:
+       mov     (sp),r1
+       bit     $4,rcsr(r1) / carrier detect bit set
+       bne     1f / if so, branch
+       mov     $511,rcsr(r1) / set ready, speed, interrupt enable,
+                             / supervisor transmit
+       movb    tty+3(r1),0f / put clist id in sleep argument
+       jsr     r0,sleep; 0:..
+       br      1b
+1:
+       mov     tty+6(r1),r5 / put tty buffer address in r5
+       tstb    (r5) / first byte of tty buffer = 0
+       bne     1f / if not, branch
+       mov     $511,rcsr(r1) / set control bits for receiver
+       mov     $511,tcsr(r1) / set control bits for transmitter
+       movb    $210,tty+4(r1) / put 210 in tty table word 3 / set flags
+1:
+       incb    (r5) / inc first byte of tty buffer
+       tst     (sp)+
+       tst     u.ttyp / is there a process control tty
+       bne     1f / yes, then branch
+       mov     r5,u.ttyp / no, make this tty the process control tty
+       br      1f / return
+
+ccvt:
+       sub     $28.,r1
+       asl     r1 / 0%4
+       asl     r1
+       mov     tty+6(r1),r5
+       decb    (r5)
+1:
+       jmp     sret
+
diff --git a/ux.s b/ux.s
new file mode 100644 (file)
index 0000000..0a021f7
--- /dev/null
+++ b/ux.s
@@ -0,0 +1,102 @@
+/ ux -- unix
+
+systm:
+
+       .=.+2
+       .=.+128.
+       .=.+2
+       .=.+64.
+       s.time: .=.+4
+       s.syst: .=.+4
+       s.wait: .=.+4
+       s.idlet:.=.+4
+       s.chrgt:.=.+4
+       s.drerr:.=.+2
+inode:
+       i.flgs: .=.+2
+       i.nlks: .=.+1
+       i.uid:  .=.+1
+       i.size: .=.+2
+       i.dskp: .=.+16.
+       i.ctim: .=.+4
+       i.mtim: .=.+4
+       . = inode+32.
+_mount:        .=.+1024.
+proc:
+       p.pid:  .=.+[2*nproc]
+       p.dska: .=.+[2*nproc]
+       p.ppid: .=.+[2*nproc]
+       p.break:.=.+[2*nproc]
+       p.link: .=.+nproc
+       p.stat: .=.+nproc
+tty:
+       . = .+[ntty*8.]
+fsp:   .=.+[nfiles*8.]
+bufp:  .=.+[nbuf*2]+6
+sb0:   .=.+8
+sb1:   .=.+8
+swp:   .=.+8
+ii:    .=.+2
+idev:  .=.+2
+cdev:  .=.+2
+deverr: .=.+12.
+active:        .=.+2
+rfap:  .=.+2
+rkap:  .=.+2
+tcap:  .=.+2
+tcstate:.=.+2
+tcerrc:        .=.+2
+mnti:  .=.+2
+mntd:  .=.+2
+mpid:  .=.+2
+clockp:        .=.+2
+rootdir:.=.+2
+toutt: .=.+16.; touts: .=.+32.
+runq:  .=.+6
+
+wlist: .=.+40.
+cc:    .=.+30.
+cf:    .=.+31.
+cl:    .=.+31.
+clist: .=.+510.
+imod:  .=.+1
+smod:  .=.+1
+mmod:  .=.+1
+uquant:        .=.+1
+sysflg:        .=.+1
+pptiflg:.=.+1
+ttyoch:        .=.+1
+ .even
+ .=.+100.; sstack:
+buffer:        .=.+[ntty*140.]
+       .=.+[nbuf*520.]
+
+ . = core-64.
+user:
+       u.sp:    .=.+2
+       u.usp:   .=.+2
+       u.r0:    .=.+2
+       u.cdir:  .=.+2
+       u.fp:    .=.+10.
+       u.fofp:  .=.+2
+       u.dirp:  .=.+2
+       u.namep: .=.+2
+       u.off:   .=.+2
+       u.base:  .=.+2
+       u.count: .=.+2
+       u.nread: .=.+2
+       u.break: .=.+2
+       u.ttyp:  .=.+2
+       u.dirbuf:.=.+10.
+       u.pri:   .=.+2
+       u.intr:  .=.+2
+       u.quit:  .=.+2
+       u.emt:   .=.+2
+       u.ilgins:.=.+2
+       u.cdev:  .=.+2
+       u.uid:   .=.+1
+       u.ruid:  .=.+1
+       u.bsys:  .=.+1
+       u.uno:   .=.+1
+. = core
+