!**************
!*  BVT1S     *
!*DA:09.APR.80*
!**************
CONTROL  K'100001';  ! 'SYSTEM' PROGRAM (FAST ROUTINE ENTRY/EXIT)
PERMROUTINESPEC  SVC(INTEGER  EP, P1, P2)
BEGIN 
     SYSTEMROUTINESPEC  MAPHWR(INTEGER  SEGS)
     SYSTEMROUTINESPEC  LINKIN(INTEGER  SER)
     RECORDFORMAT  PF(BYTEINTEGER  SERVICE, REPLY, C 
        INTEGER  A1, A2, A3)
     RECORDFORMAT  TTF(INTEGER  KBS, KBD, TTS, TTD)
     RECORDFORMAT  BUFF(INTEGER  PT, LAST, BYTEINTEGERARRAYNAME  B)
     RECORDFORMAT  BUFFX(INTEGER  PT, LAST, ARRAYPT)
     CONSTRECORD  (BUFFX) NAME  NULL = 0
     CONSTINTEGER  RUBOUT=K'177'
     CONSTINTEGER  CAN=24
     CONSTINTEGER  CR=13
     CONSTINTEGER  BELL=7
     CONSTINTEGER  ESC=K'33'
      CONSTINTEGER  SI=K'17';        ! SHIFT INTO LOWER MODE (CTRL O)
      CONSTINTEGER  SO=K'16';        ! SHIFT OUT (CTRL N)
      CONSTINTEGER  DLE=K'20';       ! (CTRL P)
      CONSTINTEGER  EOT = K'04';     ! EOF (CTRL D)
      CONSTINTEGER  DC1=K'21';       ! CANCEL OUTPUT (CTRL Q)
      CONSTINTEGER  TAB = 9;          ! TAB (IMPLEMENTED AS 3 SPACES)
     OWNRECORD  (TTF) NAME  TT=K'137560'
     OWNINTEGER  KBINT=-2
     OWNINTEGER  TTINT=-1
     OWNINTEGER  TTSER=1; ! ???
     OWNINTEGER  CLIID=2
     OWNINTEGER  TT STATUS=0, UPPER=32, TT IDLE=0, E PT=0, EFPT=0
     RECORD  (PF) P2
     OWNRECORD  (PF) NAME  P
     CONSTINTEGER  NO OF SPECS = 6
     OWNBYTEINTEGERARRAY  SPECS(0:NO OF SPECS) =
       RUBOUT, CAN, ESC, CR, SI, SO, TAB
     INTEGER  CHAR, I, IN MODE, E LAST
     INTEGER  OUTID, SEG, CLI FLAG, CID, CADR
     OWNRECORD  (BUFF)  OUT, INH
     RECORD  (BUFFX) NAME  BUFX, INX
      RECORDFORMAT  HF(RECORD  (HF) NAME  H, RECORD  (PF) P)
      RECORDFORMAT  QF(RECORD  (HF) NAME  H)
      OWNRECORD  (HF) ARRAY  HA(0:15)
      OWNRECORD  (HF) NAME  H
      OWNRECORD  (QF) HI, HO
      OWNRECORD  (QF) FREE
      OWNINTEGER  FIRST, LAST, CURR
      OWNBYTEINTEGERARRAY  BUFFER(0:255)
     OWNBYTEINTEGERARRAY  ECHOB(1:40)
     SWITCH  INS(0:NO OF SPECS), STATE(0:7)
     ROUTINESPEC  DRIVE TT(INTEGER  CHAR)
     ROUTINESPEC  ECHO(INTEGER  X)
     ROUTINESPEC  ECHO BELL
     ROUTINESPEC  TRANSFER INPUT
     ROUTINESPEC  OUTPUT REPLY
      ROUTINESPEC  PLANT(INTEGER  N)
!!     %CONSTBYTEINTEGERARRAY CANM(0:3)= 3, '#', CR, NL
!!     %CONSTBYTEINTEGERARRAY CLIM(0:3)= 3, '<', 8, '>'
     CONSTINTEGER  MYSEG=4, MSA=K'100000'
     CONSTINTEGER  MYISEG=3, MISA=K'060000'
     MAPHWR(5);        ! MAP REGS TO SEG 5
     LINKIN(TTSER); LINKIN(KBINT); LINKIN(TTINT)
     TT_KBS=K'100'
     BUFX==OUT
     INX==INH
     CYCLE  I = 15, -1, 0
        PUSH(FREE, HA(I))
     REPEAT 
     CYCLE 
        IF  OUTID=0 AND  NOT  HO_H == NULL  START 
         H == POP(HO); PUSH(FREE, H)
         P == H_P
        ELSE 
           P == P2
           P_SERVICE = 0
           POFF(P)
        FINISH 
        IF  P_SERVICE=KBINT&X'FF' START 
           CHAR=TT_KBD&127; ! STRIP PARITY BIT
           CYCLE  I=NO OF SPECS, -1, 0
              ->INS(I) IF  CHAR=SPECS(I)
           REPEAT 
           !! NORMAL CHAR
           IF  CHAR>='A'+K'40' AND  CHAR<='Z'+K'40' THENC 
             CHAR=CHAR-UPPER;       ! TURN TO UPPER
         PLANT(CHAR)
           CONTINUE 
INS(0):                     ! RUBOUT
          IF  LAST#CURR START 
               LAST = (LAST-1)&255
            ECHO(8); ECHO(' '); ECHO(8)
           ELSE  ECHO BELL
           CONTINUE 
INS(1):    ! CANCEL
           IF  LAST#CURR START 
              LAST = CURR
              ECHO('#');  ECHO(CR);  ECHO(NL);  E LAST=E PT
           ELSE  ECHO BELL
           CONTINUE 
INS(2):         ! ESCAPE - GO TO CLI
            CLI FLAG = 1
               LAST = 0; CURR = 0; FIRST = 0
INS2:         ECHO('$'); ECHO BELL
           CONTINUE 
INS(4):             ! SHIFT IN
            UPPER = 0;  CONTINUE 
INS(5):             ! SHIFT OUT
             UPPER = 32;  CONTINUE 
INS(6):             ! TAB
             PLANT(' '); PLANT(' '); PLANT(' '); CONTINUE 
INS(3):              ! CR
            PLANT(NL); CURR = LAST
           TRANSFER INPUT
           E LAST=E PT;       ! ALLOW IT TO DO OUTPUT NOW
        ELSE  IF  P_SERVICE=TT INT&X'FF' START 
           ->STATE(TT STATUS)
DO OUT:
STATE(5):                       ! GOING IDLE
           TT STATUS=0
           IF  E PT>0 THEN  TT STATUS=2 ELSESTART 
              IF  OUT_LAST#0 THEN  TT STATUS=1
           FINISH 
           ->STATE(TT STATUS)
STATE(1):                      ! NORMAL OP
           CHAR=OUT_B(OUT_PT);  OUT_PT=OUT_PT+1
           IF  OUT_PT>=OUT_LAST THEN  TT STATUS=5 AND  OUTPUT REPLY
           DRIVE TT(CHAR)
STATE(0):  CONTINUE 
STATE(2):                       ! ECHO OP
           IF  EFPT<E PT START 
              EFPT=EFPT+1
              CHAR=ECHOB(EFPT)
              IF  EFPT=E LAST THEN  TT STATUS=5 AND  E LAST=-1
              DRIVE TT (CHAR)
           ELSE 
              TT STATUS = 6
              IF  EFPT=E LAST START 
                 E LAST=-1;  E PT=0;  EFPT=0
                 ->DO OUT
              FINISH 
           FINISH 
           IF  EFPT=E PT THEN  E PT=0 AND  EFPT=0
           CONTINUE 
STATE(3):                     ! NORMAL CR
STATE(4):                     ! ECHO CR
STATE(7):                     ! END OF LINE - NEWLINE
           TT STATUS=5
           DRIVE TT(NL+128)
           CONTINUE 
STATE(6):                  ! IN ECHO LINE
           CYCLE ; REPEAT 
        ELSE  IF  P_SERVICE=TT SER START ; ! USER REQUEST
           IF  P_A1=1 START ;        ! OUTPUT REQUEST
              IF  OUTID#0 START 
                 H == POP(FREE)
                 IF  H == NULL START 
REJ:                P_SERVICE= P_REPLY; P_REPLY = TT SER
                    P_A1 = 1; PON(P)
                    CONTINUE 
                 FINISH 
                 H_P = P;       ! COPY P INTO SAFE PLACE
                 PUSH(HO, H);   ! AND QUEUE IT
                 CONTINUE 
              FINISH 
              OUTID=P_REPLY
              SEG=P_A2>>13;         ! SEG NO OF BUFFER
              MAP VIRT(OUTID, SEG, MY SEG)
              BUFX_ARRAYPT=MSA+(P_A2&K'17777')
              OUT_PT=0;  OUT_LAST=P_A3;   ! LENGTH
              IF  OUT_LAST=0 THEN  OUTPUT REPLY ELSESTART 
                    ->DO OUT IF  TT STATUS=0;   ! TT IDLE
               FINISH 
           ELSE 
              !! INPUT REQUEST
              IF  P_A1 # 0 START 
                CID = P_REPLY;  CADR = P_A2
                CONTINUE  IF  P_A3 # 0; ! JUST READ FROM CLI
              FINISH 
              H == POP(FREE)
              -> REJ IF  H == NULL
              H_P = P;         ! COPY P INTO A SAFE PLACE
              PUSH(HI, H);     ! AND Q IT
               IF  P_A1#0 AND  FIRST=LAST THEN  -> INS2
               IF  FIRST#CURR START ;   ! NON EMPTY LINE
                  TRANSFER INPUT
              FINISH 
           FINISH 
        FINISH 
     REPEAT 
     ROUTINE  DRIVE TT(INTEGER  CHAR)
        IF  CHAR=NL START 
           TT STATUS=TT STATUS+2
           CHAR=CR
        FINISH 
        TT_TTD=CHAR
        TT_TTS=TT_TTS!K'100'; ! INTS ON
     END 
     ROUTINE  ECHO(INTEGER  X)
        RETURN  IF  E PT>40
        E PT=E PT+1;  ECHOB(E PT)=X
        IF  TT STATUS=0 OR  TT STATUS=6 START 
           TT STATUS=2
           DRIVE TT(X)
           EFPT=1
        FINISH 
     END 
     ROUTINE  ECHO BELL
        ECHO(BELL);  E LAST=E PT
     END 
     ROUTINE  PLANT(INTEGER  CHAR)
        BUFFER(LAST) = CHAR
        LAST = (LAST+1)&255
        ECHO(CHAR)
     END 
     ROUTINE  TRANSFER INPUT
        INTEGER  SEG, I, ID, ADR, N
        IF  CLI FLAG # 0 START ;  ! PREEMPTED BY CLI
           ID = CID;  ADR = C ADR; CLI FLAG = 0
        ELSE 
           IF  HI_H == NULL THEN  RETURN 
           H == POP(HI);  PUSH(FREE, H)
           ID = H_P_REPLY; ADR = H_P_A2
        FINISH 
        IF  ID#0 START 
           SEG=ADR>>13
           MAP VIRT(ID, SEG, MYISEG)
           INX_ARRAY PT=MISA+(ADR&K'17777')
           CYCLE  I = 0, 1, 80
               N = BUFFER(FIRST)
               INH_B(I) = N
               FIRST = (FIRST+1)&255
               EXIT  IF  N = NL
           REPEAT 
           P_SERVICE=ID;  P_REPLY=TTSER
           P_A1=I+1
           PON(P)
           MAP VIRT(0, -1, MYISEG)
        FINISH 
     END 
     ROUTINE  OUTPUT REPLY
        MAP VIRT(0, -1, MYSEG)
        P_SERVICE=OUTID;  P_REPLY=TTSER
        P_A1=0
        PON(P)
        OUTID=0; OUT_LAST = 0
     END 
ENDOFPROGRAM