From: Ken Thompson Date: Tue, 20 Jun 1972 10:00:00 +0000 (-0500) Subject: Research V1 development X-Git-Tag: Research-V1~1 X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/commitdiff_plain/45cc16b2cad2d871bf62d4579c096d04b78e8c96 Research V1 development 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 Synthesized-from: v1/sys --- diff --git a/init.s b/init.s new file mode 100644 index 0000000000..5f39d9b4c9 --- /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 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: +shell: +shellm: <-\0> +tapx: +rk0: +utmp: +wtmp: +ttyx: +getty: +usr: + .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 index 0000000000..63a1c79b2c --- /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 + ; .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 + ; .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 + ; .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 + ; .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 + ; .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 + ; .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 + ; .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: + + +at: + <@ > + +qchdir: + +glogin: + +shell: + +glob: + +binpb: + +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 index 0000000000..43f7d1a920 --- /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: + / 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. + + 43. + + 44. + + 45. + + 46. + +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. + + 02. + + 03. + + 04. + + 05. + + 06. + + 07. + + 08. + + 09. + + 10. + + 11. + + 12. + + 13. + + 14. + + 15. + + 16. + + 17. + + 18. + + 19. + + 20. + + 21. + + 22. + + 01. + / 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. + +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: + +6: + + .even +9: + +/ end of initialization data + + 0 + + .endif + diff --git a/u1.s b/u1.s new file mode 100644 index 0000000000..13091fbbdb --- /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: + + +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 index 0000000000..4001856916 --- /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 index 0000000000..3aecda7864 --- /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 index 0000000000..e23aa6b794 --- /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 index 0000000000..26dd2065ec --- /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 index 0000000000..b13b2782dc --- /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 index 0000000000..234db72ab7 --- /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 index 0000000000..9ef7cc62eb --- /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 index 0000000000..7fc5998b4a --- /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 index 0000000000..0a021f7f3e --- /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 +