! FILE 'CLI1S'
! FILE 'CLI1S'
!**************
!* CLI1S      *
!* 16.JUN.80  *
!**************

PERMINTEGERFNSPEC  SVC(INTEGER  EP, INTEGER  P1, INTEGER  P2)
PERMINTEGERMAPSPEC  INTEGER(INTEGER  X)
PERMBYTEINTEGERMAPSPEC  BYTEINTEGER(INTEGER  X)
PERMINTEGERFNSPEC  ADDR(INTEGERNAME  X)
SYSTEMINTEGERFNSPEC  GETID


CONTROL  K'101011';                    ! TRUSTED

RECORDFORMAT  DUMREC(INTEGER  X)
CONSTRECORD  (DUMREC) NAME  NULL = 0


BEGIN 
     CONSTINTEGER  DELETE = 5
     CONSTINTEGER  SCHEDULE = 9
     CONSTINTEGER  MAP PSECT = 16

     CONSTINTEGER  TASK LOW LIMIT = 30
                                       ! SEE SUPERVISOR FOR UPDATES
     OWNINTEGER  TASK LIMIT = 55

     CONSTINTEGER  T POFF = 2

      OWNINTEGER  TT SER = 1;           ! TT HANDLER (SHAREABLE CODE !!)
     CONSTINTEGER  LOAD SER = 5;       ! MAIN LOADER SERVICE

     RECORDFORMAT  UREGSF(INTEGER  R0, R1, R2, R3, R4, R5, PC, PS, SP)
     RECORDFORMAT  SEGF(INTEGER  PAR, PDR, DADD, USE)
     RECORDFORMAT  PSECTF(INTEGER  Q, C 
       BYTEINTEGER  ID, STATE, BYTEINTEGERARRAY  C 
       NAME(0:3), BYTEINTEGER  PRIO, INTEGER  POFFQ, RECORD  (UREGSF C 
       )URS, INTEGER  TRAPV, RECORD  (SEGF) ARRAY  SEG(0:7))

     RECORDFORMAT  PF(BYTEINTEGER  SERVICE, REPLY, INTEGER  A, B, C)
     RECORDFORMAT  P2F(BYTEINTEGER  SERVICE, REPLY, A1, A2, C 
       BYTEINTEGERNAME  B, BYTEINTEGER  C1, C2)

      CONSTBYTEINTEGERNAME  INT CHAR = K'100060';   ! IN SEG 4 !!!
      CONSTBYTEINTEGERNAME  CHANGE OUT ZERO = K'160310'

     RECORDFORMAT  D1F(INTEGER  X)
     RECORDFORMAT  D2F(BYTEINTEGERNAME  B)
     RECORDFORMAT  D3F(INTEGERNAME  Z)
     RECORDFORMAT  D4F(RECORD  (PSECTF) NAME  PST)

     RECORD  (PF)P
     RECORD  (P2F) NAME  P2

     INTEGER  ID, INPT
     INTEGER  NCHAR, OSEG, CKSM
     OWNINTEGER  READ FLAG = 0, FSYS = 0, PROG = 1

     OWNBYTEINTEGERARRAY  STORE(0:70) = 
     0, 'L', 'O', 'A', 'D', 'U', 'P', NL, 0(0)


     ROUTINESPEC  PRI
     ROUTINESPEC  RELEASE(INTEGER  SEG)
     ROUTINESPEC  PUT READ ON(INTEGER  TYPE)
     ROUTINESPEC  OCTAL(INTEGER  N)
      RECORD  (PSECTF) MAP  SPEC  GET PSECT(INTEGER  ID)
      RECORD  (PSECTF) MAP  SPEC  GET NAME(BYTEINTEGERNAME  ST)
     ROUTINESPEC  PNAME(BYTEINTEGERARRAYNAME  NAME)
     INTEGERFNSPEC  CLI

     RECORD  (D1F)D1
     RECORD  (D2F) NAME  D2
     RECORD  (D3F) NAME  D3

     D2 == D1;  D3 == D2; P2 == P
     IF  TT SER#1 START 
        CHANGE OUT ZERO = TT SER; ! SWITCH TO NEW CONSOLE
        STORE(6) = 'U';   ! LOADES 'LOADUU'
     FINISH 

     ID = GETID
     -> FROM OUT;                      ! INITIAL SPECS LOAD
     CYCLE 
        PUT READ ON(0) IF  READ FLAG = 0
        P_SERVICE = 0
        POFF(P)

        IF  P_REPLY = TT SER START ;     ! REPLY FROM KEYBOARD
           NCHAR = P_A;               ! GET NO OF CHARS
           READ FLAG = 0
           IF  STORE(1) = NL THENCONTINUE 

           PROG = PROG+1;              ! COUNT LOADED PROGS

FROM OUT:                              ! ENTRY FOR EXTERNAL CALLS
           IF  CLI = 0 THEN  PROG = PROG-1 AND  CONTINUE 

            ! NOT AN INSTRUCTION, SO PASS TO LOADER
            P_SERVICE = LOAD SER; P_REPLY = ID
            D2_B == STORE(1)
            P2_A1 = 1; P2_A2 = FSYS; P_B = D1_X
            P2_C1 = 0; P2_C2 = TT SER
            PON(P2)
        ELSE 
           IF  P_A = 3 START ;         ! LOADED EXTRA PROG
               PROG = PROG+1
               CONTINUE 
           FINISH 

           IF  P_A = 2 START ;        ! PROG STOPPING
              IF  P_C = 0 START 
                 IF  PROG # 1 THEN  PRINTSTRING('stopped
')
              ELSE 
                 IF  P_C #- 2 START 
                    PRINTSTRING('F A U L T ');  WRITE(P_C, 1)
                 ELSE 
                    PRINTSTRING("term req.")
                 FINISH 
                 NEWLINE
              FINISH 
            ELSE 
 
               IF  P_A = 0 START 
                  IF  P_B = 3 START 
                     PRINTSTRING("*no "); PRI
                  ELSE 
                     PRINTSYMBOL('*'); PRI
                     PRINTSTRING(" fault ")
                     PRINTSYMBOL(P_B+'0')
                  FINISH 
                  NEWLINE
               FINISH 
           FINISH 
           PROG = PROG-1
           IF  PROG <= 0 THEN  PROG = 0 AND  PUT READ ON(1)
        FINISH 
      REPEAT 





      ROUTINE  PRI
         INTEGER  I, J
         CYCLE  I = 1, 1, 6
            J = STORE(I)
            EXIT  IF  J<= ' '
            PRINTSYMBOL(J)
         REPEAT 
      END 

     ROUTINE  RELEASE(INTEGER  SEG)
        IF  SEG #- 1 START 
           MAP VIRT(0, -1, 4);         ! ALWAYS RELEASE LOADER SEG 4
        FINISH 
     END 


     ROUTINE  PUT READ ON(INTEGER  TYPE)
        RECORDFORMAT  P3F(BYTEINTEGER  SERVICE, REPLY, INTEGER  A, C 
          BYTEINTEGERNAME  B, INTEGER  C)
        RECORD  (P3F)P3
        P3_SERVICE = TT SER;  P3_REPLY = ID
        P3_B == STORE(1)
        IF  TYPE = 0 THEN  P3_A = 2 ELSE  P3_A = 5
        IF  PROG < 0 THEN  PROG = 0
        P3_C = PROG;                  ! SYSTEM IDLE FLAG
        READ FLAG = 1;                 ! WAITING FOR REPLY
        PON(P3)
     END 


     ROUTINE  OCTAL(INTEGER  N)
        INTEGER  I
        SPACE
        PRINTSYMBOL(N >> I&7+'0') FOR  I = 15, -3, 0
     END 

     RECORD  (PSECTF) MAP  GET PSECT(INTEGER  ID)
        INTEGER  N
        RECORD  (D4F) NAME  D4;  RECORD  (D1F)D1
        D4 == D1
        N = SVC(MAP PSECT, ID, 5);     ! MAP TO MY K'100000'
        D1_X = N
        RESULT  == D4_PST
     END 

     RECORD  (PSECTF) MAP  GET NAME(BYTEINTEGERNAME  ST)
        RECORD  (PSECTF) NAME  PST
        INTEGER  PT, ID, J, CHAR, MATCH
        RECORDFORMAT  D5F(BYTEINTEGERARRAYNAME  STR)
        RECORD  (D2F) NAME  D2; RECORD  (D5F) D5
        D2 == D5
        D2_B == ST
        CYCLE  ID = TASK LOW LIMIT, 1, TASK LIMIT
           PST == GET PSECT(ID)
           UNLESS  PST == NULL START 
              CYCLE  J = 0, 1, 3
                 CHAR = D5_STR(J);  MATCH = PST_NAME(J)
                 EXITIF  CHAR <= ' ' >= MATCH
                 -> NO IF  CHAR # MATCH
              REPEAT 
              RESULT  == PST UNLESS  PST_STATE = 0
           FINISH 
NO:     REPEAT 
        RESULT  == NULL
     END 


     ROUTINE  PNAME(BYTEINTEGERARRAYNAME  NAME)
        INTEGER  I
        PRINTSYMBOL(NAME(I)) FOR  I = 0, 1, 3
     END 


     INTEGERFN  CLI
        RECORDFORMAT  D1F(STRINGNAME  S)
        RECORDFORMAT  D2F(BYTEINTEGERNAME  N)

        RECORD  (D1F)D1
        RECORD  (D2F) NAME  D2

        RECORD  (PSECTF) NAME  PST

        INTEGER  I, J, K, ID, CHAR, TYPE

        CONSTINTEGER  COM LIMIT = 10

        CONSTSTRING  (5) ARRAY  COMMS(0:COM LIMIT) = 'LOGON',  C 
          'TASKS', 'REGS', 'SEGS', 'PURGE', 'KILL', 
        'FREE', 'HOLD', 'INT', 'KICK', 'ABORT'

        SWITCH  COMSW(0:COM LIMIT)
        RECORDFORMAT  REGF(INTEGERARRAY  R(0:8))
        RECORD  (REGF) NAME  REG
        CONSTSTRING  (2) ARRAY  REGS(0:8) = 'R0', 'R1', 'R2', 'R3',  C 
          'R4', 'R5', 
        'PC', 'PS', 'SP'
        RECORD  (SEGF) NAME  SEG


        INPT = 1
        INPT = INPT+1 WHILE  'A' <= STORE(INPT) <= 'Z' AND  INPT <= C 
          NCHAR
        STORE(0) = INPT-1
        D2 == D1
        D2_N == STORE(0)
        CYCLE  I = 0, 1, COM LIMIT
           IF  COMMS(I) = D1_S START 
              IF  I = 8 START 
                 CHAR = STORE(INPT+1);  INPT = INPT+2
              FINISH 
              IF  I >= 2 START 
                 PST == GET NAME(STORE(INPT+1))
                 IF  PST == NULL START 
                    PRINTSTRING('TASK?
')
                    RESULT  = 0
                 FINISH 
              FINISH 
              -> COMSW(I)
           FINISH 
        REPEAT 
        RESULT  = 1

COMSW(1):                              ! TASKS
        CYCLE  ID = TASK LOW LIMIT, 1, TASK LIMIT
           PST == GET PSECT(ID)
           UNLESS  PST == NULL START 
              PNAME(PST_NAME)
              OCTAL(PST_ID);  OCTAL(PST_STATE)
              NEWLINE
           FINISH 
        REPEAT 
        -> OK
COMSW(2):                              ! REGS  OF NOMINATED TASK
        REG == PST_URS
        CYCLE  I = 0, 1, 8
           PRINTSTRING(REGS(I));  OCTAL(REG_R(I));  SPACE
           NEWLINE IF  I = 4
        REPEAT 
        NEWLINE
        -> OK
COMSW(3):                              ! SEGS
        CYCLE  I = 0, 1, 7
           SEG == PST_SEG(I)
           OCTAL(SEG_PAR);  OCTAL(SEG_PDR)
           OCTAL(SEG_DADD);  NEWLINE
        REPEAT 
OK:     RESULT  = 0

COMSW(4):                              ! PURGE
        PROG = PROG-1
         I = SVC(SCHEDULE, PST_ID, 1); ! HOLD IT
        PNAME(PST_NAME)
        PRINTSTRING(' purged
')
        I = SVC(DELETE, PST_ID, 0)
        -> OK

COMSW(5):                              ! KILL
        I = SVC(SCHEDULE, PST_ID, 1)
        I = SVC(SCHEDULE, PST_ID, K'020000')
        -> OK

COMSW(0):                              ! LOG
        FSYS = (STORE(INPT+1)-'0') << 3+STORE(INPT+2)-'0'
        NEWLINE
        -> OK

COMSW(6):                              ! FREE TASK   (PUT ON CPUQ
COMSW(9):                               ! KICK TASK
        TYPE = 0
KICK IT:
         I = SVC(SCHEDULE, PST_ID, 0); ! REMOVE HOLD
        IF  PST_STATE # T POFF THEN  ->OK
        P_SERVICE = PST_ID;  P_REPLY = 7;  P_A = TYPE;  PON(P)
        -> OK

COMSW(10):                            ! ABORT TASK
        TYPE = 1
        -> KICK IT

COMSW(7):                              ! WAIT PROCESS
         I = SVC(SCHEDULE, PST_ID, 1); ! HOLD IT
        -> OK

COMSW(8):                              ! INT 'CHAR' 'TASK'
        IF  PST_ID > K'42' START ;     ! NOT SYSTEM TASKS
           MAP VIRT(PST_ID, 7, 4)
           INT CHAR = CHAR
           RELEASE(0);                 ! RELEASE THE SEG
        FINISH 
        -> OK
     END 
ENDOFPROGRAM