Google
 

Trailing-Edge - PDP-10 Archives - BB-F493Z-DD_1986 - 10,7/703mon/rnxkon.mac
There are 8 other files named rnxkon.mac in the archive. Click here to see a list.
TITLE	RNXKON -- DRIVER FOR RP20'S  V050
SUBTTL	G.M. UHLER/GMU   10 SEP 85
	SEARCH	F,S,ICHPRM
	$RELOC
	$HIGH



;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
.CPYRT<1980,1986>
;COPYRIGHT (C) 1980,1982,1984,1986
;BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;ALL RIGHTS RESERVED.


;
XP VRNKON,050
SALL


;ASSEMBLY INSTRUCTIONS:
;	.R MACRO
;	*RNXKON,RNXKON/C=KONPAR,RNXKON

RNXKON::ENTRY	RNXKON


;NOTE THAT LABELS OF THE FORM RNXBP? ARE USED BY THE RP20 TRACE
;PROGRAM FOR SNOOP. BREAKPOINTS.  DO NOT REMOVE THESE LABELS.


;TECHNICAL INFORMATION AND TECHNIQUES FOR PROGRAMMING THE
;RH20/DX20/RP20 ARE AVAILABLE IN THE FOLLOWING DOCUMENTS:
;
;  FUNCTIONAL SPECIFICATION FOR DX20-V210 MICRO CODE,
;	AUG 79
;  DX20 PROGRAMMED DEVICE ADAPTER TECHNICAL MANUAL,
;	DOCUMENT NUMBER EK-0DX20-TM-001, FEB 78
;  RH20 MASSBUS CONTROLLER UNIT DESCRIPTION,
;	DOCUMENT NUMBER EK-RH20-UD-001, AUG 76
;  DX20-V210 RP20 DISK SUBSYSTEM MICRO-CODE,
;	DOCUMENT NUMBER MAINDEC-10-DXMCD-A, AUG 79
	SUBTTL	RH20/DX20 DEVICE DEPENDENT REGISTER/BIT DEFINITIONS


.DXCTR==00B5			;CONTROL REGISTER
	CR.IGN==1B14		;BIT SET IN UNILAS TO INDICATE THAT THIS
				; COMMAND WAS TOSSED
	CR.FNC==76B35		;FUNCTION CODE
		.CRNOP==01	;NO-OP
		.CRRCL==07	;RECALIBRATE
		.CRSRC==31	;SEARCH
		.CRWRT==61	;WRITE DATA
		.CRWTF==63	;WRITE FORMAT
		.CRRED==71	;READ DATA
		.CRRDF==73	;READ FORMAT
	CR.IOP==40B35		;BITS TELLING THAT THIS OPERATION WAS
				;  AN I/O FUNCTION
	CR.RED==10B35		;BIT TELLING THAT THIS I/O OPERATION WAS
				;  A READ
	CR.GO==1B35		;GO BIT

.DXSTR==01B5			;STATUS REGISTER
	ST.CER==1B21		;COMPOSITE ERROR
	ST.RUN==1B23		;MICROPROCESSOR RUNNING

.DXERR==02B5			;ERROR REGISTER
	ER.SCC==17B23		;ERROR SUB CLASS CODE
	ER.ECC==17B27		;ERROR CLASS CODE
		.ERSEL==3	;DEVICE SELECT ERROR
	ER.UPE==1B28		;MICROPROCESSOR ERROR
	ER.STP==1B29		;MICROPROCESSOR STOPPED
	ER.MPE==1B30		;MICRO BUS PARITY ERROR
	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
	ER.ERR==ER.MPE!ER.DPE!ER.CPE!ER.RMR!ER.ILR!ER.ILF

.DXMTR==03B5			;MAINTENANCE REGISTER
	MR.SCY==1B31		;MICROPROCESSOR SINGLE CYCLE
	MR.STR==1B33		;MICROPROCESSOR START
	MR.RES==1B34		;MICROPROCESSOR RESET

.DXASR==04B5			;ATTENTION SUMMARY REGISTER
	AT.ATN==377B35		;THE ATTENTION BITS

.DXDAR==05B5			;DESIRED ADDRESS REGISTER (TRACK/SECTOR)
	DA.TRK==377B27		;TRACK
	DA.SEC==377B35		;SECTOR
.DXDTR==06B5			;DRIVE TYPE REGISTER
	DT.COD==777B35		;DRIVE TYPE
		.DTCOD==061	;CODE FOR DX20

.DXESR==20B5			;ENDING STATUS REGISTER
	ES.STM==1B21		;STATUS MODIFIER
	ES.CUE==1B22		;CONTROL UNIT END
	ES.BSY==1B23		;BUSY
	ES.CHE==1B24		;CHANNEL END
	ES.DVE==1B25		;DEVICE END
	ES.UCK==1B26		;UNIT CHECK
	ES.UEX==1B27		;UNIT EXCEPTION
	ES.SUI==1B28		;STATUS UPDATE INTERLOCK
	ES.IDX==177B35		;STATUS INDEX
		.ESSB0==0	;INDEX TO GET SENSE BYTE 0(-3)
		.ESSB7==1	;INDEX TO GET SENSE BYTE (4-)7

.DXASY==21B5			;ASYNCHRONOUS STATUS REGISTER
	AS.DVS==377B27		;DRIVE STATUS
	AS.DRV==377B35		;DRIVE NUMBER
	AS.UNF==17B35		;UNIT NUMBER

.DXFLG==22B5			;FLAGS/ARGUMENT
	FA.RTY==1B23		;COMMAND RETRY
	FA.FNC==377B35		;FUNCTION FOR SENSE/NOOP
		.FATIO==0	;CODE FOR TEST I/O

.DXDNM==23B5			;DRIVE NUMBER REGISTER
	DN.CUA==17B31		;CONTROL UNIT ADDRESS
	DN.DRV==17B35		;DRIVE NUMBER

.DXDCR==24B5			;DESIRED CYLINDER REGISTER

.DXES1==26B5			;EXTENDED STATUS REGISTER 1

.DXES2==27B5			;EXTENDED STATUS REGISTER 2

.DXMIR==30B5			;MICROCONTROLLER INSTRUCTION REGISTER

.DXPCR==31B5			;MICROPROCESSOR PC REGISTER
	PC.IRE==1B20		;INSTRUCTION REGISTER ENABLE
	PC.MSE==1B21		;MICROSTORE ENABLE
	PC.PCE==1B22		;PC ENABLE
	PC.PCI==1B23		;PC AUTO INCREMENT
	PC.MPC==7777B35		;MICROPROCESSOR PC

.DXIPE==37B5			;DIAGNOSTIC REGISTER 7
	DX.IPE==1B22		;INSTRUCTION REGISTER PARITY ERROR
;SENSE BYTE DEFINITIONS

S0.CRJ==1B2		;COMMAND REJECT
S0.IRQ==1B3		;INTERVENTION REQUIRED
S0.BOP==1B4		;CHANNEL BUS OUT PARITY
S0.EQC==1B5		;EQUIPMENT CHECK
S0.DTC==1B6		;DATA CHECK
S0.OVR==1B7		;OVERRUN
S1.PER==1B10		;PERMANENT ERROR
S1.ITF==1B11		;INVALID TRACK FORMAT
S1.ECY==1B12		;END OF CYLINDER
S1.NRF==1B14		;NO RECORD FOUND
S1.FPR==1B15		;FILE PROTECTED
S1.WRI==1B16		;WRITE INHIBITED
S1.OPI==1B17		;OPERATION INCOMPLETE


DEFINE	HEX(SYM,VAL),<
	SYM==0
	IRPC VAL,<
	  SYM==SYM*^D16
	  IFLE <"VAL"-"9">,<SYM==SYM+"VAL"-"0">
	  IFG  <"VAL"-"9">,<SYM==SYM+"VAL"-"A"+^D10>
	>
>

HEX(.S7ECC,53)		;SENSE BYTE 7 CODE INDICATING ECC RECOVERABLE ERROR


;RH20 CONI/CONO/LOGOUT AREA BIT DEFINITIONS

CI.ERR==CI.DBP!CI.LWC!CI.DRE!CI.RAE!CI.OVR
			;ALL CONI ERROR BITS
CO.CLR==CO.RAE!CO.TEC!CO.CCD	;CONO BITS TO CLEAR ERRORS
CS.ERR==CS.MPE!CS.NAE!CS.NXM!CS.RHE!CS.LWC!CS.SWC!CS.OVR
			;ALL CHANNEL LOGOUT AREA ERROR BITS
	SUBTTL	KONEBK/UNIEBK BLOCK OFFSETS


;OFFSETS IN THE KONEBK AND UNIEBK BLOCKS FOR THE RP20.  DAEMON KNOWS
;ABOUT THESE OFFSETS SO IF YOU CHANGE THEM, BE SURE TO CHANGE DAEMON
;ALSO.  IF YOU CHANGE THE LENGTH OF THIS BLOCK, YOU MUST ALSO MAKE
;THE CORRESPONDING CHANGE IN THE DATA BLOCK GENERATION MACROS IN COMMOD.
;
;FIRST DEFINE THE SYMBOLS USED IN RNXKON FOR THE OFFSETS.

.EBNMR==RNVNMR		;NUMBER OF MASSBUS REGISTERS (DEFINED BY MBRLST)
.EBNDR==^D24		;NUMBER OF DRIVE REGISTERS

.EBTYP==0		;BYTE (9) DX20 ADDR(9)0(18) MICROCODE VERSION
.EBCS0==1		;CHANNEL LOGOUT 0
.EBCS1==2		;CHANNEL LOGOUT 1
.EBCS2==3		;CHANNEL LOGOUT 2
.EBCC1==4		;FIRST CCW
.EBCC2==5		;SECOND CCW
.EBMPE==6		;COUNT OF MPE
.EBNXM==7		;COUNT OF NXM
.EBMBR==10		;+LEN,,OFFSET FROM . OF MASSBUS REGISTERS
.EBDVL==11		;+LEN,,OFFSET FROM . OF DEVICE REGISTERS
.EBSMR==12		;START OF MASSBUS REGISTER BLOCK
.EBSTR==.EBSMR+1	;WHERE STATUS REGISTER IS STORED
.EBERR==.EBSMR+2	;WHERE ERROR REGISTER IS STORED
.EBESR==.EBSMR+7	;WHERE ENDING STATUS REGISTER IS STORED
.EBSDR==.EBSMR+.EBNMR	;START OF DEVICE REGISTER BLOCK
.EBS07==.EBSDR+1	;WORD CONTAINING SENSE BYTE 7
	EB.S07==377B35	;POSITION OF SENSE BYTE 7
.EBS18==.EBSDR+4	;WORD CONTAINING SENSE BYTES 18 AND 19
	EB.S18==177777B35 ;POSITION OF SENSE BYTES 18 AND 19
.EBS20==.EBSDR+5	;WORD CONTAINING SENSE BYTES 20 AND 21
	EB.S20==177777B17 ;POSITION OF SENSE BYTES 20 AND 21
.EBICR==.EBSDR+.EBNDR	;CONTENTS OF INITIAL CONTROL REGISTER


;NOW DEFINE THE VALUES THAT THE REST OF THE MONITOR USES TO INTERFACE
;TO THIS BLOCK.

RNVEBK==:.EBICR		;LENGTH OF THE ???EBK BLOCK
RNVSMR==:.EBSMR 	;OFFSET OF START OF MASSBUS REGISTERS IN KONEBK/UNIEBK
	SUBTTL	DATA STRUCTURE FIELD AND BYTE POINTER DEFINITIONS


RNXMVR==:300,,1		;MINIMUM MICROCODE VERSION ALLOWED

;FIELDS IN RNXFLG(J)

RN.DCU==1B0		;KNOW THE DCU CONTROLLER ADDRESS
			;MUST BE SIGN BIT FOR SKIPL
RN.UPA==:1B1		;BEEN THROUGH RNXUPA ONCE FOR THIS CONTROLLER
RNPUPA==:(RN.UPA)	;PUBLISH THIS SYMBOL FOR THE REST OF THE MONITOR
RN.FKA==1B2		;FOUND THE DX20 MASSBUS ADDRESS FOR THIS CONTROLLER
RN.FTL==1B3		;LAST TRANSFER ERROR WAS FATAL
RN.CLR==RN.FTL		;BITS TO CLEAR IN CONECT
RN.DCA==17B31		;4 BITS OF DCU ADDRESS (SUBFIELD OF RN.CUA)
RN.DXN==7B35		;DX20 ADDRESS (MASSBUS SLOT)


;BYTE POINTERS TO ABOVE FIELDS

RNYDCA::POINTR	RNXFLG##(J),RN.DCA ;DCU ADDRESS
RNYDXN::POINTR	RNXFLG##(J),RN.DXN ;DX20 ADDRESS


;FIELDS IN RNXCMD(J)

CM.FNC==77B5		;FUNCTION ISSUED TO DRIVE (I.E., BITS 30-35
			;  OF DATAO TO CONTROL REGISTER OR STCR)
CM.XFR==1B0		;THIS FUNCTION CAUSES A DATA TRANSFER
CM.IO==1B2		;1=READ, 0=WRITE
CM.HNG==1B6		;THIS INTERRUPT CAME THROUGH RNXSTP
CM.DVA==377B35		;DEVICE ADDRESS FOR THIS OPERATION
CM.UNF==17B35		;4 BIT UNIT NUMBER
;MISCELLANEOUS PARAMETER DEFINITIONS

.CRM10==210			;CONTENTS OF CRAM LOCATION 10
.DXSAD==5			;DX20 RESTART ADDRESS
MAXRSC==^D8			;NUMBER OF TIMES TO SIMPLY RESTART THE
				;  DX20 WHEN WE DISCOVER THAT IT STOPPED
				;  BEFORE SIMPLY CALLING IT DEAD
RTYNUM==^D24			;NUMBER OF RETRIES TO DO IN ERROR RECOVERY
ATNRTY==^D10			;NUMBER OF TIMES TO RETRY CLEARING AN
				;  ATTENTION BIT FOR A DX20 THAT WE KNOW
				;  ABOUT BEFORE RESORTING TO A MASSBUS
				;  INIT TO CLEAR IT
ALLERR==777770B35		;ALL POSSIBLE ERROR BITS SET BY INTERRUPT
				;SERVICE IN THE COMMUNICATIONS WORD
MAXDCU==^D16			;MAXIMUM NUMBER OF DCU ADDRESSES WE
				;  CAN HAVE ON A DX20
MAXSPD==^D16			;MAXIMUM NUMBER OF SPINDLES WE CAN HAVE
				;  ON A DCU
	SUBTTL	MACRO DEFINITIONS


;MACRO TO COMPUTE THE WIDTH OF A MASK
;	"WID" RETURNS THE LENGTH OF THE LEFTMOST STRING OF
;	CONSECUTIVE ONES IN THE WORD.

DEFINE	WID(MASK),<<^L<-<<MASK>_<^L<MASK>>>-1>>>

;MACRO TO COMPUTE THE POSITION OF A MASK

DEFINE	POS(MASK),<<^L<MASK>+^L<-<<MASK>_<^L<MASK>>>-1>-1>>

;MACRO TO BUILD A POINTER TO A MASKED QUANTITY
;	POINTR	LOCATION,MASK

DEFINE	POINTR(LOC,MASK),<<POINT WID(MASK),LOC,POS(MASK)>>

;MACRO TO LOAD AN ARBITRARY BYTE FROM A LOCATION INTO AN AC.
;	LOAD	AC,LOC,MASK

DEFINE	LOAD(A,B,C),<.LDST.(A,B,C,HRRZ,HLRZ,LDB,MOVE)>

;MACRO TO STORE AN ARBITRARY BYTE FROM AN AC INTO A LOCATION
;	STORE	AC,LOC,MASK

DEFINE	STORE(A,B,C),<.LDST.(A,B,C,HRRM,HRLM,DPB,MOVEM)>

;UTILITY MACRO USED BY LOAD AND STORE

DEFINE	.LDST.(A,B,C,D,E,F,G),<
	IFNB	<C>,<..T==0
		IFE	C-777777,<..T==1
			D	A,B>
		IFE	C-777777000000,<..T==1
			E	A,B>
		IFE	..T,<F	A,[POINTR(B,C)]>>
	IFB	<C>,<G	A,B>
>  ;END OF DEFINE .LDST.

;MACRO TO INSERT A VALUE IN A MASKED FIELD
;	INSVL.(VALUE,MASK)

DEFINE INSVL.(VALUE,MASK),<<<<VALUE>B<POS(<MASK>)>>&<MASK>>>
;MACRO TO WAIT AWHILE.  USED IN DODTI TO GIVE THE DRIVE TIME TO
;RESPOND WITH THE VALUE OF THE EXTERNAL REGISTER.

DEFINE	STALL, <
	IMULI	T2,1
	XLIST
	IMULI	T2,1
	LIST
>

;MACRO TO DEFINE THE MASSBUS REGISTERS TO SAVE IN THE KDB WHEN AN
;ERROR IS DETECTED.  ARGUMENT IS A LIST OF THE OCTAL MASSBUS REGISTER
;NUMBERS TO SAVE.  THE TOTAL NUMBER OF REGISTERS MUST NOT EXCEED ^D36.

DEFINE	MBRLST	(LST), <
	..CNT==0	;START WITH 0 REGISTERS
	MBRTBL==0	;AND WITH NO BITS
	IRP LST, <
	   IFE <LST-0>,<.EBM00==..CNT>
	   IFE <LST-30>,<.EBM30==..CNT>
	   ..CNT==..CNT+1 ;BUMP NUMBER BY 1
	   MBRTBL==MBRTBL!<1_<^D35-LST>> ;SET BIT IN TABLE
	> ;END IRP LST
	RNVNMR==:..CNT	;DEFINE THE NUMBER OF REGISTERS
>

MBRLST	<0,1,2,3,4,5,6,20,21,22,23,24,25,26,27,30,31,32,33,34,35,36,37>
	SUBTTL	START DRIVE POSITIONING


;ROUTINE TO CAUSE THE DRIVE TO DO A RECALIBRATE OPERATION.
;CALL:
;	J/KDB ADDRESS
;	U/UDB ADDRESS
;	PUSHJ	P,RNXRCL
;RETURN CPOPJ IF ERROR
;	CPOPJ1 WITH RECAL STARTED

RNXRCL::MOVEI	T1,.DXCTR!.CRRCL ;GET RECAL FUNCTION CODE
	PUSHJ	P,CONECT	;CONNECT TO THE DRIVE
	  JRST	RNXDWN		;DRIVE IS DOWN
	MOVSI	T2,(.DXDCR)	;SET CYLINDER AND
	MOVSI	T3,(.DXDAR)	;  TRACK/SECTOR TO ZERO
	PJRST	RNXGO		;JOIN COMMON CODE


;ROUTINE TO START A POSITION OPERATION GOING.  FOR RP20'S, FILIO ALWAYS
;DOES A SEEK BEFORE EVERY TRANSFER REGARDLESS OF WHETHER THE DRIVE IS
;ALREADY ON CYLINDER.  WE TURN THAT INTO A SEARCH COMMAND SO THAT WE
;GET AN INTERRUPT WHEN THE DRIVE IS BOTH ON CYLINDER AND ON SECTOR.
;CALL WITH UNIBLK(U) CONTAINING THE DESIRED BLOCK NUMBER.
;CALL:
;	J/KDB ADDRESS
;	U/UDB ADDRESS
;	PUSHJ	P,RNXPOS
;RETURN CPOPJ IF ERRORS
;	CPOPJ1 WITH POSITION STARTED

RNXPOS::MOVEI	T1,.DXCTR!.CRSRC ;GET SEARCH COMMAND
	PUSHJ	P,CONECT	;CONNECT TO DRIVE
	  JRST	RNXDWN		;DRIVE IS DOWN
	PJRST	RNXGO		;JOIN COMMON CODE
	SUBTTL	START DATA TRANSFERS


;ROUTINES TO START A DATA TRANSFER GOING ON A DRIVE.  ENTRY POINTS
;ARE:
;	RNXRED	- READ DATA, DON'T STOP ON ERROR
;	RNXRDS	- READ DATA, STOP ON ERROR
;	RNXRDF	- READ FORMAT
;	RNXWRT	- WRITE DATA, DON'T STOP ON ERROR
;	RNXWTS	- WRITE DATA, STOP ON ERROR
;	RNXWTF	- WRITE FORMAT
;CALL:
;	J/KDB ADDRESS
;	U/UDB ADDRESS
;	P1/CHANNEL DATA BLOCK ADDRESS
;	PUSHJ	P,ROUTINE
;RETURN CPOPJ IF ERRORS WITH:
;	T1/ERROR BITS
;	CPOPJ1 IF TRANSFER STARTED SUCCESSFULLY


;HERE TO START TRANSFER TO READ/WRITE FORMATS.

RNXRDF::SKIPA	T1,[.CRRDF]	;GET FUNCTION CODE FOR READ FORMAT
RNXWTF::MOVEI	T1,.CRWTF	;DITTO FOR WRITE FORMAT
	MOVE	T2,KONCNT##(J)	;WHEN READING OR WRITING FORMATS,
	IDIVI	T2,202		;  SECTORS ARE 202 WORDS LONG BUT FILIO
	SKIPE	T3		;  COMPUTED THE BLOCK COUNT BASED ON 200
	ADDI	T2,1		;  WORD SECTORS.  RECOMPUTE THE BLOCK
	HRRM	T2,CHNNUM##(P1)	;  COUNT TO KEEP THE RH20 HAPPY.
	JRST	RNXDGO		;JOIN COMMON TRANSFER CODE
;HERE TO START TRANSFER TO READ/WRITE DATA, NOT STOPPING ON ERRORS.

RNXRED::SKIPA	T1,[DO.DTE!.CRRED] ;GET FUNCTION FOR READ DATA+DXES
RNXWRT::MOVEI	T1,DO.DTE!.CRWRT ;DITTO FOR WRITE DATA+DXES
	JRST	RNXDGO		;JOIN COMMON CODE

;HERE TO START TRANSFER TO READ/WRITE DATA, STOPPING ON ERRORS.

RNXRDS::SKIPA	T1,[.CRRED]	;GET FUNCTION CODE FOR READ DATA
RNXWTS::MOVEI	T1,.CRWRT	;DITTO FOR WRITE DATA

;HERE FROM ALL TRANSFER OPERATIONS TO ACTUALLY DO THE WORK WITH
;T1 CONTAINING THE FUNCTION.

RNXDGO:	PUSHJ	P,CONECT	;CONNECT TO DRIVE
	  JRST	RNXDWN		;DRIVE IS DOWN
	PUSH	P,T4		;SAVE IGNORE COMMAND FLAG
	MOVN	T4,CHNNUM##(P1)	;GET NEGATIVE BLOCK COUNT FOR TRANSFER
	STORE	T4,T1,DO.CNT	;STORE IN APPRPRIATE PLACE IN STCR
	TLO	T1,(.DOSTC!DO.RCP!DO.SCS) ;SETUP TO TALK TO STCR
	POP	P,T4		;RESTORE T4
;HERE TO START ALL OPERATIONS GOING THROUGH EITHER THE STCR OR THE
;DX20 CONTROL REGISTER WITH:
;	T1/STCR OR CONTROL REGISTER DATAO
;	T2/DATAO TO SETUP DESIRED CYLINDER REGISTER
;	T3/DATAO TO SETUP DESIRED ADDRESS REGISTER
;	T4/NON-ZERO TO TOSS THIS COMMAND

RNXGO:	JUMPN	T4,RNXGO1	;DON'T DO DATAO'S IF TOSSING COMMAND
	PUSH	P,T3		;SAVE DESIRED ADDRESS REGISTER
	PUSHJ	P,DODTO		;WRITE DESIRED CYLINDER REGISTER
	POP	P,T2		;RESTORE DESIRED ADDRESS REGISTER
	PUSHJ	P,DODTO		;WRITE THAT ALSO
RNXGO1:	LDB	T3,RNYDXN	;GET DX20 NUMBER
	TLO	T1,<(DO.LDR!DO.DRE)>(T3) ;SET LDR, DRE, AND DS
	SKIPE	T4		;TOSSING THIS COMMAND?
	TLO	T1,(CR.IGN)	;YES, SET FLAG SO WE CAN TELL
	MOVEM	T1,UNILAS##(U)	;STORE AS LAST COMMAND FOR THIS UNIT
	JUMPN	T4,RNXGO2	;EXIT NOW IF TOSSING COMMAND
	STORE	T1,RNXCMD##(J),CM.FNC ;STORE FUNCTION IN KDB
	TRNE	T1,CR.IOP	;THIS AN I/O FUNCTION?
	RDTIME	RNXITB##(J)	;YES, READ THE STARTING TIME BASE
RNXBP1:	XCT	RNXDO1##(J)	;START THE OPERATION
RNXGO2:	PUSHJ	P,REASPI	;REASSIGN PIA
	JRST	CPOPJ1##	;GIVE SKIP RETURN


;HERE IF THE DRIVE OR KONTROLLER WAS DECLARED DOWN BY CONECT TO RETURN
;AN ERROR INDICATION TO FILIO.

RNXDWN:	PUSHJ	P,SETCO		;SET CONO MASK
	TRO	T4,CO.RAE	;MAKE SURE RAE IS CLEAR
	XCT	RNXCO4##(J)	;GIVE IT A PIA
	XCT	RNXCI2##(J)	;GET CONI INTO T2
	MOVE	T3,KONEBK##+.EBERR(J) ;GET ERROR REGISTER
	HRL	T3,KONEBK##+.EBSTR(J) ;MAKE IT STATUS,,ERROR REGISTER
RNXBP5:	POPJ	P,		;RETURN
	SUBTTL	STOP TRANSFER FOR HUNG RECOVERY


;ROUTINE TO STOP THE CURRENT TRANSFER WHEN THE HUNG TIMER TIMES
;OUT.  NOTE THAT THE SETTING OF STOP TRANSFER CAUSES AN IMMEDIATE
;INTERRUPT SO RNXINT HAS TO KNOW ABOUT THESE KINDS OF INTERRUPTS.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNXSTP
;RETURN CPOPJ IF COULDN'T GET BUSY TO CLEAR
;	CPOPJ1 IF SUCCESSFUL

RNXSTP::XCT	RNXCI2##(J)	;GET CONI BEFORE STOPPING TRANSFER
	PUSH	P,T2		;SAVE IT
	PUSHJ	P,RNXIVI	;ASSIGN AN IVI SINCE WE MIGHT BE HERE
				;  AS THE RESULT OF POWER FAIL RESTART
	MOVSI	T2,(CM.HNG)	;SET BIT TELLING RNXINT THAT THIS
	IORM	T2,RNXCMD##(J)	;  INTERRUPT WAS THE RESULT OF A HUNG
	MOVEI	T2,CO.STP	;GET THE STOP TRANSFER BIT
	XCT	RNXCO2##(J)	;STOP THE RH20
	XCT	RNXCI2##(J)	;GET THE CONI BACK
RNXBP6:	TRNN	T2,CI.BSY	;DID BUSY CLEAR?
	AOS	-1(P)		;YES, GIVE SKIP RETURN
	POP	P,T2		;RESTORE CONI
	MOVEI	T3,0		;DATAI WILL BE SAVED BY RNXINT
	PJRST	REASPI		;REASSIGN PIA AND RETURN
	SUBTTL	INTERRUPT HANDLER


;ROUTINE TO PROCESS RP20 INTERRUPTS.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNXINT
;EXITS CPOPJ ALWAYS THROUGH FILINT WITH:
;	T1/COMMUNICATIONS WORD (ATN BITS+DRIVE,,ERROR+FUNCTION)
;	T2/CONI
;	T3/ENDING STATUS,,ERROR REGISTER

RNXINT::PUSHJ	P,SAVE3##	;SAVE P1-P3
	XCT	RNXDI2##(J)	;GET REGISTER RH20 IS CONNECTED TO
	PUSH	P,T2		;SAVE IT
	MOVEI	T2,^D2000	;JUST IN CASE SOMETHING IS HAPPENING,
	PUSHJ	P,WGOCLR	;  WAIT FOR THE GO BIT TO CLEAR
	PUSHJ	P,RNXINR	;PROCESS ANY OPERATION IN PROGRESS
				;  PLUS ANY ERRORS THAT OCCURRED WHILE
				;  THERE WAS NO OPERATION IN PROGRESS
				;  (MICRODIAGNOSTIC FAILURE, UCODE RELOAD)
	PUSHJ	P,CHKATN	;CHECK ON ASYNCHRONOUS EVENTS AND CALL FILIO
	HLLZ	T2,0(P)		;GET BACK REGISTER (WE MAY HAVE INTERRUPTED
	TLZ	T2,^-<(DO.REG!DO.DRV)> ;  BETWEEN THE DATAO AND DATAI
	XCT	RNXDO2##(J)	;  IN DODTI AT UUO LEVEL SO RESTORE IT
	JRST	T2POPJ##	;RESTORE T2 AND RETURN
;ROUTINE TO PROCESS ANY OPERATION CURRENTLY IN PROGRESS OR ERRORS
;THAT OCCURRED WHILE THERE WAS NO OPERATION IN PROGRESS SUCH
;AS MICRODIAGNOSTIC FAILURES OR INTERRUPTS FOR MICROCODE RELOADS.
;CALLED FROM INTERRUPT SERVICE AND CONECT.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNXINR
;RETURN CPOPJ ALWAYS WITH:
;	J/KDB ADDRESS
;	T1/FILIO COMMUNICATION WORD
;	P1/FLAGS FROM RNXCMD OR 0 IF NO OPERATION IN PROGRESS
;	P2/ERROR REGISTER,,ENDING STATUS REGISTER
;	P3/CHANNEL STATUS,,CONI

RNXINR:	SETZB	T1,P2		;CLEAR COMMUNICATION AND DATAI WORDS
	XCT	RNXCI2##(J)	;GET CONI IN T2
	MOVEI	P3,(T2)		;MOVE TO P3
	MOVEI	P1,0		;START WITH ZERO FLAGS
	EXCH	P1,RNXCMD##(J)	;ZERO FLAG WORD, PUT FLAGS IN P1
	MOVEM	P1,RNXLAS##(J)	;SAVE VALUE FOR DEBUGGING
	MOVSI	T2,(.DXESR)	;POINT AT ENDING STATUS REGISTER
	PUSHJ	P,DODTI		;READ IT
	MOVEI	P2,(T2)		;MOVE TO P2
	JUMPGE	P1,RNXIN2	;GO IF NOT A DATA TRANSFER OPERATION
	MOVE	T2,KONIOC##(J)	;GET ADDRESS OF RH20 LOGOUT AREA
	HLL	P3,.CSCLP(T2)	;COPY CHANNEL STATUS TO LH(P3)
RNXIN2:	MOVE	U,KONCUA##(J)	;SETUP POSSIBLE UDB ADDRESS
	PUSHJ	P,CHKERR	;CHECK ON DX20 DETECTED ERRORS
	JUMPL	P1,DATINT	;DISPATCH TO DATA XFER DONE HANDLER
	JUMPE	P1,NOPINT	;DISPATCH IF NO OPERATION IN PROGRESS
	LDB	T2,UNYPUN##	;GET PHYSICAL UNIT NUMBER
	MOVE	T2,BITTBL##(T2)	;AND CORRESPONDING BIT
	TLNE	P1,(CM.HNG)	;COME THROUGH RNXSTP?
	IORM	T2,RNXATN##(J)	;YES, MUST BE A HUNG RECAL
;;	PJRST	POSINT		;FALL INTO POSITION DONE HANDLER
;HERE ON A POSITION INTERRUPT AT POSINT OR AN INTERRUPT WITH NO
;OPERATION IN PROGRESS AT NOPINT WITH THE FOLLOWING AC'S SETUP:
;	T1/ERROR BITS
;	P1/FLAGS FROM RNXCMD OR 0 IF NO OPERATION IN PROGRESS
;	P2/ERROR REGISTER,,ENDING STATUS REGISTER
;	P3/CONI

POSINT:	LOAD	T2,P1,CM.UNF	;GET UNIT NUMBER OF DRIVE
	TRNN	T1,ALLERR	;NO 2ND INTERRUPT IF WE GOT AN ERROR
	TRNE	P2,ES.DVE	;DEVICE END UP IN ENDING STATUS REGISTER?
	PUSHJ	P,POSDON	;YES, SET CORRESPONDING BIT IN RNXATN
NOPINT:	TRO	T1,OPPOS	;FLAG THIS AS A POSITION OPERATION
	TRZE	T1,ALLERR	;ANY ERRORS DETECTED?
	PUSHJ	P,LOGUPE	;YES, LOG THEM
	POPJ	P,		;RETURN


;HERE ON A DATA TRANSFER INTERRUPT WITH THE FOLLOWING AC'S SETUP:
;	T1/ERROR BITS
;	P1/FLAGS FROM RNXCMD
;	P2/ERROR REGISTER,,ENDING STATUS REGISTER
;	P3/CHANNEL STATUS,,CONI

DATINT:	TLNE	P1,(CM.HNG)	;HERE FROM RNXSTP?
	TRO	T1,IODERR	;YES, SET DEVICE ERROR
	TLNE	P1,(CM.IO)	;DOING A READ?
	TROA	T1,OPRED	;YES, FLAG IT AS SUCH
	TRO	T1,OPWRT	;NO, FLAG IT AS A WRITE
	TLC	P3,(CS.NAE)	;COMPLEMENT ADDRESS PARITY BIT
	TDNN	P3,[CS.ERR!CI.ERR] ;ANY CHANNEL OR RH20 ERRORS DETECTED?
	JRST	DATIN1		;NO
	TLNE	P3,(CS.MPE)	;MEMORY PARITY ERROR?
	TRO	T1,IOCHMP	;YES
	TLNE	P3,(CS.NXM)	;NXM?
	TRO	T1,IOCHNX	;YES
	TLNE	P3,(CS.OVR)	;OVERRUN?
	TRO	T1,IOVRUN	;YES
	TRNN	T1,ALLERR	;ANY ERRORS FLAGGED (BETTER BE)
	TRO	T1,IODERR	;NO??? FLAG A DEVICE ERROR
DATIN1:	TLC	P3,(CS.NAE)	;RECOMPLEMENT ADDRESS PARITY BIT
	TRNN	T1,ALLERR	;ANY ERRORS DETECTED?
	SKIPLE	UNIECT##(U)	;NO, READ SUCCEED ON RETRY?
	PUSHJ	P,RDREG		;YES, READ THE REGISTERS
	HRRZ	T2,UNICHN##(U)	;UPDATE THE LAST KNOWN POSITION
	MOVE	T2,CHNNUM##(T2)	; OF THE DISK
	ADD	T2,UNIBLK##(U)
	ADDI	T2,^D14		;PLUS A FUDGE FACTOR
	LDB	T3,UNYBPT##
	IDIV	T2,T3
	DPB	T3,UNYLKP##
	POPJ	P,		;RETURN
;ROUTINE TO CHECK FOR ASYNCHRONOUS EVENTS AND DO THE FINAL INTERRUPT
;PROCESSING BEFORE CALLING FILINT.
;CALL:
;	J/KDB ADDRESS
;	T1/ERROR BITS
;	P1/FLAGS FROM RNXCMD OR 0
;	P2/ERROR REGISTER,,ENDING STATUS REGISTER
;	P3/CHANNEL STATUS,,CONI
;	PUSHJ	P,CHKATN
;RETURN CPOPJ ALWAYS

CHKATN:	PUSHJ	P,CLRATN	;CLEAR ATTENTION BITS
	PUSHJ	P,CLRERG	;CLEAR THE ERROR REGISTER
	MOVSI	T2,(.DXASY)	;POINT AT THE ASYNCHRONOUS STATUS REGISTER
	PUSHJ	P,DODTI		;READ IT
	JUMPE	T2,INTDON	;GO IF NONE THERE
	TRNE	T2,AS.DVS	;ANY STATUS BITS SET?
	JRST	RNXBP2		;YES, CONTINUE
	MOVSI	T2,(.DXASY)	;THERE'S A UCODE RACE WHICH CAUSES IT TO GIVE
	PUSHJ	P,DODTI		;US A DRIVE WITH NO STATUS, SO READ IT AGAIN
RNXBP2:	PUSH	P,T2		;SAVE IT
	MOVSI	T2,(.DXASY)	;POINT AT REGISTER AGAIN
	PUSHJ	P,DODTO		;CLEAR IT SO WE CAN GET MORE
	POP	P,T2		;RESTORE VALUE TO PROCESS
	SKIPN	P1		;IF NO OPERATION IN PROGRESS,
	MOVEI	P2,(T2)		;MOVE ASYNCHRONOUS STATUS TO P2 FOR .SYS P
	LOAD	T2,T2,AS.UNF	;GET UNIT NUMBER PRESENTING STATUS
	PUSHJ	P,POSDON	;SET THE CORRESPONDING BIT IN RNXATN
;;	PJRST	INTDON		;FALL INTO INTDON
;HERE TO DO THE FINAL EXIT PROCESSING BEFORE CALLING FILINT WITH:
;	J/KDB ADDRESS
;	T1/ERROR BITS
;	P1/FLAGS FROM RNXCMD OR 0
;	P2/ERROR REGISTER,,ENDING STATUS REGISTER
;	P3/CHANNEL STATUS,,CONI
;	LH(RNXATN(J))/ATTENTION BITS OF DRIVES IN POSITION

INTDON:	MOVEI	T4,CO.CLR	;GET BITS TO CLEAR RH20
	XCT	RNXCO4##(J)	;DO SO
	PUSHJ	P,REASPI	;REASSIGN PIA
	HLLZ	T4,RNXATN##(J)	;GET ATTENTION BITS
	LOAD	T2,P1,CM.UNF	;GET UNIT NUMBER LAST CONNECTED TO
	TLO	T1,(T2)		;SET IN LH OF T1
	TRNN	T1,OPPOS	;THIS A POSITION OPERATION?
	TDZ	T4,BITTBL##(T2)	;NO, MAKE SURE WE DON'T CALL FILIO WITH
				;  A POSITION DONE INTERRUPT ON A TRANSFERRING
				;  DRIVE.  IT HAPPENS AND IT CONFUSES FILIO
	;PJRST	CALFIO		;CALL FILIO TO PROCESS THIS EVENT


;ROUTINE TO ACTUALLY CALL FILIO TO PROCESS AND INTERRUPT.
;CALL:
;	J/KDB ADDRESS
;	T1/COMMUNICATION WORD
;	T4/ATTENTION BITS
;	P2/ERROR REGISTER,,ENDING STATUS REGISTER
;	P3/CHANNEL STATUS,,CONI
;	PUSHJ	P,CALFIO
;RETURN CPOPJ ALWAYS

CALFIO:	PUSH	P,J		;SAVE KONTROLLER ADDRESS; FILINT MAY SMASH IT
	HRRZS	RNXATN##(J)	;CLEAR ATTENTION BITS IN KDB
	MOVE	T2,P3		;GET CONI IN T2
	MOVS	T3,P2		;  AND DATAI'S IN T3
	MOVEM	T1,RNXEC3##(J)	;****; TEMPORARY FOR DEBUGGING
	TLZ	T1,777700	;CLEAR UNUSED BITS
	TRNE	T1,OPPOS	;POSITION INTERRUPT?
	TLNE	T4,777774	;  WITH NO ATTENTION BITS UP?
RNXBP3:	PUSHJ	P,FLHTID##	;NO, CALL FILIO AND RETURN
	PJRST	JPOPJ##		;YES, AVOID A LONG NO-OP IN FILIO
	SUBTTL	DETERMINE CAPACITY AND STATUS


;ROUTINE TO RETURN CAPACITY AND STATUS OF AN RP20 DRIVE TO FILSER.
;CALL:	J/KDB ADDRESS
;	U/UDB ADDRESS
;	PUSHJ	P,RNXCPY
;RETURN CPOPJ IF ERROR
;	CPOPJ1 IF DRIVE EXISTS AND IS OK TO USE WITH:
;	T1/BLOCKS PER UNIT
;	T2/BLOCKS PER UNIT INCLUDING MAINTENANCE CYLINDERS
;	T3/BLOCKS PER UNIT IN 10/11 COMPATABILITY MODE
;	T4/STATUS BITS (KOPUHE,KOPNSU,KOP22B),,UNIT TYPE
;	LH(J)/DRIVE SERIAL NUMBER
;	W/BLOCKS PER TRACK,,BLOCKS PER CYLINDER

RNXCPY::PUSHJ	P,SAVE2##	;SAVE P1-P2
	MOVEI	T2,CO.MBE	;MAKE SURE MASSBUS
	XCT	RNXCO2##(J)	;  ENABLE IS ON AND DEASSIGN PI
	PUSHJ	P,RNXIVI	;SET INTERRUPT VECTOR ADDRESS
	MOVSI	T2,U2PNRM##	;SET NON-REMOVABLE MEDIUM
	IORM	T2,UNIDS2##(U)	;  IN UDB
	MOVSI	T4,KOP22B##	;RP20 IS ALWAYS 22 BIT, UNIT TYPE IS 0
	SKIPE	RNXCMD##(J)	;ARE WE DOING SOMETHING NOW?
	JRST	RNXCP4		;YES, CAN'T TOUCH THE DRIVE
	PUSHJ	P,RNXFKA	;FIND DX20 ADDRESS, CHECK MICROPROCESSOR
	  JRST	RNXCP6		;SOMETHING FAILED, BITS SET IN T4
	MOVSI	P1,-MAXDCU	;LOOP INDEX FOR ALL POSSIBLE DCU'S
RNXCP1:	PUSHJ	P,MPRUN		;DX20 STILL RUNNING?
	  JRST	RNXCP4		;NO, CALL UNIT OFF-LINE
	SKIPL	RNXFLG##(J)	;DO WE KNOW THE DCU CONTROLLER ADDRESS?
	DPB	P1,RNYDCA	;NO, TRY THE NEXT
	PUSHJ	P,DO2TIO	;DO TWO TEST I/O'S
	  JRST	RNXCP4		;GO IF THE DX20 DIDN'T RESPOND
	PUSHJ	P,INIERR	;CHECK FOR ERRORS
	  JRST	RNXCP5		;DRIVE IS ON-LINE
	  JRST	RNXCP4		;DRIVE EXISTS BUT IS OFF-LINE
	SKIPL	RNXFLG##(J)	;ALREADY KNOW THE DCU CONTROLLER ADDRESS?
	AOBJN	P1,RNXCP1	;NO, TRY NEXT CONTROLLER FOR THIS UNIT
;HERE IF NO SUCH UNIT EXISTS OR THE DRIVE TYPE REGISTER IS NOT
;FOR A DX20.

RNXCP3:	TLOA	T4,KOPUHE##!KOPNSU## ;INDICATE NO SUCH UNIT

;HERE IF THE UNIT EXITS BUT IS OFF-LINE OR IF WE'RE NOT REALLY SURE
;AND DON'T WANT TO TELL FILSER THAT NO SUCH UNIT EXISTS.

RNXCP4:	TLO	T4,KOPUHE##	;INDICATE OFF-LINE
	JRST	RNXCP6		;JOIN COMMON EXIT CODE

;HERE IF THE DRIVE IS ON-LINE AND NO ERRORS WERE DETECTED.

RNXCP5:	AOS	0(P)		;GIVE SKIP RETURN
	MOVSI	T2,(RN.DCU)	;INDICATE THAT WE NOW KNOW THE
	IORM	T2,RNXFLG##(J)	;  DCU CONTROLLER ADDRESS
RNXCP6:	LDB	T1,RNYDCA	;GET DCU
IFN FTDUAL,<
;THERE'S NO WAY TO READ THE SERIAL NUMBER OF AN RP20 SO WE
;BUILD A FAKE SERIAL NUMBER BASED ON THE UNIT NUMBER.
;THE QUESTION IS: IF YOU'VE GOT SEVERAL RH20'S WORTH OF
;RP20'S, HOW DO YOU TELL WHICH RH20 IS DUAL PORTED WITH WHICH?
;THE ANSWER IS: YOU CUT THE TWO DCU'S TO BE THE SAME ADDRESS.
;IF THE DCU'S MATCH THE DRIVES WILL BE CONSIDERED DUAL PORTED.
;THERE'S A SPECIAL CASE, HOWEVER, IN THAT A DCU OF ZERO DOESN'T
;MATCH ANYTHING. NOTE THAT THE FACTORY SETS ALL THE DCU ADDRESSES TO ZERO.
;YOU CAN INSTALL ANY NUMBER OF THESE WITH NO MODIFICATION AND THEY WILL
;ALL BE SINGLE PORTED. IF YOU WANT THEM TO BE DUAL PORTED THEN YOU
;HAVE TO ASSIGN A UNIQUE DCU ADDRESS.
	JUMPE	T1,RNXCP7	;GO IF FACTORY JUMPERS
>
	LSH	T1,4		;MAKE ROOM FOR UNIT NUMBER
	LDB	T2,UNYPUN##	;GET UNIT NUMBER
	IOR	T1,T2		;DUMMY UP A DRIVE SERIAL NUMBER
	MOVEI	T2,.DTCOD	;GET DT VALUE, VERIFIED BY CHKDTR
RNXCP7:	HRRZM	T1,UNISER##(U)	;RETURN SERIAL NUMBER IN UNISER
	PUSHJ	P,CLRERG	;CLEAR ERROR REGISTER
	PUSHJ	P,CLRATN	;CLEAR ATTENTIONS
	PUSHJ	P,REASPI	;RESTORE PI ASSIGNMENT
	DMOVE	T1,[EXP ^D839250,^D840000] ;BLOCKS/UNIT WITH/WITHOUT MAINT CYL
	TRNE	T4,KOPNSU##	;NO SUCH UNIT?
	SETZB	T1,T2		;YES, RETURN 0'S
	MOVEI	T3,0		;NO BLOCKS IN 10/11 COMPATABILITY MODE
	MOVE	W,[^D25,,^D750]	;BLOCKS/TRACK,,BLOCKS/CYLINDER
	POPJ	P,		;RETURN
;ROUTINE TO FIND THE DX20 CONTROLLER MASSBUS ADDRESS AND CHECK
;THE INTEGRETY OF THE MICROPROCESSOR CONTROL STORE.
;CALL:
;	J/KDB ADDRESS
;	U/UDB ADDRESS
;	PUSHJ	P,RNXFKA
;RETURN CPOPJ IF ERROR WITH:
;	T4/ERROR BITS INDICATING TYPE OF FAILURE
;	CPOPJ1 IF NO ERROR WITH MICROPROCESSOR RUNNING

RNXFKA::MOVSI	T2,(RN.FKA)	;DO WE ALREADY KNOW
	TDNE	T2,RNXFLG##(J)	;  THE DX20 CONTROLLER ADDRESS?
	JRST	RNXFK2		;YES, JUST CHECK THE MICROPROCESSOR
	PUSHJ	P,SAVE1##	;SAVE P1
	HLLZ	P1,KONTBP##(J)	;MAKE AOBJN POINTER TO MAX CONTROLLER ADDR
RNXFK1:	DPB	P1,RNYDXN	;STORE CONTROLLER ADDRESS
	PUSHJ	P,CHKDTR	;CHECK DRIVE TYPE REGISTER
	  JRST	RNXFK4		;NO MATCH, TRY NEXT
RNXFK2:	PUSHJ	P,MPINI		;CHECK AND RELOAD MICRO IF NECESSARY
	  JRST	RNXFK5		;FAILED, CALL THE DRIVE OFF-LINE
	MOVSI	T2,(RN.FKA)	;SET FLAG INDICATING THAT WE
	IORM	T2,RNXFLG##(J)	;  KNOW THE DX20 ADDRESS
	AOS	0(P)		;GIVE SKIP RETURN
	JRST	RNXFK6		;AND EXIT
RNXFK4:	MOVEI	T2,CO.RAE!CO.MBE ;GET BIT TO CLEAR RAE
	XCT	RNXCO2##(J)	;CLEAR ANY POSSIBLE RAE
	AOBJN	P1,RNXFK1	;AND TRY NEXT DX20 ADDRESS
	TLOA	T4,KOPUHE##!KOPNSU## ;IF NO DX20, MARK THIS UNIT NONEXISTANT
RNXFK5:	TLO	T4,KOPUHE##	;ELSE JUST CALL IT OFF-LINE
RNXFK6:	MOVEI	T2,CO.CLR!CO.MBE ;GET BITS TO CLEAR THE RH20
	XCT	RNXCO2##(J)	;DO SO
	POPJ	P,		;RETURN SKIP/NONSKIP
	SUBTTL	RETURN ECC MASK AND POSITION


;ROUTINE TO RETURN THE ECC POSITION AND MASK TO FILIO FOR AN ECC
;CORRECTABLE ERROR IN A BLOCK.  THE RP20 RETURNS THE ECC POSITION
;AND MASK IN THE SENSE BYTES WHICH ARE NOW IN KONEBK AS FOLLOWS:
;  18-19  FIRST BYTE IN ERROR COUNTED FROM THE LAST BYTE IN THE
;	  BLOCK.  A COUNT OF ZERO MEANS THAT THE ECC ERROR OCCURRED
;	  IN THE ECC BYTE ITSELF AND MAY BE IGNORED.
;  20-21  MASK WHICH WHEN XORED WITH THE DATA ACTUALLY READ WILL
;	  CORRECT THE ERROR.
;NOTE THAT THE BOTH MASK WORDS ARE SWAPPED SINCE THAT'S THE WAY AN
;RP06 WOULD RETURN THEM AND THE WAY FILIO EXPECTS THEM.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNXECC
;RETURN CPOPJ IF NO ECC INFORMATION AVAILABLE
;	CPOPJ1 WITH CORRECTION DATA AS FOLLOWS:
;	T1/WORD POSITION OF START OF ERROR RELATIVE TO START OF BLOCK
;	T2-T3/MASK

RNXECC::HLRZ	T2,KONEBK##+.EBDVL(J) ;GET NUMBER OF DEVICE REGS STORED
	JUMPE	T2,CPOPJ##	;GIVE UP IF NONE
	LOAD	T3,KONEBK##+.EBS07(J),EB.S07 ;GET FORMAT TYPE AND CODE
	CAIN	T3,.S7ECC	;ECC ERROR?
	CAIGE	T2,.EBS07-.EBSDR+1 ;OR IF WE DIDN'T GET AT LEAST 0-7
	POPJ	P,		;NO ECC INFORMATION AVAILABLE
	SETZB	T2,T3		;ZERO MASKS FOR EARLY EXIT
	LOAD	T1,KONEBK##+.EBS18(J),EB.S18 ;GET BYTES 18-19
	JUMPE	T1,CPOPJ1##	;NO CORRECTION IF IN ECC BYTE
	CAILE	T1,^D576	;OR IF OUT
	POPJ	P,		;  OF RANGE
	MOVNI	T1,-^D576(T1)	;COMPUTE NUMBER OF BYTES FROM START OF BLOCK
	LSH	T1,3		;CONVERT TO COUNT OF BITS
	TLZ	T1,-1		;CLEAR JUNK
	IDIVI	T1,^D36		;COMPUTE WORD COUNT, OFFSET IN WORD
	MOVNI	T4,-<^D36-^D16>(T2) ;COMPUTE SHIFT COUNT IN THIS WORD
	LOAD	T2,KONEBK##+.EBS20(J),EB.S20 ;GET CORRECTION MASK
	LSHC	T2,(T4)		;SHIFT TO PROPER POSITION FOR MASK
	MOVSS	T2		;SWAP THE MASK SO THAT IT
	MOVSS	T3		;  LOOKS LIKE THAT RETURNED BY AN RP06
	JRST	CPOPJ1##	;GIVE SKIP RETURN
	SUBTTL	DIRECT FILIO IN ERROR RECOVERY


;ROUTINE TO DIRECT FILIO IN ERROR RECOVERY.  SINCE THE DCU DOES ITS OWN
;SEEK ERROR RECOVERY AND SINCE WE DON'T HAVE ANY OFFSET CAPABILITY,
;THE BASIC ERROR RECOVERY ALGORITHM IS TO SIMPLY DO 24 STRAIGHT RETRIES.
;IF RN.FTL IS SET IN RNXFLG, HOWEVER, WE GIVE UP IMMEDIATELY.
;CALL:
;	J/KDB ADDRESS
;	T1/RETRY NUMBER
;	P1/CHANNEL DATA BLOCK ADDRESS
;	PUSHJ	P,RNXERR
;RETURN CPOPJ ALWAYS WITH:
;	T1/0 IF STRAIGHT RETRY
;	   2 IF LAST TIME
;	   3 IF GIVE UP

RNXERR::MOVE	T2,RNXFLG##(J)	;GET ERROR FLAGS SET BY CHKERR
	TLNE	T2,(RN.FTL)	;FATAL ERROR?
	MOVEI	T1,RTYNUM	;YES, FORCE IT TO BE FATAL
	CAIGE	T1,RTYNUM-1	;STILL DOING STRAIGHT RETRIES?
	MOVEI	T2,0		;YES
	CAIN	T1,RTYNUM-1	;LAST TIME?
	MOVEI	T2,2		;YES
	CAIL	T1,RTYNUM	;TIME TO GIVE UP?
	MOVEI	T2,3		;YES
	MOVEI	T1,(T2)		;MOVE TO WHERE FILIO WANTS IT
	POPJ	P,		;RETURN
	SUBTTL	MISCELANEOUS GLOBAL FUNCTIONS


;ROUTINE TO RETURN THE LATENCY TIME FOR AN RP20 DRIVE.  SINCE THE
;RP20 CAN'T TELL US WHERE IT REALLY IS (THAT'S RIGHT, NO LOOK AHEAD
;REGISTER RP06 FANS), AND SINCE WE ALWAYS DO SEARCHES BEFORE EACH
;DATA TRANSFER SO THAT WE GET AN INTERRUPT WHEN THE DRIVE IS ON
;BOTH CYLINDER AND SECTOR, WE ALWAYS RETURN A LATENCY TIME OF
;ZERO IN THE HOPE THAT FILIO WILL GET BACK TO START THE TRANSFER
;BEFORE THE DISK REVOLVES PAST THE BLOCK.
;CALL:
;	PUSHJ	P,RNXLTM
;RETURN CPOPJ1 ALWAYS WITH:
;	T1/LATENCY TIME (ZERO)

RNXLTM::MOVEI	T1,0		;RETURN A ZERO
	JRST	CPOPJ1##	;GIVE SKIP RETURN


;ROUTINE TO RETURN THE DISTANCE TO THE TARGET CYLINDER.  SINCE WE WANT
;TO DO SEEKS (REALLY SEARCHES), WE ALWAYS TELL FILIO THAT WE ARE OFF
;CYLINDER EVEN IF WE ARE ON CYLINDER. 
;BE AWARE THAT WHEN CHOOSING SOMEBODY FROM THE POSITION WAIT QUEUE,
;IF THERE ARE SEVERAL PEOPLE ALREADY ON CYLINDER, FILIO
;WILL TRY TO CHOOSE THE ONE WHOSE ROTATIONAL LATENCY IS THE
;SMALLEST. IN THE CASE OF AN RP20, WE MUST LIE TO FILIO.
;IF WE'RE ON CYLINDER, LIE TO FILIO AND TELL HIM THAT WE'RE OFF
;CYLINDER. BUT LIE BY AN AMOUNT LINEARLY PROPORTIONATE TO THE
;EXPECTED ROTATIONAL LATENCY OF THE DISK. THE EXPECTED LATENCY
;IS CALCULATED FROM THE LAST KNOWN POSITION OF THE DISK.
;THE ONLY TIME WE CAN ACCURATELY KNOW THE POSITION OF THE DISK
;IS AT THE CONCLUSION OF A TRANSFER. IT HAPPEN'S THAT'S
;THE ONLY TIME WE PICK SOMEBODY FROM THE POSITION WAIT QUEUE
;ANYWAY.

;CALL:
;	PUSHJ	P,RNXCCM
;RETURN CPOPJ ALWAYS WITH:
;	T1/DISTANCE FROM CURRENT CYLINDER TO TARGET CYLINDER

RNXCCM::PUSHJ	P,CYLCM##	;LET FILIO COMPUTE THE REAL DISTANCE
	MOVMS	T1
	ADDI	T1,100		;EXCESS 100
	CAIE	T1,100		;ON CYL?
	POPJ	P,		;NO
	MOVE	T1,DEVBLK##(F)	;YES, COMPUTE TARGET SECTOR
	LDB	T3,UNYBPT##
	IDIV	T1,T3
	LDB	T1,UNYLKP##	;LAST KNOWN POSITION OF DISK
	CAMLE	T1,T2		;TOO LATE?
	ADD	T2,T3		;YES, WAIT ANOTHER REVOLUTION
	SUBM	T2,T1		;DISTANCE TO TARGET
	ADDI	T1,1		;ASSURE NON-ZERO
	SKIPL	UNIECT##(U)	;IN ERROR RECOVERY?
	SETZ	T1,		;YES, TELL THE TRUTH (ON CYL)
	POPJ	P,		;RETURN


;ROUTINES WHICH SHOULD NEVER BE CALLED SINCE THE DISPATCH BITS
;IN COMMOD PROHIBIT THIS.  IF WE DO GET HERE HOWEVER...

RNXRDC::			;READ 10/11 COMPATABILITY MODE
RNXWTC::			;WRITE 10/11 COMPATABILITY MODE
RNXUNL::			;UNLOAD DRIVE
	STOPCD	CPOPJ1##,DEBUG,NIF, ;++RNXKON ISN'T FANCY
	SUBTTL	CHECK DRIVE/CONTROLLER STATUS


;ROUTINE TO INSURE THAT THE RH20 AND DX20 ARE OK FOR THE OPERATION
;ABOUT TO BE DONE AND SETUP FOR THAT OPERATION.
;CALL:
;	J/KDB ADDRESS
;	U/UDB ADDRESS
;	T1/FUNCTION
;	PUSHJ	P,CONECT
;RETURN CPOPJ IF ERROR WITH:
;	T1/ERROR BITS
;	CPOPJ1 IF OK WITH:
;	T1/FUNCTION
;	T2/CYLINDER
;	T3/TRACK/SECTOR IN .DXDAR FORMAT
;	T4/NON-ZERO TO TOSS THIS COMMAND

CONECT:	MOVEI	T4,CO.MBE	;MAKE SURE PIA IS OFF AND MBE
	XCT	RNXCO4##(J)	;  IS ON
	SKIPE	T4,RNXCMD##(J)	;COMMAND IN PROGRESS ALREADY?
RNXBP4:	PUSHJ	P,CMDWAT	;YES, WAIT FOR IT TO FINISH
	JUMPN	T4,CONEC2	;GO IF TOSSING COMMAND
	MOVSI	T2,(RN.CLR)	;CLEAR TEMPORARY BITS
	ANDCAM	T2,RNXFLG##(J)	;  IN KDB
	PUSHJ	P,RNXIVI	;MAKE SURE RH20 HAS AN IVI
	XCT	RNXCI2##(J)	;GET CONI IN T2
	TRNE	T1,CR.IOP	;TRYING TO DO I/O?
	TRNN	T2,CI.BSY!CI.DON ;YES, IS BUSY OR DONE UP?
	JRST	CONEC1		;NO
;HERE WHEN WE ARE TRYING TO DO AN I/O OPERATION AND BUSY OR DONE
;IS STILL UP IN THE RH20 CONI.  TRY TO FORCE THE RH20 INTO A
;REASONABLE STATE, FIRST GENTLY AND, IF THAT FAILS, BY BLASTING IT.

	PUSH	P,T1		;SAVE FUNCTION
	PUSHJ	P,RDREG		;READ THE REGISTERS
	POP	P,T1		;RESTORE FUNCTION
	MOVSI	T2,UNPHNG##+UNPFIR## ;IF NOT IN ERROR RECOVERY,
	SKIPGE	UNIECT##(U)	;  SET A FLAG
	MOVEM	T2,UNIECT##(U)	;  FOR FILIO
	XCT	RNXCI2##(J)	;GET THE CONI BACK
	MOVEI	T4,CO.MBE!CO.STP ;GET BITS TO CLEAR BUSY, SET DONE
	TRNE	T2,CI.BSY	;IS BUSY STILL UP?
	XCT	RNXCO4##(J)	;YES, ATTEMPT TO CLEAR IT
	AOS	UNIHNG##(U)	;COUNT THE OCCURRANCE
	MOVEI	T2,CO.MBE!CO.CLR ;GET BITS TO CLEAR DONE
	XCT	RNXCO2##(J)	;DO SO
	XCT	RNXCI2##(J)	;GET THE CONI BACK
	TRNE	T2,CI.BSY	;IS BUSY STILL SET?
	JRST	CONERR		;YES, CALL THE DRIVE DOWN
	TRNN	T2,CI.DON	;HOW ABOUT DONE?
	JRST	CONEC1		;CLEAR, CONTINUE WITH SETUP
	PUSHJ	P,CLRRH2	;BLAST THE RH20
	XCT	RNXCI2##(J)	;GET THE CONI BACK
	TRNE	T2,CI.BSY!CI.DON ;DID WE MANAGE TO CLEAR IT UP?
	JRST	CONERR		;NO, GIVE UP AND CALL IT OFFLINE
;HERE WHEN THE RH20 IS IN SOME KIND OF REASONABLE STATE TO START THE
;OPERATION.  MAKE SURE THAT THE DX20 IS ALSO IN SOME REASONABLE STATE
;AND CONTINUE THE FINAL SETUP.

CONEC1:	SETZ	T4,		;LET THIS COMMAND GO THROUGH
CONEC2:	SKIPL	RNXFLG##(J)	;MUST KNOW THE CONTROLLER ADDRESS
	  JRST	CONOFL		;CALL THE DRIVE OFF-LINE
	PUSHJ	P,MPRUN		;IS THE DX20 STILL RUNNING?
	  AOSA	T2,@RNXRSC##(J)	;NO, COUNT THIS
	JRST	CONEC3		;YES, CONTINUE
	CAIG	T2,MAXRSC	;ALREADY RESTARTED IT TOO MANY TIMES?
	PUSHJ	P,MPCHKS	;NO, TRY TO RESTART IT AGAIN
	  JRST	CONMPS		;FAILED, CALL THE DRIVE OFF-LINE
CONEC3:	JUMPN	T4,CONEC5	;DON'T TOUCH HARDWARE IF TOSSING COMMAND
	TRNE	T1,CR.IOP	;THIS AN I/O FUNCTION?
	TRNE	T1,CR.RED	;YES, A WRITE?
	JRST	CONEC4		;NO, DON'T CARE ABOUT WRITE PROTECT
	MOVSI	T2,UNPHWP##	;GET HARDWARE WRITE PROTECT BIT
	TDNE	T2,UNIDES##(U)	;IS THE UNIT WRITE PROTECTED?
	JRST	CONHWP		;YES
CONEC4:	MOVSI	T2,UNPOFL##	;GET OFF-LINE BIT (SET BY CHKERR)
	TDNE	T2,UNIDES##(U)	;DRIVE OFF-LINE?
	JRST	CONOFL		;YES
	PUSHJ	P,SETDRV	;SETUP TO TALK TO THAT DRIVE
	STORE	T2,RNXCMD##(J),CM.DVA ;STORE DRIVE ADDRESS
CONEC5:	MOVE	T2,UNIBLK##(U)	;GET THE BLOCK WE WANT TO ACCESS
	LDB	T3,UNYBPY##	;  AND THE NUMBER OF BLOCKS/CYLINDER
	IDIVI	T2,(T3)		;T2=CYLINDER, T3=REMAINDER
	MOVEM	T2,UNICYL##(U)	;STORE IN UDB
	HRLI	T2,(.DXDCR)	;SETUP REGISTER SELECT FOR DCR
	PUSH	P,T2		;SAVE CYLINDER
	MOVE	T2,T3		;MOVE REMAINDER TO T2
	LDB	T3,UNYBPT##	;GET NUMBER OF BLOCKS PER TRACK
	IDIVI	T2,(T3)		;T2=TRACK, T3=BLOCK
	STORE	T2,T3,DA.TRK	;STORE IN CORRECT PLACE IN T3
	HRLI	T3,(.DXDAR)	;SETUP REGISTER SELECT FOR DAR
	JRST	T2POJ1##	;RESTORE T2 AND GIVE SKIP RETURN


;HERE WHEN AN ERROR WAS DETECTED IN EITHER THE RH20 OR DX20 DURING
;THE SETUP.  READ THE REGISTERS AND RETURN AN ERROR INDICATION TO FILIO.

CONHWP:	TDZA	T1,T1		;SET NO FLAGS IF WRITE PROTECTED
CONMPS:	PUSHJ	P,RNXSSB	;SET KOPMPS FOR KONTROLLER
CONOFL:	PUSHJ	P,RDREG		;READ THE REGISTERS
	JUMPE	T1,CPOPJ##	;GO IF HARDWARE WRITE PROTECTED
CONERR:	MOVEI	T1,KOPOFL##	;SET BIT FOR OFF-LINE
	POPJ	P,		;  AND RETURN
;ROUTINE TO CHECK IF THE RH20 HAS A PI
;CALL:
;	J/KDB	ADDRESS
;	PUSHJ	P,RNXALV
;RETURN CPOPJ ALWAYS
RNXALV::XCT	RNXCI2##(J)	;CONI
	TRNE	T2,7		;IS IT ALIVE?
	POPJ	P,		;YES
	PUSHJ	P,CLRRH2	;NO, CLEAR THE RH
	PJRST	REASPI		;GIVE IT A PI AND RETURN
	SUBTTL	ERROR ANALYSIS ROUTINES


;ROUTINE TO CHECK TO SEE IF THE DX20 MICROCODE DETECTED AN ERROR
;IN THE LAST OPERATION.
;CALL:
;	J/KDB ADDRESS
;	T1/ERROR BITS
;	P1/FLAGS FROM RNXCMD OR 0 IF NO OPERATION IN PROGRESS
;	P2/ENDING STATUS REGISTER
;	P3/CHANNEL STATUS OR 0,,CONI
;	PUSHJ	P,CHKERR
;RETURN CPOPJ ALWAYS WITH AC'S AS ABOVE AND:
;	LH(P2)/ERROR REGISTER IF ERRORS

CHKERR:	MOVSI	T2,(.DXSTR)	;POINT AT STATUS REGISTER
	PUSHJ	P,DODTI		;READ IT
	TRNN	T2,ST.RUN	;IS MICROPROCESSOR STILL RUNNING?
	JRST	FTLERR		;NO
	TRNN	T2,ST.CER	;COMPOSITE ERROR UP?
	POPJ	P,		;NO, NO ERRORS
	MOVSI	T2,(.DXERR)	;POINT AT ERROR REGISTER
	PUSHJ	P,DODTI		;READ IT
	HRLI	P2,(T2)		;MOVE TO P2
	TLNE	P2,ER.ERR	;ANY GENERIC HARDWARE FAILURES?
	TRO	T1,IODERR	;YES, FLAG A DEVICE ERROR
	TLNN	P2,ER.UPE	;MICROPROCESSOR ERROR?
	POPJ	P,		;NO, CODE IS MEANINGLESS
	LOAD	T2,P2,<ER.ECC_^D18> ;GET ERROR CODE IN T2
	CAIL	T2,ERRTBL	;IN THE RANGE WE KNOW ABOUT?
	JRST	FTLERR		;NO, THAT'S FATAL
	JRST	@ERRTAB(T2)	;DISPATCH TO PROCESSING ROUTINE


;THE FOLLOWING TABLE GIVES THE DISPATCH ADDRESS FOR EACH CLASS OF ERROR.

ERRTAB:	EXP	FTLERR		;0  - UNKNOWN
	EXP	UDSERR		;1  - UNUSUAL DEVICE STATUS
	EXP	RLNERR		;2  - RECORD LENGTH ERROR
	EXP	SELERR		;3  - DEVICE SELECTION ERROR
	EXP	RCVERR		;4  - RECOVERABLE ERROR
	EXP	RTYERR		;5  - COMMAND RETRY REQUEST
	EXP	NRCERR		;6  - NON-RECOVERABLE ERROR
	EXP	LOGUPE		;7 -  RETRY LOG INFORMATION, LOG IT
	EXP	FTLERR		;10 - FATAL ERROR
	EXP	FTLERR		;11 - MICRODIAGNOSTIC FAILURE
	EXP	RLDERR		;12 - MICROCODE RELOAD FOR INFORMATION
ERRTBL==.-ERRTAB
;HERE ON UNUSUAL DEVICE STATUS

UDSERR:	TRNN	P2,ES.UCK	;UNIT CHECK UP IN ENDING STATUS BYTE?
	JRST	RCVERR		;NO, JUST CALL IT RECOVERABLE
	MOVEI	T2,.ESSB0	;INDEX INTO EST TO GET SENSE BYTES
	PUSHJ	P,RDEST		;READ SENSE BYTES 0-3
	  MOVEI	T2,0		;SHOULDN'T HAPPEN, DEFAULT TO ZERO BYTES
	JUMPE	P1,UDSER1	;DON'T KNOW DRIVE IF NO OPERATION
	MOVSI	T3,UNPHWP##	;GET WRITE PROTECT BIT
	TLNE	T2,(S1.WRI)	;WRITE INHIBITED?
	IORM	T3,UNIDES##(U)	;YES, SET THE BIT IN THE UDB
	TLNE	T2,(S0.IRQ)	;INTERVENTION REQUIRED?
	JRST	SELERR		;YES, CALL THE DRIVE OFF-LINE
UDSER1:	TLNE	T2,(S0.DTC)	;DATA CHECK?
	TROA	T1,IODTER	;YES, CALL IT A DATA ERROR
	TRO	T1,IODERR	;NO, FLAG A DEVICE ERROR
	MOVEI	T2,.ESSB7	;EST INDEX TO GET SENSE BYTE 7
	PUSHJ	P,RDEST		;READ IT (ACTUALLY 4-7)
	  MOVEI	T2,0		;SHOULDN'T HAPPEN, DEFAULT TO 0
	ANDI	T2,EB.S07	;KEEP JUST THE ONE BYTE
	CAIN	T2,.S7ECC	;ECC ERROR?
	TRO	T1,IOECCX	;YES, SET BIT FOR FILIO
	POPJ	P,		;RETURN

;HERE ON A RECORD LENGTH ERROR

RLNERR:	SKIPE	DINITF##	;IN ONCE-ONLY?
	TLNN	P1,(CM.IO)	;  AND DOING A READ?
	JRST	RLNER1		;NO
	TRNE	T1,ALLERR	;ANY OTHER ERRORS DETECTED SO FAR?
	POPJ	P,		;YES, THEY TAKE PRECEDENCE
	TDZ	P3,[CS.SWC!CS.OVR!CI.OVR] ;NO, MUST BE ONCE READING THE
	TLZA	P2,-1		;  HOME BLOCKS OF A TOPS20 FORMATTED PACK
RLNER1:	TRO	T1,IODERR	;ELSE FLAG A DEVICE ERROR
	POPJ	P,		;RETURN

;HERE ON A DEVICE SELECTION ERROR

SELERR:	MOVSI	T3,UNPOFL##	;GET OFF-LINE BIT
	SKIPE	P1		;DON'T NO WHAT DRIVE IF NO OPERATION
	IORM	T3,UNIDES##(U)	;MARK THE DRIVE OFF-LINE
;;	PJRST	RCVERR		;FALL INTO RCVERR

;HERE ON RECOVERABLE ERROR

RCVERR:	TRO	T1,IODERR	;FLAG DEVICE ERROR
	POPJ	P,		;RETURN
;HERE ON COMMAND RETRY REQUEST

RTYERR:	TRO	T1,IODERR	;FLAG DEVICE ERROR
	MOVSI	T2,(.DXFLG)	;POINT AT FLAG REGISTER
	PUSHJ	P,DODTI		;READ IT
	TRZ	T2,FA.RTY	;CLEAR RETRY REQUEST BIT
	HRLI	T2,(.DXFLG)	;SET TO CLEAR IT
	PJRST	DODTO		;CLEAR BIT AND RETURN

;HERE ON NON-RECOVERABLE ERROR

NRCERR:

;HERE ON FATAL ERROR OR UNKNOWN CODE

FTLERR:	TRO	T1,IODERR	;FLAG DEVICE ERROR
	MOVSI	T2,(RN.FTL)	;FLAG THIS FOR CALL TO RNXERR
	IORM	T2,RNXFLG##(J)	;  AS UNRECOVERABLE
	POPJ	P,		;RETURN
;HERE ON MICROCODE RELOAD.  DETERMINE WHICH UNITS ON THIS DX20
;ARE OFFLINE WAITING FOR OPERATOR INTERVENTION AND GIVE A FREE
;ATTENTION INTERRUPT TO FILIO FOR THOSE DRIVES.  THIS MEANS THAT
;RELOADING THE MICROCODE SHOULD BE SUFFICIENT TO RESTART ANY JOBS THAT
;ARE STOPPED WITH OFFLINE MESSAGES BECAUSE THE DX20 STOPPED.

RLDERR:	PUSHJ	P,LOGUPE	;LOG IT SINCE MPCHK WILL BLAST THE REGISTERS
	PUSHJ	P,MPCHKS	;MAKE SURE IT'S VALID MICROCODE
	  JRST	FTLERR		;IT'S NOT, CALL IT FATAL
	SETZM	@RNXRSC##(J)	;CLEAR RESTART COUNTER
	PUSHJ	P,RNXCSB	;CLEAR THE BIT IN THE KDB
	PUSHJ	P,SAVE2##	;SAVE P1-P2


;HERE FOR EACH KDB ASSOCIATED WITH THIS DX20 WITH THE KDB ADDRESS IN
;J TO LOOK AT ALL UDB'S TO SEE IF WE SHOULD GIVE FILIO AN ATTENTION
;INTERRUPT FOR THE UNIT.

RLDER1:	PUSH	P,U		;SAVE U
	MOVE	P1,KONTBP##(J)	;GET AOBJN POINTER TO UDB TABLE
	MOVEI	P2,0		;START WITH NO BITS TO SET
RLDER2:	HRRZ	U,(P1)		;GET THE NEXT KDB ADDRESS
	JUMPE	U,RLDER3	;GO IF NO UDB
	MOVE	T2,UNISTS##(U)	;GET THE UNIT STATUS FOR THIS UDB
	LDB	T3,UNYPUN##	;PLUS THE PHYSICAL UNIT NUMBER ON THE KDB
	CAIE	T2,OWCOD##	;IS IT IN ONE OF THE STATES WAITING FOR
	CAIN	T2,OCOD##	;  OPERATOR INTERVENTION?
	IOR	P2,BITTBL##(T3)	;YES, SET THE CORRESPONDING BIT IN P2
RLDER3:	AOBJN	P1,RLDER2	;LOOP FOR ALL UDB'S ON THIS KDB
	IORM	P2,RNXATN##(J)	;SET THE APPROPRIATE ATTENTION BITS
	JRST	UPOPJ##		;RESTORE U AND RETURN
	SUBTTL	ERROR LOGGING ROUTINES


;ROUTINE TO READ THE "REGISTERS" INTO KONEBK FOR THE RP20.
;ENTER AT RDREG FOR INTERNAL CALL.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNXREG
;RETURN CPOPJ ALWAYS
;DESTROYS T2-T3

RNXREG::PUSHJ	P,SETRH2	;SET IVI, MBE, PIA
RDREG:	PUSHJ	P,SAVE2##	;SAVE P1-P2
	MOVSI	T2,(.DIPBA)	;POINT AT RH20 PBAR
	PUSHJ	P,DODTIC	;READ IT
	MOVEM	T2,KONEDB##(J)	;STORE IN KDB
	MOVSI	T2,(.DIPTC)	;POINT AT RH20 PTCR
	PUSHJ	P,DODTIC	;READ IT
	MOVEM	T2,KONECR##(J)	;STORE IN KDB
	MOVE	T2,KONIOC##(J)	;GET ADDRESS OF LOGOUT AREA
	MOVE	T2,.CSICW(T2)	;GET INITIAL CHANNEL JUMP WORD
	MOVEI	T3,0		;ASSUME NO IOWDS
	TRNE	T2,-1		;ANY ADDRESS?
	MOVE	T3,0(T2)	;YES, GET FIRST CCW
	MOVEM	T3,KONEBK##+.EBCC1(J) ;STORE IT
	TRNE	T2,-1		;ANY ADDRESS?
	MOVE	T3,1(T2)	;YES, GET SECOND CCW
	MOVEM	T3,KONEBK##+.EBCC2(J) ;STORE IT
	HRLZ	T2,KONIOC##(J)	;GET LOGOUT AREA ADDRESS BACK
	HRRI	T2,KONEBK##+.EBCS0(J) ;MAKE IT A BLT POINTER
	BLT	T2,KONEBK##+.EBCS2(J) ;STORE LOGOUT AREA WORDS 0-2
	MOVE	T2,KONCHN##(J)	;GET ADDRESS OF CHANNEL DATA BLOCK
	MOVE	T3,.CHMPE(T2)	;GET COUNT OF MEMORY PARITY ERRORS
	MOVEM	T3,KONEBK##+.EBMPE(J) ;STORE IT
	MOVE	T3,.CHNXM(T2)	;GET COUNT OF NXM'S
	MOVEM	T3,KONEBK##+.EBNXM(J) ;STORE IT
	LDB	T2,RNYDXN	;GET DX20 ADDRESS
	LSH	T2,^D9		;SHIFT BY 9 BITS
	HRLM	T2,KONEBK##+.EBTYP(J) ;STORE IN KDB

				;CONTINUED ON THE NEXT PAGE
				;CONTINUED FROM THE PREVIOUS PAGE

;HERE TO STORE THE MASSBUS REGISTERS IN THE KDB.  WE ONLY SAVE THOSE
;REGISTERS SPECIFIED BY THE BIT TABLE MBRTBL.

	MOVE	T2,[.EBNMR,,.EBSMR-.EBMBR] ;GET POINTER TO MASSBUS REGS
	MOVEM	T2,KONEBK##+.EBMBR(J) ;STORE IN KDB
	MOVEI	P1,KONEBK##+.EBSMR(J) ;POINT TO START OF BLOCK
	MOVE	P2,[MBRTBL]	;GET BIT TABLE OF REGISTERS TO SAVE
RDREG1:	JUMPGE	P2,RDREG2	;IF BIT NOT SET, DON'T SAVE THIS ONE
	HLLZ	T2,P1		;GET REGISTER ADDRESS
	CAMN	T2,[.DXMIR]	;TRYING TO READ THE IR?
	TDZA	T2,T2		;YES, DO IT LATER
	PUSHJ	P,DODTI		;READ IT
	MOVEM	T2,(P1)		;STORE IN BLOCK
	HRRI	P1,1(P1)	;BUMP BLOCK POINTER BY 1
RDREG2:	ADD	P1,[1B5]	;PLUS REGISTER ADDRESS BY 1
	LSH	P2,1		;SHIFT BIT TABLE BY 1
	JUMPN	P2,RDREG1	;LOOP IF MORE TO READ
	PUSHJ	P,REDMIR	;CONDITIONALLY READ THE IR REGISTER

;HERE TO STORE THE DX20 REGISTERS IN THE KDB.  THE DX20 MUST BE RUNNING
;IN ORDER TO DO THIS SINCE WE REQUEST EACH REGISTER THROUGH THE
;EXTENDED STATUS TABLE.

	PUSHJ	P,MPRUN		;MICROPROCESSOR STILL RUNNING?
	  JRST	RDREG5		;NO, ZERO COUNT AND RETURN
	MOVSI	P1,-.EBNDR	;BUILD AOBJN POINTER TO REGISTERS
RDREG3:	MOVEI	T2,(P1)		;MOVE INDEX INTO EST TO T2 FOR RDEST
	PUSHJ	P,RDEST		;READ APPROPRIATE SENSE BYTES
	  JRST	RDREG4		;QUIT IF DX20 DIDN'T RESPOND
	MOVEI	T3,KONEBK##+.EBSDR(J) ;GET ADDRESS OF START OF BLOCK
	ADDI	T3,(P1)		;OFFSET INTO IT FOR THIS REGISTER
	MOVEM	T2,(T3)		;STORE REGISTER IN BLOCK
	AOBJN	P1,RDREG3	;LOOP FOR ALL REGISTERS
RDREG4:	MOVSS	P1		;PUT NUMBER OF REGISTERS IN LH
	HRRI	P1,.EBSDR-.EBDVL ;PUT OFFSET IN RH
	TLNN	P1,-1		;IF COUNT IS ZERO,
RDREG5:	MOVEI	P1,0		;ZERO THE WHOLE WORD
	MOVEM	P1,KONEBK##+.EBDVL(J) ;STORE IN KDB
	POPJ	P,		;RETURN
;ROUTINE TO CONDITIONALLY READ THE MICROPROCESSOR INSTRUCTION
;REGISTER.  WE DON'T DO THIS UNLESS THE MICROPROCESSOR IS STOPPED
;BECAUSE READING THE IR WITH IR ENABLE SET CAUSES IT TO BE LOADED
;FROM THE MICROSTORE LOCATION CURRENTLY POINTED TO BY THE PC.  THIS
;SOMETIMES CAUSES IR PARITY ERRORS.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,REDMIR
;RETURN CPOPJ ALWAYS

REDMIR:	DMOVE	T2,KONEBK##+.EBSMR+.EBM00(J) ;GET CONTROL AND STATUS REGS
	TRNN	T2,CR.GO	;IS GO STILL UP?
	TRNE	T3,ST.RUN	;NO, IS THE UCODE STILL RUNNING?
	POPJ	P,		;YES, DON'T READ THE REGISTER
	MOVSI	T2,(.DXPCR)	;SETUP TO READ THE PC REGISTER
	PUSHJ	P,DODTI		;DO SO
	TRZ	T2,PC.IRE	;TURN OFF IR ENABLE
	HRLI	T2,(.DXPCR)	;PUT THE REGISTER NUMBER BACK
	PUSHJ	P,DODTO		;WRITE OFF IR ENABLE
	MOVSI	T2,(.DXMIR)	;POINT TO IR REGISTER
	PUSHJ	P,DODTI		;READ IT
	MOVEM	T2,KONEBK##+.EBSMR+.EBM30(J) ;STORE WHERE IT BELONGS
	POPJ	P,		;RETURN
;ROUTINE TO CALL DAEMON TO LOG AN ERROR THAT FILIO WILL NOT, E.G.,
;POSITIONING ERRORS, MICRODIAGNOSTICS FAILURES WHILE NO OPERATION
;IS IN PROGRESS, ETC.
;CALL:
;	J/KDB ADDRESS
;	P1/FLAGS FROM RNXCMD
;	P3/CHANNEL STATUS OR 0,,CONI
;	PUSHJ	P,LOGUPE
;RETURN CPOPJ ALWAYS

LOGUPE:	SKIPE	DINITF##	;IN ONCE-ONLY?
	POPJ	P,		;YES, CAN'T LOG THEM THIS EARLY
	PUSHJ	P,SAVT##	;SAVE T1-T4
	PUSH	P,U		;  AND U
	PUSH	P,F		;  AND F
	MOVSI	T2,1		;COUNT THE NUMBER OF TIMES WE
	ADDM	T2,RNXEC1##(J)	;  WERE CALLED TO LOG AN ERROR
	PUSHJ	P,RDREG		;READ THE REGISTERS
	HRRZ	U,KONTBP##(J)	;GET BASE ADDRESS OF UDB TABLE
	LOAD	T2,P1,CM.UNF	;GET UNIT NUMBER FOR OPERATION
	ADDI	U,(T2)		;OFFSET TO CORRECT WORD IN TABLE
	HRRZ	U,(U)		;GET UDB ADDRESS
	JUMPE	U,FUPOPJ##	;QUIT IF NO UDB
	SKIPL	UNIECT##(U)	;IF THIS UDB IS IN ERROR RECOVERY, DON'T
	JRST	FUPOPJ##	;OVERWRITE THE (MORE IMPORTANT) DATA
	MOVEI	F,DSKDDB##	;GET THE GENERIC DDB
	PUSHJ	P,FSTREG##	;COPY INITIAL REGISTERS TO UDB
	PUSHJ	P,LSTER##	;  PLUS FINAL REGISTERS
	MOVEM	P3,UNISOF##(U)	;STORE INITIAL CONI
	MOVEM	P3,UNIERR##(U)	;  AND FINAL CONI
	MOVEI	T1,.ERDPE	;GET CODE FOR DISK ERROR
	HRL	T1,F		;PUT DDB ADDRESS IN LH(T1)
	PUSH	P,J		;DAEEIM SMASHES J
	PUSHJ	P,DAEEIM##	;TELL DAEMON
	POP	P,J		;RESTORE J
	JRST	FUPOPJ##	;RESTORE F, U AND RETURN
;ROUTINE TO REQUEST AND THEN READ INFORMATION FROM THE TWO EXTENDED
;STATUS REGISTERS IN THE DX20.  THE INFORMATION THAT IS RETURNED IS
;A FUNCTION OF THE VALUE OF THE STATUS INDEX WHICH IS AN INPUT ARGUMENT
;TO THIS ROUTINE.
;CALL:
;	T2/STATUS INDEX
;	J/KDB ADDRESS
;	PUSHJ	P,RDEST
;RETURN CPOPJ IF THE DX20 DIDN'T RESPOND TO THE HANDSHAKE
;	CPOPJ1 IF WE GOT THE DATA WITH:
;	T2/.DXES1,,.DXES2

RDEST:	PUSHJ	P,SAVE1##	;GET A REGISTER TO USE
	IOR	T2,[.DXESR!ES.SUI] ;SET REGISTER AND REQUEST UPDATE
	PUSHJ	P,DODTO		;ASK THE DX20 FOR THE REGISTERS
	MOVEI	P1,^D1000	;TIME TO WAIT FOR THE BIT TO CLEAR
RDEST1:	MOVSI	T2,(.DXESR)	;POINT TO STATUS INDEX REGISTER
	PUSHJ	P,DODTI		;READ IT
	TRNE	T2,ES.SUI	;DID THE DX20 CLEAR THE BIT YET?
	SOJG	P1,RDEST1	;NO, LOOP
	JUMPLE	P1,CPOPJ##	;RETURN NON-SKIP IF THE DX20 DIDN'T RESPOND
	MOVSI	T2,(.DXES2)	;POINT AT SECOND EXTENDED STATUS REGISTER
	PUSHJ	P,DODTI		;READ IT
	PUSH	P,T2		;SAVE FOR LATER
	MOVSI	T2,(.DXES1)	;POINT AT FIRST REGISTER
	PUSHJ	P,DODTI		;READ IT
	HRLM	T2,0(P)		;STORE IN LH OF STACK LOCATION
	JRST	T2POJ1##	;GIVE SKIP RETURN WITH VALUE IN T2
	SUBTTL	MISCELLANEOUS SUPPORT SUBROUTINES


;ROUTINE TO SET .DXDNM TO THE DRIVE NUMBER OF THE DRIVE FOR WHICH
;WE ARE ABOUT TO PERFORM AN OPERATION.
;CALL:
;	J/KDB ADDRESS
;	U/UDB ADDRESS
;	PUSHJ	P,SETDRV
;RETURN CPOPJ ALWAYS WITH:
;	RH(T2)/DRIVE ADDRESS
;DESTROYS T3

SETDRV:	LDB	T2,UNYPUN##	;GET PHYSICAL UNIT NUMBER FROM UDB
	LDB	T3,RNYDCA	;GET CONTROL UNIT ADDRESS FROM KDB
	LSH	T3,4		;POSITION IT
	IOR	T2,T3		;BUILD FULL DRIVE ADDRESS
;;	PJRST	WDVNUM		;FALL INTO WDVNUM


;ROUTINE TO SET .DXDNM TO THE DRIVE NUMBER OF THE DRIVE FOR WHICH
;WE ARE ABOUT TO PERFORM AN OPERATION
;CALL:
;	T2/DRIVE ADDRESS
;	J/KDB ADDRESS
;	PUSHJ	P,WDVNUM
;RETURN CPOPJ ALWAYS WITH:
;	RH(T2)/DRIVE ADDRESS

WDVNUM:	HRLI	T2,(.DXDNM)	;GET REGISTER TO WRITE
	PJRST	DODTO		;WRITE REGISTER AND RETURN
;ROUTINE TO WAIT FOR A COMMAND TO COMPLETE AND CALL RNXINR TO PROCESS
;IT BEFORE STARTING A NEW COMMAND.
;CALL:
;	T1/CURRENT COMMAND
;	T4/FLAGS FROM RNXCMD FOR OLD COMMAND
;	U/UDB ADDRESS
;	J/KDB ADDRESS
;	PUSHJ	P,CMDWAT
;RETURN CPOPJ ALWAYS WITH:
;	T4/NON-ZERO TO TOSS THIS COMMAND
;PRESERVES T1, U

CMDWAT:	AOS	RNXEC2##(J)	;COUNT NUMBER OF TIMES WE GOT HERE
	JUMPGE	T4,CMDWA2	;GO IF PREVIOUS COMMAND NOT AN XFER
	PUSHJ	P,RDREG		;READ THE REGISTERS FOR THE DUMP
	STOPCD	CPOPJ##,DEBUG,KCP, ;++KDB COMMAND IN PROGRESS
CMDWA2:	MOVEI	T2,^D2000	;WAIT FOR THE COMMAND
	PUSHJ	P,WGOCLR	;  TO FINISH
	JUMPLE	T2,CMDWA3	;JUMP IF GO STILL UP
	PUSHJ	P,SAVE3##	;RNXINR DESTROYS P1-P2
	PUSH	P,T1		;  AND T1
	PUSH	P,U		;  AND U
	PUSHJ	P,RNXINR	;DO SUBSET OF INTERRUPT PROCESSING
	POP	P,U		;RESTORE U
	SETZ	T4,		;LET THIS COMMAND THROUGH
	JRST	TPOPJ##		;RESTORE T1 AND RETURN

;HERE IF THE GO BIT DIDN'T COME DOWN IN TIME.
;EXIT FROM THE NEW COMMAND WITHOUT DOING ANYTHING.
;WAIT FOR THE PREVIOUS COMMAND TO FINISH, THEN TELL
;FILIO THAT THE NEW COMMAND IS FINISHED (THIS IS A LIE).
;IF THE NEW COMMAND IS A TRANSFER, THEN TELL FILIO "POSITION DONE".
;FILIO WILL THINK HE'S IN THUNG RECOVERY AND WILL RE-ISSUE THE
;TRANSFER COMMAND.
;IF THE NEW COMMAND IS A POSITION, THEN TELL FILIO "RECAL DONE".
;FILIO WILL THINK HE'S IN PHUNG RECOVERY AND WILL RE-ISSUE THE
;POSITION COMMAND.
CMDWA3:	MOVSI	T4,(1B0)	;RECAL BIT (PHUNG RECOVERY)
	CAIN	T1,.DXCTR!.CRSRC;POSITION COMMAND?
	IORM	T4,UNISTS##(U)	;YES, TELL FILIO "RECAL DONE"
	LDB	T4,UNYPUN##	;GET PHYSICAL UNIT NUMBER OF UNIT
	MOVE	T4,BITTBL##(T4)	;GET CORRESPONDING BIT
	IORM	T4,RNXATN##(J)	;SET IN KDB FOR INTERRUPT
	MOVSI	T4,1		;COUNT THIS EVENT
	ADDM	T4,RNXEC2##(J)	;  IN THE KDB
	POPJ	P,		;RETURN WITH T4 NON-ZERO
;ROUTINE TO WAIT FOR THE GO BIT TO CLEAR IN THE CONTROL REGISTER.
;CALL:
;	J/KDB ADDRESS
;	T2/LOOP COUNT TO WAIT BEFORE TIMING OUT
;	PUSHJ	P,WGOCLR
;RETURN CPOPJ ALWAYS WITH:
;	T2/LOOP COUNT AT WHICH GO BIT CLEARED
;DESTROYS T2,T3

WGOCLR:	PUSH	P,T2		;SAVE LOOP COUNT
WGOCL1:	MOVSI	T2,(.DXCTR)	;POINT AT CONTROL REGISTER
	PUSHJ	P,DODTI		;READ IT
	TRNN	T2,CR.GO	;GO BIT STILL UP?
	JRST	T2POPJ##	;NO, RETURN
	SOSLE	0(P)		;DECREMENT LOOP COUNT
	JRST	WGOCL1		;AND LOOP
	AOS	RNXEC1##(J)	;COUNT NUMBER OF TIMES GO BIT DIDN'T CLEAR
	JRST	T2POPJ##	;TIMED OUT, RETURN ANYWAY
;ROUTINE TO CLEAR THE ATTENTION SUMMARY REGISTER FOR THIS DX20.  WE
;ALSO CHECK TO MAKE SURE THAT NO SPURIOUS ATTENTION BITS HAVE COME UP
;FOR SOME OTHER DEVICE ON THIS RH20 AND MAKE SURE THAT THEY ARE
;CLEARED.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,CLRATN
;RETURN CPOPJ ALWAYS
;DESTROYS T2,T3

CLRATN:	PUSH	P,T4		;SAVE T4 (SEE RNXCPY)
	MOVEI	T4,1		;GET A BIT TO SHIFT
	LDB	T2,RNYDXN	;GET DX20 MASSBUS SLOT
	LSH	T4,(T2)		;SHIFT TO CORRECT POSITION
	HRLS	T4		;COPY TO LH
	TLC	T4,AT.ATN	;MAKE IT ALL BUT THAT BIT IN LH
	MOVSI	T2,(.DXASR)	;SET TO READ ATTENTION SUMMARY REGISTER
	PUSHJ	P,DODTI		;READ IT
;	TSNE	T2,T4		;ANY UNEXPECTED ATTENTION BITS SET?
;	PUSHJ	P,LOGUPE	;YES, LOG THIS AS AN ERROR
	TRNN	T2,AT.ATN	;ANY ATTENTION BITS TO CLEAR?
	JRST	CLRAT2		;NO, EXIT
	HRLI	T2,(.DXASR)	;SET TO CLEAR THE BITS WE READ
	PUSHJ	P,DODTO		;CLEAR THE ATTENTION BITS
	MOVSI	T2,(.DXASR)	;SET TO READ THE REGISTER AGAIN
	PUSHJ	P,DODTI		;READ IT
	TSNE	T2,T4		;STILL HAVE UNEXPECTED BITS SET?
	JRST	CLRAT1		;YES, HAVE TO BLAST THE RH20 THEN
	TDNN	T2,T4		;STILL HAVE THE DX20 BIT UP?
	JRST	CLRAT2		;NO, EXIT
	AOS	T2,RNXAEC##(J)	;INCREMENT RETRY COUNT OF TIMES TO CLEAR IT
	TLZ	T2,-1		;CLEAR LEFT HALF
	CAIG	T2,ATNRTY	;FAIL TO CLEAR IT TOO MANY TIMES?
	JRST	T4POPJ##	;BELOW THE THRESHOLD, JUST EXIT
;	PUSHJ	P,LOGUPE	;LOG THIS AS AN ERROR
CLRAT1:	MOVSI	T2,1		;INCREMENT THE LEFT HALF TO
	ADDM	T2,RNXAEC##(J)	;  INDICATE THAT WE DID SOMETHING
	PUSHJ	P,CLRRH2	;BLAST THE RH20 TO CLEAR THE BITS
CLRAT2:	HLLZS	RNXAEC##(J)	;CLEAR RH OF RETRY COUNT WORD
	JRST	T4POPJ##	;RESTORE T4 AND EXIT


;The calls to LOGUPE are not assembled because CLRATN is called from
;RNXCPY without P1 and P3 containing the data that LOGUPE wants in
;those ACs.  We really need a BUGCHK mechanism for this kind of
;thing.
;ROUTINE TO CLEAR THE ERROR REGISTER IN THE DX20.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,CLRERG
;RETURN CPOPJ ALWAYS
;DESTROYS T2,T3

CLRERG:	MOVSI	T2,(.DXERR)	;POINT AT ERROR REGISTER
	PJRST	DODTO		;CLEAR IT AND RETURN


;ROUTINES TO SET/CLEAR KOPMPS IN THE KDB WHEN THE MICROPROCESSOR
;STOPS/RESTARTS.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNX?SB
;RETURN CPOPJ ALWAYS
;DESTROYS T2

RNXCSB::SKIPA	T2,[ANDCAM T2,KONMPS##(J)] ;GET INSTR TO CLEAR BIT
RNXSSB:	MOVE	T2,[IORM T2,KONMPS##(J)]  ;OR INSTR TO SET BIT
	PUSH	P,T2		;SAVE INSTRUCTION
	MOVSI	T2,KOPMPS##	;GET THE BIT
	XCT	0(P)		;SET/CLEAR IT
	JRST	T2POPJ##	;BRING STACK INTO PHASE AND RETURN
;ROUTINE TO READ THE DRIVE TYPE REGISTER FOR THE DX20 AND CHECK
;TO MAKE SURE THAT IT IS CORRECT FOR THE RP20.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,CHKDTR
;RETURN CPOPJ IF NOT A DX20 FOR AN RP20
;	CPOPJ1 IF MATCH WITH:
;	T2/CONTENTS OF REGISTER

CHKDTR:	MOVSI	T2,(.DXDTR)	;POINT AT DRIVE TYPE REGISTER
	PUSHJ	P,DODTI		;READ IT
	PUSH	P,T2		;SAVE FOR RETURN
	ANDI	T2,DT.COD	;MASK OFF JUST THE DRIVE TYPE
	CAIN	T2,.DTCOD	;DOES IT MATCH?
	AOS	-1(P)		;YES, GIVE SKIP RETURN
	PJRST	T2POPJ		;RETURN VALUE IN T2


;ROUTINE TO ASSIGN AN INTERRUPT VECTOR ADDRESS TO THE RH20 AND
;GIVE IT A PIA WITH OR WITHOUT ATTENTION INTERRUPT ENABLE DEPENDING
;ON WHAT'S HAPPENING.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,SETRH2
;RETURN CPOPJ ALWAYS
;PRESERVES ALL AC'S

SETRH2:	PUSHJ	P,RNXIVI	;ASSIGN IVI, ENABLE MASSBUS
;	PJRST	REASPI		;FALL INTO REASPI


;ROUTINE TO REASSIGN THE PIA FOR THE RH20 WITH OR WITHOUT ATTENTION
;INTERRUPT ENABLE DEPENDING ON WHAT'S HAPPENING.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,REASPI
;RETURN CPOPJ ALWAYS
;PRESERVES ALL AC'S

REASPI:	PUSH	P,T4		;SAVE T4
	PUSHJ	P,SETCO		;SETUP CONO MASK
	XCT	RNXCO4##(J)	;LIGHT PIA, POSSIBLY AIE
	JRST	T4POPJ##	;RESTORE T4 AND RETURN
;ROUTINE TO FORCE THE RH20 AND CONNECTED DEVICES INTO A KNOWN STATE.
;THIS INVOLVES DOING A MASSBUS INIT, A STOP TRANSFER, AND A CLEAR
;DONE.  WE THEN HAVE TO REASSIGN THE RH20 IVI AND RESTART THE MICRO-
;PROCESSOR.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,CLRRH2
;RETURN CPOPJ ALWAYS

CLRRH2:	MOVEI	T2,CO.MBI	;THE ONLY THING LEFT TO DO IS TO
	XCT	RNXCO2##(J)	;  BLAST THE RH20. DO A MASSBUS INIT FIRST
	MOVEI	T2,CO.MBE!CO.STP ;THEN A
	XCT	RNXCO2##(J)	;  STOP TRANSFER
	MOVEI	T2,CO.MBE!CO.CLR ;AND FINALLY A
	XCT	RNXCO2##(J)	;  CLEAR DONE
	PUSHJ	P,RNXIVI	;GIVE IT AN IVI AGAIN SINCE MBI BLASTS IT
	PJRST	RNXMPS		;START THE MICROPROCESSOR GOING AGAIN
;ROUTINE TO ASSIGN AN INTERRUPT VECTOR ADDRESS TO THE RH20.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNXIVI
;RETURN CPOPJ ALWAYS
;PRESERVES ALL AC'S

RNXIVI::PUSHJ	P,SAVT##	;SAVE T1-T4
	MOVEI	T2,CO.MBE	;ENABLE MASSBUS TRANSCEIVERS
	XCT	RNXCO2##(J)	;  FIRST
	LDB	T2,KOYPI##	;GET PI ASSIGNMENT
	LSH	T2,1		;COMPUTE AN INTERRUPT
	ADDI	T2,40		;  ADDRESS OF 40+2N
	HRLI	T2,(.DOIVI)	;POINT TO PROPER REGISTER
	PJRST	DODTO		;WRITE REGISTER AND RETURN


;ROUTINE TO SETUP A CONO MASK WITH THE PIA AND POSSIBLY ATTENTION
;INTERRUPT ENABLE IF NO TRANSFER IS TAKING PLACE.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,SETCO
;RETURN CPOPJ ALWAYS WITH:
;	T4/CONO MASK

SETCO:	LDB	T4,KOYPI##	;GET PIA FOR THE RH20
	TRO	T4,CO.MBE	;SET TO ENABLE MASSBUS TRANSCEIVERS
	SKIPL	RNXCMD##(J)	;TRANSFER IN PROGRESS?
	TRO	T4,CO.AIE	;NO, ALLOW INTERRUPTS ON ATTENTIONS
	POPJ	P,		;RETURN
;ROUTINE TO SET A BIT IN RNXATN CORRESPONDING TO A DRIVE NUMBER
;WHICH JUST COMPLETED A POSITION OPERATION.
;CALL:
;	T2/DRIVE NUMBER (ALL 4 BITS)
;	PUSHJ	P,POSDON
;RETURN CPOPJ ALWAYS

POSDON:	MOVE	T3,BITTBL##(T2)	;GET THE APPROPRIATE BIT
	IORM	T3,RNXATN##(J)	;SET BIT IN KDB
	HRRZ	T3,T2		;COPY 4 BIT DRIVE ADDRESS
	ADD	T3,KONTBP##(J)	;POINT AT UDB ADDRESS SLOT IN KDB
	SKIPN	T3,(T3)		;GET UDB ADDRESS
	JRST	POSDO3		;NO UDB, CALL NEWDSK
	MOVSI	T2,UNPHWP##	;GET HARDWARE WRITE PROTECT BIT
	SKIPE	T4,UNISTS##(T3)	;UNIT IDLE?
	CAIL	T4,OWCOD##	; OR SOME FORM OF OPERATOR WAIT?
	ANDCAM	T2,UNIDES##(T3)	;CLEAR HARDWARE WRITE PROTECT BIT
	POPJ	P,		;RETURN

;HERE IF THERE WAS NO UDB FOR THE DRIVE. CALL NEWDSK TO TELL THE
;MONITOR THAT A NEW DRIVE JUST CAME ON-LINE.  T2 CONTAINS THE 4 BIT
;DRIVE ADDRESS OF THE UNIT THAT CAME ON-LINE.

POSDO3:
IFE FTAUTC,<
	POPJ	P,		;CHUCK IT IF NO AUTCON
>
IFN FTAUTC,<
	PUSHJ	P,SAVT##	;SAVE THE T AC'S
	MOVEI	T1,.DTCOD	;SETUP DRIVE TYPE FOR NEWDSK
	HRLZS	T2		;PUT THE DRIVE NUMBER IN THE LEFT HALF
	PJRST	NEWDSK##	;CALL NEWDSK AND RETURN
>
	SUBTTL	INITIALIZATION SUPPORT SUBROUTINES


;ROUTINE TO DO TWO TEST I/O COMMANDS TO A PARTICULAR DRIVE TO SEE
;IF IT IS ON-LINE.  TWO COMMANDS ARE REQUIRED BECUASE SOMETIMES THE
;8000 LIES AND SAYS THE DRIVE IS ON-LINE WHEN IT ISN'T AND THE FIRST
;ATTEMPT TO ACCESS THE DRIVE CAUSES OFF-LINE MESSAGES.  TWO TEST I/O'S
;ALWAYS SEEM TO WORK (IF YOU BELIEVE...)
;CALL DOTIOC IF THE CONTROLLER AND DRIVE NUMBERS HAVE ALREADY BEEN
;WRITTEN INTO MASSBUS REGISTER .DXDNM.  THIS ENTRY POINT DOES NOT
;REQUIRE THAT U BE SETUP TO THE UDB ADDRESS.
;CALL:
;	U/UDB ADDRESS
;	J/KDB ADDRESS
;	PUSHJ	P,DO2TIO
;RETURN CPOPJ IF THE DX20 DIDN'T RESPOND
;	CPOPJ1 IF IT PROCESSED BOTH COMMANDS

DO2TIO:	PUSHJ	P,SETDRV	;SETUP TO TALK TO THE DRIVE
DOTIOC:	MOVSI	T2,<(.DXFLG)>+INSVL.(.FATIO,FA.FNC) ;TELL THE DX20
	PUSHJ	P,DODTO		;  THAT IT'S A TEST I/O
	PUSHJ	P,DO2TI1	;DO THE FIRST TEST I/O
	  POPJ	P,		;RETURN IF THE DX20 DIDN'T RESPOND
DO2TI1:	PUSHJ	P,CLRERG	;CLEAR THE ERROR REGISTER
	MOVEI	T2,.DXCTR!.CRNOP ;NO-OP IS THE GENERIC COMMAND
	PUSHJ	P,DODTO		;START IT GOING
	MOVEI	T2,^D5000	;MAX TIME TO WAIT FOR IT TO FINISH
	PUSHJ	P,WGOCLR	;WAIT FOR THE GO BIT TO CLEAR
	JUMPG	T2,CPOPJ1##	;GIVE SKIP RETURN IF THE BIT CLEARED
	POPJ	P,		;NON-SKIP IF IT DIDN'T


;ROUTINE TO CHECK FOR ERRORS IN THE TEST I/O SEQUENCE DONE TO
;SEE IF A UNIT IS ON-LINE.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,INIERR
;RETURN CPOPJ IF DRIVE IS ON-LINE
;	CPOPJ1 IF DRIVE EXISTS BUT IS OFF-LINE
;	CPOPJ2 IF DRIVE DOESN'T EXIST

INIERR:	MOVSI	T2,(.DXERR)	;POINT TO THE ERROR REGISTER
	PUSHJ	P,DODTI		;READ IT
	TRNN	T2,ER.UPE!ER.STP!ER.ERR	;ANY ERRORS SEEN?
	POPJ	P,		;NO, DRIVE IS ON-LINE
	LOAD	T2,T2,ER.ECC	;GET ERROR CLASS CODE
	CAIE	T2,.ERSEL	;WAS IT SELECT ERROR?
	JRST	CPOPJ1##	;NO, IT EXISTS BUT IT'S OFF-LINE
	JRST	CPOPJ2##	;ELSE IT DOESN'T EXIST
;ROUTINE TO FIND THE NEXT RP20 UNIT THAT EXISTS AND RETURN THE
;CONTROLLER AND UNITS NUMBERS TO AUTCON.
;CALL:
;	T1/CONTROLLER ADDRESS,,UNIT ADDRESS (-1 FOR FIRST TIME)
;	T2/DRIVE SELECT CODE FOR DATAO (RNYDXN)
;	J/KDB ADDRESS
;	PUSHJ	P,RNXCFG
;RETURN CPOPJ IF NO MORE UNITS ON THIS DX20
;	CPOPJ1 IF ANOTHER UNIT FOUND WITH:
;	T1/CONTROLLER ADDRESS,,UNIT ADDRESS OF NEXT UNIT

RNXCFG::PUSHJ	P,SAVE3##	;SAVE P1-P3
	MOVE	P1,T1		;SAVE INITIAL VALUE OF T1 FOR FLAG
	HLRE	P2,T1		;GET THE INITIAL CONTROLLER NUMBER
	HRRE	P3,T1		;  AND THE INITIAL UNIT NUMBER
	DPB	T2,RNYDXN	;STORE THE DRIVE SELECT CODE IN THE KDB
	AOJN	P3,RNXCF1	;GO IF NOT THE FIRST TIME FOR THIS DX20
	PUSHJ	P,MPINI		;MAKE SURE THE MICROCODE IS VALID
	  POPJ	P,		;IT'S NOT, GIVE UP
RNXCF1:	PUSHJ	P,MPRUN		;CHECK TO MAKE SURE IT'S STILL RUNNING
	  POPJ	P,		;IT'S NOT, GIVE UP ON THAT ALSO
RNXCF2:	CAIL	P3,MAXSPD	;DONE ALL THE POSSIBLE UNITS YET?
	POPJ	P,		;YES, NO MORE UNITS FOUND
	JUMPGE	P1,RNXCF4	;GO IF ALREADY HAD THE CONTROLLER ADDR
	SETOM	P2		;INITIALIZE IT TO ZERO
RNXCF3:	AOS	P2		;INCREMENT THE CONTROLLER ADDRESS
	CAIL	P2,MAXDCU	;CHECKED ALL THE ONES FOR THIS UNIT?
	AOJA	P3,RNXCF2	;YES, INCREMENT THE UNIT AND CONTINUE
RNXCF4:	HRRZ	T2,P2		;GET THE CONTROLLER ADDRESS
	LSH	T2,4		;MAKE ROOM FOR THE UNIT NUMBER
	IOR	T2,P3		;OR IN THE UNIT NUMBER
	PUSHJ	P,WDVNUM	;TELL THE DX20 WHICH UNIT
	PUSHJ	P,DOTIOC	;DO TWO TEST I/O'S ON THE DRIVE
	  POPJ	P,		;DX20 DIDN'T RESPOND, GIVE UP
	PUSHJ	P,INIERR	;CHECK FOR ERRORS
	  JRST	RNXCF5		;ON-LINE DRIVE, RETURN IT
	  JRST	RNXCF5		;OFF-LINE DRIVE, RETURN IT
	JUMPL	P1,RNXCF3	;TRY NEXT DCU ADDR IF NOT FOUND YET
	AOJA	P3,RNXCF2	;ELSE INCREMENT UNIT ADDRESS AND CONTINUE
RNXCF5:	MOVSI	T1,(RN.FKA)	;SET FLAG TO AVOID THE DRIVE
	IORM	T1,RNXFLG##(J)	;  SELECT LOOP IN RNXFKA
;	DPB	P2,RNYDCA	;STORE DCU
;	MOVSI	T1,(RN.DCA)
;	IORM	T1,RNXFLG##(J)
	HRLZ	T1,P2		;CONTROLLER ADDRESS TO LH
	HRR	T1,P3		;UNIT ADDRESS TO RH
	JRST	CPOPJ1##	;GIVE SKIP RETURN
	SUBTTL	KONTROLLER ONCE-A-SECOND CODE


;ROUTINE TO CHECK THE MICROPROCESSOR
;CALL:	PUSHJ	P,RNXSEC
;RETURN	CPOPJ ALWAYS

RNXSEC::MOVSI	T2,(.DXSTR)	;POINT AT STATUS REGISTER
	PUSHJ	P,DODTI		;READ IT
	TRNN	T2,ST.RUN	;IS MICROPROCESSOR STILL RUNNING?
	SKIPG	KONRLD##(J)	;NOT RUNNING--OK TO ATTEMPT RELOAD?
	POPJ	P,		;RETURN
	PJRST	RNXRLD		;GO RELOAD MICROPROCESSOR
	SUBTTL	MICROPROCESSOR HANDLING ROUTINES


;ROUTINE TO START ALL DX20'S FOR RP20'S ON THIS CPU IF THEY ARE NOT
;ALREADY RUNNING.
;CALL:	PUSHJ	P,RNXSAK
;RETURN CPOPJ ALWAYS

RNXSAK::PJSP	T1,RNXAPP	;RETURN AT .+1 FOR EACH DX20
	PUSHJ	P,MPRUN		;THIS DX20 RUNNING?
	  PUSHJ	P,MPCHKS	;NO, CHECK THE CRAM AND RESTART IT
	POPJ	P,		;ALWAYS GIVE CPOPJ RETURN
	POPJ	P,		;DITTO


;ROUTINE TO CALL A SUBROUTINE FOR EACH RP20 DX20 ON THIS CPU.
;CALL:
;	T1/ADDRESS OF ROUTINE TO CALL
;	PUSHJ	P,RNXAPP
;RETURN CPOPJ ALWAYS
;THE ROUTINE BEING CALLED MUST RETURN CPOPJ ONLY.

RNXAPP:	PUSHJ	P,SAVT##	;SAVE THE T REGS
	PUSH	P,J		;DON'T SMASH J
	PUSH	P,T1		;SAVE THE ROUTINE ADDRESS
	MOVEI	J,SYSKON##-KONNXT## ;POINT TO START OF KDB CHAIN
RNXAP1:	HLRZ	J,KONNXT##(J)	;STEP TO NEXT DISK KDB
	JUMPE	J,RNXAP2	;GO IF END OF CHAIN
	LDB	T1,KOYKTP##	;GET KONTROLLER TYPE
	MOVE	T2,KONCAM##(J)	;  AND OWNING CPU MASK
	CAIN	T1,TYPRN##	;THIS AN RP20?
	TDNN	T2,.CPBIT##	;YES, IS IT ON THIS CPU?
	JRST	RNXAP1		;NO, CONTINUE
	PUSHJ	P,CHKDTR	;MAKE SURE IT'S REALLY AN RP20
	  JRST	RNXAP1		;NOT, CONTINUE
	PUSHJ	P,@0(P)		;CALL ROUTINE FOR THIS ONE
	JRST	RNXAP1		;TRY NEXT
RNXAP2:	POP	P,0(P)		;BRING STACK INTO PHASE
	JRST	JPOPJ##		;RESTORE J AND RETURN
;ROUTINE TO CHECK THE VALIDITY OF THE MICROPROCESSOR CONTROL STORE.
;THIS INVOLVES CHECKING THREE THINGS AS FOLLOWS:
;   1. CRAM LOCATION 7 MUST CONTAIN A COPY OF THE DRIVE TYPE REGISTER
;   2. CRAM LOCATION 10 MUST CONTAIN AN OCTAL 210 (.CRM10)
;   3. DX.IPE MUST NOT COME UP WHILE READING ANY OF THE ABOVE
;STORES THE MICROCODE VERSION NUMBER IN THE KDB(S) FOR THE DX20.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,MPCHK
;RETURN CPOPJ IF AN ERROR IS DETECTED
;	CPOPJ1 IF ALL OK
;PRESERVES T1

MPCHK:	PUSHJ	P,MPRES		;RESET THE MICROPROCESSOR
	MOVE	T2,[.DXPCR!PC.IRE!PC.PCE!PC.PCI!INSVL.(7,PC.MPC)] ;REGISTER TO WRITE+
				;  IR ENABLE+PC ENABLE+PC AUTO INCR+PC TO READ
	PUSHJ	P,DODTO		;WRITE THE REGISTER
	MOVSI	T2,(.DXMIR)	;POINT AT IR REGISTER
	PUSHJ	P,DODTI		;READ THE CONTENTS
	PUSH	P,T2		;SAVE FOR COMPARE
	MOVSI	T2,(.DXDTR)	;POINT AT DRIVE TYPE REGISTER
	PUSHJ	P,DODTI		;READ THAT
	POP	P,T3		;RESTORE CRAM LOCATION 7
	CAME	T2,T3		;HAVE TO BE THE SAME
	POPJ	P,		;ERROR IF NOT
	MOVSI	T2,(.DXIPE)	;POINT AT DIAGNOSTIC REGISTER 7
	PUSHJ	P,DODTI		;READ IT
	TRNE	T2,DX.IPE	;IR PARITY ERROR ON LAST READ?
	POPJ	P,		;YES, THAT'S AN ERROR
	MOVSI	T2,(.DXMIR)	;POINT AT DIAGNOSTIC REGISTER 0 AGAIN
	PUSHJ	P,DODTI		;READ CRAM LOC 10 (PC AUTO INCR SET)
	CAIE	T2,.CRM10	;MUST BE THIS VALUE
	POPJ	P,		;NOT, ERROR
	MOVSI	T2,(.DXIPE)	;POINT AT DIAGNOSTIC REGISTER 7
	PUSHJ	P,DODTI		;READ IT
	TRNE	T2,DX.IPE	;IR PARITY ERROR ON LAST READ?
	POPJ	P,		;YES, THAT'S AN ERROR
	MOVE	T2,[.DXPCR!PC.IRE!PC.PCE!INSVL.(0,PC.MPC)] ;SET TO READ CRAM LOC 0
	PUSHJ	P,DODTO		;TELL THE DX20
	MOVSI	T2,(.DXMIR)	;ANSWER APPEARS HERE
	PUSHJ	P,DODTI		;READ VERSION NUMBER
	MOVEM	T2,KONEBK##+.EBTYP(J) ;STORE MP VERSION IN KDB
	JRST	CPOPJ1##	;GIVE SKIP RETURN
;ROUTINE TO CHECK THE VALIDITY OF THE MICROPROCESSOR CONTROL STORE AND
;START IT IF NO ERRORS ARE DETECTED.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,MPCHKS
;RETURN CPOPJ IF AN ERROR IS DETECTED
;	CPOPJ1 WITH MICROPROCESSOR RESTARTED
;PRESERVES T1

MPCHKS:!PUSHJ	P,MPCHK		;CHECK THE CONTROL STORE
	  POPJ	P,		;ERROR DETECTED
	AOS	0(P)		;GIVE SKIP RETURN
;;	PJRST	RNXMPS		;FALL INTO RNXMPS


;ROUTINE TO START THE MICROPROCESSOR AT .DXSAD.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNXMPS
;RETURN CPOPJ ALWAYS

RNXMPS::PUSHJ	P,MPRES		;RESET THE MICROPROCESSOR
	MOVE	T2,[.DXPCR!PC.IRE!PC.PCE!PC.PCI!INSVL.(.DXSAD,PC.MPC)]
				;POINT TO REGISTER AND SET BITS
	PUSHJ	P,DODTO		;TELL MP ITS START ADDRESS
	MOVE	T2,[.DXMTR!MR.STR] ;SET START BIT IN MAINTENANCE REG
	PJRST	DODTO		;START IT AND RETURN


;ROUTINE TO RESET THE MICROPROCESSOR
;CALL:
;	J/KDB ADDRESS
;	U/UDB ADDRESS
;	PUSHJ	P,MPRES
;RETURN CPOPJ ALWAYS

MPRES:	MOVE	T2,[.DXMTR!MR.RES] ;SET RESET BIT IN MAINT REG
	PJRST	DODTO		;WRITE REGISTER AND RETURN
;ROUTINE TO SEE IF THE DX20 MICROCODE IS STILL RUNNING.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,MPRUN
;RETURN CPOPJ IF NOT RUNNING
;	CPOPJ1 IF RUNNING
;DESTROYS T2,T3

MPRUN:	MOVSI	T2,(.DXSTR)	;POINT AT STATUS REGISTER
	PUSHJ	P,DODTI		;READ IT
	TRNE	T2,ST.RUN	;IS IT RUNNING?
	AOS	0(P)		;YES
	POPJ	P,		;RETURN


;ROUTINE TO CHECK THE VALIDITY OF THE MICROPROCESSOR CONTROL STORE
;AND ATTEMPT TO RELOAD IT IF IT IS BAD.  RETURNS WITH THE
;MICROPROCESSOR STARTED.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,MPINI
;RETURN CPOPJ IF COULDN'T VERYIFY, RELOAD, OR START IT
;	CPOPJ1 WITH THE PROCESSOR RUNNING

MPINI:	PUSHJ	P,MPCHKS	;CHECK INTEGRETY OF MP CONTROL STORE
	  JRST	RNXRLD		;BAD, TRY TO RELOAD IT
	JRST	CPOPJ1##	;GIVE SKIP RETURN
; ENABLE/DISABLE MICROCODE LOADING
RNXEDL::SE1ENT			;ENTER SECTION ONE
	HRRZS	J		;REMOVE JUNK IN LH
	MOVE	T2,T1		;COPY BIT
	XMOVEI	T1,RNXULB##(W)	;POINT TO UCODE LOADER BLOCK IN KDB
	PJRST	BTUEDL##	;ENABLE OR DISABLE


;ROUTINE TO RELOAD THE DX20 MICROCODE IF IT IS FOUND BAD.  CALLED
;VIA THE KONRLD KDB DISPATCH AND FROM MPINI INTERNALLY.  RETURNS
;WITH THE MICROPROCESSOR STARTED.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNXRLD
;RETURN CPOPJ IF COULDN'T VERIFY, RELOAD OR START MICROPROCESSOR
;	CPOPJ1 WITH THE PROCESSOR RUNNING

RNXRLD::SE1ENT			;ENTER SECTION ONE
	HRRZS	KONRLD##(J)	;ASSUME RELOAD WILL SUCCEED
	LDB	T1,[POINT 7,RNXDO2##(J),9] ;GET RH20 DEVICE CODE
	LSH	T1,2		;MAKE IT FULL 9 BIT DEVICE CODE
	LDB	T2,RNYDXN	;GET THE DX20 NUMBER
	HRL	T2,T1		;MAKE IT DEVICE CODE,,DX20 NUMBER
	MOVEM	T2,RNXULB##+.ULDEV(J) ;SAVE
	MOVEI	T1,RNXULB##(J)	;POINT TO MICROCODE LOADER BLOCK
	PUSHJ	P,DXLOAD## 	;TRY TO RELOAD AND VERIFY THE DX20
	  SKIPA			;FAILED
	JRST	CPOPJ1##	;GIVE SKIP RETURN
	HRROS	KONRLD##(J)	;INDICATE RELOAD FAILED
	POPJ	P,		;AND RETURN
	SUBTTL	ROUTINES TO ACCESS MASSBUS REGISTERS


;ROUTINE TO WRITE ONE MASSBUS REGISTER.
;CALL:
;	T2/DATAO ARGUMENT
;	J/KDB ADDRESS
;	PUSHJ	P,DODTO
;RETURN CPOPJ ALWAYS
;DESTROYS T3

DODTO:	LDB	T3,RNYDXN	;GET "DRIVE NUMBER" OF DX20 ON MASSBUS
	TLO	T2,<(DO.LDR!DO.DRE)>(T3) ;DRIVE NUMBER, LOAD REG, DISABLE RAE
	XCT	RNXDO2##(J)	;DO THE DATAO
	XCT	RNXRAE##(J)	;DID IT RESULT IN AN RAE?
	AOSA	RNXRAC##(J)	;YES, INCREMENT COUNT AND RETRY
	POPJ	P,		;NO, RETURN
	PUSH	P,T4		;SAVE T4
	MOVEI	T3,^D10		;RETRY OPERATION 10 TIMES
	MOVEI	T4,CO.MBE!CO.RAE ;MASSBUS ENABLE PLUS CLEAR RAE
DODTO1:	XCT	RNXCO4##(J)	;CLEAR THE ERROR
	XCT	RNXDO2##(J)	;RETRY THE OPERATION
	XCT	RNXRAE##(J)	;STILL HAVE AN ERROR?
	SOJG	T3,DODTO1	;YES, LOOP BUT NOT TOO MANY TIMES
	XCT	RNXCO4##(J)	;INSURE THAT RAE IS CLEARED
	JRST	T4POPJ##	;RESTORE T4 AND RETURN
;ROUTINE TO READ A DRIVE OR CONTROLLER REGISTER.
;CALL:
;	T2/DATAO ARGUMENT TO LOAD PREPARATION REGISTER
;	J/KDB ADDRESS
;	PUSHJ	P,DODTI
;RETURN CPOPJ ALWAYS WITH:
;	T2/16 BITS OF RETURNED DATAI
;DESTROYS T3

DODTI:	LDB	T3,RNYDXN	;GET "DRIVE NUMBER" OF DX20 MASSBUS SLOT
	TLO	T2,<(DO.DRE)>(T3) ;INSERT NUMBER AND DISABLE RAE
	XCT	RNXDO2##(J)	;SETUP THE PREPARATION REGISTER
	PUSH	P,T2		;SAVE THE ARGUMENT
	STALL			;WAIT FOR THINGS TO SETTLE
	XCT	RNXDI2##(J)	;READ THE VALUE
	XCT	RNXRAE##(J)	;DID WE GET AN RAE?
	JRST	DODTI2		;YES, TRY TO RECOVER
DODTI1:	POP	P,(P)		;BRING STACK INTO PHASE
	ANDI	T2,177777	;RETURN ONLY DATA BITS
	POPJ	P,		;RETURN
DODTI2:	MOVSI	T3,1		;ASSUME CONTROL BUS PARITY ERROR
	TLNN	T2,(DI.TRA)	;DID TRA COME UP?
	MOVEI	T3,1		;NO, MUST BE NON-EXISTENT DRIVE
	ADDM	T3,RNXRAC##(J)	;INCREMENT CORRECT COUNT
	PUSH	P,T4		;SAVE T4
	MOVEI	T3,^D10		;RETRY OPERATION 10 TIMES
	MOVEI	T4,CO.MBE!CO.RAE ;MASSBUS ENABLE PLUS CLEAR RAE
DODTI3:	XCT	RNXCO4##(J)	;CLEAR THE ERROR
	MOVE	T2,-1(P)	;GET DATAO ARGUMENT BACK
	XCT	RNXDO2##(J)	;SETUP THE PREPARATION REGISTER AGAIN
	STALL			;WAIT FOR THINGS TO SETTLE
	XCT	RNXDI2##(J)	;READ THE VALUE
	XCT	RNXRAE##(J)	;STILL HAVE THE ERROR?
	SOJG	T3,DODTI3	;YES, LOOP
	XCT	RNXCO4##(J)	;MAKE SURE THE RAE IS CLEARED
	POP	P,T4		;RESTORE T4
	JRST	DODTI1		;RETURN TO THE USER


;ROUTINE TO READ A CONTROLLER REGISTER
;CALL:
;	T2/DATAO ARGUMENT TO LOAD PREPARATION REGISTER
;	J/KDB ADDRESS
;	PUSHJ	P,DODTIC
;RETURN CPOPJ ALWAYS WITH:
;	T2/36 BITS OF RETURNED DATAI

DODTIC:	XCT	RNXDO2##(J)	;SETUP THE PREPARATION REGISTER
	XCT	RNXDI2##(J)	;READ THE DATA
	POPJ	P,		;RETURN


	END