.TITLE MOSETH - MOS ETHERNET DRIVER ; THE LOSERS OUT AT PARC MADE THIS THING (UNLIKE ALL OTHER PDP-11 ; COMMUNICATION EQUIPMENT WITH THE EXCEPTION OF THE ALSO LOSING ; IMP-11A'S) SEND THE HIGH ORDER BYTE FIRST. ; THUS YOU USUALLY HAVE TO SWAB THE WHOLE PACKET FIRST. LOSERS. ; FINALLY, THE KLUDGE WAY OF DOING COLLISIONS (WITH A SEPARATE ; INTERRUPT VECTOR) REQUIRES THAT THE DEVICE USES UP 5 WORDS ; IN INTERRUPT VECTOR SPACE. CAVEAT HAQUUR. ; FINALLY, THE INPUT COUNT IS ACTUALLY A ONE'S COMPLEMENT ; COUNT, NOT A TWO'S COMPLEMENT AS PROMISED BY THE DOCUMENTATION. ; ; MODIFIED: ; 14 May 1983 Bob Baldwin MIT ; - added bounds checking on buffer and iorb ; 2 June 1983 Bob Baldwin MIT ; - bug fix in ETHCIN r1 should be used instead of r0 ; 9 June 1983 Jeffrey Mogul Stanford ; - changed ETHCIN to do "binary exponential backoff" ; 14 June 1983 Bob Baldwin MIT ; - ETHMSK moved to DCTDV2 to allow multiple ethernet interfaces. ; - ETHADDR moved to DCTDV1 for same reason. ; - DCTDV3 counts number of collisions since last device init. ; - Note that these fields are only in the output DCT. ; 25 June 1983 Bob Baldwin MIT ; - Make .ETHOT properly fill in source addr, reduced # of instructions. ; DEFINE THE FOLLOWING THING NON-ZERO TO GET THE BUSY WAITING VERSION NOINT = 0 .INSRT ../moscnf-1.sml .INSRT ../mosmac.sml .INSRT ../mostbl.sml .ENABL ISD $CNFIG $DFDCT $DFIOR $DFIST .GLOBL .ETHII ;NET I/P INITIALIZE ROUTINE .GLOBL .ETHOI ;NET O/P INITIALIZE ROUTINE .GLOBL .ETHIT ;NET INPUT TRANSFER ROUTINE .GLOBL ETHICM ;** HACK FOR PATCHING .GLOBL .ETHOT ;NET OUTPUT TRANSFER ROUTINE .GLOBL ETHOCM ;** HACK FOR PATCHING .GLOBL ETHIIN ;NET I/P INTERRUPT ROUTINE .GLOBL ETHOIN ;NET O/P INTERRUPT ROUTINE .GLOBL ETHCIN ;NET O/P COLLISION INTERRUPT .GLOBL $IOCMP ;I/O COMPLETION EXIT .GLOBL $METTP,$METBT ;CODE SPACE TOP/BOTTOM .GLOBL $TOD ;USED FOR RETRY RANDOMNESS .GLOBL $LOMEM ;START OF DATA STORAGE AREA .CSECT MOS .SBTTL ETHERNET INTERFACE REGISTER ASSIGNMENTS ; ; ETTWC = 0 ;TRANSMIT WORD COUNT REG ETTBUF = 2 ;TRANSMIT BUFFER ADDR REG ETTCSR = 4 ;TRNASMIT COMMAND AND STATUS REG ETOSD = 6 ;OUTPUT START DELAY ETRWC = 0 ;RECEIVE WORD COUNT REG ETRBUF = 2 ;RECEIVE BUFFER ADDR REG ETRCSR = 4 ;RECEIVE COMMAND AND STATUS REG ETHAR = 6 ;HOST ADDRESS REG ; COMMAND STATUS REG BITS ET.TENB = 1 ;TRANSMITTER ENABLE ET.UN1 = 76 ;UNUSED ET.TIE = 100 ;TRANSMIT DONE INTERRUPT ENABLE ET.TDN = 200 ;TRANSMIT DONE ET.UN2 = 77400 ET.TERR = 100000 ;ERROR (COLLISION, UNDERRUN) ET.RENB = 1 ;RECEIVER ENABLE ET.RALL = 2 ;RECEIVE ALL PACKETS ET.UN3 = 74 ET.RIE = 100 ;RECEIVE DONE INTERRUPT ENABLE ET.RDN = 200 ;RECEIVE DONE ET.UN4 = 77400 ET.RERR = 100000 ;ERROR (OVERRUN, OVERFLOW, CRC) ; COUNTER BITS ET.TWC = 1777 ;TRANSMIT WORD COUNTER ET.ODC = 377 ;OUTPUT DELAY COUNTER ET.RWC = 1777 ;RECEIVE WORD COUNTER ET.HA = 377 ;HOST ADDRESS REG .PAGE .SBTTL SOME ETHER CONSTANTS ETHHL = 4 ;HEADER LENGTH IN BYTES ETHRMX = 3776 ;MAX PKT SIZE IN BYTES - CRC WRD COUNTS ETHTMX = 4000 ;FOR TRANSMIT IT DOESN'T ETHSAL = 0 ;HARDWARE SOURCE ADDRESS LOC VECSZ = 4 ;NUMBER OF BYTES IN AN INTERRUPT VECTOR ECMSK = 177777 ;Initial mask; # of bits set is ; # of retries allowed. ETHCIV = 10 ;OFFSET OF COLLISION INT VECT .PAGE .SBTTL ETHER INTERFACE INITIALIZATION ROUTINES ; ; CALLED WITH: R2 - ADDRESS OF DCT ; $METTP: .ETHII: $PUSH R0,R1 MOV R2,R0 ; SET UP MY INT VECT ADD #DCTIHX,R0 ; CALCULATE LINKAGE TO INT ROUTINE MOV DCTIVA(R2),R1 ; GET VECTOR LOCATION MOV R0,(R1)+ ; STORE AWAY MOV #340,(R1)+ BIC #DF.OFL,DCTFLG(R2) ; MARK DEVICE AS INITIALIZED MOV DCTCSR(R2),R0 ; STORE OUR HOST NUMBER MOV ETHAR(R0),R0 ; GET ADDRESS COM R0 ; TURN INTO HUMAN READABLE FORM BIC #-ET.HA-1,R0 MOV R2,R1 ; SAVE PTR IN CASE OUTPUT NEEDS INIT MOV DCTLNK(R2),R2 ; Switch to output DCT MOVB R0,DCTDV1(R2) ; Save net address BIT #DF.OFL,DCTFLG(R2) ; IS OUTPUT INIT'ED? BEQ 1$ JSR PC,.ETHOI ; IF NOT, DO IT 1$: MOV R1,R2 $POP R1,R0 RTS PC ; RETURN .ETHOI: $PUSH R0,R1 CLR DCTDV3(R2) ; Zero collision counter MOV R2,R0 ; SET UP MY INT VECT ADD #DCTIHX,R0 ; CALCULATE LINKAGE TO INT ROUTINE MOV DCTIVA(R2),R1 ; GET VECTOR LOCATION MOV R0,(R1)+ ; STORE AWAY MOV #340,(R1)+ MOV DCTIVA(R2),R0 ; SET UP COLLSION VECTOR ADD #ETHCIV,R0 ; MAKE COLLISION INTERRUPT MOV R0,(R0) ADD #VECSZ,(R0)+ ; GO TO LOC AFTER VECTOR MOV #340,(R0)+ MOV COLINS,(R0)+ ; TOTALLY SICK AND DISGUSTING KLUDGE MOV #ETHCIN,(R0)+ ; TO GET DCT POINTER TO COLL ROUTINE MOV R2,(R0)+ ; STORE POINTER TO DCT BIC #DF.OFL,DCTFLG(R2) $PUSH R2 ; GO INITIALIZE OTHER HALF MOV DCTLNK(R2),R2 BIT #DF.OFL,DCTFLG(R2) ; ALREADY DONE? BEQ 1$ JSR PC,.ETHII ; NO, GO DO HIM 1$: $POP R2,R1,R0 RTS PC .PAGE .SBTTL ETHER INPUT TRANSFER INITIALIZATION ROUTNE ; ; CALLED WITH: R2 - POINTER TO DEVICE CONTROL TABLE (DCT) ; .ETHIT: $PUSH R0,R1 MOV DCTBR(R2),R0 CMP R0,#ETHHL ; LONG ENOUGH? BLT 1$ CMP R0,#ETHRMX ; TOO LONG? BGT 1$ BIT #1,R0 ; WORD XFER? BNE 1$ ; BIT #1,DCTUVA(R2) ; WORD ADDRESS? ; BEQ 2$ MOV DCTUVA(R2),R1 ; CHECK THE BUFFER ADDRESS BIT #1,R1 ; FOR BEING ODD BNE 1$ ; BRANCH TO ERROR IF ODD CMP R1, $LOMEM ; FOR BEING IN CODE SEGMENT BGT 2$ ; BRANCH IF OK 1$: BUGHLT 2$: ASR R0 COM R0 ; CONVERT TO ONE'S COMP (HDW BUG) MOV DCTCSR(R2),R1 ; GET ADDRESS OF DEVICE MOV DCTUVA(R2),ETRBUF(R1) ; SET BUFFER ADDRESS MOV R0,ETRWC(R1) ; AND COUNT ETHICM: .IF NE, NOINT BIS #ET.RENB,ETRCSR(R1) .IFF BIS #ET.RENB!ET.RIE,ETRCSR(R1) .ENDC BIS #DF.ACT,DCTFLG(R2) ; MARK AS ACTIVE $POP R1,R0 ; AND GO RTS PC .PAGE .SBTTL ETHER OUTPUT TRANSFER INITIALIZATION ROUTINE ; ; CALLED WITH: R2 - POINTER TO DEVICE CONTROL TABLE (DCT) ; .ETHOT: $PUSH R0,R1 MOV DCTBR(R2),R0 CMP R0,#ETHHL ; LONG ENOUGH? BLT 1$ CMP R0,#ETHTMX ; TOO LONG? BGT 1$ BIT #1,R0 ; WORD XFER? BNE 1$ MOV DCTUVA(R2),R1 ; CHECK THE BUFFER ADDRESS BIT #1,R1 ; FOR BEING ODD BNE 1$ ; BRANCH TO ERROR IF ODD CMP R1, $LOMEM ; FOR BEING IN CODE SEGMENT BGT 2$ ; BRANCH IF OK 1$: BUGHLT 2$: ASR R0 ; CONVERT TO WORDS NEG R0 ; CONVERT TO TWO'S COMP $PUSH R0 MOVB DCTDV1(R2),ETHSAL(R1) ; put source address in packet MOV #ECMSK,DCTDV2(R2) ; Set initial mask MOV DCTCSR(R2),R0 ; GET ADDRESS OF DEVICE $POP ETTWC(R0) ; SET WORD COUNT MOV R1,ETTBUF(R0) ; SET BUFFER ADDRESS CLR ETOSD(R0) ; CLEAR DELAY ETHOCM: .IF NE, NOINT BIS #ET.TENB,ETTCSR(R0) ; START THE TRANSFER .IFF BIS #ET.TENB!ET.TIE,ETTCSR(R0) ; START THE TRANSFER .ENDC BIS #DF.ACT,DCTFLG(R2) ; MARK AS ACTIVE $POP R1,R0 ; AND GO RTS PC .PAGE .SBTTL ETHER INPUT INTERRUPT HANDLER ; ; CALLED WITH: R0 - ADDRESS OF DEVICE CONTROL TABLE ; (SP) - OLD R0 ; ETHIIN: $PUSH R1,R2,R3 MOV DCTCSR(R0),R1 ; GET REGISTER LOC MOV DCTQH(R0),R2 ; GET IORB ; BNE 2$ ; ERROR IF NONE CMP R2,$LOMEM ; ERROR IF IORB ADDRESS IS BGT 2$ ; IN THE CODE SEGMENT BUGHLT 2$: BIT #ET.RERR,ETRCSR(R1) ; ANY ERRORS? BEQ 1$ BIS #I.ERR,IRSTA(R2) ; YES, LOG 1$: MOV ETRWC(R1),R3 ; CALCULATE RESIDUAL BYTE COUNT BIS #-ET.RWC-1,R3 ; NOW ONE'S COMP OF NUMBER LEFT INC R3 ; AND CONVERT TO TWO'S COMP ASL R3 ; CONVERT TO BYTES ADD DCTBR(R0),R3 ; IS SAME AS SUBTRCTING NUMBER LEFT MOV R3,IRBX(R2) ; AND RETURN TO USER BIC #DF.ACT,DCTFLG(R0) ; MARK AS INACTIVE BIS #DF.RUN,DCTFLG(R0) ; AND HAD AN INTERRUPT RECENTLY $POP R3,R2,R1 JMP $IOCMP .PAGE .SBTTL ETHER OUTPUT INTERRUPT HANDLER ; ; CALLED WITH: R0 - ADDRESS OF DEVICE CONTROL TABLE ; (SP) - OLD R0 ; ETHOIN: $PUSH R1,R2 MOV DCTCSR(R0),R1 ; GET REGISTER LOC MOV DCTQH(R0),R2 ; GET IORB ; BNE 2$ ; ERROR IF NONE CMP R2,$LOMEM ; ERROR IF IORB ADDRESS IS BGT 2$ ; IN THE CODE SEGMENT BUGHLT 2$: BIT #ET.TERR,ETTCSR(R1) ; ANY ERRORS? BEQ 1$ BIS #I.ERR,IRSTA(R2) ; YES, LOG 1$: MOV IRBR(R2),IRBX(R2) ; NO WAY TO FIND OUT NUMBER BIC #DF.ACT,DCTFLG(R0) ; MARK AS INACTIVE BIS #DF.RUN,DCTFLG(R0) ; AND HAD AN INTERRUPT RECENTLY $POP R2,R1 JMP $IOCMP .PAGE .SBTTL ETHER OUTPUT COLLISION INTERRUPT HANDLER ; ; CALLED WITH: R0 - POINTER TO POINTER TO DEVICE CONTROL TABLE ; (SP) - OLD R0 ; ETHCIN: $PUSH R1,R2 MOV @R0,R0 ; GET A POINTER TO THE DCT INC DCTDV3(R0) ; Inc collision counter TST DCTDV2(R0) ; Is mask 0 (exhausted) yet? BNE 1$ $POP R2,R1 ; YAH, PUNT - LET O/P COMP MARK AS ERR JMP ETHOIN 1$: ASL DCTDV2(R0) ; Open up one more bit in mask MOV $TOD+2,R2 ; Get a "random" number BIC DCTDV2(R0),R2 ; Clear all but low bits MOV DCTCSR(R0),R1 ; GET REGS MOV R2,ETOSD(R1) ; SET DELAY as calculated at 1$ MOV DCTUVA(R0),ETRBUF(R1) ; SET BUFFER ADDRESS MOV DCTBR(R0),ETRWC(R1) ; AND COUNT BIS #ET.RENB!ET.RIE,ETRCSR(R1) $POP R2,R1,R0 ; AND GO $RTT $METBT: .PAGE .SBTTL DATA AREA .CSECT MOSDAT, STATIC COLINS: JSR R0,@(PC)+ ; INSTRUCTION EXEC'D BY COLL INT .END