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