Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_SRC_1_19910112 - 6-1-monitor/phymei.mac
There are 2 other files named phymei.mac in the archive. Click here to see a list.
;<6-1-MONITOR>PHYMEI.MAC.168, 18-Mar-85 01:36:02, Edit by LOUGHEED
;<6-1-MONITOR>PHYMEI.MAC.167, 15-Mar-85 14:12:56, Edit by LOUGHEED
; Move some code into extended code section
; Flush EVENCF conditional, previous edit history
SEARCH PROLOG,SERCOD,PHYPAR
TTITLE (PHYMEI,,< - DEVICE DEPENDENT CODE FOR MEIS INTERFACE>)
SUBTTL L. BOSACK 4-MAR-82 /LB/KSL/DE

;COPYRIGHT (C) 1982, 1983, 1984, 1985
;THE BOARD OF TRUSTEES, LELAND STANFORD JUNIOR UNIVERSITY, STANFORD, CA  94305
;ALL RIGHTS RESERVED.

IFNDEF REL6,<REL6==1>		;DEFAULT ASSEMBLY FOR RELEASE 6.X

IFE REL6,<DEFINE XRESCD <RESCD>>
IFE REL6,<DEFINE XSWAPCD <SWAPCD>>
SUBTTL PARAMETER DEFINITIONS

MXMEUN==2			;MAXIMUM MEIS INTERFACES PER CONTROLLER

;REGISTERS

;**NOTE**: (*) FLAGS REGISTERS WHOSE CONTENTS CHANGE AS A FUNCTION OF NET SEL.

DR.CR==0	;CONTROL REGISTER
DR.SR==1	;(*)STATUS REGISTER
DR.ER==2	;ERROR REGISTER
DR.MR==3	;MAINTENANCE REGISTER
DR.AS==4	;ATTENTION SUMMARY 
DR.BC==5	;BYTE COUNT REGISTER
DR.DT==6	;DRIVE TYPE REGISTER
DR.DPC==7	;(*)DATA CONTROLLER PC REGISTER
DR.RA==10	;(*)RECEIVER BUFFER ADDRESS REGISTER
DR.RBD==11	;(*)RECEIVER BUFFER DATA REGISTER
DR.RS==12	;(*)RECEIVED PACKET STATUS REGISTER
DR.MD==13	;DATA CONVERSION MODE REGISTER (AND NET SELECT)
DR.CSN==14	;CONTROLLER SERIAL NUMBER REGISTER
DR.DMD==15	;DIAGNOSTIC MEMORY DATA REGISTER
DR.DMA==16	;DIAGNOSTIC MEMORY ADDRESS REGISTER
DR.ABA==17	;(*)ABSOLUTE RECEIVER BUFFER ADDRESS REGISTER
DR.EA==20	;(*)ETHERNET ADDRESS REGISTER
DR.HC==21	;TRANSMIT PACKET HEADER COUNT
DR.DSN==23	;(*)ETHERNET INTERFACE SERIAL NUMBER
N.MEIR==24	;NUMBER OF REGISTERS

DO.CR==0B5	;CONTROL REGISTER
DO.SR==1B5	;(*)STATUS REGISTER
DO.ER==2B5	;ERROR REGISTER
DO.MR==3B5	;MAINTENANCE REGISTER
DO.AS==4B5	;ATTENTION SUMMARY 
DO.BC==5B5	;BYTE COUNT REGISTER
DO.DT==6B5	;DRIVE TYPE REGISTER
DO.DPC==7B5	;(*)DATA CONTROLLER PC REGISTER
DO.RA==10B5	;(*)RECEIVER BUFFER ADDRESS REGISTER
DO.RBD==11B5	;(*)RECEIVER BUFFER DATA REGISTER
DO.RS==12B5	;(*)RECEIVED PACKET STATUS REGISTER
DO.MD==13B5	;DATA CONVERSION MODE REGISTER (AND NET SELECT)
DO.CSN==14B5	;CONTROLLER SERIAL NUMBER REGISTER
DO.TRD==15B5	;TRAILING DATA REGISTER (USED TO APPEND PUP CHECKSUMS)
DO.DMA==16B5	;DIAGNOSTIC MEMORY ADDRESS REGISTER
DO.ABA==17B5	;(*)ABSOLUTE RECEIVER BUFFER ADDRESS REGISTER
DO.EA==20B5	;(*)ETHERNET ADDRESS REGISTER
DO.HC==21B5	;TRANSMIT PACKET HEADER COUNT
DO.MCV==22B5	;MICROCODE VERSION NUMBER
DO.DSN==23B5	;(*)ETHERNET INTERFACE SERIAL NUMBER
;FUNCTIONS

DF.NOP==1		;NO OPERATION
DF.REN==3		;RECEIVER ENABLE
DF.RDI==5		;RECEIVER DISABLE
DF.FRP==7		;FLUSH RECEIVED PACKET
DF.CLR==11		;CLEAR
DF.FXP==13		;FLUSH TRANSMIT BUFFER (3MB), UCODE DUMP (10MB)
DF.WRT==61		;WRITE DATA
DF.RED==71		;READ DATA
;**NOTE** (*) FLAGS BITS THAT REFLECT THE SELECTED NET INTERFACE ONLY

;BITS IN STATUS REGISTER

DS.ATA==1B20		;ATTENTION
DS.ERR==1B21		;COMPOSITE ERROR (LOGICAL OR OF BITS IN ERROR REGISTER)
DS.CD==1B23		;(*)ETHER CARRIER DETECT
DS.IEX==1B24		;(*)INTERFACE EXISTS
DS.XAQ==1B25		;(*)TRANSMIT ACQUIRED ETHER
DS.XA1==1B26		;TRANSMIT BUFFER AVAILABLE ON INTERFACE 1 (DS.XAV)
DS.XA0==1B27		;TRANSMIT BUFFER AVAILABLE ON INTERFACE 0
DS.DRY==1B28		;DRIVE READY (ALWAYS 1)
DS.REN==1B32		;(*)RECEIVER ENABLED
DS.ROV==1B33		;(*)RECEIVER OVERRUN (PACKET BUFFER EXHAUSTED)
DS.RP1==1B34		;RECEIVED PACKET ON INTERFACE 1
DS.RP0==1B35		;RECEIVED PACKET ON INTERFACE 0  (DS.RPK)

;ERROR REGISTER

ER.IVR==1B20		;INVALID READ
ER.IVW==1B21		;INVALID WRITE
ER.AQ1==1B22		;AQUISITION FAILED ON ETHER 1
ER.AQ0==1B23		;AQUISITION FAILED ON ETHER 0
ER.ABT==1B24		;MASSBUS TRANSFER ABORTED
ER.DPE==1B31		;DATA BUS PARITY ERROR
ER.CPE==1B32		;CONTROL BUS PARITY ERROR
ER.RMR==1B33		;REGISTER MODIFICATION REFUSED
ER.ILR==1B34		;ILLEGAL REGISTER
ER.ILF==1B35		;ILLEGAL FUNCTION

;MAINTENANCE REG

MR.SEL==1B20		;BOARD SELECT
MR.INI==1B21		;INIT
MR.LLP==1B28		;LOCAL LOOPBACK
MR.PRM==1B30		;PASS ALL PACKETS
MR.RCV==1B31		;ENABLE RECEPTION
MR.ATA==1B32		;MAINT ATA
MR.DPI==1B33		;DATA PARITY (1 INVERTS TO CAUSE ERRORS)
MR.CPI==1B34		;CTL PARITY  (1 INVERTS TO CAUSE ERRORS)
MR.EN==1B35		;ENABLE MAINT MODE
;RECEIVED PACKET STATUS

RS.CRC==1B20		;CRC ERROR  (3MB ONLY)
RS.OFL==1B23		;OVERFLOW (PACKET EXCEEDED BUFFER) (3MB ONLY)
RS.PLM==7777		;PACKET LENGTH MASK

;DATA CONVERSION MODE AND ETHER SELECT REGISTER

MD.HDR==1B30		;HEADER MODE SELECT (0= 16-BIT MODE, 1= 32-BIT MODE)
MD.SEL==1B32		;ETHER SELECT (0= ETHER 0, 1= ETHER 1)
MD.TRL==1B28		;ENABLE SENDING TRAILER DATA

;0  - LOW 16 BITS IN EACH 18 BIT HALFWORD
;1  - 32 HIGH BITS OF EACH 36 BIT WORD (BYTE HDW FORMAT)
;2  - 36 BITS PACKED
;3  - 7 BIT ASCII
;4  - BYTE SWAP (LIKE 0 BUT WITH THE 8 BIT BYTES SWAPPED)
;5  - 9 BIT ASCII

;ETHERNET ADDRESS REGISTER DEFINITIONS

EA.WEN==1B20		;WRITE ENABLE

EA.AE3==1B27		;ADDRESS ENABLE FOR 3MB
EA.AM3==377		;ADDRESS MASK FOR 3MB

EA.10A==3777		;ADDRESS MASK FOR 10MB
EA.10D==377		;DATA MASK FOR 10MB
;KDB EXTENSION DEFINITIONS

;KDBUDB==KDBDDP		;UDB TABLE IS OF VARIABLE LENGTH
MEKADR==KDBDDP+MXMEUN	;MAX 2 INTERFACES ON A MEIS
MEKSER==MEKADR+1	;MEIS CONTROLLER SERIAL NUMBER
MEKUDB==MEKSER+1	;ACTIVE UDB (0 IF NONE)
MEKATS==MEKUDB+1	;ATTN STATUS IF ATTN DURING XFR (FLAG TO MEIINT)ELSE -1

LK.MEI==MEKATS+1	;LENGTH OF KDB FOR MEIS

;UDB EXTENSION DEFINITIONS

IFE REL6,<MEUBAS==UDBDDD>	;START OF MEIS UDB CELLS
IFN REL6,<MEUBAS==UDBDDM>	;START OF MEIS UDB CELLS

MEUFLG==MEUBAS		;BOOKKEEPING FLAGS
MEUERR==MEUBAS+1	;SMASHED PACKET COUNT - CRC AND OVERFLOW
MEUMCV==MEUBAS+2	;MICROCODE VERSION NUMBER
MEUNCT==:MEUBAS+3	;MULTINET NCT CORRESPONDING TO THIS INTERFACE
MEUHNG==MEUBAS+4	;NUMBER OF TIMES MEIHNG WAS INVOKED
MEUROV==MEUBAS+5	;RECEIVER OVERFLOW COUNT
MEUSIZ==MEUBAS+6	;DRIBBLE PACKET COUNT
MEUFLS==MEUBAS+7	;FLUSHED PACKET COUNT
MEUXAV==MEUBAS+10	;TRANSMIT BUFFER AVAILABLE STATUS BIT MASK
MEURPK==MEUBAS+11	;RECEIVED PACKET AVAILABLE STATUS BIT MASK
MEURIQ==MEUBAS+12	;-1 IF READ IN QUEUE, 0 OTHERWISE

L.MEI==MEUBAS+13	;LENGTH OF MEIS UDB

;FLAGS IN LEFT HALF OF MEUFLG.   RIGHT HALF CONTAINS MINIMUM PACKET SIZE.

MU%10M==1B0		;NI IS THE 10MB VARIETY (OFF IMPLIES 3MB FLAVOR)
MU%ENA==1B1		;NI HAS BEEN ENABLED FOR RECEPTION
MU%LLP==1B2		;NI IS IN HARDWARE LOOPBACK
MU%PRM==1B3		;NI IS A PROMISCUOUS RECEIVER
MU%MNT==1B4		;NI MAINTENANCE MODE STATUS HAS CHANGED
SUBTTL DISPATCH AND INITIALIZATION

MEIDSP::JRST MEIINI	;0 - INITIALIZE
	JRST MEISIO	;1 - START IO
	JRST MEIINT	;2 - DONE INTERRUPT
	JRST RSKP	;3 - ERROR RECOVERY
	JRST MEIHNG	;4 - HUNG DEVICE RESET
	RET		;5 - CONVERT LINEAR ADDRESS TO POSITION
	RET		;6 - BEST LATENCY COMPUTATION, MUST RETURN IORB
	RET		;7 - START POSITIONING, USED TO GET LINK SETUP
	JRST MEIATN	;10 - ATTENTION INTERRUPT
	RET		;11 - SKIP IF POSITION REQUIRED
	RET		;12 - STACK SECOND CHANNEL COMMAND, FAIL
	JRST RETZ	;13 - CHECK UNIT EXISTS
	RET		;14 - CHECK FOR HALTED MICROCODE IN CONTROLLER
	RET		;15 - RELEASE PORT
SUBTTL INITIALIZATION

;WE ARE CALLED ONCE PER MEIS FOUND. WE MUST BUILD THE KDB AND AS MANY
;UDBS AS ARE REQUIRED (ONE PER NET INTERFACE)
;P1/ CDB, Q2/ MASSBUS UNIT NUMBER OF MEIS

MEIINI:	SAVEQ
	MOVE P2,CDBIUN(P1)	;GET KDB ADDRESS
	ADD P2,Q2		;POINT TO CORRECT UNIT
	MOVE P2,0(P2)		;GET ENTRY
	SKIPE P3,P2		;KDB ALREADY EXIST?
	 JRST MEIIOU		;YES - DON'T CREATE A NEW ONE
	MOVX T1,LK.MEI		;LENGTH OF KDB
	CALL PHYALC		;RESERVE SPACE
	 RET			;RETURN IF NO SPACE FOUND
	MOVEM T1,P2		;SAVE ADDRESS IN PROPER AC
	MOVE P3,T1		;COPY KDB
	MOVEI T1,.BTKDB		;MARK AS KDB
	DPB T1,USYBKT		; ...
	MOVX T2,DO.CSN		;GET MEIS SERIAL NUMBER
	CALL RDREG3		; ...
	MOVEM T1,MEKSER(P2)	;STORE IN KDB
	MOVX T1,.UTMEI		;SET UP UNIT TYPE IN KDB
	STOR T1,USTYP,(P2)	;...
	MOVSI T1,-MXMEUN	;SET UP AOBJN INDEX LH
	HRRI T1,KDBUDB(P2)	;MAKE RH POINT TO UDB ENTRIES IN KDB
	MOVEM T1,KDBIUN(P2)	;INITIAL POINTER
	MOVEM T1,KDBCUN(P2)	;CURRENT POINTER
	HRRZM Q2,MEKADR(P2)	;SAVE KDB ADDRESS
	XMOVEI T1,MEIDSP	;INSERT DISPATCH VECTOR
	MOVEM T1,KDBDSP(P2)	; ...
	SETOM MEKATS(P2)	;NO INTERRUPT ACTION NEEDED
MEIIOU: MOVSI Q1,-MXMEUN	;SLAVE INDEX
MEIILP:	CALL MEIUIN		;INITIALIZE A SINGLE INTERFACE
	 NOP			;IGNORE ERROR RETURN, NOTHING TO DO ABOUT IT
	AOBJN Q1,MEIILP		;TRY NEXT SLAVE
	RET
;HERE TO INITIALIZE A SINGLE INTERFACE
;FIRST DETERMINE IF THIS NET INTERFACE EXISTS. IF SO, BUILD A UDB FOR IT.

MEIUIN:	HRRZ T2,Q1		;GET SLAVE NUMBER
	LSH T2,3		;POSITION
	TXO T2,DO.MD		;BUILD DATAO
	CALL WTREG3		;SELECT UNIT
	MOVX T2,DO.SR		;READ STATUS REG
	CALL RDREG3		; ...
	TXNN T1,DS.IEX		;INTERFACE EXIST?
	 JRST MEIINX		;NO, DO NOTHING
	MOVE T3,[XWD MEIDSP, L.MEI] ;DISPATCH,,LENGTH FOR PHYUDB
	CALL PHYUDB		;CREATE UDB AS SPECIFIED
	 BUG.(HLT,PMENUB,PHYMEI,HARD,<No free stg for MEIS UDB>)
	MOVEI T1,.UTMEI		;SETUP UNIT TYPE
	TLO T1,(US.PRQ!US.TAP)	;IMAGINE POSITIONING IS REQUIRED AND WE
	IORM T1,UDBSTS(P3)	;ARE LIKE A MAGTAPE
	HRRZM Q1,UDBSLV(P3)	;SET SLAVE ADDRESS
	MOVX T2,DO.DSN		;GET INTERFACE SERIAL NUMBER
	CALL RDREG		; ...
	MOVEM T1,UDBDSN(P3)	;STORE IN UDB
	MOVE T2,[MU%10M+^D60]	;ASSUME 10MB INTERFACE, 60. BYTE MINIMUM
	CAIGE T1,10000		;IS THIS A 10MB NI?
	 MOVEI T2,4		;3MB INTERFACE, 4. BYTE MINIMUM PACKET
	MOVEM T2,MEUFLG(P3)	;SET UP FLAG WORD
	MOVX T2,DO.MCV		;GET MICROCODE VERSION NUMBER
	CALL RDREG		; ...
	MOVEM T1,MEUMCV(P3)	;STOR IN UDB
	HRRZ T1,Q1		;GET UNIT NUMBER
	ADDI T1,KDBUDB(P2)	;ADDRESS TABLE
	MOVEM P3,(T1)		;SAVE UDB IN KDB
	MOVEM P2,UDBKDB(P3)	;SAVE KDB IN UDB
	CALL RAMCLR		;CLEAR ALL ADDRESSES IN ADDRESS RAM
	SKIPN T1,ENCUTP		;GET POINTER TO PHYSICAL DEVICE TABLE
	 MOVE T1,ENIUTP		;FIRST TIME, GET INITIAL POINTER
	JUMPGE T1,MEIINX	;HAVE ALL WE ARE ALLOWED?
	MOVE T2,P3		;GET UDB
	HRL T2,UDBCDB(P3)	;GET CDB,,UDB IN T2
	MOVEM T2,ENCUTB(T1)	;STORE IN TABLE
	ADJSP T1,1		;INCREMENT POINTER AND COUNT
	MOVEM T1,ENCUTP		;STORE UPDATED POINTER
	DMOVE T1,[ DS.XA0	;GET TX AND RX AVAILABLE FLAGS FOR NI 0
		   DS.RP0 ]
	SKIPE UDBSLV(P3)	;SKIP IF THIS IS INTERFACE 0
	DMOVE T1,[ DS.XA1	;GET TX AND RX AVAILABLE FLAGS FOR NI 1
		   DS.RP1 ]
	MOVE T3,MEUMCV(P3)	;GET CONTROLLER MICROCODE VERSION
	CAIGE T3,1003		;SKIP IF IT IS THE MOST RECENT REVISION
	DMOVE T1,[ DS.XA1
		   DS.RP0 ]	;ELSE GET THE OLD TX AND RX FLAG BITS
	DMOVEM T1,MEUXAV(P3)	;SET THE STATUS FLAG MASK WORDS
MEIINX:	RETSKP			;DONE
;RAMCLR - CLEAR ADDRESS RAM FOR 3 OR 10MB INTERFACE
;MUST BE CALLED WITH INTERRUPTS OFF
;TAKES	P1,P2,P3 SET UP
;RETURNS +1 ALWAYS

RAMCLR:	CALL MEIRDI		;SELECT INTERFACE, DISABLE RECEPTION
	MOVE T1,MEUFLG(P3)	;GET OUR FLAGS
	TXNN T1,MU%10M		;10MB INTERFACE?
	 JRST RAM3CL		;NO, GO CLEAR A 3MB INTERFACE
	MOVSI T4,-EA.10A	;SET UP AOBJN POINTER
RAM10L:	MOVEI T2,(T4)		;SELECT AN ADDRESS
	TXO T2,DO.EA		; ...
	CALL WTREG		; ...
	MOVX T2,DO.EA+EA.WEN	;WRITE A ZERO TO THAT ADDRESS
	CALL WTREG		; ...
	AOBJN T4,RAM10L		;LOOP OVER ENTIRE ADDRESS RAM
	RET			;RETURN TO CALLER

RAM3CL:	MOVSI T4,-EA.AM3	;SET UP LOOP COUNTER
RAM3LP:	MOVEI T2,(T4)		;GET ADDRESS WE WANT TO CLEAR
	TXO T2,DO.EA+EA.WEN	;WRITE RAM, BUT DO NOT ENABLE RECEPTION
	CALL WTREG		;DISABLE RECEPTION AT THAT ADDRESS
	AOBJN T4,RAM3LP		;LOOP OVER ENTIRE ADDRESS RAM
	RET			;RETURN TO CALLER
;UTILITY ROUTINE TO ENABLE RECEPTION
;*NOTE*:THIS ROUTINE CHANGES THE SELECTED NET - BEWARE IF INTERRUPTABLE
;P1,P2,P3/ CDB,KDB,UDB

MEIENR:	CALL MEICON		;SELECT THE INTERFACE
	MOVE T2,[EXP DO.CR!DF.REN] ;ENABLE RECEPTION
	CALLRET WTREG		; ...

;UTILITY ROUTINE TO DISABLE RECEPTION
;*NOTE*:THIS ROUTINE CHANGES THE SELECTED NET - BEWARE IF INTERRUPTABLE
;P1,P2,P3/ CDB,KDB,UDB

MEIRDI:	CALL MEICON		;SELECT THE INTERFACE
	MOVE T2,[EXP DO.CR!DF.RDI] ;DISABLE RECEPTION
	CALLRET WTREG		; ...
;MEISDN - CALLED FROM HIGHER LEVELS TO CHECK IF MEIS IS ENABLED
;CALLED FROM PROCESS CONTEXT
;T1/ CDB,,UDB
;RETURNS +1 ALWAYS

	XSWAPCD

MEISDN::HRRZS T1		;DON'T NEED CDB
	MOVE T1,MEUFLG(T1)	;GET FLAGS FOR THIS NI
	TXNN T1,MU%ENA		;ENABLED
	RETSKP			;NO, SKIP RETURN
	RET			;YES, MEIS IS NOT DOWN

;MEITYP - CALLED FROM HIGHER LEVELS TO CHECK INTERFACE TYPE
;CALLED FROM PROCESS CONTEXT
;T1/ CDB,,UDB
;RETURNS +1 3MB INTERFACE
;	 +2 10MB INTERFACE

MEITYP::HRRZS T1		;DON'T NEED CDB
	MOVE T1,MEUFLG(T1)	;GET FLAGS FOR THIS NI
	TXNE T1,MU%10M		;10MB INTERFACE?
	RETSKP			;YES, SKIP RETURN
	RET			;NO, MUST BE 3MB INTERFACE
;MEIPRM - FORCE AN INTERFACE INTO PROMISCUOUS MODE
;TAKES 	T1/ CDB,,UDB
;	T2/ 0 FOR NORMAL RECEPTION, -1 FOR PROMISCUOUS 
;RETURNS +1 ALWAYS

MEIPRM::HRRZS T1		;DON'T NEED CDB
	MOVE T3,MEUFLG(T1)	;GET FLAGS FOR THIS NI
	TXO T3,MU%PRM!MU%MNT	;SET PROMISCUOUS AND MAINT ACTION NEEDED
	SKIPN T2		;ASSUMPTION CORRECT?
	 TXZ T3,MU%PRM		;NO, CLEAR PROMISCUOUS
MEIPM0:	MOVEM T3,MEUFLG(T1)	;RESET FLAG WORD
	SETZM MEITIM		;MAKE SCHEDULER SET NEW MAINT MODE STATUS
	RET			;RETURN TO CALLER

;MEILLP - FORCE AN INTERFACE INTO HARDWARE LOOPBACK
;TAKES 	T1/ CDB,,UDB
;	T2/ 0 FOR NORMAL RECEPTION, -1 FOR LOOPBACK
;RETURNS +1 ALWAYS

MEILLP::HRRZS T1		;DON'T NEED CDB
	MOVE T3,MEUFLG(T1)	;GET FLAGS FOR THIS NI
	TXO T3,MU%LLP!MU%MNT	;SET LOOPBACK AND MAINT ACTION NEEDED
	SKIPN T2		;ASSUMPTION CORRECT?
	 TXZ T3,MU%LLP		;NO, CLEAR LOOPBACK
	JRST MEIPM0		;GO JOIN COMMON CODE
;SET10M - SET/CLEAR A (NON-WILD) 48-BIT HARDWARE ADDRESS IN A 10MB MEIS
;NI MUST BE SELECTED AND DISABLED. INTERRUPTS MUST ALSO BE OFF.
;TAKES	T1/ FSM NUMBER - 1B0 SET IF SETTING THAT ADDRESS, CLEAR IF CLEARING
;	T2/ POINTER TO 6 BYTE STRING OF 8-BIT BYTES
;	P1,P2,P3/ SET UP AS USUAL
;RETURNS +1 ALWAYS

	XRESCD

SET10M:	SAVEQ			;PRESERVE QX REGISTERS
	DMOVE Q1,T1		;COPY OUR ARGUMENTS
	MOVSI Q3,-6		;SET UP LOOP COUNT
SET10L:	MOVEI T2,(Q3)		;COPY BYTE NUMBER
	LSH T2,^D8		;SHIFT IT TO FORM HIGH BITS OF ADDRESS
	ILDB T3,Q2		;GET BYTE OF ADDRESS DATA
	IORI T2,(T3)		;OR INTO ADDRESS MASK (FORM 11 BIT ADDRESS)
	TXO T2,DO.EA		;ETHERNET ADDRESS REGISTER
	CALL WTREG		;SELECT AN OFFSET INTO THE ADDRESS RAM
	MOVX T2,DO.EA		;READ CURRENT CONTENTS OF THAT OFFSET
	CALL RDREG		; ...
	ANDI T1,EA.10D		;MASK OUT ANY EXTRANEOUS BITS
	MOVE T2,BITS(Q1)	;CREATE A BIT PATTERN TO SELECT THE RIGHT FSM 
	ROT T2,^D8		;FSM #0 IS MSB OF ADDRESS RAM DATA, ETC.
	SKIPGE Q1		;SKIP IF CLEARING THIS ADDRESS
	 TDOA T2,T1		;SET FSM ASSIGNMENT AND SKIP
	  ANDCA T2,T1		;CLEAR FSM ASSIGNMENT
	TXO T2,DO.EA+EA.WEN	;ETHERNET ADDRESS REGISTER, WRITE ENABLE
	CALL WTREG		;SET DATA 
	AOBJN Q3,SET10L		;LOOP OVER ALL ADDRESS BYTES
	RET			;RETURN TO CALLER
;SET3MB - SET/CLEAR AN 8-BIT HARDWARE ADDRESS IN A 3MB MEIS
;NI MUST BE SELECTED AND DISABLED. INTERRUPTS MUST ALSO BE OFF.
;TAKES	T1/ 8-BIT ADDRESS - 1B0 SET IF SETTING THAT ADDRESS, CLEAR IF CLEARING
;	P1,P2,P3/ SET UP AS USUAL
;RETURNS +1 ALWAYS

SET3MB:	MOVE T2,[EXP DO.EA!EA.WEN] ;WRITE ETHER ADDRESS MASK
	TXZE T1,1B0		;ENABLING RECEPTION?
	 TXO T1,EA.AE3		;YES, INDICATE SO
	IORI T2,(T1)		;AT THIS ADDRESS
	CALL WTREG		; ...
	RET			;RETURN TO CALLER
;MEIADR - SET MEIS ADDRESS
;CALLED FROM PROCESS CONTEXT
;ALSO DISABLES RECEPTION FOR THE SPECIFIED INTERFACE
;TAKES	T1/ CDB,,UDB
;   FOR 3MB:	T2/ 8-BIT ADDRESS
;
;   FOR 10MB:	T2/ FSM NUMBER (FSM ZERO RESERVED FOR BROADCAST)
;		T3/ FIRST 32 BITS OF ADDRESS, RIGHT JUSTIFIED
;		T4/ LAST 16 BITS OF ADDRESS, RIGHT JUSTIFIED
;RETURNS +1 ALWAYS

MEIADR::SAVEP			;PRESERVE ACS
	ASUBR <MEIAD1,MEIAD2,MEIAD3,MEIAD4> ;LOCAL STORAGE
	HLRZ P1,T1		;GET CDB
	HRRZ P3,T1		;GET UDB
	MOVE P2,UDBKDB(P3)	;GET KDB
	NOSKED
	IOPIOF			;INTERLOCK AGAINST INTERRUPTS
	CALL MEIRDI		;SELECT MEIS, DISABLE RECEPTION
	MOVE T1,MEUFLG(P3)	;GET OUR FLAG WORD
	TXNE T1,MU%10M		;10MB INTERFACE?
	 JRST MEIAD0		;YES, JUMP TO 10MB MASK CODE
	MOVE T1,MEIAD2		;COPY ADDRESS WE WISH TO LISTEN ON
	TXO T1,1B0		;SAY ENABLE RECEPTION
	CALL SET3MB		;FIRST SET SPECIFIED ADDRESS
	MOVX T1,1B0		;SETUP FOR BROADCASTS
	CALL SET3MB		; ...
MEIADZ:	IOPION
	OKSKED
	MOVX T1,MU%ENA		;INTERFACE ENABLED FLAG
	IORM T1,MEUFLG(P3)	;RECORD IN UDB
	RET

;SET MASK FOR 10MB INTERFACE

MEIAD0:	MOVX T1,1B0+0		;SET ADDRESS IN FSM 0
	MOVE T2,[POINT 8,[EXP -1,-1]]	;THE BROADCAST ADDRESS (ALL ONES)
	CALL SET10M		;SET BROADCAST ADDRESS
	MOVE T1,MEIAD4		;GET LAST 16 BITS OF HDW ADDRESS
	LSH T1,^D20		;LEFT JUSTIFY IT
	MOVEM T1,MEIAD4		;AND PUT IT BACK
	MOVEI T2,MEIAD3		;BEGIN SETTING UP THE BYTE POINTER
	HRLI T2,(POINT 8,,3)	;SET UP POINTER TO START OF HDW ADDRESS
	MOVE T1,MEIAD2		;GET FSM SPECIFIED BY USER
	TXO T1,1B0		;INDICATE WE ARE SETTING THE ADDRESS
	CALL SET10M		;SET OUR PRIMARY ADDRESS
	JRST MEIADZ		;JOIN EXIT CODE
;ROUTINE CALLED FROM HIGHER LEVELS TO ENABLE RECEPTION
;CALLED FROM PROCESS CONTEXT
;T1/ CDB,,UDB

MEION::	SAVEP			;PRESERVE ACS
	HLRZ P1,T1		;GET CDB
	HRRZ P3,T1		;GET UDB
	MOVE P2,UDBKDB(P3)	;GET KDB
	NOSKED			;NO SCHEDULING
	IOPIOF			;INTERLOCK AGAINST INTERRUPTS
	CALL MEIENR		;ENABLE RECEPTION
	MOVX T1,MU%ENA		;GET FLAG TO SAY WE'RE ENABLED
	IORM T1,MEUFLG(P3)	;SET IT
	CALL MEIMNT		;SET UP ANY MAINTENANCE MODE CHARACTERISTICS
	IOPION			;REALLOW PI LEVEL 5 ACTIVITY
	OKSKED			;REALLOW SCHEDULING
	RET			;RETURN TO CALLER
;ROUTINE CALLED FROM HIGHER LEVELS TO DISABLE RECEPTION
;CALLED FROM PROCESS CONTEXT
;T1/ CDB,,UDB

MEIOFF::SAVEP			;PRESERVE ACS
	HLRZ P1,T1		;GET CDB
	HRRZ P3,T1		;GET UDB
	MOVE P2,UDBKDB(P3)	;GET KDB
	NOSKED
	IOPIOF			;INTERLOCK AGAINST INTERRUPTS
	CALL MEIRDI		;DISABLE RECEPTION
	IOPION
	OKSKED
	MOVX T1,MU%ENA		;RECEPTION ENABLED FLAG
	ANDCAM T1,MEUFLG(P3)	;CLEAR IT
	RET
;MEICON - SELECT THE NET INTERFACE
;ASSUMES P1,P2,P3 SET UP

	RESCD

MEICON:	MOVX T2,DO.MD		;WANT MODE REGISTER
	SKIPE UDBSLV(P3)	;SKIP IF INTERFACE IS IN SLOT 0
	 TXO T2,MD.SEL		;ELSE SELECT INTERFACE IN SLOT 1
	CALL WTREG		;AND WRITE SELECT
	RET			;RETURN TO CALLER
SUBTTL START IO

;MEISIO - START I/O ON THE MEIS
;TAKES P1/ CDB POINTER
;      P3/ UDB POINTER
;      P4/ IORB POINTER
;RETURNS +1 FAILURE
;	 +2 SUCCESS, CHANNEL STARTED

MEISIO:	SAVEQ			;SAVE REGISTERS
	MOVE P2,UDBKDB(P3)	;SET UP THE KDB
	SKIPLE T1,UDBERR(P3)	;SPECIAL ERROR RECOVERY FUNCTION?
	 JRST MEISI1		;YES - USE IT
	LDB T1,IRYFCN		;GET FUNCTION FROM IORB
	CAIG T1,MXEFCN		;LESS THAN MAX EXTERNAL FUNCTION?
MEISI1:	SKIPN Q1,MEIFCN(T1)	;NO, GET HARDWARE FUNCTION WORD
	 BUG.(HLT,MEIILF,PHYMEI,HARD,<Illegal function at MEISIO>,<<T1,FNC>>)
	CALL CHKCON		;CHECK DEVICE OK AND SELECT INTERFACE
	 RET			;INTERFACE SICK
	SETOM MEKATS(P2)	;FLAG NO SPECIAL DONE INTERRUPT ACTION
	HRRZM P3,MEKUDB(P2)	;SAVE ACTIVE UDB
	LDB T2,IRYFCN		;GET ORIGINAL FUNCTION
	CAIE T2,IRFWRT		;IS IT A WRITE?
	 JRST MEISI2		;NO, PROCEED WITH READ CODE
	TDNE T1,MEUXAV(P3)	;YES - IS THE TRANSMIT BUFFER AVAILABLE?
	 JRST MEISI3		;YES, PROCEED WITH WRITE CODE
	BUG.(CHK,PMEXNA,PHYMEI,SOFT,<Transmit buffer unavailable at MEISIO>)
	MOVX T1,IS.ERR		;GET ERROR BIT
	IORM T1,IRBSTS(P4)	;SET IT IN IORB SO IT GETS DEQUEUED
	CALL MEIHNG		;RESET INTERFACE
	RET			;QUIT NOW

MEISI3:	JE IRTRF,(P4),MEISI2	;SKIP THIS STUFF IF NOT USING TRAILER MODE
	LOAD T2,IRCHK,(P4)	;WANT TRAILER. GET CHECKSUM.
	TXO T2,DO.TRD		;SEND TO TRAILING DATA REG
	CALL WTREG		; ...
MEISI2:	LOAD T2,IRPMD,(P4)	;GET DATA MODE
	HRRZ T1,UDBSLV(P3)	;GET SLAVE NO
	LSH T1,3		;BUILD MODE WORD
	OPSTR <SKIPE>,IRTRF,(P4) ;TRAILER MODE WANTED?
	 TXO T2,MD.TRL		;YES - TELL HARDWARE.
	OPSTR <SKIPE>,IRHDR,(P4) ;32-BIT MODE HEADERS WANTED?
	 TXO T2,MD.HDR		;YES - TELL HARDWARE
	IOR T2,T1		;...
	TXO T2,DO.MD		; ..
	CALL WTREG		;SEND TO HW
	LOAD T2,IRHLN,(P4)	;GET HEADER LENGTH
	TXO T2,DO.HC		;...
	CALL WTREG		;SEND TO MEIS
	MOVE T1,IRBCNT(P4)	;GET DATA BYTE COUNT
	LOAD T2,IRPMD,(P4)	;GET DATA MODE
	LDB T3,IRYFCN		;GET FUNCTION (READ OR WRITE)
	CAIE T3,IRFRED		;READING?
	IFSKP.
	  LOAD T3,IRHLN,(P4)	;YES, GET HEADER LENGTH
	  CALL WRDCNV		;MAKE INTO NUMBER OF WORDS
	  LSH T1,2		;MAKE INTO NUMBER OF 9-BIT BYTES
	  MOVE T2,T1		;COPY INTO T2 FOR LATER
	ELSE.
	  CAIE T2,.PM36		;36-BIT MODE?
	  IFSKP.
	    MOVE T2,T1		;YES, COPY BYTE SIZE
;THIS CODE MUST BE HERE SO THAT WE GIVE THE UNHACKED BYTE COUNT TO WRDCNV
;WHEN READING IN A PACKET.  WE ONLY HACK THE COUNT WHEN WRITING.
	    IDIVI T2,^D18	;FIND MODULO 18
	    CAIN T3,^D14	;IF IT WAS 14
	     SUBI T1,2		;MAKE IT 12 INSTEAD
	  ENDIF.		;END OF .PM36 CONVERSION

;NOTE THAT WE ARE ASSUMING AN EVEN NUMBER OF 16-BIT HEADER WORDS!
;AT THIS POINT THE DATA COUNT IS IN T1 SO WE TAKE ADVANTAGE OF
;THE ADD TO COPY IT INTO T2 WHERE WE WANT IT...
	  LOAD T2,IRHLN,(P4)	;GET HEADER LENGTH (IN 16-BIT WORDS)
	  LSH T2,1		;CONVERT TO BYTES
	  ADDI T2,(T1)		;CALCULATE TOTAL NUMBER OF BYTES
	ENDIF.			;END OF WRITE BYTE COUNT CALCULATION
	HRLI T2,(DO.BC)		;BUILD DATAO
	CALLRET CHSTRT		;START CHANNEL, FUNCTION WORD IN Q1
				;NON-SKIP IF ERROR, SKIP IF OKAY
;CHKCON - CHECK IF THIS INTERFACE IS USABLE AND SELECT IT
;TAKES P1,P2,P3 SET UP
;RETURNS +1 INTERFACE UNUSABLE, T1/ STATUS
;	 +2 INTERFACE OKAY, T1/ STATUS

CHKCON:	CALL MEICON		;SELECT THE INTERFACE
	MOVX T2,DO.SR		;READ STATUS REGISTER
	CALL RDREG		; ...
	PUSH P,T1		;SAVE STATUS FLAGS
	TXNE T1,DS.ROV		;OVERFLOW?
	 AOS MEUROV(P3)		;YES, COUNT IT
	TXNN T1,DS.ERR!DS.ROV	;ANY ERRORS?
	 JRST CHKCN1		;NO, NO PROBLEMS
	CALL MEIHNG		;YES, RESET THE MEIS
	MOVEM T1,(P)		;SAVE NEW STATUS RETURNED BY MEIHNG
	TXNE T1,DS.ERR!DS.ROV	;STILL ERRORS?
	 JRST CHKNOK		;YES - NOT OK
CHKCN1:	MOVX T1,US.OFS		;NO - CLEAR UNSAFE BITS
	ANDCAM T1,UDBSTS(P3)	; ...
	POP P,T1		;RESTORE STATUS
	RETSKP			;AND RETURN GO

CHKNOK:	MOVX T2,US.OFS		;ACT UNSAFE.
	IORM T2,UDBSTS(P3)	;STORE IN STATUS WORD
	POP P,T1		;RESTORE STATUS
	RET			;RETURN UNAVAILABLE
;WRDCNV - CONVERT BYTE COUNT TO 36-BIT WORD COUNT
;TAKES	T1/ DATA BYTE COUNT
;	T2/ DATA MODE (BETTER BE LEGAL BECAUSE WE DON'T CHECK)
;	T3/ HEADER WORD COUNT
;RETURNS +1 ALWAYS WITH T1/ COUNT OF 36-BIT WORDS

WRDCNV::CALL @[	IFIW!WRDC16	;.PM16
		IFIW!WRDC16	;.PM32
		IFIW!TO36	;.PM36
		IFIW!WRDC7	;.PMASC
		IFIW!WRDC16	;.PM16S
		IFIW!WRDC16 ](T2) ;.PM9
	LSH T3,-1		;CONVERT HEADER WORDS TO 36-BIT WORDS
	ADDI T1,(T3)		;COUNT THE HEADER BYTES
	RET			;RETURN TO CALLER

WRDC7:	IDIVI T1,5		;FIND NUMBER OF WHOLE WORDS TO USE
	SKIPE T2		;IF THERE ARE ANY BYTES LEFT OVER
	 ADDI T1,1		;THEN USE ANOTHER WORD FOR THEM
	RET			;THAT'S ALL FOR ASCII MODE

WRDC16:	TRZE T1,3		;REMAINDER MOD 4?
	 ADDI T1,4		;YES, ROUND UP
	LSH T1,-2		;DIVIDE DOWN
	RET
;FRM36 - GIVEN COUNT OF 36-BIT WORDS, CALCULATE COUNT OF ETHERNET BYTES
;USED ONLY FOR THE 36-BIT DATA MODE
;TAKES	T1/ NO. OF 36-BIT WORDS
;RETURNS +1 ALWAYS, T1/ NO. OF 8-BIT ETHERNET BYTES
;CLOBBERS T1-T2

FRM36::	LSHC T1,-1		;GET NUMBER OF PAIRS OF WORDS, EXTRA BIT IN T2
	IMULI T1,^D9		;9 BYTES PER PAIR OF WORDS
	TXNE T2,1B0		;IF WE ORIGINALLY HAD AN EXTRA WORD
	 ADDI T1,^D5		;COUNT IT IN
	RET			;RETURN TO CALLER

;TO36 - CONVERT ETHERNET BYTES INTO 36-BIT WORDS FOR READ FROM NET
;TAKES  T1/ NO. OF 8-BIT ETHERNET BYTES
;RETURNS +1 ALWAYS, T1/ NO. OF 36-BIT WORDS
;CLOBBERS T1-T2

TO36::	IDIVI T1,^D9		;9 BYTES FOR EVERY TWO WORDS
	LSH T1,1		;COMPUTE NUMBER OF WHOLE WORD PAIRS
	CAIL T2,5		;ENOUGH LEFT OVER TO MAKE ANOTHER WORD?
	 ADDI T1,1		;YES, ADD IT IN
	RET
SUBTTL HUNG DEVICE

;MEILUP - LOOP OVER ALL MEIS DEVICES, XCT'ING INSTRUCTION AT CALLER +1
;SETS UP P1,P2,P3
;RETURNS +2 ALWAYS

MEILUP:	PIOFF			;DON'T LET NOBODY TOUCH US NOW
	MOVE P5,ENIUTP		;SET UP POINTER INTO CHANNEL,,UNIT TABLE
MEILU0:	SKIPN ENCUTB(P5)	;SKIP IF WE HAVE A MEIS HERE
	 JRST MEILU1		;GO ON TO THE NEXT IF NOT
	HLRZ P1,ENCUTB(P5)	;GET CDB
	HRRZ P3,ENCUTB(P5)	;GET UDB
	MOVE P2,UDBKDB(P3)	;GET KDB
	XCT @0(P)		;EXECUTE INSTRUCTION AT CALLER PC +1
MEILU1:	AOBJN P5,MEILU0		;LOOP OVER ALL MEIS DEVICES
	PION			;PI'S BACK ON
	RETSKP			;RETURN TO CALLER
;MEIFIX - MDDT CALLABLE ROUTINE TO RESET ALL THE MEIS DEVICES

MEIFIX:	CALL MEILUP		;LOOP OVER ALL MEIS DEVICES
	 CALL MEIFX0		;RESET EACH ONE (INST IS XCT'ED BY MEILUP)
	SETZM MEITIM		;SCHEDULER WILL RESTART THE INTERFACES
	RET			;RETURN TO CALLER

MEIFX0: CALL MEIHNG		;RESET THE INTERFACE, FIX UP DATA STRUCTURES
	MOVE T2,[DO.MR!MR.EN!MR.INI]	;FINISH WITH MASTER RESET OF CONTROLLER
	CALL WTREG		;WIPE STATE OF BOTH INTERFACES
	RET			;RETURN TO CALLER


;MEIREG - MDDT CALLABLE ROUTINE TO EXAMINE THE FIRST MEIS'S STATUS REGISTER

MEIREG:	SKIPN T1,ENCUTB		;IF NO MEIS THERE
	 RET			;DON'T DO ANYTHING
	HRRZ P3,T1		;GET UDB
	HLRZ P1,T1		;GET CDB
	MOVE P2,UDBKDB(P3)	;GET KDB
	NOSKED			;NO SCHEDULING
	PIOFF			;NO INTERRUPTS OF ANY TYPE
	CALL MEICON		;SELECT THE INTERFACE
	MOVX T2,DO.SR		;CODE FOR STATUS REGISTER
	CALL RDREG		;READ THE REGISTER INTO T1
	PION			;TURN ON PI SYSTEM
	OKSKED			;REALLOW SCHEDULING
	RET			;RETURN TO CALLER
;MEIMNT - PUT MEIS INTO SOME TYPE OF MAINTENANCE MODE
;USES FLAG BITS IN MEUFLG(P3) BELOW TO DETERMINE APPROPRIATE ACTION

MEIMNT:	MOVE T1,MEUFLG(P3)	;GET FLAG WORD FOR THIS INTERFACE
	SETZ T2,		;NO CONTROL BITS SET YET
	TXNE T1,MU%LLP		;SETTING LOCAL LOOPBACK?
	 TXO T2,MR.EN!MR.RCV!MR.LLP	;YES, SET THE BITS
	TXNE T1,MU%PRM		;WANT PROMISCUOUS RECEPTION?
	 TXO T2,MR.EN!MR.RCV!MR.PRM	;YES, SET THE BITS
	TXZN T1,MU%MNT		;SKIP MAINTENANCE MODE STATUS HAS CHANGED
	JUMPE T2,R		;QUIT NOW IF NOTHING TO DO
	MOVEM T1,MEUFLG(P3)	;UPDATE FLAG WORD
	TXO T2,DO.MR		;WANT TO WRITE MAINTENANCE REGISTER
	SKIPE UDBSLV(P3)	;SKIP IF NETWORK INTERFACE 0 IS SELECTED
	 TXO T2,MR.SEL		;SET BOARD SELECT BIT IF WE WANT N.I. 1
	CALL WTREG		;WRITE THE MAINTENANCE REGISTER
	RET			;RETURN TO CALLER
;MEIHNG - HERE WHEN SOMETHING GOES WRONG.
;WE RETURN NEW STATUS REGISTER CONTENTS IN T1

MEIHNG:	AOS MEUHNG(P3)		;COUNT ANOTHER INVOKATION OF MEIHNG
	MOVX T2,US.REW		;CLEAR REWIND (THIS IS SOMEWHAT RISKY)
	ANDCAM T2,UDBSTS(P3)
	SETZM MEURIQ(P3)	;CLEAR READ IN QUEUE FLAG
	MOVE T2,MEKUDB(P2)	;GET UDB OF ACTIVE INTERFACE
	CAMN T2,P3		;IS IT US?
	 SETZM MEKUDB(P2)	;YES, CLEAR ACTIVE UDB
	MOVX T2,DO.ER		;READ ERROR REGISTER
	CALL RDREG		; ...
	JUMPE T1,MEIHN0		;GO RESET IF NO COMPOSITE ERROR
	BUG.(CHK,MEIERR,PHYMEI,HARD,<MEIS hardware error>,<<T1,A>,<P3,B>>)
	MOVE T2,[DO.MR!MR.EN!MR.INI]	;MASTER RESET OF CONTROLLER
	CALL WTREG		;WIPE STATE OF BOTH INTERFACES
	SETZM MEITIM		;SCHEDULER WILL RESTART THE INTERFACES
	JRST MEIHN1		;GO READ STATUS AND RETURN

MEIHN0:	MOVX T2,<DO.CR!DF.CLR>	;FUNCTION IS MEIS CLEAR
	CALL WTREG		; ...
	MOVE T2,[EXP DO.CR!DF.REN] ;RE-ENABLE RECEIVER
	CALL WTREG		; ...
	CALL MEIMNT		;ENABLE ANY MAINTENANCE MODE FUNCTIONS
MEIHN1:	MOVX T2,DO.SR		;READ STATUS REGISTER
	CALL RDREG		; ...
	RET			;RETURN TO CALLER
SUBTTL MEIS EXISTENCE CHECKS

;MEICHK - CHECK THE MEIS UNITS EVERY MINUTE
;CALLED BY 100 MS CLOCK IN SCHEDULER

MEICHK::SAVEP			;SAVE SOME REGISTERS
	MOVE P4,ENIUTP		;INITIAL POINTER TO MEIS CDB,,UDB TABLE
MEICH0:	HRRZ P3,ENCUTB(P4)	;GET UDB ADDRESS
	JUMPE P3,MEICH3		;ALL DONE IF WE'VE RUN OUT OF UDB'S
	MOVE T1,MEUFLG(P3)	;GET FLAG WORD OF THE UDB
	TXNN T1,MU%ENA		;DO WE THINK THIS MEIS IS ENABLED?
	JRST MEICH2		;NO, SKIP OVER IT
	HLRZ P1,ENCUTB(P4)	;GET CDB ADDRESS
	MOVE P2,UDBKDB(P3)	;GET KDB ADDRESS
	IOPIOFF			;LOCK OUT INTERRUPTS
	SKIPE MEKUDB(P2)	;ANY ACTIVE INTERFACES ON THIS CONTROLLER?
	 JRST MEICH1		;YES, SKIP THE CHECKS
	CALL MEICON		;SELECT THE APPROPRIATE INTERFACE
	MOVX T2,DO.SR		;READ STATUS REGISTER
	CALL RDREG		; ...
	MOVE T2,CDBADR(P1)	;GET CHANNEL ADDRESS
	MOVE T3,UDBADR(P3)	;GET UNIT ADDRESS
	MOVE T4,UDBSLV(P3)	;GET SLOT NUMBER
	TXNE T1,DS.IEX		;DOES THE INTERFACE STILL EXIST?
	IFSKP.		
	  BUG.(INF,MEIGON,PHYMEI,HARD,<MEIS interface vanished>,<<T2,C>,<T3,U>,<T4,N>>)
	  MOVX T1,MU%ENA	;GET RECEIVER ENABLED FLAG
	  ANDCAM T1,MEUFLG(P3)	;AND CLEAR IT
	  JRST MEICH1		;GO CHECK NEXT MEIS, IF ANY
	ENDIF.
	TXNE T1,DS.REN		;IS THE RECEIVER STILL ENABLED?
	IFSKP.
	  BUG.(INF,MEIOFX,PHYMEI,HARD,<MEIS interface restarted>,<<T2,C>,<T3,U>,<T4,N>>)
	  CALL MEIHNG		;RESET AND REENABLE THE MEIS
	ENDIF.
MEICH1:	CALL MEIMNT		;CHECK MAINTENANCE MODE STATUS
	IOPION			;REALLOW INTERRUPTS
MEICH2:	AOBJN P4,MEICH0		;LOOP OVER ALL MEIS'S
MEICH3:	MOVEI T1,^D60000	;CHECK IN 60 SECONDS
	MOVEM T1,MEITIM		;RESET MEIS TIMER
	RET			;RETURN TO CALLER
SUBTTL INTERRUPT PROCESSING

;HERE TO HANDLE DEVICE ATTENTIONS

MEIATN:	MOVE P3,MEKUDB(P2)	;GET ACTIVE UDB
	JUMPE P3,MEIATR		;NONE - SEE WHAT HAPPENED
	MOVE T2,UDBSTS(P3)	;GET STATUS OF DRIVE
	TXNN T2,US.ACT		;EXPECTING AN INTERRUPT FROM THIS DEVICE?
	 JRST MEIATR		;NO - SEE WHAT HAPPENED
	CALL SETIRB		;YES - GET ACTIVE IORB
	CALL MEICON		;SELECT THIS NET INTERFACE
	MOVX T2,DO.SR		;READ STATUS REGISTER
	CALL RDREG		; ...
	SKIPE T2,UDBERR(P3)	;IN ERROR RECOVERY?
	 JRST ERRATN		;YES, HAVE TO USE A DISPATCH ADDRESS
	TXNE T1,DS.ROV		;OVERFLOW?
	 AOS MEUROV(P3)		;YES, COUNT IT
	TXNE T1,DS.ERR!DS.ROV	;NO, ERROR?
	 JRST MEIATE		;YES
;HERE ON ATTENTION INTERRUPT WITH NO ERRORS
;WE CAN GET HERE IF AN ATTENTION CONDITION COMES UP DURING OR JUST AFTER
;THE END OF A TRANSFER. SET MEKATS NON-NEGATIVE AS A FLAG TO MEIINT. WHEN
;THIS FLAG IS SET MEIINT WILL DO THE SECOND PART OF ATTENTION PROCESSING
;AFTER THE TRANSFER TERMINATION LOGIC
	MOVEM T1,MEKATS(P2)	;FLAG SPECIAL ACTION NEEDED
ATNX0:	MOVEI P4,0		;NO SPECIFIC IORB TO RETURN
MEICLA:				;CLEAR ATTENTION, CALLED AS A SUBR
ATNXIT:	MOVEI T2,1		;POSITION OUR BIT
	HRRZ T1,MEKADR(P2)	;WITH OUR UNIT ADDRESS
	ROT T2,(T1)		; ...
	HRLI T2,(DO.AS)		;BUILD DATAO
	CALLRET WTREGX		;AND CLEAR OUR ATTENTION BIT

MEIATE:	HRRZ T3,UDBAKA(P3)	;ERROR - GET UNIT #
	CAMN T3,CDBXFR(P1)	;SAME UNIT AS TRANSFER?
	JRST ATNX0		;YES - ERROR ON XFERING UNIT (IGNORE)
				; WILL HANDLE LATER IN XFER INTERRUPT CODE
;HERE IF AN ERROR ON A NON-TRANSFERRING DRIVE
	MOVX T1,IS.ERR!IS.NRT	;FLAG ERROR IN IORB
	IORM T1,IRBSTS(P4)	; ...
	TLO P4,-1		;SET SEEK ERROR FLAG
	CALLRET MEIHNG		;RESET DEVICE AND RETURN TO CHANNEL

;HERE ON ATTENTION INTERRUPT IF DRIVE IS IN ERROR RECOVERY

ERRATN:	MOVE T1,UDBERR(P3)	;GET FUNCTION BEING PERFORMED
	SKIPL T1,MEIFCN(T1)	;GET DISPATCH ADDRESS
	JRST (T1)		;GO PROCESS THE INTERRUPT
	JRST ATNX0		;DATA TRANSFER FUNCTION - DEFER
;HERE ON AN ATTENTION INTERRUPT WHEN THE DEVICE IS NOT ACTIVE
;ALSO CALLED AS A SUBROUTINE FROM MEIINT WHEN AN ATTENTION WAS NOTICED
;AT THE END OF A TRANSFER.
;THIS ROUTINE CHECKS EACH NET INTERFACE FOR RECEIVED PACKETS AND PROCESSES
;ALL THAT CAN BE PROCESSED AT INTERRUPT LEVEL. THE REMAINING (AT MOST ONE PER
;NET INTERFACE)PACKETS HAVE TO BE SENT DOWN THE CHANNEL

;CALLED UNDER CONTROLLED CIRCUMSTANCES
;	CALL MEIATR
;RETURNS+1(ALWAYS):
;ALL NI ATTENTION CONDITIONS PROCESSED AND ATTENTION CLEARED
;MODIFIES P3,P4,Q1 (SO SAVE THEM IF YOU CARE!!)

MEIATR:	CALL MEICLA		;CLEAR ATTENTION
	SKIPE P3,KDBUDB+0(P2)	;GET UDB FOR INTERFACE 0
	 CALL MEIATU		;EXAMINE IT
	SKIPE P3,KDBUDB+1(P2)	;GET UDB FOR INTERFACE 1
	 CALL MEIATU		;EXAMINE IT
	SKIPN P3		;SKIP IF WE HAVE A UDB POINTER
	 MOVE P3,KDBUDB+0(P2)	;WAS NO UDB FOR 1, PRESUMABLY WE HAVE ONE FOR 0
	MOVX T2,DO.SR		;READ STATUS REGISTER NOW
	CALL RDREG		; ...
	TXNE T1,DS.ATA		;ATTENTION STILL UP?
	 JRST MEIATR		;YES, GO SCAN INTERFACES AGAIN
	RET			;RETURN TO CALLER
;MEIATU - EXAMINE A SINGLE NETWORK INTERFACE FOR ATTENTION CONDITIONS
;P1,P2,P3 SET UP
;RETURNS +1 ALWAYS

MEIATU:	PUSH P,[0]		;SIMULATE STKVAR FOR SPEED
	CALL MEICON		;SELECT THE INTERFACE
MEIAT0:	MOVX T2,DO.SR		;READ STATUS REGISTER
	CALL RDREG		; ...
	MOVEM T1,0(P)		;SAVE STATUS BITS
	TXNE T1,DS.ROV		;OVERFLOW?
	 AOS MEUROV(P3)		;YES, COUNT IT
	TXNE T1,DS.ERR!DS.ROV	;COMPOSITE ERROR OR RECEIVER OVERFLOW UP?
	 JRST MEIAT2		;YES, GO CLEAR IT AND RETURN
	TDNN T1,MEURPK(P3)	;ATTN DUE TO PACKET AVAILABLE?
	 JRST MEIAT4		;NO, SOMETHING ELSE.
	CALL MEIPRP		;PROCESS RECEIVED PACKET
	 AOSA MEUFLS(P3)	;DONE - FLUSH IT AFTER COUNTING IT
	  JRST MEIAT1		;PACKET QUEUED, LOOK AT OTHER CONDITIONS
	MOVE T2,[EXP DO.CR!DF.FRP] ;FLUSH PACKET
	CALL WTREG		; ...
	JRST MEIAT0		;LOOP FOR MORE PACKETS

MEIAT1:	SKIPA T1,0(P)		;LOAD SAVED STATUS AND SKIP
MEIAT2:	 CALL MEIHNG		;CLEAR ERROR, RETURN NEW STATUS IN T1
MEIAT4:	TDNN T1,MEUXAV(P3)	;TRANSMIT BUFFER AVAILABLE?
	 JRST MEIATX		;NO - GO CLEAN UP AND EXIT
	MOVX T2,US.REW		;YES - CLEAR REWIND
	TDNN T2,UDBSTS(P3)	;NOW UP?
	JRST MEIATX		;NO - DO NOTHING
	TLO Q1,-1		;YES - FLAG CHAN SCHED CYCLE NEEDED
	ANDCAM T2,UDBSTS(P3)	;AND CLEAR IN UDB
MEIATX:	ADJSP P,-1		;ADJUST STACK
	RET			;RETURN TO CALLER
;MEIPRP - PROCESS A RECEIVED PACKET
;RETURNS NONSKIP IF PACKET IS DONE, ELSE QUEUES IORB AND SKIPS.
;NOTE: ONLY ONE READ CAN BE IN PROGRESS AT ANY TIME - THE PACKET LOOKAHEAD
; ONLY PEEKS AT THE TOP PACKET.

MEIPRP:	AOS T1,MEICNT		;COUNT AN INTERRUPT
	CAIL T1,^D5000		;TOO MUCH TIME AT INTERRUPT LEVEL?
	 JRST MEIPR2		;YES, NET IS BUSTED.  GO RESET WORLD.
	SKIPE MEURIQ(P3)	;IS THERE A READ QUEUED UP ON THIS INTERFACE
	 RETSKP			;YES, HAVE TO PUNT
	MOVX T2,DO.RS		;GET LENGTH HW SAW
	CALL RDREG		; ...
	TXNE T1,RS.CRC!RS.OFL	;ERRORS? (3MB INTERFACE ONLY)
	 JRST MEIPR0		;YES, HANDLE SPECIALLY
	ANDI T1,RS.PLM		;NO ERRORS - MASK LENGTH
	HRRZ T2,MEUFLG(P3)	;GET MINIMUM LEGAL PACKET LENGTH
	CAIGE T1,(T2)		;SKIP IF INTERFACE GAVE US A REASONABLE PACKET
	 JRST MEIPR1		;HANDLE SMALL PACKETS SPECIALLY
	PUSH P,T1		;SAVE LENGTH ON STACK
	MOVE T2,[EXP DO.RA!7]	;ASSUME 10MB INTERFACE
	MOVE T3,MEUFLG(P3)	;GET FLAG WORD
	TXNN T3,MU%10M		;WAS ASSUMPTION CORRECT?
	 MOVE T2,[EXP DO.RA!1]	;NO, IT'S A 3MB INTERFACE
	CALL WTREG		;SET ADDRESS COUNTER
	MOVX T2,DO.RBD		;AND READ THE PACKET TYPE WORD
	CALL RDREG		; ...
	MOVE T2,T1		;PASS UP PACKET TYPE IN T2
	POP P,T1		;PACKET LENGTH IS PASSED IN T1
IFE REL6,<CALL ETHRCI>		;HIGHER LEVELS FIGURE OUT WHAT TO DO WITH IT
IFN REL6,<XCALL (XCDSEC,ETHRCI)> ;HIGHER LEVELS FIGURE OUT WHAT TO DO WITH IT
	 RET			;FLUSH PACKET FROM RAM
	CALL ONTWQ		;IORB IN T1, APPEND TO TWQ
	TLO Q1,-1		;INDICATE CHAN SCHED NEEDED
	SETOM MEURIQ(P3)	;INDICATE READ IN QUEUE
	RETSKP			;SKIP RETURN TO CALLER
;HERE WHEN THE PACKET IS SMASHED OR HAS A BAD CRC (3MB ONLY) OR IF THE
; PACKET IS ABNORMALLY SMALL.

MEIPR0:	AOSA MEUERR(P3)		;COUNT A SMASHED OR BAD CRC PACKET
MEIPR1:  AOS MEUSIZ(P3)		;COUNT A BAD PACKET SIZE
	RET			;FLUSH THE PACKET

;HERE WHEN WE COUNTED TOO MANY INTERRUPTS WITHIN ONE 100 MS. TIME PERIOD.
; THIS USUALLY HAPPENS IF THE NET HARDWARE IS BROKEN.  RATHER THAN SPEND ANY
; MORE TIME AT INTERRUPT LEVEL, WE BLAST BOTH INTERFACES WITH A MAINTENANCE
; MODE RESET.  WE CLEAR MEITIM WHICH WILL INVOKE MEICHK TO RESTART THE ACTIVE
; INTERFACES.

MEIPR2:	CALL MEIHNG		;RESET THE INTERFACE (FIX UP SOFTWARE FLAGS)
	MOVE T2,[DO.MR!MR.EN!MR.INI]	;MASTER RESET OF CONTROLLER
	CALL WTREG		;WIPE STATE OF BOTH INTERFACES
	SETZM MEITIM		;SCHEDULER WILL RESTART THE INTERFACES
	BUG.(INF,MEIRST,PHYMEI,SOFT,<MEIS controller reset>,<<P2,P2>>)
	RETSKP			;PRETEND WE READ A PACKET
;MEIRTL - READ TRAILING 16-BIT WORD OF THE CURRENT ETHERNET PACKET
;TAKES	T1/ LENGTH OF PACKET IN BYTES
;	T2/ CDB,,UDB
;RETURNS +1 ALWAYS, T1/ 16-BITS OF DATA

	XRESCD

MEIRTL::SAVEP			;PRESERVE THE P REGISTERS
	HLRZ P1,T2		;CDB ADDRESS
	HRRZ P3,T2		;UDB ADDRESS
	MOVE P2,UDBKDB(P3)	;KDB ADDRESS 
	ADDI T1,1		;ROUND UP USER'S COUNT
	LSH T1,-1		;CONVERT TO 16-BIT WORDS
	MOVX T2,DO.RA		;WRITE ADDRESS REGISTER
	IORI T2,-1(T1)		;CALCULATE RELATIVE OFFSET OF LAST WORD
	CALL WTREG		;SET RAM POINTER AT DESIRED WORD
	MOVX T2,DO.RBD		;READ A WORD FROM THE RECEIVER BUFFER
	CALL RDREG		; ...
	RET			;RETURN, T1/ DESIRED WORD

	RESCD
;MEIRHD - READ LEADING BYTES FROM PACKET INTO A USER BUFFER
;ASSUMES HIGHER LEVELS ARE USING 32-BIT HEADER MODE
;TAKES	T1/ GLOBAL (EXTENDED) ADDRESS OF BUFFER
;	T2/ CDB,,UDB
;	T4/ BYTES TO READ INTO BUFFER
;USES P4 AND P5 AS A DOUBLE-WORD GLOBAL BYTE POINTER
;RETURNS +1 ALWAYS

	XRESCD

MEIRHD::SAVEP			;WE WIPE MOST OF THE P REGISTERS
	HLRZ P1,T2		;CDB ADDRESS
	HRRZ P3,T2		;UDB ADDRESS
	MOVE P2,UDBKDB(P3)	;KDB ADDRESS 
	SKIPG T4		;RANGE CHECK
	 BUG.(HLT,MEIHDR,PHYMEI,SOFT,<Bad arg to MEIRHD>,<<T4,DATA>>)
	ADDI T4,1		;ROUND USER BYTE COUNT UP
	LSH T4,-1		;CONVERT TO 16-BIT WORDS
	MOVSI P4,442040		;"POINT 16," WITH GLOBAL BIT SET
	MOVE P5,T1		;SET UP ADDRESS PORTION OF BYTE POINTER
	MOVX T2,DO.RA		;SET ADDRESS COUNTER TO WORD ZERO
	CALL WTREG		; ...
MEIRH0:	MOVX T2,DO.RBD		;AND READ
	CALL RDREG		; ...
	IDPB T1,P4		;STORE
	SOJG T4,MEIRH0		;DONE?
	RET			;RETURN TO CALLER

	RESCD
;HERE ON DATA TRANSFER DONE INTERRUPTS

MEIINT:	SKIPN P3,MEKUDB(P2)	;HAVE A CURENT UDB?
	 JRST MEIBDD		;BAD DONE INT
	SETZM MEKUDB(P2)	;CLEAR ACTIVE UDB
	CALL SETIRB		;SET POINTER TO CURRENT IORB IN P4
	CALL CHKRH		;CHECK CHANNEL FOR ERRORS
	 JRST MEIIER		;ERRORS, GO RESET THE WORLD
	CALL CHKMEI		;SELECT MEIS AND CHECK FOR ERRORS(STATUS IN T1)
	 JRST MEIIER		;ERRORS, GO RESET WORLD
	LDB T2,IRYFCN		;GET FUNCTION
	CAIE T2,IRFRED		;READ?
	IFSKP.
	  SETZM MEURIQ(P3)	;CLEAR READ IN QUEUE FLAG
	  AOS UDBRED(P3)	;UPDATE READ COUNT
	  AOS UDBRCT(P3)	; ...
	ELSE.
  	  AOS UDBWRT(P3)	;UPDATE WRITE COUNT
	  AOS UDBWCT(P3)	; ...
	ENDIF.
	TXNE T1,DS.RP0!DS.RP1	;PACKETS TO PROCESS IN EITHER NI (STATUS IN T1)
	JRST MEIIN2		;YES - ACT AS IF ATTN HAPPENED
	SKIPGE MEKATS(P2)	;WAS THERE AN ATTENTION EARLIER IN THE DONE?
	 JRST MEIIN3		;NO - CHECK TRANSMIT BUFFER AVAILABLE
MEIIN2:	PUSH P,P3		;YES - SAVE UDB
	PUSH P,P4		;SAVE IORB
	PUSH P,Q1		;SAVE Q1
	CALL MEIATR		;CALL 2ND PART OF ATTENTION INTERRUPT
	POP P,Q1		;RESTORE Q1
	POP P,P4		;RESTORE P4
	POP P,P3		;RESTORE P3
	SETOM MEKATS(P2)	;NOTHING MORE TO DO
	CALL MEICON		;MUST RE-SELECT THIS NI
	MOVX T2,DO.SR		;READ STATUS AGAIN
	CALL RDREG		; ...
MEIIN3:	TDNE T1,MEUXAV(P3)	;TRANSMIT BUFFER AVAILABLE?(STATUS STILL IN T1)
	 JRST MEIIN5		;YES - NOTHING MORE TO DO
;THE TRANSMIT BUFFER IS NOT AVAILABLE.  TO PREVENT PHYSIO FROM TRYING TO
;TO SCHEDULE A WRITE AT THE END OF THIS DONE INTERRUPT, WE MUST SET US.REW
;IF THE NEXT IORB IN THE TWQ IS INDEED A WRITE OR IF THERE IS NO IORB.
	MOVX T1,US.REW		;NO - GET FLAG
	HRRZ T3,IRBLNK(P4)	;LOOK AT SUCCESSOR IORB
	JUMPE T3,MEIIN4		;NONE
	EXCH T3,P4		;NEED TO LOOK AT FUNCTION
	LDB T2,IRYFCN		;GET FUNCTION
	EXCH T3,P4		;RESTORE
	CAIE T2,IRFRED		;A READ?
MEIIN4:  IORM T1,UDBSTS(P3)	;NO, A WRITE - MUST ACT BUSY
MEIIN5:	RETSKP			;ALL DONE
;CHKRH - CHECK RHXX CHANNEL FOR ERRORS
;TAKES	P1/ ADDRESS OF CDB
;RETURNS +1 ERROR
;	 +2 NO ERRORS
;CLOBBERS T1,T2

CHKRH:	CALL CKERR		;CALL CHANNEL INDEPENDENT CHECKING ROUTINE
	 TRNA			;SOME ERRORS, GO REPORT THEM
	  RETSKP		;ALL GOOD, SKIP RETURN
	MOVE T1,CDBCNI(P1)	;GET CONI AT INTERRUPT
	HRRZ T2,CDBICP(P1)	;GET POINTER TO CHANNEL LOGOUT AREA
	MOVE T2,1(T2)		;GET STATUS BITS FROM LOGOUT AREA 
	BUG.(CHK,MEIRHX,PHYMEI,HARD,<RH20/MEIS error>,<<T1,CNI>,<T2,LGT>>)
	RET			;TAKE FAILURE RETURN

;CHKMEI - SELECT AND CHECK MEIS DEVICE FOR ERRORS
;RETURNS(+1):
; ERROR CONDITION, CLOBBERS T1-T3
;RETURNS(+2):
; MEIS NI IS GOOD, STATUS IN T1, T2-T3 CLOBBERED

CHKMEI:	MOVE T1,UDBSLV(P3)	;GET INTERFACE NUMBER
	LSH T1,3		;SET APPROPRIATE INTERFACE BIT
	MOVX T2,DO.MD		;WE WRITE THE MODE REGISTER
	IOR T2,T1		;SET NI NUMBER
	CALL WTREG		;SELECT THE NI
	MOVX T2,DO.SR		;READ STATUS REGISTER
	CALL RDREG		; ...
	TXNE T1,DS.ROV		;OVERFLOW?
	 AOS MEUROV(P3)		;YES, COUNT IT
	TXNN T1,DS.ERR!DS.ROV	;ERROR OR RECEIVER OVERFLOW?
	RETSKP			;NO, TAKE GOOD RETURN
	PUSH P,T1		;SAVE STATUS BITS
	MOVX T2,DO.ER		;ERROR REGISTER
	CALL RDREG		;READ IT
	POP P,T2		;RESTORE STATUS REGISTER BITS
	BUG.(CHK,MEIDVX,PHYMEI,HARD,<MEIS termination error>,<<T2,S>,<T1,E>>)
	RET			;TAKE FAILURE RETURN

;RECOVER FROM AN ERROR DETECTED AT TRANSFER TERMINATION
;COMMON HANDLING FOR CHKRH AND CHKMEI ERROR RETURNS

MEIIER:	CALL CLRCHL		;RESET CHANNEL
	CALL MEIHNG		;RESET INTERFACE
	MOVX T1,IS.ERR!IS.DTE!IS.NRT ;CALL IT A DATA ERROR, DON'T RETRY
	IORM T1,IRBSTS(P4)	;SET ERROR FLAGS IN IORB STATUS WORD
	RET			;AND HOPE FOR ERROR RECOVERY

;HERE WHEN A DONE INTERRUPT WITH NO UDB ACTIVE

MEIBDD:	BUG.(CHK,PMEBDD,PHYMEI,HARD,<MEIS done interrupt with no active UDB>)
	RET
;FUNCTION TABLE

MEIFCN:	0		;0 - ILLEGAL
	DF.RED		;1 - READ
	0		;2 - ILLEGAL (READ FORMAT)
	DF.WRT		;3 - WRITE

MXEFCN==.-MEIFCN-1	;MAXIMUM EXTERNAL FUNCTION
MXFCN==.-MEIFCN-1	;MAXIMUM FUNCTION

	TNXEND
	END