*COMDECK PBTMRSRVS
_$J+? 
                                                          _80 12 18?
_***********************************************************************
*                                                                      *
*                             PBINSERT                                 *
*                                                                      *
*                INSERT THE PACKET IN THE LINKED LIST                  *
*                                                                      *
***********************************************************************?
_$R-,G-,I-  NOT RECURSIVE, INTERRUPTS MUST BE DISABLED BY CALLER ?
_***********************************************************************
*                                                                      *
** OVERVIEW -  PACKETS WHICH REPRESENT TIMERS THAT NEED TO BE SET OR   *
*              RESET ARE HANDLED BY THE INSERT ROUTINE.  THE INSERT    *
*              ROUTINE DIVIDES THE REQUESTED TIME BY THE DELTA TIME    *
*              (THE TIME BETWEEN PACKETS POINTED TO BY THE PARTITION   *
*              TABLE ENTRIES) AND USES THIS VALUE TO INDEX INTO THE    *
*              PARTITION TABLE.  THE EXPIRATION TIME OF THE PACKET     *
*              TO BE INSERTED IS COMPARED TO THAT OF THE PACKET        *
*              POINTED TO BY THE PARTITION TABLE ENTRY AND A FORWARD   *
*              OR BACKWARD SEARCH ENSUES TO FIND THE PROPER PLACE-     *
*              MENT.                                                   *
*                                                                      *
** INPUT -     POINTER TO TIMER PACKET                                 *
*                                                                      *
** CALLING PROGRAMS -                                                  *
*              TMRSRVS.                                                *
*              PBTICK.                                                 *
*                                                                      *
** OUTPUT -    NONE.                                                   *
*                                                                      *
** EXTERNAL SUBROUTINES -                                              *
*              NONE.                                                   *
*                                                                      *
***********************************************************************?
PROCEDURE PBINSERT; 
VAR 
      T7ENTRY  : B7PKTPTR;                  _ CURRENT TIME INTERVAL    ?
                                            _ MARKER                   ?
      T7EXTIME : INTEGER;                   _EXPIR. TIME NEW ENTRY     ?
      T7INDX   : INTEGER;                   _INDEX INTO PARTITION TABLE?
                                            _ HEAD                     ?
BEGIN 
WITH B7LSTPTR' DO 
  BEGIN 
  BKTIMRK  := FALSE;                        _NOT A TIME INTERVAL MARKER?
  T7EXTIME := CICLKADT.CICOUNT + BKTIME;    _GET EXPIRATION TIME       ?
  BKEXTIME := T7EXTIME;                     _STICK INTO NEW ENTRY      ?
  T7INDX   := BKTIME DIV B7TMINTVL;         _COMPUTE INDEX             ?
  IF T7INDX > B7NPTNS -1                    _IF INDEX IS GREATER THAN  ?
  THEN                                      _ THE END OF THE TABLE     ?
    T7INDX := B7NPTNS -1;                   _ ADJUST TO EQUAL THE END  ?
                                            _ OF THE TABLE             ?
  T7INDX := B7TOPINDX + T7INDX;             _CALCULATE INDEX           ?
  IF T7INDX > B7ENDINDX                     _IF PAST END OF TABLE      ?
  THEN
    T7INDX := T7INDX - B7ENDINDX - 1;       _THEN ADJUST FOR WRAPAROUND?
  T7ENTRY := BKTMPTR [T7INDX];
_ 
* * * *  FIRST TEST IF A FORWARD OR A BACKWARD SEARCH IS REQUIRED 
? 
  IF (T7ENTRY'.BKEXTIME - T7EXTIME) < 1     _NEW ENTRY GE MARKER ENTRY ?
  THEN                                      _FORWARD SEARCH            ?
_ 
* * * *  FORWARD SEARCH, SEE IF PACKET REPLACES TAIL PACKET 
? 
    IF (B7LSTTAIL'.BKEXTIME -               _NEW PACKET IS GE LAST     ?
        T7EXTIME) < 1                       _PACKET IN CHAIN           ?
    THEN                                    _MAKE NEW TAIL BY          ?
      BEGIN                                 _UPDATING POINTERS         ?
      B7LSTTAIL'.BKFORLNK := B7LSTPTR;      _OLD TAIL FORWARD POINTER  ?
      BKBAKLNK  := B7LSTTAIL;               _PACKET BACKWARD POINTER   ?
      BKFORLNK  := NIL;                     _PACKET FORWARD POINTER    ?
      B7LSTTAIL := B7LSTPTR;                _LIST TAIL POINTER         ?
      END 
    ELSE                                    _NOT A TAIL                ?
_ 
* * * *  FORWARD SEARCH, NO NEW TAIL, START THE SEARCH
? 
      BEGIN 
      REPEAT                                _SEARCH FORWARD TILL       ?
        T7ENTRY := T7ENTRY'.BKFORLNK;       _PACKET FOUND LESS THAN    ?
      UNTIL (T7EXTIME - T7ENTRY'.           _INSERTION PACKET          ?
             BKEXTIME) < 0; 
      BKFORLNK := T7ENTRY;                  _INSERT PACKET BEFORE ENTRY?
      BKBAKLNK := T7ENTRY'.BKBAKLNK;        _ BY UPDATING POINTERS     ?
      BKBAKLNK'.BKFORLNK := B7LSTPTR; 
      T7ENTRY'.BKBAKLNK  := B7LSTPTR; 
      END _ IF T7INDX = B7BOTINDX?
  ELSE                                      _BACKWARD SEARCH           ?
_ 
* * * *  BACKWARD SEARCH, SEE IF PACKET REPLACES HEAD ENTRY 
? 
    IF (T7EXTIME - B7LSTHEAD'.              _NEW PACKET IS LT HEAD     ?
        BKEXTIME) < 1                       _PACKET IN CHAIN           ?
                                            _MAKE NEW HEAD ENTRY       ?
    THEN                                    _ BY UPDATING POINTERS     ?
      BEGIN 
      B7LSTHEAD'.BKBAKLNK := B7LSTPTR;      _HEAD BACKWARD POINTER     ?
      BKFORLNK  := B7LSTHEAD;               _PACKET FORWAD POINTER     ?
      BKBAKLNK  := NIL;                     _PACKET BACKWARD POINTER   ?
      B7LSTHEAD := B7LSTPTR;                _HEAD POINTER              ?
_ 
* * * *  RESET LIMIT, BE SURE NEW LIMIT IS HIGHER THAN CURRENT COUNT
? 
      CICLKADT.CILIMIT := T7EXTIME;         _SET NEW (LOWER) LIMIT     ?
      IF (T7EXTIME -
          CICLKADT.CICOUNT) < 2             _NEW LIMIT LT 2 TICKS AWAY ?
      THEN                                  _YES,                      ?
        CICLKADT.CILIMIT :=                 _BE SURE TO MAKE IT 1 TICK ?
        CICLKADT.CICOUNT + 2;               _AWAY. NOTE: COUNT CAN BE  ?
                                            _BUMPED DURING THIS SEQUENC?
      END _IF ((T7INDX = B7TOPINDX)...? 
    ELSE                                    _SEARCH BACKWARD TO FIND   ?
_ 
* * * *  BACKWARD SEARCH, NO NEW HEAD, START THE SEARCH 
? 
      BEGIN 
      WHILE (T7EXTIME - T7ENTRY'.           _ENTRY GREATER THAN OR     ?
        BKEXTIME) < 0 DO                    _ EQUAL TO THE NEW PACKET  ?
        T7ENTRY := T7ENTRY'.BKBAKLNK;       _ AND INSERT AFTER ENTRY   ?
      BKFORLNK := T7ENTRY'.BKFORLNK;        _ BY UPDATING POINTERS     ?
      BKBAKLNK := T7ENTRY;
      BKFORLNK'.BKBAKLNK := B7LSTPTR; 
      T7ENTRY'.BKFORLNK  := B7LSTPTR; 
      END; _IF T7INDX = B7TOPINDX?
  
  BKACTIVE := TRUE; 
  END;_WITH B7LSTPTR' DO? 
END; _PROCEDURE PBINSERT? 
_$J+? 
                                                          _80 12 18?
_***********************************************************************
*                                                                      *
*                               PBTMRSRVS                              *
*                                                                      *
***********************************************************************?
_$R-,G-,I+  NON RECURSIVE, NON INTERRUPTABLE ?
_***********************************************************************
*                                                                      *
** OVERVIEW -  TMRSRVS IS THE INTERFACE TO THE USER AND                *
*              DETERMINES THE APPROPRIATE SUBROUTINES TO CALL.         *
*                                                                      *
** CALLING PROGRAMS -                                                  *
*              ANY TIMER SERVICES USER, OPERATING AT EITHER OPS OR     *
*              MUX2 INTERRUPT LEVEL.                                   *
*                                                                      *
** INPUT -     T7LPKTPTR.                                              *
*                                                                      *
** OUTPUT -    NONE.                                                   *
*                                                                      *
** EXTERNAL SUBROUTINES -                                              *
*              PBHALT.                                                 *
*              PBINSERT.                                               *
*              PBRDPGE                                                 *
*              PBPSWITCH                                               *
*                                                                      *
***********************************************************************?
PROCEDURE PBTMRSRVS (T7LPKTPTR : B7PKTPTR); 
  
VAR 
      T7PGSAVE    : INTEGER;
  
BEGIN 
B7LSTPTR := T7LPKTPTR;                      _SET GLOBAL PACKET PTR     ?
WITH B7LSTPTR' DO 
  BEGIN 
_ 
* * * *  DELETE ACTIVE PACKET FROM THE TIMER LIST 
? 
  IF BKACTIVE 
  THEN
    BEGIN 
    IF BKFORLNK = NIL                       _LAST ENTRY IN LIST        ?
    THEN
      BEGIN 
      IF B7LSTTAIL " B7LSTPTR 
      THEN                                  _HALT IF THIS              ?
        PBHALT (J0TMRSRVS);                 _PACKET NOT IN CHAIN       ?
      B7LSTTAIL := BKBAKLNK;                _UPDATE LIST TAIL          ?
      END 
    ELSE
      BEGIN 
      IF BKFORLNK'.BKBAKLNK " B7LSTPTR
      THEN                                  _HALT IF THIS              ?
        PBHALT (J0TMRSRVS);                 _PACKET NOT IN CHAIN       ?
      BKFORLNK'.BKBAKLNK := BKBAKLNK;       _UPDATE NEXT BACK-LINK     ?
      END;
    IF BKBAKLNK = NIL                       _FIRST ENTRY IN LIST       ?
    THEN
      B7LSTHEAD := BKFORLNK                 _YES, UPDATE LIST-HEAD     ?
    ELSE
      BKBAKLNK'.BKFORLNK := BKFORLNK;       _NO, UPDATE PREV FORW-LINK ?
    BKACTIVE := FALSE;
    END; _IF BKACTIVE?
_ 
* * * *  INSERT PACKET AT PROPER PLACE IN LIST, EXCEPT FOR CANCEL 
? 
  IF BKTYPE " BKCANCEL
  THEN
    BEGIN 
    PBRDPGE   (T7PGSAV);
    PBPSWITCH (SYSPGE);                     _SWITCH TO SYSTEM PAGE     ?
    PBINSERT;                               _INSERT TIMER PACKET       ?
    PBPSWITCH (T7PGSAV);                    _RESTORE CALLERS PAGE      ?
    END;
  END; _WITH B7LSTPTR' DO?
END; _PROCEDURE PBTMRSRVS?
_$J+? 
                                                          _80 12 18?
_***********************************************************************
*                                                                      *
*                             PBTICK                                   *
*                                                                      *
*                 PROCESSES EXPIRED TIMER PACKETS                      *
*                                                                      *
***********************************************************************?
_$R-,G-,I-? 
_***********************************************************************
*                                                                      *
** OVERVIEW -  TICK IS ACTIVATED WITH A HARDWARE INTERRUPT WHENEVER    *
*              THE ADT CLOCK EXPIRES.  BY PLACING THE TIME OF THE      *
*              HEAD PACKET IN THE ADT CLOCK LIMIT WORD AT INITIALIZA-  *
*              TION AND EXIT FROM THE TICK ROUTINE THE TICK ROUTINE    *
*              WILL BE ACTIVATED ONLY WHEN THE HEAD PACKET HAS         *
*              EXPIRED.  THE TICK ROUTINE NOTIFIES THE USER ROUTINE    *
*              THAT HIS TIMER HAS EXPIRED WITH A WORK LIST ENTRY.      *
*              PERIODIC TIMERS ARE RESET AND PARTITION TABLE TIMERS    *
*              ARE PASSED TO THE ROUTINE UPDATE TO BE RESET.           *
*                                                                      *
** INPUT -     ADT CLOCK INTERRUPT                                     *
*                                                                      *
** CALLING PROGRAMS -                                                  *
*              NONE                                                    *
*                                                                      *
** OUTPUT -    WORK LIST ENTRY TO USER                                 *
*                                                                      *
** EXTERNAL SUBROUTINES -                                              *
*              PBLSPUT                                                 *
*              PBINSERT                                                *
*              PBCLKINT                                                *
*                                                                      *
***********************************************************************?
PROCEDURE PBTICK; 
  
CONST 
      T7TMRLVL    = RTCLK;                  _TIMER INTERRUPT LEVEL     ?
  
VAR 
      T7EXTIME    : B0OVERLAY;              _TOP ENTRY EXPIRATION TIME ?
      T7MIF       : BOOLEAN;                _MUX INTERRUPT FLAG        ?
      T7ENTRY     : B7PKTPTR;               _WORK PTR FOR SEARCHING    ?
      T7HSTIMR    : INTEGER;                _HALF SECOND TIMER COUNTER ?
  
BEGIN 
_ 
* * * *  INHIBIT INTERRUPTS DURING TEST AND DELINK TOP ENTRY, AND 
*        DURING TEST AND RESET OF CLOCK-LIMIT FOR NEXT PERIOD 
? 
IINT; 
T7EXTIME.BAINT := B7LSTHEAD'.BKEXTIME;      _GET TOP EXPIRATION TIME   ?
WHILE (T7EXTIME.BAINT -                     _PROCESS ENTRIES UP TO 2   ?
       CICLKADT.CICOUNT) < 3 DO             _ TICKS AWAY               ?
  BEGIN 
  B7LSTPTR := B7LSTHEAD;                    _GET CURR. LIST HEAD       ?
  WITH B7LSTPTR' DO 
    BEGIN 
    B7LSTHEAD           := BKFORLNK;        _UPDATE HEAD POINTER       ?
    B7LSTHEAD'.BKBAKLNK := NIL;             _ZERO LIST-HEAD BACK PTR   ?
    IF BKTIMRK                              _TEST FOR TIMER INTERV.MARK?
    THEN
_ 
* * * *  PUT EXPIRED TIMER INTERVAL MARKER AT END OF LIST 
? 
      BEGIN 
      T7EXTIME.BAINT := BKEXTIME +
                        B7TMINTVL * B7NPTNS;_COMPUTE NEW MARKER TIME   ?
      T7EXTIME.BASET := T7EXTIME.BASET -
                        [BIT0];             _FIX ONES-COMPLEMENT OVERFL?
      BKEXTIME       := T7EXTIME.BAINT;     _PUT NEW TIME IN PACKET    ?
_ 
* * * *  INSERT AT TAIL IF THIS ENTRY IS GE CURRENT LAST ENTRY
? 
      IF (B7LSTTAIL'.BKEXTIME - 
          T7EXTIME.BAINT) < 1               _IF NEW LAST-MARKER        ?
      THEN                                  _ IS GREATER/EQUAL THAN    ?
        BEGIN                               _ CURRENT TAIL             ?
        B7LSTTAIL'.BKFORLNK := B7LSTPTR;
        BKBAKLNK  := B7LSTTAIL; 
        BKFORLNK  := NIL; 
        B7LSTTAIL := B7LSTPTR;
        END _IF (B7LSTTAIL'.BKEXTIME - ..?
_ 
* * * *  NOT AT TAIL, SEARCH BACKWARDS UNTIL PLACEMENT IN LIST FOUND
? 
      ELSE
        BEGIN 
        T7ENTRY := B7LSTTAIL;               _SET PTR TO TAIL ENTRY     ?
        REPEAT                              _SEARCH BACKWARD UNTIL     ?
          T7ENTRY := T7ENTRY'.BKBAKLNK;     _ENTRY FOUND LE THAN       ?
        UNTIL (T7ENTRY'.BKEXTIME -          _NEW MARKER TO INSERT      ?
               T7EXTIME.BAINT) < 1; 
        BKFORLNK := T7ENTRY'.BKFORLNK;      _INSERT AFTER FOUND ONE    ?
        BKBAKLNK := T7ENTRY;
        BKFORLNK'.BKBAKLNK := B7LSTPTR; 
        T7ENTRY'.BKFORLNK  := B7LSTPTR; 
        END;
_ 
* * * *  BUMP TO MARKER INDEX, WRAP AROUND TO ZERO
? 
      B7TOPINDX := B7TOPINDX + 1;           _BUMP INDEX TO TOP MARKER  ?
      IF B7TOPINDX > B7ENDINDX
      THEN                                  _PASSED LAST MARKER        ?
        B7TOPINDX := 0;                     _RESET TO FIRST ONE        ?
      EINT;                                 _ENABLE INTERRUPT          ?
      END _IF BKTIMRK THEN? 
    ELSE
_ 
* * * *  NOT A MARKER, RE-INSERT IF PERIODIC, SEND WLE TO USER
? 
      BEGIN 
      BKACTIVE := FALSE;                    _SET INACTIVE              ?
      IF BKPERIODIC                         _IF PERIODIC TIMER PACKET  ?
      THEN                                  _ THEN CALL INSERT ROUTINE ?
        PBINSERT; 
      EINT;                                 _ENABLE INTERRUPT          ?
      IF BKWLINDX = B0TIWL                  _100 MILLISECOND TIMER     ?
      THEN
_ 
* * * *  100 MILLISECOND TIMER EXPIRED
? 
        BEGIN 
        PB100MS;                            _PERFORM 100 MS SERVICES   ?
        T7HSTIMR := T7HSTIMR + 1; 
        IF T7HSTIMR < 5 
        THEN                                _DONT SEND WL IF HALF      ?
          GOTO 10;                          _SECOND TIMER NOT EXPIRED  ?
_ 
* * * *  500 MILLISECOND TIMER EXPIRED
? 
        T7HSTIMR := 0;                      _RESTART HALF SECOND TIMER ?
*IF DEF,TUP 
        IF NOT (JUTUPTABLE.JUSHLTFLG !      _NOT IN SPECIAL TUP MODE   ?
                JUTUPTABLE.JUHLTFLG)
        THEN
*ENDIF
          WITH BTMONOWN DO
            BEGIN 
            BTTIMER := BTTIMER - 1; 
            IF BTTIMER = 0                  _IF COUNTER HAS ROLLED OVER?
            THEN                            _ THEN                     ?
              PBHALT(J0OPSTO);              _MONITOR HALT              ?
            END; _WITH BTMONOWN DO? 
        END;
_ 
* * * *  SEND WORKLIST ENTRY TO USER
? 
      WITH BWWLENTRY [T7TMRLVL].B0EWLQ DO   _INDEX TO INTERMEDIATE ARR.?
        BEGIN 
        MMWKCOD   := BKWKCODE;              _INSERT WORKCODE           ?
        MMWTCOUNT := BKUSRBYTE;             _BUILD A WORK LIST ENTRY   ?
        MMLINO    := BK1USRWRD;             _ FROM THE USERS FIELDS    ?
        MMIBP     := BK2UPTR; 
        END; _WITH BWWLENTRY [T7TMRLVL]..?
      PBLSPUT (BWWLENTRY [T7TMRLVL],
               BYWLCB [BKWLINDX]);
      IF BKWLINDX = MMEWLQ
      THEN                                  _SET MUX INTERRUPT FLAG    ?
        T7MIF := TRUE;
      END; _IF BKTIMRK ELSE?
    END; _WITH B7LSTPTR' DO?
  
10: 
  IINT;                                     _INHIBIT DURING NEXT TEST  ?
  T7EXTIME.BAINT := B7LSTHEAD'.BKEXTIME;    _GET NEXT TOP EXPIRATION   ?
  
  END; _WHILE T7EXTIME.BAINT - CICLKADT...? 
_ 
* * * *  RESET THE CLOCK LIMIT TO TOP ENTRY IN LIST 
? 
CICLKADT.CILIMIT := T7EXTIME.BAINT;         _RESET CLOCKS LIMIT        ?
PBCLKINT; 
EINT; 
_ 
* * * *  FORCE MUX-LEVEL INTERRUPT IF WLE SENT TO MUX-LEVEL 
? 
IF T7MIF                                    _IF AT LEAST ONE WORK LIST ?
THEN                                        _ ENTRY WAS TO MUX LEVEL   ?
  BEGIN 
  T7MIF := FALSE;                           _RESET MUX INTERRUPT FLAG  ?
  INST ($E400,N2P3INTAD,$0BA2);             _GENERATE A PSEUDO         ?
  END; _IF T7MIF? 
                                            _ INTERRUPT                ?
END; _PROCEDURE PBTICK? 
