Google
 

Trailing-Edge - PDP-10 Archives - BB-X140B-BB_1986 - 10,7/703mon/td2kon.mac
There are 11 other files named td2kon.mac in the archive. Click here to see a list.
TITLE TD2KON - DX20/TX02 DEVICE DEPENDENT CODE FOR TAPSER V060
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<1978,1986>
;COPYRIGHT (C) 1978,1979,1980,1982,1984,1986
;BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;ALL RIGHTS RESERVED.

;
XP VTD2KN,060	;VERSION NUMBER FOR LINK MAP
	SALL

TD2KON::ENTRY	TD2KON




;TECHNICAL INFORMATION AND TECHNIQUES FOR PROGRAMMING THE DX20 ARE
;AVAILABLE IN THE FOLLOWING DOCUMENTS:
;
;  FUNCTIONAL SPECIFICATION FOR DX20-V100 MICRO CODE,
;	DOCUMENT NUMBER 105-220-001-00,  MAR 78
;  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
;  DX10 DATA CHANNEL MAINTENANCE MANUAL ADDENDUM, CHAPTERS 4-6,
;	DOCUMENT NUMBER EK-DX10-AD-001, JUN 77
;  DX20-V100 MAGNETIC TAPE SUBSYSTEM MICRO-CODE,
;	DOCUMENT NUMBER MAINDEC-10-DXMCA-A-D, SEP 77
	SUBTTL	BIT AND REGISTER DEFINITIONS


	;DX20 MASSBUS REGISTER AND BIT DEFINITIONS

	.DXCTR==0B5		;CONTROL REGISTER
		CR.NOP==0!CR.CGO	;NO-OP
		CR.UNL==2!CR.CGO	;REWIND AND UNLOAD
		CR.REW==6!CR.CGO	;REWIND
		CR.ERA==24!CR.CGO	;ERASE GAP
		CR.WTM==26!CR.CGO	;WRITE TAPE MARK
		CR.SFR==30!CR.CGO	;SPACE FORWARD RECORD
		CR.SBR==32!CR.CGO	;SPACE BACKWARD RECORD
		CR.SFF==34!CR.CGO	;SPACE FORWARD FILE
		CR.SBF==36!CR.CGO	;SPACE BACKWARD FILE
		CR.DSE==42!CR.CGO	;DATA SECURITY ERASE
		CR.SNS==44!CR.CGO	;SENSE
		CR.WTF==60!CR.CGO	;WRITE DATA
		CR.RDF==70!CR.CGO	;READ DATA
		CR.RDR==76!CR.CGO	;READ REVERSE
		CR.CGO==1B35		;GO BIT (INCLUDED IN ABOVE FUNCTIONS)

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

	.DXERR==2B5		;ERROR REGISTER
		ER.ESC==17B23	;ERROR SUB-CLASS CODE
		  .ERRTT==4	;READ TRANSFER TIMEOUT (ERROR CODE=7)
		ER.ECC==17B27	;ERROR CLASS CODE
		ER.UPE==1B28	;MICROPROCESSOR ERROR
		ER.STP==1B29	;MICROPROCESSOR STOPPED
		ER.MPE==1B30	;MICROBUS PARITY ERROR
		ER.DPE==1B31	;DATA BUFFER PARITY ERROR
		ER.CPE==1B32	;CONTROLLER BUS PARITY ERROR
		ER.RMR==1B33	;REGISTER MODIFICATION REFUSED
		ER.ILR==1B34	;ILLEGAL REGISTER ACCESSED
		ER.ILF==1B35	;ILLEGAL FUNCTION ATTEMPTED
		ER.ERR==ER.MPE!ER.DPE!ER.CPE!ER.RMR!ER.ILR!ER.ILF

	.DXMTR==3B5		;MAINTENANCE REGISTER
		MR.STR==1B33	;MICROPROCESSOR START
		MR.RES==1B34	;MICROPROCESSOR RESET

	.DXASR==4B5		;ATTENTION SUMMARY REGISTER
		AS.ATN==377	;ATTENTION BITS

	.DXFCR==5B5		;FRAME COUNT REGISTER (IDENTICAL WITH .GXGP5)
	.DXDTR==6B5		;DRIVE TYPE REGISTER
		DT.COD==777	;MASK FOR DRIVE TYPE
		.DTCOD==060	;DRIVE TYPE FOR DX20

	.DXGP0==20B5		;STATUS INDEX/ENDING STATUS REGISTER
		G0.ATN==1B20	;ATTENTION
		G0.STM==1B21	;STATUS MODIFIER
		G0.CUE==1B22	;CONTROL UNIT END
		G0.BSY==1B23	;BUSY
		G0.CHE==1B24	;CHANNEL END
		G0.DVE==1B25	;DEVICE END
		G0.UCK==1B26	;UNIT CHECK
		G0.UEX==1B27	;UNIT EXCEPTION
		G0.RES==1B28	;SET BIT TO REQUEST EXTENDED STATUS
		G0.IDX==177B35	;INDEX INTO THE STATUS TABLE
		  .S6EST==1	;INDEX INTO THE EST TO GET SENSE BYTE 6

	.DXGP1==21B5		;DRIVE NUMBER/MODE REGISTER
		G1.DTM==17B23	;DATA MODE
		G1.DVM==17B27	;DRIVE MODE
		G1.DRV==377B35	;DRIVE NUMBER

	.DXGP2==22B5		;EXTENDED STATUS TABLE SIZE REGISTER

	.DXGP3==23B5		;TRACK IN ERROR/FLAGS REGISTER
		G3.SAS==1B25	;SUPPRESS AUTO SENSE ON UNIT CHECK
		G3.RSO==1B26	;REQUEST SENSE OPERATION
		G3.TER==1B27	;REQUEST TIE ERROR RECOVERY
		G3.TIE==377B35	;TIE BYTE FOR ERROR RECOVERY
		G3.ALL==G3.SAS!G3.RSO!G3.TER!G3.TIE ;MASK OF ALL BITS

	.DXGP4==24B5		;ASYNCHRONOUS STATUS REGISTER
		G4.DVS==377B27	;DEVICE STATUS BYTE FOR ASYNC STATUS
		G4.DRV==377B35	;DEVICE NUMBER GIVING ASYNC STATUS
		G4.ATN==1B20	;ATTENTION
		G4.STM==1B21	;STATUS MODIFIER

	.DXGP5==25B5		;FRAME COUNT REGISTER (IDENTICAL WITH .DXFCR)
	.DXGP6==26B5		;EXTENDED STATUS REGISTER 0

	.DXGP7==27B5		;EXTENDED STATUS REGISTER 1

	.DXDR0==30B5		;DIAGNOSTIC REGISTER 0

	.DXDR1==31B5		;DIAGNOSTIC REGISTER 1
		D1.IRE==1B20	;INSTRUCTION REGISTER ENABLE
		D1.MSE==1B21	;MICROSTORE ENABLE
		D1.PCE==1B22	;PC ENABLE
		D1.PCI==1B23	;PC AUTO INCREMENT
		D1.MPC==7777B35	;MICRO PROCESSOR PC

	.DXDR7==37B5		;DIAGNOSTIC REGISTER 7
		D7.IRP==1B22	;INSTRUCTION REGISTER PARITY ERROR
	;FOLLOWING ARE SENSE BYTE BIT DEFINITIONS FOR BYTES 0-3.
	;THESE DEFINITIONS ASSUME THAT THE BYTES ARE STORED IN
	;ONE WORD IN THE FORMAT 0(2-9), 1(10-17), 2(20-27), 3(28-35)

	S0.CRJ==1B2		;COMMAND REJECT
	S0.IRQ==1B3		;INTERVENTION REQUIRED
	S0.BOC==1B4		;BUS OUT CHECK
	S0.EQC==1B5		;EQUIPMENT CHECK
	S0.DTC==1B6		;DATA CHECK
	S0.OVR==1B7		;OVERRUN
	S0.WCZ==1B8		;WORD COUNT ZERO
	S0.DCC==1B9		;DATA CONVERTER CHECK
	S0.ALL==377B9		;ALL OF SENSE BYTE ZERO
	S1.NSE==1B10		;NOISE
	S1.TUA==1B11		;TU STATUS A
	S1.TUB==1B12		;TU STATUS B
	S1.7TK==1B13		;7 TRACK FEATURE
	S1.BOT==1B14		;BOT - LOAD POINT
	S1.WTS==1B15		;WRITE STATUS
	S1.FPR==1B16		;FILE PROTECTED
	S1.NTC==1B17		;NOT CAPABLE
	S2.TIE==377B27		;TRACK IN ERROR BYTE
	S3.VRC==1B28		;READ/WRITE VRC
	S3.MTE==1B29		;LRC/MTE
	S3.SKW==1B30		;SKEW ERROR
	S3.CRC==1B31		;EDC/CRC ERROR
	S3.ENV==1B32		;ENV/ECC ERROR
	S3.D16==1B33		;1600 BPI
	S3.BKW==1B34		;BACKWARD STATUS
	S3.CPC==1B35		;C/P COMPARE
	SB.UCE==S0.ALL!S1.TUB!S1.NTC ;BAD ERRORS ON UNIT CHECK


	;OTHER SENSE BYTE DEFINTITIONS

	S6.7TK==1B20		;7-TRACK DRIVE
	S6.D62==1B22		;6250 BPI IF S3.D16 IS OFF


	;RH20 CONI/CONO/LOGOUT AREA BIT DEFINITIONS

	CI.ERR==CI.DBP!CI.LWC!CI.DRE!CI.RAE ;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.OVR
				;ALL CHANNEL LOGOUT ERRORS
	;OFFSETS IN TUBFEP FOR COMMUNICATION WITH DAEMON.  IF THESE
	;DEFINITIONS CHANGE CHECK DAEMON FOR A CORRESPONDING CHANGE.

	.TFZRO==0	;ZERO WORD; ALL UNDEFINED ENTRIES MAP TO HERE
	.TFCNI==1	;CONI INITIAL
	.TFCIF==2	;CONI FINAL
	.TFRED==3	;NUMBER OF FRAMES READ
	.TFWRT==4	;NUMBER OF FRAMES WRITTEN
	.TFD1I==5	;DATAI PTCR INITIAL
	.TFD1F==6	;DATAI PTCR FINAL
	.TFD2I==7	;DATAI PBAR INITIAL
	.TFD2F==10	;DATAI PBAR FINAL
	.TFCS0==11	;CHANNEL LOGOUT 0
	.TFCS1==12	;CHANNEL LOGOUT 1
	.TFCS2==13	;CHANNEL LOGOUT 2
	.TFCC1==14	;FIRST CCW
	.TFCC2==15	;SECOND CCW
	.TFMPE==16	;COUNT OF MPE
	.TFNXM==17	;COUNT OF NXM
	.TFOVR==20	;COUNT OF OVERRUNS
	.TFICR==21	;CONTENTS OF INITIAL CONTROL REG
	.TFVER==22	;BYTE (9)DX20 ADDRESS(9)0(18)MICROCODE VER
	.TFMBR==23	;# OF MASSBUS REGS,,OFFSET TO FIRST
	.TFDVL==24	;# OF DEVICE REGS,,OFFSET TO FIRST
	.TFMBX==25	;START OF NUMBER MASSBUS REGISTERS
	.TFD2R==.TFMBX+.TD2MR ;START OF DX20 REGISTERS
	.TFTIE==.TFD2R	;TIE BYTE STORED HERE ON ERROR
	.TFEND==.TFD2R+.TD2ES-1 ;LAST ENTRY IN TUBFEP


	IFN <.TD2MC-<.TFDVL+1>>, <
		PRINTX ?.TD2MC INCORRECT; CHECK VALUE IN S
		PASS2
		END
	>
	;MISCELLANEOUS DEFINITIONS


	TD2MVR==:1000,,34	;MINIMUM MICROCODE VERSION ALLOWED

	.DXSAD==6		;DX20 MONITOR RESTART ADDRESS
	.CRM10==100		;CORRECT CONTENTS OF CRAM LOCATION 10
	.CRM11==042562		;CORRECT CONTENTS OF CRAM LOCATION 11
	DX2VER==10		;MINIMUM ALLOWABLE MICROCODE VERSION
	D2VLSH==^D10		;# BITS TO LSH TO RIGHT-JUSTIFY VERSION


	;OFFSETS IN TKBCCL FOR OUR USE

	TKBWCT==TKBCCL##+0	;UNUSED,,-BYTE COUNT FOR LAST NON-ERROR TRANSFER
				;SIGN BIT MUST BE ZERO FOR THIS TO BE VALID
	TKBSCH==TKBCCL##+1	;-1 IF SCHEDULE CYCLE REQUESTED
	TKBFLG==TKBCCL##+2	;FLAGS FROM IOFTBL
	TKBASY==TKBCCL##+3	;DX20 NUMBER,,ASYNCHRONOUS STATUS
				;DURING FORCED SENSE OPERATION
	TKBATN==TKBCCL##+4	;IORB ADDRESS,,ATTENTION BITS DURING
				;ASYNCHRONOUS STATUS PROCESSING


	;BYTE POINTERS INTO THE UDB

DRVNUM:	POINT	3,TUBAKA##(U),17 ;POINTER TO DRIVE NUMBER
	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 WAIT AWHILE. USED IN RDREG TO GIVE THE MASSBUS TIME TO
;ACCEPT THE DATAO TO SETUP THE PREPARATION REGISTER BEFORE
;DOING THE DATAI TO READ THE REGISTER

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


;MACRO TO DEFINE THE MASSBUS REGISTERS TO SAVE IN THE UDB 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>,<.TFM00==.TFMBX+..CNT>
		   IFE <LST-30>,<.TFM30==.TFMBX+..CNT>
		   ..CNT==..CNT+1 ;BUMP NUMBER BY 1
		   MBRTBL==MBRTBL!<1_<^D35-LST>> ;SET BIT IN TABLE
		> ;END IRP LST
		IFN <.TD2MR-..CNT>, <
			PRINTX ?.TD2MR IS INCORRECT; CHECK VALUE IN S
			PASS2
			END
		> ;END IFN
	>

	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	DISPATCH TABLE FOR TAPSER CALLS


TD2DSP::IFIW	TD2INI		;00 - INITIALIZE
	IFIW	TD2RES		;01 - RESET ACTIVE I/O
	IFIW	TD2SIO		;02 - START I/O
	IFIW	TD2INT		;03 - INTERRUPT SERVICE
	EXP	0		;04 - SET DEVICE COMMAND
	IFIW	CPOPJ##		;05 - SET KONTROLLER IDLE
	IFIW	TD2ONL		;06 - TEST IF CTL ON-LINE
	IFIW	TD2SCH		;07 - FORCE A SCHEDULE CYCLE
	IFIW	TD2INX		;10 - RE-INITIALIZATION
	IFIW	TD2LOD		;11 - LOAD MICROCODE
	IFIW	TD2EDL		;12 - ENABLE/DISABLE MICROCODE LOADING
IFN FTAUTC,<IFIW TD2CFG>	;13 - AUTOCONFIGURE
	SUBTTL	AUTO CONFIGURATION
IFN FTAUTC,<
;ENTER WITH P3=CURRENT DRIVE NUMBER
;EXIT P3= NEXT DRIVE NUMBER, LH= TUBSTS IF NOT AN 800/1600 DRIVE
TD2CFG:	JUMPGE	P3,TD2CF2	;IF FIRST TIME THROUGH
	PUSHJ	P,MPRES
	PUSHJ	P,MPCHK		;MAKE SURE MICROCODE IS OK
	  SKIPA			;NO GOOD
	JRST	TD2CF1		;ONWARD
	PUSHJ	P,TD2LOD	;LOAD THE MICROCODE
	  POPJ	P,		;GIVE UP
TD2CF1:	PUSHJ	P,MPSTRT	;START THE MICROCODE
	PUSHJ	P,CHKDTR	;MAKE SURE IT'S THE RIGHT FLAVOR
	  POPJ	P,		;ITS BAD. DON;T DO ANY MORE
TD2CF2:	AOS	T2,P3		;STEP TO NEXT DRIVE
	TRZE	P3,10		;DONE?
	SOJA	P3,CPOPJ##	;YES, RETURN P3=-1
	HRLI	T2,(.DXGP1)	;SAY WHAT DRIVE WE WANT TO TALK TO
	PUSHJ	P,WTREG		;TELL THE HARDWARE
	MOVE	T2,[.DXCTR!CR.SNS] ;DO A SENSE ON THE DRIVE
	PUSHJ	P,WTREGX	; SO WE CAN READ SENSE BYTES
	MOVEI	T1,2000		;LOOP COUNTER
TD2CF3:	MOVSI	T2,(.DXASR)	;POINT TO ATTENTION SUMMARY REGISTER
	PUSHJ	P,RDREGX	;READ IT
	TRNN	T2,377		;HAVE AN ATTENTION?
	SOJG	T1,TD2CF3	;NO, WAIT SOME MORE
	JUMPLE	T1,TD2CF6	;DRIVE NOT THERE IF WE TIMED OUT
	MOVE	T2,[.DXASR!377]	;CLEAR THE ATTENTION WE JUST GOT
	PUSHJ	P,WTREGX
	MOVE	T4,[TRNN T2,G0.RES]
TD2CF4:	MOVEI	T1,100		;HOW LONG TO WAIT
TD2CF5:	MOVSI	T2,(.DXGP0)	;POINT TO ENDING STATUS REGISTER
	PUSHJ	P,RDREGX
	XCT	T4		;WAIT FOR CONDITION
	SOJG	T1,TD2CF5	;NO, WAIT SOME MORE
	TLZE	T4,(<TRNN>^!<TRNE>) ;CONVERT TRNN TO TRNE IF NOT ALREADY
	JRST	TD2CF4		;WASN'T, WAIT TO CLEAR
	JUMPLE	T1,TD2CF6	;NO DRIVE IF WE TIMED OUT
	PUSHJ	P,REDEST	;READ SENSE BYTES 0-3
	TLNN	T4,(S1.TUA!S1.TUB) ;DRIVE EXIST?
	JRST	TD2CF6		;NO
	MOVEI	T2,.S6EST	;YES. READ SENSE BYTE 6
	PUSHJ	P,SETEST	;TELL THE DX WHAT WE WANT TO READ
	  POPJ	P,		;CANT READ IT. ASSUME TU70
	PUSHJ	P,REDEST	;READ THE SENSE BYTE
	TRNE	T4,S6.7TK	;7 TRACK DRIVE?
	HRLI	T3,TUCDR7##+K.DX2 ;YES
	TRNE	T4,S6.D62	;6250 DRIVE?
	HRLI	T3,TUCDR5##+K.DX2 ;YES
	MOVSI	T2,(.DXERR)	;POINT TO ERROR REGISTER
	PUSHJ	P,WTREGX	;CLEAR IT AND REURN WITH NEXT DRIVE NUMBER
	HLRZS	T3		;POSITION CONFIG INFO
	POPJ	P,

;HERE IF NO SUCH DRIVE
TD2CF6:	MOVSI	T2,(.DXERR)	;POINT AT ERROR REGISTER
	PUSHJ	P,WTREGX	;CLEAR IT
	JRST	TD2CF2		;AND TRY NEXT DRIVE
>	;END IFN FTAUTC
	SUBTTL	INITIALIZATION


;HERE FROM SYSINI AT SYSTEM STARTUP AND TAPUUO OR TAPSER WHEN A
;KONTROLLER COMES BACK ONLINE TO INITIALIZE ALL DX20'S ON THIS
;RH20. TD2INI (TPKINI) IS THE SYSINI ENTRY POINT, TD2INX (TPKINX)
;IS THE TAPUUO OR TAPSER ENTRY POINT.  CALL WITH:
;	W/KDB ADDRESS,  F/MT?DDB IF ENTRY AT TD2INI
;RETURN+1 ALWAYS

DX.FND==1B1			;SET IN P3 IF WE FOUND A DX20
TD2INI:	TDZA	T3,T3		;SET FLAG FOR ENTRY AT TD2INI
TD2INX:	MOVSI	T3,(1B0)	;DITTO FOR ENTRY AT TD2INX
	PUSHJ	P,SAVE4##	;SAVE P1-P4
	PUSH	P,F
	MOVEI	T2,CO.MBE	;GET BIT TO ENABLE THE MASSBUS
	XCT	TD2COS##(W)	;DO SO
	MOVE	P1,TKBIUN##(W)	;GET AOBJN POINTER TO UDB LIST
	SKIPN	P3,T3		;MOVE FLAG TO P3, SKIP IF TD2INX ENTRY
	HRRI	P3,-1		;RH OF P3 WILL BE THE DX20 NUMBER
TD2IN2:	SKIPN	U,(P1)		;GET NEXT UDB POINTER
	JRST	TD2IN6		;NONE, TRY NEXT
	PUSH	P,TUBAKA##(U)	;SAVE CURRENT VALUE OF TUBAKA
	HRRZ	T2,TUBADR##(U)	;GET REAL UNIT NUMBER
	HRLM	T2,TUBAKA##(U)	;WTREG WANTS UNIT NUMBER HERE
	JUMPL	P3,TD2IN3	;DON'T DIDDLE DDB'S IF ENTRY AT TD2INX
	DPB	T2,PUNIT##	;STORE UNIT NUMBER IN DDB
	HLRZ	F,DEVSER(F)
	MOVEI	T2,TUCIRD##	;"INTERRUPT ON REWIND DONE" BIT
	IORM	T2,TUBCNF##(U)	;TELL TAPUUO WE GET AN INTERRUPT ON REWIND DONE
TD2IN3:	HLRZ	T2,TKBUNI##(W)	;GET DX20 NUMBER FOR THIS DRIVE
	CAIN	T2,(P3)		;ALREADY SEEN THIS ONE?
	JRST	TD2IN4		;YES, DON'T DIDDLE IT AGAIN
	HRRI	P3,(T2)		;SAVE NUMBER FOR NEXT TIME
	PUSHJ	P,CHKDTR	;CHECK DRIVE TYPE REGISTER
	  JRST	TD2IN4		;BAD, DON'T TOUCH IT FURTHER
	PUSHJ	P,MPRES		;RESET THE MICROPROCESSOR
	PUSHJ	P,MPVER		;READ DX20 MICROCODE VERSION NUMBER
	HRRZS	P4,T2		;SAVE IN RH OF P4
	LSH	T3,^D9		;SHIFT DX20 ADDR INTO LEFT 9 BITS OF RH
	HRLI	P4,(T3)		;SAVE DX20 ADDRESS_9 IN LH
	LSH	T2,-D2VLSH	;GET IT
	CAIL	T2,DX2VER	;UCODE CURRENT?
	  JRST	TD2IN5		;YES, PROCEED
	MOVE	T2,[DX2VER,,[ASCIZ/Please reload the DX20 with at least microcode version/]]
	PUSHJ	P,TAPREV##
	JRST	TD2IN4		;DON'T START BAD UCODE
TD2IN5:	PUSHJ	P,MPCHK		;CHECK INTEGRETY OF MICROSTORE
	  JRST	TD2IN4		;BAD, DON'T START IT
	PUSHJ	P,MPSTRT	;START THE DX20 AT THE RESTART ADDRESS
	TLO	P3,(DX.FND)	;FLAG A DX20 FOUND
				;FALL INTO TD2IN4

TD2IN4:	POP	P,TUBAKA##(U)	;RESTORE INITIAL VALUE OF TUBAKA
	MOVEM	P4,TD2FST##+.TFVER(U) ;SAVE DX20 ADR,,MICROCODE VER IN FEP BLOCK
	MOVSI	T2,TUSREW##	;"DRIVE REWINDING" BIT
	ANDCAM	T2,TUBSTS##(U)	;CLEAR REWINDING IN UDB
TD2IN6:	AOBJN	P1,TD2IN2	;LOOP FOR ALL UDB'S
	POP	P,F
	TLNN	P3,(DX.FND)	;FIND A LEGAL DX20?
	POPJ	P,		;NO, DON'T GIVE IT A PIA
	PUSHJ	P,SETIVO	;SETUP INTERRUPT VECTOR ADDRESS
	PJRST	CLRALL		;CLEAR RH20 AND RETURN
	SUBTTL	RESET I/O ON HUNG DEVICE


;HERE TO RESET I/O ON A HUNG DEVICE.  STOP THE RH20 AND RESET
;AND RESTART ALL DX20'S.
;CALL WITH:
;	W/KDB ADDRESS,	U/UDB ADDRESS
;RETURN+1 ALWAYS

TD2RES:	MOVSI	T2,TKSOFL##	;GET OFFLINE BIT
	TDNE	T2,TKBSTS##(W)	;IS KON OFFLINE?
	POPJ	P,		;YES, JUST RETURN
	PUSHJ	P,SAVE2##	;SAVE P1-P2
	PUSH	P,U		;SAVE U FOR CALLER
	XCT	TKBCIS##(W)	;GET CONI IN T2
	PUSH	P,T2		;SAVE FOR LATER
	PUSHJ	P,SETIVO	;SETUP INTERRUPT VECTOR ADDRESS
	MOVEI	T2,CO.STP	;GET "STOP TRANSFER" BIT AND DEASIGN PI
	XCT	TD2COS##(W)	;STOP ANY TRANSFER
	MOVE	P1,TKBFLG(W)	;SETUP FLAGS FOR OPERATION
	PUSHJ	P,RDAREG	;READ INITIAL AND FINAL REGISTERS
	POP	P,TD2FST##+.TFCNI(U) ;STORE CONI IN BLOCK
	MOVE	P1,TKBIUN##(W)	;GET AOBJN POINTER TO UDB LIST
	SETOM	P2		;P2 WILL BE DX20 NUMBER
TD2RE1:	SKIPN	U,(P1)		;GET NEXT UDB ADDRESS
	JRST	TD2RE2		;NONE, SKIP IT
	MOVSI	T2,TUSREW##	;GET UNIT IS REWINDING BIT
	ANDCAM	T2,TUBSTS##(U)	;CLEAR IN UDB
	HLRZ	T2,TKBUNI##(W)	;GET DX20 NUMBER FOR THIS DRIVE
	CAIN	T2,(P2)		;ALREADY SEEN THIS ONE?
	JRST	TD2RE2		;YES, DON'T TOUCH IT AGAIN
	MOVE	P2,T2		;SAVE NEW DX20 NUMBER
	PUSHJ	P,MPSTRT	;RESET AND START THE DX20
TD2RE2:	AOBJN	P1,TD2RE1	;LOOP FOR ALL UNITS
	POP	P,U		;RESTORE U
	PUSHJ	P,CLRFLG	;CLEAR KDB FLAGS
	PJRST	REASPI		;REASSIGN PI AND RETURN
	SUBTTL	START I/O


;HERE FROM TAPSER TO START AN OPERATION GOING ON A DRIVE.  IF THE
;OPERATION IS ILLEGAL FOR SOME REASON, WE SET THE APPROPRIATE BITS
;IN THE IORB AND DO A NO-OP TO GET TO INTERRUPT LEVEL WHERE IT WILL
;BE SEEN.  CALL WITH:
;	U/UDB ADDRESS, W/KDB ADDRESS
;RETURN+1 ALWAYS WITH OPERATION STARTED

TD2SIO:	PUSHJ	P,CHKIRB##	;GET IORB, RETURN ADDR IN T1
	  JRST	TAPDIS##	;NONE, FORGET IT
	PUSHJ	P,SETIVO	;SET INTERRUPT VECTOR
	PUSHJ	P,SAVE2##	;SAVE P1-P2
	SKIPGE	T2,TRBRCT(T1)	;IN ERROR RECOVERY? (IOWD SETUP BY MAKLST)
	MOVEM	T2,TKBWCT(W)	;NO, SAVE -WORD COUNT FOR LATER
	LDB	P2,PRBFCN##	;GET FUNCTION FROM IORB
	MOVEI	T2,CO.MBE	;ENABLE MASSBUS AND DIASSIGN PI
	XCT	TD2COS##(W)	;DO SO
	PUSHJ	P,MPRUN		;IS MICROPROCESSOR STILL RUNNING
	  JRST	[MOVSI	T2,RB.SED!RB.SER!RB.SOL ;GET ERROR BITS
		 JRST	GENINT]	;GO CAUSE AN INTERRUPT
	SKIPL	P1,IOFTBL(P2)	;IS FUNCTION LEGAL?
	PUSHJ	P,SETMOD	;YES, SETUP DRV #, DENS, MODE, RETURN MODE IN T4
	  JRST	[MOVSI	T2,RB.SED!RB.SER!RB.SIL ;GET ERROR BITS
		 JRST	GENINT]	;GO CAUSE AN INTERRUPT

	TLNN	P1,(TB.DAT)	;DATA OPERATION?
	JRST	TD2SI2		;NO
	SKIPL	T2,TKBWCT(W)	;IN ERROR RECOVERY ? (FROM ABOVE)
	JRST	TD2SI4		;YES, USE PREVIOUS FRAME COUNT
	MOVSS	T2		;MAKE IT FLAG,,-WORD(BYTE) COUNT
	TLOE	T2,-1		;SKIP MULTIPLYIF ALREADY -BYTE COUNT
	IMUL	T2,TMODTB##(T4)	;CONVERT -WORD COUNT TO -BYTE COUNT
	HRRZM	T2,TKBWCT(W)	;SAVE FOR RECOVERY ATTEMPT
	JRST	TD2SI4		;  AND JOIN COMMON CODE
TD2SI2:	MOVEI	T2,0		;ASSUME NO FRAME COUNT NEEDED
	TRNE	P1,TB.ZFC	;ARE WE CORRECT?
	JRST	TD2SI4		;YES
	TRNE	P1,TB.OFC	;-1 FRAME COUNT NEEDED?
	SOJA	T2,TD2SI4	;YES, MAKE IT -1 AND JOIN COMMON CODE
	HRRZ	T2,TRBXCW(T1)	;GET NUMBER OF OPS FROM IORB
	MOVNS	T2		;MAKE IT NEGATIVE
TD2SI4:	ANDI	T2,177777	;MAKE IT 16 BITS ONLY
	HRLI	T2,(.DXFCR)	;POINT TO FRAME COUNT REGISTER
	PUSHJ	P,WTREG		;TELL THE DX20 HOW MANY FRAMES


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


	HRRZ	T3,TRBXCW(T1)	;GET EXEC VIRTUAL ADDR OF CMD LIST
	HRLI	T3,RH2JMP##	;MAKE IT AN RH20 JUMP WORD
	HRRZ	T2,TKBICP##(W)	;GET ADDRESS OF RH20 LOGOUT AREA
	MOVEM	T3,.CSICW(T2)	;STORE JUMP WORD IN LOGOUT AREA
	HRRZI	T2,(P1)		;GET HDW FCN AND SET REGISTER (.DXCTR==0)
	TRZ	T2,-1-TB.FCN	;CLEAR ALL BUT FUNCTION BITS
	TLNE	P1,(TB.DAT)	;DATA OPERATION?
	TDO	T2,[.DOSTC!DO.RCP!DO.SCS!177700] ;YES, TALK TO RH20
	SKIPGE	TUBERR##(U)	;IF NEXT TO LAST ERROR RETRY
	TRO	T2,DO.DTE	; LITE DXES
	SKIPN	TUBERR##(U)	;IF NOT IN ERROR RECOVERY,
	MOVEM	T2,TD2FST##+.TFICR(U) ;SAVE LAST COMMAND
	IORM	P1,TKBFLG(W)	;REMEMBER WHAT WE WERE DOING
	HLRZ	T3,TKBUNI##(W)	;GET THE DX20 NUMBER
	HRLZM	T3,TKBASY(W)	;SAVE FOR QUICK INTERRUPT CHECK
	PUSHJ	P,WTREGX	;START THE TRANSFER
	PJRST	REASPI		;LITE PIA AND RETURN
;ROUTINE TO TELL THE DX20 THE DRIVE NUMBER, DENSITY, PARITY, DATA
;MODE, AND RECOVERY PROCEDURES FOR THE CURRENT OPERATION.  CALL WITH:
;	T1/IORB ADDRESS, P1/IOFTBL ENTRY, P2/FUNCTION,
;	W/KDB ADDRESS, U/UDB ADDRESS
;RETURN+1 IF DENSITY OR MODE IS ILLEGAL
;RETURN+2 IF ALL IS OK WITH:
;	T1/UNCHANGED,  T4/MODE FROM IORB

SETMOD:	LDB	T2,DRVNUM	;GET THE DRIVE NUMBER
	LDB	T4,PRBDEN##	;GET DENSITY FROM IORB
	MOVEI	T3,TUC7TK##	;GET "DRIVE IS A 7 TRACK" BIT
	TDNN	T3,TUBCNF##(U)	;IS IT?
	JRST	SETMO1		;NO, DO 9 TRACK SET
;
;HERE TO SETUP THE DENSITY AND PARITY FOR A 7 TRACK DRIVE.  WE NEED
;ONLY DO THIS IF TB.MS7 IS SET IN P1.
;
	TRNN	P1,TB.MS7	;NEED A MODE SET FOR THIS FUNCTION?
	JRST	SETMO2		;NO, SKIP IT
	CAIL	T4,RB.D2	;DENSITY LESS THAN 200?
	CAILE	T4,RB.D8	;GREATER THAN 800?
	POPJ	P,		;YES, ERROR
	LSH	T4,1		;DEN7TB ENTRIES ARE 2 WORDS (ODD AND EVEN PARITY)
	MOVSI	T3,RB.PAR	;GET EVEN PARITY BIT
	TDNE	T3,TRBLNK(T1)	;THIS FUNCTION EVEN PARITY?
	IORI	T4,1		;YES, BUMP THE POINTER TO THE NEXT WORD
	IOR	T2,DEN7TB(T4)	;OR IN THE APPROPRIATE HARDWARE DENSITY
	JRST	SETMO2		;AND JOIN COMMON CODE
;
;HERE TO SETUP THE DENSITY FOR A 9 TRACK DRIVE.  WE NEED ONLY DO THIS
;IF TB.MS9 IS SET IN P1 AND THE DRIVE IS AT BOT.
;
SETMO1:	MOVSI	T3,TUSBOT##	;GET BOT BIT
	TRNE	P1,TB.MS9	;NEED TO DO A MODE SET?
	TDNN	T3,TUBSTS##(U)	;  AND DRIVE IS AT BOT?
	JRST	SETMO2		;NO, SKIP IT
	CAIL	T4,RB.D8	;DENSITY LESS THAN 800?
	CAILE	T4,RB.D62	;GREATER THAN 6250?
	POPJ	P,		;YES, ERROR
	IOR	T2,DEN9TB(T4)	;OR IN THE APPROPRIATE HARDWARE DENSTIY
;
;HERE TO SETUP THE MODE FOR THIS FUNCTION.  CALLER WANTS MODE IN T4.
;
SETMO2:	LDB	T4,PRBMOD##	;GET MODE FROM IORB
	SKIPGE	T3,MODTBL(T4)	;GET HARDWARE MODE, SKIP IF LEGAL
	POPJ	P,		;IT'S NOT, ILLEGAL
	IORI	T2,(T3)		;SET THE MODE INTO THE WORD

	HRLI	T2,(.DXGP1)	;POINT AT REGISTER TO SET
	PUSHJ	P,WTREG		;TELL THE DX20


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


;HERE TO SETUP ANY ERROR RECOVERY PROCEDURES FOR THIS OPERATION.
;WE ALSO FORCE A SENSE ON THIS OPERATION IF IT IS A READ FROM BOT
;SO THAT WE CAN TELL THE USER THE REAL DENSITY OF THE TAPE.

	MOVSI	T2,(.DXGP3)	;POINT AT TIE,FLAGS REGISTER
	MOVE	T3,TUBCNF##(U)	;GET TUBSTS, TUBCNF (TUBCNF=TUBSTS)
	TLNE	P1,(TB.RED)	;IS THIS A READ COMMAND?
	TLNN	T3,TUSBOT##	;FROM BOT?
	CAIA			;NOT A READ OR NOT AT BOT
	JRST	[TLO	P1,(TB.FSN) ;TELL INTERRUPT LEVEL THAT WE FORCED A SENSE
		 JRST	SETMO4]	;JOIN COMMON CODE
	TRNN	P1,TB.REW	;IS THIS A REWIND OR UNLOAD?
	TRNN	T3,TUCSNS##	;NO, WAS A SENSE REQUESTED BY THE USER?
	JRST	SETMO5		;NO SENSE REQUIRED
SETMO4:	TRO	T2,G3.RSO	;SET REQUEST SENSE BIT
SETMO5:	LDB	T3,[POINTR TD2FST##+.TFTIE(U),S2.TIE] ;GET TIE BYTE FROM LAST ERROR
	CAIN	P2,RB.FCR	;THIS A CORRECTION READ?
	TRO	T2,G3.TER(T3)	;YES, SET TIE BYTE AND REQUEST TIE RECOVERY
	TRNE	T2,G3.ALL	;NEED TO DO THIS?
	PUSHJ	P,WTREG		;YES, DO SO
	JRST	CPOPJ1##	;RETURN SUCCESS
;HERE TO SETUP THE APPROPRIATE FLAGS AND GENERATE AN INTERRUPT SO
;THAT WE CAN GET TO INTERRUPT LEVEL TO REPORT AN ERROR NOTICED WHEN
;WE WERE TRYING TO START AN OPERATION.
;CALL WITH:
;	T1/IORB ADDRESS,  T2/ERROR BITS TO SET IN IORB
;RETURN+1 ALWAYS

GENINT:	IORM	T2,TRBSTS(T1)	;SET ERROR BITS IN IORB
	MOVE	T2,IOFTBL+RB.FYB ;GET DUMMY FUNCTION
	IORM	T2,TKBFLG(W)	;STORE IN KDB FOR INTERRUPT LEVEL
	HLRZ	T2,TKBUNI##(W)	;GET DX20 NUMBER
	HRLZM	T2,TKBASY(W)	;STORE FOR INTERRUPT CHECK
	MOVEI	T2,CO.STP	;GET STOP TRANSFER BIT
	XCT	TD2COS##(W)	;SET DONE, CAUSING AND INTERRUPT
	PJRST	REASPI		;LITE PIA AND RETURN

	SUBTTL	INTERRUPT SERVICE


;HERE ON AN INTERRUPT FOR THIS KONTROLLER WITH:
;	W/KDB ADDRESS
;RETURNS+1 ALWAYS TO TAPINT TO DISMISS THE INTERRUPT AND MAYBE
;START MORE I/O WITH
;	T1/IORB ADDRESS IF FUNCTION COMPLETED,
;	   0 IF ANOTHER INTERRUPT COMING
;	   -1 IF SCHEDULE CYCLE REQUESTED


TD2INT:	PUSHJ	P,SAVE3##	;SAVE P1-P3
	MOVE	U,TKBCUN##(W)	;POINT AT UNIT WE'RE TALKING TO
	MOVE	U,(U)		;GET UDB ADDRESS
	SKIPE	P1,TKBFLG(W)	;OPERATION OR SENSE IN PROGRESS?
	TLNN	P1,-1		;CHECK ONLY LEFT HALF
	JRST	CHKATN		;  GO CHECK ATTENTIONS
	PUSHJ	P,CLRATN	;CLEAR ATTNS TO AVOID RACE IN GO BIT CHECK
	HLRZ	T3,TKBASY(W)	;GET DX20 NUMBER
	PUSHJ	P,MPRUNX	;MICROPROCESSOR RUNNING?
	  JRST	TD2IT1		;NO, SKIP CHECK FOR GO BIT
	MOVSI	T2,(.DXCTR)	;POINT AT CONTROL REGISTER
	PUSHJ	P,RDREGX	;READ IT
	TRNN	T2,CR.CGO	;GO BIT STILL UP FOR THIS DX20?
TD2IT1:	PUSHJ	P,CHKIRB##	;CHECK IORB, RETURN ADDRESS IN T1
	  JRST	CHKATN		;NONE, CHECK ATTENTIONS
	MOVSI	T2,(.DXGP0)	;POINT AT ENDING STATUS REGISTER
	PUSHJ	P,RDREG		;READ IT
	HRRI	P1,(T2)		;CARRY IN RH OF P1

	TLNE	P1,(TB.ILF)	;HERE BECAUSE OF ILLEGAL FUNCTION?
	HLL	T1,TRBSTS(T1)	;YES, SETUP BITS STORED BY GENINT
	MOVSI	T2,TUSBOF##	;GET BOT AND OFFLINE BITS
	ANDCAM	T2,TUBSTS##(U)	;AND CLEAR THEM IN THE UDB
	SETZM	TD2FST##+.TFRED(U) ;ZERO FRAMES READ AND
	SETZM	TD2FST##+.TFWRT(U) ;  FRAMES WRITTEN
	PUSHJ	P,CHKERR	;CHECK ON ERRORS IN LAST OP
	  JRST	DONE		;FATAL ERRORS FOUND, GIVE UP
	LDB	T2,[POINTR P1,TB.SFC] ;GET SOFTWARE FUNCTION FOR THIS OP
	CAILE	T2,MAXINT	;GREATER THAN MAX FUNCTION?
	JRST	TAPIFI##	;YES, ERROR
	JRST	@INTTBL(T2)	;DISPATCH TO SPECIFIC INTERRUPT HANDLER
	SUBTTL	FUNCTION SPECIFIC INTERRUPT HANDLERS


;DISPATCH HERE THROUGH INTTBL TO DO FUNCTION SPECIFIC INTERRUPT
;HANDLING.  ENTER WITH:
;	T1/ERROR BITS,,IORB ADDRESS, U/UDB ADDRESS, W/KDB ADDRESS
;	P1/LH IOFTBL ENTRY,,DEVICE STATUS BYTE
;	P2/SENSE BYTES 0-3
;EXIT THROUGH DONE WITH:
;	T1/UPDATED ERROR BITS,,IORB ADDRESS


;HERE ON A READ BACKWARD INTERRUPT

RDBINT:	SOS	TUBREC##(U)	;DECREMENT RECORD COUNT
	TRNE	P1,G0.UEX	;UNIT EXCEPTION?
	PUSHJ	P,LSTFIL	;YES, JUST SAW TAPE MARK
	TRNN	P1,G0.UCK	;UNIT CHECK?
	JRST	RDXINT		;NO, JOIN COMMON READ CODE
	TLNE	P2,(SB.UCE)	;UNIT CHECK DUE TO ERRORS?
	PUSHJ	P,SNSANL	;YES, ANALYZE SENSE BYTES
	PUSHJ	P,CHKBOT	;CHECK FOR BOT
	JRST	RDXINT		;JOIN COMMON READ CODE


;HERE ON A READ FORWARD/CORRECTION READ/READ LOW THRESHOLD INTERRUPT

RDFINT:	AOS	TUBREC##(U)	;INCREMENT RECORD COUNT
	TRNE	P1,G0.UEX	;UNIT EXCEPTION?
	PUSHJ	P,NXTFIL	;YES, JUST SAW TAPE MARK
	TRNE	P1,G0.UCK	;UNIT CHECK?
	PUSHJ	P,SNSANL	;YES, ANALYZE SENSE BYTES
;;	JRST	RDXINT		;FALL INTO RDXINT


;HERE TO DO PROCESSING COMMON TO ALL READ INTERRUPTS

RDXINT:	MOVSI	T2,(.DXFCR)	;POINT AT FRAME COUNT REGISTER
	PUSHJ	P,RDREG		;READ IT
	MOVEM	T2,TRBRCT(T1)	;SAVE CHARACTERS READ IN IORB
	MOVEM	T2,TUBCCR##(U)	;  AND IN UDB
	MOVEM	T2,TD2FST##+.TFRED(U) ;  AND FOR DAEMON
	ADDM	T2,TUBCRD##(U)	;BUMP CHARACTERS READ SINCE UNLOAD
	ADDM	T2,.CPTFI##
	LDB	T3,PRBMOD##	;GET DATA MODE FROM IORB
	IDIV	T2,TMODTB##(T3)	;COMPUTE NUMBER OF WORDS AND RESIDUE
	HRLM	T2,TUBCHR##(U)	;STORE WORD COUNT IN UDB
	DPB	T3,PMTNCR##	;  AND RESIDUE
	JRST	DONE		;EXIT THROUGH COMMON CODE
;HERE ON A WRITE INTERRUPT

WRTINT:	AOS	TUBREC##(U)	;INCREMENT RECORD COUNT
	TRNE	P1,G0.UEX	;UNIT EXCEPTION?
	TLO	T1,RB.SET	;YES, SAW END-OF-TAPE
	TRNE	P1,G0.UCK	;UNIT CHECK?
	JRST	CHKWLK		;YES, CHECK FOR WRITE LOCK ERROR
	HRRE	T2,TKBWCT(W)	;GET -NUMBER OF BYTES WRITTEN
	MOVNS	T2		;MAKE IT POSITIVE
	MOVEM	T2,TD2FST##+.TFWRT(U) ;SAVE FOR DAEMON
	ADDM	T2,TUBCWR##(U)	;BUMP CHARACTERS WRITTEN SINCE UNLOAD
	ADDM	T2,.CPTFO##
	JRST	DONE		;EXIT THROUGH COMMON CODE


;HERE ON WRITE TAPE MARK INTERRUPT

WTMINT:	TRNE	P1,G0.UEX	;UNIT EXCEPTION?
	TLO	T1,RB.SET	;YES, SAW END-OF-TAPE
	TRNE	P1,G0.UCK	;UNIT CHECK?
	JRST	CHKWLK		;YES, CHECK FOR WRITE LOCKED TAPE
	AOS	TUBFIL##(U)	;ADJUST FILE AND RECORD COUNT (DON'T
	SETZM	TUBREC##(U)	; CALL NXTFIL CAUSE IT SET RB.STM)
	JRST	DONE		;EXIT THROUGH COMMON CODE


;HERE ON AN ERASE GAP INTERRUPT

ERGINT:	TRNE	P1,G0.UEX	;UNIT EXCEPTION?
	TLO	T1,RB.SET	;YES, SAW END-OF-TAPE
	TRNE	P1,G0.UCK	;UNIT CHECK?
	JRST	CHKWLK		;YES, CHECK FOR WRITE LOCKED TAPE
	JRST	DONE		;EXIT THROUGH COMMON CODE


;HERE ON A DATA SECURITY ERASE INTERRUPT

DSEINT:	TRNN	P1,G0.UCK	;UNIT CHECK?
	JRST	DONE		;NO, EXIT THROUGH COMMON CODE
;;	JRST	CHKWLK		;FALL INTO CHKWLK


;HERE ON UNIT CHECKS ON WRITE TYPE OPERATIONS TO CHECK FOR A
;WRITE LOCKED TAPE

CHKWLK:	PUSHJ	P,SNSANL	;ANALYZE SENSE BYTES
	TLNE	P2,(S1.FPR)	;IS UNIT WRITE PROTECTED?
	HRLI	T1,RB.SLK	;YES, TELL TAPUUO
	JRST	DONE		;EXIT THROUGH COMMON CODE
;HERE ON A REWIND AND UNLOAD INTERRUPT

UNLINT:	MOVSI	T2,TKSOFL##	;GET "UNIT IS OFFLINE" BIT
	IORM	T2,TUBSTS##(U)	;SET IT IN THE UDB
	MOVSI	T2,TUSBOT##!TUSREW##	;GET BOT BIT & REW
	ANDCAM	T2,TUBSTS##(U)	;AND CLEAR IT IN THE UDB
	JRST	REWIN1		;DO MOST OF REWIND CODE ALSO


;HERE ON A REWIND INTERRUPT

REWINT:	MOVSI	T2,TUSREW##	;GET "UNIT IS REWINDING" BIT
	IORM	T2,TUBSTS##(U)	;SET IN UDB
REWIN1:	TRNE	P1,G0.UCK	;UNIT CHECK? (PROBABLY OFF-LINE)
	PUSHJ	P,SNSANL	;YES, ANALYZE SENSE BYTES
	JRST	DONE		;EXIT THROUGH COMMON CODE


;HERE ON A SPACE FORWARD RECORD INTERRUPT

SFRINT:	PUSHJ	P,ADJREC	;ADJUST TUBREC AS APPROPRIATE
	TRNE	P1,G0.UEX	;UNIT EXCEPTION?
	PUSHJ	P,NXTFIL	;YES, SAW A TAPE MARK
	TRNE	P1,G0.UCK	;UNIT CHECK?
	PUSHJ	P,SNSANL	;YES, ANALYZE SENSE BYTES
	PUSHJ	P,CHKBOT	;CHECK FOR BOT
	JRST	DONE		;EXIT THROUGH COMMON CODE


;HERE ON A SPACE BACKWARD RECORD INTERRUPT
 
SBRINT:	PUSHJ	P,ADJREC	;ADJUST TUBREC AS APPROPRIATE
	TRNN	P1,G0.UEX	;UNIT EXCEPTION?
	JRST	SBRIN1		;NO
	PUSHJ	P,LSTFIL	;BACKED INTO A TAPE MARK
	SETOM	TUBREC##(U)	;AT AN EOF
SBRIN1:	TRNN	P1,G0.UCK	;UNIT CHECK?
	JRST	DONE		;NO, EXIT THROUGH COMMON CODE
	TLNE	P2,(SB.UCE)	;UNIT CHECK DUE TO ERRORS?
	PUSHJ	P,SNSANL	;YES, ANALYZE SENSE BYTES
	PUSHJ	P,CHKBOT	;CHECK FOR BOT
	JRST	DONE		;EXIT THROUGH COMMON CODE
;HERE ON A SPACE FORWARD FILE INTERRUPT.  THIS CODE IS NOT ASSEMBLED
;SINCE TOPS10 DOES NOT USE THIS FUNCTION AT PRESENT.

SFFINT==TAPIFI##		;WHERE TO GO IF NOT ASSEMBLED
REPEAT 0, <			;DON'T ASSEMBLE THIS CODE
SFFINT:	TRNE	P1,G0.UCK	;UNIT CHECK?
	PUSHJ	P,SNSANL	;YES, ANALYZE SENSE BYTES
	PUSHJ	P,ADJFIL	;ADJUST TUBFIL, TUBREC
	PUSHJ	P,CHKBOT	;CHECK FOR BOT
	JRST	DONE		;EXIT THROUGH COMMON CODE
>;END REPEAT 0


;HERE ON A SPACE BACKWARD FILE INTERRUPT. THIS CODE IS NOT ASSEMBLED
;SINCE TOPS10 DOES NOT USE THIS FUNCTION AT PRESENT.

SBFINT==TAPIFI##		;WHERE TO GO IF NOT ASSEMBLED
REPEAT 0,<			;DON'T ASSEMBLE THIS CODE
SBFINT:	TRNN	P1,G0.UCK	;UNIT CHECK?
	JRST	SBFIN1		;NO
	TLNE	P2,(SB.UCE)	;UNIT CHECK DUE TO ERRORS?
	PUSHJ	P,SNSANL	;YES, ANALYZE SENSE BYTES
	PUSHJ	P,CHKBOT	;CHECK FOR BOT
SBFIN1:	PUSHJ	P,ADJFIL	;ADJUST TUBFIL, TUBREC
	JRST	DONE		;EXIT THROUGH COMMON CODE
>;END REPEAT 0
;HERE AT THE COMPLETION OF FUNCTION SPECIFIC INTERRUPT PROCESSING
;OF A COMMAND COMPLETION INTERRUPT (BOTH DATA TRANSFER AND NON-DATA TRANSFER)
;WITH:
;	T1/ERROR BITS,,IORB ADDRESS

DONE:	TLNN	T1,RB.SLK	;CHANNEL ERRS MEANINGLESS ON WLK ERRS
	PUSHJ	P,CHKCHN	;CHECK FOR CHANNEL ERRORS
	PUSHJ	P,TSTERR	;READ ERROR REGISTERS IF NECESSARY
	MOVSI	T2,(.DXERR)	;SETUP TO CLEAR ERROR REGISTER
	PUSHJ	P,WTREG		;DO SO
	HLLZ	T2,T1		;GET THE ERROR BITS
	IORM	T2,TRBSTS(T1)	;SET THEM IN THE IORB
	MOVSI	T2,TKSOFL##	;GET OFF-LINE BIT
	TLNE	T1,RB.SOL	;IS IT?
	IORM	T2,TUBSTS##(U)	;YES, SET THE BIT IN THE UDR
	MOVSI	T2,RB.EXC	;GET EXCEPTION BIT
	TLZE	T1,-1		;ANY BITS SET?
	IORM	T2,TRBLNK(T1)	;YES, SET EXCEPTION ALSO
	HRLM	T1,TKBATN(W)	;SAVE IORB ADDRESS FOR LATER
	TLO	P1,(TB.DON)	;TELL CHKATN WE'VE BEEN THROUGH DONE
	PUSHJ	P,CHKATN	;CHECK FOR ASYNCHRONOUS STATUS
	PJRST	CLRALL		;RETURN
	SUBTTL	ANSYNCHRONOUS EVENT PROCESSING


;HERE TO CHECK FOR ANY ASYNCHRONOUS STATUS PRESENTED BY THE DX20
;AS A RESULT OF REWIND-DONE OR DRIVE ONLINE.  IF ANY SUCH STATUS
;IS PRESENTED, WE START A FORCED SENSE FUNCTION ON THAT DRIVE AND
;GO AWAY, TELLING TAPSER THAT ANOTHER INTERRUPT WILL FOLLOW.  WHEN
;ALL ASYNCHRONOUS STATUS IS PROCESSED, WE RETURN THE IORB FOR THE
;OPERATION THAT WAS IN PROGRESS TO TAPSER.

CHKATN:	MOVE	P3,P1		;COPY FLAG BITS TO P3
	PUSHJ	P,CLRATN	;CLEAR ATTN BITS, RETURN IN T2, 0 IN T3
	SKIPGE	T1,TKBSCH(W)	;INTERRUPT TO FORCE A SCHEDULE?
	JRST	[SETZM	TKBSCH(W)	;YES, CLEAR SCHEDULE FLAG
		 JRST	CLRALL]		;AND RETURN -1 TO TAPSER
	MOVEI	P1,(T2)		;MOVE TO SAFER PLACE
	MOVEI	P2,1		;GET MASK FOR DX20 TO DO
	PUSH	P,U		;SAVE U
CHKAT1:	JUMPE	P1,ATNDON	;DONE IF NO MORE BITS UP
	TRNN	P1,(P2)		;THIS DX20 NEED ATTENTION?
	JRST	CHKAT2		;NO, CHECK NEXT
	PUSHJ	P,MPRUNX	;IS MICROPROCESSOR STILL RUNNING?
	  JRST	[HLRZ	T2,TKBASY(W) ;GET DX20 NUMBER FROM POSSIBLE OPERATION
		 TLNE	P3,(TB.DON)  ;BEEN THROUGH DONE?
		 CAIE	T2,(T3)	     ;  FOR THIS DX20?
		 PUSHJ	P,LOGUPE     ;NO, LOG THE ERROR
		 JRST	CHKAT2]	     ;TRY NEXT ONE
	PUSHJ	P,ASYNST	;YES, CHECK FOR ASYNCHRONOUS STATUS
CHKAT2:	MOVSI	T2,(.DXERR)	;AVOID A POSSIBLE LOOP
	PUSHJ	P,WTREGX	;BY CLEARING THE ERROR REGISTER HERE
	TRZ	P1,(P2)		;CLEAR THIS ATTENTION BIT
	LSH	P2,1		;STEP TO NEXT BIT POSITION
	AOJA	T3,CHKAT1	;BUMP DX20 NUMBER AND LOOP

;HERE WHEN ALL ASYNCHRONOUS STATUS HAS BEEN PROCESSED.  CLEAR ALL
;ASYNCHRONOUS STATUS FLAGS AND RETURN ANY IORB TO TAPSER.

ATNDON:	HLRZ	T1,TKBATN(W)	;GET SAVED IORB ADDRESS, IF ANY
	SETZM	TKBATN(W)	;NO ATTENTIONS TO WORRY ABOUT
	SETZM	TKBASY(W)	;NO ASYNCH
	POP	P,U		;RESTORE U
	PJRST	CLRERR		;CLEAR ERROR AND RETURN

;HERE TO RETURN A ZERO TO TAPSER TO TELL IT THAT ANOTHER INTERRUPT
;IS COMING.

RTNZRO:	MOVEI	T1,0		;RETURN TO TAPSER.
	POPJ	P,		;AND RETURN.

	SUBTTL	INTERRUPT LEVEL SUPPORT SUBROUTINES


;ROUTINE TO CHECK FOR ANY ASYNCHRONOUS STATUS PRESENTED BY A
;DRIVE AT THE COMPLETION OF REWIND DONE, COMING ONLINE, ETC.
;CALL WITH:
;	T3/DX20 NUMBER,  W/KDB ADDRESS,  P1/ATTENTION BITS
;RETURN+1 IF NO STATUS PRESENTED
;RETURN+2 IF STATUS READ AND SENSE FUNCTION STARTED ON THAT DRIVE
;	WITH TKBASY(W)/DX20 NUMBER,,ENDING STATUS OF DRIVE
;BOTH RETURN WITH:
;	T3/UNCHANGED

ASYNST:	MOVSI	T2,(.DXGP4)	;POINT AT ASYNCHRONOUS STATUS REGISTER
	PUSHJ	P,RDREGX	;READ IT
	JUMPE	T2,CPOPJ##	;RETURN+1 IF NO STATUS
	TRNE	T2,G4.DVS	;ANY STATUS BITS SET?
	JRST	ASYNS1		;YES, CONTINUE
	MOVSI	T2,(.DXGP4)	;THERE'S A UCODE RACE WHICH CAUSES IT TO GIVE
	PUSHJ	P,RDREGX	;US A DRIVE WITH NO STATUS, SO READ IT AGAIN
ASYNS1:	HRLM	T3,TKBASY(W)	;SAVE DX20 NUMBER
	HRRM	T2,TKBASY(W)	;  AND STATUS FOR INTERRUPT
	HRRM	P1,TKBATN(W)	;SAVE CURRENT STATE OF ATTENTIONS
	LDB	T2,[POINTR TKBASY(W),G4.DRV]	;GET DRIVE #
	PUSHJ	P,SETUDB##	;SETUP U TO UDB ADDRESS IF ANY
	  POPJ	P,		;NONE, JUST TRY NEXT
	MOVE	T2,TKBASY(W)	;GET ASSYNC AND DRIVE STATUS.
	MOVE	T4,TUBSTS(U)	;GET OLD STATUS
	TRNN	T2,G4.STM	;WRITE LOCK?
	  TLZA	T4,TUSWTL##	;NO
	TLO	T4,TUSWTL##	;YES
	TRNE	T2,G4.ATN	;AT BOT?
	  TLOA	T4,TUSBOT##	;YES
	TLZA	T4,TUSBOT##	;NO
	  TLZ	T4,TUSREW##	;NOT REWINDING IF SO
	TLZE	T4,TKSOFL##	;NOT OFF-LINE NOW, WAS IT?
	  PUSHJ	P,NOWONL	;YES, TELL MDA
	MOVSI	T2,TUSREW##!TKSOFL##!TUSWTL##!TUSBOT##
	ANDCAM	T2,TUBSTS##(U)	;CLEAR IN TUB
	IORM	T4,TUBSTS##(U)	;SO CAN SET OUR VALUES
	TLNE	T4,TUSBOT##
	PUSHJ	P,UNIBOT##
	MOVSI	T2,(.DXGP4)	;SETUP TO CLEAR ASYNC STATUS REGISTER.
	PUSHJ	P,WTREGX	;DO IT!!!
	PJRST	CLRERR
;ROUTINE TO REQUEST THAT THE DX20 STORE A PARTICULAR LOCATION
;FROM ITS EXTENDED STATUS TABLE INTO MASSBUS REGISTERS 26 AND 27.
;CALL WITH:
;	T2/EST OFFSET REQUESTED, U/UDB ADDRESS, W/KDB ADDRESS
;RETURN+1 IF THE DX20 TIMED OUT ON THE REQUEST
;RETURN+2 IF SUCCESSFUL

SETEST:	HRLI	T2,(.DXGP0)	;POINT TO EST REGISTER
	TRO	T2,G0.RES	;SET THE REQUEST EST BIT
	PUSHJ	P,WTREG		;TELL THE DX20
	PUSH	P,T1		;SAVE T1
	MOVEI	T1,100		;MAX LOOP COUNT TO WAIT FOR BIT TO CLEAR
SETES1:	MOVSI	T2,(.DXGP0)	;POINT AT EST REGISTER AGAIN
	PUSHJ	P,RDREG		;READ IT
	TRNE	T2,G0.RES	;DX20 DONE WHAT WE WANT?
	SOJG	T1,SETES1	;NO, LOOP
	JUMPLE	T1,TPOPJ##	;IF WE TIMED OUT, QUIT
	JRST	TPOPJ1##	;GOT IT, GIVE SKIP RETURN


;ROUTINE TO READ THE INFORMATION FROM THE TWO EXTENDED STATUS
;REGISTERS.  THE EXACT INFORMATION READ DEPENDS UPON THE VALUE
;OF THE STATUS INDEX IN .DXGP0.
;CALL WITH:
;	T3/DX20 NUMBER,  W/KDB ADDRESS
;RETURN+1 ALWAYS WITH T4/.DXGP6,,.DXGP7
;ENTER AT REDES3 TO SETUP T3 FROM TKBUNI

REDES3:	HLRZ	T3,TKBUNI##(W)	;GET THE DX20 NUMBER
REDEST:	MOVSI	T2,(.DXGP6)	;POINT AT EXTENDED STATUS REGISTER 0
	PUSHJ	P,RDREGX	;READ IT
	HRLZ	T4,T2		;MOVE TO WHERE CALLER EXPECTS IT
	MOVSI	T2,(.DXGP7)	;POINT AT EXTENDED STATUS REGISTER 1
	PUSHJ	P,RDREGX	;READ IT
	HRR	T4,T2		;MOVE TO WHERE CALLER EXPECTS IT
	POPJ	P,		;AND RETURN
;ROUTINE TO CLEAR ALL ATTENTION BITS IN THE ATTENTION SUMMARY REGISTER
;AND UPDATE THE ATTENTION BITS IN TKBATN.
;CALL WITH:
;	W/KDB ADDRESS
;RETURN+1 ALWAYS WITH:
;	T2/UPDATED ATTENTION BITS,  T3/0 (DX20 NUMBER)

CLRATN:	MOVSI	T2,(.DXASR)	;POINT TO ATTENTION SUMMARY REGISTER
	MOVEI	T3,0		;ASR IS NOT DX20 SPECIFIC
	PUSHJ	P,RDREGX	;READ IT
	ANDI	T2,AS.ATN	;KEEP ONLY ATTENTION BITS
	TDNN	T2,TKBUNI##(W)	;ATTEN FOR THIS UNIT?
	JRST	CLRAT1		;NO, RETURN 0
	HRRZ	T2,TKBUNI##(W)	;YES, GET JUST THAT BIT
	IORM	T2,TKBATN(W)	;UPDATE CORE COPY
	HRLI	T2,(.DXASR)	;SETUP TO CLEAR THE REGISETER
	PUSHJ	P,WTREGX	;DO SO
CLRAT1:	HRRZ	T2,TKBATN(W)	;RETURN UPDATED BITS TO CALLER
	POPJ	P,		;RETURN


;ROUTINES TO SET RB.STM, ZERO TUBREC AND ADJUST TUBFIL
;TO REFLECT THE ENDING STATE OF THE LAST OPERATION.  ENTRY POINTS ARE:
;	NXTFIL - ADD 1 TO TUBFIL
;	LSTFIL - SUBTRACT 1 FROM TUBFIL
;	ADJFIL - ADJUST TUBFIL BY NUMBER OF FILES DONE (+ OR -)
;CALL WITH:
;	W/KDB ADDRESS,  U/UDB ADDRESS,  T1/ERROR BITS,,IORB ADDRESS
;RETURN+1 ALWAYS WITH:
;	T1/ERROR BITS+RB.STM,,IORB ADDRESS

LSTFIL:	SOSA	TUBFIL##(U)	;AT LAST FILE
NXTFIL:	AOS	TUBFIL##(U)	;AT NEXT FILE
	JRST	ADJFI1		;JOIN COMMON CODE
ADJFIL:	PUSHJ	P,NUMOPS	;COMPUTE NUMBER OF FILES MOVED
	ADDM	T3,TUBFIL##(U)	;ADJUST TUBFIL BY THAT AMOUNT
	JUMPE	T3,ADJFI2	;DON'T SET RB.STM IF NO MOTION
ADJFI1:	TLO	T1,RB.STM	;SAW TAPE MARK
ADJFI2:	SETZM	TUBREC##(U)	;AT FIRST RECORD OF FILE
	POPJ	P,		;RETURN


;ROUTINE TO ADJUST TUBREC BY THE NUMBER OF RECORDS MOVED IN THE
;LAST OPERATION. CALL WITH:
;	U/UDB ADDRESS,  W/KDB ADDRESS
;RETURN+1 ALWAYS

ADJREC:	PUSHJ	P,NUMOPS	;COMPUTE NUMBER OF RECORDS MOVED
	ADDM	T3,TUBREC##(U)	;ADJUST TUBREC ACCORDINGLY
	POPJ	P,		;AND RETURN
;ROUTINE TO COMPUTE THE NUMBER OF OPERATIONS PERFORMED AS A RESULT
;OF THE LAST NON DATA TRANSFER REQUEST.  DEPENDS ON THE FACT THAT
;TAPUUO SETS UP TRBXCW TO THE CORRECT NUMBER OF OPERATIONS FOR ANY
;REQUEST ON WHICH NUMOPS IS TO BE CALLED. CALL WITH:
;	U/UDB ADDRESS,  W/KDB ADDRESS,  T1/ERROR BITS,,IORB ADDRESS
;	P1/IOFTBL ENTRY,,DEVICE STATUS BITS
;RETURN+1 ALWAYS WITH:
;	T3/+NUMBER IF FORWARD OPERATION, -NUMBER IF REVERSE

NUMOPS:	MOVSI	T2,(.DXFCR)	;POINT TO FRAME COUNT REGISTER
	PUSHJ	P,RDREG		;READ -NUMBER OF OPS NOT PERFORMED
	HRRZ	T3,TRBXCW(T1)	;GET +NUMBER REQUESTED BY TAPUUO
	JUMPE	T2,NUMOP1	;IF ALL WERE DONE, TAKE QUICK PATH
	IOR	T2,[-1,,600000]	;MAKE IT 36 BIT NEGATIVE NUMBER
	MOVNS	T2		;MAKE IT POSITIVE
	SUB	T3,T2		;COMPUTE NUMBER ACTUALLY DONE
NUMOP1:	TLNE	P1,(TB.REV)	;THIS A REVERSE OPERATION?
	MOVNS	T3		;YES, MAKE IT NEGATIVE
	POPJ	P,		;RETURN TO CALLER


;ROUTINE TO SEE IF THE UNIT IS CURRENTLY AT BOT AND ADJUST THE UNIT
;AND IORB STATUS TO REFLECT THIS.  CALL WITH:
;	U/UDB ADDRESS,  W/KDB ADDRESS,  T1/ERROR BITS,,IORB ADDRESS
;	P2/SENSE BYTES 0-3
;RETURN+1 ALWAYS WITH:
;	T1/UPDATED ERROR BITS,,IORB ADDRESS,
;	TUBFIL AND TUBREC ZEROED IF AT BOT,  TUBSTS UPDATED

CHKBOT:	TLNN	P2,(S1.BOT)	;NOW AT BOT?
	POPJ	P,		;NO, RETURN
	SKIPN	TUBREC##(U)	;IF NOT PREVIOUSLY
	SKIPE	TUBFIL##(U)	;  AT BOT,
	PJRST	SETBOT		;  SET IT NOW
	TLO	T1,RB.SNM	;OTHERWISE, NO MOTION
;;	PJRST	SETBOT		;AND FALL INTO BOT


;ROUTINE TO ADJUST UDB AND IORB STATUS TO SHOW THAT THE UNIT IS
;AT BOT.  CALL WITH:
;	U/UDB ADDRESS,  W/KDB ADDRESS,  T1/ERROR BITS,,IORB ADDRESS
;RETURN+1 ALWAYS WITH:
;	T1/ERROR BITS+RB.SBT,,IORB ADDRESS,
;	TUBREC, TUBFIL ZEROED,  TUBSTS UPDATED

SETBOT:	TLO	T1,RB.SBT	;NOW AT BOT
	PJRST	UNIBOT##	;LET TAPSER DO THE REST
;ROUTINE TO CHECK FOR ANY ERRORS IN THE LAST OPERATION.
;CALL WITH:
;	T1/ERROR BITS,,IORB ADDRESS,  U/UDB ADDRESS,  W/KDB ADDRESS,
;	P1/IOFTBL BITS,,ENDING STATUS BYTE
;RETURN+1 IF HARD ERROR
;RETURN+2 IF NO ERRORS (OR A RECOVERABLE ERROR) DETECTED
;BOTH RETURN WITH:
;	P2/0 IF NO ERRORS
;	   SENSE BYTES 0-3 IF  ERROR
;	T1/UPDATED ERROR BITS,,IORB ADDRESS

CHKERR:	MOVEI	P2,0		;ASSUME NO ERRORS AND RETURN ZERO SENSE BYTES
	MOVSI	T2,(.DXSTR)	;POINT AT STATUS REGISTER
	PUSHJ	P,RDREG		;READ IT
	TRNN	T2,SR.RUN	;MICROPROCESSOR STILL RUNNING?
	JRST	MPSERR		;NO
	AOS	0(P)		;ASSUME NO ERROR OR RECOVERABLE ERROR
	TRNN	T2,SR.CER	;COMPOSITE ERROR?
	PJRST	CHKDEN		;NO, CHECK FOR SENSE DATA FOR DENSITY DETECT
	MOVSI	T2,(.DXERR)	;POINT AT ERROR REGISTER
	PUSHJ	P,RDREG		;READ IT
	TRNE	T2,ER.ERR	;SOME GENERIC HARDWARE FAILURE?
	TLO	T1,RB.SED	;YES, JUST TRY RECOVERY
	TDNN	P1,[TB.FSN!G0.UCK] ;FORCED A SENSE OR HAVE A UNIT CHECK?
	JRST	CHKER1		;NO, NO SENSE BYTES WERE READ
	PUSH	P,T2		;SAVE ERROR REGISTER
	PUSHJ	P,REDES3	;GET SENSE BYTES FOR THIS DRIVE
	MOVE	P2,T4		;MOVE SENSE BYTES TO CORRECT PLACE
	PUSHJ	P,CHKDEN	;CHECK FOR DENSITY DETECT EVEN IF ERRORS
	POP	P,T2		;RESTORE ERROR REGISTER
CHKER1:	TRNN	T2,ER.UPE	;MICROPROCESSOR ERROR?
	JRST	ERRXIT		;NO, THEN CODE IS MEANINGLESS
	LDB	T3,[POINTR T2,ER.ECC] ;GET ERROR CLASS CODE
	CAILE	T3,ECCMAX	;BIGGER THAN WE KNOW ABOUT
	JRST	FTLERR		;YES, FATAL
	JRST	@ECCTBL(T3)	;DISPATCH TO ERROR HANDLER
;DISPATCH TABLE OF ROUTINES TO HANDLE SPECIFIC ERROR CONDITIONS
;DETECTED BY THE DX20. THE TABLE IS INDEXED BY THE ERROR CLASS
;CODE IN THE ERROR REGISTER.

ECCTBL:	EXP	FTLERR		;0 - UNKNOWN
	EXP	ERRXIT		;1 - UNUSUAL DEVICE STATUS
	EXP	ERRXIT		;2 - SHORT RECORD - NOT AN ERROR
	EXP	LNGREC		;3 - LONG RECORD 
	EXP	OFLERR		;4 - DRIVE SELECTION ERROR
	EXP	RTYERR		;5 - RECOVERABLE ERROR (TAPE MOTION)
	EXP	NOMERR		;6 - RECOVERABLE ERROR (NO TAPE MOTION)
	EXP	NRTERR		;7 - NON-RECOVERABLE ERROR
	EXP	FTLERR		;10 - FATAL ERROR
	EXP	FTLERR		;11 - MICRODIAGNOSTICS FAILURE
ECCMAX==.-ECCTBL-1		;MAXIMUM ERROR CODE WE KNOW ABOUT


NRTERR:	LDB	T3,[POINTR T2,ER.ESC] ;GET SUB-CLASS CODE FOR THIS ERROR
	CAIE	T3,.ERRTT	;READ TRANSFER TIMEOUT (BLANK TAPE)?
	JRST	NRTER1		;NO
	JRST	MPSERR		;YES, SET OFF-LINE ALSO

FTLERR:	SOS	0(P)		;GIVE NON-SKIP RETURN FOR HARD BAD ERROR
	TLO	T1,RB.SMO	;FLAG AS SET OFFLINE BY MONITOR
	PUSHJ	P,MPRES		;MAKE DAMN SURE IT STAYS OFF LINE
MPSERR:	TLOA	T1,RB.SED!RB.SER!RB.SOL ;SOME ERROR+NO RETRY+SET OFF LINE
NRTER1:	TLO	T1,RB.SED!RB.SER ;SOME ERROR+NO RETRY
	JRST	ERRXIT		;JOIN COMMON EXIT

OFLERR:	TLO	T1,RB.SOL	;SELECT ERROR MEANS DRIVE IS OFF-LINE
NOMERR:	TLO	T1,RB.SNM	;NO MOTION
RTYERR:	TLOA	T1,RB.SED	;SOME ERROR
LNGREC:	TLO	T1,RB.STL!RB.SER ;LONG RECORD+NO RETRY

ERRXIT:	TLNE	T1,-1		;SEE ANY ERRORS AT ALL?
	TLO	P1,(TB.ERR)	;YES, SET FLAG FOR QUICK CHECK
	POPJ	P,		;RETURN
;ROUTINE TO CHECK TO SEE IF WE FORCED A SENSE ON A READ OPERATION SO
;THAT WE CAN TELL THE USER THE REAL DENSITY THAT THE TAPE IS WRITTEN
;AT.
;CALL WITH:
;	T1/ERROR BITS,,IORB ADDRESS,  U/UDB ADDRESS,  W/KDB ADDRESS
;	P1/IOFTBL ENTRY,,ENDING STATUS BYTE,  P2/SENSE BYTES 0-3 (0 IF NOT READ)
;RETURN+1 ALWAYS WITH DENSITY UPDATED IN THE IORB

CHKDEN:	MOVEI	T2,TUC7TK##	;GET 7 TRACK BIT
	TDNN	T2,TUBCNF##(U)	;NO SENSE BYTE INFO IF A 7 TRACK DRIVE
	TLNN	P1,(TB.FSN)	;FORCED SENSE DONE?
	POPJ	P,		;NEITHER, RETURN NOW
	JUMPN	P2,CHKDE1	;GO IF ALREADY HAVE THE SENSE BYTES
	PUSHJ	P,REDES3	;READ SENSE BYTES 0-3 NOW
	JUMPE	T4,CPOPJ##	;DIDN'T GET THEM IF ALL ZERO
	MOVE	P2,T4		;MOVE THEM TO WHERE WE WANT THEM
CHKDE1:	TRNE	P2,S3.D16	;IS THE TAPE AT 1600?
	JRST	[MOVEI T2,RB.D16 ;YES, SET 1600 BPI
		 JRST  CHKDE2]	;AND STORE IT
	MOVEI	T2,.S6EST	;GET OFFSET INTO EST TO READ SENSE BYTE 6
	PUSHJ	P,SETEST	;ASK THE DX20 FOR THE INFORMATION
	  POPJ	P,		;CAN'T GET IT, GIVE UP
	PUSHJ	P,REDES3	;READ SENSE BYTES 4-7 INTO T4
	MOVEI	T2,RB.D8	;ASSUME 800 BPI
	TRNE	T4,S6.D62	;WAS IT A 6250 BPI TAPE?
	MOVEI	T2,RB.D62	;YES, USE THAT INSTEAD
CHKDE2:	DPB	T2,PRBDEN##	;STORE THAT IN THE IORB FOR THE WORLD
	POPJ	P,		;RETURN
;ROUTINE TO ANALYZE THE SENSE BYTES FOR A DRIVE ON WHICH AN ERROR
;OCCURRED AND SET THE APPROPRIATE ERROR BITS.
;CALL WITH:
;	T1/ERROR BITS,,IORB ADDRESS,
;	P1/IOFTBL ENTRY,,DEVICE STATUS BYTE,  P2/SENSE BYTES 0-3
;RETURN+1 ALWAYS WITH:
;	T1/UPDATED ERROR BITS,,IORB ADDRESS

SNSANL:	TLO	P1,(TB.ERR)	;SET ERROR
	TLNE	P2,(S0.EQC)	;EQUIPMENT CHECK?
	JRST	EQCERR		;YES, GO ANALYZE IT
	TLNE	P2,(S0.BOC)	;BUS-OUT CHECK?
	JRST	BOCERR		;YES
	TLNE	P2,(S0.IRQ)	;INTERVENTION REQUIRED WITHOUT
	TRNE	P1,G0.DVE	; DEVICE END MEANS
	JRST	SNSAN1		; DEVICE IS OFFLINE OR
	JRST	IRQERR		; NON-EXISTENT
SNSAN1:	TLNE	P2,(S0.CRJ!S1.NTC) ;COMMAND REJECT OR NOT CAPABLE?
	JRST	CMRERR		;YES
	TLNE	P2,(S0.OVR)	;OVERRUN?
	JRST	OVRERR		;YES
	TLNE	P2,(S0.DTC)	;DATA CHECK?
	JRST	DTCERR		;YES


;COMMAND REJECT AND EQUIPMENT CHECK ARE CONSIDERED FATAL ERRORS

CMRERR:
EQCERR:	TLOA	T1,RB.SER!RB.SED ;NON-RECOVERABLE + ERROR
IRQERR:	TLO	T1,RB.SED!RB.SOL!RB.SNM ;IRQ GETS OFFLINE + NO MOTION
	POPJ	P,		;RETURN


;BUS OUT CHECK WITHOUT DEVICE END MEANS NO MOTION, ELSE RETRY

BOCERR:	TRNN	P1,G0.DVE	;DEVICE END UP?
	TLO	T1,RB.SNM	;NO, SET NO MOTION


;OVERRUN CAUSES REPOSITION AND RETRY

OVRERR:	TLOA	T1,RB.SED	;SOME ERROR


;DATA CHECK INVOKES TAPSER'S ERROR RETRY ALGORITHM

DTCERR:	TLO	T1,RB.SDE!RB.SED ;DATA ERROR + ERROR
	POPJ	P,		;RETURN
;ROUTINE TO CHECK FOR AND HANDLE ANY CHANNEL ERRORS THAT OCCURRED
;ON THE LAST OPERATION. CALL WITH:
;	T1/ERROR BITS,,IORB ADDRESS,  P1/IOFTBL ENTRY FOR FUNCTION
;	W/KDB ADDRESS
;RETURN+1 ALWAYS WITH:
;	T1/UPDATED ERROR BITS,,IORB ADDRESS

CHKCHN:	XCT	TKBCIS##(W)	;GET CONI INTO T2
	MOVE	T3,TKBICP##(W)	;GET ADDRESS OF CHANNEL LOGOUT AREA
	HLL	T2,.CSCLP(T3)	;LOGOUT AREA ERROR BITS IN LH
	TLNN	P1,(TB.DAT)	;THIS A DATA OPERATION?
	TLZA	T2,-1		;NO, CLEAR THE STATUS BITS; THEY'RE USELESS
	TLC	T2,(CS.NAE)	;MAKE BIT EQUAL 1 IF ADDRESS PARITY ERROR
	TDNN	T2,[CS.ERR!CI.ERR] ;ANY ERROR DETECTED?
	POPJ	P,		;NO, RETURN
	TRNE	T2,CI.RAE	;REGISTER ACCESS ERROR?
	JRST	CHKCH2		;YES, GO SET THE APPROPRIATE BITS AND RETRY
	TLNN	T2,(CS.MPE!CS.NXM) ;MEM PAR ERROR OR NXM?
	JRST	CHKCH1		;NO
	PUSHJ	P,SAVE1##	;GET A REGISTER TO USE
	PUSH	P,T1		;AND SAVE OUR T1
	MOVEI	T3,CHNNXM##	;POINT AT RTN TO CALL FOR NXM
	MOVSI	T4,IOCHNX	;ASSUMING NXM
	TLNN	T2,(CS.NXM)	;ARE WE CORRECT?
	MOVEI	T3,CHNMPE##	;NO, USE THIS ONE
	TLNN	T2,(CS.NXM)	; ...
	MOVSI	T4,IOCHMP	; ...
	HRRZ	T1,TKBICP##(W)	;GET ADDRESS OF LOGOUT AREA
	HRRZ	P1,TKBCDB##(W)	;GET CHANNEL DATA BLOCK ADDRESS
	HRRZ	F,TUBCUR##(U)	;GET DDB ADDRESS
	IORM	T4,CHNNUM##(P1)	;MARK MEMORY ERROR FOR LATER SWEEP
	SKIPN	TUBERR##(U)	;CALL ERRCON ON FIRST ERROR ONLY
	PUSHJ	P,(T3)		;LET COMMON HANDLE THE ERROR
	POP	P,T1		;RESTORE T1
CHKCH1:	TLOA	T1,RB.SED	;TELL UPPER LEVEL OF ERROR
CHKCH2:	TLO	T1,RB.SNM!RB.SED ;NO MOTION, SOME ERROR FOR RAE
	TLO	P1,(TB.ERR)	;ALSO SET ERROR
	POPJ	P,		;AND RETURN
	SUBTTL	CHECK FOR KONTROLLER ONLINE


;HERE TO SEE IF A KONTROLLER IS ONLINE.  WHAT WE REALLY DO IS
;CHECK TO SEE THAT ALL DX20'S ON THIS KONTROLLER ARE RUNNING.
;CALL WITH:
;	W/KDB ADDRESS
;RETURN+1 IF ANY DX20 IS NOT RUNNING
;RETURN+2 IF ALL DX20'S ARE RUNNING

TD2ONL:	MOVE	T3,TKBSTS##(W)	;ALWAYS ONLINE IF
	HRRZ	T1,TKBCDB##(W)	;POINTER TO CHANNEL
	SKIPGE	(T1)		;DON'T DO CONO'S IF CHAN IS IN USE (USER  MODE DIAG)

	TLNE	T3,TKSSEL##!TKSSTD##!TKSSCH## ;THE KONTROLLER
	JRST	CPOPJ1##	;IS GOING
	PUSHJ	P,SAVE2##	;SAVE P1-P2
	PUSH	P,U		;SAVE U FOR TAPSER
	MOVE	P1,TKBIUN##(W)	;GET AOBJN POINTER TO UNITS
	SETOM	P2		;INITIALIZE DX20 NUMBER
TD2ON1:	SKIPN	U,(P1)		;GET ADDRESS OF NEXT UDB
	JRST	TD2ON2		;IGNORE IF ZERO
	HLRZ	T3,TKBUNI##(W)	;PICK UP DX20 NUMBER
	CAIN	T3,(P2)		;DONE THIS DX20 ALREADY?
	JRST	TD2ON2		;YES, DON'T DO IT AGAIN
	MOVE	P2,T3		;SAVE NEW DX20 NUMBER
	PUSHJ	P,CHEKOK	;IS IT A DX20 WHICH IS RUNNING?
	  JRST	UPOPJ##		;NO, CALL IT OFF-LINE
TD2ON2:	AOBJN	P1,TD2ON1	;LOOP FOR ALL UDB'S
IFN FTAUTC,<
	JUMPGE	P2,UPOPJ1##	;WIN IF ANY DRIVES WERE FOUND
	PUSH	P,P3		;NO DRIVES - NO MICROCODE WAS THERE
	SETO	P3,		;START AT 1ST DRIVE
	XCT	TKBDIS##(W)	;SAVE PREPERATION REGISTER
	PUSHJ	P,CHEKOK	;IS IT RUNNING?
	  JRST	TD2ON4		;NO, DON'T BOTHER TRYING TO START IT
	MOVEI	T2,CO.MBI	;YES, GET IT INTO A KNOWN STATE
	XCT	TD2COS##(W)
	MOVEI	T2,CO.MBE	;MASBUS ENABLE SO WE CAN TALK TO IT
	XCT	TD2COS##(W)
TD2ON3:	PUSHJ	P,TD2CFG	;FIND THE NEXT DRIVE
	JUMPL	P3,TD2ON4	;DONE IF NO MORE DRIVES
	HRRZ	T2,P3		;NEXT DRIVE NUMBER
	MOVEI	T1,.DTCOD	;TELL AUTCON ITS A DX20/TU7X
	PUSHJ	P,NEWTAP##	;INFORM THE WORLD THAT A NEW DRIVE APPEARED
	JRST	TD2ON3		;AND SEE IF NEXT DRIVE IS THERE
TD2ON4:	POP	P,P3
>
	JRST	UPOPJ1##	;RETURN SUCCESSS
;ROUTINE TO CHECK THAT THE DX20 IS ALIVE AND WELL
;CALL WITH:
;	W/KDB ADDRESS
;RETURN+1 IF NOT OK
;RETURN+2 IF OK
CHEKOK:	PUSHJ	P,CHKDTR	;IS IT REALLY A DX20?
	  POPJ	P,		;NO, ERROR RETURN
	MOVSI	T2,(.DXSTR)	;POINT AT STATUS REGISTER
	TAPOFF			;AVOID RACE WITH INTERRUPT RDREGX
	PUSHJ	P,RDREGX	;GO READ STATUS REGISTER
	TAPON			;TURN PI BACK ON
	TRNE	T2,SR.RUN	;MP RUNNING?
	AOS	(P)		;YES. TAKE GOOD RETURN
	POPJ	P,

;ROUTINE TO READ THE DRIVE TYPE REGISTER TO INSURE THAT THE KONTROLLER
;THAT WE ARE TALKING TO IS REALLY A DX20.
;CALL WITH:
;	W/KDB ADDRESS
;RETURN+1 IF NOT A DX20
;RETURN+2 IF IT IS A DX20

CHKDTR:	MOVSI	T2,(.DXDTR)	;POINT AT DRIVE TYPE REGISTER
	PUSHJ	P,RDREG		;READ IT
	ANDI	T2,DT.COD	;ISOLATE DRIVE TYPE
	CAIN	T2,.DTCOD	;IS IT A DX20?
	AOS	0(P)		;YES, GIVE SKIP RETURN
	POPJ	P,		;RETURN
	SUBTTL	CAUSE A SCHEDULE CYCLE


;HERE TO FORCE A SCHEDULE CYCLE.  WE SET A FLAG FOR LATER
;AND SET THE STOP BIT IN THE RH20 WHICH CAUSES AN INTERRUPT.
;AT INTERRUPT LEVEL, WE CHECK THE FLAG AND RETURN T1=-1 TO
;TAPSER TO FORCE A SCHEDULE CYCLE.
;CALL WITH:
;	W/KDB ADDRESS
;RETURN+1 ALWAYS

TD2SCH:	SETOM	TKBSCH(W)	;SET FLAG FOR SCHEDULE CYCLE
	PUSHJ	P,SETIVO	;SETUP INTERRUPT VECTOR ADDRESS
	MOVEI	T2,CO.STP	;GET "STOP TRANSFER" BIT
	XCT	TD2COS##(W)	;STOP THE RH20
	PUSHJ	P,CLRFLG	;CLEAR KDB FLAGS
	PJRST	REASPI		;REASSIGN PI AND RETURN


;ROUTINE TO ENABLE THE MASSBUS AND SETUP THE RH20
;INTERRUPT VECTOR ADDRESS
;CALL WITH:
;	W/KDB ADDRESS
;RETURN+1 ALWAYS

SETIVO:	MOVEI	T2,CO.MBE!CO.RAE ;GET MASSBUS ENABLE BIT
	XCT	TD2COS##(W)	;DO SO
	MOVEI	T3,TKBVIN##(W)	;SET UP ICWA+3
	HRLI	T3,(XPCW)

	MOVE	T2,TKBICP##(W)
	MOVEM	T3,3(T2)
	MOVE	T2,TKBIVI##(W)	;GET DATAO WORD TO SETUP INTERRUPT VECTOR
	XCT	TKBDOS##(W)	;WE GET INTERRUPTS AT 40+2N
	POPJ	P,		;RETURN
	SUBTTL	ASSORTED SMALL ROUTINES


;ROUTINE TO CLEAR ALL ERRORS, THE KDB FLAGS AND REASSIGN THE RH20
;PI.  CALL WITH:
;	W/KDB ADDRESS
;RETURN+1 ALWAYS

CLRALL:	PUSHJ	P,CLRFLG	;CLEAR KDB FLAGS
;;	PJRST	CLRERR		;FALL INTO CLRERR


;ROUTINE TO CLEAR THE ERROR BITS IN THE RH20 CONI WORD AND REASSIGN
;THE PI ASSIGNMENT.  DESTROYS T2.
;CALL WITH:
;	W/KDB ADDRESS
;RETURN+1 ALWAYS

CLRERR:	MOVEI	T2,CO.CLR	;GET BITS TO CLEAR ERRORS
	XCT	TD2COS##(W)	;CLEAR THEM
;;	PJRST	REASPI		;FALL INTO REASPI


;ROUTINE TO REASSIGN THE RH20 PI. DESTROYS T2.
;CALL WITH:
;	W/KDB ADDRESS
;RETURN+1 ALWAYS

REASPI:	MOVEI	T2,CO.AIE!CO.MBE!TAPCHN## ;GET BITS TO ENABLE INTERRUPTS
	XCT	TD2COS##(W)	;DO SO
	POPJ	P,		;RETURN


;ROUTINE TO CLEAR ALL KDB FLAGS.
;CALL WITH:
;	W/KDB ADDRESS
;RETURN+1 ALWAYS

CLRFLG:	HRRZS	TKBATN(W)	;CLEAR ALL BUT ATTENTION BITS
	SETZM	TKBASY(W)	;PLUS ASYNCHRONOUS STATUS
	SETZM	TKBFLG(W)	;AND OPERATION FLAGS
	POPJ	P,		;RETURN


;ROUTINE TO TELL THE MOUNTABLE DEVICE ALLOCATOR THAT A TAPE
;DRIVE JUST CAME ONLINE.  PRESERVES T1-T4.
;RETURN+1 ALWAYS

NOWONL:	PUSHJ	P,SAVT##	;SAVE T1-T4
	PJRST	TPMONL##	;TELL MDA AND RETURN
	SUBTTL	MICROPROCESSOR HANDLING ROUTINES


;ROUTINE TO CHECK THE VALIDITY OF THE MICROPROCESSOR CONTROL STORE.
;THIS INVOLVES CHECKING FOUR THINGS AS FOLLOWS:
;
;	1. CRAM LOCATION 7 MUST CONTAIN A COPY OF THE DRIVE TYPE REGISTER
;	2. CRAM LOCATION 10 MUST CONTAIN AN OCTAL 100 (.CRM10)
;	3. CRAM LOCATION 11 MUST CONTAIN THE MAGIC VALUE 042562 (.CRM11)
;	4. D7.IRP MUST NOT COME UP WHILE READING ANY OF THE ABOVE
;
;CALL WITH:
;	W/KDB ADDRESS, U/UDB ADDRESS
;RETURN+1 IF AN ERROR IS DETECTED
;RETURN+2 IF ALL OK

MPCHK:	MOVE	T2,[.DXDR1!D1.IRE!D1.PCE!D1.PCI!7] ;REGISTER TO WRITE+
				;  IR ENABLE+PC ENABLE+PC AUTO INCR+PC TO READ
	PUSHJ	P,WTREG		;WRITE THE REGISTER
	MOVSI	T2,(.DXDR0)	;POINT AT DIAGNOSTIC REGISTER 0
	PUSHJ	P,RDREG		;READ THE CONTENTS
	PUSH	P,T2		;SAVE FOR COMPARE
	MOVSI	T2,(.DXDTR)	;POINT AT DRIVE TYPE REGISTER
	PUSHJ	P,RDREG		;READ THAT
	POP	P,T3		;RESTORE CRAM LOCATION 7
	CAME	T2,T3		;HAVE TO BE THE SAME
	POPJ	P,		;ERROR IF NOT
	MOVSI	T2,(.DXDR7)	;POINT AT DIAGNOSTIC REGISTER 7
	PUSHJ	P,RDREG		;READ IT
	TRNE	T2,D7.IRP	;IR PARITY ERROR ON LAST READ?
	POPJ	P,		;YES, THAT'S AN ERROR
	MOVSI	T2,(.DXDR0)	;POINT AT DIAGNOSTIC REGISTER 0 AGAIN
	PUSHJ	P,RDREG		;READ CRAM LOC 10 (PC AUTO INCR SET)
	CAIE	T2,.CRM10	;MUST BE THIS VALUE
	POPJ	P,		;NOT, ERROR
	MOVSI	T2,(.DXDR7)	;POINT AT DIAGNOSTIC REGISTER 7
	PUSHJ	P,RDREG		;READ IT
	TRNE	T2,D7.IRP	;IR PARITY ERROR ON LAST READ?
	POPJ	P,		;YES, ERROR
	MOVSI	T2,(.DXDR0)	;POINT AT DIAGNOSTIC REGISTER 0 ONCE MORE
	PUSHJ	P,RDREG		;READ CRAM LOCATION 11
	CAIE	T2,.CRM11	;MUST BE THIS VALUE
	POPJ	P,		;NOT, ERROR
	MOVSI	T2,(.DXDR7)	;POINT AT DIAGNOSTIC REGISTER 7
	PUSHJ	P,RDREG		;READ IT
	TRNN	T2,D7.IRP	;IR PARITY ERROR ON LAST READ?
	AOS	(P)		;NO, GIVE SKIP RETURN
	POPJ	P,		;   AND RETURN
;ROUTINE TO START THE MICROPROCESSOR AT A SPECIFIED LOCATION
;CALL WITH:
;	W/KDB ADDRESS, U/UDB ADDRESS
;RETURN+1 ALWAYS

MPSTRT:	PUSHJ	P,MPRES		;RESET THE MICROPROCESSOR
	MOVE	T2,[.DXDR1!D1.IRE!D1.PCE!D1.PCI!.DXSAD] ;POINT TO REGISTER AND SET BITS
	PUSHJ	P,WTREG		;TELL MP ITS START ADDRESS
	MOVE	T2,[.DXMTR!MR.STR] ;SET START BIT IN MAINTENANCE REG
	PJRST	WTREG		;START IT AND RETURN


;ROUTINE TO RESET THE MICRO PROCESSOR
;CALL WITH:
;	W/KDB ADDRESS, U/UDB ADDRESS
;RETURN+1 ALWAYS

MPRES:	MOVE	T2,[.DXMTR!MR.RES] ;SET RESET BIT IN MAINT REG
	PJRST	WTREG		;WRITE REGISTER AND RETURN


;ROUTINE TO READ THE DX20 MICROCODE VERSION NUMBER FROM CRAM
;LOCATION 0.
;CALL WITH:
;	W/KDB ADDRESS,  U/UDB ADDRESS
;RETURN+1 ALWAYS WITH:
;	T2/MICROCODE VERSION NUMBER, T3/DX20 ADDRESS

MPVER:	MOVE	T2,[.DXDR1!D1.IRE!D1.PCE!0] ;SET TO READ CRAM LOC 0
	PUSHJ	P,WTREG		;TELL THE DX20
	MOVSI	T2,(.DXDR0)	;ANSWER APPEARS HERE
	PJRST	RDREG		;READ VERSION NUMBER AND RETURN


;ROUTINE TO SEE IF THE MICROPROCESSOR IS STILL RUNNING?
;CALL WITH:
;	W/KDB ADDRESS,  U/UDB ADDRESS
;RETURN+1 IF NOT RUNNING
;RETURN+2 IF RUNNING

MPRUN:	HLRZ	T3,TKBUNI##(W)	;GET DX20 NUMBER
MPRUNX:	MOVSI	T2,(.DXSTR)	;POINT AT STATUS REGISTER
	PUSHJ	P,RDREGX	;READ IT
	TRNE	T2,SR.RUN	;IS IT RUNNING?
	AOS	0(P)		;YES, GIVE SKIP RETURN
	POPJ	P,		;RETURN
;ROUTINE TO MAKE AN ERROR ENTRY FOR A DX20 THAT HAS HALTED.
;CALL WITH:
;	W/KDB ADDRESS,  T3/DX20 NUMBER
;RETURN+1 ALWAYS
;PRESERVES U,F,T3

LOGUPE:	PUSHJ	P,SAVE1##	;SAVE P1
	PUSH	P,U		;  AND U
	PUSH	P,F		;  AND F
	PUSH	P,T3		;  AND T3
	MOVEI	T2,(T3)		;COPY DX20 NUMBER TO T2
	LSH	T2,3		;CONSTRUCT OFFSET TO DRIVE 0 ON DX20
	HLRE	T1,TKBIUN##(W)	;GET -VE COUNT OF DRIVES ON THIS KDB
	MOVMS	T1		;MAKE IT POSITIVE
	CAIGE	T2,(T1)		;DOES SUCH A DRIVE EXIST?
	PUSHJ	P,SETUDB##	;YES, FIND IT'S UDB
	  JRST	LOGUP2		;NONE???
	MOVSI	T2,(1B1)	;FLAG THIS A HARD
	IORM	T2,TUBTRY##(U)	;  ERROR FOR DAEMON
	MOVEI	P1,0		;SET NO FLAGS
	PUSHJ	P,RDAREG	;READ INITIAL AND FINAL REGISTERS
	SKIPE	F,TUBCUR##(U)	;ANY DDB IN USE?
	JRST	LOGUP1		;YES, USE IT
	SKIPN	F,TUBDDB##(U)	;NO, TRY FOR UNIT 0 DDB
	MOVEI	F,MT0DDB##	;CAN'T FIND ONE, USE SOMETHING
LOGUP1:	MOVEI	T1,.ERDXE	;DX20 DEVICE ERROR
	HRL	T1,F		;PUT DDB ADDRESS IN LH OF F
	PUSHJ	P,DAEERR##	;LOG THIS ERROR
LOGUP2:	POP	P,T3		;RESTORE T3
	POP	P,F		;  AND F
	JRST	UPOPJ##		;  AND U AND RETURN
	SUBTTL	ROUTINES TO SAVE ERROR INFORMATION IN TUBFEP


;ROUTINE TO READ THE ERROR INFORMATION INTO THE UDB IF AN ERROR
;WAS DETECTED OR AS THE RESULT OF A RECOVERED ERROR.
;CALL WITH:
;	U/UDB ADDRESS,  W/KDB ADDRESS
;RETURN+1 ALWAYS

TSTERR:	SKIPE	TUBERR##(U)	;IN ERROR RECOVERY?
	PJRST	RDFREG		;YES, READ FINAL REGISTERS
	MOVEI	T2,TUCSNS##	;GET "REQUEST FORCED SENSE" BIT
	TLZN	P1,(TB.ERR)	;ERROR SEEN ON THIS OPERATION?
	TDNE	T2,TUBCNF##(U)	; OR USER FORCE A SENSE?
	PJRST	RDIREG		;YES, READ INITIAL REGISTERS
	POPJ	P,		;NO, JUST RETURN


;ROUTINE TO READ BOTH THE INITIAL AND FINAL "REGISTERS" INTO THE
;UDB.
;CALL WITH:
;	U/UDB ADDRESS,  W/KDB ADDRESS
;	P1/IOFTBL ENTRY,,DEVICE STATUS BYTE
;RETURN+1 ALWAYS

RDAREG:	PUSH	P,TUBERR##(U)	;SAVE VALUE OF TUBERR
	SETZM	TUBERR##(U)	;FORCE READ OF INITIAL REGISTERS
	PUSHJ	P,RDIREG	;READ "INITIAL" REGISTERS
	SETOM	TUBERR##(U)	;FORCE READ OF FINAL REGISTERS
	PUSHJ	P,RDFREG	;READ "FINAL" REGISTERS
	POP	P,TUBERR##(U)	;RESTORE VALUE OF TUBERR
	POPJ	P,		;RETURN
;ROUTINE TO SAVE INFORMATION IN THE UDB AT THE TIME OF THE ERROR.
;CALL WITH:
;	U/UDB ADDRESS,  W/KDB ADDRESS,
;	P1/IOFTBL ENTRY,,DEVICE STATUS BYTE
;RETURN+1 ALWAYS

RDIREG:	XCT	TKBCIS##(W)	;GET ERROR CONI
	MOVEM	T2,TD2FST##+.TFCNI(U) ;SAVE IN UDB
	MOVSI	T2,(.DIPTC)	;POINT TO PTCR
	PUSHJ	P,RDREG		;READ IT
	MOVEM	T2,TD2FST##+.TFD1I(U) ;SAVE IT
	MOVSI	T2,(.DIPBA)	;POINT TO PBAR
	PUSHJ	P,RDREG		;READ IT
	MOVEM	T2,TD2FST##+.TFD2I(U) ;SAVE IT
	HRRZ	T2,TKBICP##(W)	;GET LOGOUT AREA ADDRESS
	HRLI	T2,-3		;MAKE IT AN AOBJN POINTER
	MOVEI	T3,TD2FST##+.TFCS0(U) ;WHERE TO PUT THEM
RDIRE1:	MOVE	T4,(T2)		;GET NEXT WORD OF LOGOUT AREA
	MOVEM	T4,(T3)		;STORE IN UDB
	ADDI	T3,1		;BUMP OUTPUT POINTER
	AOBJN	T2,RDIRE1	;LOOP FOR ALL
	HRRZ	T2,TRBXCW(T1)	;GET ADDRESS OF CHANNEL COMMAND LIST
	TLNN	P1,(TB.DAT)	;THIS A DATA OPERATION?
	TDZA	T3,T3		;NO, NO COMMAND LIST
	MOVE	T3,(T2)		;GET FIRST CCW
	MOVEM	T3,TD2FST##+.TFCC1(U) ;SAVE IN UDB
	TLNE	P1,(TB.DAT)	;DATA OP?
	MOVE	T3,1(T2)	;YES, GET NEXT CCW
	MOVEM	T3,TD2FST##+.TFCC2(U) ;SAVE IN UDB
	HRRZ	T2,TKBCDB(W)	;GET ADDRESS OF CHN DB
	MOVE	T3,.CHMPE(T2)	;GET NUMBER OF MEM PAR ERRORS
	MOVEM	T3,TD2FST##+.TFMPE(U) ;SAVE IN UDB
	MOVE	T3,.CHNXM(T2)	;GET NUMBER OF NXM'S
	MOVEM	T3,TD2FST##+.TFNXM(U) ;SAVE IN UDB
	PUSHJ	P,REDMBR	;READ INITIAL MASSBUS REGISTERS
;;	PJRST	REDD2R		;READ DX20 REGISTERS AND RETURN
;ROUTINE TO READ THE DX20 REGISTERS INTO THE UDB WHEN AN ERROR IS
;DETECTED.
;CALL WITH:
;	U/UDB ADDRESS,  W/KDB ADDRESS
;RETURN+1 ALWAYS

REDD2R:	PUSHJ	P,MPRUN		;IS MICROPROCESSOR RUNNING?
	  JRST	REDD24		;NO, ZERO COUNT AND RETURN
	PUSHJ	P,SAVE2##	;SAVE P1-P2
	MOVSI	P1,-.TD2ES	;BUILD AOBJN POINTER FOR NUMBER OF REGS
REDD21:	MOVEI	T2,(P1)		;GET EST INDEX THAT WE WANT
	PUSHJ	P,SETEST	;GET THE DX20 TO LOAD THE VALUES
	  JRST	REDD23		;GO IF WE TIMED OUT
	PUSHJ	P,REDES3	;READ THE INFORMATION, RETURN IN T4
	MOVEI	T2,TD2FST##+.TFD2R(U) ;GET BASE OF REGISTER BLOCK
	ADDI	T2,(P1)		;OFFSET TO THIS REGISTER
	MOVEM	T4,(T2)		;STORE IN CORRECT PLACE
	AOBJN	P1,REDD21	;LOOP FOR ALL REGISTERS
REDD23:	MOVSS	P1		;PUT NUMBER OF REGISTERS IN LH
	HRRI	P1,.TFD2R-.TFDVL ;OFFSET TO FIRST IN RH
	TLNN	P1,-1		;IF COUNT IS ZERO,
REDD24:	MOVEI	P1,0		;ZERO THE WHOLE WORD
	MOVEM	P1,TD2FST##+.TFDVL(U) ;STORE IN UDB
	POPJ	P,		;RETURN
;ROUTINE TO SAVE INFORMATION IN THE UDB ON SUBSEQUENT ERRORS DURING
;ERROR RECOVERY OR WHEN THE ERROR IS RECOVERED.
;CALL WITH:
;	U/UDB ADDRESS,  W/KDB ADDRESS
;RETURN+1 ALWAYS

RDFREG:	XCT	TKBCIS##(W)	;GET FINAL CONI
	MOVEM	T2,TD2FST##+.TFCIF(U) ;SAVE IN UDB
	MOVSI	T2,(.DIPTC)	;POINT AT PTCR
	PUSHJ	P,RDREG		;READ IT
	MOVEM	T2,TD2FST##+.TFD1F(U) ;SAVE IN UDB
	MOVSI	T2,(.DIPBA)	;POINT AT PBAR
	PUSHJ	P,RDREG		;READ IT
	MOVEM	T2,TD2FST##+.TFD2F(U) ;SAVE IN UDB
;;	PJRST	REDMBR		;READ FINAL MASSBUS REGISTERS AND RETURN


;ROUTINE TO READ THE MASSBUS REGISTERS SPECIFIED BY THE BIT TABLE
;MBRTBL AND STORE THEM IN THE UDB.
;CALL WITH:
;	U/UDB ADDRESS,  W/KDB ADDRESS
;RETURN+1 ALWAYS

REDMBR:	PUSHJ	P,SAVE2##	;SAVE P1-P2
	MOVE	P1,[.TD2MR,,.TFMBX-.TFMBR] ;# OF MBR,,OFFSET TO FIRST
	MOVEM	P1,TD2FST##+.TFMBR(U) ;SAVE IN UDB
	MOVEI	P1,TD2FST##+.TFMBX(U) ;POINT TO PLACE TO STORE REGS
	MOVE	P2,[MBRTBL]	;GET BIT TABLE OF REGISTERS TO SAVE
REDMB1:	JUMPGE	P2,REDMB2	;IF SIGN BIT NOT SET, DON'T SAVE THIS ONE
	HLLZ	T2,P1		;GET REGISTER ADDRESS
	CAMN	T2,[.DXDR0]	;READING THE IR?
	TDZA	T2,T2		;YES, READ IT LATER
	PUSHJ	P,RDREG		;READ THE REGISTER
	SKIPN	TUBERR##(U)	;IN ERROR RECOVERY?
	HRRZM	T2,(P1)		;NO, SAVE INITIAL VALUE
	SKIPE	TUBERR##(U)	;OTHERWISE
	HRLM	T2,(P1)		;SAVE FINAL VALUE
	HRRI	P1,1(P1)	;BUMP BLOCK POINTER BY 1
REDMB2:	ADD	P1,[1B5]	;PLUS REGISTER ADDRESS BY 1
	LSH	P2,1		;SHIFT BIT TABLE BY 1
	JUMPN	P2,REDMB1	;IF MORE TO READ, LOOP
;;	PJRST	REDMIR		;FALL INTO REDMIR
;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 WITH:
;	W/KDB ADDRESS,	U/UDB ADDRESS
;RETURN+1 ALWAYS

REDMIR:	DMOVE	T2,TD2FST##+.TFM00(U) ;GET CONTROL AND STATUS REGS
	SKIPN	TUBERR##(U)	;IN ERROR RECOVERY?
	JRST	REDMI1		;NO, CONTINUE
	MOVSS	T2		;YES, BITS ARE IN THE
	MOVSS	T3		;  LEFT HALF OF THE WORD
REDMI1:	TRNN	T2,CR.CGO	;IS GO STILL UP?
	TRNE	T3,SR.RUN	;NO, IS THE UCODE STILL RUNNING?
	POPJ	P,		;YES, DON'T READ THE REGISTER
	MOVSI	T2,(.DXDR1)	;SETUP TO READ THE PC REGISTER
	PUSHJ	P,RDREG		;DO SO
	TRZ	T2,D1.IRE	;TURN OFF IR ENABLE
	HRLI	T2,(.DXDR1)	;PUT THE REGISTER NUMBER BACK
	PUSHJ	P,WTREG		;WRITE OFF IR ENABLE
	MOVSI	T2,(.DXDR0)	;POINT TO IR REGISTER
	PUSHJ	P,RDREG		;READ IT
	SKIPN	TUBERR##(U)	;IN ERROR RECOVERY?
	HRRZM	T2,TD2FST##+.TFM30(U) ;NO, SAVE INITIAL VALUE
	SKIPE	TUBERR##(U)	;OTHERWISE
	HRLM	T2,TD2FST##+.TFM30(U) ;SAVE FINAL VALUE
	POPJ	P,		;RETURN
	SUBTTL	ROUTINES TO ACCESS MASSBUS REGISTERS


;ROUTINE TO READ THE CONTENTS OF A MASSBUS REGISTER.  ENTER AT
;RDREGX IF DX20 NUMBER IS ALREADY SETUP IN T3.
;CALL WITH:
;	T2/REGISTER TO READ (IN DATAO FORMAT),
;	T3/DX20 NUMBER IF ENTRY AT RDREGX
;	W/KDB ADDRESS, U/UDB ADDRESS
;RETURN+1 ALWAYS WITH C(REGISTER) IN T2

RDREG:	HLRZ	T3,TKBUNI##(W)	 ;GET DX20 NUMBER FOR DS
RDREGX:	TLO	T2,<(DO.DRE)>(T3) ;SET DS AND DISABLE RAE
	XCT	TKBDOS##(W)	;TELL MBC WHICH REGISTER WE WANT TO READ
	STALL			;GIVE IT TIME TO THINK ABOUT IT
	XCT	TKBDIS##(W)	;READ THE REGISTER
	ANDI	T2,177777	;RETURN ONLY 16 BITS
	POPJ	P,		;  AND RETURN


;ROUTINE TO WRITE A MASSBUS REGISTER.  ENTER AT WTREGX IF THE DX20
;NUMBER IS ALREADY SETUP IN T3.
;CALL WITH:
;	T2/CONTENTS TO SEND TO REGISTER (IN DATAO FORMAT),
;	T3/DX20 NUMBER IF ENTRY AT WTREGX,
;	W/KDB ADDRESS, U/UDB ADDRESS
;RETURN+1 ALWAYS

WTREG:	HLRZ	T3,TKBUNI##(W)	 ;GET DX20 NUMBER FOR DS
WTREGX:	TLO	T2,<(DO.LDR!DO.DRE)>(T3) ;TELL MBC TO WRITE REG AND DISABLE RAE
	XCT	TKBDOS##(W)	;WRITE THE REGISTER
	POPJ	P,		;AND RETURN
	SUBTTL	TABLES TO CONTROL I/O


;THE FOLLOWING TABLE CONVERTS FROM THE SOFTWARE DATA MODES TO
;THOSE NEEDED BY THE HARDWARE. -1 IS ILLEGAL.

MODTBL:	EXP	-1		;SOFTWARE MODE 0 IS ILLEGAL
	EXP	1B<POS(G1.DTM)>	;CORE DUMP
	EXP	2B<POS(G1.DTM)>	;INDUSTRY COMPATIBLE BYTE MODE
	EXP	3B<POS(G1.DTM)>	;SIXBIT
	EXP	4B<POS(G1.DTM)>	;ASCII
	EXP	3B<POS(G1.DTM)>	;7 TRACK CORE DUMP (SIXBIT)


;THE FOLLOWING TWO TABLES CONVERT FROM THE SOFTWARE DENSITY
;SETTINGS TO THOSE NEEDED BY THE HARDWARE.  FOR THE 7 TRACK
;TABLE, EACH ENTRY CONSISTS OF TWO WORDS-ONE FOR EACH PARITY
;SETTING.

DEN7TB==.-<RB.D2*2>	;MAKE TABLE START AT CORRECT OFFSET
	EXP	1B<POS(G1.DVM)>	;7 TRACK, 200 BPI, ODD PARITY
	EXP	5B<POS(G1.DVM)>	;7 TRACK, 200 BPI, EVEN PARITY
	EXP	2B<POS(G1.DVM)>	;7 TRACK, 556 BPI, ODD PARITY
	EXP	6B<POS(G1.DVM)>	;7 TRACK, 556 BPI, EVEN PARITY
	EXP	3B<POS(G1.DVM)>	;7 TRACK, 800 BPI, ODD PARITY
	EXP	7B<POS(G1.DVM)>	;7 TRACK, 800 BPI, EVEN PARITY

DEN9TB==.-RB.D8		;MAKE TABLE START AT CORRECT OFFSET
	EXP	13B<POS(G1.DVM)>	;9 TRACK, 800 BPI
	EXP	14B<POS(G1.DVM)>	;9 TRACK, 1600 BPI
	EXP	15B<POS(G1.DVM)>	;9 TRACK, 6250 BPI
;THE FOLLOWING TABLE CONVERTS FROM THE SOFTWARE FUNCTION IN THE IORB
;TO THAT REQUIRED BY THE HARDWARE.  IT ALSO HOLDS FLAG BITS FOR
;THE FUNCTION.  NOTE WELL THAT THE SPACE FILE FUNCTIONS ARE MARKED
;AS ILLEGAL SINCE TOPS10 DOES SPACE FILE OPERATIONS VIA MULTIPLE
;SPACE RECORD OPERATIONS.  SEE ALSO SFFINT AND SBFINT.
;
;IT IS ALSO IMPORTANT TO NOTE THE PLACEMENT OF THE FLAG BITS WITHIN
;THE FUNCTION WORD.  FLAG BITS THAT ARE ONLY USED DURING THE START
;OPERATION SEQUENCE (TD2SIO AND FRIENDS) ARE PLACED IN THE RIGHT
;HALF OF THE WORD WITH THE HARDWARE FUNCTION CODE.  FLAG BITS THAT
;MUST BE PASSED TO THE INTERRUPT LEVEL ROUTINES MUST BE PLACED IN THE
;LEFT HALF OF THE WORD BECAUSE ONLY THE LEFT HALF IS PRESERVED AT
;INTERRUPT LEVEL.

	TB.ILF==1B0	;ILLEGAL FUNCTION  (MUST BE SIGN BIT)
	TB.DAT==1B1	;TALK TO RH20 REG INSTEAD OF DX20
	TB.RED==1B2	;OPERATION PERFORMS A READ
;1B7 FORMERLY TB.SNS, NOT NEEDED WITH VERSION 10 UCODE
	TB.REV==1B8	;OPERATION MOVES TAPE BACKWARDS
	TB.ERR==1B9	;OPERATION DETECTED AN ERROR
;1B10 FORMERLY TB.SIO, NOT NEEDED WITH VERSION 10 UCODE
	TB.DON==1B11	;BEEN THROUGH DONE BEFORE GOING TO CHKATN
	TB.FSN==1B12	;FORCED SENSE DONE ON THIS COMMAND
	TB.SFC==37B17	;SOFTWARE FUNCTION CODE, I.E. INDEX IN TABLE

	TB.ZFC==1B18	;USE ZERO IN FRAME COUNT REGISTER
	TB.OFC==1B19	;USE -1 IN FRAME COUNT REGISTER
	TB.REW==1B20	;FUNCTION DOES A REWIND
	TB.MS7==1B21	;MODE SET ON 7 TRACK NEEDED
	TB.MS9==1B22	;MODE SET ON 9 TRACK NEEDED
	TB.FCN==77B<POS(CR.CGO)> ;HARDWARE FUNCTION CODE

	DEFINE	FCN (CODE,FLAGS), <
	  EXP <FLAGS>+<.-IOFTBL>B<POS(TB.SFC)>+<CODE>B<POS(TB.FCN)>
	>

IOFTBL:	FCN(0,TB.ILF)				;0 - ILLEGAL
	FCN(CR.RDF,TB.DAT+TB.RED+TB.MS7)	;1 - READ FORWARD
	FCN(CR.WTF,TB.DAT+TB.MS7+TB.MS9) 	;2 - WRITE FORWARD
	FCN(CR.RDR,TB.DAT+TB.RED+TB.MS7+TB.REV)	;3 - READ REVERSE
	FCN(CR.SFR,TB.MS7)			;4 - SPACE FORWARD RECORD
	FCN(CR.SBR,TB.MS7+TB.REV)		;5 - SPACE BACKWARD RECORD
	FCN(CR.SFF,TB.ILF+TB.MS7)		;6 - SPACE FORWARD FILE
	FCN(CR.SBF,TB.ILF+TB.MS7+TB.REV)	;7 - SPACE BACKWARD FILE
	FCN(CR.ERA,TB.MS7+TB.MS9) 		;10 - ERASE GAP
	FCN(CR.DSE,TB.ZFC)			;11 - DATA SECURITY ERASE
	FCN(CR.REW,TB.ZFC+TB.REW)		;12 - REWIND
	FCN(CR.UNL,TB.ZFC+TB.REW)		;13 - REWIND AND UNLOAD
	FCN(CR.WTM,TB.MS7+TB.MS9)		;14 - WRITE TAPE MARK
	FCN(CR.NOP,TB.ILF)			;15 - WAIT FOR KONTROLLER IDLE
	FCN(CR.RDF,TB.DAT+TB.RED+TB.MS7)	;16 - CORRECTION READ
	FCN(CR.RDF,TB.DAT+TB.RED+TB.MS7)	;17 - READ LOW THRESHOLD
;THE FOLLOWING TABLE GIVES THE ADDRESSES OF THE SPECIFIC INTERRUPT
;HANDLER FOR EACH FUNCTION.

INTTBL:	EXP	TAPIFI##	;0 - ILLEGAL
	EXP	RDFINT		;1 - READ FORWARD
	EXP	WRTINT		;2 - WRITE FORWARD
	EXP	RDBINT		;3 - READ REVERSE
	EXP	SFRINT		;4 - SPACE FORWARD RECORD
	EXP	SBRINT		;5 - SPACE BACKWARD RECORD
	EXP	SFFINT		;6 - SPACE FORWARD FILE
	EXP	SBFINT		;7 - SPACE BACKWARD FILE
	EXP	ERGINT		;10 - ERASE GAP
	EXP	DSEINT		;11 - DATA SECURITY ERASE
	EXP	REWINT		;12 - REWIND
	EXP	UNLINT		;13 - REWIND AND UNLOAD
	EXP	WTMINT		;14- WRITE TAPE MARK
	EXP	DONE		;15 - WAIT FOR KONTROLLER IDLE (USED AS A NOOP)
	EXP	RDFINT		;16 - CORRECTION READ
	EXP	RDFINT		;17 - READ LOW THRESHOLD
MAXINT==.-INTTBL-1		;HIGHEST LEGAL FUNCTION
SUBTTL	LOAD MICROCODE


; MAGIC NUMBER TRANSLATION TABLE
TD2MAG::XWD	.CRM10,000010	;LOCATION 10
	XWD	.CRM11,000011	;LOCATION 11
	EXP	-1		;TERMINATE TABLE


; ENABLE/DISABLE MICROCODE LOADING
TD2EDL:	SE1ENT			;ENTER SECTION ONE
	HRRZS	W		;REMOVE JUNK IN LH
	MOVE	T2,T1		;COPY BIT
	XMOVEI	T1,TD2ULB##(W)	;POINT TO UCODE LOADER BLOCK IN KDB
	PJRST	BTUEDL##	;ENABLE OR DISABLE


; LOAD MICROCODE
TD2LOD:	SE1ENT			;ENTER SECTION ONE
	LDB	T1,[POINT 7,TD2COS##(W),9] ;GET RH20 DEVICE CODE
	LSH	T1,2+22		;MAKE IT FULL 9 BIT DEVICE CODE IN THE LH
	HLR	T1,TKBUNI##(W)	;GET THE DX20 NUMBER
	MOVEM	T1,TD2ULB##+.ULDEV(W) ;SAVE IN LOADER BLOCK
	XMOVEI	T1,TD2ULB##(W)	;POINT TO MICROCODE LOADER BLOCK
	PUSHJ	P,DXLOAD##	;LOAD AND VERIFY MICROCODE
	  POPJ	P,		;FAILED
	PUSHJ	P,TD2INI	;INITIALIZE
	JRST	CPOPJ1##	;AND RETURN
SUBTTL	END

	END