|
DataMuseum.dkPresents historical artifacts from the history of: RC4000/8000/9000 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about RC4000/8000/9000 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 67584 (0x10800) Types: TextFile Names: »kkmc«
└─⟦621cfb9a2⟧ Bits:30002817 RC8000 Dump tape fra HCØ. Detaljer om "HC8000" projekt. └─⟦0364f57e3⟧ └─⟦this⟧ »kkmc«
\f m. moncentral - monitor central logic b.i30 w. i0=81 04 06, i1=12 00 00 ; if newtime (i0,i1) > oldtime (a133,a134) then oldtime:=newtime; c.i0-a133 c.i0-a133-1, a133=i0, a134=i1, z. c.i1-a134-1, a134=i1, z. z. i10=i0, i20=i1 i15=i10/100000 , i10=i10-i15*100000 , i25=i20/100000 , i20=i20-i25*100000 i14=i10/10000 , i10=i10-i14*10000 , i24=i20/10000 , i20=i20-i24*10000 i13=i10/1000 , i10=i10-i13*1000 , i23=i20/1000 , i20=i20-i23*1000 i12=i10/100 , i10=i10-i12*100 , i22=i20/100 , i20=i20-i22*100 i11=i10/10 , i10=i10-i11*10 , i21=i20/10 , i20=i20-i21*10 i2: <: date :> (:i15+48:)<16+(:i14+48:)<8+46 (:i13+48:)<16+(:i12+48:)<8+46 (:i11+48:)<16+(:i10+48:)<8+32 (:i25+48:)<16+(:i24+48:)<8+46 (:i23+48:)<16+(:i22+48:)<8+46 (:i21+48:)<16+(:i20+48:)<8+ 0 i3: al. w0 i2. ; write date: rs w0 x2+0 ; first free:=start(text); al w2 0 ; jl x3 ; return to slang(status ok); jl. i3. ; e. j. \f ; segment 1 : enter monitor after load ; the monitor is entered in word 8. the words +2,+4 must at entry contain - ; +2 load flag, writetext ; +4 medium ; where ; load flag: 1 autoload of device controllers ; 0 no autoload s. i2 w. i0: i2. ; length of segment 1 0 ; init cat switch: writetext i1: 0 ; init cat switch: medium ; entry from autoloader: al. w3 i0. ; calculate top address of rl w2 x3 ; last segment; wa w3 4 ; se w2 0 ; (i.e. until segment size = 0) jl. -6 ; al. w2 i2. ; insert start address of segment 2; dl. w1 i1. ; get init cat switches jd x3-2 ; jump to segment 10 i2: ; first word of segment 2 ; exit with: ; w0, w1 = init cat switches ; w2 = start address of segment 2 e. ; end segment 1 b. v100, r28, g70, f20, e62, d140, c200 \f ; segment 2: monitor s. k = 8, j0 w.b127=k, j0, k=k-2 ; segment structure: ; monitor table (b names) ; interrupt response (c names) ; utility procedures (d names) ; monitor procedures (e names) ; name table (f names) ; process descriptions (f names) ; buffers (f names) ; ; (g and h and i names are used locally) ; monitor table ; all addresses are absolute addresses ; an integer after the semicolon means, that the address can't ; be changed, because it - unfortunately - has been published ; or because they have a hardware-function b65: 0-0-0 ; 8: base of controller description table b66: c25 ; 10: power up entry b67: 0-0-0 ; first controller table entry b68: 0-0-0 ; top controller table entry b69: b69 ; queue head: software timeout b69 ; (for devices) b70: 0 , 0 ; time when last inspected b72: 0-0-0 ; b53 ; start of interrupt table b73: 0-0-0 ; b54 ; max external interrupt number b0: 0-0-0 ; b53 - b16 ; (relative start of interrupt table b74: a198 ; device address of this cpu b75: 0 ; after powerfail (0==false, else true) b18: 0 ; current buffer address b19: 0 ; current receiver b20: c96 ; address of simple wait event procedure b21: 0-0-0 ; owner of std-driver-locations b101:0 ; return from subprocs b102:0-0-0 ; a66 ; start of table(subproc-drivers) b103:0 ; address of entry for send message for linkdriver areas b76: 0 ; start of secondary interrupt chain b30: 0-0-0 ; errorlog proc b31: g66 ; errorlog entry r. (:64-k+2:) > 1 ; 60-62 reserved for testprograms a135<12+a136 ; 64: release, version of monitor b1: 0 ; 66: current process b2: b2 ; time slice queue head: next process b2 ; last process b3: 0-0-0 ; 72: name table start b4: 0-0-0 ; 74: first device in name table b5: 0-0-0 ; 76: first area in name table b6: 0-0-0 ; 78: first internal in name table b7: 0-0-0 ; 80: name table end b8: b8 ; mess buf pool queue head: next buf b8 ; last buf 0-0-0 ; 86: first byte of mess buf pool area 0-0-0 ; 88: last byte of mess buf pool area a6 ; 90: size of message buffer b22: 0-0-0 ; 92: first drum chain in name table b23: 0-0-0 ; 94: first disc chain in name table b24: 0-0-0 ; 96: chain end in name table b25: 0 ; 98: main cat chain table 0-0-0 ;(100) not used ??? b10: a85 ; maximum time slice b11: 0 ;104: time slice (of current process) 0 ;106: zero (earlier: micro seconds) b13: 0 , 0 ;108:110: time (unit of 0.1 milli seconds) b14: 0 ; last sensed clock value 0 ; (not used) b12: 0-0-0 ;116: number of storage bytes a111<12 + a109 ;118: min global key, min aux cat key ????? b15: 0 , 0 ; clockchange, after set clock: ; newtime - oldtime c.a400-1 b27: 0 ;124: first process extension(cur) b28: 0 ;126: second process extension(cur) b141:0 ;128: coroutine testoutput address ; links to cmon procedures: b140:c100 ;130: address of cmon procedure start c101 ;132: - '' - wait c102 ;134: - '' - pass c103 ;136: - '' - inspect c104 ;138: - '' - csendmessage c105 ;140: - '' - cwaitanswer c106 ;142: - '' - answer_arrived c107 ;144: - '' - signal_binary c108 ;146: - '' - signal_sem c109 ;148: - '' - wait_sem c110 ;150: - '' - signal_chained c111 ;152: - '' - inspect_chained c112 ;154: - '' - wait_chained c113 ;156: - '' - sem_send_mess c114 ;158: - '' - sem_answer_proc c115 ;160: - '' - message_received c116 ;162: - '' - timer_message c117 ;164: - '' - timer_scan c118 ;166: - '' - cregretmessage c119 ;168: - '' - user testoutput z. b26 = b5 ; use area processes as pseudo processes ; definition of general registers in rc8000 b90 = 8.14 * 2 ; ilevc : interrupt level limit copy b91 = 8.15 * 2 ; inf : current interrupt stack element address b92 = 8.17 * 2 ; size : top available core address b93 = 8.20 * 2 ; montop : 1 < 11 - top monitor procedure number b94 = 8.62 * 2 ; clock b95 = 8.57 * 2 ; ir : used to clear selected bits in interrupt reg b97 = 8.60 * 2 ; dswr : data swithes b98 = 8.61 * 2 ; regsel : register swithes b99 = 8.60 * 2 ; display ; b100= 8.21*2 ; cpukind: 0: /45 ; -1: /15, /25, /35 ; 50: /50 ; 55: /55 ; definition of interrupt stack. ; parameters are relative to base of stack element (i.e. 1,3,5,..) b.j0 j0=-1 , j0=j0+2 ; base of stack element a326=j0 , j0=j0+2 ; regdump a327=j0 , j0=j0+2 ; exception routine a328=j0 , j0=j0+2 ; escape routine a329=j0 , j0=j0+2 ; monitor call entry a330=j0 , j0=j0+2 ; external interrupt entry a331=j0 , j0=j0+2 ; interrupt limits, disabled/enabled a325=j0-a326 ; size of interrupt stack element e. ; external interrupt entry: ; ; when an external interrupt occurs, or when 'user exception first' ; or 'user escape first' are zero, the cpu will save all registers ; in the current process descrition. ; exit is made to here with: ; w1 = top register dump ; w2 = 2 * interrupt number ; ex = 0 c1: wa w2 b0 ; monfunc := cause + int.table.base - mon.proc.base; ; monitor call entry: ; ; if the current process executes a montor call, the cpu will ; save all the registers in the current process description. ; exit is made to here with: ; w1 = top register dump ; w2 = monitor function ; ex = 0 c0: al w1 x1-a178 ; w1 := current process; jl. (x2+b16.) ; switch out through int.table or monproc.table; ; second level external interrupt entry: ; ; exit is made to here with: ; w1 = top register dump ; w2 = 2 * interrupt number c8: sn w2 2*6 ; if cause = powerfail then jl c6 ; goto power fail routine; jl -3<1 ; halt; ; program errors in the current process are transferred to here, ; (as external interrupts): ; ; w1 = cur c2: ; internal interrupts, overflow, spill, escape errors: c3: ; monitor bugs (i.e. exception- or escape-addresses ; outside write-limits of process) c4: ; bus error in operand transfer: (no strategy yet) c5: ; bus error in instruction fetch: (- - - ) jl w2 (b31) ; call errorlog al w0 a96 ; state := running after error; jl w3 d9 ; remove internal(cur, running after error); jl c99 ; goto interrupt return; ; parameter errors in monitor call: ; ; all monitor procedures check that the parameters are ; within certain limits. ; if the parameters are wrong, the calling process is break'ed. ; ; (all regs irrellevant) b. j10 w. ; ; definitin of exception regdump: j0 = a29 - a28 ; w0, w1 j1 = a31 - a28 ; w2, w3 j2 = a33 - a28 ; status, ic j3 = a177- a28 ; cause, sb a180 = j3 + 2 ; top of exception regdump = new rel ic c29: ; internal 3: rl w1 b1 ; al w3 6 ; rs w3 x1+a176 ; cause (cur) := 6; i.e. monitor call break; rl w2 x1+a27 ; w2 := exception address (cur); sn w2 0 ; if exception address = 0 then jl c2 ; goto internal interrupt; al w3 x2 ; save w2 and jl w2 (b31) ; call errorlog al w2 x3 ; restore w2 wa w2 x1+a182 ; w2 := abs exception address; dl w0 x1+a29 ; move: save w0 ds w0 x2+j0 ; save w1 dl w0 x1+a31 ; save w2 ds w0 x2+j1 ; save w3 dl w0 x1+a33 ; save status ds w0 x2+j2 ; save ic ; rs w0 x1+a28 ; save w0 := save ic; ; al w0 14<2+0 ; ; rs w0 x1+a29 ; save w1 := 'jd'-instruction; dl w0 x1+a177 ; save cause (= 6) ds w0 x2+j3 ; save sb to user exception addres; ; rs w0 x1+a30 ; save w2 := save sb; ; rs w3 x2+a31 ; save w3 := save cause (= 6); ws w2 x1+a182 ; w2 := logic user exception address; al w2 x2+a180 ; rs w2 x1+a33 ; save ic := exception address + no of regdump bytes e. ; ;. ..... husk at nulstille addresse-bits i status ..... ; continue with interrupt return; ; interrupt return: ; a new internal process may have been put up in front of ; the time slice queue, due to an external interrupt, or because ; the current monitor call was 'send message' or the like. ; therefore it must be tested, that the current process is still ; the one in front. if not: select that one. c24: ; dummy interrupt c99: ; interrupt return: dl w2 b2 ; w1 := cur; w2 := first in time slice queue; sn w1 x2-a16 ; if cur = first then ri a179 ; return interrupt; ; (preferably without reloading limit-copies) ; initialize the previous interrupt stack element: al w2 x2-a16 ; cur := new cur; i.e. first in time slice queue; rs w2 b1 ; rl w0 x2+a35 ; time slice := quantum(new current); rs w0 b11 ; gg w3 b91 ; w3 := inf (= address of current stack element); dl w1 x2+a170 ; move: user escape address (cur) ; user exception address (cur) ds w1 x3+a325+a328; al w0 x2+a28 ; address of regdump area (cur) rs w0 x3+a325+a326; to: previous interrupt stack element; c.a400-1 ; insert process extension addresses in monitor table dl w1 x2+a306 ; wa w0 x2+a182 ; wa w1 x2+a182 ; ds w1 b28 ; z. ; if the new current process is a driver process then maybe ; exchange driver std-locations: rl w0 x2+a302 ; if the new current process has not se w0 0 ; defined a 'wait first event' sn w2 (b21) ; or the new cur = owner of std-locations then ri a179 ; return interrupt; ; (limit-copies must be initialized) ; the contents of the std-driver-locations have to be exchanged: ; ; save the old contents in the outpointed process description: ; rl w3 b21 ; w3 := previous owner of std locations; dl w1 g21 ; move: g20 ds w1 x3+a302+4 ; g21 dl w1 g23 ; g22 ds w1 x3+a302+8 ; g23 rl w1 g24 ; g24 rs w1 x3+a302+10; b18 dl w1 b19 ; b19 ds w1 x3+a302+14; to: previous process description; ; restore the std-locations from the new current process: rs w2 b21 ; new owner := current process; dl w1 x2+a302+4 ; move: g20 ds w1 g21 ; g21 dl w1 x2+a302+8 ; g22 ds w1 g23 ; g23 rl w1 x2+a302+10; g24 rs w1 g24 ; b18 dl w1 x2+a302+14; b19 ds w1 b19 ; from: new current process; ri a179 ; return interrupt; ; (limit-copies must be initialized) ; power failure: ; ; may occur at any level ; ; save the current interrupt stack entry address, unless ; already saved ; (this should prevent powerfail-cascades from disturbing the system) b. h10, i10 w. ; c6: gg w2 b91 ; w2 := current stack element; rl w3 h0 ; w3 := previous power up element; sn w3 0 ; if previous element is free then rs w2 h0 ; power up element := current stack element; al w2 0 ; ilevc := 0; gp w2 b90 ; (i.e. the following will provoke a systemfault) jl -1<1 ; halt; h0: b49 ; power up element: initially monitor element ; power up: ; ; initialize: montop (i.e. max monitor function) ; size (i.e. core size) ; inf (i.e. power up element) ; ; clear any pending interrupt bits, because they may be irrellevant ; ; entry conditions: ; inf register = 1 ; totally disabled c25: al w3 -1<11 ; montop := 1 < 11 ac w3 x3+b17 ; - top monitor function number; gp w3 b93 ; rl w3 b12 ; size := number of storage bytes; gp w3 b92 ; c.(:a90>0 a.1:)-1 jl. w3 d140. ; dump core via fpa z. al w3 6 ; ilevc := 0 < 12 + 6; gp w3 b90 ; i.e. enable for powerfail; rl w3 h0 ; w3 := power up element; sn w3 0 ; if power up element = 0 then jl -2<1 ; halt; i.e. power fail was not serviced; rs w3 b75 ; after powerfail := true; ; (should be tested by clockdriver) rl w2 b73 ; intno := max external interrupt number; i0: gp w2 b95 ; rep: clear (intno) in cpu; al w2 x2-1 ; intno := intno - 1; sl w2 6+1 ; if intno > powerfail then jl i0 ; goto rep; al w1 0 ; (prepare a new h0...) je k+2 ; (if any power fail during this start up, jd k+2 ; it will be 'serviced' now, i.e. systemfault) ; the following sequence of instructions have to be executed ; without any disturbance, else the system won't work rs w1 h0 ; clear previous power up element; ; (i.e. prevent two consecutive powerups) gp w3 b91 ; inf := power up element; ri a179 ; return interrupt; ; (the limit-copies must be initialized) e. ; end of power fail/restart ; procedure deliver external interrupt ; ; when an external interrupt is accepted by the monitor, ; control is transferred out into the corresponding ; device description, which should contain: ; ; dev descr + a240 : jl w2 c51 ; ; return must be made to the standard interrupt return action, ; which will take care of a possible selection of the driver. ; ; call: w2 = dev descr + a241 ; return address = interrupt return c51: rl w3 x2-a241+a230; w3 := top of executed channel program; al w0 4 ; result := 4; (i.e. prepare for abnormal termination) se w3 0 ; if top command address defined then bl w3 x3-6+1 ; w3 := last command executed; sn w3 -1<8 ; if last command = 'stop' then al w0 0 ; result := 0; sn w3 4<8 ; if last command = 'wait' then al w0 5 ; result := 5; c50: al w3 c99 ; link := interrupt return; ; continue with deliver interrupt ; procedure deliver interrupt ; function: delivers the interrupt operation in the event queue ; of the corresponding driver process. ; the driver process is started, if it was waiting for ; an event. ; ; call: w0 = result (=0, 1, 2, 3, 4, 5, 6), w2 = operation, w3 = link ; exit: all regs undef ; return address: link b. h10 w. ; d121:rs w3 h0 ; save (return); jl w1 d131 ; set result and descrease all stopcounts; ; w2 = device descr rl w1 x2+a250 ; driver := driverproc (device descr); sh w1 0 ; if driver undefined then jl (h0) ; return; al w2 x2+a241 ; oper := timeout operation (device descr); rl w3 h0 ; restore (return); bz w0 x1+a13 ; state := state(driver); sn w0 a104 ; if driver is waiting for event then jl d127 ; goto take interrupt; al w1 x1+a15 ; link (event queue (driver) , oper); jl d6 ; return; h0: 0 ; saved return; e. ; ; procedure take interrupt ; function: let the driver receive the interrupt operation at once ; ; call: w1 = driver process, w2 = interrupt operation, w3 = link ; exit: all regs undef ; return address: link d127:al w2 x2-a241+a246; rs w2 x1+a30 ; save w2 (driver) := address of driver service inst al w0 2 ; save w0 (driver) := 2; i.e. indicate interrupt; rs w0 x1+a28 ; link internal (driver); ; (only relevant after deliver interrupt) jl d10 ; return; ; procedure prepare driver(proc) ; function: initializes current external process and current buffer ; exits to the interrupt address given in proc: ; int addr : normal exit ; ; the call must be made like this: ; ; proc + a246: jl w1 c30 ; driver service instruction ; --- ; proc + a245: interrupt address ; --- ; proc + a54 : next message buf ; ; call: w1 = proc + a247 ; exit: w0 = result(proc), w1 = proc, w2 = buf(proc) ; int.addr : normal exit c30: al w1 x1-a247 ; rs w1 b19 ; current receiver := buf; rl w2 x1+a54 ; rs w2 b18 ; current buffer address := next mess(proc); rl w0 x1+a244 ; result := timeout(proc); jl (x1+a245) ; goto interrupt address(proc); ; procedure clear device ; ; function: everything is cleared-up in the device description, ; i.e. the controller is reset (except after 'wait'-program) ; a possible pending interrupt is cleared ; a possible pending interrupt operation is removed ; if any stopcounts were increased, they will be decreased ; ; call: w1 = link, w2 = device descr ; exit: w2 = unchanged, w0, w1, w3 = undef ; return address: link d129: ; unconditionally reset: am a235-a225; (point at something <> 0) d130: ; conditionally reset: rl w0 x2+a225 ; get transfer code to see if transfer in progress; rl w3 x2+a235 ; w3 := device address(device description); ; it should be noted, that the controller is not reset when a wait-program is timed out se w0 0 ; if transfer code <> 0 then do w3 x3+2.01<1 ; reset device (device address); ls w3 1 ; entry := device address ls w3 -1 ; (remove bit 0) wa w3 b65 ; + controller table base; rl w0 x3+a313 ; w0 := interrupt number(controller table (entry)); gp w0 b95 ; clear interrupt bit in cpu; al w2 x2+a242 ; oper := timeout operation(device descr); ; continue with set result and decrease all stopcounts ; (result = undef) ; procedure set result and decrease all stopcounts ; ; call: w0 = result: 0 = transfer terminated by stop ; 1 = bus reject when started ; 2 = bus timeout when started (i.e. disconnected) ; (3 = software timeout) ; 4 = transfer terminated, before stop ; 5 = wait-program terminated ; (6 = power restart) ; w1 = link w2 = timeout operation ; exit: w2 = device description, w0, w1, w3 = undef d131:rs w0 x2-a241+a244; save result in timeout-field; se w2 (x2) ; (if in timer queue then jl w3 d5 ; remove(timeout operation); ) al w2 x2-a241 ; w2 := device descr; ; continue with decrease all stopcounts ; procedure decrease all stopcounts ; ; function: if any stopcounts increased, then decrease them again ; transfer code(device descr) := 0 ; ; call: w1 = link, w2 = device descr b. h10, i10 w. ; d132:ds w2 h1 ; save (link, device descr); rl w1 x2+a225 ; get transfer code(device descr); sn w1 -1 ; if no transfer to processes then jl i1 ; goto clear up; so w1 2.1 ; if transfer code odd then jl i0 ; begin i.e. transfer to/from driver area; rl w1 x2+a250 ; driver := driver process (device descr); jl w3 d133 ; decrease stopcount(driver); rl w2 h1 ; restore(device descr); al w1 -1<1 ; la w1 x2+a225 ; restore (transfer code) (even) i0: ; end; sn w1 0 ; if transfer code shows transfer to/from sender the jl i1 ; begin jl w3 d133 ; decrease stopcount(sender); rl w2 h1 ; restore (device descr); ; end; i1: al w1 0 ; clear up: rs w1 x2+a225 ; transfer code(device descr) := 0; i.e. no transfer jl (h0) ; return; h0: 0 ; saved return h1: 0 ; saved device descr e. ; ; procedure decrease stopcount ; ; function: the stopcount of the process is decreased by 1. ; if the stopcount becomes zero, and the process is waiting ; to be stopped, the process is stopped now (i.e. put in ; the state 'waiting for start by...'), and the following will ; be done: ; if the process was stopped by its parent, the stop-answer ; will be send to the parent (as defined by the wait-address ; in the process), indicating that the stopping has been ; accomplished. ; the decrease-action is repeated for the parent etc.etc. ; ; call: w1 = process, w3 = link ; exit: all regs undef ; return address: link b. i10 w. ; d133: ; decrease stopcount: i0: al w0 -1 ; loop: ba w0 x1+a12 ; stopcount (process) := hs w0 x1+a12 ; stopcount (process) - 1; bz w2 x1+a13 ; sn w0 0 ; if stopcount <> 0 or so w2 a105 ; process not waiting for being stopped then jl x3 ; return; al w0 x2+a106 ; state (process) := state (process) hs w0 x1+a13 ; + 'waiting for start'; ; prepare for repeating the loop: rl w2 x1+a40 ; buf := wait address(process); rl w1 x1+a34 ; process := parent (process); se w0 a99 ; if state <> 'waiting for start by parent' then jl i0 ; goto loop; ; prepare the buffer for returning the answer: al w0 1 ; receiver(buf) := result := 1; rs w0 x2+a141 ; al w0 x3 ; (save return) jl. w3 d15. ; deliver answer(buf); rl w3 0 ; (restore return) jl i0 ; goto loop; e. ; ; return result in save w0(cur); ; entry: w1=cur r5: am 5-4 ; r4: am 4-3 ; r3: am 3-2 ; r2: am 2-1 ; r1: am 1-0 ; r0: al w0 0 ; r28: rs w0 x1+a28 ; save w0:=result; jl c99 ; goto interrupt return; ; elementary link-procedures: ; procedure remove(elem); ; comment: removes a given element from its queue and leaves the element linked to itself. ; call: w2=elem, w3=link ; exit: w0, w1, w2=unchanged, w3=next(elem) ; return address: link b. i1 w. d5: rs w3 i0 ; save return; rl w3 x2 ; w3 := next(elem); rx w2 x2+2 ; w2 := prev(elem); prev(elem) := elem; rs w3 x2 ; next(w2) := next(elem); rx w2 x3+2 ; w2 := elem; prev(next(elem)) := old prev(elem); rs w2 x2 ; next(elem) := elem; jl (i0) ; return; ; procedure increase bufclaim, remove release buf; ; comment: bufclaim(cur) is increased, continue with release buf ; call: w1=cur, w2=buf, w3=link ; exit: w0, w1=undef, w2, w3=unchanged ; return address: link d109: ; al w0 1 ; ba w0 x1+a19 ; increase(bufclaim(cur)); hs w0 x1+a19 ; ; continue with d106 ; procedure remove release buf; ; comment: removes the buffer from its queue, continue with release mess buf ; call: w2=buf, w3=link ; exit: w0, w2, w3=unchanged, w1=undef ; return address: link d106: ; al w1 x3 ; save return jl w3 d5 ; remove (buf); al w3 x1 ; restore return; ; continue with d13 ; procedure release mess buf(buf); ; comment: clears sender and receiver and links the buffer to the pool. ; call: w2=buf, w3=link ; exit: w0=unchanged, w1=undef, w2, w3=unchanged ; return address: link d13: al w1 0 ; sender(buf):=0; rs w1 x2+4 ; receiver(buf):=0; rs w1 x2+6 ; c. (:a128>2 a. 1:) - 1; if rc6000 then rl w1 b8 ; head:=next(mess buf pool); (i.e. link in front of pool) z. ; else c. - (:a128>2 a. 1:) ; al w1 b8 ; head := mess buf pool head; (i.e. link in rear); z. ; ; procedure link(head, elem); ; comment: links the element to the end of the queue ; call: w1=head, w2=elem, w3=link ; exit: w0, w1, w2=unchanged, w3=old last(head); d6: rs w3 i0 ; save return; rl w3 x1+2 ; old last:=last(head); rs w2 x1+2 ; last(head):=elem; rs w2 x3+0 ; next(old last):=elem; rs w1 x2+0 ; next(elem):=head; rs w3 x2+2 ; last(elem):=old last; jl (i0) ; return; i0: 0 ; saved return: remove, link e. ; procedure remove user(internal, proc); ; procedure remove reserver(internal, proc); ; comment: removes the id-bit of internal from the reserver- and-or userbits ; call: w1=internal, w2=proc, w3=link ; exit: w0=undef, w1,w2,w3=unchanged ; return address: link b. i0 w. d123:rs w3 i0 ; ba w2 x1+a14 ; w2:=addr of rel. halfword; bz w0 x2+a402 ; w0:=userbits.curr.intproc; bz w3 x1+a14+1 ; w3:=userbit.intproc sz w0 x3 ; if userbit.curr.intproc is on then bs w0 x1+a14+1 ; remove userbit.curr.intproc; hs w0 x2+a402 ; return userbits; bs w2 x1+a14 ; reset w2 to addr(extproc) d124:rl w0 x2+a52 ; w0:=reserver.proc; sn w0 (x1+a14) ; if intproc is reserver then al w0 0 ; remove intproc as reserver rs w0 x2+a52 ; clear reserver; jl (i0) ; return; i0:0 e. ; procedure insert reserver(internal, proc); ; procedure insert user(internal, proc); ; comment: adds the id-bit of internal to reserver- and-or userbits ; call: w1=internal, w2=proc, w3=link ; exit: w0=undef, w1,w2,w3=unchanged ; return address: link d125: rl w0 x1+a14 ; w0:=idbit.intproc; rs w0 x2+a52 ; extproc.reserver:=idbit.intproc; d126: ba w2 x1+a14 ; bz w0 x2+a402 ; w0:=userbits.curr.intproc; lo w0 x1+a14 ; set curr.intproc as user of extproc; hs w0 x2+a402 ; bs w2 x1+a14 ; reset w2; jl x3 ; return ; procedure check user; ; ; call: w1=internal, w2=proc, w3=link ; exit: w0=undef, w1, w2, w3=unchanged ; return address: link+2: cur was user ; link : cur was not user d102: ; ba w2 x1+a14 ; bz w0 x2+a402 ; w0:=userbits.curr.intproc; bs w2 x1+a14 ; reset w2; sz w0 (x1+a14) ; if curr.intproc is user then jl x3+2 ; return to link+2: i.e. user jl x3 ; return to link: not user ; procedure check any reserver; ; ; call: w1=internal, w2=proc, w3=link ; exit: w0=undef, w1, w2, w3=unchanged ; return address: link : other process is reserver ; link+2: internal is reserver ; link+4: not reserved by anyone d113: ; rl w0 x2+a52 ; if reserver(proc)=0 then sn w0 0 ; jl x3+4 ; return to link+4; i.e. not reserved se w0 (x1+a14) ; if reserver(proc) <> idbit(cur) then jl x3 ; return to link; i.e. other reserver; jl x3+2 ; return to link+2; i.e. already reserved ; procedure check mess area and name(save w3) area; ; procedure check name(save w3) area; ; procedure check name(save w2) area; ; comment: checks that the areas are within the process ; call: w1=cur, w3=link ; exit: w0=undef, w1=unchanged, w2=name, w3=unchanged ; return address: link: within process ; c29 : not within process d110: ; check message area and name area: rl w2 x1+a29 ; al w0 x2+14 ; mess:=save w1(cur); sh w0 0 ; jl c29 ; if overflow or sl w2 (x1+a17) ; mess<first addr(cur) or sl w0 (x1+a18) ; mess+14>=top addr(cur) then jl c29 ; goto internal 3; d17: am a31-a30; check name(save w3) area: d111: ; check name(save w2) area: rl w2 x1+a30 ; al w0 x2+6 ; ; procedure check within(first, last); ; comment: checks that the specified area is within the process ; call: w0=last, w1=cur, w2=first, w3=link ; exit: w0, w1, w2, w3=unchanged ; return address: link: within process ; c29 : not within process d112: ; check within: sh w0 0 ; jl c29 ; if overflow or sl w2 (x1+a17) ; first<first addr(cur) or sl w0 (x1+a18) ; last>=top addr(cur) then jl c29 ; goto internal 3; jl x3 ; return; ; procedure check message area and buf (=d18+d12); ; ; call: w1=cur, w3=link ; exit: w0=undef, w1=cur, w2=buf, w3=unchanged ; return address: link: ok ; c29 : mess area outside cur ; c29 : buf not message buf d103: ; rl w2 x1+a29 ; mess:=save w1(cur); al w0 x2+14 ; sh w0 0 ; if overflow or jl c29 ; sl w2 (x1+a17) ; mess<first addr(cur) or sl w0 (x1+a18) ; mess+14>=top addr(cur) then jl c29 ; goto internal 3; ; procedure check message buf; ; comment: checks whether the save w2 of the internal process is a message buffer address ; call: w1=internal, w3=link ; exit: w0=undef, w1=cur, w2=buf, w3=unchanged ; return address: link: buffer ok ; c29 : save w2 not message buffer d12: rl w2 x1+a30 ; buf:=save w2(internal); sl w2 (b8+4) ; if buf<mess buf pool start or sl w2 (b8+6) ; buf >=mess buf pool end then jl c29 ; goto internal 3; al w1 x2 ; ws w1 b8+4 ; if (buf-pool start) mod mess buf size al w0 0 ; <>0 then wd w1 b8+8 ; goto internal 3; rl w1 b1 ; w1:=cur; sn w0 0 ; jl x3 ; return; jl c29 ; ; procedure check event(proc, buf); ; comment: checks that buf is the address of an operation in the event queue of the internal process ; call: w1=proc, w2=buf, w3=link ; exit: w0=undef, w1, w2, w3=unchanged ; return address: link: buffer address ok ; c29 : buf is not in the queue b. i0 w. d19: al w0 x2 ; al w2 x1+a15 ; oper:=event q(proc); i0: rl w2 x2+0 ; next: oper:=next(oper); sn w2 x1+a15 ; if oper=event q(proc) then jl c29 ; goto internal 3; (i.e. not in queue); se w0 x2 ; if buf<>oper then jl i0 ; goto next; jl x3 ; return; e. ; procedure check and search name (=d17+d11); ; ; call: w1=cur, save w3(cur)=name, w3=link ; exit: w0, w1=unchanged, w2=name, w3=entry ; return address: link: entry not found ; link+2: entry found ; c29 : name area outside current process b. i20 w. d101: ; ds w1 i1 ; save(w0, cur); rl w2 x1+a31 ; name:=save w3(cur); al w0 x2+6 ; sh w0 0 ; if overflow or jl c29 ; sl w2 (x1+a17) ; name<first addr(cur) or sl w0 (x1+a18) ; name+6>=top addr(cur) then jl c29 ; goto internal 3; dl w1 x1+a43 ; w0w1:=catbase(cur); jl i14 ; goto search name(name, entry, base); ; the following procedures searches the name table for a given entry and delivers its entry in ; the name table. if name is undefined, the entry is name table end. ; procedure search name(name, entry); ; call: w2=name, w3=link ; exit: w0, w1, w2=unchanged, w3=entry ; return address: link : name not found, w3=(b7) ; link+2: name found d11: ds w1 i1 ; save(w0, w1); am (b1) ; dl w1 +a43 ; base:=catbase(cur); i14: al w3 x3+1 ; link := link + 1; i.e. destinguish between normal and error return; ; procedure search name(name, entry, base); ; call: w0, w1=base, w2=name, w3=link ; exit: w0, w1=undef, w2=unchanged, w3=entry ; return address: link : name not found, w3=(b7) ; link : name found, w3 <> (b7) d71: ds w3 i3 ; save (name, return); i4: al w1 x1-1;used ; bs w0 i4+1 ; ds w1 i6 ; base:=base+(1, -1); dl w1 d73 ; ds w1 i8 ; min base:=extreme; rl w1 b7 ; rs w1 i9 ; found:=name table end; rl w1 b1 ; get physical name address wa w2 x1+a182 ; dl w1 x2+6 ; ds w1 i13 ; move name to last name in name table; dl w1 x2+2 ; sn w0 0 ; if name(0)<>0 then jl i18 ; ds w1 i11 ; rl w3 b3 ; for entry:=name table start jl i17 ; i15: dl w1 i11 ; i16: al w3 x3+2 ; step 2 until name table end do i17: rl w2 x3 ; sn w1 (x2+a11+2) ; begin se w0 (x2+a11+0) ; proc:=name table(entry); jl i16 ; dl w1 i13 ; sn w0 (x2+a11+4) ; se w1 (x2+a11+6) ; if name.proc=name and jl i15 ; sn w2 c98 ; jl i18 ; dl w1 x2+a49 ; sl w0 (i7) ; lower.proc>=lower.min and sl w0 (i5) ; lower.proc<=lower.base and jl i15 ; sh w1 (i8) ; upper.proc<=upper.min and sh w1 (i6) ; upper.proc>=upper base then jl i15 ; begin ds w1 i8 ; min:=interval.proc; rs w3 i9 ; found:=entry; jl i15 ; end; i18: ; end; dl w0 i0 ; restore(w0, w1, w2); dl w2 i2 ; w3:=found; sn w3 (b7) ; if w3=name table end then jl (i3) ; return to link am (i3) ; else jl +1 ; return to link+1; i9: 0 ;i0-2: found (i.e. current best entry, or (b7)) i0: 0 ;i1-2: saved w0 i1: 0 ;i2-2: saved w1 i2: 0 ;i3-2: saved w2 i3: 0 ; saved return i5: 0 ;i6-2: lower base+1 for search i6: 0 ; upper base-1 for search i7: 0 ;i8-2: lower minimum i8: 0 ; upper minimum ; the last entry in name table must point here: c98 = k-a11 i10: 0 ; name to search for i11: 0 ; i12: 0 ; i13: 0 ; a107 ; max base lower d72: a108 ; max base upper a107-1 ; extreme lower d73: a108+1 ; extreme upper e. ; procedure claim buffer ; ; call: w1=cur, w2=buf, w3=link ; exit: w0=undef, w1, w2, w3=unchanged ; return address: link: claim decreased ok ; c99 : claims exceeded, save w2(cur):=0 b. i0 w. d108: ; bz w0 x1+a19 ; if bufclaim(cur)=0 then sn w0 0 ; jl i0 ; goto no buffer; bs. w0 1 ; hs w0 x1+a19 ; decrease(bufclaim(cur)); ac w0 (x2+4) ; rs w0 x2+4 ; receiver(buf):=-receiver(buf); jl x3 ; return to link; i0: rs w0 x1+a30 ; no buffer: save w2(cur):=0; jl c99 ; goto interrupt return; e. ; procedure regretted message ; comment simulates the release of a message buffer, as in wait answer. the bufclaim of the ; sender is increased. the buffer is removed and released (unless in state: received) ; ; call: w2=buf, w3=link ; exit: w0, w1, w2=unchanged, w3=undef b. i20 w. i0: 0 ; saved w0 i1: 0 ; saved w1 i2: 0 ; saved w2 i3: 0 ; saved w3 i8: 0 ; internal d75: rs w3 i3 ; save(return); ds w1 i1 ; save(w0, w1); rl w1 x2+6 ; proc:=sender(buf); sh w1 0 ; if proc<=0 then jl i6 ; goto exit; (message already regretted); ac w0 x1 ; (only relevant from remove process); rs w0 x2+6 ; sender(buf):=-proc; (i.e. regretted); rl w0 x1+a10 ; if kind(proc) = pseudo kind sn w0 64 ; then proc:= main(proc); rl w1 x1+a50 ; if proc is neither internal process nor sz w0 -1-64 ; pseudo process rl w1 x1+a250 ; then proc:= driver proc(proc); bz w3 x1+a19 ; al w3 x3+1 ; increase(bufclaim(proc)); hs w3 x1+a19 ; ; check if the buffer is claimed by receiver, or contains an answer: rl w1 x2+4 ; receiver:=receiver(buf); sh w1 0 ; if receiver<=0 then jl i6 ; goto exit; (i.e. claimed); sh w1 5 ; if receiver<=5 then jl i5 ; goto remove and release; (i.e. an answer); ; the message is neither answered nor claimed: rl w0 x1+a10 ; kind:=kind(receiver); se w0 0 ; if receiver is internal process or sn w0 64 ; pseudo process then jl i5 ; goto remove and release; i4: se w2 (x1+a54) ; if buf is first in queue then jl i5 ; al w0 -1 ; decrease(interrupt addr(proc)) wa w0 x1+a56 ; sz w0 1 ; unless already odd rs w0 x1+a56 ; i5: jl w3 d106 ; remove release(buf); i6: dl w1 i1 ; exit: restore(w0, w1); jl (i3) ; return; ; procedure move mess(from, to); ; comment: moves 8 message (or answer) words from a given storage address to another. ; call: w1=from, w2=to, w3=link ; exit: w0=undef, w1, w2=unchanged, w3=undef ; return address: link d14: rs w3 i3 ; dl w0 x1+2 ; ds w0 x2+2 ; dl w0 x1+6 ; move 8 words from (from) to (to); ds w0 x2+6 ; dl w0 x1+10 ; ds w0 x2+10 ; dl w0 x1+14 ; ds w0 x2+14 ; jl (i3) ; return; e. ; procedure update time(slice); ; comment: senses the timer and updates current time slice and time; ; ; call: w3=link ; exit: w0=undef, w1=unchanged, w2=slice, w3=unchanged ; return address: link b. i9 w. d7: gg w2 b94 ; al w0 x2 ; new value:=sense(timer); ws w2 b14 ; increase:=new value-clock; rs w0 b14 ; clock:=new value; sh w2 -1 ; if increase<0 then wa w2 i9 ; increase:=increase+size of clock; ; comment: timer overflowed...; al w0 x2 ; wa w2 b11 ; slice:=slice+increase; rs w2 b11 ; wa w0 b13+2 ; rs w0 b13+2 ; time low:=time low+increase; sx 2.01 ; jl i8 ; if carry then jl x3 ; i8: al w0 1 ; time high:=time high+1; wa w0 b13 ; rs w0 b13 ; jl x3 ; return; i9: 1<16 ; increase when timer overflows; ; the following entries removes the current process from the timequeue, and initializes state. ; call: w1=cur ; return address: interrupt return d105: ; remove wait message: ; bz w0 x1+a19 ; ; sn w0 0 ; if buf claim(cur)=0 then ; jl d108 ; goto claim buffer (and exit with save w2=0); am a102-a104 ; state:=wait message; d107: ; remove wait event: am a104-a103 ; state:=wait event; d104: ; remove wait answer: al w0 a103 ; state:=wait answer; al w3 c99 ; return:=interrupt return; ; continue with remove internal; ; procedure remove internal(internal, proc state); ; comment: removes the internal process from the timer queue and sets its state ; after this a new current process is selected. ; call: w0=proc state, w1=cur, w3=link ; exit: w0, w1=undef, w2=cur+a16, w3=undef ; return address: link d9: rs w3 i0 ; save(return); hs w0 x1+a13 ; state(cur):=proc state; jl w3 d7 ; update time(slice); rs w2 x1+a35 ; quantum(cur):=slice; dl w3 b13+2 ; ds w3 x1+a39+2 ; start wait(cur):=time; al w2 x1+a16 ; rl w3 i0 ; jl d5 ; remove(cur+a16); ; return; i0: 0 ; saved return ; procedure link internal(proc); ; comment: links the internal process to the timer queue. the timer queue is kept as a ; sorted list, according to the priority. (the smaller the priority is, the better ; is the priority). ; if the time quantum is less than the maximum time slice, the process will be ; linked up in front of other processes with the same priority. otherwise in the ; rear (the time quamtum of the process is transferred to runtime(proc), except ; the amount which is already used of the next quantum). ; call: w1=proc, w3=link ; exit: w0, w1, w2, w3=undef d10: bz w0 x1+a13 ; if state(proc) = running then sn w0 a95 ; jl x3 ; return; rs w3 i0 ; save(return); al w0 a95 ; hs w0 x1+a13 ; state(proc):=running; al w2 x1+a16 ; rl w3 x1+a301 ; priority:=priority(proc); rl w1 x1+a35 ; sl w1 (b10) ; if quantum(proc)>=max slice then jl i3 ; goto insert in rear; al w3 x3-1 ; (code facility); al w1 b2 ; worse:=timer q head; i1: rl w1 x1 ; next: worse:=next(worse); sl w3 (x1-a16+a301) ; if priority(worse)<priority then jl i1 ; goto next; i2: ; insert process: jl w3 d6 ; link(worse, proc+a16); se w3 b2 ; if proc is not linked as the front jl (i0) ; internal then return; rl w1 b1 ; jl w3 d7 ; update time(slice); rs w2 x1+a35 ; quantum(cur):=slice; (may actually be >= max slice); sh w2 (b10) ; if old quantum <= max slice then jl (i0) ; return; ; the following will take care of the round-robin time scheduling; rl w2 (b2) ; proclink := second proc in timer queue; jl w3 d5 ; remove(proclink); rl w3 x2-a16+a301; priority:=priority(proc); (as above) rl w1 x2-a16+a35 ; quantum:=quantum(proc); (as above) ; the process has been in front of the queue for more than the max time slice. ; the run time should be updated with all the quantum, but this would give the process a ; complete time slice next time. instead the used quantum is split in two parts: ; the amount by which it exceeds a multiplum of the max slice, and the rest. these parts ; are the increase in runtime and the new quantum. ; finally the process is inserted in the rear of the timer queue, according to priority. i3: al w0 a85-1 ; w0 := mask for extracting new quantum; la w0 2 ; quantum(proc) := quantum(proc) extract slice; rs w0 x2-a16+a35; ws w1 0 ; al w0 0 ; aa w1 x2-a16+a36+2; add the remaining part of quantum to ds w1 x2-a16+a36+2; runtime(proc); ; at this point there is at least one process in the timer queue, ; i.e. either the dummy process or a 'better' process ; the following is intended for skipping quickly the dummy process: rl w1 b2+2 ; worse := rear of timer queue; (normally dummy process); sl w3 (x1-a16+a301); if priority >= priority(worse) then jl i5 ; goto found; (only in case of inserting dummy process) al w3 x3+1 ; (code facility) i4: rl w1 x1+2 ; next: worse:=last(worse); sn w1 b2 ; if worse<>timer q head and jl i5 ; sh w3 (x1-a16+a301) ; priority(worse)>priority then jl i4 ; goto next; ; notice: the loop went one step to far . . .; i5: rl w1 x1 ; now w1 has been repaired; jl i2 ; goto insert proc; e. \f ; to facilitate the error recovery the interrupt stack and the ; stationary pointers of the monitor table are placed at fixed ; addresses. b128=1200, 0,r.(:b128-k+2:)>1-6 a130 ; date of options a131 ; time of options 0, r.4 ; room for machine id. m. copies of some mon table entries, int stack, mon reg dump (24, 32, 26 hw) ; copy of some monitor pointers: 0-0-0 ; b3: 72: name table start 0-0-0 ; b4: 74: first device in name table 0-0-0 ; b5: 76: first area in name table 0-0-0 ; b6: 78: first internal in name table 0-0-0 ; b7: 80: name table end 0-0-0 ; b8+4: 86: first byte of mess buf pool area 0-0-0 ; b8+6: 88: last byte of mess buf pool area 0-0-0 ; b22: 92: first drum chain in name table 0-0-0 ; b23: 94: first disc chain in name table 0-0-0 ; b24: 96: chain end in name table b50 ; start of interrupt stack 0-0-0 ; b86: driver proc save area ; definition of interrupt stack: b50: 0 ; end of stack b49=k-1 ; terminating stack-address ; power fail element: 0 ; (irrellevant regdump) 0 ; (exception disabled) 0 ; (escape disabled) 0 ; (monitor call not permitted in monitor) c8 ; external interrupt, second level 1 < 23 + 0 ; monitor mode + totally disabled ; monitor element: b52 ; monitor regdump 0 ; monitor exception routine 0 ; monitor escape routine c0 ; monitor call entry c1 ; external interrupt entry, first level 1 < 23 + 6 ; monitor mode + disable all but power/bus error ; user element: 0-0-0 ; user regdump (initialized by select internal) 0-0-0 ; user exception ( - - - - ) 0-0-0 ; user escape ( - - - - ) ; monitor regdump area ; ; used when initializing the whole system, ; and to hold the working registers etc. in case of ; powerfailure or buserror during monitor code b52: 0 ; w0 = 0 (irrellevant) 0 ; w1 = 0 (irrellevant) 0 ; w2 = 0 (irrellevant) 0 ; w3 = 0 (irrellevant) 1 < 23 ; status = monitor mode c99 ; ic = interrupt return 0 ; cause = 0 (irrellvant) 0 ; sb = 0 (irrellvant) 0 ; cpa = 0 (irrellevant) 0 ; base = 0 (irrellevant) 8 ; lower write limit 8.3777 7777 ; upper write limit = all possible core 0 < 12 + 6 ; interrupt limits \f ; comment: the following utility procedures are used by external ; processes during input/output; ; procedure deliver result(result) ; comment: moves the general input/output answer to the beginning of the driver process. ; (the last 3 words of the message buffer are copied too, so they will remain unchanged). ; the answer is send with the specified result to the sender of the buffer. ; ; call: w0 = result, w3 = link, b18 = buffer ; exit: w0 = undef, w1 = proc (= b19), w2 = undef, w3= unchanged ; return address: link: answer delivered ; (internal 3 if buf not claimed and claims exceeded) b. i10 w. g3: am 5-4 ; result 5: g4: am 4-3 ; result 4: g5: am 3-2 ; result 3: g6: am 2-1 ; result 2: g7: al w0 1 ; result 1: w0 := result; rl w3 b20 ; return := wait-next action in driver process; jl g19 ; goto deliver result; g18: al w0 1 ; result 1: w0 := result; g19: ; deliver result: jd k+2 ; disable; ds w0 i3 ; save(link, result); rl w1 b1 ; rl w2 b18 ; buf := current buffer; ac w3 (x2+4) ; sl w3 0 ; if receiver(buf) > 0 then jl i0 ; begin comment: buf not claimed, see link operation; bz w0 x1+a19 ; if bufclaim(cur) <> 0 then sn w0 0 ; begin jl i0 ; decrease(bufclaim(cur)); bs. w0 1 ; receiver(buf) := -receiver(buf); hs w0 x1+a19 ; end; (i.e. claims exceeded will provoke a break below); rs w3 x2+4 ; end; i0: rl w0 x1+a182 ; rl w1 x1+a302 ; wa w1 0 ; get physical address of save area dl w0 x2+a151 ; save first four words of mess. ds w0 g29 ; (used by errorlog ) dl w0 x2+a153 ; ds w0 g30 ; dl w0 x2+22 ; move last 3 words from buf ds w0 x1+14 ; to area; rl w0 x2+18 ; (to retain compatibility with old conventions) rl w3 g24 ; ds w0 x1+10 ; move the 5 std answer words dl w0 g23 ; to area; ds w0 x1+6 ; dl w0 g21 ; ds w0 x1+2 ; (you are disabled, so do not worry about timeslicing...); dl w0 i3 ; restore (link, result); am (b1) ; rl w1 +a302 ; get logical address of save area jd 1<11+22; send answer(result, area, buf); rl w1 b19 ; w1 := current receiver; rl w2 x1 ; if kind of receiver=subprocess then se w2 84 ; check status sn w2 85 ; else return jl. i1. ; jd x3 ; i1: rl w2 g20 ; if one or more of statusbits 1,2,4,9,10,11 se. w1 (b32.) ; or if receiver = special watched receiver sz. w2 (i5.) ; then jl w2 (b31) ; call errorlog jd x3 ; restore link and return i2: 0 ; saved link i3: 0 ; saved result b32: 0 ; proc adr for special watched receiver m. statusmask for errorlog i5: 8.36070000 ; status mask: bit 1 2 3 4 9 10 11 ; procedure link operation (buf) ; comment: links a message to the receiver and returns to the receiver, in case it is the only ; message in the queue (and interrupt address is even). ; otherwise it returns to the wait-next action in the driver process. ; ; call: w2 = buf, w3 = link ; exit: w0 = operation, w1 = proc, w2 = unchanged, w3 = unchanged ; return address: link: single in queue ; (b20): others in queue ; (b20): interrupt addr odd (i.e. driver busy) g17: jd k+2 ; link operation: rs w3 i3 ; save return; ac w3 (x2+4) ; sh w3 0 ; if receiver(buf) < 0 then jl i4 ; begin comment: buf claimed. now release claim; rs w3 x2+4 ; receiver(buf) := -receiver(buf); i.e. positive; rl w1 b1 ; bz w3 x1+a19 ; increase(buf claim(cur)); al w3 x3+1 ; hs w3 x1+a19 ; end; i4: am (b19) ; al w1 +a54 ; jl w3 d6 ; link(mess q(proc), buf); se w3 x1 ; if old last <> mess q(proc) then c33: jl (b20) ; goto wait next(driver process); al w1 x1-a54 ; w1 := proc; rl w0 x1+a56 ; w0 := interrupt addr(proc); so w0 2.1 ; if interrupt addr(proc) is odd then jl w3 g64 ;+2 goto wait next(driver process); jl (b20) ;+2 examine queue: empty => goto wait next; jl (i3) ; return e. ; procedure check user ; comment: checks whether an external process is used ; by the current internal process. if the external is reserved ; it is also checked whether it is reserved by the current ; internal process. ; call: return: ; w0 destroyed ; w1 cur cur ; w2 buf buf ; w3 link link b. i5 w. g14: ; check user; sn w1 (b1) ; if curr.intproc=sender then jl x3 ; return (sender=driverproc) ds w3 i3 ; save w2 w3; rl w2 b19 ; w2:= extproc; jl w3 d113 ; check reserver; jl g6 ; return 0 other reservers goto result 2 else jl i0 ; return 2 intproc is reserver goto nornal return else ; return 4 no reservers jl w3 d102 ; check user jl g6 ; if not user then result 2 else i0: rl w2 i2 ; jl (i3) ; normal return; i2: 0 ; save w2; i3: 0 ; save w3; e. ; end ; procedure check reservation ; comment: checks whether an external process is reserved ; by the current internal process. ; call: return: ; w0 reserved ; w1 cur cur ; w2 buf buf ; w3 link link b.i24 ; begin w. g15: ; check reserver; sn w1 (b1) ; if curr.intproc= sender then jl x3 ; return (sender=driverproc); am (b19) ; rl w0 a52 ; w0:=reserver.extproc; sn w0 (x1+a14) ; if intproc is reserver then jl x3 ; normal return else jl g6 ; result 2; e. ; end ; procedure check operation(oper mask, mode mask) ; comment: checks whether the operation and mode are ; within the repertoire of the receiver. the legal values are ; defined by two bitpatterns in which bit i=1 indicates ; that operation (or mode) number i is allowed. if the ; operation is odd, it is checked whether the input/output ; area is within the internal process. ; call: return: ; w0 oper mask destroyed ; w1 mode mask destroyed ; w2 buf buf ; w3 link destroyed b.i24 ; begin w.g16:rs w3 i0 ; bz w3 x2+9 ; ls w1 x3+0 ; bz w3 x2+8 ; ls w0 x3+0 ; sh w0 -1 ; if mode mask(mode(buf))=0 sl w1 0 ; or oper mask (operation(buf))=0 jl g5 ; then goto result 3; so w3 1 ; jl (i0) ; rl w1 x2+6 ; dl w0 x2+12 ; if odd(operation(buf)) la w3 g50 ; make first and la w0 g50 ; last address in buf even; sl w3 (x1+a17) ; and (first addr(buf)<first addr(sender) sl w0 (x1+a18) ; or last addr(buf)>=top addr(sender) jl g5 ; sh w0 x3-2 ; or first addr(buf)>last addr(buf)) jl g5 ; then goto result 3; ds w0 x2+12 ; message even; jl (i0) ; i0: 0 ; e. ; end ; input/output answer: w.g20: 0 ; status g21: 0 ; bytes g22: 0 ; characters g23: 0 ; file count g24: 0 ; block count g40: 0 ; word5 g41: 0 ; word6 g42: 0 ; word7 0 ; mess(1) operation g29: 0 ; mess(2) first 0 ; mess(3) last g30: 0 ; mess(4) segment no ; procedure next operation ; comment: examines the message queue of the receiver and ; returns to the receiver if there is a message from a ; not-stopped sender. otherwise it returns to the current ; internal process. ; call: return: ; w0 oper ; w1 proc ; w2 buf ; w3 link sender b.i24 ; begin w.g25:rs w3 i2 ; jl w3 g64 ; examine queue( jl c33 ; dummy interrupt); jl (i2) ; i2: 0 ; e. ; end ; procedure examine queue(queue empty) ; call: return: ; w0 operation ; w1 proc ; w2 buf ; w3 link sender b.i24 ; begin w.g64:rs w3 i2 ; i0: rl w1 b19 ; exam q:proc:=current receiver; rl w2 x1+a54 ; buf:=next(mess q(proc)); sn w2 x1+a54 ; if buf=mess q(proc) jl (i2) ; then goto queue empty; rs w2 b18 ; rl w3 x2+6 ; internal:=sender(buf); xl x2+8 ; sh w3 -1 ; ac w3 x3+0 ; bz w0 x3+a13 ; rl w3 x2+6 ; if state(internal)=stopped sx 2.1 ; and operation(buf)(23)=1 so w0 a105 ; or internal<0 sh w3 -1 ; then jl i1 ; begin bz w0 x2+8 ; am (i2) ; no operation; jl 2 ; goto exam q; i1: jl w3 g26 ; end; jl i0 ; oper:=byte(buf+8); i2: 0 ; e. ; end ; procedure no operation ; call: return: ; w0 destroyed ; w1 proc ; w2 destroyed ; w3 link destroyed b.i24 ; begin w.g26:al w0 1 ; g27:al w1 0 ; rs w1 g20 ; status:= g28:rs w1 g21 ; bytes:= rs w1 g22 ; character:=0; jl g19 ; deliver result(1); e. ; end ; procedure increase stop count ; comment: increases the stop count of the sender by 1. ; call: return: ; w0 unchanged ; w1 unchanged ; w2 buf buf ; w3 link destroyed b.i24 ; begin w.g31:rs w3 i0 ; am (x2+6) ; bz w3 a12 ; al w3 x3+1 ; stop count(sender(buf)):= am (x2+6) ; stop count(sender(buf))+1; hs w3 a12 ; jl (i0) ; i0: 0 ; e. ; end ; procedure decrease stop count ; comment: the stop count of the sender is decreased by 1 ; if the operation is odd. if stop count becomes zero and the ; sender is waiting to be stopped, the sender is stopped ; and the stop count of its parent is decreased by 1. ; if the parent has stopped its child, an answer is sent to ; the parent in the buffer defined by the wait address of ; the child. ; call: return: ; w0 destroyed ; w1 destroyed ; w2 destroyed ; w3 link destroyed b.i24 ; begin w.g32:rs w3 i3 ; rl w2 b18 ; bz w0 x2+8 ; rl w3 x2+6 ; internal:=sender(buf); sz w0 1 ; if odd(operation(buf)) sh w3 -1 ; and internal>=0 then jl (i3) ; begin bz w0 x3+a12 ; bs. w0 1 ; stop count(internal):= hs w0 x3+a12 ; stop count(internal)-1; i0: se w0 0 ; exam stop: jl (i3) ; if stop count(internal)=0 bz w1 x3+a13 ; and state(internal)=wait stop so w1 a105 ; then jl (i3) ; begin al w1 x1+a106 ; child state:= hs w1 x3+a13 ; state(internal):=wait start; rl w2 x3+a40 ; buf:=wait address(internal); rl w3 x3+a34 ; internal:=parent(internal); bz w0 x3+a12 ; bs. w0 1 ; stop count(internal):= hs w0 x3+a12 ; stop count(internal)-1; se w1 a99 ; if child state<>wait start parent jl i0 ; then goto exam stop; ; let the current driver claim the buffer, so that ; it may send the answer: rl w1 b1 ; ac w0 x1 ; receiver(buf) := -cur; (i.e. claimed) rs w0 x2+4 ; bz w3 x1+a19 ; decrease(bufclaim(cur)); al w3 x3-1 ; (even if claims would be exceeded) hs w3 x1+a19 ; rl w1 x1+a17 ; answer area := first addr(cur); al w0 1 ; result := 1; jd 1<11+22; send answer; jd (i3) ; return disabled; i2: 0 ; i3: 0 ; e. ; end ; procedure exam sender(sender stopped) ; call: return: ; w0 unchanged ; w1 unchanged ; w2 unchanged ; w3 link link b.i24 ; begin w.g34:rs w3 i0 ; am (b18) ; rl w3 6 ; internal:=sender(buf); sh w3 -1 ; jl (i0) ; if internal<0 bz w3 x3+a13 ; sz w3 a105 ; or state(internal)=stopped jl (i0) ; then goto sender stopped; rl w3 i0 ; jl x3+2 ; i0: 0 ; e. ; end ; procedure follow chain(no. of slices,chain table index, slice) ; the return value is the chain table index of entry number <no. ; of slices> in the chain starting at <chain table index> ; call: return: ; w0 n.o.s. destroyed ; w1 unchanged ; w2 c.t.i. slice ; w3 link destroyed b.i8 w.d74:rs w3 i3 ; save return ac w3 (0) ; as w3 1 ; count := -2 * no. of slices jl. i2. ; goto test; repeat: i0: sl w3 -30 ; if count >= -30 jl. x3+i1. ; then goto advance(-count) ba w2 x2 ; r. 16 ; i1: al w3 x3+32 ; count := count + 32 i2: sh w3 -2 ; test: if count < 0 jl. i0. ; then goto repeat jl (i3) ; return i3: 0 ; e. ; ; bitpatterns: g48: 3 ; constant 3 (= number of chars per word) g50: 8.7777 7776 ; first 23 bits g51: 8.7777 0000 ; first 12 bits g52: 8.0000 7777 ; last 12 bits g53: 8.0000 0377 ; last 8 bits g49: 1<23 ; bit 0 g62: 1<18 ; bit 5 g65: 8.3777 7777 ; last 23 bits g63: 1 ; bit 23 ▶EOF◀