home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / SIMTEL / CPMUG / CPMUG015.ARK / KERNL.ASM < prev    next >
Assembly Source File  |  1984-04-29  |  58KB  |  1,737 lines

  1.  
  2.  
  3.  
  4.  
  5.        TITLE  'THE KERNEL SUBROUTINES'
  6.  
  7.  
  8.  
  9.  
  10. ;NOTE:  Small letters will denote the contents of locations referred to
  11. ;       by capital letters.  For example, cpp = (CPP), a = (A), etc.
  12.  
  13.  
  14. ;NMPCB = Total number of PCBs allocated to the operating system
  15. ;NMMB  = Total number of message buffers allocated to the system
  16. ;MBPP  = Number of message buffers allotted to each process
  17. ;NMPR  = Number of priorities allowed
  18.  
  19. ;       0 < NMPCB , NMMB            0 < NMPR          NMPCB < 32
  20. ;       0 < cpp =< NMPCB
  21.  
  22.  
  23. NMPCB  EQU    5
  24. MBPP   EQU    5
  25. NMMB   EQU    NMPCB*MBPP
  26. NMPR   EQU    5
  27.  
  28. MASKQ  EQU    1
  29. MASKM  EQU    2
  30. MASKA  EQU    4
  31.  
  32. ISIS   EQU    64           ; ISIS entry point
  33. LOAD   EQU    6
  34. ERROR  EQU    12
  35.  
  36.  
  37. ;                              MACROS
  38. ;                              ------
  39.  
  40.  
  41. ;Register indexed address:
  42. RXAD   MACRO  REGPR,BSADD       ; (H&L) _ regpr + BSADD
  43.        LXI    H,BSADD
  44.        DAD    REGPR
  45.        ENDM
  46.  
  47.  
  48. ;Register indexed load:
  49. RXLD   MACRO  REG,REGPR,BSADD   ; reg _ (regpr + BSADD) 
  50.        RXAD   REGPR,BSADD
  51.        MOV    REG,M
  52.        ENDM
  53.  
  54.  
  55. ;Register indexed store
  56. RXST   MACRO  REG,REGPR,BSADD   ; (regpr + BSADD) <- reg
  57.        RXAD   REGPR,BSADD
  58.        MOV    M,REG
  59.        ENDM
  60.  
  61.  
  62. ;Register direct load
  63. RDLD   MACRO  REG,ADDR      ; reg <- (ADDR)
  64.        LXI    H,ADDR
  65.        MOV    REG,M
  66.        ENDM
  67.  
  68.  
  69. JNZR   MACRO  REG,LABEL     ; If  reg  is not 0, then jump to LABEL
  70.        XRA    A
  71.        CMP    REG
  72.        JNZ    LABEL
  73.        ENDM
  74.  
  75.  
  76. JZR    MACRO  REG,LABEL      ; If  reg=0 , then jump to LABEL
  77.        XRA    A    
  78.        CMP    REG
  79.        JZ     LABEL
  80.        ENDM
  81.  
  82.  
  83. M6A    MACRO                 ; d <- 0 , e <- 6*a
  84.        RLC
  85.        MOV    E,A            ; e <- 2*a
  86.        RLC
  87.        ADD    E              ; a <- 6*a
  88.        MOV    E,A
  89.        MVI    D,0
  90.        ENDM
  91.  
  92.  
  93. STDM   MACRO                 ; (D&E) is stored at address in (H&L)
  94.        MOV    M,E
  95.        INX    H
  96.        MOV    M,D
  97.        ENDM
  98.  
  99.  
  100. STORE  MACRO  
  101.        PUSH   PSW
  102.        PUSH   H
  103.        PUSH   D
  104.        PUSH   B
  105.        LDA    CPP               ; Now to load STKP with sp
  106.        RLC
  107.        MOV    E,A
  108.        MVI    D,0               ; d _ 0
  109.        RXAD   D,STKP
  110.        XCHG
  111.        LXI    H,0
  112.        DAD    SP
  113.        XCHG                     ; (D&E) <- sp
  114.                                 ; (H&L) <- address of STKP
  115.        MOV    M,E
  116.        INX    H
  117.        MOV    M,D
  118.        ENDM
  119.  
  120.  
  121. RSTOR  MACRO
  122.        RLC                     ; First to load sp with value from STKP
  123.        MOV    C,A
  124.        RXAD   B,STKP
  125.        MOV    E,M
  126.        INX    H
  127.        MOV    D,M
  128.        XCHG
  129.        SPHL 
  130.        POP    B
  131.        POP    D
  132.        POP    H
  133.        POP    PSW
  134.        ENDM
  135.  
  136.  
  137. TRNAM  MACRO
  138. ;Transfer 6 bytes starting in location indicated by H&L to location
  139. ;indicated by D&E.  Note that  b = 0  at end.
  140.        MVI    B,6
  141. XX:    MOV    A,M
  142.        STAX   D
  143.        DCR    B
  144.        JZ     YY+3
  145.  
  146.        INX    D
  147.        INX    H
  148. YY:    JMP    XX
  149.        ENDM
  150.  
  151.  
  152. UNLNK  MACRO  LAST,NEXT
  153. ;Unlink a PCB with index t (which is held in B&C) from the doubly-
  154. ;linked list which uses pointers LAST and NEXT.  We assume that
  155. ;        e = NEXT[t]  and  a = t .
  156.        RXLD   C,B,LAST      ; c <- (LAST[t]) = x
  157.        RXST   E,B,NEXT      ; (NEXT[x]) <- e
  158.        RXST   C,D,LAST      ; (LAST[y]) <- x
  159.        MOV    C,A           ; Restore t to C
  160.        ENDM
  161.  
  162.  
  163.  
  164.  
  165.  
  166.        ORG    8000H        ; Origin is set to 32K
  167.  
  168.  
  169. ;                 THE DATA STRUCTURE
  170. ;                 ------------------
  171.  
  172.  
  173. CPP:   DB     1
  174. AP:    DB     0
  175. FP:    DB     1
  176. FMBP:  DB     1
  177.  
  178. AS:    DB     1  
  179.        DB     0
  180.  
  181. PRP:   ORG    $ + NMPR
  182. NMR:   ORG    $ + NMPR
  183.  
  184.        ; The storage allocated to the message buffers
  185. MBSP   EQU    $ - 1
  186.        ORG    $ + NMMB
  187. NMBP   EQU    $ - 1
  188.        ORG    $ + NMMB
  189. ASTAT  EQU    $ - 1
  190.        ORG    $ + NMMB
  191. MESS   EQU    $ - 2
  192.        ORG    $ + 2*NMMB
  193.  
  194.        ; The storage allocated to the PCBs                 BLOCKED bit
  195. NAM    EQU    $ - 6                ;             PROGRAM bit   |
  196.        ORG    $ + 6*NMPCB          ;                     :     :
  197. EXC    EQU    $ - 1                ;         (EXC[t]) =  XX0000XX
  198.        ORG    $ + NMPCB            ;                      ^     ^
  199. PR     EQU    $ - 1                ;                      | STOPPED bit
  200.        ORG    $ + NMPCB            ;             RESIDENT bit
  201. MBC    EQU    $ - 1  
  202.        ORG    $ + NMPCB
  203. WDMK   EQU    $ - 1
  204.        ORG    $ + NMPCB
  205. RDMK   EQU    $ - 1
  206.        ORG    $ + NMPCB
  207. FMP    EQU    $ - 1
  208.        ORG    $ + NMPCB
  209. FQP    EQU    $ - 1
  210.        ORG    $ + NMPCB
  211. FAP    EQU    $ - 1
  212.        ORG    $ + NMPCB
  213. ABP    EQU    $ - 1
  214.        ORG    $ + NMPCB
  215. NSWP   EQU    $ - 1
  216.        ORG    $ + NMPCB
  217. SEMP   EQU    $ - 1
  218.        ORG    $ + NMPCB
  219. LAP    EQU    $ - 1
  220.        ORG    $ + NMPCB
  221. NAP    EQU    $ - 1
  222.        ORG    $ + NMPCB
  223.  
  224.  
  225.  
  226.  
  227. LP     EQU    $ - 1
  228.        ORG    $ + NMPCB
  229. NP     EQU    $ - 1
  230.        ORG    $ + NMPCB
  231. DSM    EQU    $ - 2
  232.        ORG    $ + 2*NMPCB
  233. STAD   EQU    $ - 2
  234.        ORG    $ + 2*NMPCB
  235. STKP   EQU    $ - 2
  236.        ORG    $ + 2*NMPCB
  237. STACK  EQU    $ - 10             ; Used to store the register pairs B,
  238.        ORG    $ + 10*NMPCB       ; D, H, and also the PSW and PLC
  239.  
  240.  
  241.  
  242. ;                THE KERNEL SUBROUTINES
  243. ;                ----------------------
  244.  
  245.  
  246.  
  247. ;                     SCHED (INDEX)
  248.  
  249.  
  250. ;It is assumed that interrupts were disabled before the scheduler
  251. ;was called.  The integer INDEX is passed to the routine in the B
  252. ;register and has the following interpretation:
  253.  
  254. ;    INDEX          action to be taken and initial data
  255. ;  ---------------------------------------------------------------
  256. ;      0       If there is another ready process of the same pri-
  257. ;              ority as the current one, then the next such after
  258. ;              the current one is scheduled.  (The current process
  259. ;              will be rescheduled if it is the only ready process
  260. ;              in its queue.)  Otherwise, we try to schedule the
  261. ;              first ready process of lower priority.  If there is
  262. ;              none, then we HALT.  We assume that
  263. ;                           c = q = (PR[cpp]).
  264. ;     > 0      The process corresponding to the PCB with index
  265. ;              INDEX is scheduled.  We assume that
  266. ;                          c = r = (PR[INDEX]).
  267.  
  268. ;At the end we have  b = 0.
  269.  
  270.  
  271. SCHED: STORE
  272.        MOV    A,B
  273.        MVI    B,0
  274.        ORA    A
  275.        JZ     ROBIN             ; Jump is INDEX = 0
  276.  
  277. SCH00:                          ; Entry point for initialization
  278.                                 ; routine
  279.        STA    CPP               ; cpp _ INDEX
  280.        MOV    E,A               ; e <- INDEX
  281.        MOV    D,B               ; d <- 0
  282.        RXLD   E,D,NAP           ; e <- x = (NAP[INDEX])
  283.        RXST   E,B,PRP           ; (PRP[r]) <- x
  284.        ; PRP[r] now points to the PCB following the one with
  285.        ; index INDEX
  286.  
  287. SCH0:  RSTOR
  288.        EI
  289.        RET                      ; Return
  290.  
  291. ROBIN: RXLD   A,B,NMR           ; a _ (NMR[q]) 
  292.        ORA    A
  293.        JZ     SCH2              ; Jump if there is no ready process
  294.                                 ; of priority q
  295.  
  296.        ; The case where  (NMR[q]) > 0
  297.        RXLD   E,B,PRP           ; e _ t = (PRP[q])
  298.        MOV    D,B               ; d <- 0
  299. SCH1:  RXLD   A,D,EXC           ; a _ (EXC[t])
  300.        ANI    00000010B
  301.        JNZ    NEXT              ; Jump if this process is BLOCKED
  302.  
  303.  
  304.  
  305.  
  306.        RXLD   A,D,NAP           ; a <- (NAP[e])
  307.        RXST   A,B,PRP           ; The priority pointer is set
  308.                                 ; to the process after the one
  309.                                 ; that is now being scheduled
  310.        LXI    H,CPP
  311.        MOV    M,E               ; cpp <- t
  312.        MOV    A,E
  313.        JMP    SCH0
  314.  
  315. NEXT:  RXLD   E,D,NAP           ; e _ (NAP[t])
  316.        JMP    SCH1
  317.  
  318. SCH2:  INR    C                 ; Case where (NMR[q]) = 0
  319.        MVI    A,NMPR            ; a _ NMPR
  320.        SUB    C
  321.        JP     ROBIN             ; Jump if  q =< NMPR
  322.  
  323.        EI
  324. HALT:  HLT                      ; Case of no ready processes
  325.  
  326.  
  327.  
  328. ;                             P [ID,SEM]
  329.  
  330.  
  331. ;SEM is the address of the semaphore and is passed to the routine in
  332. ;the D and E registers. ID is a 1 byte integer specifying which global
  333. ;semaphore SEM is referring to, if any.  It is passed to the routine
  334. ;in the C register.
  335.  
  336. ;         ID                   semaphore
  337. ;     -----------------------------------------------------
  338. ;          2                       AS
  339. ;          0          DSM or any other semaphore local
  340. ;                             to a process
  341.  
  342. ;Neither  b  nor  c  may be zero at the end if the semaphore had a 
  343. ;non-zero value.
  344.  
  345. P:     DI
  346.        XCHG
  347.        JZR    M,PZZ             ; Jump if value of semaphore is 0
  348.  
  349.        DCR    M                 ; Decrease value of semaphore by 1
  350.        EI
  351.        RET                      ; Return
  352.  
  353. PZZ:   MOV    A,C               ; a _ ID
  354.        XCHG
  355.        RDLD   C,CPP             ; c <- cpp
  356.        MVI    B,0               ; b _ 0
  357.        RXST   A,B,SEMP          ; (SEMP[cpp]) <- ID
  358.        XCHG
  359.        INX    H                 ; (H&L) _ address of FWP[SEM]
  360.        MOV    E,M               ; e _ t = index of first process R
  361.                                 ; waiting on this semaphore
  362.        MOV    D,B               ; d _ 0
  363.        XRA    A
  364. PXX:   CMP    E
  365.        JNZ    PNXT              ; Jump if other processes waiting
  366.                                 ; on semaphore
  367.  
  368.        MOV    M,C               ; fwp or (NSWP[t]) _ cpp
  369.        RXST   B,B,NSWP          ; (NSWP[cpp]) <- 0
  370.        RXLD   A,B,EXC           ; a <- (EXC[cpp])
  371.        ORI    00000010B
  372.        MOV    M,A               ; BLOCKED bit of current process
  373.                                 ; has been set to 1
  374.        RXLD   C,B,PR            ; c <- q = (PR[cpp])
  375.        RXAD   B,NMR             ; (H&L) <- address of NMR[q]
  376.        DCR    M                 ; (NMR[q]) _ (NMR[q])-1
  377.        JMP    SCHED             ; Note that  b = 0  and  c = q
  378.  
  379. PNXT:  RXLD   E,D,NSWP          ; e _ (NSWP[t]) 
  380.        JMP    PXX
  381.  
  382.  
  383. ;                            V [SEM]
  384.  
  385.  
  386. ;SEM is  the address of the semaphore and is passed to the routine
  387. ;in the B and C registers.
  388. ;NOTE.  The D register is not used.
  389.  
  390.  
  391. V:     DI
  392.        MOV    H,B
  393.        MOV    L,C
  394.        SHLD   VTMP1             ; Store the address of the semaphore
  395.        INX    H                 ; (H&L) _ address of FWP[SEM]
  396. VXX:   JNZR   M,VYY             ; Jump if at least one (other) process
  397.                                 ; is waiting on this semaphore
  398.  
  399.        LHLD   VTMP1             ; (H&L) _ address of VAL[SEM]
  400.        INR    M                 ; Increase value of the semaphore by 1
  401. VOUT:  EI
  402.        RET
  403.  
  404. VYY:   SHLD   VTMP2             ; Store address of the FWP or NSWP[t]
  405.        MOV    C,M               ; c _ t = index of the next PCB whose
  406.                                 ; corresponding process R is waiting
  407.                                 ; on this semaphore
  408.        MVI    B,0               ; b _ 0  (b may be non-zero from START)
  409.        RXLD   A,B,EXC           ; a _ (EXC[t])
  410.        RRC
  411.        JNC    VZZ               ; Jump if Rs STOPPED bit is 0
  412.  
  413.        RXAD   B,NSWP            ; (H&L) _ address of NSWP[t]
  414.        JMP    VXX
  415.  
  416. VZZ:   RLC
  417.        ANI    01000000B
  418.        MOV    M,A               ; EXC[t]  now has BLOCKED (and
  419.                                 ; STOPPED) bit set to 0
  420.        RXST   B,B,SEMP          ; (SEMP[t]) <- 0
  421.        RXLD   A,B,NSWP          ; a _ (NSWP[t])
  422.        LHLD   VTMP2             ; Load address of FWP or previous NSWP
  423.        MOV    M,A               ; R has now been removed from the queue
  424.                                 ; of processes waiting on semaphore
  425.        RXLD   A,B,PR            ; a _ r = (PR[t])
  426.        MOV    E,C               ; e _ t , i.e., store t
  427.        MOV    C,A               ; c <- r
  428.        RXAD   B,NMR             ; (H&L) <- address of NMR[r]
  429.        INR    M                 ; NMR[r] <- NMR[r] + 1
  430.        RDLD   C,CPP             ; c <- cpp
  431.        RXAD   B,PR              ; (H&L) _ address of PR[cpp]
  432.        CMP    M
  433.        JP     VOUT              ; Jump if  r  q = (PR[cpp])
  434.  
  435.        ; Case where  r < q
  436.        MOV    C,A               ; c _ r
  437.        MOV    B,E               ; b _ t
  438.        JMP    SCHED
  439.  
  440. VTMP1: DW     0
  441. VTMP2: DW     0
  442.  
  443.  
  444. ;                      RESULT := SCAN (NAME)
  445.  
  446.  
  447. ;NAME is passed to this routine in the H and L registers and is the
  448. ;address of the new name.  The routine returns an integer RESULT in
  449. ;the A register with the following interpretation:
  450.  
  451. ;                 RESULT              Meaning
  452. ;               ------------------------------------------
  453. ;                    1        name belongs to a process
  454. ;                    2        name belongs to a program
  455. ;                    3             name not found
  456.  
  457. ;At the end, the C register will contain the index t of the last PCB
  458. ;scanned.  If RESULT is 1 or 2, then  b = 0 .
  459.  
  460. SCAN:  SHLD   LBLK              ; Store NAME in LBLK (from parameter
  461.                                 ; block for ISIS load routine)
  462.        LDA    AP                ; A now holds the index t of the first
  463.                                 ; PCB to look at. We assume that t  0.
  464. SC1:   MOV    C,A               ; c _ t
  465.        M6A                      ; d _ 0 , e _ 6*t
  466.        RXAD   D,NAM
  467.        XCHG                     ; (D&E) _ address of NAM[6*t]
  468.        LHLD   LBLK              ; (H&L) _ NAME
  469.        MVI    B,6
  470. NXTCH: LDAX   D                 ; Next character of name in PCB is
  471.                                 ; loaded into A
  472.        CMP    M
  473.        JZ     MTCH              ; Jump if characters match
  474.  
  475.        MVI    B,0               ; Reset B to 0
  476.        RXLD   A,B,NP            ; a _ (NP[t])
  477.        ORA    A
  478.        JNZ    SC1               ; Jump if there are more processes
  479.                                 ; to scan
  480.        MVI    A,3               ; RESULT _ 3
  481.        RET                      ; Case where name was not found
  482.  
  483. MTCH:  DCR    B                 ; b _ b-1
  484.        JZ     SC2               ; Jump if all 6 characters match
  485.  
  486.        INX    D
  487.        INX    H
  488.        JMP    NXTCH
  489.  
  490.        ; Case where a PCB with the right name was found.  Register C
  491.        ; contains the index of that PCB.  Also,  b = 0.
  492. SC2:   RXLD   A,B,EXC           ; a _ (EXC[t])
  493.        RLC
  494.        JC     SC3               ; Jump if this PCB corresponds to a
  495.                                 ; program
  496.        MVI    A,1               ; RESULT _ 1
  497.        RET
  498.  
  499. SC3:   MVI    A,2               ; RESULT _ 2
  500.        RET
  501.  
  502.  
  503. ;                          RESULT := CREA
  504.  
  505.  
  506. ;This subroutine performs the basic function of setting up a PCB for a
  507. ;program which either is already in memory or which has been loaded
  508. ;into memory from the disk.  It is assumed that LBLK holds the address
  509. ;of the name of the process which is to be created.  The routine re-
  510. ;turns an integer RESULT in the D register which specifies any errors
  511. ;that may have occurred:
  512.  
  513. ;            RESULT                   Status
  514. ;         ------------------------------------------------------
  515. ;              0                     no error
  516. ;              1      error while attempting to load file from
  517. ;                      disk - probably no file with that name
  518. ;              3               no free PCBs available
  519.  
  520.  
  521. CREA:  DCR    A
  522.        JZ     CR0               ; Jump if name corresponds to a program
  523.  
  524. CR00:  MVI    C,LOAD            ; Entry point for initialization
  525.                                 ; routine
  526.        LXI    D,LBLK
  527.        CALL   ISIS              ; Load program from disk using ISIS
  528.        LDA    STAT              ; Test error status
  529.        ORA    A
  530.        JZ     CR1               ; Jump if no error in loading
  531.  
  532.        ; Case of error while attempting to load file from disk.  Note
  533.        ; that ISIS specifies the error.
  534.        MVI    C,ERROR
  535.        LXI    D,EBLK
  536.        CALL   ISIS              ; Type out error message on console
  537.        MVI    D,1               ; RESULT _ 1
  538.        RET   
  539.  
  540.        ; Case where name corresponded to a program.  We assume that
  541.        ; b = 0  and  c = t , where t is the index of the PCB for this
  542.        ; program.
  543. CR0:   RXLD   A,B,EXC           ; a _ (EXC[t])
  544.        ANI    01000000B
  545.        ORI    00000001B
  546.        MOV    M,A               ; (EXC[t]) _ 0X000001
  547.        ; NOTE:  Setting EXC here means that in START we have to reset
  548.        ; the STOPPED bit to 0; however, we save fetching EXC in CREAT.
  549.        MOV    A,C               ; a _ t
  550.        M6A                      ; d _ 0 , e _ 6*t
  551.        JMP    INIT
  552.  
  553.        ; Program is now loaded
  554. CR1:   LXI    D,FP              ; (D&E) _ address of FP
  555.        LDAX   D                 ; a _ fp
  556.        ORA    A
  557.        JNZ    CR2               ; Jump if a free PCB is available
  558.  
  559.        ; No more free PCBs are available
  560.        MVI    D,3               ; RESULT _ 3
  561.        RET 
  562.  
  563.  
  564.  
  565.  
  566.  
  567. CR2:   MOV    C,A               ; C now holds the index t of a free PCB
  568.        MVI    B,0               ; b _ 0
  569.        RXLD   A,B,NP            ; a _ (NP[t])
  570.        STAX   D                 ; The FP is updated
  571.  
  572.        ; Now to store the name of the process in the PCB name field.
  573.        MOV    A,C               ; a _ t
  574.        M6A                      ; d _ 0 , e _ 6*t
  575.        RXAD   D,NAM
  576.        XCHG                     ; (D&E) _ address of NAM[6*t]
  577.        LHLD   LBLK              ; (H&L) _ NAME
  578.        TRNAM                    ; Transfer name
  579.  
  580. CR4:   RXAD   B,EXC             ; (H&L) _ address of EXC[t]
  581.        MVI    M,00000001B       ; (EXC[t]) _ 00000001, i.e., STOPPED
  582.                                 ; bit is set
  583.        LHLD   ENTRY
  584.        XCHG
  585.        RXAD   B,STAD
  586.        DAD    B                 ; (H&L) <- address of STAD[2*t]
  587.        STDM
  588.  
  589.        ; Note that  b = 0 , that the execution-state field has been set
  590.        ; to  0X000001 , and that STAD[2t,2t+1] contains the initial
  591.        ; starting address of this process.
  592.        ; Next we initialize the remaining fields of the PCB.
  593. INIT:  RXAD   B,PR
  594.        MVI    M,4               ; (PR[t]) _ 4 , i.e., the priority is
  595.                                 ; set to a default value of 4
  596.        LXI    D,NMPCB           ; Note that we still have  d = 0
  597.        DAD    D
  598.        MVI    M,MBPP            ; (MBC[t]) _ MBPP
  599.  
  600.        ; The WDMK, RDMK, FMP, FQP, FAP, ABP, NSWP, SEMP, LAP, NAP,
  601.        ; and LP for this process are now set to  0 .
  602.        MVI    A,11
  603. CR5:   DAD    D     
  604.        MVI    M,0  
  605.        DCR    A
  606.        JNZ    CR5 
  607.  
  608.        ; Now to link the PCB at the head of the all-PCB-queue and to
  609.        ; update the AP.
  610.        DAD    D                 ; (H&L) _ address of NP[t]
  611.        LDA    AP
  612.        MOV    M,A               ; (NP[t]) _ ap
  613.        ORA    A
  614.        JZ     CR6               ; Jump if  ap = 0. This case occurs
  615.                                 ; only during initialization
  616.        MOV    E,A               ; e _ ap
  617.        RXST   C,D,LP            ; (LP[ap]) <- t
  618. CR6:   MOV    A,C               ; a _ t
  619.        STA    AP                ; ap _ t
  620.  
  621.  
  622.  
  623.  
  624.  
  625.        ; Next to set the DSM and STKP
  626.        RLC                      ; a _ 2*t
  627.        MOV    E,A               ; e _ 2*t
  628.        RLC                      ; a _ 4*t
  629.        ADD    C                 ; a _ 5*t
  630.        MOV    L,A               ; l _ 5*t
  631.        MOV    H,B               ; h _ 0
  632.        DAD    H
  633.        XCHG                     ; (D&E) _ 10*t
  634.        MOV    C,L               ; c _ 2*t
  635.        RXST   B,B,DSM           ; The DSM field is set to 0
  636.        INX    H                 ;    "         "        "
  637.        MOV    M,B               ;    "         "        "
  638.        RXAD   D,STACK           ; (H&L) _ address of STACK[10*t]
  639.        XCHG
  640.        RXAD   B,STKP            ; (H&L) _ address of STKP[2*t]
  641.        STDM                     ; (STKP[2*t]) _ address of STACK[10*t]
  642.        XCHG                     ; (H&L) _ address of STACK[10*t]
  643.  
  644.        ; Now to set the top 8 bytes of the stack to 0 so that
  645.        ; when a process is scheduled for the first time its
  646.        ; registers will all be initialized to 0
  647.        MVI    A,8
  648. CR7:   MVI    M,0
  649.        INX    H
  650.        DCR    A
  651.        JNZ    CR7
  652.  
  653.        XCHG                     ; (D&E) _ address of STACK[10*t+8]
  654.        RXLD   A,B,STAD
  655.        STAX   D
  656.        INX    D
  657.        INX    H
  658.        MOV    A,M
  659.        STAX   D                 ; The starting address for the new pro-
  660.                                 ; gram is now stored at the bottom of
  661.                                 ; the stack.  This address is loaded
  662.                                 ; into the PLC when the process is
  663.                                 ; started.
  664.        MOV    D,B               ; RESULT _ 0
  665.        RET                      ; Note that  c = 2*t  and  b = 0 .
  666.  
  667.  
  668. ;                      RESULT := CREAT (NAME)
  669.  
  670.  
  671. ;NAME is passed to this routine in the B and C registers and is the
  672. ;address of the name of the process to be created.  The routine re-
  673. ;turns an integer RESULT in the A register with the following in-
  674. ;terpretation:
  675.  
  676. ;      RESULT                     event
  677. ;   ------------------------------------------------------------
  678. ;        0         routine completed its task successfully
  679. ;        1         error while attempting to load file from
  680. ;                   disk - probably no file with that name
  681. ;        2           name already used by another process
  682. ;                                or program
  683. ;        3                no more PCBs available
  684.  
  685.  
  686. CREAT: PUSH   B                 ; Store NAME on the process stack
  687.                                 ; Note that an interrupt could occur
  688.                                 ; here, so that one cannot simply
  689.                                 ; store NAME in memory
  690.        LXI    D,AS
  691.        MVI    C,2
  692.        CALL   P                 ; P[AS]
  693.        POP    H                 ; (H&L) _ NAME
  694.        CALL   SCAN
  695.        SUI    3
  696.        JM     CR10              ; Jump if name not found among current
  697.                                 ; process or program names
  698.  
  699.        MVI    D,2               ; RESULT _ 2
  700.  
  701.        ; NOTE: EXIT is a global address which is used by almost all
  702.        ; the routines.
  703. EXIT:  LXI    B,AS
  704.        CALL   V                 ; V[AS]
  705.        MOV    A,D               ; Set RESULT
  706.        RET
  707.  
  708.  
  709. CR10:  CALL   CREA
  710.        JMP    EXIT
  711.  
  712.  
  713.        ; The parameter block for the ISIS load routine.  It is used by
  714.        ; the routines SCAN, CREA, CREAT, START
  715. LBLK:  DW     0                 ; Pointer to filename
  716. BIAS:  DW     0                 ; Bias address
  717. RETSW: DW     0                 ; Return switch
  718.        DW     ENTRY             ; Starting address for the program
  719.                                 ; which was loaded
  720.        DW     STAT              ; Status (returned)
  721. ENTRY: DS     2
  722.  
  723. EBLK:                           ; The parameter block for the ISIS
  724.                                 ; error routine (used by CREA).
  725. STAT:  DS     2
  726.        DW     STAT
  727.  
  728.  
  729.  
  730. ;                RESULT := START (NAME,PRIORITY)
  731.  
  732.  
  733. ;NAME is passed to this routine in the B and C registers and is the
  734. ;address of the name of a process which is to be started.  The E
  735. ;register holds the integer PRIORITY which specifies the priority
  736. ;that the new process is to have.  A value of 0FFH for PRIORITY is
  737. ;interpreted to mean that the new process is to be started with
  738. ;whatever priority it already had.  RESULT is an integer which is
  739. ;returned by the routine in the A register.  It has the following
  740. ;interpretation:
  741.  
  742. ;      RESULT                      event
  743. ;   ------------------------------------------------------------
  744. ;        0          routine completed its task successfully
  745. ;        1          error while attempting to load file from
  746. ;                    disk - probably no file with that name
  747. ;        2             specified process was not stopped
  748.  
  749.  
  750. START: PUSH   D                 ; Store PRIORITY on the stack
  751.        PUSH   B                 ; Store NAME on the stack
  752.        LXI    D,AS
  753.        MVI    C,2
  754.        CALL   P                 ; P[AS]
  755.        POP    H                 ; (H&L) _ NAME
  756.        CALL   SCAN
  757.        DCR    A
  758.        JNZ    NTFND             ; Jump if name not found among current
  759.                                 ; process names
  760.  
  761.        ; Note that C now contains the index t of the PCB with the name
  762.        ; we were looking for and that  b = 0 .
  763.  
  764.        ; Now to check the STOPPED bit
  765.        RXLD   A,B,EXC           ; a <- (EXC[t])
  766.        RRC
  767.        JC     ST1               ; Jump if process was stopped
  768.  
  769.        MVI    D,2               ; RESULT <- 2
  770. ST0:   POP    H                 ; So as not to leave PRIORITY on 
  771.                                 ; stack
  772.        JMP    EXIT
  773.  
  774.        ; Next to store the status of the BLOCKED bit
  775. ST1:   RLC                      ; a <- (EXC[t])
  776.        ANI    01000010B
  777.        MOV    M,A               ; STOPPED bit in EXC[t] has now
  778.                                 ; been set to 0
  779.        ANI    00000010B
  780. ST2:   STA    ST4+1             ; Store the BLOCKED bit for check-
  781.                                 ; ing later
  782.  
  783.        ; Now to store PRIORITY
  784.        POP    D                 ; e <- PRIORITY
  785.        MOV    D,B               ; d <- 0
  786.        MVI    A,0FFH            ; a <- 0FFH
  787.        CMP    E
  788.        RXAD   B,PR              ; (H&L) <- address of PR[t]
  789.        JNZ    ST7               ; Jump if priority is to be changed
  790.  
  791.  
  792.  
  793.  
  794.        MOV    E,M               ; e <- old priority
  795.  
  796.        ; Next to compare the priority q of the new process
  797.        ; with  r = (PR[cpp])
  798. ST3:   MOV    A,E               ; a <- q
  799.        RDLD   E,CPP             ; e <- cpp
  800.        RXAD   D,PR              ; (H&L) <- address of PR[cpp]
  801.        CMP    M
  802.        PUSH   PSW               ; Save comparison of q and r
  803.  
  804.        ; Next to check the BLOCKED bit
  805.        MOV    E,A               ; e <- q
  806. ST4:   MVI    A,0               ; NOTE:  The BLOCKED bit has been
  807.                                 ; stored here by an earlier
  808.                                 ; instruction
  809.        ORA    A                 ; Test the BLOCKED bit
  810.        JNZ    ST5               ; Jump if the new process is blocked
  811.  
  812.        RXAD   D,NMR
  813.        INR    M                 ; (NMR[q]) <- (NMR[q])+1
  814.  
  815.        ; Now to link the new PCB into the appropriate active queue
  816.        ; at the correct place.
  817. ST5:   RXAD   D,PRP             ; (H&L) <- address of PRP[q]
  818.        JZR    M,ST9             ; Jump if there are no processes
  819.                                 ; of priority q
  820.  
  821.        POP    PSW               ; Restore comparison of q and r.
  822.                                 ; Note that  a <- q .
  823.        PUSH   PSW               ; Resave comparison for later
  824.        JNZ    ST8               ; Jump if r does not equal q .
  825.                                 ; Note that  e = q .
  826.  
  827.        ;Case where  q = r
  828.        RDLD   E,CPP             ; e <- cpp
  829.        CALL   LINK              ; Link the new PCB in front of the
  830.                                 ; PCB for the current process
  831.  
  832.        ; Now to check if  cpp = (PRP[q])
  833.        MOV    E,A               ; e <- q
  834.        LDA    CPP
  835.        RXAD   D,PRP             ; (H&L) <- address of PRP[q]
  836.        CMP    M
  837.        JNZ    ST6               ; Jump if  cpp  and  (PRP[q])  are
  838.                                 ; unequal
  839.  
  840.        MOV    M,C               ; (PRP[q]) <- t
  841. ST6:   POP    PSW               ; Restore the sign bit
  842.        JP     EXIT              ; Jump if  q >= r
  843.  
  844.  
  845.  
  846.        ; Case where the new process has higher priority than the
  847.        ; current one, so that it should be scheduled to run
  848.        MOV    B,C               ; b <- t
  849.        MOV    C,E               ; c <- q
  850.        PUSH   B                 ; Store q and t
  851.        LXI    B,AS
  852.        CALL   V                 ; V[AS]
  853.        POP    B
  854.        DI
  855.        JMP    SCHED
  856.  
  857. ST7:   MOV    M,E               ; (PR[t]) _ PRIORITY
  858.        JMP    ST3
  859.  
  860.        ; Case where r does not equal q
  861. ST8:   MOV    E,M               ; e <- (PRP[q])
  862.        CALL   LINK              ; Link the new PCB in front of the
  863.                                 ; PCB pointed to by the PRP[q]
  864.                                 ; pointer
  865.        JMP    ST6
  866.  
  867. ST9:   MOV    M,C               ; (PRP[q]) <- t
  868.        RXST   C,B,NAP           ; (NAP[t]) <- t
  869.        RXST   C,B,LAP           ; (LAP[t]) <- t
  870.        JMP    ST6
  871.  
  872.  
  873. NTFND: CALL   CREA
  874.        JNZR   D,ST0             ; Jump if error in program loading
  875.  
  876.        MOV    A,C               ; a _ 2*t , where t is the index of
  877.                                 ; the newly created PCB
  878.        RRC
  879.        MOV    C,A               ; c _ t
  880.        RXLD   A,B,EXC           ; a <- (EXC[t])
  881.        ANI    01000000B
  882.        MOV    M,A               ; (EXC[t]) <- 0X000000
  883.        XRA    A                 ; a <- 0
  884.        JMP    ST2
  885.  
  886.  
  887.  
  888.  
  889.  
  890. ;                         LINK
  891.  
  892.  
  893. ;This subroutine is used by START to link the PCB with index c in
  894. ;front of the PCB with index e into the doubly-linked ready list.
  895.  
  896.  
  897. LINK:  RXST   E,B,NAP
  898.        RXLD   E,D,LAP
  899.        MOV    M,C
  900.        RXST   C,D,NAP
  901.        RXST   E,B,LAP
  902.        RET
  903.  
  904.  
  905.  
  906. ;                          STOP0
  907.  
  908.  
  909. ;The main task of this routine is to unlink a process PCB from the
  910. ;ready queue and to adjust the relevant priority pointer.  It is
  911. ;called by both the STOP and REMOV routines.  We assume that  b=0 ,
  912. ;c=t , and  a=( (EXC[t]) shifted right 1 ) , where t is the index
  913. ;of the PCB whose corresponding process is to be stopped.  Also,
  914. ;registers H and L are assumed to hold the address of EXC[t].
  915. ;We still have  b = 0  and  c = t  at the end.
  916.  
  917.  
  918. STOP0: RLC
  919.        ORI    00000001B
  920.        MOV    M,A               ; Set STOPPED bit to 1
  921.        ANI    00000010B
  922.        RXLD   E,B,PR            ; e _ q = Qs priority
  923.        MOV    D,B               ; d _ 0
  924.        JNZ    STP01             ; Jump if Q is blocked
  925.  
  926.        RXAD   D,NMR             ; (H&L) _ address of NMR[q]
  927.        DCR    M                 ; (NMR[q] _ (NMR[q])-1
  928.  
  929.        ; Now to remove the process from its circular list of active
  930.        ; processes
  931. STP01: RXLD   A,B,NAP           ; a _ (NAP[t]) = y
  932.        RXAD   D,PRP             ; (H&L) _ address of PRP[q]
  933.        CMP    C
  934.        JZ     STP03             ; Jump if Q was the only active
  935.                                 ; process of priority q , i.e., y = t
  936.  
  937.        MOV    E,A               ; e <- y
  938.        MOV    A,C               ; a <- t
  939.        CMP    M
  940.        JNZ    STP02             ; Jump if  t  is unequal to   (PRP[q])
  941.  
  942.        MOV    M,E               ; (PRP[q]) _ y
  943. STP02: UNLNK  LAP,NAP           ; Unlink Qs PCB from active list
  944.        RET
  945.  
  946. STP03: MOV    M,B               ; (PRP[q]) _ 0
  947.                                 ; List of active priority-q processes
  948.                                 ; is now empty.
  949.        RET
  950.  
  951.  
  952.  
  953. ;                    RESULT := STOP (NAME)
  954.  
  955.  
  956. ;NAME is passed to this routine in the B and C registers and is the
  957. ;address of the name of a process which is to be stopped.  If  b = 0 ,
  958. ;then the current process is trying to stop itself.  RESULT is an
  959. ;integer which is returned by the routine in the A register.  It
  960. ;has the following interpretation:
  961.  
  962. ;      RESULT                      event
  963. ;   -------------------------------------------------------------
  964. ;        0          routine completed its task successfully
  965. ;        1         name not found among current process names
  966.  
  967.  
  968. STOP:  PUSH   B                 ; Store NAME on the stack
  969.        LXI    D,AS
  970.        MVI    C,2
  971.        CALL   P                 ; P[AS]
  972.        POP    H                 ; (H&L) _ NAME
  973.        JZR    H,STP2            ; Jump if current running process is
  974.                                 ; trying to stop itself
  975.  
  976.        CALL   SCAN
  977.        DCR    A
  978.        JZ     STP1              ; Jump if name found among current
  979.                                 ; processes
  980.  
  981.        MVI    D,1               ; RESULT _ 1
  982.        JMP    EXIT              ; See CREAT
  983.  
  984.  
  985.        ; We now have  c = 0 and  b = t , where t is the index of the
  986.        ; PCB with the name of the process Q that we were looking for.
  987. STP1:  RXLD   A,B,EXC           ; a _ (EXC[t])
  988.        RRC
  989.        JC     EXIT              ; Jump if process was STOPPED
  990.  
  991.        CALL   STOP0
  992.        JMP    EXIT              ; Note that  d = 0
  993.  
  994.        ; Case where process is trying to stop itself.
  995. STP2:  RDLD   C,CPP             ; c <- cpp
  996.        MVI    B,0
  997.        RXLD   A,B,EXC           ; a _ (EXC[cpp])
  998.        CALL   STOP0+1
  999. NEWP:                           ; REMOV uses this entry point
  1000.        RXLD   D,B,PR            ; d _ q = (PR[cpp])
  1001.        LXI    B,AS
  1002.        CALL   V                 ; V[AS]
  1003.        MOV    C,D               ; c _ q
  1004.        MVI    B,0               ; b <- 0
  1005.        DI
  1006.        JMP    SCHED
  1007.  
  1008.  
  1009. ;                            RMV
  1010.  
  1011. ;This subroutine is called by REMOV to free the resources of the
  1012. ;process that is about to be removed.
  1013.  
  1014.  
  1015. RMV:   ANI    01000000B
  1016.        JNZ    RV11              ; Jump if Q corresponds to a permanent-
  1017.                                 ; ly resident program
  1018.  
  1019.        RXLD   E,B,NP            ; e _ (NP[t])=y
  1020.        LDA    FP
  1021.        MOV    M,A               ; (NP[t]) _ fp
  1022.        MOV    A,C     
  1023.        STA    FP                ; fp _ t
  1024.        ; Qs PCB is now back on stack of free PCBs
  1025.  
  1026.        LDA    AP
  1027.        CMP    C
  1028.        JZ     RV12              ; Jump if  ap = t , i.e., Q is the
  1029.                                 ; first process in the queue
  1030.  
  1031.        MOV    A,C               ; a <- t
  1032.        UNLNK  LP,NP             ; Unlink Qs PCB from the list of
  1033.                                 ; all PCBs
  1034.  
  1035.        ; Now to return all message buffers
  1036. RV1:   RXAD   B,FMP             ; (H&L) _ address of FMP[t]
  1037.        JZR    M,RV3             ; Jump if message queue is empty
  1038.  
  1039.        PUSH   B                 ; Store t on stack
  1040. RV2:   MOV    E,M               ; e _ (FMP[t])=z=index of message
  1041.                                 ; buffer
  1042.        RXLD   C,D,MBSP          ; c _ (MBSP[z])=u
  1043.        RXAD   B,MBC             ; (H&L) _ address of MBC[u]
  1044.        INR    M                 ; (MBC[u]) _ (MBC[u])+1
  1045.        RXAD   D,NMBP            ; (H&L) _ address of NMBP[z]
  1046.        CMP    M                 ; Note that  a = 0
  1047.        JNZ    RV2               ; Jump if more messages in queue
  1048.  
  1049.        ; Now to link all the buffers in the message queue back
  1050.        ; on the free stack
  1051.        LDA    FMBP              ; a _ fmbp
  1052.        MOV    M,A               ; (NMBP[z]) _ fmbp
  1053.        POP    B
  1054.        RXLD   A,B,FMP           ; a _ (FMP[t])
  1055.        STA    FMBP              ; fmbp _ z
  1056.  
  1057.        ; Now to return all returned-answer buffers
  1058. RV3:   RXAD   B,FAP             ; (H&L) _ address of FAP[t]
  1059.        JZR    M,RV5             ; Jump if answer queue is empty
  1060.  
  1061.        PUSH   B
  1062.        MOV    E,M               ; e _ (FAP[t]) = z , i.e., save
  1063.                                 ; index of first buffer
  1064. RV4:   MOV    C,M               ; c _ z
  1065.        RXAD   B,NMBP            ; (H&L) _ address of NMBP[z]
  1066.        CMP    M                 ; Note that  a = 0
  1067.        JNZ    RV4               ; Jump if more buffers
  1068.  
  1069.        LDA    FMBP
  1070.        MOV    M,A               ; (NMBP[z]) <- fmbp
  1071.  
  1072.        MOV    A,E               ; a _ z
  1073.        STA    FMBP
  1074.        POP    B
  1075.  
  1076.        ; Now to return all question buffers
  1077. RV5:   LXI    H,FQP
  1078.        CALL   RMVQA
  1079.  
  1080.        ; Now to return all answer buffers
  1081.        LXI    H,ABP
  1082.        CALL   RMVQA
  1083.  
  1084.        ; All buffers from message system have now been returned
  1085.        ; Next, to clear those sender fields in the message buffers
  1086.        ; which refer to the process which is being removed
  1087.        MOV    A,C               ; a <- t
  1088.        LXI    D,NMMB
  1089.        INR    D
  1090.        LXI    H,MBSP
  1091. RV6:   INX    H
  1092.        CMP    M
  1093.        JNZ    RV7
  1094.  
  1095.        MVI    M,0
  1096. RV7:   DCR    E
  1097.        JNZ    RV6
  1098.  
  1099.        DCR    D
  1100.        JNZ    RV6
  1101.  
  1102.        ; Finally, to remove Qs PCB from any semaphore queue
  1103.        RXAD   B,SEMP             ; (H&L) <- address of SEM[t]
  1104.        JNZR   M,RV8
  1105.        RET
  1106.  
  1107.        ; Case where process is waiting on AS semaphore
  1108. RV8:   RXLD   C,B,NSWP           ; c <- (NSWP[t])
  1109.        LXI    H,AS
  1110.        INX    H                  ; (H&L) <- address of FWP[AS]
  1111.        MOV    E,M                ; e <- x = index of first process
  1112.                                  ; waiting on AS
  1113. RV9:   CMP    E
  1114.        JZ     RV10
  1115.  
  1116.        RXLD   E,D,NSWP           ; e <- (NSWP[x])
  1117.        JMP    RV9
  1118.  
  1119. RV10:  MOV    M,C
  1120.        RET                       ; Note that  d = 0
  1121.  
  1122. RV11:  ORI    10000000B
  1123.        MOV    M,A                ; Reset EXC field
  1124.        MOV    D,B                ; d <- 0
  1125.        JMP    RV1
  1126.  
  1127. RV12:  MOV    A,E                ; a <- y
  1128.        ORA    A                  ; Test y
  1129.        JZ     HALT               ; Jump if we were asked to
  1130.                                  ; remove the only process in
  1131.                                  ; existence
  1132.  
  1133.        STA    AP                 ; ap <- y
  1134.        JMP    RV1
  1135.  
  1136.  
  1137.  
  1138.  
  1139.  
  1140. ;                        RMVQA
  1141.  
  1142.  
  1143. RMVQA: DAD    B
  1144.        JZR    M,RV15
  1145.  
  1146.        PUSH   B
  1147.        MOV    C,M
  1148. RV13:  RXLD   E,B,NMBP
  1149.        MOV    M,B               ; Set memory to 0
  1150.        PUSH   D
  1151.        RXAD   B,ASTAT           ; (H&L) _ address of ASTAT[z]
  1152.        MVI    M,1               ; (ASTAT[z]) _ 1
  1153.        RXLD   E,B,MBSP
  1154.        MOV    B,C
  1155.        MVI    C,MASKA           ; c _ 00000100
  1156.        LXI    H,FAP
  1157.        CALL   SSUB
  1158.        POP    B
  1159.        JNZR   C,RV13
  1160.  
  1161. RV14:  POP    B
  1162. RV15:  RET
  1163.  
  1164.  
  1165.  
  1166. ;                   RESULT := REMOV (NAME)
  1167.  
  1168.  
  1169. ;NAME is passed to this routine in the B and C registers and is the
  1170. ;address of the name of a process which is to be removed. If  b = 0,
  1171. ;then the process is trying to remove itself.  RESULT is an integer
  1172. ;which is returned by the routine in the A register with the fol-
  1173. ;lowing interpretation:
  1174.  
  1175. ;       RESULT                     event
  1176. ;    -----------------------------------------------------------
  1177. ;         0          routine completed its task successfully
  1178. ;         1           name not found among current processes
  1179. ;                               and programs
  1180.  
  1181.  
  1182.  
  1183. REMOV: PUSH   B                 ; Store NAME on the stack
  1184.        LXI    D,AS
  1185.        MVI    C,2
  1186.        CALL   P                 ; P[AS]
  1187.        POP    H                 ; (H&L) _ NAME
  1188.        JZR    H,REM3            ; Jump if this process is trying to
  1189.                                 ; remove itself
  1190.  
  1191.        CALL   SCAN
  1192.        SUI    3
  1193.        JM     REM1              ; Jump if name found among current
  1194.                                 ; processes or programs
  1195.  
  1196.        MVI    D,1               ; RESULT _ 1
  1197.        JMP    EXIT              ; See CREAT
  1198.  
  1199.        ; We now have  b = 0 and  c = t , where t is the index of the
  1200.        ; PCB with the name of the process Q that we were looking for.
  1201. REM1:  RXLD   A,B,EXC           ; a _ (EXC[t])
  1202.        PUSH   H                 ; Save address of EXC[t]
  1203.        RRC
  1204.        CNC    STOP0             ; Stop Q if it is not already stopped
  1205.  
  1206.        ; We still have  b = 0  and  c = t
  1207. REM2:  POP    H                 ; (H&L) <- address of EXC[t]
  1208.        MOV    A,M               ; a <- (EXC[t])
  1209.        CALL   RMV
  1210.        JMP    EXIT              ; Note that  d = 0
  1211.  
  1212.        ; Case where process is trying to remove itself
  1213. REM3:  RDLD   C,CPP             ; c <- cpp
  1214.        MVI    B,0
  1215.        RXLD   A,B,EXC           ; a <- (EXC[cpp])
  1216.        PUSH   H                 ; Save address of EXC[cpp]
  1217.        CALL   STOP0+1
  1218.        POP    H                 ; (H&L) <- address of EXC[cpp]
  1219.        MOV    A,M               ; a <- (EXC[cpp])
  1220.        PUSH   B                  
  1221.        CALL   RMV   
  1222.        POP    B
  1223.        JMP    NEWP              ; See STOP
  1224.  
  1225.  
  1226.  
  1227. ;                  THE MESSAGE SYSTEM
  1228.                    ------------------
  1229.  
  1230.  
  1231. ;The next four subroutines (SENDM, SENDQ, SENDA, and WAIT) form the
  1232. ;basis for the message system between processes.  SENDM allows one
  1233. ;process to send a message to another.  SENDQ also is used to send
  1234. ;a message, except that this time an answer is expected back.  This
  1235. ;answer is returned by the other process via SENDA.  WAIT allows a
  1236. ;process to wait for either a message, question, answer, or
  1237. ;interrupt.
  1238.  
  1239. ;NOTE:  MB will be an abbreviation for "message buffer".
  1240.  
  1241.  
  1242.  
  1243.  
  1244. ;            RESULT := SENDM (MESSAGE,NAME)
  1245.  
  1246.  
  1247. ;For definiteness assume that process Q wants to send a message
  1248. ;to process R.  The 2-byte word MESSAGE is passed in the B&C
  1249. ;register pair.  NAME is passed in the D&E register pair and is
  1250. ;the address of a 6-byte block in memory containing Rs name.  The
  1251. ;routine returns a 1-byte integer RESULT in the A register with
  1252. ;the following interpretation:
  1253.  
  1254. ;    RESULT                       event
  1255. ;  ------------------------------------------------------------
  1256. ;      0         The routine completed its task successfully
  1257. ;      1             no more message buffers available
  1258. ;      2       receivers name not found among current processes
  1259.  
  1260.  
  1261. SENDM: CALL   SMQ
  1262.        MOV    E,C           ; e <- t = index of Rs PCB
  1263.        LXI    H,FMP
  1264.        MVI    C,MASKM
  1265.        CALL   SSUB
  1266.        JMP    EXIT
  1267.  
  1268.  
  1269.  
  1270.  
  1271. ;            RESULT := SENDQ (ADDRESS,NAME)
  1272.  
  1273.  
  1274. ;The only difference between this routine and SENDM is that an
  1275. ;answer is expected back.  The parameters are also basically the
  1276. ;same.  The only change is caused by the fact that one can only
  1277. ;pass two parameters in PL/M.  ADDRESS is the address of a 3-byte
  1278. ;block in memory with the following two fields:
  1279.  
  1280. ;     BID:      1 byte
  1281. ;     QUESTION: 2 bytes which are the question (similar to MESSAGE
  1282. ;               in SENDM)
  1283.  
  1284. ;The integer BID is returned by the routine and is the index of
  1285. ;the MB that was used to send the question.  It has importance to
  1286. ;this particular process only in connection with the WAIT routine
  1287. ;when it awaits the answer.
  1288. ;RESULT is an integer returned in the A register with the same
  1289. ;interpretation as in SENDM.
  1290.  
  1291.  
  1292. SENDQ: PUSH   B
  1293.        INX    B
  1294.        MOV    H,B
  1295.        MOV    L,C           ; (H&L) <- ADDRESS+1
  1296.        MOV    C,M
  1297.        INX    H
  1298.        MOV    B,M           ; (B&C) <- QUESTION
  1299.        CALL   SMQ
  1300.        POP    H             ; (H&L) <- ADDRESS
  1301.        MOV    M,B           ; Store BID in appropriate location
  1302.        MOV    E,C           ; e <- t = index of Rs PCB
  1303.        LXI    H,FQP
  1304.        MVI    C,MASKQ
  1305.        CALL   SSUB
  1306.        JMP    EXIT
  1307.  
  1308.  
  1309.  
  1310.  
  1311. ;            RESULT := SENDA (ANSWER,BID)
  1312.  
  1313.  
  1314. ;ANSWER is a 2-byte word passed in the B&C register pair and BID
  1315. ;is a 1-byte integer passed in the E register.  BID is the index
  1316. ;of the MB that is to be used to return the answer to the process
  1317. ;that asked the original question.  The routine returns a 1-byte
  1318. ;integer RESULT in the A register with the following interpreta-
  1319. ;tion:
  1320.  
  1321. ;    RESULT                       event
  1322. ;  ------------------------------------------------------------
  1323. ;      0          routine completed its task successfully
  1324. ;      1        the correct buffer for returning the answer
  1325. ;                           could not be found
  1326. ;      2         process to whom answer was to be sent was
  1327. ;                                 removed
  1328.  
  1329.  
  1330. SENDA: CALL   SA
  1331.        MOV    E,B           ; e <- t = index of PCB which belongs
  1332.                             ;          to process to which answer
  1333.                             ;          is being sent
  1334.        MOV    B,C           ; b <- BID
  1335.        LXI    H,FAP
  1336.        MVI    C,MASKA
  1337.        CALL   SSUB
  1338.        JMP    EXIT
  1339.  
  1340.  
  1341.  
  1342.  
  1343. ;                        SMQ
  1344.  
  1345. ;This subroutine is used by SENDM and SENDQ.  SENDA also uses
  1346. ;part of it.
  1347.  
  1348.  
  1349. SMQ:   PUSH   B
  1350.        PUSH   D
  1351.        MVI    C,2
  1352.        LXI    D,AS 
  1353.        CALL   P             ; P(AS)
  1354.        POP    H             ; (H&L) <- NAME
  1355.        CALL   SCAN
  1356.        CPI    1
  1357.        JNZ    SXX           ; Jump if Rs name not found among
  1358.                             ; processes
  1359.  
  1360.        ;  b = 0  and  c = t , where  t  is the index of Rs PCB
  1361.        RDLD   E,CPP         ; e <- cpp
  1362.        MVI    D,0
  1363.        RXAD   D,MBC         ; (H&L) <- address of MBC[cpp]
  1364.        XRA    A             ; a <- 0
  1365.        CMP    M
  1366.        JZ     SYY           ; Jump if  (MBC[cpp]) = 0
  1367.  
  1368.        DCR    M             ;  (MBC[cpp]) <- (MBC[cpp]) - 1
  1369.        RDLD   E,FMBP        ; e <- BID = fmbp
  1370.        RXLD   A,D,NMBP
  1371.        STA    FMBP          ; fmbp <- (NMBP[fmbp])
  1372.        MOV    B,E           ; Store new MB index BID in B
  1373.        RXAD   D,MBSP        ; (H&L) <- address of MBSP[BID]
  1374.        JMP    SMQ1
  1375.  
  1376.        ; Entry point from SA subroutine
  1377. SAE:   MOV    E,C           ; e <- BID
  1378.        MVI    D,0
  1379.        MOV    B,A           ; b <- t
  1380. SMQ1:  LDA    CPP
  1381.        MOV    M,A           ; (MBSP[BID]) <- cpp
  1382.        RXST   D,D,NMBP      ; (NMBP[BID]) <- 0
  1383.        RXST   D,D,ASTAT     ; (ASTAT[BID]) <- 0
  1384.        RXAD   D,MESS
  1385.        DAD    D             ; (H&L) <- address of MESS[2*BID]
  1386.        POP    D             ; (D&E) <- MESSAGE or ANSWER
  1387.        STDM                 ; Store MESSAGE or ANSWER in MESS
  1388.                             ; field of MB
  1389.        ; In case of SENDM or SENDQ we now have  c = t  and 
  1390.        ; b = BID
  1391.        RET
  1392.  
  1393.  
  1394. ;                           SA
  1395.  
  1396. ;This subroutine is used by SENDA.
  1397.  
  1398.  
  1399. SA:    PUSH   B
  1400.        PUSH   D
  1401.        LXI    D,AS
  1402.        MVI    C,2
  1403.        CALL   P             ; P(AS)
  1404.        POP    B             ; c <- BID
  1405.        MVI    B,0
  1406.  
  1407.        ; Begin searching answer-buffer queue for MB with index BID
  1408.        RDLD   E,CPP         ; e <- cpp
  1409.        MOV    D,B           ; d <- 0
  1410.        RXAD   D,ABP         ; (H&L) <- address of ABP[cpp]
  1411.        JMP    SA2
  1412.  
  1413. SA1:   LXI    H,NMBP
  1414.        MOV    E,A
  1415.        DAD    D
  1416. SA2:   MOV    A,M
  1417.        CMP    D
  1418.        JZ     SYY           ; Jump if no buffer found with index
  1419.                             ; equal to BID
  1420.  
  1421.        CMP    C
  1422.        JNZ    SA1           ; Jump if index of this buffer does not
  1423.                             ; equal BID
  1424.  
  1425.        XCHG
  1426.        RXLD   A,B,NMBP
  1427.        STAX   D
  1428.        ; End of search.  Also, buffer has been unlinked from queue.
  1429.  
  1430.        ; Check whether sender of question has been removed in the
  1431.        ; meantime
  1432.        RXLD   A,B,MBSP      ; (H&L) <- address of MBSP[BID]
  1433.                             ; a <- t = (MBSP[BID])
  1434.        ORA    A             ; Test if  a = 0
  1435.        JNZ    SAE           ; Jump if sender not removed
  1436.  
  1437.        ; Case where sender was removed
  1438.        LDA    FMBP
  1439.        RXST   A,B,NMBP      ; (NMBP[BID]) <- fmbp
  1440.        MOV    A,C
  1441.        STA    FMBP          ; fmbp <- BID
  1442.        JMP    SXX
  1443.  
  1444.  
  1445.  
  1446.        ; Exit points
  1447. SXX:   MVI    D,1
  1448. SYY:   POP    H             ; Pop NAME or BID
  1449.        POP    H             ; Pop return address from SENDX
  1450.        INR    D             ; Set RESULT
  1451.        JMP    EXIT
  1452.  
  1453.  
  1454. ;                         SSUB
  1455.  
  1456. ;This subroutine is used by SENDM, SENDQ, SENDA, and RMV.
  1457. ;For this subroutine we expect MASKX in C, BID in B, index t of
  1458. ;Rs PCB in E, and address of FXP in H&L.
  1459.  
  1460.  
  1461. SSUB:  MVI    D,0
  1462.        DAD    D             ; (H&L) <- address of (FMP or FQP
  1463.                             ; or FAP)[t]
  1464.        JZR    M,SSUB2
  1465.  
  1466.        PUSH   D             ; Save t
  1467. SSUB1: MOV    E,M           ; e <- s
  1468.        RXAD   D,NMBP        ; (H&L) <- address of NMBP[s]
  1469.        CMP    M             ; Note that  a = 0
  1470.        JNZ    SSUB1         ; Jump if we still have not reached
  1471.                             ; the last MB in the queue
  1472.  
  1473.        POP    D             ; e <- t
  1474. SSUB2: MOV    M,B
  1475.  
  1476.        ; Entry point from send-interrupt routine
  1477. SENDI: RXAD   D,RDMK        ; (H&L) <- address of RDMK[t]
  1478.        MOV    A,C           ; a <- MASKX
  1479.        DI
  1480.        ORA    M
  1481.        MOV    M,A           ; (RDMK[t]) <- (RDMK[t]) v SMASK
  1482.        RXAD   D,WDMK        ; (H&L) <- address of WDMK[t]
  1483.        MOV    A,C
  1484.        ANA    M
  1485.        JZ     SSUB3         ; Jump if (WDMK[receiver] AND SMASK)=0
  1486.  
  1487.        MVI    M,0           ; (WDMK[receiver]) <- 0
  1488.        EI
  1489.        RXAD   D,DSM
  1490.        DAD    D             ; (H&L) <- address of DSM[2*t]
  1491.        MOV    C,L
  1492.        MOV    B,H
  1493.        CALL   V             ; V(DSM[receiver])
  1494.        RET                  ; Note that  d = 0
  1495.  
  1496. SSUB3: EI
  1497.        RET                  ; Note that  d = 0
  1498.  
  1499.  
  1500. ;             RESULT := WAIT (WTBLK,MASK)
  1501.  
  1502.  
  1503. ;This routine allows a process to wait for a message or interrupt.
  1504. ; WTBLK (passed in the B&C register pair) is the address of a 10 
  1505. ; byte block in memory with the following fields:
  1506.  
  1507. ;      EVENT:    1 byte.  This binary word specifies what type of
  1508. ;                data was received and has the same interpretation
  1509. ;                as MASK.
  1510. ;      DATA:     2 bytes that are either a message, question, or
  1511. ;                answer.
  1512. ;      BUFID:    1 byte. Since it is possible to send more than one
  1513. ;                question to another process, in order to determine
  1514. ;                to which question an answer (obtained via the WAIT
  1515. ;                routine) corresponds, one merely has to check that
  1516. ;                the integer BUFID matches the integer BID that was
  1517. ;                returned by the SENDQ routine.
  1518. ;      SENDER:   6 bytes which contain the name of the sender.
  1519.  
  1520. ; MASK is a 1-byte word passed in the E register.  Its bits specify
  1521. ; what data is being waited for:
  1522.  
  1523. ;           MASK
  1524. ;            bit                  Request
  1525. ;         ------------------------------------
  1526. ;             0                   Question
  1527. ;             1                   Message
  1528. ;             2                   Answer
  1529. ;            3-7                 Interrupts
  1530.  
  1531. ; Requests for interrupts are handled first.  After that, the word
  1532. ; is scanned from right to left.
  1533. ; The routine returns a 1-byte integer RESULT in the A register
  1534. ; with the following interpretation:
  1535.  
  1536. ;       RESULT                      event
  1537. ;     ----------------------------------------------------------
  1538. ;         0          routine completed its task successfully
  1539. ;         1                   case of dummy answer
  1540. ;         2               case where sender was removed
  1541.  
  1542.  
  1543. WAIT:  PUSH   B             ; Store WTBLK on stack
  1544. WT1:   RDLD   C,CPP         ; c <- cpp
  1545.        MVI    B,0
  1546.        RXAD   B,RDMK        ; (H&L) <- address of RDMK[cpp]
  1547.        MOV    A,E           ; a <- MASK
  1548.        DI
  1549.        ANA    M             ; a <- (MASK AND (RDMK[cpp]))
  1550.        CMP    B
  1551.        JNZ    WCASE         ; Jump if  a  is not  0
  1552.  
  1553.        RXST   E,B,WDMK      ; (WDMK[cpp]) <- MASK
  1554.        RXAD   B,DSM
  1555.        DAD    B             ; (H&L) <- address of DSM[2*cpp]
  1556.        PUSH   D             ; Save MASK
  1557.        XCHG
  1558.        MOV    C,B           ; c <- 0
  1559.        CALL   P+1           ; P(DSM[cpp])
  1560.        POP    D
  1561.        JMP    WT1
  1562.  
  1563.  
  1564.        ; Case where desired data had been received
  1565. WCASE: CPI    8
  1566.        JP     CASEI         ; Jump if event is interrupt
  1567.  
  1568.        PUSH   H             ; Store address of RDMK[cpp] on stack
  1569.        PUSH   PSW
  1570.        LXI    D,AS
  1571.        MVI    C,2
  1572.        CALL   P             ; P(AS)
  1573.        POP    PSW
  1574.        POP    D             ; (D&E) <- address of RDMK[cpp]
  1575.        RRC
  1576.        JNC    WAM           ; Jump if question is not desired
  1577.  
  1578.        ; Case of a question
  1579. CASEQ: LXI    H,ABP-RDMK
  1580.        DAD    D             ; (H&L) <- address of ABP[cpp]
  1581.        PUSH   H
  1582.        LXI    H,FQP-RDMK
  1583.        MVI    A,MASKQ
  1584.        CALL   WMAIN
  1585.        JMP    EXIT
  1586.  
  1587.  
  1588. WAM:   RRC
  1589.        LXI    H,FMBP
  1590.        PUSH   H
  1591.        JNC    CASEA         ; Jump if message is not desired
  1592.  
  1593.        ; Case of a message
  1594. CASEM: LXI    H,FMP-RDMK
  1595.        MVI    A,MASKM
  1596.        CALL   WMAIN
  1597.        JC     EXIT          ; Jump if  sdr = 0 , i.e., actual
  1598.                             ; sender has been removed in the
  1599.                             ; meantime
  1600.  
  1601.        RXAD   B,MBC         ; (H&L) <- address of MBC[sdr]
  1602.        INR    M             ; (MBC[sdr]) <- (MBC[sdr])+1
  1603.        JMP    EXIT
  1604.  
  1605.  
  1606.        ; Case of an answer (and no message or question)
  1607. CASEA: LXI    H,FAP-RDMK
  1608.        MVI    A,MASKA
  1609.        CALL   WMAIN
  1610.        RDLD   C,CPP         ; c <- cpp
  1611.        RXAD   B,MBC         ; (H&L) <- address of MBC[cpp]
  1612.        INR    M             ; (MBC[cpp]) <- (MBC[cpp])+1
  1613.        JMP    EXIT
  1614.  
  1615.  
  1616.        ; Case of interrupt
  1617. CASEI: MOV    C,A           ; c <- (MASK AND RDMK[cpp])
  1618.        MVI    B,1           ; b <- MASKI
  1619. WINT1: MOV    A,B
  1620.        RRC                  ; Rotate MASKI right
  1621.        MOV    B,A
  1622.        ANA    C             ; a <- (MASKI AND MASK AND (RDMK[cpp]))
  1623.        ORA    A             ; Test if  a = 0
  1624.        JZ     WINT1         ; Jump if  a = 0
  1625.  
  1626.  
  1627.  
  1628.        CMA
  1629.        ANA    M             ; (RDMK[cpp]) <- (RDMK[cpp]) AND -MASKI
  1630.        MOV    M,A
  1631.        EI
  1632.        POP    H
  1633.        MOV    M,B
  1634.        XRA    A             ; RESULT = 0
  1635.        RET
  1636.  
  1637.  
  1638.  
  1639. ;                         WMAIN
  1640.  
  1641. ;This subroutine does all the necessary work for WAIT.
  1642.  
  1643.  
  1644. WMAIN: DAD    D             ; (H&L) <- address of FXP[cpp] ,
  1645.                             ; where  X = M, Q, or A
  1646.        PUSH   D             ; Save address of RDMK[cpp]
  1647.        MVI    B,0
  1648.        MOV    C,M           ; c <- BUFID
  1649.        XCHG                 ; (D&E) <- address of FXP[cpp]
  1650.        RXAD   B,NMBP        ; (H&L) <- address of NMBP[BUFID]
  1651.        MOV    B,A           ; Save MASKX in B
  1652.        MOV    A,M           ; a <- (NMBP[BUFID])
  1653.        XCHG                 ; (D&E) <- address of NMBP[BUFID]
  1654.                             ; (H&L) <- address of FXP[cpp]
  1655.        MOV    M,A           ; Set FXP to new value
  1656.        POP    H             ; (H&L) <- address of RDMK[cpp]
  1657.        ORA    A             ; Test if  (NMBP[BUFID]) = 0
  1658.        JNZ    WM1           ; Jump if queue is not empty
  1659.  
  1660.        MOV    A,B
  1661.        CMA
  1662.        ANA    M
  1663.        MOV    M,A           ; Appropriate bit in (RDMK[cpp]) has
  1664.                             ; been set to 0
  1665. WM1:   POP    H             ; (H&L) <- return address from call to
  1666.                             ;          WMAIN
  1667.        XTHL                 ; Exchange H&L with top of stack
  1668.                             ; which holds address of FMBP (in case
  1669.                             ; of message or answer) or ABP[cpp]
  1670.        MOV    A,M
  1671.        STAX   D             ; Store  a  in NMBP[BUFID]
  1672.        MOV    M,C           ; fmbp  or  (ABP[cpp]) <- BUFID
  1673.  
  1674.        ; Assemble wait block
  1675.        POP    H             ; (H&L) <- return address from call
  1676.                             ; to WMAIN
  1677.        XTHL                 ; Exchange H&L with top of stack which
  1678.                             ; holds WTBLK
  1679.        MOV    M,B           ; Store record of event, namely MASKX,
  1680.                             ; in WTBLK
  1681.        INX    H
  1682.        PUSH   H
  1683.        MVI    B,0
  1684.        RXLD   A,B,ASTAT     ; a <- (ASTAT[BUFID])
  1685.        ORA    A             ; Test if  a = 0
  1686.        JNZ    WM2           ; Jump if MB contains a dummy answer.
  1687.                             ; This can happen only if WMAIN was
  1688.                             ; called from CASEA.  It may have hap-
  1689.                             ; pened that a process was removed and
  1690.                             ; it never had a chance to answer the
  1691.                             ; question it was asked.  In that case
  1692.                             ; (ASTAT[BUFID]) was set to 1.
  1693.  
  1694.        RXAD   B,MESS
  1695.        DAD    B             ; (H&L) <- address of MESS[2*BUFID]
  1696.        MOV    E,M
  1697.        INX    H
  1698.        MOV    D,M           ; (D&E) <- MESSAGE or ANSWER
  1699.  
  1700.  
  1701.  
  1702.        POP    H
  1703.        STDM                 ; Store MESSAGE or ANSWER in WTBLK
  1704.        INX    H
  1705.        MOV    M,C           ; Store BUFID in WTBLK
  1706.        INX    H
  1707.        XCHG
  1708.        RXLD   A,B,MBSP      ; a <- sdr = (MBSP[BUFID])
  1709.        ORA    A             ; Test if  a = 0
  1710.        JZ     WM3           ; Jump if  sdr = 0 , i.e., actual
  1711.                             ; sender has been removed in the
  1712.                             ; meantime
  1713.  
  1714. ;      NOTE: We assume that the carry bit which now is 0 stays
  1715. ;      that way until we return from this subroutine.
  1716.        MOV    C,A           ; Save  sdr  in C
  1717.        PUSH   D
  1718.        M6A                  ; e <- 6*sdr , d <- 0
  1719.        RXAD   D,NAM         ; (H&L) <- address of NAM[6*sdr]
  1720.        POP    D             ; (D&E) <- address of SENDER field
  1721.                             ; in WTBLK
  1722.        TRNAM                ; Transfer name
  1723.        MOV    D,B           ; d <- 0
  1724.        RET                  ; Note that the carry bit is assumed
  1725.                             ; to be 0
  1726.  
  1727.  
  1728. WM2:   MVI    D,1           ; Set RESULT
  1729.        RET
  1730.  
  1731. WM3:   MVI    D,2           ; Set RESULT (sdr=0)
  1732.        STC                  ; Set the carry bit to 1
  1733.        RET
  1734.  
  1735.  
  1736.        END    HALT