PGM EMCSEG
REL
***********************************************************
* *
* ASSEMBLER ROUTINES USED BY THE LAN HANDLER *
* (Version to interpret port number.) *
* *
***********************************************************
EMCS DW EMCEND-EMCS/2 LENGTH
DW SECWORD
DB 17,"EMCSEG 26-Nov-80"
*
******************************************************
* *
* ETXBUFF(DESC, TXPKT) *
* *
* SUBROUTINE TO FILL TRANSMIT FIFO AND GO *
* *
******************************************************
DB 7,"ETXBUFF"
ETXBUFF ADD BP,DX STD BCPL ENTRY
MOV 4(BP),DX
POP (BP)
POP 2(BP)
MOV 6(BP),SI
MOV 8(BP),BX SAVE ARGUMENTS
MOV 10(BP),AX
*
SHL BX GET MC ADDRESS OF DESCRIPTOR
MOV SI,2(BX) DATA ADDRESS
SHL SI
MOV 14(BP),SI
MOV BX,(BX) HEADER ADDRESS
SHL BX
MOV 12(BP),BX
MOV CX,!3 3 BYTES OF TYPE 1 PREAMBLE
ETXBLP MOV AL,!PREAMBL1 FIRST LOAD PREAMBLE BYTE
CALL ETXPUSH
LOOP ETXBLP
MOV AL,!PREAMBL2
CALL ETXPUSH
ADD BX,!BLOCKOFF
MOV SI,!7
XOR DX,DX RESIDUE
CALL CALCCRC CALCULATE CRC AND PUT IN AX
MOV BX,14(BP)
MOV SI,12(BP)
MOV CX,E.LEN(SI)
XCHG CH,CL
AND CH,!#7F
MOV SI,CX
MOV DX,AX
CALL CALCCRC
MOV SI,AX SAVE CRC
MOV BX,12(BP)
MOV DX,E.LEN(BX) GET LENGTH
XCHG DH,DL -> INTEL CONVENTION
AND DH,!#7F REMOVE POSSIBLE CONTROL BIT
ADD BX,!BLOCKOFF TRUE START OF BLOCK
*
MOV CX,!HEADSIZE
* LOOP FOR LOADING BLOCK
ETXBLK MOV AL,(BX)
CALL ETXPUSH
INC BX
LOOP ETXBLK
*
OR DX,DX
JLE ETXBLK3 MAY BE 0
MOV CX,DX LENGTH OF DATA PART
MOV BX,14(BP)
ETXBLK2 MOV AL,(BX)
CALL ETXPUSH
INC BX
LOOP ETXBLK2
* LOAD CRC
ETXBLK3 MOV AX,SI
CALL ETXPUSH
MOV AL,AH
CALL ETXPUSH
*
* DISABLE INTERRUPTS FOR CRITICAL SECTION
CLI
MOV SI,G.EDCB(DI)
SHL SI
MOV AX,10(BP) PKT FOR DCB
MOV D.TXPKT(SI),AX
* SET OK TO TRANSMIT
MOV CX,!16
ETXBLP2 LOOP ETXBLP2
MOV AL,!OKTOTX
OUT PORTB
MOV AL,!STROBE
OUT CONTROL THIS IS THE WAY WE STROBE
DEC AL
OUT CONTROL
STI ENABLE INTERRUPTS
* RETURN
MOV SI,4(BP)
SUB BP,SI
JIS (BP,SI)
*
* ETXPUSH ROUTINE CALLED BY ETXBUFF TO LOAD 1 BYTE INTO TRANSMIT
* FIFO. BX,SI,AH AND CX MUST BE PRESERVED. BYTE IS IN AL.
*
ETXPUSH OUT PORTB PUT BYTE ON DATA LINES
MOV AL,!ISTROBE
OUT CONTROL
DEC AL
OUT CONTROL
RET
*******************************************************
* *
* OKTORX(RXPKT) *
* *
* STROBES THE OKTORX CONTROL LINE ON THE CONTROLLER *
* AND SETS RXPKT FIELD IN DCB (WE MUST DISABLE *
* INTERRUPTS) *
* *
*******************************************************
DW LIBWORD
DB 7,"OKTORX"
OKRX CLI
MOV SI,G.EDCB(DI)
SHL SI
MOV D.RXPKT(SI),BX SET FIELD IN DCB
MOV AL,!OKTORX
OUT PORTB
MOV AL,!STROBE
OUT CONTROL
DEC AL
OUT CONTROL
STI
RETS
*
************************************************
* *
* LANRESET() *
* *
* SUBROUTINE TO RESET ETHERNET BOARD *
* *
************************************************
DW LIBWORD
DB 7,"LANRESE"
LANRESET XOR AL,AL
OUT PORTC SET CONTROL LINES INACTIVE
MOV AL,!RESETB
OUT PORTB
MOV AL,!STROBE
OUT CONTROL
DEC AL
OUT CONTROL
RETS
*
************************************************
* *
* ERXBUFF(RXPKTQ) *
* *
* SUBROUTINE TO READ A BLOCK FROM THE RECEIVE *
* FIFO, THIS ASSUMES SOMETHING HAS BEEN *
* RECEIVED. *
* *
* The queue of receive buffers is checked *
* to see if there are any reads outstanding *
* on this port. *
************************************************
DB 7,"ERXBUFF"
ERXBUFF ADD BP,DX STD BCPL ENTRY
MOV 4(BP),DX
POP (BP)
POP 2(BP)
MOV 6(BP),SI
MOV 8(BP),BX Save argument
*
MOV BX,!THEAD Read header into here
MOV 10(BP),BX
INC BX start of block + 1 (no dest.)
MOV CX,!HEADSIZE-1
CALL ERXRD READ THE HEADER
MOV -7(BX),!NODAD[B] PUT OUR ADDRESS AS DEST!
MOV AX,-6(BX)
AND AH,!#F0 Get bits of port number
* any requests outstanding for this port?
* look down list of waiting packets.
MOV SI,8(BP) head of rxpktq
NXRP SHL SI
JNE ERXQ end of list?
XOR BX,BX yes, return 0
B ERXB2
*
ERXQ MOV BX,P.ARG1(SI) get address of header part
SHL BX
MOV BX,E.P1(BX) dest. port (swapped bytes)
AND BH,!#F0
CMP AX,BX
JE FERP found port
MOV SI,(SI)
JMP NXRP try next
*
FERP MOV CX,!7 now copy header
MOV 12(BP),SI save pkt
MOV BX,P.ARG1(SI)
SHL BX
MOV SI,10(BP)
FERP2 MOV DL,(SI)
MOV BLOCKOFF(BX),DL
INC SI
INC BX
LOOP FERP2
*
MOV CX,-2(SI) GET LENGTH INFO
XCHG CH,CL -> INTEL CONVENTION
AND CX,!#7FFF REMOVE ANY CONTROL BIT
JE ERXBA2 COUNT=0
*************************************************
*************************************************
*************************************************
CMP CX,!#120
JBE ERXBA1
MOV CX,!#1234 ABORT!!!!!!!!!
INT 34 !!!!!!!!!!!!!!
ERXBA1 EQU $
*************************************************
*************************************************
*************************************************
MOV BX,12(BP) get address of data part
MOV BX,P.ARG2(BX)
SHL BX
CALL ERXRD READ REST OF BLOCK
ERXBA2 MOV BX,12(BP)
SHR BX
* RETURN
ERXB2 MOV SI,4(BP)
SUB BP,SI
JIS (BP,SI)
*
* ROUTINE USED BY ERXBUFF TO READ CX BYTES FROM BLOCK
* STARTING AT ADDRESS IN BX, WHICH REGISTER IS CHANGED.
*
ERXRD EQU $
ERXRD2 MOV AL,!OSTROBE SET UP FOR INPUT STROBE
OUT CONTROL
DEC AL
DEC AL
DEC AL
INC AL
INC AL
OUT CONTROL
IN PORTA READ BYTE
MOV (BX),AL STUFF INTO BLOCK
INC BX BUMP POINTER INTO BLOCK
LOOP ERXRD2
*
RET
*
*
* THIS SUBROUTINE WILL CALCULATE THE CRC ON A BLOCK TO BE
* TRANSMITTED ON THE LOCAL AREA NETWORK.
* ON ENTRY BX CONTAINS THE MC ADDRESS OF THE START OF THE BLOCK.
* SI = LENGTH IN BYTES
* DX = RESIDUE FROM ANY PREVIOUS PART OF BLOCK
* RETURN WITH NEW RESIDUE IN AX
* THIS NEED NOT BE PRESERVED.
*
* THE POLYNOMIAL USED IS X**16 + X**15 + X**2 + 1,
* THE SAME AS THAT USED
* BY THE MOTOROLA CRC CHIPS AND ALSO THE SAME AS THE STANDARD
* IBM BISYNC POLYNOMIAL.
*
* First, SI is set to the number of words in the block, ignoring
* any odd byte. CX is set if there is an odd number of bytes.
*
CALCCRC XOR CX,CX
SHR SI make word count
RCR CX CX := non-zero if carry is set
MOV AX,DX
* step through words calculating residue term by term.
* get message word
CC0 DEC SI
JL CC33
MOV AX,(BX)
XOR AX,DX
MOV DX,AX save message+residue
*
* 1st term
*
SHR AX *x
XOR AX,DX +N
SHR AX *x
*
* 2nd term
*
* if lsb of N = 0 then -> 0 else -> #X5000
*
TEST DX,!1
JE CC1
XOR AX,!#5000 add to 1st term
*
* 3rd term
*
* if bit 1 = 0 -> 0 else -> #XA001
*
CC1 TEST DX,!2
JE CC2
XOR AX,!#A001
*
* 4th term, if even parity -> 0 else -> #XC001
*
*
CC2 XOR DL,DH (FOR PARITY MUST BE IN 8-BIT REGISTER)
JPE CC3 jump on parity even
XOR AX,!#C001
* see if finished all complete words
CC3 MOV DX,AX NEW RESIDUE TO DX
INC BX
INC BX
JMP CC0
* finished words, see if odd byte
CC33 JCXZ CC4 no , cx=0
* do calculation for odd byte
*
* 1st term
*
XOR AL,AL
XCHG AH,AL shift low part of residue by 8
*
* 2nd term
*
MOV CX,DX get residue
XOR CH,CH leave only high part of residue
XOR CL,(BX) +message
XCHG CH,CL CHANGE SIGNIFICANCE
MOV SI,CX
SHR CX
XOR CX,SI
SHR CX
XOR AX,CX +first term
*
* 3rd term
*
MOV CL,DL get upper part of residue
XOR CL,(BX) +message
JPE CC5 jump if parity even
XOR AX,!#C001
CC5 INC BX
*
*
* return with BX changed
CC4 RET
*
*
*
* GLOBAL INITIALIZATION
*
EVEN
DW 0
DW G.OKRX/2
DW OKRXI-EMCS
DW G.LANR/2
DW LANRESEI-EMCS
DW G.ETXB/2
DW ETXBUFFI-EMCS
DW G.ERXB/2
DW ERXBUFFI-EMCS
DW G.OKRX/2
*
EMCEND EQU $
*
*
UG EQU 150
SECWORD EQU 12345
LIBWORD EQU 23456
G.ETXB EQU UG*2
G.ERXB EQU UG+1*2
G.LANR EQU UG+2*2
G.OKRX EQU UG+3*2
G.EDCB EQU UG+13*2
D.RXPKT EQU 28
D.TXPKT EQU 26
PREAMBL1 EQU #AA
PREAMBL2 EQU #2A
HEADSIZE EQU 7
BLOCKOFF EQU 16
E.P1 EQU BLOCKOFF+1
E.P2 EQU BLOCKOFF+2
P.ARG1 EQU 10
P.ARG2 EQU 12
E.LEN EQU BLOCKOFF+5
*
*
PORTA EQU #C8
PORTB EQU #CA
PORTC EQU #CC
CONTROL EQU #CE
*
*
OKTOTX EQU #FF
OKTORX EQU #9F
RESRXEND EQU #5F
*
*
ISTROBE EQU 0*2+1
OSTROBE EQU 1*2+1
RESETB EQU 2*2+1
STROBE EQU 3*2+1
*
NODAD EQU 1
*
EVEN
DSEG
EVEN
DEMCS DW DEMCSEND-DEMCS/2
OKRXI DW OKRX
DW 0
LANRESEI DW LANRESET
DW 0
ETXBUFFI DW ETXBUFF
DW 0
ERXBUFFI DW ERXBUFF
DW 0
THEAD RES 10,0 2 EXTRA FOR 'SAFETY' (!)
DEMCSEND EQU $
END