Google
 

Trailing-Edge - PDP-10 Archives - bb-bt99q-bb - td2kon.x23
There is 1 other file named td2kon.x23 in the archive. Click here to see a list.
TITLE	TD2KON - DX20/TX03 DEVICE DEPENDENT CODE FOR TAPSER V126
SUBTTL	G.M. UHLER/GMU/DPM	23-MAY-89

	SEARCH	F,S,DEVPRM
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
;  OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1978,1979,1980,1982,1984,1986,1988.
;ALL RIGHTS RESERVED.

.CPYRT<1978,1988>


XP VTD2KN,126	;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
;TD2KON TUBIEP/TUBFEP BLOCK SIZES

	.TD2MC==25			;MISCELLANEOUS VALUES
	.TD2ES==24			;DX20 EXTENDED STATUS REGISTERS
	.TD2MR==27			;MASSBUS REGISTERS
	TD2ELN==.TD2MC+.TD2ES+.TD2MR	;SIZE OF FEP TABLE

	TD2DMX==20			;MAXIMUM DRIVES PER KONTROLLER
	TD2HDN==TD2DMX-1		;HIGHEST DRIVE NUMBER ON KONTROLLER

;DRIVER CHARARCTERISTICS
;	TD2	= TD2CNF
;	MTA	= MAGTAPE
;	0	= MAXIMUM DEVICES IN SYSTEM
;	K.DX2	= KONTROLLER TYPE
;	TD2DMX	= MAXIMUM DRIVES PER KONTROLLER
;	TD2HDN	= HIGHEST DRIVE NUMBER ON KONTROLLER
;	MDSEC0	= SECTION FOR KDB/UDB
;	MDSEC0	= SECTION FOR DDB
DRVCHR	(TD2,MTA,0,K.DX2,TD2DMX,TD2HDN,MDSEC0,MDSEC0,<DR.XAD!DR.MCD!DR.DPU!DR.GCC!DR.DDN>)


	.ORG	TKBUDB		;START OF TX02 SPECIFIC DATA
TD2UTB:! BLOCK	TD2DMX		;TABLE OF POINTERS TO UDBS
TD2ULB:! BLOCK	.ULLEN		;MICROCODE LOADER BLOCK
TD2SUN:! BLOCK	1		;NON-EXISTANT DRIVE BEING SENSED
TD2IUM:! BLOCK	TD2DMW		;IGNORE DRIVE MASK
TD2NUM:! BLOCK	TD2DMW		;NEW DRIVE MASK
TD2KLN:!			;LENGTH OF KDB
	.ORG

	 .ORG	TUBLEN
TD2DID:!BLOCK	1		;DEVICE IDENTIFIER FOR ERROR LOGGING
TD2IST:!BLOCK	1		;INITIAL ERROR POINTER (NOT USED)
TD2FST:!BLOCK	TD2ELN		;LAST ERROR FINAL STATUS
TD2ULN:!			;LENGTH OF UDB
	 .ORG


TD2KDB:	KDBBEG	(TD2,TD2KLN)
	SETWRD	(KDBNAM,<SIXBIT/MT/>)	;KONTROLLER NAME
	SETWRD	(KDBIUN,<TKBUDB>)	;INITIAL POINTER TO UDBS
	SETWRD	(KDBCUN,<TKBUDB>)	;CURRENT POINTER TO UDBS
	SETWRD	(KDBIUM,<TD2IUM>)	;OFFSET TO IGNORE UNIT MASK
	SETWRD	(KDBNUM,<TD2NUM>)	;OFFSET TO NEW UNIT MASK
	SETWRD	(KDBSTS,<INSVL.(1,KD.MPT)>) ;INITIALLY ONE PATH
IFN FTMP,<SETWRD (TKBFCT,<TKBICT##>)>	;FAIRNESS COUNTER FOR QUEUED I/O
	KDBEND


TD2UDB:	UDBBEG	(TD2,TD2ULN)
	SETWRD	(UDBNAM,<SIXBIT/MT/>)	;DRIVE NAME
	SETWRD	(TUBIEP,<-1,,TD2IST>)	;INITIAL ERROR POINTER
	SETWRD	(TUBFEP,<-TD2ELN,,TD2FST>) ;FINAL ERROR POINTER
	UDBEND

EQUATE	(LOCAL,CPOPJ##,<TD2CMD,TD2IDL>)

TD2ICD==TAPICD##		;PROTOTYPE INTERRUPT CODE ADDRESS
TD2ICL==TAPICL##		;PROTOTYPE INTERRUPT CODE ADDRESS
TD2INT==TAPINT##		;INTERRUPT SERVICE

TD2DSP:	DRVDSP	(TD2,TAPCHN##,TDVDDB##,TDVLEN##,TPMDIA##)
	TPK	(TD2,NO,16K)	;SERVICE DEPENDENT DISPATCH

TD2CKT:	EXP	K.TX1,K.DX2,K.TS1,0 ;COMPATIBLE KONTROLLER TABLE

TD2NBF:	TPNBF	(RW,RU)		;NON-BLOCKING FUNCTION MASK

;PROTOTYPE MICROCODE LOADER BLOCK
TD2ULP:	 EXP	.BTTX2##		;MICROCODE INDEX
	 XWD	000,0			;DEVICE CODE,,MASSBUS UNIT NUMBER
	 SIXBIT	/TX02/			;INTERFACE NAME
	 SIXBIT	/DX20/			;CHANNEL NAME
	 EXP	TD2MVR			;MINIMUM MICROCODE VERSION
	 EXP	0			;DATE/TIME OF LOAD SUCCESS OR FAILURE
	 EXP	0			;MICROCODE VERSION
	 EXP	TD2MAG			;POINTER TO MAGIC TABLE
	 EXP	0			;MICROCODE LENGTH
	 EXP	0			;MICROCODE ADDRESS
	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
		  .SB00==0	;EST INDEX TO SENSE BYTES  0 -  3
		  .SB06==1	;EST INDEX TO SENSE BYTES  4 -  7
		  .SB08==2	;EST INDEX TO SENSE BYTES  8 - 11
		  .SB12==3	;EST INDEX TO SENSE BYTES 12 - 15
		  .SB16==4	;EST INDEX TO SENSE BYTES 16 - 19
		  .SB20==5	;EST INDEX TO SENSE BYTES 20 - 23

	.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 XFER
				;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
	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 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	AUTO CONFIGURATION

TD2CFG:	CAIL	T1,FSTICD/4	;AN RH20?
	CAILE	T1,LSTICD/4	;...
	JRST	CPOPJ1##	;WRONG DRIVER
	TLNE	T2,(CI.PPT)	;IPA CHANNEL?
	JRST	CPOPJ1##	;YES
	PUSHJ	P,SAVE2##	;SAVE P1-2
	SETZ	P1,		;MASSBUS UNIT NUMBER 0, DRIVE 0

TD2CF1:	PUSHJ	P,TD2UNI	;AUTOCONFIGURE A SINGLE MASSBUS UNIT
	HLLOS	P1		;RESET DRIVE NUMBER
	AOBJN	P1,.+1		;ADVANCE TO NEXT MASSBUS UNIT
	TLNN	P1,10		;CHECKED ALL UNITS?
	JRST	TD2CF1		;LOOP BACK FOR ANOTHER
	JRST	CPOPJ1##	;TRY ANOTHER DEVICE ON SAME CHANNEL
;AUTOCONFIGURE A SINGLE MASSBUS UNIT
TD2UNI:	PUSHJ	P,RDDTR##	;READ DRIVE TYPE REGISTER
	CAIE	T2,TY.DXA	;IS IT A DX20/TAPE?
	POPJ	P,		;NO--GIVE UP
	MOVSI	T1,CP.RH2	;RH20 CHANNEL
	PUSHJ	P,AUTCHN##	;BUILD A CHANNEL DATA BLOCK
	  POPJ	P,		;NO CORE
	XMOVEI	T1,TD2MDT##	;POINT TO MONGEN'ED DEVICE TABLE
	SETZ	T2,		;THE DEFAULT IS IMPLICIT (RH20 TEST)
	HLLO	T3,P1		;MASSBUSS UNIT,,NO DRIVE INFORMATION
	MOVEI	T4,MD.KON	;SEARCH FOR A KONTROLLER DEFINITION
	PUSHJ	P,AUTMDT##	;SEE IF WE HAVE ANY DATA
	  SETZ	T1,		;NO DATA IF NO SPECIAL ENTRY
	TRNN	T1,-1		;ANY MAX. UNIT INFO?
	HRRI	T1,-1		;NO, JUST TRUST THE TX
	MOVE	P2,T1		;SAVE THE DATA WORD
	HLRZ	T1,P1		;GET MASSBUS UNIT NUMBER
	PUSHJ	P,AUTKDB##	;BUILD A KDB
	  POPJ	P,		;GIVE UP IF NO CORE
	PUSHJ	P,TAPCSA##	;SET UP CSO CONI ADDRESS
	MOVEI	T1,CO.MBE	;GET BIT TO ENABLE THE MASSBUS
	XCT	KDBCNO(W)	;DO SO
	PUSHJ	P,MPRES		;RESET MICROPROCESSOR
	PUSHJ	P,TD2LOD	;LOAD THE MICROCODE
	  POPJ	P,		;GIVE UP
	SETOM	TD2SUN(W)	;NOT SENSING NON-EXISTANT UNITS
	MOVNI	P3,1		;INIT DRIVE NUMBER

TD2UN2:	PUSHJ	P,TD2DRV	;AUTOCONFIGURE A SINGLE DRIVE
	  JFCL			;IGNORE ERRORS
	HRRZ	T1,P1		;GET DRIVE NUMBER
	CAIGE	T1,TD2DMX-1	;DONE ALL DRIVES?
	AOJA	P1,TD2UN2	;LOOP BACK FOR MORE
	POPJ	P,		;ALL DONE
;AUTOCONFIGURE A SINGLE DRIVE
TD2DRV:	PUSHJ	P,TD2DCK	;CHECK FOR DRIVE EXISTANCE
	  JRST	TD2DR5		;NOT THERE
	MOVEI	T2,.SB12	;SENSE BYTE 12
	PUSHJ	P,SETEST	;SET UP READ
	  JRST	TD2DR5		;SHOULDN'T FAIL
	PUSHJ	P,REDEST	;READ SENSE BYTES 12 - 15
	PUSH	P,T4		;SAVE RESULTS
	MOVEI	T2,.SB16	;SENSE BYTE 16
	PUSHJ	P,SETEST	;SET UP READ
	  JRST	TD2DR4		;SHOULDN'T FAIL
	PUSHJ	P,REDEST	;READ SENSE BYTES 16 - 19

	MOVE	T1,(P)		;COPY SENSE BYTES 12-15
	TLZ	T1,777600	;ISOLATE BYTE 13 (HIGH BYTE OF TX UNIT S/N)
	LSH	T1,-14		;ISOLATE BYTE 14 (LOW BYTE OF TX UNIT S/N)
	SKIPN	T1		;HAVE A NON-ZERO S/N?
	HRRZ	T1,.CPDVC##	;USE DEVICE CODE
	TRNN	P1,TD2DMX/2	;CU FOR LOW NUMBERED DRIVES?
	MOVEM	T1,KDBSER(W)	;YES
	TRNE	P1,TD2DMX/2	;CU FOR HIGH NUMBERED DRIVES?
	MOVEM	T1,KDBSER+1(W)	;YES
	TLNN	T4,(S172CH_2)	;TWO CHANNEL SWITCH CAPABILITY?
	TLZ	T4,(S17SWF_2)	;MAKE SURE NO PORTS
	LDB	T1,[POINTR (T4,S17SWF_2)] ;GET SWITCH FEATURES
	ANDI	T1,3		;STRIP OFF HI/LO UNIT BIT
	AOS	T1		;GET MAXIMUM NUMBER OF PORTS
	LSH	T1,1		;ACCOUNT FOR A/B PATHS PER TCU
	CAILE	T1,(P2)		;IF MDT KNOWS BETTER THAN WE DO,
	HRRZ	T1,P2		;USE ITS MAXIMUM
	DPB	T1,[POINTR (KDBSTS(W),KD.MPT)] ;SAVE
	MOVSI	T2,(KD.MPD)	;GET A BIT
	CAIE	T1,1		;IF MORE THAN ONE POSSIBLE PATH,
	IORM	T2,KDBSTS(W)	;THEN SAY MULTI-PORTED DEVICE

TD2DR1:	MOVE	T3,(P)		;COPY SENSE BYTES 12 - 15
	MOVE	T1,T3		;SAVE INCASE NO S/N
	ANDI	T3,377		;ISOLATE HIGH ORDER S/N BITS
	LSH	T4,2		;POSITION LOW ORDER S/N BITS
	LSHC	T3,-34		;MERGE HIGH AND LOW BITS
	DMOVE	T1,T3		;COPY RESULTS
	JUMPN	T2,TD2DR2	;HAVE A SERIAL NUMBER?
	MOVE	T1,(P)		;GET SENSE BYTES 12 - 15 AGAIN
	TLZ	T1,777740	;ISOLATE HIGH BYTE OF TX UNIT S/N
	LSHC	T1,-20		;SHIFT OUT LOW BYTE OF TX UNIT S/N
	LSH	T1,-2		;RIGHT JUSTIFY HIGH BYTE IN RH(T1)
	LSHC	T1,10		;FORM FULL TX UNIT S/N
	HRRZ	T2,P1		;MAKE WORD 2 = DRIVE NUMBER

TD2DR2:	POP	P,(P)		;KEEP STACK IN PHASE
	HRR	T3,P1		;GET PHYSICAL DRIVE NUMBER
	PUSHJ	P,AUTDSN##	;FAKE UP S/N IF A ZERO & SAVE TEMPORARILY
	HRR	T3,P1		;GET PHYSICAL DRIVE NUMBER
	PUSHJ	P,AUTDPU##	;LINK UP DUAL PORTED DRIVES
	  JFCL			;MUST PROCEED EVEN IF DUAL PORTED
	MOVEI	T2,.SB06	;SENSE BYTE 6
	PUSHJ	P,SETEST	;TELL THE DX20 WHAT WE WANT TO READ
	  JRST	TD2DR5		;CAN'T TALK TO THE DX20
	MOVEI	T1,TUCD80##+TUCD16## ;ASSUME TU70 TO START
	PUSHJ	P,REDEST	;READ THE SENSE BYTE
	TRNE	T4,S6.7TK	;7 TRACK DRIVE?
	MOVEI	T1,TUCD20##+TUCD55##+TUCD80##+TUC7TK##
	TRNE	T4,S6.D62	;6250 DRIVE?
	MOVEI	T1,TUCD16##+TUCD62##
	TRO	T1,TUCIRD##+K.DX2 ;INCLUDE REWIND INTERRUPT AND KONT TYPE
	MOVE	T2,T1		;COPY DRIVE INFO
	HRLZ	T1,P1		;PHYSICAL DRIVE NUMBER
	HRR	T1,P1		;UDB TABLE INDEX
	LDB	T3,[POINT 4,T4,27] ;GET TU MODEL BITS
	SETZ	T4,		;INCASE WE CAN'T FIGURE IT OUT
	CAIN	T3,5		;TU70/71?
	MOVE	T4,['TU70  ']	;YES
	TRNE	T2,TUC7TK##	;BUT IS IT 7-TK?
	TRO	T4,10000	;MAKE IT A TU71
	CAIN	T3,14		;TU72?
	MOVE	T4,['TU72  ']	;YES
	CAIN	T3,15		;TU73?
	MOVE	T4,['TU73  ']	;YES
	XMOVEI	T3,HNGTBL	;POINT TO HUNG TIMER TABLE
	PUSHJ	P,TAPDRV##	;BUILD AND LINK UP UDB AND DDB
	  JFCL			;FAILED

TD2DR3:	DMOVE	T1,.CPTSN##	;RETRIEVE DRIVE SERIAL NUMBER
	DMOVEM	T1,UDBDSN(U)	;SAVE IN UDB
	AOSA	(P)		;ONWARD

TD2DR4:	POP	P,(P)		;PHASE STACK

TD2DR5:	MOVSI	T2,(.DXERR)	;POINT TO ERROR REGISTER
	PJRST	WTMBR##		;CLEAR IT AND RETURN
;CHECK FOR DRIVE EXISTANCE
TD2DCK:	HRRZ	T1,P1		;GET UNIT
	MOVE	T1,BITTBL##(T1)	;AND IT'S BIT
	TDNE	T1,TD2IUM(W)	;WANT TO IGNORE THIS DRIVE?
	POPJ	P,		;SAY IT DOESN'T EXIST
	SKIPL	T1,TD2SUN(W)	;FULL AUTOCONFIGURE?
	JRST	TD2DC0		;NO
	HRRZS	T1		;ISOLATE POSSIBLE DRIVE NUMBER
	HRRZ	T2,P1		;AND THE ONE BEING CONFIGURED NOW
	CAIN	T1,(T2)		;MATCH?
	JRST	CPOPJ1##	;THEN INTERRUPT LEVEL TOLD US IT EXISTED
TD2DC0:	HRRZ	T2,P1		;GET DRIVE NUMBER
	HLLZ	T3,P1		;AND MASSBUS UNIT NUMBER
	HRLI	T2,(.DXGP1)	;SAY WHAT DRIVE WE WANT TO TALK TO
	PUSHJ	P,WTMBR##	;TELL THE HARDWARE
	MOVE	T2,[.DXCTR!CR.SNS] ;DO A SENSE ON THE DRIVE
	PUSHJ	P,WTMBR##	; SO WE CAN READ SENSE BYTES
	SKIPL	TD2SUN(W)	;DOING FULL AUTOCONFIGURE?
	PJRST	REASPI		;NO--JUST LITE PIA AND RETURN
	MOVEI	T1,2000		;LOOP COUNTER
TD2DC1:	MOVSI	T2,(.DXASR)	;POINT TO ATTENTION SUMMARY REGISTER
	PUSHJ	P,RDMBR##	;READ IT
	TRNN	T2,377		;HAVE AN ATTENTION?
	SOJG	T1,TD2DC1	;NO, WAIT SOME MORE
	JUMPLE	T1,TD2DC4	;DRIVE NOT THERE IF WE TIMED OUT
	MOVE	T2,[.DXASR!377]	;CLEAR THE ATTENTION WE JUST GOT
	PUSHJ	P,WTMBR##
	MOVE	T4,[TRNN T2,G0.RES]
TD2DC2:	MOVEI	T1,100		;HOW LONG TO WAIT
TD2DC3:	MOVSI	T2,(.DXGP0)	;POINT TO ENDING STATUS REGISTER
	PUSHJ	P,RDMBR##
	XCT	T4		;WAIT FOR CONDITION
	SOJG	T1,TD2DC3	;NO, WAIT SOME MORE
	TLZE	T4,(<TRNN>^!<TRNE>) ;CONVERT TRNN TO TRNE IF NOT ALREADY
	JRST	TD2DC2		;WASN'T, WAIT TO CLEAR
	JUMPLE	T1,TD2DC4	;NO DRIVE IF WE TIMED OUT
	PUSHJ	P,REDEST	;READ SENSE BYTES 0-3
	TLNE	T4,(S1.TUA!S1.TUB) ;DRIVE EXIST?
	JRST	CPOPJ1##	;YES
TD2DC4:	MOVSI	T2,(.DXERR)	;POINT AT ERROR REGISTER
	PJRST	WTMBR##		;CLEAR IT 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,SAVE1##	;SAVE P1
	PUSH	P,U		;SAVE U FOR CALLER
	XCT	KDBCNI(W)	;GET CONI IN T2
	PUSH	P,T1		;SAVE FOR LATER
	PUSHJ	P,SETIVO	;SETUP INTERRUPT VECTOR ADDRESS
	MOVEI	T1,CO.STP	;GET "STOP TRANSFER" BIT AND DEASIGN PI
	XCT	KDBCNO(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
	PUSHJ	P,MPSTRT	;RESET AND START THE DX20
	MOVE	P1,KDBIUN(W)	;POINTER TO UDB TABLE
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,KDBUNI(W)	;GET DX20 NUMBER FOR THIS DRIVE
TD2RE2:	CAMGE	P1,KDBFUN(W)	;FINAL UDB?
	AOJA	P1,TD2RE1	;LOOP FOR MORE
	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
	PUSH	P,T1		;SAVE IORB
	MOVEI	T1,CO.MBE	;ENABLE MASSBUS AND DIASSIGN PI
	XCT	KDBCNO(W)	;DO SO
	POP	P,T1		;RESTORE IORB
	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
	  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,@IRBACC(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,WTMBR##	;TELL THE DX20 HOW MANY FRAMES


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


	HRRZ	T3,@IRBACC(T1)	;GET EXEC VIRTUAL ADDR OF CMD LIST
	HRLI	T3,(INSVL.(.CCJMP,CC.OPC)) ;MAKE IT AN RH20 JUMP WORD
	MOVE	T2,KDBICP(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,KDBUNI(W)	;GET THE DX20 NUMBER
	HRLZM	T3,TKBASY(W)	;SAVE FOR QUICK INTERRUPT CHECK
	PUSHJ	P,WTMBR##	;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:	MOVE	T2,UDBPDN(U)	;PHYSICAL 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 & EVEN PARITY)
	MOVSI	T3,RB.PAR	;GET EVEN PARITY BIT
	TDNE	T3,TRBFNC(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,WTMBR##	;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,TUBSTS(U)	;GET TUBSTS
	TLNE	P1,(TB.RED)	;IS THIS A READ COMMAND?
	TLNN	T3,TUSBOT##	;FROM BOT?
	SKIPA	T3,TUBCNF(U)	;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,WTMBR##	;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,KDBUNI(W)	;GET DX20 NUMBER
	HRLZM	T2,TKBASY(W)	;STORE FOR INTERRUPT CHECK
	PUSH	P,T1		;SAVE IORB
	MOVEI	T1,CO.STP	;GET STOP TRANSFER BIT
	XCT	KDBCNO(W)	;SET DONE, CAUSING AND INTERRUPT
	POP	P,T1		;RESTORE IORB
	PJRST	REASPI		;LITE PIA AND RETURN

SUBTTL	CHECK FOR KONTROLLER BUSY


;CHECK FOR KONTROLLER BUSY
;CALL:	MOVE	W, KDB ADDRESS
;	MOVE	U, UDB FOR DRIVE TRYING TO SCHEDULE
;	PUSHJ	P,TD2BSY
;	  <RETURN 1>		;BUSY
;	  <RETURN 2>		;NOT-BUSY
;	<RETURN 3>		;DON'T KNOW
;
;USES T1 AND T2

TD2BSY:	MOVE	T1,KDBCHN(W)	;LOOK AT THE CHANNEL DATA BLOCK
	MOVE	T1,CHNTBP##(T1)	;SEE IF MORE THAN ONE KONT ON THE RH20
	AOBJN	T1,CPOPJ2##	;IF SO, THEN AVOID OVERHEAD & SAY "DON'T KNOW"
	PUSHJ	P,SAVE2##	;SAVE P1 AND P2
	PUSH	P,U		;SAVE U
	MOVE	P1,KDBIUN(W)	;POINT TO START OF DRIVE TABLE
	MOVSI	P2,-<TD2DMX/2>	;ACTUAL RANGE OF DRIVES PER KONT
	MOVE	T1,UDBPDN(U)	;GET PHYSICAL DRIVE NUMBER
	TRZ	T1,<TD2DMX/2>-1	;MASK OUT DRIVE LEAVING KONTROLLER OFFSET
	ADDI	P1,(T1)		;ADJUST STARTING TABLE INDEX

TD2BS1:	SKIPE	U,(P1)		;GET A TUB ADDRESS
	PUSHJ	P,CHKIRB##	;SEE IF IT HAS A VALID IORB
	  JRST	TD2BS2		;TRY ANOTHER DRIVE
	LDB	T2,PRBFCN##	;GET FUNCTION CODE
	MOVE	T2,BITTBL##	;NOT PICK UP THE ASSOCIATED BIT
	TDNN	T2,TD2NBF	;NON-BLOCKING FUNCTION?
	POPJ	P,		;NO--KONT IS BUSY

TD2BS2:	AOBJN	P2,TD2BS1	;LOOP BACK IF MORE DRIVES TO CHECK
	JRST	UPOPJ1##	;RESTORE U AND RETURN KONT NOT BUSY
	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


TD2ISR:	PUSHJ	P,SAVE4##	;SAVE P1-P4
	PUSHJ	P,SVMBR##	;SAVE CURRENT MBR FOR UUO LEVEL
	SETZ	P4,		;CLEAR ERROR FLAGS
	MOVE	U,@KDBCUN(W)	;POINT AT UDB WE'RE TALKING TO
	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
	PUSHJ	P,MPRUN		;MICROPROCESSOR RUNNING?
	  JRST	TD2IT1		;NO, SKIP CHECK FOR GO BIT
	MOVSI	T2,(.DXCTR)	;POINT AT CONTROL REGISTER
	PUSHJ	P,RDMBR##	;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,RDMBR##	;READ IT
	HRRI	P1,(T2)		;CARRY IN RH OF P1

	TLNE	P1,(TB.ILF)	;HERE BECAUSE OF ILLEGAL FUNCTION?
	HLLZ	P4,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/IORB ADDRESS, U/UDB ADDRESS, W/KDB ADDRESS
;	P1/LH IOFTBL ENTRY,,DEVICE STATUS BYTE
;	P2/SENSE BYTES 0-3
;	P4/ERROR BITS
;EXIT THROUGH DONE WITH:
;	T1/IORB ADDRESS
;	P4/UPDATED ERROR BITS


;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,RDMBR##	;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,TKBCRD(W)
	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	P4,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,TKBCWR(W)
	ADDM	T2,.CPTFO##
	JRST	DONE		;EXIT THROUGH COMMON CODE


;HERE ON WRITE TAPE MARK INTERRUPT

WTMINT:	TRNE	P1,G0.UEX	;UNIT EXCEPTION?
	TLO	P4,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	P4,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?
	MOVSI	P4,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
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


;HERE ON A SPACE BACKWARD FILE INTERRUPT.
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
;HERE AT THE COMPLETION OF FUNCTION SPECIFIC INTERRUPT PROCESSING
;OF A COMMAND COMPLETION INTERRUPT (BOTH DATA TRANSFER AND NON-DATA TRANSFER)
;WITH:
;	T1/IORB ADDRESS
;	P4/ERROR BITS

DONE:	TLNN	P4,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,WTMBR##	;DO SO
	IORM	P4,TRBSTS(T1)	;SET ERROR BITS IN THE IORB
	MOVSI	T2,TKSOFL##	;GET OFF-LINE BIT
	TLNE	P4,RB.SOL	;IS IT?
	IORM	T2,TUBSTS(U)	;YES, SET THE BIT IN THE UDR
	MOVSI	T2,RB.EXC	;GET EXCEPTION BIT
	TLZE	P4,-1		;ANY BITS SET?
	IORM	T2,TRBFNC(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:	PUSHJ	P,CLRATN	;CLEAR ATTENTION BITS
	SKIPL	T1,TKBSCH(W)	;INTERRUPT TO FORCE A SCHEDULE?
	JRST	CHKAT1		;NO
	SETZM	TKBSCH(W)	;CLEAR SCHEDULE FLAG
	JRST	CLRALL		;AND RETURN -1 TO TAPSER
CHKAT1:	PUSH	P,U		;SAVE U
	PUSHJ	P,MPRUN		;IS MICROPROCESSOR STILL RUNNING?
	  SKIPA	T2,[LOGUPE]	;NO--MUST LOG THE ERROR
	MOVEI	T2,ASYNST	;ELSE CHECK FOR ASYNCHRONOUS STATUS
	PUSHJ	P,(T2)		;DO SOMETHING
	MOVSI	T2,(.DXERR)	;DX20 REGISTER
	PUSHJ	P,WTMBR##	;CLEAR THE ERROR REGISTER

;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:
;	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,RDMBR##	;READ IT
	JUMPE	T2,ASYNS2	;MAYBE POLLING FOR NEW DRIVES
	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,RDMBR##	;US A DRIVE WITH NO STATUS, SO READ IT AGAIN
ASYNS1:	HLRZ	T3,KDBUNI(W)	;GET DX20 NUMBER
	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##
	JRST	ASYNS4		;GO FINISH UP

ASYNS2:	MOVSI	T2,(.DXGP1)	;NEED TO KNOW WHICH DRIVE RAISED INTERRUPTED
	PUSHJ	P,RDMBR##	;ASK DX20
	ANDI	T2,G1.DRV	;KEEP ONLY DRIVE NUMBER
	MOVE	T1,KDBIUN(W)	;GET POINTER TO UDB TABLE
	ADDI	T1,(T2)		;INDEX TO TARGET UDB
	SKIPN	(T1)		;ALREADY KNOWN TO US?
	CAILE	T2,TD2HDN	;OR OUT OF RANGE?
	JRST	ASYNS4		;GIVE UP
	MOVE	T1,BITTBL##(T2)	;GET ASSOCIATED BIT
	TDNE	T1,TD2IUM(W)	;WANT TO IGNORE THIS DRIVE?
	JRST	ASYNS3		;YES
	PUSHJ	P,REDEST	;FETCH SENSE BYTES OUT OF DX20 REGISTERS
	TLNE	T4,(S1.TUA+S1.TUB) ;DRIVE EXIST?
	IORM	T1,TD2NUM(W)	;REMEMBER WHICH NEW DRIVE TO CONFIGURE
	HRROS	KDBNUM(W)	;FLAG IT FOR THE ONCE-A-SECOND CODE
ASYNS3:	HRROS	TD2SUN(W)	;OK TO CHECK ANOTHER DRIVE NOW

ASYNS4:	MOVSI	T2,(.DXGP4)	;SETUP TO CLEAR ASYNC STATUS REGISTER.
	PUSHJ	P,WTMBR##	;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,WTMBR##	;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,RDMBR##	;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:
;	W/KDB ADDRESS
;RETURN+1 ALWAYS WITH T4/.DXGP6,,.DXGP7

REDEST:	MOVSI	T2,(.DXGP6)	;POINT AT EXTENDED STATUS REGISTER 0
	PUSHJ	P,RDMBR##	;READ IT
	HRLZ	T4,T2		;MOVE TO WHERE CALLER EXPECTS IT
	MOVSI	T2,(.DXGP7)	;POINT AT EXTENDED STATUS REGISTER 1
	PUSHJ	P,RDMBR##	;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

CLRATN:	MOVSI	T2,(.DXASR)	;POINT TO ATTENTION SUMMARY REGISTER
	MOVEI	T3,0		;ASR IS NOT DX20 SPECIFIC
	PUSHJ	P,RDMBR##	;READ IT
	ANDI	T2,AS.ATN	;KEEP ONLY ATTENTION BITS
	TDNN	T2,KDBUNI(W)	;ATTEN FOR THIS UNIT?
	JRST	CLRAT1		;NO, RETURN 0
	HRRZ	T2,KDBUNI(W)	;YES, GET JUST THAT BIT
	IORM	T2,TKBATN(W)	;UPDATE CORE COPY
	HRLI	T2,(.DXASR)	;SETUP TO CLEAR THE REGISETER
	PUSHJ	P,WTMBR##	;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/IORB ADDRESS,  P4/ERROR BITS
;RETURN+1 ALWAYS WITH:
;	T1/IORB ADDRESS,  P4/ERROR BITS+RB.STM

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	P4,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 IRBCCW 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/IORB ADDRESS
;	P1/IOFTBL ENTRY,,DEVICE STATUS BITS
;	P4/ERROR BITS
;RETURN+1 ALWAYS WITH:
;	T3/+NUMBER IF FORWARD OPERATION, -NUMBER IF REVERSE

NUMOPS:	MOVSI	T2,(.DXFCR)	;POINT TO FRAME COUNT REGISTER
	PUSHJ	P,RDMBR##	;READ -NUMBER OF OPS NOT PERFORMED
	HRRZ	T3,@IRBACC(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/IORB ADDRESS
;	P2/SENSE BYTES 0-3
;	P4/ERROR BITS
;RETURN+1 ALWAYS WITH:
;	T1/IORB ADDRESS,
;	P4/UPDATED ERROR BITS
;	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	P4,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/IORB ADDRESS,  P4/ERROR BITS
;RETURN+1 ALWAYS WITH:
;	T1/IORB ADDRESS,  P4/ERROR BITS+RB.SBT,
;	TUBREC, TUBFIL ZEROED,  TUBSTS UPDATED

SETBOT:	TLO	P4,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/IORB ADDRESS,  U/UDB ADDRESS,  W/KDB ADDRESS,
;	P1/IOFTBL BITS,,ENDING STATUS BYTE
;	P4/ERROR BITS
;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/IORB ADDRESS
;	P4/UPDATED ERROR BITS

CHKERR:	MOVEI	P2,0		;ASSUME NO ERRORS AND RETURN ZERO SENSE BYTES
	MOVSI	T2,(.DXSTR)	;POINT AT STATUS REGISTER
	PUSHJ	P,RDMBR##	;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,RDMBR##	;READ IT
	TRNE	T2,ER.ERR	;SOME GENERIC HARDWARE FAILURE?
	TLO	P4,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,REDEST	;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:	IFIW	FTLERR		;0 - UNKNOWN
	IFIW	ERRXIT		;1 - UNUSUAL DEVICE STATUS
	IFIW	ERRXIT		;2 - SHORT RECORD - NOT AN ERROR
	IFIW	LNGREC		;3 - LONG RECORD
	IFIW	OFLERR		;4 - DRIVE SELECTION ERROR
	IFIW	RTYERR		;5 - RECOVERABLE ERROR (TAPE MOTION)
	IFIW	NOMERR		;6 - RECOVERABLE ERROR (NO TAPE MOTION)
	IFIW	NRTERR		;7 - NON-RECOVERABLE ERROR
	IFIW	FTLERR		;10 - FATAL ERROR
	IFIW	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	P4,RB.SMO	;FLAG AS SET OFFLINE BY MONITOR
	PUSHJ	P,MPRES		;MAKE DAMN SURE IT STAYS OFF LINE
MPSERR:	TLOA	P4,RB.SED!RB.SER!RB.SOL ;SOME ERROR+NO RETRY+SET OFF LINE
NRTER1:	TLO	P4,RB.SED!RB.SER ;SOME ERROR+NO RETRY
	JRST	ERRXIT		;JOIN COMMON EXIT

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

ERRXIT:	SKIPE	P4		;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/IORB ADDRESS,  U/UDB ADDRESS,  W/KDB ADDRESS
;	P1/IOFTBL ENTRY,,ENDING STATUS BYTE,  P2/SENSE BYTES 0-3(0 IF NOT READ)
;	P4/ERROR BITS
;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,REDEST	;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,.SB06	;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,REDEST	;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/IORB ADDRESS,
;	P1/IOFTBL ENTRY,,DEVICE STATUS BYTE,  P2/SENSE BYTES 0-3
;	P4/ERROR BITS
;RETURN+1 ALWAYS WITH:
;	T1/IORB ADDRESS
;	P4/UPDATED ERROR BITS

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	P4,RB.SER!RB.SED ;NON-RECOVERABLE + ERROR
IRQERR:	TLO	P4,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	P4,RB.SNM	;NO, SET NO MOTION


;OVERRUN CAUSES REPOSITION AND RETRY

OVRERR:	TLOA	P4,RB.SED	;SOME ERROR


;DATA CHECK INVOKES TAPSER'S ERROR RETRY ALGORITHM

DTCERR:	TLO	P4,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/IORB ADDRESS,  P1/IOFTBL ENTRY FOR FUNCTION,  P4/ERROR BITS
;	W/KDB ADDRESS
;RETURN+1 ALWAYS WITH:
;	T1/IORB ADDRESS
;	P4/UPDATED ERROR BITS

CHKCHN:	PUSH	P,T1		;SAVE IORB
	XCT	KDBCNI(W)	;GET CONI INTO T1
	MOVE	T2,T1		;COPY RESULTS
	POP	P,T1		;RESTORE IORB
	MOVE	T3,KDBICP(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,CHENXM##	;POINT AT RTN TO CALL FOR NXM
	MOVSI	T4,IOCHNX	;ASSUMING NXM
	TLNN	T2,(CS.NXM)	;ARE WE CORRECT?
	MOVEI	T3,CHEMPE##	;NO, USE THIS ONE
	TLNN	T2,(CS.NXM)	; ...
	MOVSI	T4,IOCHMP	; ...
	MOVE	T1,KDBICP(W)	;GET ADDRESS OF LOGOUT AREA
	MOVE	P1,KDBCHN(W)	;GET CHANNEL DATA BLOCK ADDRESS
	MOVE	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	P4,RB.SED	;TELL UPPER LEVEL OF ERROR
CHKCH2:	TLO	P4,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:	MOVSI	T2,(.DXSTR)	;POINT AT STATUS REGISTER
	TAPOFF			;AVOID RACE WITH INTERRUPT RDMBR
	PUSHJ	P,RDMBR##	;GO READ STATUS REGISTER
	TAPON			;TURN PI BACK ON
	TRNN	T2,SR.RUN	;MP RUNNING?
	POPJ	P,		;REPORT CONTROLLER OFFLINE
	SKIPL	@KDBCHN(W)	;CHANNEL BUSY?
	JRST	CPOPJ1##	;LEAVE IT ALONE
	SKIPE	T1,TD2NUM(W)	;GET BIT MASK
	JFFO	T1,TD2ON3	;FIND FIRST UNIT NUMBER
	HRRZS	KDBNUM(W)	;INDICATE NO DRIVES TO CONFIGURE
	SKIPL	T1,TD2SUN(W)	;GET NON-EXISTANT UNIT BEING SENSED
	JRST	CPOPJ1##	;DO NOTHING IF SENSE IN PROGRESS
	PUSHJ	P,SAVE1##	;SAVE P1
	AOS	T1		;ADVANCE TO NEXT UNIT
	HRRZS	T1		;CLEAR LH FLAG
	CAILE	T1,TD2HDN	;OVERFLOW?
	MOVEI	T1,0		;START WITH DRIVE ZERO
	ADD	T1,KDBIUN(W)	;INDEX INTO TABLE

TD2ON1:	SKIPN	(T1)		;KNOWN UNIT?
	JRST	TD2ON2		;NO
	CAMGE	T1,KDBFUN(W)	;END OF TABLE?
	AOJA	T1,TD2ON1	;TRY ANOTHER
	SETOM	TD2SUN(W)	;RESET COUNTER
	JRST	CPOPJ1##	;AND INDICATE CONTROLLER ONLINE

TD2ON2:	SUB	T1,KDBIUN(W)	;REDUCE TO A DRIVE NUMBER
	MOVEM	T1,TD2SUN(W)	;SAVE FOR NEXT TIME
	MOVE	P1,T1		;COPY PHYSICAL DRIVE NUMBER
	HLL	P1,KDBUNI(W)	;INCLUDE MASSBUS UNIT
	PUSHJ	P,TD2DCK	;QUEUE UP SENSE REQUEST
	  JFCL			;SHOULD NEVER SKIP
	JRST	CPOPJ1##	;RETURN

TD2ON3:	PUSHJ	P,AUTLOK##	;GET AUTCON INTERLOCK
	  JRST	CPOPJ1##	;TRY AGAIN NEXT TIME
	MOVE	P1,T2		;COPY PHYSICAL DRIVE NUMBER
	HLL	P1,KDBUNI(W)	;INCLUDE MASSBUS UNIT
	MOVE	T1,KDBDVC(W)	;DEVICE CODE
	XMOVEI	T2,TD2DSP	;DISPATCH
	MOVE	T3,KDBCHN(W)	;CHANNEL DATA BLOCK
	PUSHJ	P,AUTSET##	;SET UP CPU VARIABLES
	PUSHJ	P,TD2DRV	;TRY TO CONFIGURE A DRIVE
	  JFCL			;IGNORE ERRORS
	PUSHJ	P,AUTULK##	;RELEASE AUTCON INTERLOCK
	JRST	CPOPJ1##	;TELL TAPSER THE CONTROLLER IS ALIVE
;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,RDDTR##	;IS IT REALLY A DX20?
	CAIE	T2,.DTCOD	;DX20?
	POPJ	P,		;NO, ERROR RETURN
	MOVSI	T2,(.DXSTR)	;POINT AT STATUS REGISTER
	TAPOFF			;AVOID RACE WITH INTERRUPT RDMBR
	PUSHJ	P,RDMBR##	;GO READ STATUS REGISTER
	TAPON			;TURN PI BACK ON
	TRNE	T2,SR.RUN	;MP RUNNING?
	AOS	(P)		;YES. TAKE GOOD RETURN
	POPJ	P,
	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
	PUSH	P,T1		;SAVE T1
	MOVEI	T1,CO.STP	;GET "STOP TRANSFER" BIT
	XCT	KDBCNO(W)	;STOP THE RH20
	POP	P,T1		;RESTORE T1
	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:	PUSH	P,T1		;SAVE T1
	MOVEI	T1,CO.MBE!CO.RAE ;GET MASSBUS ENABLE BIT
	XCT	KDBCNO(W)	;DO SO
	POP	P,T1		;RESTORE T1
	MOVE	T3,KDBVIN(W)	;SET UP ICWA+3
	HRLI	T3,(XPCW)

	MOVE	T2,KDBICP(W)
	MOVEM	T3,3(T2)
	MOVE	T2,KDBIVI(W)	;GET DATAO WORD TO SETUP INTERRUPT VECTOR
	XCT	KDBDTO(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
;CALL WITH:
;	W/KDB ADDRESS
;RETURN+1 ALWAYS

CLRERR:	PUSH	P,T1		;SAVE T1
	MOVEI	T1,CO.CLR	;GET BITS TO CLEAR ERRORS
	XCT	KDBCNO(W)	;CLEAR THEM
	SKIPA			;FALL INTO REASPI


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

REASPI:	PUSH	P,T1		;SAVE T1
	MOVEI	T1,CO.AIE!CO.MBE!TAPCHN## ;GET BITS TO ENABLE INTERRUPTS
	XCT	KDBCNO(W)	;DO SO
	POP	P,T1		;RESTORE T1
	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,WTMBR##	;WRITE THE REGISTER
	MOVSI	T2,(.DXDR0)	;POINT AT DIAGNOSTIC REGISTER 0
	PUSHJ	P,RDMBR##	;READ THE CONTENTS
	PUSH	P,T2		;SAVE FOR COMPARE
	MOVSI	T2,(.DXDTR)	;POINT AT DRIVE TYPE REGISTER
	PUSHJ	P,RDMBR##	;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,RDMBR##	;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,RDMBR##	;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,RDMBR##	;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,RDMBR##	;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,RDMBR##	;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,WTMBR##	;TELL MP ITS START ADDRESS
	MOVE	T2,[.DXMTR!MR.STR] ;SET START BIT IN MAINTENANCE REG
	PJRST	WTMBR##		;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	WTMBR##		;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,WTMBR##	;TELL THE DX20
	MOVSI	T2,(.DXDR0)	;ANSWER APPEARS HERE
	PJRST	RDMBR##		;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:	MOVSI	T2,(.DXSTR)	;POINT AT STATUS REGISTER
	PUSHJ	P,RDMBR##	;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
;RETURN+1 ALWAYS
;PRESERVES U,F

LOGUPE:	PUSHJ	P,SAVE1##	;SAVE P1
	PUSH	P,U		;  AND U
	PUSH	P,F		;  AND F
	PUSH	P,T3		;SAVE T3
	HLRZ	T2,KDBUNI(W)	;GET DX20 NUMBER
	LSH	T2,3		;CONSTRUCT OFFSET TO DRIVE 0 ON DX20
	ADD	T2,KDBIUN(W)	;INDEX INTO UDB TABLE
	CAMG	T2,KDBFUN(W)	;REASONABLE OFFSET?
	SKIPN	U,(T2)		;FETCH UDB ADDRESS
	JRST	LOGUP1		;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
	PUSHJ	P,TPELOG##	;LOG THIS ERROR
LOGUP1:	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
	MOVE	T1,TD2ULP+.ULVER ;GET UCODE VERSION
	HLL	T1,KDBUNI(W)	;INCLUDE MASSBUS UNIT NUMBER
	MOVEM	T1,TD2FST+.TFVER(U) ;SAVE IN FEP BLOCK
	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:	PUSH	P,T1		;SAVE T1
	XCT	KDBCNI(W)	;GET ERROR CONI
	MOVEM	T1,TD2FST+.TFCNI(U) ;SAVE IN UDB
	POP	P,T1		;RESTORE
	MOVSI	T2,(.DIPTC)	;POINT TO PTCR
	PUSHJ	P,RDMBR##	;READ IT
	MOVEM	T2,TD2FST+.TFD1I(U) ;SAVE IT
	MOVSI	T2,(.DIPBA)	;POINT TO PBAR
	PUSHJ	P,RDMBR##	;READ IT
	PUSH	P,T1		;SAVE IORB ADDRESS
	MOVSI	T1,-3		;AOBJN POINTER
	MOVEM	T2,TD2FST+.TFD2I(U) ;SAVE IT
	MOVE	T2,KDBICP(W)	;GET LOGOUT AREA ADDRESS
	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	T2,1		;BUMP LOGOUT AREA POINTER
	ADDI	T3,1		;BUMP OUTPUT POINTER
	AOBJN	T1,RDIRE1	;LOOP FOR ALL
	POP	P,T1		;RESTORE IORB ADDRESS
	HRRZ	T2,@IRBACC(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
	MOVE	T2,KDBCHN(W)	;GET ADDRESS OF CHN DB
	MOVE	T3,CHNMPE(T2)	;GET NUMBER OF MEM PAR ERRORS
	MOVEM	T3,TD2FST+.TFMPE(U) ;SAVE IN UDB
	MOVE	T3,CHNNXM(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,REDEST	;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:	PUSH	P,T1		;SAVE T1
	XCT	KDBCNI(W)	;GET FINAL CONI
	MOVEM	T1,TD2FST+.TFCIF(U) ;SAVE IN UDB
	POP	P,T1		;RESTORE
	MOVSI	T2,(.DIPTC)	;POINT AT PTCR
	PUSHJ	P,RDMBR##	;READ IT
	MOVEM	T2,TD2FST+.TFD1F(U) ;SAVE IN UDB
	MOVSI	T2,(.DIPBA)	;POINT AT PBAR
	PUSHJ	P,RDMBR##	;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,RDMBR##	;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,RDMBR##	;DO SO
	TRZ	T2,D1.IRE	;TURN OFF IR ENABLE
	HRLI	T2,(.DXDR1)	;PUT THE REGISTER NUMBER BACK
	PUSHJ	P,WTMBR##	;WRITE OFF IR ENABLE
	MOVSI	T2,(.DXDR0)	;POINT TO IR REGISTER
	PUSHJ	P,RDMBR##	;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	TABLES TO CONTROL I/O


;HUNG TIMER TABLE
	EXP	^D320			;MAXIMUM TIMEOUT VALUE
HNGTBL:	BYTE(9)	^D000,^D031,^D031,^D031	;IL,RD,WT,RB
	BYTE(9)	^D031,^D031,^D320,^D320	;SR,BR,SF,BF
	BYTE(9)	^D031,^D320,^D090,^D090	;LG,SE,RW,RU
	BYTE(9)	^D031,^D031,^D031,^D031	;TM,YB,CR,RL

;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.
;
;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.MS7)			;6 - SPACE FORWARD FILE
	FCN(CR.SBF,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:	IFIW	TAPIFI##	;(00) ILLEGAL
	IFIW	RDFINT		;(01) READ FORWARD
	IFIW	WRTINT		;(02) WRITE FORWARD
	IFIW	RDBINT		;(03) READ REVERSE
	IFIW	SFRINT		;(04) SPACE FORWARD RECORD
	IFIW	SBRINT		;(05) SPACE BACKWARD RECORD
	IFIW	SFFINT		;(06) SPACE FORWARD FILE
	IFIW	SBFINT		;(07) SPACE BACKWARD FILE
	IFIW	ERGINT		;(10) ERASE GAP
	IFIW	DSEINT		;(11) DATA SECURITY ERASE
	IFIW	REWINT		;(12) REWIND
	IFIW	UNLINT		;(13) REWIND AND UNLOAD
	IFIW	WTMINT		;(14) WRITE TAPE MARK
	IFIW	DONE		;(15) WAIT FOR KONTROLLER IDLE (USED AS A NOOP)
	IFIW	RDFINT		;(16) CORRECTION READ
	IFIW	RDFINT		;(17) READ LOW THRESHOLD
MAXINT==.-INTTBL-1		;HIGHEST LEGAL FUNCTION
SUBTTL	LOADABLE MICROCODE CONTROL


; 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
	XMOVEI	T1,TD2ULB(W)	;POINT TO MICROCODE LOADER BLOCK
	PUSHJ	P,DXLOAD##	;LOAD AND VERIFY MICROCODE
	  POPJ	P,		;FAILED
	PUSHJ	P,SETIVO	;SETUP INTERRUPT VECTOR ADDRESS
	JRST	CPOPJ1##	;AND RETURN
SUBTTL	ERROR LOGGING


TD2ELG:	HLLZ	T1,ELGTBL+.EXFLG ;GET -VE LENGTH OF XFER TABLE
	ADD	T1,TUBFEP(U)	;PLUS -VE FEP LENGTH
	MOVMS	T1		;MAKE POSITIVE
	ADD	T1,TD2MBR(U)	;PLUS NUMBER OF MASSBUS REGISTERS
	ADD	T1,TD2DVL(U)	;PLUS NUMBER OF DX20 REGISTERS
	HLRZS	T1		;PUT IN RH
	PUSHJ	P,ALCSEB##	;ALLOCATE A SYSTEM ERROR BLOCK
	  POPJ	P,		;NO CORE
	HRLZ	T2,KDBDSP(W)	;GET DEVICE CODE
	IOR	T2,TD2VER(U)	;INCLUDE UCODE VERSION
	HRRI	T2,001001	;PLUS RH20 MAGTAPE FLAGS
	MOVEM	T2,TD2DID(U)	;SAVE AS DEVICE IDENTIFIER
	XMOVEI	T2,ELGTBL	;POINT TO TRANSFER TABLE
	PUSHJ	P,XFRSEB##	;LOAD UP THE ERROR RECORD
	  JFCL			;CAN'T FAIL HERE
	MOVEI	T2,43		;OFFSET WITHIN RECORD
	SKIPE	.EBHDR+43(T1)	;MASSBUS REGISTERS SUB-BLOCK POINTER?
	ADDM	T2,.EBHDR+43(T1) ;RELOCATE (R43)
	MOVEI	T2,44		;OFFSET WITHIN RECORD
	SKIPE	.EBHDR+44(T1)	;DX20 REGISTER SUB-BLOCK POINTER?
	ADDM	T2,.EBHDR+44(T1) ;RELOCATE (R44)
	SKIPN	T2,.EBHDR+43(T1);ANY MASSBUS REGISTERS?
	JRST	CPOPJ1##	;NO
	ADDI	T2,.EBHDR(T1)	;POINT TO STORAGE
	HLRZ	T3,T2		;GET COUNT
	MOVNS	T3		;MAKE NEGATIVE
	HRL	T2,T3		;MAKE AN AOBJN POINTER TO STORAGE
	HRRZ	T3,TD2MBR(U)	;GET OFFSET TO MBR BLOCK
	ADDI	T3,TD2MBR	;INDEX INTO FEP BLOCK
	ADD	T3,U		;RELOCATE

TD2EL1:	MOVE	T4,(T3)		;GET A WORD
	MOVEM	T4,(T2)		;PUT A WORD
	AOS	T3		;ADVANCE SOURCE POINTER
	AOBJN	T2,TD2EL1	;LOOP FOR ALL MASSBUS REGISTERS
	SKIPN	T3,.EBHDR+44(T1) ;GET POINTER TO DX20 REGISTER SUB-BLOCK
	JRST	CPOPJ1##	;NONE THERE
	HLRZ	T4,T3		;GET REGISTER COUNT
	MOVNS	T4		;NEGATE
	HRL	T2,T4		;MAKE AN AOBJN POINTER TO STORAGE
	HRRZ	T3,TD2DVL(U)	;GET OFFSET TO DX20 REG BLOCK
	ADDI	T3,TD2DVL	;INDEX INTO FEP BLOCK
	ADD	T3,U		;RELOCATE

TD2EL2:	MOVE	T4,(T3)		;GET A WORD
	MOVEM	T4,(T2)		;PUT A WORD
	AOS	T3		;ADVANCE SOURCE POINTER
	AOBJN	T2,TD2EL2	;LOOP FOR ALL DX20 REGISTERS
	JRST	CPOPJ1##	;RETURN AND LOG ERROR

;OFFSETS WITHIN THE FEP BLOCK
	 .ORG	TD2FST	;DEFINED RELATIVE TO START OF FEP BLOCK
TD2ZRO:! BLOCK	1	;ZERO WORD (UNDEFINED ENTRIES MAP HERE)
TD2CNI:! BLOCK	1	;CONI INITIAL
TD2CIF:! BLOCK	1	;CONI FINAL
TD2RED:! BLOCK	1	;NUMBER OF FRAMES READ
TD2WRT:! BLOCK	1	;NUMBER OF FRAMES WRITTEN
TD2D1I:! BLOCK	1	;DATAI PTCR INITIAL
TD2D1F:! BLOCK	1	;DATAI PTCR FINAL
TD2D2I:! BLOCK	1	;DATAI PBAR INITIAL
TD2D2F:! BLOCK	1	;DATAI PBAR FINAL
TD2CS0:! BLOCK	1	;CHANNEL LOGOUT 0
TD2CS1:! BLOCK	1	;CHANNEL LOGOUT 1
TD2CS2:! BLOCK	1	;CHANNEL LOGOUT 2
TD2CC1:! BLOCK	1	;FIRST CCW
TD2CC2:! BLOCK	1	;SECOND CCW
TD2MPE:! BLOCK	1	;COUNT OF MPE
TD2NXM:! BLOCK	1	;COUNT OF NXM
TD2OVR:! BLOCK	1	;NUMBER OF OVERRUNS
TD2ICR:! BLOCK	1	;CONTENTS OF INITIAL CONTROL REG
TD2VER:! BLOCK	1	;BYTE (9)DX20 ADDRESS(9)0(18)UCODE VERSION
TD2MBR:! BLOCK	1	;# OF MASSBUS REGS,,OFFSET TO FIRST
TD2DVL:! BLOCK	1	;# OF DEVICE REGS,,OFFSET TO FIRST
	 .ORG

ELGTBL:	SEBTBL	(.ERDXE,ELGEND,)
	MOVE	UDBNAM(U)	;(R00) DEVICE NAME
	MOVE	TUBRID(U)	;(R01) REELID
	MOVE	TD2DID(U)	;(R02) DEVICE IDENTIFIER
	MOVE	TUBPBE(U)	;(R03) POSITION BEFORE ERROR
	MOVE	TUBFES(U)	;(R04) FINAL ERROR STATE
	MOVE	TD2CNI(U)	;(R05) CONI INITIAL
	MOVE	TD2CIF(U)	;(R06) CONI FINAL
	MOVE	TD2ZRO(U)	;(R07) NUMBER OF SEEKS (0 FOR MAGTAP)
	MOVE	TD2RED(U)	;(R10) NUMBER OF FRAMES READ
	MOVE	TD2WRT(U)	;(R11) NUMBER OF FRAMES WRITTEN
	MOVE	TD2ZRO(U)	;(R12) SIXBIT FILENAME
	MOVE	TUBUID(U)	;(R13) PPN OF USER
	MOVE	TUBPGM(U)	;(R14) SIXBIT PROGRAM NAME
	MOVE	TD2D1I(U)	;(R15) DATAI PTCR INITIAL
	MOVE	TD2D1F(U)	;(R16) DATAI PTCR FINAL
	MOVE	TD2D2I(U)	;(R17) DATAI PBAR INITIAL
	MOVE	TD2D2F(U)	;(R20) DATAI PBAR FINAL
	MOVE	TUBSRE(U)	;(R21) SOFT READ ERRORS
	MOVE	TUBSWE(U)	;(R22) SOFT WRITE ERRORS
	MOVE	TUBHRE(U)	;(R23) HARD READ ERRORS
	MOVE	TUBHWE(U)	;(R24) HARD WRITE ERRORS
	MOVE	TUBFIL(U)	;(R25) FILE POSITION
	MOVE	TUBREC(U)	;(R26) RECORD POSITION
	MOVE	TD2CS0(U)	;(R27) CHANNEL LOGOUT 0
	MOVE	TD2CS1(U)	;(R30) CHANNEL LOGOUT 1
	MOVE	TD2CS2(U)	;(R31) CHANNEL LOGOUT 2
	MOVE	TD2CC1(U)	;(R32) FIRST CCW
	MOVE	TD2CC2(U)	;(R33) SECOND CONTROL WORD
	MOVE	TD2MPE(U)	;(R34) COUNT OF MPE
	MOVE	TD2NXM(U)	;(R35) COUNT OF NXM
	MOVE	TD2ZRO(U)	;(R36) SOFT POSITIONING ERRORS
	MOVE	TD2ZRO(U)	;(R37) HARD POSITIONING ERRORS
	MOVE	TD2OVR(U)	;(R40) NUMBER OF OVERRUNS
	MOVE	TD2ICR(U)	;(R41) CONTENTS OF INITIAL CONTROL REG
	MOVE	TD2VER(U)	;(R42) DX20 MICRO-CODE VERSION #
	MOVE	TD2MBR(U)	;(R43) # OF MASSBUS REGS,,OFFSET TO FIRST
	MOVE	TD2DVL(U)	;(R44) # OF DEVICE REGS,,OFFSET TO FIRST
ELGEND:!			;END OF TABLE
SUBTTL	END

	END