DataMuseum.dk

Presents historical artifacts from the history of:

RC4000/8000/9000

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about RC4000/8000/9000

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download

⟦21d5533a8⟧ TextFile

    Length: 115968 (0x1c500)
    Types: TextFile
    Names: »mcentral    «

Derivation

└─⟦9ccaf6601⟧ Bits:30008165 Bånd med SW8000 kildetekst/release værktøjer
    └─⟦2ba378e4a⟧ 
        └─⟦this⟧ »mcentral    « 

TextFile

\f


m.                moncentral - monitor central logic 17.0 beta
;--------------------------------------------------------------------------
;                      REVISION HISTORY 
;--------------------------------------------------------------------------
; DATE      TIME OR INIT       DESCRIPTION
;           RELEASE
;--------------------------------------------------------------------------
;88.03.24 R14.1A HSI  start of description
;88.03.24 14.53 hsi  insert ap procedure (d4)
;         18.30 hsi  addr 138: max number of processors 
;                     initialized at power up
;88.04.19 15.0  tsh  c45, c46 rewritten and c47 added
;88.04.24 14.24 hsi  addr 138 count instead value in monitor call
;88.04.24 11.16 kak  io-test change in decrease stopcount (x2+8 --> x2+a138+1)       
;88.05.09 10.05 kak  w1=main at c45 and c46 before test
;         14.33 kak  at return from c45 check-result in w0 instead of w2
;88.05.24 07.50 kak  change of cpa and address base included
;88 05 30 10.59 hsi  define global constants in monitor table
;88 06 01 09.15 hsi  add constants to table
;88 06 02 07.00 tsh  updates of c45 and c47 due to protocol changes
;88 06 16 11.12 kak  function table at 'check itc function' extended
;88 08 16 13.32 hsi  update constant table
;88 08 17 17.45 hsi  add new function: stop normal communication
;88 09 12 13.54      d132: answer to removed link: use driverproc
;88 09 16 16.36      update constant table
;88 09 19 11.37 hsi  move constant table to hw addr 160
;88 10 06 13.07 hsi    error in calculate hw (c47) (R15)
;88 10 13 13.55 kak  queue in ioc/lan main is checked after answer device and
;                    deliver interrupt
;88 11 21 13.39 kak  bit 12-14 in message buffer state field is used to result or
;                    a disjunction of results (chained operations)
;                    and the final result is extracted from this field
;88 12 06 15.36 kak  only the first status from chained operations are used
;89 01 23 12.53 kak  deactivate process after program error (c2)
;89 03 08 09.09 kak  no check of waiting operation to mainprocesses after deliver interrupt to driverproc,
;                    the check is performed when driverproc has token care of the interrupt
;89 03 15 15.10 kak  decrease number of outstanding operation is delayed until answer device operation (c47)
;                    or after deliver interrupt to driver (c48), in the last case the main process
;                    is removed from the timer queue before the interrupt is delivered
;89 03 20 10.36 kak  it is checked that clock process is not in queue before the clockinterrupt is delivered
;89 04 03 20.44 hsi  error in c5: set process in running after error
;89 05 25 14.10 kak call of deliver answer changed: result must not be set in receiver field, but kept in w0

;--------------------------------------------------------------------------
;90 05 10 09.36 kak release 17.0
;90 05 10 09.37 kak new test point (41) at deliver interrupt to itc-main (c48)
;90 05 29 14.37 kak errorlog called at ioc and lan errors 
;                   special watched receiver introducted for ioc and lan devices

b.i30 w.
i0=91 02 01 
i1=09 36 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. i3
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      ;
ds. w3 i3.   ; ---------
     se  w2     0       ;     (i.e. until segment size = 0)
     jl.       -8       ; -6
     al. w2     i2.     ;   insert start address of segment 2;
     dl. w1     i1.     ;   get init cat switches
     jd      x3-2       ;   jump to segment 10
     0,
i3:0 ; -----------
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, l60, g70, f30, e70, d160, 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)
;     ITC  functions         (l names)
;     ITC  states            (l names)
;
;     (g and h i and j 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 i/o 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             ;     process description address of driverpoc
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
b58: 0                 ; 54: device address register (used by ifp)
b59: 0-0-0             ;     pu-information table address
b38: 0-0-0             ;     rtc-table address
     r. (:64-k+2:) > 1 ; 60-62 reserved for testprograms
     a135<12+a136      ; 64: release, version of monitor
b42: -1000000          ; 66: current process (single cpu)
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;( last word of last monitor table)
     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
b1:  0-0-0             ;cur process in monitor
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
b9:  0-0-0             ; pu kind offset
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
b79: 0-0-0             ; interrupt statistical table (init in tabinit)
b81: b80               ; monitor call statistical table
b82: 0                 ; current number of processors
b83: 0, 0, 0, 0        ; rescedule counter
     r. (:160-k+2:) > 1; start of constant table:
b200: 0 , 0            ; double nul
b201: 1
b202: 2
b203: 3
b204: 4
b205: 5
b206: 6
b207: 7
b208: 8
b209: 9
b210:10
b211: 8.00030000       ; format identifier (in SSP/clock interrupt word)
b212: 8.37777777       ; last  23 bits
b213: 8.77777776       ; first 23 bits
b214: 8.00017777       ; last  13 bits
b215: 8.00007777       ; last  hw
b216: 8.00003777       ; last  11 bits
b217: 8.77770000       ; first hw
b218: 8.77600000       ; first byte
b219: 8.00177400       ; midt  byte
b220: 8.00000377       ; last  byte
b235: 8.77777400       ; first tree byte
b236: 8.77777777       ; full house
b221: 512              ;
b222: 768
b223: 1<12 
b224: 1<13
b225: 1<14
b226: 1<15
b227: 1<16
b228: 1<17
b229: 1<18
b230: 1<19
b231: 1<20
b232: 1<21
b233: 1<22
b234: 1<23
b237: 8.00177777

;redefinition of old constants
g48 = b203
g49 = b234
g50 = b213
g51 = b217
g52 = b215
g53 = b220
g62 = b229
g63 = b201
g65 = b212
g67 = b216
g68 = b214


b26 = b5                ; use area proceses as pseudo processes

l50 = (:a80>16a.1:)-1   ; ida/ifp device driver included (not used anymore)
l53 = (:a84>16a.1:)-1   ; ida/ifp device driver testoutput 0=yes, -1=no
                        ; Sending a message to the main process the test mask may set, the mask contain 48 bit,
                        ;  default bit 45 and 46 and 47 are set, the meaning of the bits are:
                        ;  no   procedure                       output          no of hw
                        ;  1: area driver part 1                message           18
                        ;  2: area driver part 2                message           18
                        ;  3: area driver part 2                message state      2
                        ;  6: disc driver part 1                message           18
                        ;  7: disc driver part 2                message           18
                        ;  8: disc driver part 2                message state      2
                        ; 11: tape driver part 1                message           18
                        ; 12: tape+printer+gsd driver part 2    message           18
                        ; 13: tape+printer+gsd driver part 2    message state      2
                        ; 16: main driver part 2                message           18
                        ; 17: main driver part 2                message state      2
                        ; 24: tape+printer+gsd driver part 1    message           18
                        ; 25: csp terminal driver part 1        message           18
                        ; 26: csp terminal driver part 2        message           18
                        ; 40: special set up reserve and
                        ;     release process                   ext proc          14
                        ; 41: interrupt, supervisor message     comm. area        24
                        ; 45: interrupt                         buffer addr.       2
                        ; 46: start controller                  comm. area        24
                        ; 47: interrupt                         comm. area        24


c.(:a399>23a.1:)-1
; definition of dump area used in prepare dump (only RC9000-model 10)
      0                 ; lower dump area: first address
b27:  0                 ; lower dump area: no of segments
      0                 ; upper dump area: first address
b28:  0                 ; upper dump area: no of segments
z.

; 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
b96 = 8.04 * 2         ; status : cpu status register
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
                     ;         60:  /60
                     ;         65:  /65

; the following registers are only defined in a mp:

b104= 8.24*2         ; cur process register
b105= 8.26*2         ; pu table register
b106= 8.27*2         ; exception offset register
b107= 8.30*2         ; dump offset register
b108= 8.25*2         ; pu index register

; 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.

; 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)
c29: jl.      (+2)   ; goto internal break
            c28      ;


; 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.

b.  i2, j0  w.
c99:                   ; interrupt return:
b. h1 w.               ;  if mp then
     am        (b9)    ;
h0=k
     jl.       0       ;  begin
     jl         c24    ; goto mp activation
c.(:h0+a8-k-1:)
     am  0, r.(: h0+a8+2-k :)>1 ;  fill up
z.
e.                     ;  end mp

     rl  w1     b1     ; proc := cur
     sh  w1     0      ; if cur defined and
     jl.        i0.    ;
     zl  w0  x1+a13    ;  proc.state <> running then
     sn  w0     a94    ;  begin
     ri         a179   ;
i0:  jl. w3     d8.    ;     activate process
     rs  w1     b42    ;
     rs  w1     b51    ;     cur:= proc
     rs  w1     b1     ;     cur process in monitor := proc;
     al  w2  x1        ;
     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;

     ri         a179   ;    return interrupt;
c24: rl  w2     b2     ;    proc:=first in queue ; activated:=true
     al  w1  x2-a16    ;
     se  w2     b2     ;    do while queue not empty and activated
     jl  w3     d4     ;     activate process; 88.03.24 14.53
     ri         1      ;     return to user;
     jl. w3     d8.    ;
     rl  w3     b82    ;    if no of cpues = 1 then
     sn  w3     1      ;    cur process := proc;
     rs  w1     b42    ;
     jl         c24    ;    endwhile
                       ; end
                       ; return
e.


; procedure check itc function
;
;
;     call
;
;  w0  - 
;  w1  -
;  w2  - (8000 special: main + a241)
;  w3  -
;

b. i10,  j21  w.
c45:                      ; procedure check_itc_function
                          ; begin
c.l53  b.  f4  w.         ; ****** test 47 ******
     rs. w3     f1.       ;
     al  w1  x2-a241      ; 
     rs. w1     f0.       ;
     jl. w3    (f3.)      ;
     47                   ;
f0:  0                    ; main
f1:  0                    ;
     jl.        f2.       ;
     al  w0  x1+a500      ; dump main.communication area
     al  w1  x1+a517      ;
     jl. w3    (f4.)      ;
     jl.        f2.       ;
f3:  d150                 ;
f4:  d151                 ;
f2:                       ;
e.z.                      ; ****** end test 47 ******
                          ;   -----> 8000 special <------
     al  w1  x2-a241      ; 
                          ;   -----> end 8000 special <------
     al  w0     8.0377    ;
     la  w0  x1+a500      ;   if main.gen_info.result = no_credit or
     se  w0     6         ;      main.gen_info.result = illigal_link then
     sn  w0     7         ;      panic; <* protocol error *>
     jl        -1         ;
     rs. w0     i6.       ;   <* save result *>
                          ;
     rl  w0     b227      ;   if main.gen_info.answer then   <* bit 1<16 *>
     la  w0  x1+a500      ;   begin
     sn  w0     0         ;
     jl.        j1.       ;     main.free_buffers :=
     al  w0     1         ;     main.free_buffers + 1;
     ba  w0  x1+a78+0     ;
     hs  w0  x1+a78+0     ;   end;
j1:                       ;
     rl  w0     b219      ;   <* middle octet *>
     la  w0  x1+a500      ;
     ls  w0    -8         ;
     rl  w3  x1+a503      ;
     sn  w3     0         ;   if process-id = 0 then
     jl.        j2.       ;   skip errorlog check;
     se  w3     (b32)     ;   if special watched receiver or
     se  w0     0         ;      check<>0 then
     sz                   ;
     jl.        j2.       ;   begin
     rx  w1     6         ;
     jl  w2     (b31)     ;     < call error-log >
     al  w1  x3           ;
     al  w2  x1+a241      ;
                          ;   end;
j2:                       ;
     rl  w3     b218      ;   <* left octet *>
     la  w3  x1+a500      ;
     ls  w3    -15        ;
     sl  w3     63        ;   if main.function > 15 then
     jl        -1         ;   panic;
                          ;
     rl. w0     i6.       ;   <* w0: result, w1: main, w2: main+a241 *>
     jl.    (x3+j3.)      ;   goto case function of
                          ;func, a :
j3:            -1         ;  0   0 : undef
               -1         ;  0   1 : undef
               -1         ;  1   0 : undef
     c47                  ;  1   1 : answer device operation
     c48                  ;  2   0 : create link           - deliver interrupt
     c48                  ;  2   1 : answer create link    - deliver interrupt
               -1         ;  3   0 : undef
     c48                  ;  3   1 : answer remove link    - deliver interrupt
     c48                  ;  4   0 : attention             - deliver interrupt
               -1         ;  4   1 : undef
               -1         ;  5   0 : undef
     c48                  ;  5   1 : answer regret         - deliver interrupt
               -1         ;  6   0 : undef
     c48                  ;  6   1 : answer reserve device - deliver interrupt
               -1         ;  7   0 : undef
     c48                  ;  7   1 : answer release device - deliver interrupt
     c48                  ;  8   0 : remove link request   - deliver interrupt
               -1         ;  8   1 : undef
               -1         ;  9   0 : undef
     c48                  ;  9   1 : answer initialize controller - deliver interrupt
               -1         ; 10   0 : undef
     c47                  ; 10   1 : answer supervisor_operation
               -1         ; 11   0 : undef
     c48                  ; 11   1 : answer reset
               -1         ; 12   0 : undef
     c48                  ; 12   1 : answer stop normal communication
               -1         ; 13   0 : undef
     c47                  ; 13   1 : answer operator message
               -1         ; 14   0 : undef
               -1         ; 14   1 : answer close system: just panic
               -1         ; 15   0 : undef
               -1         ; 15   1 : answer reload system: just panic

i6:  0                    ; save result
                          ;
e.                        ; end;


; interrupt acknowledge procedure
;
; the controller has read it's communication area
;
;     call
; w0  -
; w1  -
; w2  - (8000 special: main + a229)
; w3  -
;

b. j5 w.
c46:                      ; procedure acknowledge interrupt
                          ; begin
c. l53  b.  f4 w.         ; ****** test 45 ******
     rs. w3     f1.       ;
     al  w1  x2-a229      ; 
     rs. w1     f0.       ;
     jl. w3    (f3.)      ;
     45                   ;
f0:  0                    ; main
f1:  0                    ;
     jl.        f2.       ;
     al  w0  x1+a551      ; dump message buffer address
     al  w1  x1+a551      ;
     jl. w3    (f4.)      ;
     jl.        f2.       ;
f3:  d150                 ;
f4:  d151                 ;
f2:                       ;
e.z.                      ; ****** end test 45 ******
                          ;
                          ; ------>    RC8000 special    <-------
     al  w1  x2-a229      ; 
                          ; ------>  end RC8000 special  <-------
     ac  w0     2.010000+1;
     la  w0  x1+a78       ;   main.com_state := ready;
     hs  w0  x1+a78+1     ;
;
c42:                      ; entry2: <* after answer device *>
     rl  w2  x1+a81       ;   element := main.waiting_q.first;
     sn  w2  x1+a81       ;   if element = none then
     jl         c99       ;      return_from_interrupt;
     al  w0     0         ;   force :=
     sl  w2     (b8+4)    ;
     sl  w2     (b8+6)    ;   if element <> message then no
     jl         j2        ;
     al  w0     2.1000000 ;   else message.state.force;
     la  w0  x2+a138      ;
     ls  w0     -6
j2:                       ;
     jl.       (+2)       ;   test_ready_and_setup(force, message);
                d142      ;
                          ; end;

e.

; procedure deliver clock interrupt.
; only the clock interrupt from the i-o mp (or the cpu) is transferred to
; the monitor clock driver.
; return: interrupt return

c49: al  w0     0      ; 
b. h0 w.               ; if mp then
     am        (b9)    ; get pu index
   h0=k                ;
     jl.         0     ;
     gg  w0     b108   ; 
c.(:h0+a8-k-1:)
     am 0, r.(:h0+a8+2-k:)>1
z.
e.                     ; end
     sn  w2  (x2)      ; if in queue or
     se  w0     0      ; not i-o pu or cpu then
     jl         c99    ;   return 
     jl         c50    ; else deliver interrupt



; 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 -10         ; test test
;    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);
     rl  w3  x1+2      ;
     rs  w2  x1+2      ;
     rs  w2  x3+0      ;
     rs  w1  x2+0      ;
     rs  w3  x2+2      ;
     jl        (h0)    ;
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);
     zl  w0  x1+a13    ; if process not running then
     se  w0     a94    ; link process to running queue
     jl         d10    ;
     jl      x3        ;


; 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
b. i5, j5  w.

i1: 0                  ; saved return
                       ;
d129:                  ; unconditionally reset:
     am       a235-a225;   <point at something <> 0>
d130:                  ; conditionally reset:
     rl  w0  x2+a225   ;   note: the controller is not reset when a
     rl  w3  x2+a235   ;         wait program is timed out;
     sn  w0     0      ;   if transfer in progress then
     jl         j1     ;   begin
     rs  w1     i1     ;     <w3: physical device address>
     al  w1     3      ;     if proc.kind = ifpmain then
     rl  w0  x2+a10    ;        reset device(ifp-reset)
     sn  w0     q26    ;        device address := physical address;
     rs  w3     b58    ;
     se  w0     q26    ;     else 
     am         2.01<1 ;        reset device(normal reset);
     do  w1  x3+0      ;     note: ifp: sub address must be zero - reset is
     rl  w1     i1     ;                signaled in work register!
j1:                    ;   end;

     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)
e.

; 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.         ;
     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(sender.mess): d132

; procedure decrease stopcount(process): d133
;
; 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: d132: w2= message or
d132:
     rl  w1  x2+a142   ;    proc= sender(mess)
     sh  w1  0         ;    if regretted then
     ac  w1  x1        ;    proc= -sender(mess)
     rl  w0  x1+a10    ;    if kind.proc = pseudo then
     sn  w0  64        ;    proc = main proc.sender
     rl  w1  x1+a50    ;
     sz  w0  -1-64     ;    if proc is neither internal nor pseudo then
     rl  w1  b21       ;    proc = driverproc (there is only one)
                       ;    (continue with d133)
; call: d133: w1 = process, w3 = link
; exit: all regs undef
; return address: link

b. i10 w.              ;
d133:rs  w3     i3     ; 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         (i3)   ;      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;
     jl. w3     (i1.)  ;    deliver answer(buf);
     jl         i0     ;    goto loop;
i1:  d15               ;
i3:  0                 ;    saved return;
e.                     ;


; procedure activate_process(internal)
;
; sw-implementation of 'ap'-instruction.
; when using this procedure it is possible to connect and disconnect 
; cpu's during normal operation only by increase and decrease b82.
;
;       call          return
;  w0    -            destroyed
;  w1   internal      internal
;  w2    -            destroyed
;  w3   link          destroyed
;
;  return:  link + 0: no free pu
;           link + 2: internal has been activated
;

b.  i5,  j5  w.

d4:                       ; procedure activate_process(internal)
     rl  w2    (b59)      ; begin
     rl  w0  x2+0         ;
     sh  w0     0         ;   if pu_table.free_pu = 0 then
     jl      x3+0         ;      return(link);
                          ;
     rs. w3     i3.       ;
     rl  w3  x1+a186      ;
     am      x3           ;
     rl  w0  x2+2         ;
     ls  w3    -1         ;   if internal.last_pu < no_of_pu and
     sl  w3    (b82)      ;      pu_table(internal.last_pu) = 0 then
     jl.        j1.       ;   begin
     ls  w3    +1         ;
     sn  w0     0         ;     selected_pu := internal.last_pu;
     jl.        j3.       ;   end
j1:                       ;   else
     rl  w3     b82       ;   begin
     ls  w3    +1         ;     selected_pu := no_of_pu;
j2:  am      x3           ;     while pu_table(selected_pu) <> 0 do
     rl  w0  x2           ;     begin
     al  w3  x3-2         ;       selected_pu := selected_pu - 1;
     se  w0     0         ;
     jl.        j2.       ;     end;
j3:                       ;   end;
     al  w0    -1         ;
     wa  w0  x2+0         ;   pu_table.free_pu :=
     rs  w0  x2+0         ;   pu_table.free_pu - 1;
     am      x3           ;
     rs  w1  x2+2         ;   pu_table(selected_pu) := internal;
     rl. w3     i3.       ;
     jl      x3+2         ;   return(link+2);
                          ;
i3:  0                    ; saved link

e.                        ; end;

; 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      ;    
     al  w1     b8    ;    head := mess buf pool head; (i.e. link in rear);

; 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.

; ****** stepping stones for absolute addresseable monitor routines ******
;

; procedure claim buffer(cur, buffer);  <* d108 *>
;
;        call          return
;  w0    -             destroyed
;  w1    cur           cur
;  w2    buffer        buffer
;  w3    link          link
;

d108: jl.       (+2)    ; claim buffer
                  d58   ;


; procedure regretted message(buffer);  <* d75 *>
;
;        call          return
;
;  w0    -             unchanged
;  w1    -             unchanged
;  w2    buffer        buffer
;  w3    link          destroyed
;

d75:  jl.       (+2)    ; regretted message
                  d65   ;


; 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 addr: link: within process
;              c29 : not within process

d110: jl.      (+2)     ; check message area and name area:
                 d66    ;
d17:  jl.      (+2)     ; check name (save w3) area:
                 d67    ;
d111: jl.      (+2)     ; check name (save w2) area:
                 d115   ;

; procedure check within(first, last);
; comment: checks that the specified area is within the process
;        call          return
;  w0    last          last
;  w1    cur           cur
;  w2    first         first
;  w3    link          link
;  return: link: within process
;          c29 : not within process

d112: jl.      (+2)     ; check within:
                 d116   ;


; procedure check message area and buf
;        call          return
;  w0    -             destroyed
;  w1    cur           cur
;  w2    -             buf
;  w3    link          link
;  return:  link: ok
;           c29 : mess area outside cur
;           c29 : buf not message buf

d103: jl.      (+2)     ; check message area and buf
                 d117   ;


; procedure check message buffer;
; checks whether the save w2 of the internal process is a message buffer address
;        call          return
;  w0    -             destroyed
;  w1    cur           cur
;  w2    -             buf
;  w3    link          link

d12: jl.       (+2)     ; check message buffer:
                 d68    ;


; procedure check event(proc, buf);
; checks that buf is the address of an operation in the event queue of 
; the internal process
;        call          return
;  w0    -             destroyed
;  w1    proc          proc
;  w2    buf           buf
;  w3    link          link
;  return: link: buffer address ok
;          c29:  buf is not in the queue

d19: jl.      (+2)      ; check event:
                d69     ;
; procedure conditional reschedule
; procedure unconditional reschedule
; If the 'conditional' entrypoint is used, the internal process is 
; rescheduled if 'no of free pu' in the pu-table is 0 otherwise no
; rescheduling is performed. This test is done because there is no
; need for rescheduling if ther is an idle pu; if done the process
; may change pu and the cache will be destroyed.
;         call              return
; w0      -                 destroyed
; w1      internal          internal
; w2      -                 destroyed
; w3      link              destroyed
;

d20:  jl.      (+2)      ; conditional reschedule
                 d40     ;

d21:  jl.      (+2)      ; unconditional reschedule
                 d41     ;



; 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
d101:jl.      (+2)      ; check and search name;
                d43     ;

; 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: jl.      (+2)      ; search name;
                d44     ;

; 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: jl.      (+2)      ; search name;
                d45     ;

     a107              ; max base lower
d72: a108              ; max base upper
     a107-1            ; extreme lower
d73: a108+1            ; extreme upper


 

; procedure update time(slice);
; comment: senses the timer and updates current time slice and time;
;
; call: w3=link
; exit: w0=undef, w1=unchanged, w2=new clock, w3=unchanged
; return address: link

b. i9, j4 w.
d7:  gg  w2     b94    ;
     al  w0     0      ;
b. h1 w.               ;  if mp then
     am        (b9)   ;
h0=k
     jl.       0       ;  begin
     gg  w0     b108   ; get pu index
c.(:h0+a8-k-1:)
     am  0, r.(: h0+a8+2-k :)>1 ;  fill up
z.
e.                     ;  end mp
     sn  w0     0      ; if not i-o pu or cpu then
     jl.        i6.    ;  begin
     rl. w0     i9.    ;    rct(i-o mp) := undefined
     rs  w0    (b38)   ;    get clock from i-0 mp
     al  w0     a194   ;    wait until rct(i-o mp) defined
     do  w0    (b74)   ;
j4:  rl  w2    (b38)   ;
     sn. w2    (i9.)   ;   
     jl.        j4.    ; end
i6:

     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...;
     rx  w0     4      ;

     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;


;procedure activate process
;comment: unlinks the first proc in running queue, increases stopcount
;         and  sets the state to running,
;      call:      return:
; w0:             undefined
; w1:             proc
; w2:             proc+a16 (running queue link)
; w3: link        undefined
d8:  rs  w3     j0     ; save return;

     rl  w2     b2     ; get first in running queue
     al  w1  x2-a16    ; w1:= proc
     al  w0     1      ; proc.stopcount:= 
     ba  w0  x1+a12    ;     proc.stopcount + 1
     hs  w0  x1+a12    ;
     al  w0     a94    ; proc.state:= running
     hs  w0  x1+a13    ;
     jl  w3     d7     ; update time;
     al  w0  x2        ;
     al  w2  x1+a16    ;
     ws  w0  x1+a35    ; proc.quantum := starttime
     rs  w0  x1+a35    ;
     rl  w3  x2        ; unlink proc
     rx  w2  x2+2      ;
     rs  w3  x2        ;
     rx  w2  x3+2      ;
     rs  w2  x2        ;
     jl        (j0)    ; return


; 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 passivate process (new state)
; passivates the current process i.e
;     - decreases stopcount (eventually stopping the process)
;     - updates the time quantum used by the process
;     - sets the state to new state if the process has not been stopped
;
;       call         return

;w0   new state      process state
;w1   proc           undefined
;w2                  proc.timeq (proc +a16)
;w3   link           undefined


d9:  
     ds  w0     j1     ; save state , return, and proc
     rs  w1     j2     ;
     jl  w3     d7     ; update time
     sh  w2 (x1+a35)   ; if stoptime > starttime then
     wa. w2     i9.    ;    stoptime := stoptime + size of clock
     ws  w2  x1+a35    ; proc.quantum:= stoptime-starttime     
     rs  w2  x1+a35    ;
     dl  w3  b13+2     ; proc.start wait:= now
     ds  w3  x1+a39+2  ;
     jl  w3  d133      ; test and decrease stopcount
     al  w0     0      ; rescedule count := 0
     al  w1     0      ; 
b. h1 w.               ;
     am     (b9)       ;
h0=k                   ;
     jl.        0      ;
     gg  w1     b108   ;
c. (:h0+a8-k-1:)       ;
     am 0, r.(:h0+a8+2-k:)>1;
z.                     ;
e.                     ;
     rs  w0  x1+b83    ;
     rl  w1  j2        ; if proc.state still is running then
     zl  w0  x1+a13    ;
     sn  w0     a94    ;
     rl  w0     j1     ; proc.state:= new state
     hs  w0  x1+a13    ;
     al  w2  x1+a16    ;
b. h1 w.               ;  if mp then
     am        (b9)    ;
h0=k
     jl.       0       ;  begin
     dp                ;   deactivate process;
c.(:h0+a8-k-1:)
     am  0, r.(: h0+a8+2-k :)>1 ;  fill up
z.
e.                     ;  end mp
     jl        (j0)    ;

j0: 0                  ; return
j1: 0                  ; new state
j2: 0                  ; current process

                       ;    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: rs  w3     i0     ;    save(return);
     al  w0     a95    ;  
     hs  w0  x1+a13    ;    state(proc):=waiting for cpu;

     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);
     sn  w1     b2     ; until last
     jl         i2     ;
     sl  w3 (x1-a16+a301) ; if priority(worse)<priority then
     jl         i1     ;    goto next;
i2:                    ; insert process:
     rl  w3  x1+2      ;
     rs  w2  x1+2      ;
     rs  w2  x3+0      ;
     rs  w1  x2+0      ;
     rs  w3  x2+2      ;
     jl        (i0)    ;      internal then return;

; 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);
     al  w1     b2     ; insert process in rear of queue

     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

m.                       end of link internal
; 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-7
a125        ;  job host identification
a130        ;  date of options
a131        ;  time of options
t.

m.                copies of some mon table entries, int stack, mon reg dump (26, 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
     a135<12+a136      ;       64: release, version of monitor
     0-0-0             ; b59:  56: pu inf table
     0-0-0             ; b79: 124: interrupt stat table
     0-0-0             ; b81: 126: monitor call stat table
     0-0-0             ;           reserved
     0-0-0             ;           reserved
     0-0-0             ;           reserved

; definition of interrupt stack:

b50: 0                 ; end of stack
b49=k-1                ; terminating stack-address

; power fail element:
     0                 ;    (irrellevant regdump)
     0                 ;    (exception disabled)
     -1                ;    (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
b51: -1                ;     current process in monitor (escape not used in monitor mode
     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+1<5    ; status = monitor mode + no process active
     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
     0                 ; puindex


; procedure move message(from, to);  <* d14 *>
;
;        call          return
;  w0    -             destroyed
;  w1    from          from
;  w2    to            to
;  w3    link          destroyed
;

d14:  jl.      (+2)     ; move message
                 d64    ;

; 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;


; procedure remove user(internal, proc);      <* d123 *>
; procedure remove reserver(internal, proc);  <* d124 *>
;
;        call          return
;  w0    -             destroyed
;  w1    internal      internal
;  w2    proc          proc
;  w3    link          link
;

d123: jl.      (+2)     ; remove user
                 d53    ;
                        ;
d124: jl.      (+2)     ; remove reserver
                 d54    ;


; procedure insert reserver(internal, proc);  <* d125 *>
; procedure insert user(internal, proc);      <* d126 *>
;
;        call          return
;  w0    -             destroyed
;  w1    internal      internal
;  w2    proc          proc
;  w3    link          link
;

d125: jl.      (+2)     ; insert reserver
                 d55    ;
                        ;
d126: jl.      (+2)     ; insert user
                 d56    ;


; procedure lock monitor
; returns disabled!

b. h0  w.
d80:                 ;
     am       (b9)   ; if mp then 
h0=k                 ;
     je.       0     ; (lock must be called with interrupts enabled)
     lk      b51     ; lock(monitor);
c.(:h0+a8-k-1:)
     am        0     ;
r.(:h0+a8+2-k:)>1    ;
z.

     jd    x3        ; return disabled


; procedure unlock
; returns enabled

d81:                 ;
     am      (b9)    ; if mp then
h0=k                 ;
     jl.      0      ;
     ul      b51     ; unlock(monitor)
c.(:h0+a8-k-1:)
     am       0
r.(:h0+a8+2-k:)>1
z.
     je     x3       ; returns enabled
e.
\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     b21     ; cur = driverproc
     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      (b21)     ;
     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: -2                 ; 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     b21    ; cur = driverproc
     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     destroyed
b. i5 w.
g14:                   ; check user;
     sn  w1    (b 21)    ;  if curr.intproc=driverproc then
     jl      x3        ; return 
     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    (b 21)    ;  if curr.intproc= driverproc then
     jl      x3        ;  return  ;
     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       ;
      zl  w0  x2+a138+1 ;
      rl  w3  x2+6      ;   internal:=sender(buf);
      sz  w0  2.0000001 ;   if io_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  driver claim the buffer, so that
; it may send the answer:
     rl  w1     b21    ;
     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 check i-o transfer (document size, message);
;
;        call              return
;  w0    size of document  size of document
;  w1    -                 unchanged
;  w2    message           message
;  w3    link              destroyed
;

g37:                   ; 
     jl.     (+2)      ; goto check i-o transfer;
               d146    ;

; 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.                      ;



; procedure test users , reserver, and writeprotecters(intproc,extproc);
; reg    call        return
; w0                 undef
; w1     intproc     unchanged
; w2     extproc     unchanged
; w3     link        result

; the procedure set result = 2.000001  if intproc is user
;                          = 2.000011  if intproc is reserver (and user)
;                          = 2.000101  if intproc and other ip are users
;                          = 2.000100  if there only are other users
;                          = 2.001100  if another ip is reserver (and user)
;                          = 2.01----  if intproc has writeprotected
;                          = 2.10----  if other(s) has writeprotected
;                          = 2.11----  if intproc and other(s) has writeprotected
; writeprotection bit can only be set if the extprocess is an areaprocess.
; of extproc else result is set to zero

b. i5,j5  w.
d76: ds. w3     j1.    ;  save(link,extproc);
     rl  w0  x2+a52    ;  w0:=reserver.extproc;
     al  w3     2.10   ;
     sn  w0  (x1+a14)  ;  if intproc is reserver then
     jl.        i3.    ;  goto test other users;
     al  w3     0      ;
     se  w0     0      ;  if there is another reserver then
     al  w3    2.1000  ;  set other-reserver bit;
i3:  ba  w2  x1+a14    ;  w2:=addr(bitpattern.intproc);
     bz  w0  x2        ;  w0:=  bitpattern.intproc;
     sz  w0  (x1+a14)  ;  if userbit.intproc is on then
     al  w3  x3+1      ;  w3:=w3+1 <* set intproc is user *> else
     al  w2   a402     ;
i0:  am.       (j0.)   ;
     bz  w0 x2         ;  w0:=next pattern.userbittable;
     sn  w0     0      ;  if no users then
     jl.        i1.    ;  goto f1;
     hs  w2     0      ;  
     sn  w0  (x1+a14)  ;  if only intproc is user then 
     jl.        i1.    ;  goto f1 else
     al  w3  x3+4      ;  result:=result add 2.0100;
     jl.        i2.    ;  goto return;
i1:  al  w2  x2+1      ;  w2:=next rel addr;
     se  w2 a402+a403  ;  if not end bittable then
     jl.        i0.    ;  goto f0;

i2:  rl. w2     j0.    ;  if extproc=area then 
     rl  w0  x2+a10    ;  begin
     se  w0     4      ;
     jl.        i5.    ;
     rs. w3     j0.    ;    <* save result *>
     jl. w3   d114.    ;    check writeprotect(intproc, extproc);
     jl.        i4.    ;+0: none:
     am         -2 ; j3;+2: intproc:
     am         -2 ; j4;+4: other(s):
     rl. w0     j5.    ;+6: intproc + other(s):
     rl. w3     j0.    ;
     ea  w3      1     ;    <* add writeprotection bits *>
     sz                ;  end;
i4:                    ;
     rl. w3     j0.    ;
i5:  jl.       (j1.)   ;  return;

j0:  0
j1:  0
j3: 2.010000           ; intproc
j4: 2.100000           ; other(s)
j5: 2.110000           ; intproc + other(s)
e.




; procedure check writeprotect(internal, proc);
;      call           return
; w0    -            unchanged
; w1  internal       unchanged
; w2  proc           unchanged
; w3  link           unchanged
;
; return:  link + 0: no internal has writeprotected
;          link + 2: only named internal has writeprotected
;          link + 4: other than named internal has writeprotected
;          link + 6: internal + other has writeprotected
;

b. i10, j10  w.
d114:                  ; begin
     ds. w3      i3.   ;   save registers;
     ds. w1      i1.   ;
     zl  w0  x1+a14+1  ;   <* save internal.idbit mask *>
     rs. w0      i4.   ;
     ea  w2  x1+a14    ;
     al  w2  x2+a404   ;   <* save addr of id-bit element *>
     rs. w2      i5.   ;
     rl. w3      i2.   ;
     al  w2  x3+a405   ;   <* w2: first writeprotect bit element,
     al  w3  x3+a250   ;      w3: top of writeprotect bit array,
     al  w1       0    ;      w1: state = <no internal has writeprotected> *>
j0:                    ;   repeat begin
     zl  w0  x2        ;     if element <> 0 then
     sn  w0       0    ;     begin
     jl.         j2.   ;
     sn. w2     (i5.)  ;       if element.addr = int.bitelement and
     so. w0     (i4.)  ;          element.bit(int.idbit) is on
     jl.         j1.   ;
     al  w1  x1+  2    ;       then state := state and <int has writeprot>;
     sn. w0     (i4.)  ;       if element.addr <> int.bitelement or 
     jl.         j2.   ;          other than int.idbit is on       
j1:  sh  w1       2    ;       then state := state and <others has writeprot>;
     al  w1  x1+  4    ;     end;
j2:                    ;   end until
     al  w2  x2+  1    ;   element = top element;
     se  w2  x3        ;
     jl.         j0.   ;
                       ;
     dl. w3      i3.   ;   <* restore registers and
     wa  w3       2    ;      modify return addr with state *>
     dl. w1      i1.   ;
     jl      x3        ; end;
                       ;
     0                 ; save w0:
i1:  0                 ; save w1: int
i2:  0                 ;  "   " : proc
i3:  0                 ;  "   " : link
i4:  0                 ; id bit of internal
i5:  0                 ; writeprotect id bit element addr in proc



e.


; 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:                   ; begin
     ba  w2  x1+a14     ;
     bz  w0  x2         ;   w0:=internal.userbit;
     bs  w2  x1+a14     ;   reset w2;
     sz  w0 (x1+a14)    ;   if internal is user then
     jl      x3+2       ;     return(link+2)    else
     jl      x3         ;   return(link);
                        ; end;



; 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:                   ; begin
     rl  w0  x2+a52     ;   if proc.reserver=0 then
     sn  w0     0       ;
     jl      x3+4       ;     return(link+4);
     se  w0 (x1+a14)    ;   if proc.reserver<>internal.idbit then
     jl      x3         ;     return(link+0); <* other reserver *>
     jl      x3+2       ;     return(link+2); <* internal reserver *>
                        ; end;

; procedure insert writeprotect(internal, proc)
;
; call w1=internal, w2=proc, w3=link
; exit w0=undef,  w1, w2, w3=unchanged
;

d118:                   ; begin
     ea  w2  x1+a14     ;   element:=proc.userbit element;
     zl  w0  x2+a404    ;   w0:=proc.writeprotect element;
     lo  w0  x1+a14     ;   w0:=proc.writeprotect element or internal.idbit;
     hs  w0  x2+a404    ;   proc.writeprotect element:=updated writeprotect element;
     es  w2  x1+a14     ;
     jl      x3         ; end;


; procedure remove writeprotect(internal, proc);
;
; call: w1=internal, w2=proc, w3=link
; exit: w0=undef,  w1, w2, w3=unchanged
;

d119:                   ; begin
     ea  w2  x1+a14     ;
     zl  w0  x2+a404    ;   element:=proc.userbitelement - displacement;
     sz  w0 (x1+a14)    ;   if element.bit(intproc.idbit) is on then
     lx  w0  x1+a14     ;      element.bit(intproc.idbit):=0;
     hs  w0  x2+a404    ;
     es  w2  x1+a14     ;
     jl      x3         ; end;



; ******  indirect addressed monitor routines ******

; procedure conditional reschedule    (eq d20)
; procedure unconditional reschedule  (eq d21)
; conditional: if 'no fo free pu' = 0 the internal is rescheduled.
;         call           return
; w0      -              destroyed
; w1      internal       internal
; w2      -              destroyed
; w3      link           destroyed
;

b. i10 w.

d40:  rl  w2    (b59)    ; conditional reschedule:
      rl  w2  x2         ; begin
      se  w2     0       ;   if no of free pu > 0 then
      jl      x3         ;   return;
                         ;
d41:  rs. w3     i3.     ; unconditional reschedule:
      al  w0     a95     ;
      jl  w3     d9      ;   deactivate process(internal, waiting for cpu);
      sn  w0     a95     ;   if not internal.stopped then
      jl  w3     d10     ;   link internal(internal);
      jl.       (i3.)    ;
                         ;
i3:   0                  ;
e.                       ; end;



; procedure check and search name (=d17+d11 -> d67+d44) (eq d101)
;
; 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. i25 w.

d43:                   ;
     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); (eq d11)
; call: w2=name, w3=link
; exit: w0, w1, w2=unchanged, w3=entry
; return address: link  : name not found, w3=(b7)
;                 link+2: name found

d44: 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); (eq d71)
; 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)

d45: ds. w3     i3.    ;    save (name, return);
     ds. w1     i20.   ;    save search base;
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
b. h1 w.               ;    if mp then
     am        (b9)    ;
h0=k
     jl.       0       ;    begin
     gg  w1     b104   ;      get cur register;
c.(:h0+a8-k-1:)
     am  0, r.(: h0+a8+2-k :)>1 ;  fill up
z.
e.                     ;    end mp
     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    (i21.)  ;
     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;
     sn. w0    (i19.)  ;              if base.proc = search base 
     se. w1    (i20.)  ;              then goto found;
     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                 ;
i19: 0                 ; search base
i20: 0                 ; 
i21: c98               ;
e.
;

; procedure remove user(internal, proc);      <* eq  d123 *>
; procedure remove reserver(internal, proc);  <* eq  d124 *>
;
; removes the id-bit of the internal from the reserver and/or user fields.
;
;        call           return
;  w0    -              destroyed
;  w1    internal       internal
;  w2    proc           proc
;  w3    link           link
;

d53:                   ; remove user
     ba  w2  x1+a14    ; begin
     zl  w0  x2        ;   if proc.userbits(internal.id-bit) is on then
     sz  w0 (x1+a14)   ;      proc.userbits(internal.id-bit) := 0;
     bs  w0  x1+a14+1  ;
     hs  w0  x2        ;
     bs  w2  x1+a14    ;   if proc.reserver = internal then remove reserver;
                       ; end;
                       ;
d54:                   ; remove reserver
     rl  w0  x2+a52    ; begin
     sn  w0 (x1+a14)   ;   if proc.reserver = internal then
     al  w0     0      ;      proc.reserver := 0;
     rs  w0  x2+a52    ;
     jl      x3        ; end;


; procedure insert reserver(internal, proc);  <* eq d125 *>
; procedure insert user(internal, proc);      <* eq d126 *>
; adds the id-bit of the internal to reserver-/user-fields of proc.
;
;          call           return
;  w0      -              destroyed
;  w1      internal       internal
;  w2      proc           proc
;  w3      link           link
;

d55:                   ; insert reserver
     rl  w0  x1+a14    ; begin
     rs  w0  x2+a52    ;   proc.reserver := internal.id;
                       ;   goto insert user;
                       ; end;
                       ;
d56:                   ; insert user
     ba  w2  x1+a14    ; begin
     zl  w0  x2        ;
     lo  w0  x1+a14    ;   proc.idbit(internal.id) := 1;
     hs  w0  x2        ;
     bs  w2  x1+a14    ;
     jl      x3        ; end;


; procedure claim buffer(cur, buffer);  <* eq d108 *>
; 
;        call            return
;  w0    -               destroyed
;  w1    cur             cur
;  w2    buffer          buffer
;  w3    link            link
;

b.  i0  w.

d58:                   ; claim buffer
     zl  w0  x1+a19    ; begin
     sn  w0     0      ;   if cur.bufferclaim <> 0 then
     jl.        i0.    ;   begin
     bs. w0     1      ;     cur.bufferclaim := cur.bufferclaim - 1;
     hs  w0  x1+a19    ;
     ac  w0 (x2+a141)  ;     buffer.receiver := -buffer.receiver;
     rs  w0  x2+a141   ;
     jl      x3        ;     <* ok return *>
                       ;   end
i0:                    ;   else
     rs  w0  x1+a30    ;   begin  cur.saved w2 := 0;
     jl         c99    ;     goto return from interrupt;
                       ;   end;
e.                     ; end;

; procedure regretted message(buffer);  <* eq d75 *>
; simulates the release of a messge buffer, as in wait answer. the bufferclaim
; of the sender is increased. the buffer is removed and released (unless in
; state = received).
;
;        call             return
;  w0    -                unchanged
;  w1    -                unchanged
;  w2    buffer           buffer
;  w3    link             destroyed
;

b.  i10, j10  w.

d65:                   ; regretted message
     rs. w3     i3.    ; begin
     ds. w1     i1.    ;
     rl  w1  x2+a142   ;
     sh  w1     0      ;   if message.sender < 0 then exit; <* buffer already regretted *>
     jl.        j6.    ;
     ac  w0  x1        ;   message.sender := -message.sender; <* indicates message regretted *>
     rs  w0  x2+a142   ;
     rl  w0  x1+a10    ;   if sender.kind = pseudo proc or
     se  w0     64     ;      sender.kind = csp_terminal then
     sn  w0     q8     ;      sender:= sender.main;
     rl  w1  x1+a50    ;
     sz  w0    -1-64   ;   if sender.kind<>internal and sender.kind<>pseudo then
     rl  w1  x1+a250   ;      sender := sender.driverproc;
                       ;
     zl  w3  x1+a19    ;   sender.bufferclaim := sender.bufferclaim + 1;
     al  w3  x3+1      ;
     hs  w3  x1+a19    ;
                       ;
     rl  w1  x2+a141   ;   receiver := abs(message.receiver);
     sh  w1     0      ;
     ac  w1  x1        ;   if receiver < 5 then
     sh  w1     5      ;      goto remove and release;
     jl.        j5.    ;      <* message contains an answer *>
                       ;
     rl  w0  x1+a10    ;   if receiver.kind <> internal and
     rl  w3  x1+a250   ;      receiver.kind <> pseudo and
     se  w0     0      ;      receiver.driverproc < 0 then
     sn  w0     64     ;   begin
     sz                ;     <* ida/ifp process - receiver driven by monitor *>
     sl  w3     0      ;
     jl.        j2.    ;
                       ;
j0:  sn  w0     q20    ;     proc := receiver;
     jl.        j1.    ;
     sn  w0     q26    ;
     jl.        j1.    ;     while proc.kind <> main do
     rl  w1  x1+a50    ;     proc := proc.main;
     rl  w0  x1+a10    ;
     jl.        j0.    ;
                       ;
j1:  al  w3     2.1000 ;     if message.state = stopped then
     zl  w0  x2+a138+1 ;        return
     sz  w0  x3        ;     else
     jl.        j6.    ;        message.state := stopped;
     lo  w0     6      ;
     hs  w0  x2+a138+1 ;
                       ;
     sn  w2 (x1+a81)   ;     if message = main.waiting_queue.first then
     jl.        j6.    ;        return;
     jl  w3     d5     ;     unlink(message);
     al  w0     1      ;
     jl.        d142.  ;     test ready and setup(message,force));
                       ;     <* it will exit with return from interrupt - the
                       ;        setup procedure of the receiver will take care
                       ;        of a proper action on the regretted message *>
                       ;   end;
j2:                    ;   <* receiver is not an subprocess *>
     rl  w1  x2+a141   ;   if message.claimed then
     sl  w1     0      ;   begin
     jl.        j3.    ;
     se  w0     q20    ;
     sn  w0     q26    ;     if receiver.kind = main then
     sz                ;
     jl.        j6.    ;     begin
     al  w3     2.1000 ;
     zl  w0  x2+a138+1 ;       if message.state = stopped then
     sz  w0  x3        ;       return;  <already stopped>
     jl.        j6.    ;
     lo  w0     6      ;       message.state := stopped;
     hs  w0  x2+a138+1 ;
     ac  w1  x1        ;       if message = main.waiting_queue.first or
     se  w2 (x1+a81)   ;          not message.in_queue then
     sn  w2 (x2+a140)  ;          return
     jl.        j6.    ;       else begin
     jl  w3     d5     ;         unlink(message);
     al  w0     1      ;
     jl.        d142.  ;         test ready and setup(message,force);
                       ;       end;
                       ;     end
                       ;     else return;
                       ;   end;
j3:                    ;   <* the message is neither answer nor claimed *>
     se  w0     0      ;   if receiver.kind = internal or
     sn  w0     64     ;      receiver.kind = pseudo then
     jl.        j5.    ;      goto remove and release;
     se  w0     4      ;   if receiver.kind = area then
     jl.        j4.    ;
     rl  w1  x1+a50    ;      receiver := receiver.main.main; <* physical disc proc *>
     rl  w1  x1+a50    ;
j4:  se  w2 (x1+a54)   ;   if receiver.event_q.first = message then
     jl.        j5.    ;   begin
     al  w0    -1      ;
     wa  w0  x1+a56    ;     if receiver.interrupt_addr is even then
     sz  w0     2.1    ;        receiver.interrupt_addr:=receiver.intterupt_addr-1;
     rs  w0  x1+a56    ;   end;
                       ;
j5: jl  w3      d106   ;   remove and release(message);
                       ;
j6: dl. w1      i1.    ; exit:
    jl.        (i3.)   ;   return;
                       ;
i0:  0                 ; saved registers
i1:  0                 ;
i3:  0                 ;
                       ;
e.                     ; end;


; procedure move message(from, to);  <* eq d14 *>
; moves 8 words (message or answer) from a given storage address to another.
;
;       call          return
;  w0   -             destroyed
;  w1   from          from
;  w2   to            to
;  w3   link          destroyed
;

b.  i0  w.

d64:                   ; move message
     rs. w3     i0.    ; begin
     dl  w0  x1+2      ;
     ds  w0  x2+2      ;   <* move the words *>
     dl  w0  x1+6      ;
     ds  w0  x2+6      ;
     dl  w0  x1+10     ;
     ds  w0  x2+10     ;
     dl  w0  x1+14     ;
     ds  w0  x2+14     ;
     jl.       (i0.)   ;
                       ;
i0:  0                 ;
                       ;
e.                     ; end;

; procedure check mess area and name (save w3) area;
; procedure check name (save w3) area;
; procedure check name (save w2) area;
;      call         return
;  w0  -            destroyed
;  w1  cur          cur

;  w2  -            name
;  w3  link         link

d66:                    ; check message area and name area:
     rl  w2  x1+a29     ; begin
     al  w0  x2+14      ;   mess := cur.save w1;
     sh  w0     0       ;   if overflow or
     jl         c29     ;      mess < cur.first address or
     sl  w2 (x1+a17)    ;      mess >= cur.top address  then
     sl  w0 (x1+a18)    ;      goto internal 3;
     jl         c29     ;
d67:                    ; check name (save w3) area:
     am         a31-a30 ;
d115:                   ; check name (save w2) area:
     rl  w2  x1+a30     ;
     al  w0  x2+6       ;  
                        ; continue with d116!

; procedure check within (first, last);
; checks taht the specified area is within the process
;     call          return
; w0  last          last
; w1  cur           cur
; w2  first         first
; w3  link          link
; return: link: within process
;         c29 : not within

d116:                   ; check within:
     sh  w0     0       ;   if overflow or
     jl         c29     ;      first < cur.first address or
     sl  w2 (x1+a17)    ;      last >= cur.top address  then
     sl  w0 (x1+a18)    ;      goto internal 3;
     jl         c29     ;
     jl      x3         ; end;

; procedure check message area and buf 
;      call           return
;  w0  -              destroyed
;  w1  cur            cur
;  w2  -              buf
;  w3  link           link
;  return: link: ok
;          c29 : mess area outside cur
;          c29 : buf not message buf

d117:                   ; check message area and buf:
     rl  w2  x1+a29     ; begin
     al  w0  x2+14      ;   mess := cur.save w1;
     sh  w0     0       ;   if overflow or
     jl         c29     ;      mess < cur.first address or
     sl  w2 (x1+a17)    ;      mess+14 >= cur.top address then
     sl  w0 (x1+a18)    ;      goto internal 3;
     jl         c29     ;
                        ; continue with check message buf

; procedure check message buf;
; checks whether the save w2 of the internal process is a mess buf addr.
;       call            return
;  w0   -               destroyed
;  w1   internal        cur
;  w2   -               buf
;  w3   link            link
;  return: link: buffer ok
;          c29 : save w2 not mess buf
b. i0  w.

d68:                     ; check message buf:
     rl  w2  x1+a30      ;   buf := internal.sawe w2;
     sl  w2    (b8+4)    ;   if buf < mess buf pool start or
     sl  w2    (b8+6)    ;      buf >=mess buf pool top then
     jl         c29      ;      goto internal 3;
     al  w1  x2          ;
     ws  w1     b8+4     ;   if (buf-poolstart-4) modulo size of message <> 0
     al  w1  x1-a7       ;   then goto internal 3;
     al  w0     0        ;
     wd  w1     b8+8     ;
     rl  w1     b1       ;   w1 :=  cur
     sn  w0     0        ;
     jl      x3          ; return
     jl         c29      ;
e.                       ; end;

; procedure check event (proc, buf);
; checks that buf is the address of an operation in the event queue of the internal process
;        call           return
;  w0    -              destroyed
;  w1    proc           proc
;  w2    buf            buf
;  w3    link           link
;  return: link: buffer address ok
;          c29 : buf is not in the queue

b. i0 w.
d69:                     ; check event:
     al  w0  x2          ; begin
     al  w2  x1+a15      ;   oper := proc.next;
i0:  rl  w2  x2+0        ; next: oper := oper.next;
     sn  w2  x1+a15      ;   if oper = proc.eventq then
     jl         c29      ;      goto internal 3; <*not in queue*>
     se  w0  x2          ;   if buf <> oper then goto next;
     jl.        i0.      ;
     jl      x3          ;   return;
e.                       ; end;

; 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:
;    w2 = 2 * interrupt number
;    ex = 0
b. i3 w.
c1:  al  w1  x2        ; interruptstat(intno) :=
     ls  w1     1      ; interruptstat(intno) + 1;
     wa  w1     b79    ;
     rl  w0  x1+2      ;
     ba. w0    +1      ;
     rs  w0  x1+2      ;
     se  w0     0      ;
     jl.        i3.    ;
     rl  w0  x1+0      ; <* count in double words *>
     ba. w0    +1      ;
     rs  w0  x1+0      ;
i3:                    ;
     wa  w2     b0     ; 
     rl  w1     b51    ; w1 := current process
     sh  w1     0      ; if cur defined then
     jl.        c3.    ; begin
     rs  w1     b1     ;    process in monitor := cur;
     al  w0     1      ;    if rescedule count.cpuno > max then
     al  w3     0      ;       rescedule process
b. h1 w.               ;
     am        (b9)    ;
h0=k                   ;
     jl.        0      ;
     gg  w3     b108   ;
c. (:h0+a8-k-1:)       ;
     am 0, r.(:h0+a8+2-k:)>1;
z.
e.                     ;
     ds. w2     i2.    ;
     wa  w0  x3+b83    ;    if reschedule count > max or 
     rs  w0  x3+b83    ;       internal.state <> running 
     zl  w3  x1+a13    ;    then
     sh  w0     a83    ;       unconditional reschedule
     se  w3     a94    ;    else
     am         d21-d20;       conditional reschedule;
     jl  w3     d20    ;
     dl. w2     i2.    ;
     jl.        c3.    ;    switch out through interrupt-table;

i1:  0                 ; saved proc 
i2:  0                 ; saved intno
e.

; 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:  rl  w1     b51    ;
     rs  w1     b1     ;   process in monitor := cur;
     zl  w0  x1+a13    ;  if internal.state =waiting for stop then
     so  w0     a105   ;  begin
     jl.        c7.    ;
     jl  w3     d9     ;     deactivate process
     rl  w2  x1+a33    ;     internal.ic := internal.ic - 2
     al  w2  x2-2      ;
     rs  w2  x1+a33    ;     (repeat monitor call later if started)
     jl         c99    ;
c7:  al  w3  x2        ;     moncalltable(call no) :=
     ls  w3    -1      ;     moncalltable(call no) + 1;
     ls  w3    +2      ;     <* make odd calls even *>
     wa  w3     b81    ;
     rl  w0  x3+2      ;
     ba. w0    +1      ;
     rs  w0  x3+2      ;
     se  w0     0      ;
     jl.        c3.    ;
     rl  w0  x3+0      ;
     ba. w0    +1      ;     <* count in double words *>
     rs  w0  x3+0      ;

c3:  am.       (+4)    ;    switch out through monitor procedure entry table;
     jl     (x2+0)     ;
                b16    ;    <*address of monitor entry table*>

; second level external interrupt entry:
;
; exit is made to here with:
;   w1 = top register dump
;   w2 = 2 * interrupt number
c8:
     sn  w2     2*7   ; if clock interrupt then
     ri         a179  ;  exit to monitor;

     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:
                       ; 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;
     al  w3     c99    ;
     zl  w2  x1+a13    ; if process active then
     se  w2     a95    ;   deactvate process (and return)
     jl         d9     ;
     hs  w0  x1+a13    ;   else begin                           
     al  w2  x1+a16    ;    process.state := running after error; 
     al  w3     c99    ;    unlink proc from active queue         
     jl         d5     ;   end; return


; 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)
;
; initialize pu information table and if the pu is a mp then start all remaining cpus.
; 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  w2     b59    ;    pu inf table.montop := montop;
     rs  w3  x2+a352   ;

     rl  w3     b12    ;    size := number of storage bytes;
     gp  w3     b92    ;
     rs  w3  x2+a353   ;    pu inf table.size := size;
     am        +12     ;
     al  w3     b49    ;
     rs  w3  x2+a351   ;    pu inf table.inf  := inf;
     rl  w3     b9     ;
     sn  w3     a8     ;    if pu kind = mp then
     jl.        i3.    ;    begin
     rl  w3  x2+a350   ;      iopu.pu tabel register := pu inf table.pu tabel;
     gp  w3     b105   ;
     rl  w3  x2+a354   ;      iopu.exofs register := pu inf table.exception offset;
     gp  w3     b106   ;
     rl  w3  x2+a355   ;      iopu.dmofs register := pu inf table.dump offset;
     gp  w3     b107   ;
                       ;
; start all remaining cpus
     al  w0     1      ;      no of cpues := 1;
     rs  w0     b82    ;
     al  w0     a194   ;      interruptlevel := 8; <*start pu*>
     rl  w1     b67    ;      for i := 1 step 1 until max dev do
i5:  al  w1  x1+a314   ;      if controllertabel(i).chpadr = pu inf tabel then
     sl  w1    (b68)   ;      begin  <*pu-element*>
     jl.        i2.    ;
     rl  w3  x1+a310   ;
     se  w3    (b59)   ;
     jl.        i5.    ;        puaddr := (controllertabel(i) -
     rl  w3     b82    ;
     al  w2  x1        ;                   controllertabel(0)) * 8 and (1 shift 23);
     ws  w2     b67    ;
     lo  w2     g49    ;
     do  w0  x2        ;        start pu(puaddr, interruptlevel);
     sx       2.111    ;        if pu is started then
     sz                ;
     ba. w3     1      ;        no of cpues := no of cpues + 1;
     rs  w3     b82    ;
     jl.        i5.    ;      end;
                       ;   end;
i3:                    ;   else
     al  w0     0      ;      set free pu := 0
     rs  w0 (x2)       ;  (* always rescedule when external interrupt *)
i2:                    ;    
c.(:a90>0 a.1:)-1
     al. w3       i1. ;     dump core via fpa
     jl.         (2)  ;
                d140  ;
i1:                   ;
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.        +2     ;    (if any power fail during this start up,
     jd.        +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


; 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
j4:  c2                ;

c28 :                  ; internal 3:
     rl  w1     b1     ;
     rs  w3  x1+a339   ;    make footprint!
     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.        (j4.)  ;      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
     jl         c99    ;  goto interrupt return
e.                     ;



; answer device operation
;
; the controller has delivered an answer to a 'device operation' 
; message. prepare the RC8000/RC9000 answer
;
;        call
;  w0    result
;  w1    main
;  w2    -
;  w3    function < 1

b.   i10, j30  w.         ; answer device operation
c47:                      ; begin
     ds. w1     i1.       ;
     al  w0  x3           ;
     jl. w3     d156.     ;   decrease no_of_outstanding;
     rl  w2  x1+a501      ;   message := main.message_buffer;
     rl. w3     i6.       ;
     sl  w3     5         ;   if result >= 5 then
     jl        -1         ;      panic;
     rl. w0     i6.       ;
     ls  w0     9         ;   message.state.result:=
     lo  w0  x2+a138      ;   message.state.result or last_result;
     hs  w0  x2+a138+1    ;
     ls  w3    +1         ;   case result of
     jl.    (x3+j5.)      ; 
                          ;
j5:            -1         ; 0 ; -
         j6               ; 1 ; ok
               -1         ; 2 ; -
         j15              ; 3 ; unintelligible
         j15              ; 4 ; malfunction
                          ;
j6:                       ;   ok:
                          ;   -----
     zl  w0  x2+a138+1    ;   begin
     al  w3     2.0100000 ;
     sz  w0  x3           ;     if message.state.answer = 0 then
     jl.        j7.       ;     begin
                          ;
     lo  w0     6         ;       message.state := message.state or answer;
     hs  w0  x2+a138+1    ;
     dl  w0  x1+a520+a151 ;       <* move answer from main.mess_0 - mess_7
     ds  w0  x2+a151      ;          to message.mess_0 - mess_7 *>
     dl  w0  x1+a520+a153 ;
     ds  w0  x2+a153      ;
     dl  w0  x1+a520+a155 ;
     ds  w0  x2+a155      ;
     dl  w0  x1+a520+a157 ;
     ds  w0  x2+a157      ;
                          ;
     jl.        j9.       ;     end
j7:                       ;     else
                          ;     begin
     rl  w3  x1+a520+a150 ;       if not statuserror then
     sn  w3     0         ;       begin
     sz  w0     -1024     ;         if result=1 then
     jl.        j4.       ;         begin
     rl  w0  x1+a520+a152 ;
     wa  w0  x2+a152      ;           message.octet_count :=
     rs  w0  x2+a152      ;           message.octet_count + main.mess_2;
j4:                       ;         end;
                          ;       end;
     rl  w0  x2+a150      ;       <* w3 = new status *>
     sn  w0     0         ;       if old statuserror then
     rs  w3  x2+a150      ;       skip new status;
     rl  w0     b219      ;
     la  w0  x1+a500      ;       check := main.gen_info.check;
     sn  w0     0         ;       if check then
     jl.        j8.       ;       begin
                          ;
     rl  w0  x1+a520+a150 ;         <* move mess_0, mess_3 - mess_7 to
     rs  w0  x2+a150      ;            message *>
     dl  w0  x1+a520+a154 ;
     ds  w0  x2+a154      ;
     dl  w0  x1+a520+a156 ;
     ds  w0  x2+a156      ;
     rl  w0  x1+a520+a157 ;
     rs  w0  x2+a157      ;
j8:                       ;       end <* check = 0 *>
j9:                       ;     end
     jl.        j18.      ;
                          ;   end <* ok *>
                          ;
j15:                      ;   unintelligible:
                          ;   malfunction:
                          ;   ---------------
     al  w0     2.0100000 ;   begin
     lo  w0  x2+a138      ;
     hs  w0  x2+a138+1    ;     message.state := message.state or answer;
                          ;
;    al  w0     0         ;     message.octet_count := 0;
;    rs  w0  x2+a152      ;
                          ;
     jl.        j18.      ;   end <* unintelligible, malfunction *>
                          ;
                          ;
j18:                      ;   common:
                          ;   -------
                          ;   begin
                          ; ------> 8000 special <------
     rl  w3  x1+a235      ;     
     rl  w0  x1+a10       ;     device_address := main.device_address;
     al  w1     2         ;
     se  w0     q26       ;     if main.kind <> ifp then
     am         2.11<1    ;        answer_device(normal)
     do  w1  x3+0         ;     else
     rl. w1     i1.       ;        answer_device(ifp);
                          ; ------> end 8000 special <------
     zl  w0  x2+a138+0    ;     <* don't use com_area any more *>
     bs. w0     1         ;
     hs  w0  x2+a138+0    ;     message.count := message.count - 1;
                          ;
     al  w3     2.0000100 ;
     la  w3  x2+a138      ;     if message.count = 0 and
     sn  w0     0         ;        message.state = transfer_completed then
     sn  w3     0         ;     begin
     jl.        j25.      ;
                          ;
     rl  w3  x2+a141      ;       if message.receiver <> 2 then
     sn  w3     2         ;       begin 
     jl.        j20.      ;         <* if message was sent to an area which is
     sh  w3     0         ;            removed during the operation a result 2
     ac  w3  x3           ;            is inserted in the message *>
     se  w3 (x3+a50)      ;         if receiver.main = receiver then
     jl.        j19.      ;         begin   <* receiver is a mainprocess *>
     rl  w3     b21       ;           driverproc := receiver.driverproc;
     zl  w0  x3+a19       ;           driverproc.buffer_claim :=
     ba. w0     1         ;           driverproc.buffer_claim + 1;
     hs  w0  x3+a19       ;        end;
j19:                      ;
     se  w2 (x1+a200)     ;         if message = main.prepare_dump_message then
     jl.        j20.      ;         begin
     rl  w2  x1+a201      ;
     rl  w1     b21       ;
     jl  w3     d124      ;           remove_reserver(driverproc, main.dump_device);
     al  w0     0         ;
     rl. w1     i1.       ;
     rs  w0  x1+a200      ;           main.prepare_dump_message := 0;
     rs  w0  x1+a201      ;           main.dump_device := 0;
                          ;         end;
                          ;       end;
j20:                      ;
     zl  w0  x2+a138+1    ;       if message.state.io then
     so  w0     2.0000001 ;       begin
     jl.        j22.      ;
     jl  w3     d132      ;         decrease_stopcount(message);
     rl. w1     i1.       ;
     rl  w2  x1+a501      ;
                          ;
     dl  w0  x2+a152      ;
     se  w0     0         ;       
     se  w3     0         ;
     jl.        j22.      ;
     es. w0     1         ;         if message.hw_transfered = 0 and
     wd  w0     g48       ;            message.bytecount <> 0 then
     ea. w0     1         ;            mess.hw :=(((mess.bytes-1)/3)+1)*2
     ls  w0     1         ;
     rs  w0  x2+a151      ;       end;
j22:                      ;
;    rl. w0     i6.       ;
     zl  w0  x2+a138+1    ;
     sh  w0     8.1777    ;       if result=ok then
     jl.        j23.      ;         goto result1
     sz  w0     -2048     ;       if intervention then
     am         1         ;         result:=4;
     am         2         ;         else result:=3;
j23: al  w0     1         ; result1: result:=1;
     jl. w3     d15.      ;       deliver_answer(message);
                          ;     end;
j25:                      ;
     jl.        j30.      ;   end;
                          ;
i6:  0                    ;-2: result
i1:  0                    ; 0: save main

                          ; end; 

; deliver interrupt to itc-main
; sets io result = 0 and continues with deliver interrupt

c48:

c.l53  b.  f4  w.         ; ****** test 41 ******
     rs. w3     f1.       ;
     al  w1  x2-a241      ; 
     rs. w1     f0.       ;
     jl. w3    (f3.)      ;
     41                   ;
f0:  0                    ; main
f1:  0                    ;
     jl.        f2.       ;
     al  w0  x1+a500      ; dump main.communication area
     al  w1  x1+a517      ;
     jl. w3    (f4.)      ;
     jl.        f2.       ;
f3:  d150                 ;
f4:  d151                 ;
f2:                       ;
e.z.                      ; ****** end test 47 ******

     al  w2  x1+a242      ;
     se  w2  (x2)         ; if in queue then
     jl  w3     d5        ;   remove from queue
     al  w0     0        ; io result 0
     al  w3     c99      ;
     jl         d121     ; got to deliver interrupt and goto reutrn from interrupt


j30: rl. w1     i1.      ;
     rl  w0  x1+a78      ;
     so  w0     2.010000 ; if not busy then
     jl         c42      ; continue with check main queue
     jl         c99      ; else goto return from interrupt;
e.
▶EOF◀