PGM    VMIDRIV
         REL
************************************************************
*                                                          *
* Device driver for the Logica VTS VMI-1 intelligent       *
* multibus ring (Polynet) interface.                       *
*                                                          *
************************************************************
MPICMSK  EQU    #C2
V.DEMPTY EQU    #40
ERRVEC   EQU    #3FC
VMICTRL  EQU    #50
VMIDATA  EQU    #51
*
* Pkt types
*
A.TELL   EQU    979
A.AHA    EQU    978
A.INIT   EQU    977
A.CLEAR  EQU    976
*
* DCB symbols
*
*               0               device driver ptr (BCPL)
*               2               link to code (=0)
*               4
D.ID    EQU     6               id
D.WKQ   EQU     8               work q
D.START EQU     10              start rtn for qpkt
D.STOP  EQU     14
D.CALL  EQU     18
D.INT   EQU     20
D.I     EQU     D.CALL+6
D.VEC   EQU     24
*
* Pkt sumbols
P.ID    EQU     2
P.TYPE  EQU     4
P.RES1  EQU     6
P.RES2  EQU     8
P.A1    EQU     10
P.A2    EQU     12
*
* The Rootnode
*
CRNTSK  EQU     #506
DEVMVP  EQU     #51A
DEVINT  EQU     #51E
DEVRET  EQU     #522
*
         DW     VMINITI         init. routine
         DW     VMUNINI         unin. routine
*
* Initialisation routine,
*  entry: BX = MC DCB address
*  preserve: DX,DI,BP
VMINIT   MOV    D.START(BX),!VMISTART
         MOV    D.STOP(BX),!VMISTOP
         MOV    D.START+2(BX),CS
         MOV    D.STOP+2(BX),CS
*
         MOV    D.INT(BX),!VMINT        CALLS offset
         MOV    D.INT+2(BX),CS
         MOV    SI,D.VEC(BX)            interrupt vector no.
         ADD    SI,!40
         SHL    SI
         SHL    SI
         MOV    (SI),BX         plug int. vec. with CALLS address
         ADD    (SI),!D.CALL
         MOV    2(SI),!0
         RETS
*
* Uninitialisation,
*  entry: BX = MC DCB address
*  preserve: BX
VMUNIN  MOV     SI,D.VEC(BX)    int. vec no.
*   disable interrupts
         MOV    CX,SI
         MOV    DL,!1
         SHL    DL,CL
         IN     MPICMSK
         OR     AL,DL
         OUT    MPICMSK
*
         ADD    SI,!40
         SHL    SI
         SHL    SI
         MOV    AX,ERRVEC
         MOV    (SI),AX
         MOV    AX,ERRVEC+2
         MOV    2(SI),AX
         RETS
*
* Start routine,
*  entry: BX = MC DCB address
*         SI = BCPL pkt address
*  return: non-zero
*  preserve: BP,DI
*
VMISTART SHL    SI              MC pkt addr
         MOV    D.WKQ(BX),!0    clear work q
         MOV    AX,P.TYPE(SI)
         CMP    AX,!A.CLEAR
         JNE    VMI0
*   clear interrupt by reading control port
         IN     VMICTRL
         JMP    RPKT
*
VMI0     CMP    AX,!A.TELL
         JNE    VMI1
*   interrupt the VMI-1
         OUT    VMIDATA
         JMP    RPKT
*
VMI1     CMP    AX,!A.AHA
         JNE    VMI2
*   pkt to pick up signal from VMI-1,
*   is there one pending?
         CMP    PENDFLG,!0
         JE     VMI10           not pending
*   is one, return pkt
         MOV    PENDFLG,!0      clear flag
         JMP    RPKT
*
VMI10    MOV    AHAPKT,SI       save MC pkt addr (only one)
         RETS
*
VMI2     CMP    AX,!A.INIT
         JE     VMI3
         JMP    RPKT            return junk pkt
*   perform initialisation, arg1 is byte offset of shared memory
VMI3     OUT    VMICTRL         reset the b****r
*   write the start address
         MOV    AX,P.A1(SI)
         CALL   SVMI            writes AL
         MOV    AX,P.A1(SI)
         MOV    AL,AH
         CALL SVMI
         XOR    AL,AL
         CALL   SVMI
         CALL   SVMI
*
         MOV    AHAPKT,!0
         MOV    PENDFLG,!0
         MOV    P.RES1(SI),!0   result is 0
         MOV    CL,D.VEC(BX)
*   enable ints.
         MOV    DL,!1
         SHL    DL,CL
         NOT    DL
         IN     MPICMSK
         AND    AL,DL
         OUT    MPICMSK
*
* return pkt to sender
RPKT     MOV    CX,D.ID(BX)
         MOV    BX,CRNTSK
         SHL    BX
         JIS    DEVMVP          & return from this routine
*
* Stop
*
VMISTOP  RETS
*
* Interrupt service,
*  return aha pkt or set flag.
VMINT    PUSH   BX
         PUSH   AX
         PUSH   CX
         PUSH   DX
         PUSH   SI
         MOV    BX,SP
         MOV    BX,10(BX)       get old IP pointing into DCB
*
         MOV    SI,AHAPKT
         OR     SI,SI           exists ahapkt?
         JE     VMINA           no
*   return aha pkt
         MOV    AHAPKT,!0
         MOV    PENDFLG,!0
         MOV    CX,D.ID-D.I(BX)
         MOV    BX,CRNTSK
         SHL    BX
         CIS    DEVMVP
         JIS    DEVINT
*   set pending flag
VMINA    MOV    PENDFLG,!1
         JIS    DEVRET          quick return
*
* Svmi routine sends init. data to VMI-1 from AL.
SVMI     MOV    AH,AL           save
S0       IN     VMICTRL
         TEST   AL,!V.DEMPTY
         JE     S0              not ready
         MOV    AL,AH
         OUT    VMIDATA         write
         RET
*
         EVEN
         DSEG
VMINITI  DW     VMINIT
         DW     0
VMUNINI  DW     VMUNIN
         DW     0
*
PENDFLG  DW     0
AHAPKT   DW     0
*
         END