Google
 

Trailing-Edge - PDP-10 Archives - BB-X140B-BB_1986 - 10,7/703mon/tm2kon.mac
There are 13 other files named tm2kon.mac in the archive. Click here to see a list.
TITLE TM2KON - RH10/RH20/RH11 TM02/TM03(TU16/TU45/TU77) DRIVER FOR TAPSER  V121
	SUBTTL	T WACHS/TW	10 SEP 85
	SEARCH	F,S

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

IFE FTRH11,<
	SEARCH	ICHPRM	;RH20 PARAMS (SYMBOLS REQUIRED BUT NOT USED IF KI)
>
	SALL
	.DIRECT FLBLST

	$RELOC
	$HIGH



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

;

XP VTM2KN,121
IFE FTRH11,<
ENTRY	TM2KON
TM2KON::INTERN	TM2DSP
	TTXREG==TT2REG##	;RH REGISTERS FOR ERROR
	TTXUVA==TT2UVA##	;READ-BACKWARDS TEMP
>

IFN FTRH11,<
ENTRY TRHKON
TRHKON::TRHDSP=:TM2DSP
	TTXREG==TRHREG##	;RH REGISTERS FOR ERROR
	TTXUVA==TRHUVA##	;READ-BACKWARDS TEMP
>


	;SYSERR REGISTER BLOCK DEFINITIONS

	E..CNI==TTXREG+0	;RH10/20 - CONI AT ERROR
				;RH11 - DO.CS2,,DO.CS1 AT ERROR
	E..DTI==TTXREG+1	;RH10/20 - DATAI CONTROL AT ERROR
				;RH11 - UBA STATUS REGISTER AT ERROR
	E..DT2==TTXREG+2	;RH10/20 - DATAI DATA BUFFER AT ERROR
				;RH11 - UBA MAP ENTRY AT ERROR
	E..LCM==TTXREG+3	;LAST COMMAND ISSUED
	E..MBR==TTXREG+4	;BLOCK OF MASSBUS REGISTERS AT ERRROR
;DISPATCH TABLE FOR TAPSER CALLS
TM2DSP::IFIW	TM2INI		;00 - INITIALIZE
	IFIW	TM2RES		;01 - RESET ACTIVE I/O
	IFIW	TM2SIO		;02 - START I/O
	IFIW	TM2INT		;03 - INTERRUPT SERVICE
	EXP	0		;04 - SET DEVICE COMMAND
	IFIW	CPOPJ##		;05 - KONTROLLER IS IDLE
	IFIW	TM2ONL		;06 - TEST IF CTL ON-LINE
	IFIW	TM2SCH		;07 - FORCE A SCHEDULE CYCLE
	IFIW	TM2INR		;10 - RE-INITIALIZATION
	IFIW	CPOPJ##		;11 - LOAD MICROCODE
	IFIW	CPOPJ##		;12 - ENABLE/DISABLE MICROCODE LOADING
IFN FTAUTC,<IFIW TM2CFG>	;13 - AUTOCONFIGURE

IFE FTRH11,< 	;MACRO MAKES SURE MASSBUS DATA IS STABLE WHEN READ
DEFINE STALL,<
	IMULI	P,1
  IFN FTKL10,<	IMULI	P,1 >	;;THE KL IS FASTER, DO IT AGAIN
>;STALL
>;FTRH11

	;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!CO.CCD

	;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,TTXUVA(W)	;REAL IOWD - SAVE IT
	LDB	T2,[POINT 3,TUBAKA##(U),17]	;YES, GET 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,TRBLNK(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,<
	MOVEI	T3,CO.MBE	;DONT ALLOW INTERRUPTS (BIT IGNORED IF RH10)
	XCT	TT2CO3##(W)	;(REWINDING DRIVE)
>;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,WTREG		;TELL MODE, DENSITY, SLAVE #, PARITY
	HRLI	T3,-1		;1ST TIME THROUGH (RH SET BY WTREG)
TM2SI2:	MOVSI	T2,(DO.DS)	;READ THE STATUS REGISTER OF THE SLAVE
	PUSHJ	P,RDREGX
	TRNE	T2,DS.BOT	;BOT?
	 JUMPL	P1,[.CREF TB.REV	;YES, JUMP IF FUNCTION GOES BACKWARDS
		    MOVSI P1,TUSBOT##	;SW 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
		    JRST .+1]	;AND CONTINUE
	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,<
	PUSH	P,T3		;SAVE TM02 NUMBER
	HRRZ	T3,TKBCDB##(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
	WRIO	T2,<(DO.WC)>(P2);LOAD THE WORD COUNT REGISTER
	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
	POP	P,T3		;RESTORE TM02 NUMBER
>;FTRH11
	MOVS	T2,TTXUVA(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,TRBXCW(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,WTREGX	;TELL IT HOW MUCH TO DO
TM2SI4:
IFE FTRH11,<
	.CREF	DO.CS1		;NEXT INSTR SETS UP TO WRITE CS1 FOR SPACE OP
	HRRZ	T2,TKBICP##(W)	;ICWA
	HRRZ	T3,TRBXCW(T1)	;CHAN LIST
	SKIPE	P2		;IF AN RH20,
	 TLO	T3,RH2JMP##	; 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,WTREG		;GO START UP THE WORLD
	MOVEM	P1,TKBFLG(W)	;REMEMBER WHAT WE ARE DOING
	MOVEI	T3,TAPCHN##+CO.MBE	;PIA
	TLNN	P1,(TB.DAT)	;DATA OPERATION?
	 TRO	T3,CO.AIE	;NO, ENABLE FOR ATTENTIONS
				;CONTINUE
	PUSHJ	P,SETIV		;SET UP INTERRUPT VECTOR
	JUMPE	P2,TM2SI6	;NO SWEAT IF RH10
	XCT	TKBCIS##(W)	;DID WE WIN IN THE SETUP?
	TRNE	T2,CI.RAE
	 TRO	T3,CO.STP	;NO, CAUSE AN IMMEDIATE INTERRUPT
TM2SI6:	XCT	TT2CO3##(W)	;TURN ON RH10 PI
>;FTRH11
IFN FTRH11,<
	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,WTREG
	MOVSI	T2,(DO.DS)	;IS IT REWINDING?
	PUSHJ	P,RDREGX
	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:	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,RDREGX
	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,WTREGX	;RESTORE TC REG
	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
	;U/ TUB FOR IO
	;W/ TKB FOR IO

TM2INT:	PUSHJ	P,SAVE3##	;SAVE SOME ACS
	PUSHJ	P,SETP2		;SET P2=0 IF RH10, =1 IF RH20, CSR IF RH11
	MOVE	U,TKBCUN##(W)	;UNIT WE'RE TALKING TO (MAYBE)
	MOVE	U,(U)
IFE FTRH11,<
	XCT	TKBCIS##(W)	;CONI
	TRNE	T2,CI.RAE	;REGISTER ACCESS ERROR?
	JRST	TM2IN3		;YES, GO CLEAR IT AND RETRY
>;FTRH11
IFN FTRH11,<
	LDB	T3,[POINT 3,TUBAKA##(U),14];GET TM02 NUMBER
	WRIO	T3,<(DO.CS2)>(P2);SELECT TM02
	RDIO	T2,<(DO.CS2)>(P2);GET STATUS
	TRNE	T2,D2.NXD	;TMO3 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,RDREG
	MOVEM	T2,E..TC(U)	; SO READ AND SAVE IT NOW
	MOVSI	T2,(DO.DS)	;READ STATUS REGISTER NOW, TALKING
	PUSHJ	P,RDREG		; TO TC REG LATER MAY CHANGE IT
	PUSH	P,T2		;SAVE STATUS REG
	MOVSI	T2,(DO.AS)	;READ THE ATTN SUMMARY REGISTER
	PUSHJ	P,RDREG
	ANDI	T2,377		;JUST THE ATTENTION BITS
IFE FTRH11,<
	TDNN	T2,TKBUNI##(W)	;ATTEN FOR THIS KDB?
	 JRST	TM2IN2		;NO
	HRRZ	T2,TKBUNI##(W)	;YES. GET THE CORRECT BIT
>;FTRH11
	HRLI	T2,(DO.AS)	;CLEAR THE BIT
	PUSHJ	P,WTREGX
IFN FTRH11,<
	HRRZ	T1,T2		;COPY ATTENTIONS WE HAVE
	SETZ	T3,		;START WITH TM02 # 0
TRHIN1:	LSHC	T1,-1		;GET NEXT UNPROCESSED ATTENTION
	JUMPGE	T2,NXTU45	;DON'T TOUCH IF ATTENTION NOT UP
	MOVE	T4,T3		;SAVE UNIT NUMBER
	LSH	T4,3		;PUT IN EXPECTED PLACE
>;FTRH11
	PUSHJ	P,DRVPL1	;POLL THE DRIVES FOR REW DONE
IFN FTRH11,<
NXTU45:	JUMPE	T1,TM2IN2	;EXIT IF ALL ATTNS DONE
	AOJA	T3,TRHIN1	;THERE IS ANOTHER ATTN, TRY NEXT UNIT
>;FTRH11

;HERE AFTER THE ATTENTION (IF ANY) IS HANDLED
TM2IN2:	LDB	T2,[POINT 3,TUBAKA##(U),17]	;SLAVE NUMBER
	HRLI	T2,(DO.TC)	;SET TO RECONNECT TO DRIVE, DRVPOL MIGHT HAVE
	PUSHJ	P,WTREG		; 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	TKBDIS##(W)	;DATAI
	HLL	T3,T2		;SAVE (DBTO,CBTO)
	XCT	TKBCIS##(W)	;CONI
	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,TKBICP##(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,RDREG		;(ONLY CALL RDREG 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	T1,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	T1,RB.SNM!RB.SED;TAPE DIDN'T MOVE
NOMOVE:	 TLO	T1,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	T1,RB.STM	; TELL TAPUUO WHAT WE SAW
NOTM:	TLNE	P1,(TB.WRT)	;IF WRITING,
	 TRNN	T4,DS.EOT	;AND WE SAW EOT
	CAIA
	 TLO	T1,RB.SET	;TELL TAPUUO
TM2GO:	JRST	@INTABL(P3)	;GO TO SPECIFIC INTERRUPT HANDLER


INTABL:	TAPIFI##
	INTRD			;(1)READ FORWARD
	INTWRT			;(2)WRITE
	INTRD			;(3)READ BACKWARDS
	INTSPC			;(4)SKIP RECORD
	INTSPC			;(5)BACKSPACE RECORD
	TAPIFI##		;(6)SKIP FILE
	TAPIFI##		;(7)BACKSPACE FILE
	INTERA			;(10)ERASE GAP
	TAPIFI##		;(11)DATA SECURITY ERASE
	INTREW			;(12)REWIND
	INTUNL			;(13)UNLOAD
	INTWTM			;(14)WRITE TAPE MARK
	INTNOP			;(15)YELLOW BALL/ILLEGAL FUNCTIONS
	INTRD			;(16)CORRECTION READ
	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,RDREG
	MOVEM	T2,TRBRCT(T1)	;SAVE CHAR-COUNT OF RECORD
	MOVEM	T2,TUBCCR##(U)
	ADDM	T2,TUBCRD##(U)	;UPDATE TOTAL STATS
	ADDM	T2,.CPTFI##
	CAMLE	T2,TKBCHR(W)	;TOO LARGE A RECORD?
	 TLO	T1,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,TTXUVA(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:	HLLZ	T2,T1		;BITS WE WANT TO TELL TAPUUO ABOUT
	IORM	T2,TRBSTS(T1)	;STORE IN THE IORB
TRBEXC:	MOVSI	T2,RB.EXC
	TLZE	T1,-1		;ANY FUNNY THINGS?
	 IORM	T2,TRBLNK(T1)	;YES, AN EXCEPTION HAS OCCURRED

IFE FTRH11,<
CLRCTL:	MOVE	T3,[CO1CLR
		CO.CLR+CO.MBE](P2)
	XCT	TT2CO3##(W)
CLRCTX:	MOVEI	T3,TAPCHN##+CO.AIE+CO.MBE	;ENABLE FOR INTERRUPTS
	XCT	TT2CO3##(W)
	SETZM	TKBFLG(W)	;NOTHING HAPPENING NOW
	POPJ	P,		;AND RETURN
>;FTRH11
IFN FTRH11,<
CLRCTL:	MOVEI	T2,D2.CLR	;CLEAR ALL ERRORS
	WRIO	T2,<(DO.CS2)>(P2);
CLRCTX:	MOVEI	T3,DC.IE	;ENABLE FOR INTERRUPTS
	WRIO	T3,<(DO.CS1)>(P2)
	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,.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	T1,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,RDREG		;THAT WILL HANG SOME TM03'S
	TRNN	T2,DS.PIP
	 PUSHJ	P,CLRDRV	;CLEAR THE DRIVE
	HLL	T1,TRBSTS(T1)	;GET ERROR BITS
	MOVSI	T2,TKSOFL##	;DRVPOL MAY HAVE CLEARED TKSOFL
	TLNE	T1,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	T1,RB.SNM!RB.SED ;YES, NO TAPE MOTION+ERROR
	JRST	TRBSTO

CHNER1:	HRRZ	T2,TKBUNI##(W)	;YES. GET BIT TO CLEAR
	HRLI	T2,(DO1CRA)	;CLEAR REG ACCESS ERROR
	PUSHJ	P,WTREG
	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,CHNNXM##	;SET TO CALL RIGHT ROUTINE
	MOVSI	T4,IOCHNX	;ASSUMING NXM
	TDNN	T2,[CI1NXM,,
		    CS.NXM](P2)
	 PUSHJ	P,[MOVEI T3,CHNMPE## ;NO--SET FOR MEMORY PARITY
		   MOVSI T4,IOCHMP	; ...
		   POPJ P,]
	HRRZ	T1,TKBICP##(W)	;T1=ICWA
	HRRZ	P1,TKBCDB##(W)	;P1=CDB
	HRRZ	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,<
	HRRZ	T3,TKBCDB##(W)	;GET CHANNEL DATA BLOCK
	MOVEI	T2,UNBTMO!UNBBME
	BSIO	T2,@CHNUBA##(T3) ;CLEAR POSSIBLE UBA ERRORS
>;FTRH11
	TLO	T1,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	T1,RB.SOL	;OFFLINE IF UNSAFE IS UP
	TLO	T1,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	T1,RB.SED	;PLAIN ERROR
	TLO	T1,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,WTREG

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

DRVPLX:
IFN FTRH11,<
	HLRZ	T4,TUBAKA##(U)	;TU45 # + SLAVE NUMBER
	ANDI	T4,70		;TU45 NUMBER
>;FTRH11
DRVPL1:
IFN FTRH11,<
	MOVE	T2,T4
	ADD	T4,TKBIUN##(W)	;POSITION TO RIGHT PART OF KDB
	LSH	T2,^D21		;SHIFT TU45 #
	ADD	T2,T4		;FORM LH OF AOBJN WORD
	JUMPGE	T2,CPOPJ##	;WE DON'T KNOW ABOUT THIS TU45 IF NOT NEG.
	HRLI	T4,P1		;SET INDEX FOR RIGHT SLAVE NUMBER
>;FTRH11
	PUSHJ	P,SAVE4##	;SAVE SOME ACS
	SETZ	P4,		;SET A FLAG
	PUSH	P,U		;SAVE U
IFE FTRH11,<
	HRRZ	T4,TKBIUN##(W)	;POINT TO RIGHT PART OF KDB
	TLO	T4,P1		;SET INDEX FOR RIGHT SLAVE NUMBER
>;FTRH11
DRVPL5:	MOVSI	T2,(DO.DS)	;READ STATUS REG
	PUSHJ	P,RDREGX
	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,WTREGX
	MOVSI	T2,(DO.DT)	;GET THE DRIVE TYPE
	PUSHJ	P,RDREGX
	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 A 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,WTREGX
	MOVSI	T2,(DO.DT)	;GET THE DRIVE TYPE
	PUSHJ	P,RDREGX
	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
	 HRRZ	T2,TKBCUN##(W)	;DONT CLEAR THAT DRIVE
	CAIN	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,WTREGX
	MOVSI	T2,(DO.DS)
	PUSHJ	P,RDREGX	;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,WTREGX
FNDCL1:	AOBJN	P1,FNDCLR	;CLEAR NEXT DRIVE

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

DRVPL9:	POP	P,T3		;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
>;FTRH11
DRVPL2:	MOVSI	P1,-10		;SET TO LOOK AT ALL DRIVES
DRVPL3:	SKIPN	U,@T4		;POINT U AT UDB
	 JRST	DRVPL4		;NONE, LOOK AT NEXT
	MOVSI	T2,(DO.TC)	;SET TO TALK TO THIS DRIVE
	HRR	T2,P1
	PUSHJ	P,WTREGX	;CONNECT TO IT
	MOVSI	T2,(DO.DS)
	PUSHJ	P,RDREGX	;READ STAUS REGISTER
	MOVSI	P3,TKSOFL##
	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:	AOBJN	P1,DRVPL3	;GO TEST NEXT DRIVE
	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
	SUBTTL	SYSINI INITIALIZATION

;HERE TO INITIALIZE THE TM02
TM2INI:	MOVEI	T1,TUCIRD##	;TELL TAPUUO WE GET AN INTERRUPT
	MOVE	T2,TKBCUN##(W)	; WHEN A REWIND FINISHES
TM2INL:	SKIPE	T3,(T2)		;NEXT DRIVE
	 IORM	T1,TUBSTS##(T3);SET BIT IN IT
	AOBJN	T2,TM2INL

	PUSHJ	P,SAVST2	;SAVE ACS, SET UP P2
IFN FTRH11,<
	MOVE	T1,P2		;GET IO ADDRESS OF RH11
	PUSHJ	P,UBGOOD##	;IS RH11 ALIVE ON THE UNIBUS?
	  SKIPA			;NO--SKIP NEXT INSTRUCTION
	JRST	TRHIN0		;YES--CONTINUE
	MOVSI	T1,TKSSIL##!TKSOFL## ;SILENCE MESSAGE AND OFF-LINE
	IORM	T1,TKBSTS##(W)	;SET THEM
	POPJ	P,		;RETURN

TRHIN0:	PUSH	P,F		;SAVE F FOR SYSINI
	HRRZ	T2,TRHVEC##(W)	;-11 STYLE INTERRUPT VECTOR ADDRESS
	LSH	T2,-2		;DIVIDE BY 4
	HLRZ	T3,P2		;UBA NUMBER
	ADD	T2,.EPVIT##-1(T3) ;ADD INT VECTOR TABLE BASE ADDRESS
	MOVE	T3,TRHIVI##(W)	;GET INT VECTOR INSTRUCTION
	MOVEM	T3,(T2)		;PUT INTO VECTOR TABLE
	MOVE	T1,DEVNAM(F)	;GET NAME AS SET UP BY COMDEV
>;FTRH11
	MOVE	T4,TKBIUN##(W)	;SET TO LOOP OVER ALL UNITS
TM2INN:	SKIPN	U,(T4)		;GET A UNIT
	 JRST	TM2INX		;NOT THERE
IFN FTRH11,<
	HRRZ	T2,TUBADR##(U)	;GET UDB
	DPB	T2,PUNIT##	;STORE RIGHT UNIT
	LSHC	T2,-3		;SET RIGHT NAME IN DDB
	LSH	T2,^D15
	LSHC	T2,3		;HAVE TO FIDDLE CAUSE MORE THAN 1 TU45 DOES
	ADD	T2,T1		; VERY FUNNY THINGS TO THE NAMES
	MOVEM	T2,DEVNAM(F)	;EG MTA21
	HLRZ	F,DEVSER(F)	;ADVANCE TO THE NEXT DDB
>;FTRH11
	HRRZ	T2,TUBADR##(U)	;GET UDB
	HRLI	T2,(DO.TC)	;SELECT RIGHT SLAVE
	PUSHJ	P,WTREG
	MOVSI	T2,(DO.SN)	;READ SERIAL NUMBER
	PUSHJ	P,RDREG		;AND STORE IN UDB
	MOVEM	T2,E..SN(U)	;FOR DIAGNOSTICS
	MOVSI	T2,(DO.DS)	;READ STATUS REG
	PUSHJ	P,RDREG
	MOVSI	T3,TKSOFL##
	TRNN	T2,DS.MOL	;IF NOT MEDIUM-ON-LINE
	 IORM	T3,TUBSTS##(U)	; THE DRIVE IS OFF-LINE
TM2INX:	AOBJN	T4,TM2INN
IFE FTRH11,<
TM2INC:	MOVEI	T3,CO.MBI	;CLEAR ANY PENDING INTERRUPTS
	XCT	TT2CO3##(W)
	MOVEI	T3,CO.MBE	;MASSBUS ENABLE
	XCT	TT2CO3##(W)	
	PUSHJ	P,TM2ONL	;IF NOT THERE
	  POPJ	P,		; DON'T SET UP CONSO MASK
	PUSHJ	P,SETIV		;SET UP INTERRUPT VECTOR
>;FTRH11
IFN FTRH11,<
	POP	P,F		;RESTORE F
>;FTRH11
	JRST	CLRCTL		;CLEAR RH10 AND RETURN
	SUBTTL	KONTROLLER ON-LINE & AUTO-CONFIG

;HERE ON KONTROLLER ONLINE. SKIP THE CODE TO RESET THE DDB NAMES.
IFE FTRH11,<
TM2INR:	
	PUSHJ	P,SAVST2	;SAVE P1,P2, SETUP P2
	JRST	TM2INC		;JOIN COMMOD CODE
>;FTRH11
IFN FTRH11,<TM2INR==CPOPJ##>


IFN FTAUTC,<
;HERE TO DETERMINE WHAT SLAVES ARE PRESENT
;ENTER P3= LAST SLAVE WE'VE SEEN,  LH(P2) = RH UNIT NUMBER
;EXIT P3 = NEXT SLAVE, OR 0 IF NO MORE
TM2CFG:	AOS	T2,P3
	TRZE	P3,10		;OVER THE TOP?
	 SOJA	P3,CPOPJ##	;YES, RETURN WITH P3=-1
	HLRZ	T3,P2
	HRLI	T2,(DO.TC)	;SET TO TALK TO THIS DRIVE
	PUSHJ	P,WTREGX
	MOVSI	T2,(DO.DT)	;READ DRIVE TYPE
	PUSHJ	P,RDREGX
	TRNE	T2,DT.SPR	;SLAVE PRESENT?
	 TDZA	T3,T3		;YES, RETURN WITH T3=0 (NO TUBCNF CHANGES)
	JRST	TM2CFG		;NO, TRY NEXT SLAVE
	 POPJ	P,		;AND RETURN P3= NEXT DRIVE NUMBER
>
	SUBTTL	CHECK ON-LINE STATUS

;HERE TO CHECK IF ON-LINE
TM2ONL:
IFE FTRH11,<
	MOVE	T2,TKBSTS##(W)
	HRRZ	T1,TKBCDB##(W)	;POINTER TO CHANNEL
	SKIPGE	(T1)		;DON'T DO CONO'S IF CHAN IS IN USE (USER MODE DIAG)

	 TLNE	T2,TKSSEL##!TKSSTD##!TKSSCH##
	JRST	CPOPJ1##	;SKIP THE TEST IF THE CONTROLLER IS GOING
	XCT	TKBCIS##(W)
	MOVE	T1,T2		;REMEMBER ATTEN ENABLE
>;FTRH11
	PUSHJ	P,SAVST2	;SETUP P2 (IF KL, DOES CONO)
IFN FTRH11,<
	MOVE	T1,P2		;GET IO ADDRESS OF RH11
	PUSHJ	P,UBGOOD##	;BE SURE IT IS THERE
	 POPJ	P,		;OFF-LINE
	RDIO	T2,<(DO.DS)>(T1);CAUSE A REGISTER ACCES
	RDIO	T2,<(DO.CS2)>(T1);GET STATUS REGISTER
	TRNN	T2,D2.NXD	;IS TM03 THERE?
	 JRST	TM2RL1		;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
	POPJ	P,		;OFF-LINE RETURN
TM2RL1:	;(****KROQUE UNTIL RDREG FOR THE KS GETS ITS UNIT FROM TKBUNI...****)
	RDIO	T2,<(DO.DT)>(P2);READ THE DRIVE TYPE OF THE SELECTED SLAVE
	;(****)
>;FTRH11
IFE FTRH11,<;****MORE...****
	MOVSI	T2,(DO.DT)
	PUSHJ	P,RDREG		;READ DRIVE-TYPE
>;FTRH11	(****END****)
	ANDI	T2,730
	CAIN	T2,10		;LEGAL?
	 AOS	(P)		;YES. SKIP-RETURN
IFE FTRH11,<
	MOVEI	T3,CO.AIE+TAPCHN## ;PIA AND ATTN ENABLE
	SKIPE	P2
	 TRO	T3,CO.MBE+CO.RAE
	TRNN	T1,CO.AIE	;WERE ATTENS ENABLED?
	 TRZ	T3,CO.AIE	;NO, DON'T ENABLE THEM NOW
	XCT	TT2CO3##(W)
>;FTRH11
	POPJ	P,
	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,RDREG
	MOVEM	T2,E..TC(U)
	PUSHJ	P,RDREGS	;READ OTHER REGS
>;FTRH11
	PUSHJ	P,CLRDRV
IFE FTRH11,<
TM2RS1:	PUSHJ	P,SETIV		;SET UP INTERRUPT VECTOR
	MOVEI	T3,CO.STP	;CLEAR BUSY, SET DONE
	XCT	TT2CO3##(W)	;DO IT
>;FTRH11
	JRST	CLRCTX		;CLEAR RH10 AND RETURN

IFE FTRH11,<
;ROUTINE TO SET UP INTERRUPT VECTOR
;PRESERVES ALL ACS EXCEPT T2
SETIV:	MOVE	T2,TKBIVI##(W)	;WHERE TO INTERRUPT TO
	XCT	TKBDOS##(W)	;TELL THE HARDWARE
	PUSH	P,T1
	MOVEI	T1,TKBVIN##(W)	;SET UP VECTORED INTERRUPT ADDRESS
	HRLI	T1,(XPCW)
	MOVE	T2,TKBICP##(W)
	MOVEM	T1,3(T2)	;IN ICWA+3
	JRST	TPOPJ##
>;FTRH11
	SUBTTL	MASSBUS REGISTER READ/WRITE

;READ A REGISTER - ENTER, EXIT WITH FNCN IN T2
;RESPECTS T1,T4
IFE FTRH11,<
RDREG:	HLRZ	T3,TKBUNI##(W)	;TM02 NUMBER
RDREGX:	TLO	T2,(T3)
	SKIPE	P2		;IF AN RH20,
	 TLO	T2,(DO.DRE)	; DISABLE REGISTER ACCESS ERR INTERRUPT
	XCT	TKBDOS##(W)	;SAY WHAT WE WANT TO READ
	STALL
	XCT	TKBDIS##(W)	;READ IT
	ANDI	T2,177777	;ONLY 16 BITS
	POPJ	P,		;AND RETURN
>;FTRH11
IFN FTRH11,<
RDREG:	LDB	T3,[POINT 3,TUBAKA##(U),14];TM02 NUMBER
RDREGX:	WRIO	T3,<(DO.CS2)>(P2);SELECT THE TM02 "DRIVE"
	HLRZS	T2		;GET DESIRED REGISTER NUMBER
	ADD	T2,P2		;COMPUTE UNIBUS ADDRESS OF DESIRED REGISTER
	RDIO	T2,0(T2)	;READ THAT REGISTER
	POPJ	P,		;DONE
>;FTRH11

;ROUTINE TO WRITE A REGISTER
;ENTER T2=WHAT TO DO THE DATAO WITH
;RESPECTS T1, T4
IFE FTRH11,<
WTREG:	HLRZ	T3,TKBUNI##(W)	;TM02 NUMBER
WTREGX:	TLO	T2,<(DO.LDR)>(T3) ;LIGHT LR
	SKIPE	P2		;IF AN RH20,
	 TLO	T2,(DO.DRE)	;NO INTERRUPT ON RAE
	XCT	TKBDOS##(W)	;DATAO
	POPJ	P,		;AND RETURN
>;FTRH11
IFN FTRH11,<
WTREG:	LDB	T3,[POINT 3,TUBAKA##(U),14];GET TM02 NUMBER
WTREGX:	WRIO	T3,<(DO.CS2)>(P2);SELECT DRIVE
	PUSH	P,T3		;SAVE T3 (SOME CALLERS USE LH)
	HLRZ	T3,T2		;GET REGISTER NUMBER TO WRITE
	ADD	T3,P2		;COMPUTE UNIBUS ADDRESS
	WRIO	T2,0(T3)	;WRITE THE REGISTER
	POP	P,T3		;RETURN TM02 NUMBER
	POPJ	P,
>;FTRH11
;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,<
	LDB	P2,[POINT 3,TKBDOS##(W),5]	;GET CONTROLLER CODE
	CAIE	P2,5		;RH20?
	 TDZA	P2,P2		;NO, P2=0
	MOVEI	P2,1		;YES, P2=1
	JUMPE	P2,CPOPJ##	;GO IF AN RH10
	MOVEI	T3,CO.MBE	;RH20, ENSURE THAT MASSBUS IS ENABLED
	XCT	TT2CO3##(W)
>;FTRH11
IFN FTRH11,<
	MOVE	P2,TRHBAS##(W)	;GET RH11 REGISTER ADDRESS
>;FTRH11
	POPJ	P,		;AND RETURN
IFE FTRH11,<
;ROUTINE TO READ REGISTERS ON ERROR
RDREGS:	XCT	TKBCIS##(W)
	MOVEM	T2,E..CNI(U)	;SAVE CONI
	MOVE	T2,[DO1CRC
		    .DOPTC](P2)
	PUSHJ	P,RDREG
	MOVEM	T2,E..DTI(U)	;DATAI RH10 CNTRL REG
	MOVE	T2,[DO1CDB
		    .DOPBA](P2)
	PUSHJ	P,RDREGX
	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:	PUSHJ	P,RDREGX
	MOVEM	T2,(T1)		;STORE DATA IN UDB
	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,TKBCDB##(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
	0					;6  - SKIP FILE (ILLEGAL)
	0					;7  - BACKSPACE FILE (ILLEGAL)
	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
IFN FTRH11,<TRHEND:>
TM2END:	END