PGM EDRIV
         REL
******************************************************
*                                                    *
*     DEVICE DRIVER FOR THE SIMPLE ETHERNET BOARDS.  *
*         (gigantic system version)                  *
*                                                    *
******************************************************
*
* DEVICE CONTROL BLOCK SYMBOLS
*
*            0                    DEVICE DRIVER PTR (BCPL)
*            0                    CODE LINK (=0)
D.ID     EQU 6                    ID
D.WKQ    EQU 8                    WORK QUEUE
D.START  EQU 10                   START ROUTINE (NOT USED)
D.STOP   EQU 14                   STOP ROUTINE (NOT USED)
D.CALL   EQU 18                   SUBROUTINE JUMP TO
D.INT    EQU 20                   OFFSET ADDRESS
D.I      EQU D.CALL+6             OFFSET USED IN INTERRUPT ROUTINE
D.VEC    EQU 24                   VECTOR NUMBER
D.TXPKT  EQU 26                   BCPL ADDRESS OF TX TRIPOS PKT
D.RXPKT  EQU 28                   BCPL ADDRESS OF RX TRIPOS PKT
*
* PACKET SYMBOLS
*
P.ID     EQU 2                    TASK OR DEVICE ID
P.RES1   EQU 6                    FIRST RESULT
*
* PARALLEL I/O PORT ADDRESSES
*
CONTROL  EQU #CE                  CONTROL & SET/RESET PORT C BITS
PORTC    EQU #CC
PORTA    EQU #C8
PORTB    EQU #CA                  OUTPUT
*
* STATUS BIT MASKS FOR M.S. 4 BITS OF PORT C
*
TXACKED  EQU #10                  TRANSMITTED BLOCK WAS ACKED
CONTENT  EQU #20                  CONTENTION WAS DETECTED
TXENDED  EQU #40                  BLOCK TRANSMIT COMPLETE
RXENDED  EQU #80                  BLOCK RECEIVE COMPLETE
RXACKED  EQU RXENDED
*
* PORTC L.S. BIT POSITIONS
*
RESETB   EQU 2*2+1
STROBE   EQU 3*2+1                STROBE CONTROL INFO FROM DATA LINES
*
* CONTROL WORDS
*
RESRXEND EQU #5F                  RESET RECEIVE ENDED
*
ERRVEC   EQU #3FC
MPICMSK  EQU #C2
* THE ROOTNODE
*
CRNTSK   EQU #506
DEVMVP   EQU #51A                 MOVPKT
DEVINT   EQU #51E                 INTENT
DEVRET   EQU #522                 INTRET
*
         DW EINITI
         DW EUNINI
*
* INITIALIZATION ROUTINE. SETS UP DCB, MC ADDRESS IN BX.
*
EINIT    MOV SI,!EINT             CALCULATE OFFSET FOR DCB CALL
         MOV D.INT(BX),SI         PUT IN DCB
         MOV D.INT+2(BX),CS       correct code seg in DCB
         XOR SI,SI
         MOV D.TXPKT(BX),SI       CLEAR DCB LOCATIONS
         MOV D.RXPKT(BX),SI
         MOV SI,!40*4             OFFSET IN TABLE FOR TXINT
         MOV (SI),BX              PLUG INTERRUPT VECTOR
         ADD (SI),!D.CALL
         MOV 2(SI),!0             CS := 0 FOR INTERRUPT
         MOV SI,!42*4             FOR RX INT
         MOV (SI),BX
         ADD (SI),!D.CALL
         MOV 2(SI),!0             CS := 0 FOR INTERRUPT
*
         MOV AL,!#98
         OUT CONTROL              INIT PPI
* MAKE PORT C ALL 0S
         XOR AL,AL
         OUT PORTC
* RESET ETHERNET BOARD
         MOV AL,!RESETB
         OUT CONTROL
         DEC AL
         OUT CONTROL
         MOV AL,!RESRXEND
         OUT PORTB
         MOV AL,!STROBE
         OUT CONTROL
         DEC AL
         OUT CONTROL
* ENABLE INTERRUPTS
         IN MPICMSK               GET CURRENT BITS
         AND AL,!#FA              CLEAR OUR BITS
         OUT MPICMSK              SET IT UP
*
         RETS
*
* UNINITIALIZATION. ADDRESS OF DCB IN BX.
*
EUNIN    PUSH AX
         MOV SI,!40*4
         MOV AX,ERRVEC
         MOV (SI),AX
         MOV AX,ERRVEC+2
         MOV 2(SI),AX
         MOV SI,!42*4
         MOV AX,ERRVEC
         MOV (SI),AX
         MOV AX,ERRVEC+2
         MOV 2(SI),AX
* DISABLE INTERRUPT
         IN MPICMSK
         OR AL,!5
         OUT MPICMSK
         POP AX
         RETS
*
* INTERRUPT ROUTINE ENTERED WHEN A TX OR RX ENDED INTERRUPT OCCURS.
* THE DCB ADDRESS MAY BE FOUND FROM THE SUBROUTINE RETURN ADDRESS
* ON THE MC STACK.
* WHEN EINTR IS REACHED CX SHOULD ONLY BE ZERO IF A TASK CHANGE IS NEEDED.
*
EINT     PUSH BX                  SAVE REGISTERS
         PUSH AX
         PUSH CX
         PUSH DX
         PUSH SI
         MOV BX,SP
         MOV BX,10(BX)            GET ADDRESS OFFSET 10 IN DCB
*    WHY DID IT INTERRUPT?
*    EXAMINE STATUS
         XOR CX,CX
         NOT CX                   MAKE CX NON-ZERO
         IN PORTC                 GET STATUS IN AL
         TEST AL,!RXENDED
         JNE ETRTX                NOT RX, GO SEE IF TX
* HANDLE RECEIVE ENDED INTERRUPT
         MOV SI,D.RXPKT-D.I(BX)   GET TRIPOS PKT
         SHL SI
         JE ETRTX                 IF NO PKT WAITING !!!
* SEE IF WE ACKED THE BLOCK (I.E. IT WAS OK)
         MOV AL,!RESRXEND
         OUT PORTB                SET UP CONTROL WORD
         MOV AL,!STROBE
         OUT CONTROL              STROBE TO RESET RX ENDED STATUS
         DEC AL
         OUT CONTROL              RESET STROBE
* NOW READ SAME BIT WHICH WILL BE ACTIVE IF WE ACKED
         IN PORTC
         XOR CX,CX                CX HOLDS 'RETURN CODE'
         TEST AL,!RXACKED
         JE ERXA                  YES, WAS ACKED
         NOT CX                   SET RESULT NON-ZERO FOR FAILURE
ERXA     MOV P.RES1(SI),CX        SET RESULT
         MOV D.RXPKT-D.I(BX),!0   CLEAR DCB LOCATION
         CALL EMPKT               MOVE PKT BACK TO TASK
         MOV DX,AX                SAVE NEW TCB PTR
         IN PORTC
ETRTX    TEST AL,!TXENDED         TX ENDED?
         JNE EINTR                NO TX ENDED
*
* HANDLE TRANSMIT ENDED INTERRUPT
         MOV SI,D.TXPKT-D.I(BX)
         SHL SI
         JE EINTR                 NO PKT WAITING !!!
* SEE IF THERE WAS CONTENTION AND WHETHER BLOCK WAS ACKED
*
         XOR CX,CX                RESULT
         TEST AL,!CONTENT
         JNE ETRTXA
         INC CX
         NOT CX                   RETURN -2 FOR CONTENTION
         B ETXA
ETRTXA   MOV CX,!16
ETRLP    LOOP ETRLP
         IN PORTC
         TEST AL,!TXACKED
         JE ETXA                  YES, WAS ACKED
         NOT CX                   -1 -> NO ACK RECEIVED
ETXA     MOV P.RES1(SI),CX        SET RESULT IN PKT
         MOV D.TXPKT-D.I(BX),!0
         CALL EMPKT               MOVE BACK TO TASK
         MOV DX,AX                SAVE NEW TCB PTR
EINTR    OR CX,CX                 TASK SWAP NEEDED
         JE EINTW                 YES
         JIS DEVRET               NO, RETURN QUICKLY
EINTW    MOV AX,DX                GET NEW TCB PTR
         JIS DEVINT               RETURN FOR TASK SWAP
* MOVE PKT BACK TO TASK USING MOVPKT
*
EMPKT    MOV CX,D.ID-D.I(BX)
         PUSH BX        SAVE DCB PTR
         MOV BX,CRNTSK
         SHL BX
         CIS DEVMVP
         POP BX
         RET
*
*
         EVEN
         DSEG
         EVEN
EINITI   DW EINIT
         DW 0
EUNINI   DW EUNIN
         DW 0
         END