Google
 

Trailing-Edge - PDP-10 Archives - bb-bt99q-bb - tm2kon.x23
There is 1 other file named tm2kon.x23 in the archive. Click here to see a list.
TITLE	TM2KON - RH10/RH20/RH11 TM02/TM03(TU16/TU46/TU77) DRIVER	V172
SUBTTL	T WACHS/TW/TL/DPM	16-MAY-89

	SEARCH	F,S,DEVPRM

	FTRH11==FTKS10		;KEEP TRACK OF WHAT WE'RE DOING

	SALL
	.DIRECT FLBLST

	$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
; 1975,1976,1977,1978,1979,1980,1982,1984,1986,1988.
;ALL RIGHTS RESERVED.

.CPYRT<1975,1988>

TM2KON::ENTRY 	TM2KON
XP VTM2KN,172
	TM2DMX==4			;MAXIMUM DRIVES PER KONTROLLER
	TM2HDN==TM2DMX-1		;HIGHEST DRIVE NUMBER ON KONTROLLER
	TM2ELN==16			;SIZE OF FEP TABLE

;DRIVER CHARARCTERISTICS
;	TM2	= TM2CNF
;	MTA	= MAGTAPE
;	0	= MAXIMUM DEVICES IN SYSTEM (NO LIMIT)
;	K.TM2	= KONTROLLER TYPE
;	TM2DMX	= MAXIMUM DRIVES PER KONTROLLER
;	TM2HDN	= HIGHEST DRIVE NUMBER ON KONTROLLER
;	MDSEC0	= SECTION FOR KDB/UDB
;	MDSEC0	= SECTION FOR DDB
DRVCHR	(TM2,MTA,0,K.TM2,TM2DMX,TM2HDN,MDSEC0,MDSEC0,<DR.XAD!DR.MCD!DR.DPU!DR.GCC!DR.DDN>)


	.ORG	TKBUDB		;START OF TM02 SPECIFIC DATA
TM2UTB:! BLOCK	TM2DMX		;TABLE OF POINTERS TO UDBS
TM2UVA:! BLOCK	1		;TEMP FOR READ BACKWARDS
TM2IUM:! BLOCK	TM2DMW		;IGNORE DRIVE MASK
TM2NUM:! BLOCK	TM2DMW		;NEW DRIVE MASK
TM2KLN:!			;LENGTH OF KDB
	.ORG

	 .ORG	TUBLEN
TM2ICS:! BLOCK TM2ELN		;INITIAL ERROR STATUS
TM2REG:! BLOCK TM2ELN		;FINAL ERROR STATUS
TM2ULN:!			;LENGTH OF UDB
	 .ORG


TM2KDB:	KDBBEG	(TM2,TM2KLN)
	SETWRD	(KDBNAM,<SIXBIT/MT/>)	;KONTROLLER NAME
	SETWRD	(KDBIUN,<TKBUDB>)	;INITIAL POINTER TO UDBS
	SETWRD	(KDBCUN,<TKBUDB>)	;CURRENT POINTER TO UDBS
	SETWRD	(KDBIUM,<TM2IUM>)	;OFFSET TO IGNORE UNIT MASK
	SETWRD	(KDBNUM,<TM2NUM>)	;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


TM2UDB:	UDBBEG	(TM2,TM2ULN)
	SETWRD	(UDBNAM,<SIXBIT/MT/>)	;DRIVE NAME
	SETWRD	(TUBIEP,<-TM2ELN,,TM2ICS>) ;INITIAL ERROR POINTER
	SETWRD	(TUBFEP,<-TM2ELN,,TM2REG>) ;FINAL ERROR POINTER
	UDBEND


EQUATE	(LOCAL,0,<TM2ULP,TM2ULB>)
EQUATE	(LOCAL,CPOPJ##,<TM2CMD,TM2EDL,TM2IDL,TM2LOD>)
EQUATE	(LOCAL,CPOPJ2##,<TM2BSY>)

TM2ICD==TAPICD##		;PROTOTYPE INTERRUPT CODE ADDRESS
TM2ICL==TAPICL##		;PROTOTYPE INTERRUPT CODE ADDRESS
TM2INT==TAPINT##		;INTERRUPT SERVICE
TM2ELG==TPELGX##		;MAKE AN ERROR LOG ENTRY

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

TM2CKT:	EXP	K.TM2,0	;COMPATIBLE KONTROLLER TABLE

;DEFAULT MONGEN'ED DEVICE TABLE
DEFMDT:	MDKL10	(7,270,0,0,<MD.KON>)	;RH10 DEVICE CODE 270
	MDKL10	(7,274,0,0,<MD.KON>)	;RH10 DEVICE CODE 274
	MDKL10	(7,360,0,0,<MD.KON>)	;RH10 DEVICE CODE 360
	MDKS10	(7,RH21IV,RH21CA,0,0,<MD.KON>)
	MDTERM				;TERMINATE TABLE
;SYSERR REGISTER BLOCK DEFINITIONS

	E..CNI==TM2REG+0	;RH10/20 - CONI AT ERROR
				;RH11 - DO.CS2,,DO.CS1 AT ERROR
	E..DTI==TM2REG+1	;RH10/20 - DATAI CONTROL AT ERROR
				;RH11 - UBA STATUS REGISTER AT ERROR
	E..DT2==TM2REG+2	;RH10/20 - DATAI DATA BUFFER AT ERROR
				;RH11 - UBA MAP ENTRY AT ERROR
	E..LCM==TM2REG+3	;LAST COMMAND ISSUED
	E..MBR==TM2REG+4	;BLOCK OF MASSBUS REGISTERS AT ERRROR

;OFFSETS INTO TKBCCL

	TKBFLG==TKBCCL+2		;FLAGS FROM FNCTBL
	TKBCHR==TKBCCL+3		;CHARACTER (FRAME) COUNT
	TKBSCH==TKBCCL+4		;-1 IF A SCHEDULE CYCLE
	SUBTTL	PARAMETERS

;MACRO TO ASSIGN MASSBUS REGISTERS DEPENDING ON KONTROLLER TYPE
DEFINE	MBR(NAME,RH1020,RH11),<
IFE FTRH11,< IFNB /RH1020/,<DO.'NAME==RH1020'B5> >;;RH10/20 DATAO CODE
IFN FTRH11,< IFNB /RH11/,<DO.'NAME==(RH11)> >;;	RH11 WRIO OFFSET
IFNB /RH1020/,<E..'NAME==E..MBR+RH1020>;;TUB OFFSET OF REGISTER FOR SYSERR
>;MBR
	;DRIVE REGISTERS

MBR	CS1,0,0			;DRIVE CONTROL REGISTER
MBR	WC,,2			;WORD COUNT REGISTER
MBR	BA,,4			;BUS ADDRESS REGISTER
MBR	CS2,,10			;STATUS REGISTER
MBR	DS,1,12			;DRIVE STATUS REGISTER
MBR	ER,2,14			;ERROR REGISTER
MBR	DB,,22			;DATA BUFFER REGISTER
MBR	MR,3,24			;MAINTENANCE REG
MBR	AS,4,16			;ATTN SUMMARY
MBR	FC,5,6			;FRAME COUNTER
MBR	DT,6,26			;DRIVE TYPE
MBR	CK,7,20			;CHK CHARACTER REG
MBR	SN,10,30		;SERIAL NUMBER
MBR	TC,11,32		;TAPE CONTROL REGISTER
IFN FTRH11,<
;CONTROL REGISTER BITS (DO.CS1)

	DC.SC==1B20		;SPECIAL CONDITION
	DC.TRE==1B21		;TRANSFER ERROR
	DC.CPE==1B22		;CONTROL BUS PARITY ERROR
	DC.DVA==1B24		;DRIVE AVAILABLE
	DC.PSL==1B25		;PORT SELECT
	DC.RDY==1B28		;READY
	DC.IE==1B29		;INTERRUPT ENABLED
;	DC.FNG==77		;FUNCTION + GO

;STATUS REGISTER BITS (DO.CS2)

	D2.DLT==100000		;(R) DATA LATE (OVERRUN)
	D2.WCE==40000		;(R) WRITE CHECK ERROR
	D2.UPE==20000		;(R/W) UNIBUS PARITY ERROR
	D2.NXD==10000		;(R) NON-EXISTANT DRIVE
	D2.NXM==4000		;(R) NON-EXISTANT MEMORY
	D2.PGE==2000		;(R) PROGRAM ERROR
	D2.MXF==1000		;(R/W) MISSED TRANSFER
	D2.DPE==400		;(R) DATA BUS PARITY ERROR
	D2.OR==200		;(R) OUTPUT READY
	D2.IR==100		;(R) INPUT READY
	D2.CLR==40		;(W) CONTROLLER CLEAR
	D2.PAT==20		;(R/W) PARITY TEST
	D2.BAI==10		;(R/W) UNIBUS ADDRESS INCREMENT INHIBIT
;	D2.UNI==7		;(R/W) MASSBUS UNIT # TO TALK TO

D2%CHE==D2.DLT!D2.UPE!D2.NXD!D2.NXM!D2.PGE!D2.MXF!D2.DPE ;CHANNEL-TYPE ERRORS
>;FTRH11
;DRIVE FUNCTIONS LOADED INTO DRIVE CONTROL REG (DO1CRC/.DOSTC/DO.CS1)

	DF.NOP==1		;NO-OP
	DF.UNL==3		;UNLOAD (REWIND OFF-LINE)
	DF.INT==5		;ILLEGAL FUNCTION TO CAUSE AN INTERRUPT
	DF.REW==7		;REWIND
	DF.CLR==11		;DRV CLR
	DF.RIPS==21		;READ-IN, PRESET
	DF.ERA==25		;ERASE
	DF.WTM==27		;WRITE TAPE MARK
	DF.SPF==31		;SPACE FWD
	DF.SPR==33		;SPACE REVERSE
	DF.WCF==51		;WRITE CHK FWD (READ FWD)
	DF.WCR==57		;WRITE CHK REV (READ REV)
	DF.WTF==61		;WRITE FORWARD
	DF.RDF==71		;READ FORWARD
	DF.RDR==77		;READ REVERSE


;TAPE CONTROL REGISTER (DO.TC)
	TC.PAR==1B32		;ON IF WRITE EVEN PARITY

;DRIVE TYPE REGISTER (DO.DT)
	DT.SPR==1B25		;SLAVE PRESENT
;DRIVE STATUS REGISTER (DO.DS)

	DS.ATA==1B20		;ATTENTION
	DS.ERR==1B21		;COMPOSITE ERROR
	DS.PIP==1B22		;POSITIONING IN PROGRESS
	DS.MOL==1B23		;MEDIUM ON LINE
	DS.WRL==1B24		;WRITE LOCKED
	DS.EOT==1B25		;END OF TAPE
	DS.DPR==1B27		;DRIVE PRESENT
	DS.DRY==1B28		;DRIVE READY (NOT GO)
	DS.SSC==1B29		;SLAVE STATUS CHANGE
	DS.PES==1B30		;PHASE ENCODED STATUS
	DS.SDN==1B31		;SHUTDOWN BIT
	DS.IDB==1B32		;IDENT BURST (FOR PE)
	DS.TM==1B33		;TAPE MARK
	DS.BOT==1B34		;BEGINNING OF TAPE
	DS.SLA==1B35		;SLAVE ATTENTION
	DS.OK==DS.EOT!DS.PES!DS.TM!DS.BOT!DS.SSC!DS.SDN!DS.IDB	;BITS WHICH DON'T MATTER
	DS.GUD==DS.MOL!DS.DPR!DS.DRY	;THESE BITS MUST BE ON


;DRIVE ERROR REGISTER (DO.ER)

	ER.COR==1B20		;CORRECTABLE DATA/ CRC ERROR
	ER.UNS==1B21		;UNSAFE
	ER.OPI==1B22		;OPERATION INCOMPLETE
	ER.DTE==1B23		;DRIVE TIMING ERROR
	ER.NEF==1B24		;NON-EXISTANT FUNCTION
	ER.CS==1B25		;CORRECTABLE SKEW/ ILLEGAL TAPE MARK
	ER.FCE==1B26		;FRAME COUNT ERROR
	ER.NSG==1B27		;NON-STANDARD GAP (CRAP IN THE GAP)
	ER.LRC==1B28		;LRC ERROR/ FORMAT (PREAMBLE POSTAMBLE) ERROR
	ER.INC==1B29		;INCORRECTABLE DATA/ VERTICAL PARITY ERROR
	ER.DPA==1B30		;DATA BUS PARITY ERROR
	ER.FMT==1B31		;FORMAT ERROR
	ER.CPA==1B32		;CBUS PARITY ERROR
	ER.RMR==1B33		;REG MODIFICATION REFUSED
	ER.ILR==1B34		;ILLEGAL REGISTER ADR
	ER.ILF==1B35		;ILLEGAL FUNCTION
IFE FTRH11,<
;RH10 BITS, FUNCTIONS
	DO1CRC==40B5		;RH10 CONTROL REG
	DO1CDB==50B5		;RH10 DATA BUFFER
	DO1CRA==54B5		;RH10 RAE REGISTER

;CONI/CONO BITS
	;LH BITS
	CI1SDR==200		;SELECTED DRIVE REGISTER ACCESS ERROR
	CI1CDP==4		;CHAN DATA PARITY ERROR
	CI1CWP==2		;CHAN COMMAND WORD PARITY ERROR
	CI1NXM==1		;CHAN-DETECTED NXM

	;RH BITS
	CI1ATN==40		;ATTENTION
	CI1DON==10		;DONE


	CI1ERR==536220
	CO1CLR==734210		;CLEAR ALL ERRORS


;DATAI/DATAO BITS
	CBTO==2000		;CONTROL BUS TIMEOUT


;RH20
	;CONI/CONO
	CI.ERR==CI.LWC!CI.DRE!CI.RAE
	CO.CLR==CO.RAE!CO.TEC

;CHANNEL LOGOUT AREA
	CS.ERR==CS.MPE!CS.NAE!CS.NXM!CS.RHE!CS.OVR ;ALL CHAN LOGOUT ERRS
>;IFE FTRH11
	SUBTTL	TAPSER CALL PROCESSING

	;HERE TO START IO
	;REGISTER USAGE:
	;T1/ IORB ADDRESS
	;T2/ TEMP, MASSBUS REGISTER READ/WRITTEN
	;T3/ MASSBUS UNIT # OF TM02/3
	;T4/ MODTBL ENTRY FOR IORB
	;P1/ FNCTBL ENTRY (FLAG BITS+IORB FCN,,DF.XXX)
	;P2/ CONTROLLER TYPE / IO ADDRESS OF RH11
	;U/ TUB FOR IO
	;W/ TKB FOR IO

TM2SIO:	PUSHJ	P,CHKIRB##	;GET IORB FOR THIS OP
	  JRST	TAPDIS##	;NONE, GO AWAY
	PUSHJ	P,SAVST2	;SAVE ACS, P2=0 (RH10), =1 (RH20), CSR (RH11)
	LDB	T4,PRBFCN##	;FUNCTION
	SKIPN	P1,FNCTBL(T4)	;LEGAL?
	JRST	ILLFNC		;NO
	SKIPGE	T2,TRBRCT(T1)	;IF POSITIVE IN ERROR RECOVERY
	MOVEM	T2,TM2UVA(W)	;REAL IOWD - SAVE IT
	MOVE	T2,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	LDB	T4,PRBDEN##	;GET DENSITY
	CAILE	T4,MAXDEN	;LEGAL?
	MOVEI	T4,MAXDEN	;TOO HIGH - MAKE IT THE HIGHEST
	DPB	T4,PRBDEN##	;SAVE
	SKIPGE	T4,DENTBL(T4)	;LEGAL DENSITY?
	JRST	ILLFNC		;NO
	TRO	T2,(T4)		;YES, PUT DENSITY INTO COMMAND
	MOVSI	T4,RB.PAR	;EVEN PARITY?
	TDNE	T4,TRBFNC(T1)
	TRO	T2,TC.PAR	;YES, TELL THE HARDWARE
	LDB	T4,PRBMOD##	;GET MODE
	SKIPGE	T4,MODTBL(T4)	;LEGAL?
	JRST	ILLFNC		;NO
	TRO	T2,(T4)		;YES, TELL THE HARDWARE
IFE FTRH11,<
	PUSH	P,T1		;SAVE IORB
	MOVEI	T1,CO.MBE	;DONT ALLOW INTERRUPTS (BIT IGNORED IF RH10)
	XCT	KDBCNO(W)	;(REWINDING DRIVE)
	POP	P,T1		;RESTORE IORB
>;FTRH11
IFN FTRH11,<
	MOVEI	T3,1		;MAKE SURE GO BIT ISN'T SET, AS IT WILL
	TIOE	T3,<(DO.CS1)>(P2);CAUSE A PGE, AND MAYBE DO LAST OP TWICE...
	JRST	TAPDIS##	;IN ANY CASE, WE'LL GET ANOTHER INTERRUPT
	MOVEI	T3,DC.IE	;IT'S SAFE, CLEAR INTERRUPT ENABLE
	BCIOB	T3,<(DO.CS1)>(P2);(REWINDING DRIVE)
>;FTRH11
	HRLI	T2,(DO.TC)	;SET TO TALK TO TAPE CNTRL REG
	PUSHJ	P,WTMBR##	;TELL MODE, DENSITY, SLAVE #, PARITY
	HRLI	T3,-1		;1ST TIME THROUGH (RH SET BY WTMBR)
TM2SI2:	MOVSI	T2,(DO.DS)	;READ THE STATUS REGISTER OF THE SLAVE
	PUSHJ	P,RDMBR##
	TRNN	T2,DS.BOT	;BOT?
	JRST	TM2SI1		;NO
	.CREF	TB.REV
	JUMPGE	P1,TM2SI1	;YES, JUMP IF NO BACKWARD MOVEMENT
	MOVSI	P1,TUSBOT##	;SAW BOT, UPDATE STATUS
	IORM	P1,TUBSTS(U)	;LET THE UDB KNOW
	MOVSI	P1,TUSWTL##	;YES, UPDATE WRITE-LOCK STATUS
	ANDCAM	P1,TUBSTS(U)	; BY CLEARING IT
	TRNE	T2,DS.WRL	; AND SET IT AGAIN IF WE REALLY ARE
	IORM	P1,TUBSTS(U)	; WRITE LOCKED
	MOVSI	P1,RB.SNM!RB.SBT ;SINCE DRIVE IS AT BOT
	IORM	P1,TRBSTS(T1)	;INDICATE NO MOTION, BOT
	MOVE	P1,FNCNOP	;CHANGE FUNCTION TO NO-OP
TM2SI1:	TLNN	P1,(TB.WRT)	;ARE WE READING?
	TRZ	T2,DS.WRL	;YES, WRITE-LOCKED TAPE IS OK
	SKIPL	T3		;SKIP IF PASS 1
	TRZ	T2,DS.ATA	;IF DID A DRIVE CLEAR IGNORE ATTN
	TRZ	T2,DS.OK	;CLEAR THE BITS WHICH DON'T MATTER
	CAIE	T2,DS.GUD	;IS THE DRIVE OK?
	JRST	NOSTRT		;NO, INVESTIGATE FURTHER
				;YES, CONTINUE
	TLNN	P1,(TB.DAT)	;DATA OPERATION?
	JRST	TM2SI3		;NO
IFN FTRH11,<
	MOVE	T3,KDBCHN(W)	;ADDRESS OF CHANNEL DATA BLOCK
	MOVE	T2,CHNBTC(T3)	;GET THE BYTE COUNT FOR THIS TRANSFER
	AOJ	T2,		;ROUND UP TO WORDS
	LSH	T2,-1		;MAKE 11 STYLE WORD COUNT
	MOVNS	T2		;2'S COMPLEMENT
	HRLI	T2,(DO.WC)	;LOAD THE WORD COUNT REGISTER
	PUSHJ	P,WTMBR##
	HRRZ	T2,P1		;GET FUNCTION CODE
	CAIE	T2,DF.RDR	;IS IT A READ REVERSE?
	JRST	TRHS2A		;NO--PROCEED
	MOVE	T2,CHNTCW(T3)	;GET ENDING -11 STYLE ADDRESS
	SOSA	T2		;"REAL" START FOR READ REVERSE
TRHS2A:	MOVE	T2,CHNIEA(T3)	;GET STARTING -11 STYLE ADDRESS
	WRIO	T2,<(DO.BA)>(P2);LOAD INTO BUS ADDRESS REGISTER
	LSH	T2,-^D16	;GET HIGH TWO BITS OF ADDRESS
	ANDI	T2,3		;AND ONLY THEM
	WRIOB	T2,<(DO.CS1)>+1(P2)	;STORE IN RH11
>;FTRH11
	MOVS	T2,TM2UVA(W)	;GET WORD COUNT
	HLRZS	T4		;NO OF FRAMES PER WORD
	TLOE	T2,-1		;DO WE ALREADY HAVE FRAME COUNT ?
	IMULI	T2,(T4)		;NO, COMPUTE FRAME COUNT
	MOVNM	T2,TKBCHR(W)	;SAVE IN KDB
	TLNE	P1,(TB.NFC!TB.OFC)	;0 OR -1 TO F.C.?
TM2SI3:	SETZ	T2,		;YES
	TLNE	P1,(TB.NFC!TB.DAT)	;IF T2 IS ALREADY SET,
	JRST	NOFC		;GO
	TLNE	P1,(TB.OFC)	;IF -1 TO F.C.
	SOJA	T2,NOFC		;GO
	MOVN	T2,@IRBACC(T1)	;GET -NO OF RECS TO SPACE
NOFC:	ANDI	T2,177777	;ONLY 16 BIT'S WORTH
	HRLI	T2,(DO.FC)	;TALK TO FRAME COUNT REG
	PUSHJ	P,WTMBR##	;TELL IT HOW MUCH TO DO
TM2SI4:
IFE FTRH11,<
	.CREF	DO.CS1		;NEXT INSTR SETS UP TO WRITE CS1 FOR SPACE OP
	MOVE	T2,KDBICP(W)	;ICWA
	HRRZ	T3,@IRBACC(T1)	;CHAN LIST
	SKIPE	P2		;IF AN RH20,
	TLO	T3,(INSVL.(.CCJMP,CC.OPC)) ; MAKE A JUMP-WORD
	MOVEM	T3,(T2)		;POINT ICWA AT IO LIST
	SKIPE	P2		;IF AN RH20,
	TDZA	T2,T2		; ICWA ISNT IN COMMAND
	LSH	T2,6		;POSITION ICWA FOR DATAO
	TRO	T2,(P1)		;INSERT FUNCTION
	TLNE	P1,(TB.DAT)	;TALK TO CS1 IF SPACE OP,
	TDO	T2,[DO1CRC!DO.DTE ;TALK TO RH10 CNTRL REG
		    .DOSTC!DO.RCP!DO.SCS!DO.DTE!177700](P2) ;OR RH20 CNTRL REG
	MOVEM	T2,E..LCM(U)	;SAVE LAST COMMAND IN UDB
	PUSHJ	P,WTMBR##	;GO START UP THE WORLD
	MOVEM	P1,TKBFLG(W)	;REMEMBER WHAT WE ARE DOING
	PUSH	P,T1		;SAVE IORB
	MOVEI	T3,TAPCHN##+CO.MBE ;PIA
	TLNN	P1,(TB.DAT)	;DATA OPERATION?
	TROA	T3,CO.AIE	;NO, ENABLE FOR ATTENTIONS
	PUSHJ	P,SETIV		;YES, SET UP INTERRUPT VECTOR
	JUMPE	P2,TM2SI6	;NO SWEAT IF RH10
	XCT	KDBCNI(W)	;DID WE WIN IN THE SETUP?
	TRNN	T1,CI.RAE	;IF RAE IS LIT WE DIDN'T
	JRST	TM2SI6		;ALL'S WELL
	TRO	T3,CO.STP	;NO, CAUSE AN IMMEDIATE INTERRUPT
	PUSHJ	P,SETIV		;SET UP INTERRUPT VECTOR
TM2SI6:	MOVE	T1,T3		;COPY CONO BITS
	XCT	KDBCNO(W)	;TURN ON RH10 PI
	POP	P,T1		;RESTORE IORB
>;FTRH11
IFN FTRH11,<
	PUSHJ	P,SETIV		;SET INTERRUPT VECTOR
	HRRZ	T2,P1		;GET FUNCTION
	TRO	T2,DC.IE	;INTERRUPT ENABLED
	MOVEM	T2,E..LCM(U)	;SAVE LAST COMMAND IN UDB
	WRIOB	T2,<(DO.CS1)>(P2)	;WRITE COMMAND, PRESERVE ADDRESS BITS
	MOVEM	P1,TKBFLG(W)	;REMEMBER WHAT WE ARE DOING
>;FTRH11
	POPJ	P,		;GO AWAY AND WAIT FOR INTERRUPT
;HERE IF THE DRIVE STATUS REGISTER ISN'T RIGHT
NOSTRT:	CAIE	T2,DS.GUD!DS.WRL	;ONLY WRITE-LOCK?
	JRST	BADSTS		;NO, IT REALLY IS BAD
	SKIPA	T2,[RB.SLK!RB.SER,,]	;WRITE-LOCKED
ILLFNC:	MOVSI	T2,RB.SER!RB.SIL	;ILLEGAL FUNCTION
ILLORM:	IORM	T2,TRBSTS(T1)	;TELL TAPUUO WHAT THE PROBLEM IS

;WE WILL NOW ISSUE AN ILLEGAL FUNCTION IN ORDER TO CAUSE AN INTERRUPT
;BUT WE CANNOT ISSUE THE COMMAND TO A DRIVE THAT IS REWINDING,
;AS THAT MIGHT HANG SOME TM03'S.  SO WE SEARCH FOR ANY DRIVE WHICH
;IS NOT REWINDING, PERHAPS EVEN A NON-EXISTANT ONE.
	MOVEI	P1,7		;START WITH DRIVE 7
ILLRM2:	MOVE	T2,P1		;TALK TO IT
	HRLI	T2,(DO.TC)	;SELECT THIS SLAVE
	PUSHJ	P,WTMBR##
	MOVSI	T2,(DO.DS)	;IS IT REWINDING?
	PUSHJ	P,RDMBR##	;READ REGISTER
	TRNE	T2,DS.PIP	;POSITIONING IN PROGRESS
	SOJGE	P1,ILLRM2	;YES, KEEP LOOKING
	MOVE	P1,FNCNOP	;FUNCTION TO CAUSE AN INTERRUPT
	JRST	TM2SI4		;GO CAUSE AN INTERRUPT

BADSTS:	TRNN	T2,DS.MOL	;IF OFFLINE,
	JRST	ILLFNC		;GIVE UP ON GETTING IT TO WORK
	TRNE	T2,DS.PIP	;IF PIP IS UP DON'T BOTHER TRYING
	TLZ	T3,-1		;AGAIN, CLRDRV WILL HANG SOME TMO3'S
	MOVSI	T2,RB.SOL!RB.SER ;SAY THE DRIVE IS DOWN
	JUMPGE	T3,ILLORM	;IF THIS IS SECOND TIME
	MOVSI	T2,(DO.TC)	;FIRST TIME-CLEAR DRIVE
	PUSHJ	P,RDMBR##	;READ REGISTER
	PUSH	P,T2		;SAVE TAPE CNTRL REG
	PUSHJ	P,CLRDRV	;DRVPOL CHANGES TC REG
	POP	P,T2		;(AND CLEARS 1ST TIME FLAG IN LH(T3))
	HRLI	T2,(DO.TC)
	PUSHJ	P,WTMBR##	;RESTORE TC REG
	TLZ	T3,-1		;NO LONGER THE FIRST TIME THROUGH
	JRST	TM2SI2		;AND TRY AGAIN
SUBTTL	INTERRUPT LEVEL PROCESSING

	;INTERRUPT CODE
	;REGISTER USAGE:
	;T1/ IORB ADDRESS
	;T2/ TEMP, MASSBUS REGISTER READ/WRITTEN
	;T3/ MASSBUS UNIT # OF TM02/3
	;T4/ DO.ER,,DO.DS - LH = 0 IF DS.ERR NOT SET
	;P1/ FNCTBL ENTRY (FLAG BITS+IORB FCN,,DF.XXX)
	;P2/ CONTROLLER TYPE / IO ADDRESS OF RH11
	;P4/ ERROR BITS
	;U/ TUB FOR IO
	;W/ TKB FOR IO

TM2ISR:	PUSHJ	P,SAVE4##	;SAVE SOME ACS
IFN FTKL10,<PUSHJ P,SVMBR##>	;SAVE CURRENT MBR FOR UUO LEVEL
	SETZ	P4,		;CLEAR ERROR FLAGS
	PUSHJ	P,SETP2		;SET P2=0 IF RH10, =1 IF RH20, CSR IF RH11
	MOVE	U,@KDBCUN(W)	;UNIT WE'RE TALKING TO (MAYBE)
IFE FTRH11,<
	MOVE	T1,KDBCSO(W)	;GET CONI BITS AT INTERRUPT
	MOVE	T1,TAPCII##(T1)
	TRNE	T1,CI.RAE	;REGISTER ACCESS ERROR?
	JRST	TM2IN3		;YES, GO CLEAR IT AND RETRY
>;FTRH11
IFN FTRH11,<
	MOVSI	T2,(DO.DS)	;READ A TM REGISTER
	PUSHJ	P,RDMBR##
	RDIO	T2,<(DO.CS2)>(P2) ;GET TM STATUS
	TRNE	T2,D2.NXD	;TM THERE?
	JRST	[SETZ T1,	;NO, TELL TAPSER NOTHING TO DO
		 POPJ P,]	;RETURN
>;FTRH11
	MOVSI	T2,(DO.TC)	;WE WILL LATER ZAP THE TC
	PUSHJ	P,RDMBR##	;READ REGISTER
	MOVEM	T2,E..TC(U)	; SO READ AND SAVE IT NOW
	MOVSI	T2,(DO.DS)	;READ STATUS REGISTER NOW, TALKING
	PUSHJ	P,RDMBR##	; TO TC REG LATER MAY CHANGE IT
	PUSH	P,T2		;SAVE STATUS REG
	MOVSI	T2,(DO.AS)	;READ THE ATTN SUMMARY REGISTER
	PUSHJ	P,RDMBR##
	ANDI	T2,377		;JUST THE ATTENTION BITS
	TDNN	T2,KDBUNI(W)	;ATTEN FOR THIS KDB?
	JRST	TM2IN2		;NO
	HRRZ	T2,KDBUNI(W)	;YES. GET THE CORRECT BIT
	HRLI	T2,(DO.AS)	;CLEAR THE BIT
	PUSHJ	P,WTMBR##
	PUSHJ	P,DRVPLX	;POLL THE DRIVES FOR REW DONE

;HERE AFTER THE ATTENTION (IF ANY) IS HANDLED
TM2IN2:	MOVE	T2,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	HRLI	T2,(DO.TC)	;SET TO RECONNECT TO DRIVE, DRVPOL MIGHT HAVE
	PUSHJ	P,WTMBR##	; SET TO TALK TO ANOTHER SLAVE
	POP	P,T4		;STATUS REGISTER
TM2IN3:	SKIPL	T1,TKBSCH(W)	;SCHEDULE CYCLE?
	SKIPN	T1,TKBFLG(W)	;OR OPERATION IN PROGRESS?
	JRST	[SETZM TKBSCH(W)
		 PJRST	CLRCTL]  ;RETURN 0 OR -1 TO TAPSER
	SETZM	TKBFLG(W)	;NOW NO OP IS GOING
	MOVE	P1,T1		;FLAGS IN P1
	LDB	P3,[POINT 4,P1,17]	;INDEX FOR FUNCTION IN P3
	PUSHJ	P,CHKIRB##	;GET THE IORB
	  JRST	TAPDIS##	;NOTHING THERE - GO AWAY
IFE FTRH11,<
	XCT	KDBDTI(W)	;DATAI
	HLL	T3,T2		;SAVE (DBTO,CBTO)
	MOVE	T2,T1		;SAVE T1
	XCT	KDBCNI(W)	;CONI
	EXCH	T2,T1		;RESTORE T1, GET RESULTS
	TLNN	T3,CBTO		;IF NOT CNTRL BUS TIMEOUT
	TRZ	T2,CI.DRE	; IGNORE DRIVE RESPONSE ERR
	JUMPE	P2,TM2IN4	;EASY WIN IF RH10
	MOVE	T3,KDBICP(W)	;RH20, GET LOGOUT AREA
	HLL	T2,1(T3)	;GET ERROR BITS FROM ICWA+1
	TLNN	P1,(TB.DAT)	;IF NOT A DATA OPERATION
	TLZA	T2,-1		; IGNORE ERROR BITS, THEY'RE USELESS
	TLC	T2,(CS.NAE)	;MAKE BIT=1 IF AN ERROR
TM2IN4:	TDNE	T2,[CI1ERR	;ERROR?
		    CS.ERR!CI.ERR](P2)
	JRST	CHNERR		;TOO BAD!
>;FTRH11
IFN FTRH11,<
	MOVEI	T2,DC.CPE	;CHANNEL-TYPE ERRORS
	MOVEI	T3,D2%CHE	;...
	TION	T2,<(DO.CS1)>(P2)
	TIOE	T3,<(DO.CS2)>(P2)
	JRST	CHNERR		;JUMP IF SO
>;FTRH11
	CAIN	P3,RB.FYB	;YELLOW BALL/ILLEGAL FNCTN?
	JRST	INTNOP		;YES, GO HANDLE IT
	TRNN	T4,DS.ERR	;ERROR?
	JRST	TSTERR		;NO
	MOVSI	T2,(DO.ER)	;YES, READ ERROR REG
	PUSHJ	P,RDMBR##	;(ONLY CALL RDMBR ON "REAL" ERROR)
	HRL	T4,T2		;T4=ERROR,,STATUS
	JRST	TSTBOT
TSTERR:	SKIPE	TUBERR(U)	;IN ERROR RETRY?
	PUSHJ	P,RDREGS	;YES, GET FINAL (GOOD) REGISTERS
TSTBOT:	MOVSI	T2,TUSBOT##	;CLEAR BOT
	ANDCAM	T2,TUBSTS(U)
	TRNE	T4,DS.BOT	;AND SET IT IF WE REALLY ARE
	IORM	T2,TUBSTS(U)	; AT BOT
	MOVSI	T2,TUSWTL##	;CLEAR WRITE-LOCK
	ANDCAM	T2,TUBSTS(U)
	TRNE	T4,DS.WRL	;AND SET IT AGAN IF WE REALLY ARE
	IORM	T2,TUBSTS(U)	; WRITE LOCKED
	TRNN	T4,DS.BOT	;AT BOT?
	JRST	TSTMOV		;NO
	TLO	P4,RB.SBT	;YES, TELL TAPUUO
	PUSHJ	P,UNIBOT##	;CLEAR TUBREC,FIL; SET TUBSTS
	JUMPGE	P1,TSTMOV	;IF WE MOVED BACKWARDS INTO BOT,
	TLNN	P1,(TB.DAT)	;DATA OPERATION?
	TLZ	T4,ER.COR!ER.FCE ;CAN'T BE ERROR AT BOT
	TLZE	T4,ER.OPI!ER.NEF; THESE REALLY AREN'T ERRORS
	JRST	NOMOVE		;IF ON WE DIDN'T MOVE TAPE

TSTMOV:	TLNN	T4,ER.ILF!ER.RMR!ER.NEF!ER.UNS
	JRST	MOVED		;TAPE REALLY MOVED

	TLOA	P4,RB.SNM!RB.SED;TAPE DIDN'T MOVE
NOMOVE:	TLO	P4,RB.SNM
	JRST	TM2GO		;CONTINUE
MOVED:	TLNE	P1,(TB.REV)	;REVERSE?
	SOSA	TUBREC(U)	;DECR OR INCR RECORD COUNT
	AOS	TUBREC(U)
	TRNN	T4,DS.TM	;PASS OVER (OR JUST WROTE) EOF?
	JRST	NOTM		;NO
	TLNE	P1,(TB.REV)	;YES, INCR OR DECR FILE COUNT
	SOSA	TUBFIL(U)
	AOS	TUBFIL(U)
	SETZM	TUBREC(U)	;AT 0TH RECORD ********* -1 IF REV?
	TLNN	P1,(TB.WRT)	;IF NOT WRITING AN EOF,
	TLO	P4,RB.STM	; TELL TAPUUO WHAT WE SAW
NOTM:	TLNE	P1,(TB.WRT)	;IF WRITING,
	TRNN	T4,DS.EOT	;AND WE SAW EOT
	CAIA
	TLO	P4,RB.SET	;TELL TAPUUO
TM2GO:	JRST	@INTABL(P3)	;GO TO SPECIFIC INTERRUPT HANDLER


INTABL:	IFIW	TAPIFI##	;(00) ILLEGAL
	IFIW	INTRD		;(01) READ FORWARD
	IFIW	INTWRT		;(02) WRITE
	IFIW	INTRD		;(03) READ BACKWARDS
	IFIW	INTSPC		;(04) SKIP RECORD
	IFIW	INTSPC		;(05) BACKSPACE RECORD
	IFIW	INTSPC		;(06) SKIP FILE
	IFIW	INTSPC		;(07) BACKSPACE FILE
	IFIW	INTERA		;(10) ERASE GAP
	IFIW	TAPIFI##	;(11) DATA SECURITY ERASE
	IFIW	INTREW		;(12) REWIND
	IFIW	INTUNL		;(13) UNLOAD
	IFIW	INTWTM		;(14) WRITE TAPE MARK
	IFIW	INTNOP		;(15) YELLOW BALL/ILLEGAL FUNCTIONS
	IFIW	INTRD		;(16) CORRECTION READ
	IFIW	INTRD		;(17) LOW-THRESHOLD READ
;HERE ON READ INTERRUPT
INTRD:	MOVEI	T2,RB.D16	;ASSUME DRIVE IN PE MODE
	TRNN	T4,DS.PES	;ARE WE?
	MOVEI	T2,RB.D8	;NO, ASSUME 800 NRZI
	LDB	T3,PRBDEN	;GET WHAT DDB (IORB) SAYS
	CAIE	T2,RB.D16	;IF DRIVE SAYS PE, MAKE MONITOR AGREE
	CAIN	T3,RB.D16	;NOT PE; IF MONITOR THINKS PE, CHANGE TO 800
	DPB	T2,PRBDEN	;UPDATE IORB (AND EVENTUALLY DDB)
	MOVSI	T2,(DO.FC)	;READ THE FRAME COUNTER
	PUSHJ	P,RDMBR##
	MOVEM	T2,TRBRCT(T1)	;SAVE CHAR-COUNT OF RECORD
	MOVEM	T2,TUBCCR(U)
	ADDM	T2,TUBCRD(U)	;UPDATE TOTAL STATS
	ADDM	T2,TKBCRD(W)
	ADDM	T2,.CPTFI##
	CAMLE	T2,TKBCHR(W)	;TOO LARGE A RECORD?
	TLO	P4,RB.STL!RB.SER ;YES, TELL TAPUUO
	LDB	T3,PRBMOD##	;MODE
	IDIV	T2,TMODTB##(T3);COMPUTE NUMBER OF WORDS XFERRED
	HRLM	T2,TUBCHR(U)	;SAVE WORDS
	DPB	T3,PMTNCR##	;SAVE RESIDUE

IFE FTRH11,<	;THE KS UBA DOES THIS
	CAIE	P3,RB.FRB	;IF READ BACKWARDS
	JRST	DONE		;NO
	SKIPE	T3		;IF NOT EVEN NO OF WORDS
	ADDI	T2,1		;BUMP WRDCNT
	JUMPE	T2,DONE		;NULL RECORD
	HRRZ	P1,TM2UVA(W)	;GET USER VIRTUAL ADDRESS
	MOVE	F,TUBCUR(U)	;MAKE JOB ADDRESSABLE
	PUSHJ	P,SVEUF##

	PUSH	P,T1
	LDB	T3,PRBMOD##	;SINCE THE TM02 READS BACKWARDS
	MOVE	T2,TKBCHR(W)	; IN REVERSE ORDER, HALVES SWAPPED
	IDIV	T2,TMODTB##(T3)	; WE HAVE TO REARRANGE THE DATA
	AOS	P3,P1		;FIRST WORD
	ADDI	P3,-1(T2)	;LAST WORD
	LSH	T2,-1
INTRD1:	EXCTUX	<MOVE T3,@P1>	;GET 2 WORDS
	EXCTUX	<MOVE T1,@P3>
	EXCTXU	<MOVSM T3,@P3>	;SWAP HALVES AND INVERT ORDER
	EXCTXU	<MOVSM T1,@P1>
	ADDI	P1,1
	SUBI	P3,1
	SOJG	T2,INTRD1	;DO FOR WHOLE BLOCK
	POP	P,T1
	CAMN	P1,P3		;IF AN ODD NUMBER OF WORDS,
	EXCTUU	<MOVSS @P1>	; SWAP HALVES OF MIDDLE WORD OF BLOCK
>;FTRH11
;	JRST	DONE		;OPERATION COMPLETE
;HERE AFTER AN OPERATION IS THROUGH
DONE:	TLNE	T4,-1		;ERROR BIT UP?
	PUSHJ	P,TM2ERR	;YES, GO HANDLE IT
TRBSTO:	IORM	P4,TRBSTS(T1)	;STORE ERROR BITS IN THE IORB
TRBEXC:	MOVSI	T2,RB.EXC
	TLZE	P4,-1		;ANY FUNNY THINGS?
	IORM	T2,TRBFNC(T1)	;YES, AN EXCEPTION HAS OCCURRED

IFE FTRH11,<
CLRCTL:	PUSH	P,T1		;SAVE IORB
	MOVE	T1,[CO1CLR
		    CO.CLR+CO.MBE](P2)
	MOVE	T2,KDBCSO(W)	;GET CONI BITS AT INTERRUPT
	MOVE	T3,TAPCII##(T2)
	TRZE	T3,CI.DON	;DONE LIT?
	TRO	T1,CO.CCD	;YES, CLEAR IT ALSO
	MOVEM	T3,TAPCII##(T2)
	XCT	KDBCNO(W)
	SKIPA			;ONWARD
CLRCTX:	PUSH	P,T1		;SAVE T1
	MOVEI	T1,TAPCHN##+CO.AIE+CO.MBE	;ENABLE FOR INTERRUPTS
	XCT	KDBCNO(W)
	SETZM	TKBFLG(W)	;NOTHING HAPPENING NOW
	POP	P,T1		;RESTORE T1
	POPJ	P,		;AND RETURN
>;FTRH11
IFN FTRH11,<
CLRCTL:	MOVEI	T2,D2.CLR	;CLEAR ALL ERRORS
	WRIO	T2,<(DO.CS2)>(P2);
CLRCTX:	MOVE	T2,[DO.CS1+DC.IE] ;ENABLE FOR INTERRUPTS
	PUSHJ	P,WTMBR##
	SETZM	TKBFLG(W)	;NOTHING HAPPENING NOW
	POPJ	P,		;AND RETURN
>;FTRH11
;HERE ON WRITE INTERPT
INTWRT:	MOVE	T2,TKBCHR(W)	;NO OF FRAMES WE WROTE
	ADDM	T2,TUBCWR(U)	;UPDATE STATS
	ADDM	T2,TKBCWR(W)
	ADDM	T2,.CPTFO##
	JRST	DONE		;AND FINISH UP

INTSPC:	JRST	DONE

INTWTM:	JRST	DONE

INTERA:	SOS	TUBREC(U)	;IT ISN'T ANOTHER RECORD
	JRST	DONE

INTUNL:	MOVSI	T2,TKSOFL##	;LET REST OF WORLD KNOW
	IORM	T2,TUBSTS(U)	; THAT THE DRIVE IS OFF-LINE
	TLO	P4,RB.SOL	;SAY DRIVE IS OFF-LINE

INTREW:	MOVSI	T2,TUSREW##	;SAY WE'RE REWINDING
	IORM	T2,TUBSTS(U)
	TRNN	T4,DS.PIP	;ARE WE?
	PUSHJ	P,REWDON##	;NO, MUST HAVE FINISH
	SETZM	TUBREC(U)	;CLEAR STATS
	SETZM	TUBFIL(U)
	JRST	DONE		;AND FINISH UP

INTNOP:	MOVSI	T2,(DO.DS)	;DON'T CLEAR IF REWINDING
	PUSHJ	P,RDMBR##	;THAT WILL HANG SOME TM03'S
	TRNN	T2,DS.PIP
	PUSHJ	P,CLRDRV	;CLEAR THE DRIVE
	HLLZ	P4,TRBSTS(T1)	;GET ERROR BITS
	MOVSI	T2,TKSOFL##	;DRVPOL MAY HAVE CLEARED TKSOFL
	TLNE	P4,RB.SOL	;IS TKSOFL SUPPOSED TO BE ON?
	IORM	T2,TUBSTS(U)	;YES, MAKE SURE IT IS
	JRST	TRBEXC		;SET EXCEPTION IF AN ERROR
	SUBTTL	RH10/20/11 ERROR ANALYSIS

;HERE ON CONI ERROR BIT OR CHANNEL ERROR
CHNERR:
IFE FTRH11,<
	TDNN	T2,[CI1SDR,,
		CI.RAE](P2)
	JRST	NORAE		;NO
	JUMPE	P2,CHNER1
	TLO	P4,RB.SNM!RB.SED ;YES, NO TAPE MOTION+ERROR
	JRST	TRBSTO

CHNER1:	HRRZ	T2,KDBUNI(W)	;YES. GET BIT TO CLEAR
	HRLI	T2,(DO1CRA)	;CLEAR REG ACCESS ERROR
	PUSHJ	P,WTMBR##
	JRST	CHNRTY		;AND RETRY THE OPERATION

NORAE:	TDNN	T2,[CI1CDP!CI1CWP!CI1NXM,,
		    CS.MPE!CS.NXM](P2)
	JRST	CHNRTY		;NO, JUST RETRY
	PUSHJ	P,SAVE1##	;YES
	PUSH	P,T1		;SAVE T1
	PUSH	P,T4		;SAVE T4
	MOVEI	T3,CHENXM##	;SET TO CALL RIGHT ROUTINE
	MOVSI	T4,IOCHNX	;ASSUMING NXM
	TDNN	T2,[CI1NXM,,
		    CS.NXM](P2)
	PUSHJ	P,[MOVEI T3,CHEMPE## ;NO--SET FOR MEMORY PARITY
		   MOVSI T4,IOCHMP	; ...
		   POPJ P,]
	MOVE	T1,KDBICP(W)	;T1=ICWA
	MOVE	P1,KDBCHN(W)	;P1=CDB
	MOVE	F,TUBCUR(U)	;F=DDB
	IORM	T4,CHNNUM(P1)	;MARK MEMORY ERROR FOR LATER SWEEP
	SKIPN	TUBERR(U)	;CALL ERRCON ON FIRST ERROR ONLY
	PUSHJ	P,(T3)		;GO CALL ERRCON
	POP	P,T4
	POP	P,T1
CHNRTY:>;FTRH11
IFN FTRH11,<
	MOVE	T3,KDBCHN(W)	;GET CHANNEL DATA BLOCK
	MOVEI	T2,UNBTMO!UNBBME
	BSIO	T2,@CHNUBA(T3) ;CLEAR POSSIBLE UBA ERRORS
>;FTRH11
	TLO	P4,RB.SED	;INDICATE AN ERROR
	PJRST	TRBSTO		;FINISH UP
	SUBTTL	TM02/TM03 ERROR ANALYSIS

;HERE ON ERROR BIT IN TM02
TM2ERR:	TLNN	T4,ER.UNS!ER.FMT!ER.ILR!ER.ILF!ER.OPI!ER.NEF
	JRST	TM2ER1		;NOT AN IMMEDIATE PROBLEM
	TLNE	T4,ER.FMT	;FORMAT ERROR?
	TLNN	T4,ER.COR!ER.CS!ER.FCE!ER.NSG!ER.LRC!ER.INC
	CAIA			;REAL NON-RECOVERABLE ERR
	JRST	TM2ER1		;FAKE FORMAT ERROR
	TLNE	T4,ER.UNS	;REALLY BAD PROBLEM
	TLO	P4,RB.SOL	;OFFLINE IF UNSAFE IS UP
	TLO	P4,RB.SED!RB.SER;NON-RECOVERABLE ERROR
	PJRST	CLRDRV		;DRIVE-CLEAR AND RETURN

TM2ER1:	TLNE	P1,(TB.WRT)	;IF READING,
	JRST	TM2ER2
	TLZ	T4,ER.NSG!ER.FCE	;THESE AREN'T ERRORS

	TRNE	T4,DS.PES	;IF IN PE MODE
	TLZ	T4,ER.COR!ER.CS!ER.LRC	;THESE AREN'T ERRORS

TM2ER2:	TLNN	T4,ER.COR!ER.CS!ER.FCE!ER.NSG!ER.LRC!ER.DPA!ER.INC!ER.DTE!ER.CPA
	PJRST	CLRDRV		;NOT A "REAL" ERROR, CLEAR DRIVE AND RETURN
	TLNN	T4,ER.COR!ER.CS!ER.INC!ER.LRC	;REAL ERROR
	TLOA	P4,RB.SED	;PLAIN ERROR
	TLO	P4,RB.SDE!RB.SED	;DATA ERROR
	PUSHJ	P,RDREGS	;READ DRIVE REGS INTO UDB
				;FALL INTO CLRDRV AND RETURN
	SUBTTL	DRIVE CLEAR LOGIC

;DUE TO THE PROBLEM OF DRIVE CLEAR MAKING DS.SSC GO AWAY
; IF SOME OTHER SLAVE BROUGHT IT UP, WE HAVE TO POLL THE DRIVES
; AFTER A DRIVE CLEAR TO FIND ANY THAT MAY HAVE FINISHED REWINDING
CLRDRV:	MOVEI	T2,DF.CLR	;CLEAR THE DRIVE
	PUSHJ	P,WTMBR##

DRVPOL:	PUSH	P,T4		;SAVE T4
	PUSHJ	P,DRVPLX
	PJRST	T4POPJ##	;RESTORE T4 AND RETURN

DRVPLX:	PUSHJ	P,SAVE4##	;SAVE SOME ACS
	SETZ	P4,		;SET A FLAG
	PUSH	P,U		;SAVE U
	MOVE	T4,KDBIUN(W)	;POINTER TO UDB TABLE
	ADDI	T4,(P1)		;INDEX INTO TABLE
	MOVE	T4,(T4)		;FETCH ENTRY (UDB ADDRESS)
DRVPL5:	MOVSI	T2,(DO.DS)	;READ STATUS REG
	PUSHJ	P,RDMBR##
	TRNN	T2,DS.SSC	;SLAVE STATUS CHANGE?
	JRST	DRVPL2		;NO
IFN 1,<
;YES, WE HAVE TO FIND A DRIVE WE CAN CLEAR.
;OUR CHOICE OF WHAT DRIVE TO CLEAR DEPENDS ON
;WHAT TYPE OF DRIVES WE'VE GOT.
;FOR MOST TYPES WE CAN GET AWAY WITH CLEARING ANY DRIVE
;(EVEN A NON-EXISTENT ONE).
;BUT FOR CERTAIN TYPES WE MUST ISOLATE THE EXACT DRIVE THAT RAISED SSC.
;IN ORDER TO FIGURE OUT WHAT TYPE OF DRIVE WE'VE GOT, WE MUST
;FIRST LOCATE A DRIVE THAT ACTUALLY EXISTS. THE DRIVE WHICH
;IS CURRENTLY SELECTED IN TC MAY NO LONGER EXIST (AS THE OPR
;MAY HAVE PLAYED WITH THE THUMB WHEEL).
	SETZ	P1,		;START WITH DRIVE 0
DRVPL7:	MOVE	T2,P1		;SELECT THE DRIVE
	HRLI	T2,(DO.TC)
	PUSHJ	P,WTMBR##
	MOVSI	T2,(DO.DT)	;GET THE DRIVE TYPE
	PUSHJ	P,RDMBR##
	TRNE	T2,7		;DOES THE DRIVE EXIST?
	JRST	DRVPL8		;YES
	CAIE	P1,7		;NO, KEEP LOOKING
	AOJA	P1,DRVPL7

DRVPL8:	ANDI	T2,75		;GET RID OF NOISE BITS
	CAIE	T2,11		;TM02/TE16?
	CAIN	T2,51		;TM03/TE16?
	TDZA	P3,P3		;YES, CLEAR ALL DRIVES
	MOVEI	P3,-54(T2)	;IF TU77 IT MUST BE THE DRIVE WHICH RAISED SSC
	JUMPE	P3,DRVPL0	;GO IF ONE OF THE SPECIAL TYPES
;HERE IF NOT ONE OF THE SPECIAL TYPES.
;WE MUST NOW FIND A NON-EXISTANT DRIVE AND CLEAR IT.
	MOVEI	P1,7		;START WITH DRIVE 7
DRVPL6:	MOVE	T2,P1		;SELECT THE DRIVE
	HRLI	T2,(DO.TC)
	PUSHJ	P,WTMBR##
	MOVSI	T2,(DO.DT)	;GET THE DRIVE TYPE
	PUSHJ	P,RDMBR##
	TRNE	T2,7		;DOES THE DRIVE EXIST?
	SOJGE	P1,DRVPL6	;YES, KEEP LOOKING
	TLOE	P1,-1		;DID WE FIND ONE?
>
DRVPL0:	MOVSI	P1,-10		;NO, CLEAR EVERYTHING NOT REWINDING
FNDCLR:	SKIPE	T2,TKBFLG(W)	;IF WE'RE ACTIVELY TALKING TO A DRIVE
	MOVE	T2,KDBCUN(W)	;DONT CLEAR THAT DRIVE
	CAMN	T2,T4
	JUMPE	P4,FNDCL1	;SO TRY ANOTHER
	MOVE	T2,P1		;WE CAN DO A DRIVE CLEAR ON THIS ONE
	HRLI	T2,(DO.TC)	;TALK TO THIS DRIVE
	PUSHJ	P,WTMBR##
	MOVSI	T2,(DO.DS)
	PUSHJ	P,RDMBR##	;READ SLAVE'S STATUS REGISTER
	TRNE	T2,DS.PIP	;IS DRIVE REWINDING?
	JUMPE	P4,FNDCL1	;YES (TU77). DON'T CLEAR AS THAT WILL HANG TM03
	MOVEI	T2,DF.CLR	;DO A DRIVE CLEAR
	PUSHJ	P,WTMBR##
FNDCL1:	AOBJN	P1,FNDCLR	;CLEAR NEXT DRIVE

	CAIGE	P4,3		;TRIED ENOUGH TIMES?
	AOJA	P4,DRVPL5	;NO, KEEP TRYING
IFE FTRH11,<
	PUSH	P,T1		;YES, SAVE TM03 NUMBER
	MOVEI	T1,CO.MBI	;THE TM03 MUST BE HUNG
	XCT	KDBCNO(W)	;MASSBUS INIT IS THE ONLY WAY
	JUMPE	P2,DRVPL9	;EASY IF RH10
	MOVEI	T1,CO.MBE	;ENABLE MASSBUS TRANSMITTERS
	XCT	KDBCNO(W)	;BUT DON'T ENABLE INTERRUPTS TILL LATER
	PUSHJ	P,SETIV		;RESTORE INTERRUPT VECTOR

DRVPL9:	POP	P,T1		;RESTORE TM03 NUMBER
>;FTRH11
IFN FTRH11,<
	MOVEI	T2,D2.CLR	;THE TM03 MUST BE HUNG
	WRIO	T2,<(DO.CS2)>(P2);MASSBUS INIT IS THE ONLY WAY
	PUSHJ	P,SETIV		;RESTORE INTERRUPT VECTOR
>;FTRH11
DRVPL2:	MOVE	T4,KDBIUN(W)	;POINTER TO UDB TABLE
DRVPL3:	PUSHJ	P,DRVKNO	;DO WE KNOW ABOUT THIS DRIVE?
	  JRST	DRVPL4		;NO
	MOVSI	P3,TKSOFL##	;BIT TO TEST
	TDNE	P3,TUBSTS(U)	;IF DRIVE WAS OFF-LINE
	TRNN	T2,DS.MOL	; AND IS NOW ON-LINE
	CAIA
	PUSHJ	P,NOWON		;LET THE WORLD KNOW
	TRNE	T2,DS.MOL	;OFF LINE?
	ANDCAB	P3,TUBSTS(U)	;NO
	TRNN	T2,DS.MOL
	IORB	P3,TUBSTS(U)	;YES
	TLNE	P3,TUSREW##	;WAS IT LAST REWINDING?
	TRNE	T2,DS.PIP	;YES, IS IT NOW
	JRST	DRVPL4		;YES, CONTINUE WITH NEXT DRIVE
	PUSHJ	P,REWDON##	;THROUGH REWINDING, TELL TAPUUO
DRVPL4:	CAMGE	T4,KDBFUN(W)	;FINAL UDB?
	AOJA	T4,DRVPL3	;LOOP FOR MORE
	JRST	UPOPJ##		;DONE, RETURN


;SUBROUTINE TO TELL TAPUUO WHEN A SLAVE COMES ON-LINE
;PRESERVES ALL ACS
NOWON:	PUSHJ	P,SAVT##	;SAVE T1-T4
	PJRST	TPMONL##	;AND TELL TAPUUO


;HERE TO SEE IF THE DRIVE IN QUESTION IS KNOWN
DRVKNO:	MOVE	T2,T4		;COPY UDB TABLE ADDRESS
	SUB	T2,KDBIUN(W)	;COMPUTE PHYSICAL DRIVE NUMBER
	HRLI	T2,(DO.TC)	;TAPE TRANSPORT REGISTER
	PUSHJ	P,WTMBR##	;CONNECT TO THAT DRIVE
	MOVSI	T2,(DO.DS)	;DRIVE STATUS REGISTER
	PUSHJ	P,RDMBR##	;READ IT
	SKIPE	U,(T4)		;POINT TO UDB FOR SELECTED DRIVE
	JRST	CPOPJ1##	;WE KNOW ABOUT THIS ONE
	MOVSI	T2,(DO.DT)	;DRIVE TYPE REGISTER
	PUSHJ	P,RDMBR##	;READ REGISTER
	TRNN	T2,DT.SPR	;SLAVE PRESENT?
	POPJ	P,		;NO
	MOVE	T2,T4		;COPY UDB TABLE ADDRESS
	SUB	T2,KDBIUN(W)	;COMPUTE PHYSICAL DRIVE NUMBER
	MOVE	T2,BITTBL##(T2)	;TRANSLATE TO APPROPRIATE BIT
	TDNN	T2,TM2IUM(W)	;WANT TO IGNORE THIS DRIVE?
	IORM	T2,TM2NUM(W)	;MARK NEW DRIVE TO CONFIGURE
	HRRZS	KDBNUM(W)	;ASSUME NOT THERE
	SKIPE	TM2NUM(W)	;DRIVES TO CONFIGURE?
	HRROS	KDBNUM(W)	;FLAG IT
	POPJ	P,		;SAY NO DRIVE (WILL CONFIGURE LATER)
	SUBTTL	AUTO-CONFIG

TM2CFG:
IFN FTKL10,<
	CAIL	T1,FSTICD/4	;AN RH20?
	CAILE	T1,LSTICD/4	;...
	JRST	TM2CF1		;PERHAPS AN RH10
	TLNE	T2,(CI.PPT)	;IPA CHANNEL?
	JRST	CPOPJ1##	;YES
	MOVSI	T1,CP.RH2	;RH20 CHANNEL
	JRST	TM2CF2		;ONWARD
TM2CF1:
> ;END IFN FTKL10
	XMOVEI	T1,TM2MDT##	;MONGEN'ED DEVICE TABLE
	XMOVEI	T2,DEFMDT	;DEFAULT TABLE
	MOVSI	T3,-1		;MATCH ON ANY MASSBUS UNIT
	MOVEI	T4,MD.KON	;MATCH ON KONTROLLER DEFINITION
	PUSHJ	P,AUTMDT##	;SCAN THE TABLES
	  JRST	CPOPJ1##	;NO MATCHES
IFN FTKL10,<
	XCT	.CPCNI##	;GET CONI ,T1
	TLNN	T1,4000		;CHECK FOR DF10 OR DF10C IN 18-BIT MODE
	JRST	AUTEBD##	;18-BIT DF10/DF10C, INFORM OF ERROR AND RETURN
	MOVSI	T1,0		;RH10 CHANNEL
>; END IFN FTKL10
IFN FTKS10,<MOVSI T1,CP.R11>	;RH11 CHANNEL

TM2CF2:	PUSHJ	P,AUTCHN##	;BUILD A CHANNEL DATA BLOCK
	  POPJ	P,		;NO CORE
IFN FTKS10,<
	LDB	T1,[POINT 3,.CPDVC##,17] ;GET UNIBUS ADAPTER NUMBER
	MOVEI	T2,20		;NUMBER OF MAPPING REGISTERS REQUIRED
	PUSHJ	P,AUTAMR##	;ALLOCATE MAPPING REGISTERS
	  POPJ	P,		;OOPS
	MOVE	T4,.CPCHA##	;GET CHANNEL DATA BLOCK ADDRESS
	MOVEM	T1,CHNIMR(T4)	;STORE INITIAL MAPPING REGISTERS
	MOVEM	T2,CHNMRC(T4)	;STORE NUMBER OF MAPPING REGISTERS
	MOVEM	T3,CHNIEA(T4)	;STORE INITIAL ELEVEN ADDRESS
>; END IFN FTKS10
	PUSHJ	P,SAVE2##	;SAVE P1-P2
	SETZ	P1,		;MASSBUS UNIT NUMBER 0, DRIVE 0

TM2CF3:	PUSHJ	P,TM2UNI	;AUTOCONFIGURE A SINGLE RH20 UNIT
	HLLOS	P1		;RESET DRIVE NUMBER
	AOBJN	P1,.+1		;ADVANCE TO NEXT MASSBUS UNIT
	TLNN	P1,10		;CHECKED ALL UNITS?
	JRST	TM2CF3		;LOOP BACK FOR ANOTHER
IFN FTRH11,<PUSHJ P,CLRCTL>	;CLEAR THE RH11
	JRST	CPOPJ1##	;TRY ANOTHER DEVICE ON SAME CHANNEL
;AUTOCONFIGURE A SINGLE MASSBUS UNIT
TM2UNI:	PUSHJ	P,RDDTR##	;READ DRIVE TYPE REGISTER
	CAIL	T2,TY.T2L	;RANGE CHECK
	CAILE	T2,TY.T2H	; FOR TM02
	CAIL	T2,TY.T3L	;RANGE CHECK
	CAILE	T2,TY.T3H	; FOR TM03
	POPJ	P,		;NOT A TM02/TM03
	HLRZ	T1,P1		;GET MASSBUS UNIT NUMBER
	PUSHJ	P,AUTKDB##	;BUILD A KDB
	  POPJ	P,		;GIVE UP IF NO CORE
	PUSHJ	P,SETP2		;SETUP P2 WITH CONTROLLER TYPE
	SETZB	T1,T2		;NO KONTROLLER SERIAL NUMBER
	PUSHJ	P,AUTKSN##	;DUMMY ONE UP AND STORE IT
IFN FTKL10,<
	PUSHJ	P,TAPCSA##	;SET UP CSO CONI ADDRESS
	MOVEI	T1,CO.MBI	;CLEAR ANY PENDING INTERRUPTS
	XCT	KDBCNO(W)	;CONO
	MOVEI	T1,CO.MBE	;MASSBUS ENABLE
	XCT	KDBCNO(W)	;CONO
	PUSHJ	P,TM2ONL	;IF NOT THERE
	  POPJ	P,		; DON'T SET UP CONSO MASK
> ;END IFN FTKL10
	PUSHJ	P,SETIV		;SET UP INTERRUPT VECTOR
	MOVSI	T2,(DO.DT)	;GET DRIVE TYPE REGISTER
	PUSHJ	P,RDMBR##	;...
	TRNN	T2,TR.DRQ	;DRIVE REQUEST REQUIRED (DUAL PORTED)?
	JRST	TM2UN1		;NO
	MOVEI	T2,2		;THERE CAN BE TWO PATHS
	DPB	T2,[POINTR (KDBSTS(W),KD.MPT)] ;STORE COUNT
	MOVSI	T2,(KD.MPD)	;GET MULTI-PORTED BIT
	IORM	T2,KDBSTS(W)	;LITE FOR FUTURE REFERENCE

TM2UN1:	MOVNI	P3,1		;INIT DRIVE NUMBER

TM2UN2:	PUSHJ	P,TM2DRV	;AUTOCONFIGURE A SINGLE DRIVE
	  JFCL			;IGNORE ERRORS
	HRRZ	T1,P1		;GET DRIVE NUMBER
	CAIGE	T1,TM2HDN	;DONE ALL DRIVES?
	AOJA	P1,TM2UN2	;LOOP BACK FOR MORE
	POPJ	P,		;DONE
;AUTOCONFIGURE A SINGLE DRIVE
TM2DRV:	HRRZ	T1,P1		;GET UNIT
	MOVE	T1,BITTBL##(T1)	;AND IT'S BIT
	TDNE	T1,TM2IUM(W)	;WANT TO IGNORE THIS DRIVE?
	POPJ	P,		;SAY IT DOESN'T EXIST
IFN FTKL10,<
	MOVE	T1,KDBCSO(W)	;GET TAPICD BLOCK ADDRESS
	SETZM	TAPCII##(T1)	;DON'T CONFUSE CLRCTL
>
	PUSHJ	P,CLRCTL	;RESET CONTROLLER
	HRRZ	T2,P1		;DRIVE NUMBER
	HRLI	T2,(DO.TC)	;SET TO TALK TO THIS DRIVE
	PUSHJ	P,WTMBR##	;WRITE REGISTER
	MOVSI	T2,(DO.DT)	;DRIVE TYPE REGISTER
	PUSHJ	P,RDMBR##	;READ REGISTER
	TRNN	T2,DT.SPR	;SLAVE PRESENT?
	PJRST	CLRCTL		;NO, CLEAR CONTROLLER AND RETURN
	HRRZ	T1,P1		;GET DRIVE NUMBER
	SETCA	T1,BITTBL##(W)	;TRANSLATE DRIVE NUMBER TO A BIT
	SETZ	T2,		;ASSUME NO OTHER NEW DRIVES
	SYSPIF			;AVOID RACE WITH INTERRUPT LEVEL
	ANDB	T1,TM2NUM(W)	;CLEAR SINCE DRIVE IS NO LONGER "NEW"
	SKIPE	T1		;WORK PENDING FOR OTHER DRIVES?
	MOVNI	T2,1		;YES
	HLLM	T2,KDBNUM(W)	;UPDATE FLAG
	SYSPIN			;RELEASE INTERLOCK
	MOVSI	T2,(DO.SN)	;MASSBUS REGISTER
	PUSHJ	P,RDMBR##	;READ DRIVE SERIAL NUMBER
	SETZ	T1,		;REALLY A ONE WORD QUANTITY
	HRRZ	T3,P1		;GET PHYSICAL DRIVE NUMBER
	PUSHJ	P,AUTDSN##	;FAKE UP S/N IF A ZERO & SAVE TEMPORARILY
	HRRZ	T3,P1		;GET PHYSICAL DRIVE NUMBER
	PUSHJ	P,AUTDPU##	;LINK UP DUAL PORTED DRIVES
	  JFCL			;MUST PROCEED EVEN IF DUAL PORTED
	HRLZ	T1,P1		;PHYSICAL DRIVE NUMBER
	HRR	T1,P1		;UDB TABLE INDEX
	PUSHJ	P,RDDTN##	;GET DRIVE TYPE NAME
	MOVE	T4,T2		;COPY TO A BETTER PLACE
	MOVEI	T2,TUCFOI##+TUCIRD##+TUCD80##+TUCD16##+K.TM2
	XMOVEI	T3,HNGTBL	;POINT TO HUNG TIMER TABLE
	PUSHJ	P,TAPDRV##	;BUILD AND LINK UP UDB AND DDB
	  JFCL			;FAILED
	DMOVE	T1,.CPTSN##	;RETRIEVE DRIVE SERIAL NUMBER
	DMOVEM	T1,UDBDSN(U)	;SAVE IN UDB
	MOVEM	T2,E..SN(U)	;SAVE FOR DIAGNOSTICS
	MOVE	T2,UDBPDN(U)	;PHSICAL DRIVE NUMBER
	HRLI	T2,(DO.TC)	;SELECT RIGHT SLAVE
	PUSHJ	P,WTMBR##	;DATAO
	MOVSI	T2,(DO.DS)	;READ STATUS REG
	PUSHJ	P,RDMBR##	;DATAI
	MOVSI	T3,TKSOFL##	;BIT TO SET
	TRNN	T2,DS.MOL	;IF NOT MEDIUM-ON-LINE
	IORM	T3,TUBSTS(U)	; THE DRIVE IS OFF-LINE
	PUSHJ	P,CLRCTL	;RESET CONTROLLER
	JRST	CPOPJ1##	;RETURN
	SUBTTL	CHECK ON-LINE STATUS

;HERE TO CHECK IF ON-LINE
TM2ONL:
IFE FTRH11,<XCT	KDBCNI(W)>
	PUSHJ	P,SAVST2	;SETUP P2 (IF KL, DOES CONO)
	PUSH	P,T1		;SAVE T1
IFN FTRH11,<
	MOVE	T1,P2		;GET IO ADDRESS OF RH11
	PUSHJ	P,UBGOOD##	;BE SURE IT IS THERE
	  JRST	TPOPJ##		;OFF-LINE
	MOVSI	T2,(DO.DS)	;READ A TM REGISTER
	PUSHJ	P,RDMBR##
	RDIO	T2,<(DO.CS2)>(P2) ;GET STATUS REGISTER
	TRNN	T2,D2.NXD	;IS TM03 THERE?
	JRST	TM2ON1		;YES, CHECK DRIVE TYPE
	MOVEI	T2,D2.CLR	;NO--DO CONTROLLER CLEAR
	WRIO	T2,<(DO.CS2)>(T1); IN CASE IT COMES BACK TO CLEAR NXD
	JRST	TPOPJ##		;OFF-LINE RETURN
TM2ON1:
>;FTRH11
	MOVSI	T2,(DO.DT)
	PUSHJ	P,RDMBR##	;READ DRIVE-TYPE
	ANDI	T2,730
	CAIN	T2,10		;LEGAL?
	AOS	-1(P)		;YES. SKIP-RETURN
	POP	P,T3		;GET SAVED STATUS
IFE FTRH11,<
	MOVEI	T1,CO.AIE+TAPCHN## ;PIA AND ATTN ENABLE
	SKIPE	P2
	TRO	T1,CO.MBE+CO.RAE
	TRNN	T3,CO.AIE	;WERE ATTENS ENABLED?
	TRZ	T1,CO.AIE	;NO, DON'T ENABLE THEM NOW
	XCT	KDBCNO(W)
>;FTRH11
	SKIPE	T1,TM2NUM(W)	;GET BIT MASK
	JFFO	T1,TM2ON2	;FIND FIRST UNIT NUMBER
	HRRZS	KDBNUM(W)	;INDICATE NO DRIVES TO CONFIGURE
	POPJ	P,		;DONE
TM2ON2:	PUSHJ	P,AUTLOK##	;GET AUTCON INTERLOCK
	  JRST	CPOPJ1##	;TRY AGAIN NEXT TIME
	MOVEI	P1,(T2)		;GET PHYSICAL DRIVE NUMBER
	HLL	P1,KDBUNI(W)	;INCLUDE MASSBUS UNIT
	MOVE	T1,KDBDVC(W)	;DEVICE CODE
	XMOVEI	T2,TM2DSP	;DISPATCH
	MOVE	T3,KDBCHN(W)	;CHANNEL DATA BLOCK
	PUSHJ	P,AUTSET##	;SET UP CPU VARIABLES
	PUSHJ	P,TM2DRV	;TRY TO CONFIGURE A DRIVE
	  JFCL			;IGNORE ERRORS
	PJRST	AUTULK##	;RELEASE AUTCON INTERLOCK AND RETURN
	SUBTTL	SCHEDULE, RESET, & INTERRUPT VECTOR

;HERE TO CAUSE A SCHEDULE CYCLE
TM2SCH:	PUSHJ	P,SAVST2	;SAVE ACS, SET UP P2
	SETOM	TKBSCH(W)	;SET FLAG
IFE FTRH11,<
	JRST	TM2RS1		;CAUSE AN INTERRUPT
>;FTRH11
IFN FTRH11,<
	SETZM	TKBFLG(W)	;NOTHING HAPPENING NOW
	MOVEI	T3,DC.RDY+DC.IE	;CAUSE AN INTERRUPT
	WRIOB	T3,<(DO.CS1)>(P2)
	POPJ	P,		;RETURN
>;FTRH11

;HERE TO RESET AN ACTIVE DRIVE
TM2RES:	PUSHJ	P,SAVST2	;SAVE ACS, SET UP P2
IFE FTRH11,<
	MOVSI	T2,(DO.TC)	;READ TC REGISTER
	PUSHJ	P,RDMBR##
	MOVEM	T2,E..TC(U)
	PUSHJ	P,RDREGS	;READ OTHER REGS
>;FTRH11
	PUSHJ	P,CLRDRV
TM2RS1:	PUSHJ	P,SETIV		;SET UP INTERRUPT VECTOR
IFE FTRH11,<
	PUSH	P,T1		;SAVE T1
	MOVEI	T1,CO.STP	;CLEAR BUSY, SET DONE
	XCT	KDBCNO(W)	;DO IT
	POP	P,T1		;RESTORE T1
>;FTRH11
	JRST	CLRCTX		;CLEAR RH10 AND RETURN

;ROUTINE TO SET UP INTERRUPT VECTOR
SETIV:	PUSH	P,T1		;SAVE T1
IFN FTKL10,<
	PUSH	P,T2		;SAVE T2
	MOVE	T2,KDBIVI(W)	;WHERE TO INTERRUPT TO
	XCT	KDBDTO(W)	;TELL THE HARDWARE
	MOVE	T1,KDBVIN(W)	;SET UP VECTORED INTERRUPT ADDRESS
	HRLI	T1,(XPCW)	;MAKE AN XPCW INSTRUCTION
	MOVE	T2,KDBICP(W)
	MOVEM	T1,3(T2)	;IN ICWA+3
	POP	P,T2		;RESTORE T2
> ;END IFN FTKL10
IFN FTKS10,<
	MOVE	T1,KDBVIN(W)	;GET ADDRESS OF VECTOR ROUTINE
	HRLI	T1,(XPCW)	;INTERRUPT INSTRUCTION IS AN XPCW
	MOVEM	T1,@KDBIVI(W)	;SAVE IN VECTOR INTERRUPT TABLE
> ;END IFN FTKS10
	JRST	TPOPJ##		;RESTORE T1 AND RETURN
;PRESERVES T1
SAVST2:	POP	P,T4		;SAVE RETURN ADDRESS
	PUSHJ	P,SAVE2##	;SAVE P1,P2
	PUSH	P,T4		;RESTORE RETURN ADDR

;SUBROUTINE TO SET UP P2 =0 FOR RH10, =1 FOR RH20, = CSR ADDRESS FOR RH11
;PRESERVES T1,T4
SETP2:
IFE FTRH11,<
	MOVE	P2,KDBDVC(W)	;GET DEVICE CODE
	CAIL	P2,FSTICD/4	;RH20?
	CAILE	P2,LSTICD/4
	TDZA	P2,P2		;NO, P2=0
	MOVEI	P2,1		;YES, P2=1
	JUMPE	P2,CPOPJ##	;GO IF AN RH10
	PUSH	P,T1		;SAVE T1
	MOVEI	T1,CO.MBE	;RH20, ENSURE THAT MASSBUS IS ENABLED
	XCT	KDBCNO(W)
	POP	P,T1		;RESTORE T1
>;FTRH11
IFN FTRH11,<
	MOVE	P2,KDBDVC(W)	;GET RH11 REGISTER ADDRESS
>;FTRH11
	POPJ	P,		;AND RETURN
IFE FTRH11,<
;ROUTINE TO READ REGISTERS ON ERROR
RDREGS:	PUSH	P,T1		;SAVE T1
	XCT	KDBCNI(W)
	MOVEM	T1,E..CNI(U)	;SAVE CONI
	POP	P,T1		;RESTORE T1
	MOVE	T2,[DO1CRC
		    .DOPTC](P2)
	PUSHJ	P,RDMBR##
	MOVEM	T2,E..DTI(U)	;DATAI RH10 CNTRL REG
	MOVE	T2,[DO1CDB
		    .DOPBA](P2)
	PUSHJ	P,RDMBR##
	MOVEM	T2,E..DT2(U)	;DATAI RH10 DATA BUFFER
	PUSH	P,T1
	MOVEI	T1,E..MBR(U)	;(REG+3 = LAST COMMAND)
	HRLI	T1,E..CS1-E..TC	;READ REGISTERS 0- <TC-1> (TC READ AT TM2INT)
	MOVSI	T2,(DO.CS1)	;STARTING HERE
RDREG1:	PUSH	P,T2		;SAVE REGISTER NUMBER
	PUSHJ	P,RDMBR##
	MOVEM	T2,(T1)		;STORE DATA IN UDB
	POP	P,T2		;GET REGISTER NUMBER BACK
	ADD	T2,[1B5]	;STEP TO NEXT REGISTER
	TLZ	T2,^-<(77B5)>	;KEEP ONLY REGISTER NUMBER
	AOBJN	T1,RDREG1
	JRST	TPOPJ##
>;FTRH11
IFN FTRH11,<
;ROUTINE TO READ REGISTERS ON ERROR
; RESPECTS T1-T4
RDREGS:	PUSHJ	P,SAVT##		;SAVE TEMP REGS
	RDIO	T2,<(DO.CS1)>(P2)	;GET RH11 STATUS
	RDIO	T1,<(DO.CS2)>(P2)
	HRLI	T2,(T1)
	MOVEM	T2,E..CNI(U)		;SAVE "CONI" STATUS
	MOVE	T4,KDBCHN(W)		;GET ADDRESS OF CHANNEL DATA BLOCK
	RDIO	T3,@CHNUBA(T4)		;READ UBA STATUS REGISTER
	MOVEM	T3,E..DTI(U)		;SAVE HERE IN KDB
	LSH	T2,-10			;POSITION 2 BIT ADDRESS EXT (IN MTCS1)
	RDIO	T1,<(DO.BA)>(P2)	;GET THE ENDING BUS ADDRESS
	DPB	T2,[POINT 2,T1,19]	; AND PUT IN HIGH ORDER BITS
	IDIVI	T1,UBAMUL		;COMPUTE MAP REGISTER OFFSET
	ADDI	T1,UBAEXP		;ADD IN THE BASE ADDRESS
	HLL	T1,CHNUBA(T4)		;PUT IN PROPER UBA NUMBER
	RDIO	T2,(T1)			;READ OUT MAP SLOT OF LAST WORD XFER'ED
	MOVEM	T2,E..DT2(U)		;SAVE HERE IN KDB
	MOVEI	T1,E..MBR(U)		;(REG+3 = LAST COMMAND)
	HRLI	T1,E..CS1-E..TC		;READ REGISTERS 0- <TC-1> (TC READ AT TM2INT)
	MOVE	T4,[POINT 6,RH11OF]	;CONVERSION TABLE
RDREG1:	ILDB	T2,T4			;GET NEXT REGISTER (BY MASSBUS #)
	ADD	T2,P2			;CONVERT TO IO ADDRESS
	RDIO	T2,(T2)			;READ CONTENTS
	MOVEM	T2,(T1)			;STORE DATA IN UDB
	AOBJN	T1,RDREG1		;LOOP FOR ALL BUT TC
	POPJ	P,			;RETURN

	DEFINE X(A),<ZZ==<ZZZ==0>
IRP A,<IFE <ZZ-6>,<EXP ZZZ
	ZZ==<ZZZ==0>>
ZZZ==ZZZ!<('A')>B<5+<ZZ*6>>
ZZ==ZZ+1>
	EXP	ZZZ
	PURGE	ZZ,ZZZ
>

	;TABLE DEFINING ORDER IN WHICH ERROR REGISTERS ARE STORED IN UDB
	;DAEMON/SPEAR KNOW ABOUT THIS, AND ASSUME RH10/20 ORDER IS SAME

RH11OF:	X	<DO.CS1,DO.DS,DO.ER,DO.MR,DO.AS,DO.FC,DO.DT,DO.CK,DO.SN,DO.TC>
>;FTRH11
	SUBTTL	IO CONTROL TABLES

;TABLES TO CONTROL IO
	TB.REV==1B0				;TAPE MOVES BACKWARDS
	TB.WRT==1B1				;OPERATION WRITES ON TAPE
	TB.DAT==1B2				;DATA TRANSFER OPERATION
	TB.SPC==1B3				;SPACING OPERATION
	TB.RD==1B4				;OPERATION READS TAPE
	TB.ERA==1B5				;OPERATION IS ERASE
	TB.WTM==1B6				;OPERATION IS WRITE TAPE MARK
	TB.NFC==1B7				;PUT NULL/ZERO IN FRAME COUNTER
	TB.OFC==1B8				;PUT -1 IN FRAME COUNTER
	TB.REW==1B9				;OPERATION IS REWIND
;	TB.FNC==17B17				;TAPSER FUNCTION CODE

FNCTBL:	0					;0  - ILLEGAL
	TB.DAT!TB.RD!TB.NFC!DF.RDF!1B17		;1  - READ FORWARD
	TB.WRT!TB.DAT!DF.WTF!2B17		;2  - WRITE
	TB.DAT!TB.RD!TB.NFC!TB.REV!DF.RDR!3B17	;3  - READ REVERSE
	TB.SPC!DF.SPF!4B17			;4  - SKIP RECORD
	TB.SPC!TB.REV!DF.SPR!5B17		;5  - BACKSPACE RECORD
	TB.SPC!DF.SPF!6B17			;6  - SKIP FILE
	TB.SPC!TB.REV!DF.SPR!7B17		;7  - BACKSPACE FILE
	TB.WRT!TB.ERA!TB.OFC!DF.ERA!10B17	;10 - ERASE
	0					;11 - DATA SECURITY ERASE (ILLEGAL)
	TB.NFC!TB.REW!TB.REV!DF.REW!12B17	;12 - REWIND
	TB.NFC!DF.UNL!13B17			;13 - REW, UNLOAD
	TB.WRT!TB.WTM!TB.OFC!DF.WTM!14B17	;14 - WRITE TAPE MARK
FNCNOP:	TB.SPC!DF.INT!15B17			;15 - YELLOW BALL
	TB.DAT!TB.RD!TB.NFC!DF.RDF!16B17	;16 - CORRECTION READ
	TB.DAT!TB.RD!TB.NFC!DF.RDF!17B17	;17 - LOW THRESHOLD READ

;FRAMES/WORD,,MODE
MODTBL:	-1					;0 - ILLEGAL
	5,,0B31					;1 - CORE DUMP
	4,,3B31					;2 - BYTE (4 B-BIT BYTES/WRD)
	-1					;3 - SIXBIT...ILLEGAL
	5,,2B31					;4 - 7 BIT (ASCII)
	6,,1B31					;5 - 7 TRACK CORE DUMP

;TM02 DENSITY CODE BY TAPSER CODE
DENTBL:	-1
	0B27					;200
	1B27					;556
	2B27					;800
	4B27					;1600
MAXDEN==.-DENTBL-1

;HUNG TIMER TABLE
	EXP	^D150			;MAXIMUM TIMEOUT VALUE
HNGTBL:	BYTE(9)	^D000,^D031,^D031,^D031	;IL,RD,WT,RB
	BYTE(9)	^D031,^D031,^D000,^D000	;SR,BR,SF,BF
	BYTE(9)	^D031,^D000,^D150,^D150	;LG,SE,RW,RU
	BYTE(9)	^D031,^D031,^D031,^D031	;TM,YB,CR,RL
IFN FTRH11,<TRHEND:>
TM2END:	END