Google
 

Trailing-Edge - PDP-10 Archives - BB-4170G-SM - sources/phym2.mac
There are 48 other files named phym2.mac in the archive. Click here to see a list.
;<3A.MONITOR>PHYM2.MAC.20, 22-Aug-78 14:22:36, EDIT BY FORTMILLER
;Set US.REW in the attention routine instead of START I/O
;<3A.MONITOR>PHYM2.MAC.19,  1-Aug-78 15:26:43, EDIT BY MILLER
;COMPUTE WRITE STATISTICS CORRECTLY
;<3A.MONITOR>PHYM2.MAC.18, 30-Jul-78 17:36:11, Edit by MCLEAN
;<3A.MONITOR>PHYM2.MAC.17, 14-Jul-78 13:44:18, EDIT BY BOSACK
;DONT IGNORE PRE/POSTAMBLE ERRORS ON PE READ
;<3A.MONITOR>PHYM2.MAC.16,  2-Jun-78 14:58:35, EDIT BY BOSACK
;ENSURE TM2POL ALWAYS LEAVES TM02/3 WITH ERRORS RESET
;<3A-NEW>PHYM2.MAC.15, 31-May-78 09:50:11, Edit by FORTMILLER
;<3A-NEW>PHYM2.MAC.14, 25-May-78 22:20:46, Edit by FORTMILLER
;ADD DX20 SUPPORT
;PUT DENSITYS DRIVE IS CAPABLE OF IN UDBCHR
;CONVERT UDBDSN TO DECIMAL SERIAL NUMBER
;<3A.MONITOR>PHYM2.MAC.13, 18-May-78 13:12:37, EDIT BY BOSACK
;CLEAR ERROR BYTE POINTER AT TERMINATION OF ERROR RECOVERY
;<3A.MONITOR>PHYM2.MAC.12, 29-Mar-78 12:11:03, Edit by MCLEAN
;FIX MTINDX TO POINT TO FREE MTCUTB
;<3A.MONITOR>PHYM2.MAC.11, 29-Mar-78 08:19:07, EDIT BY MILLER
;ADD UNIT,KONTROLLER,CHANNEL INFO TO ALL "HARDWARE" BUG TYPEOUTS
;<3A.MONITOR>PHYM2.MAC.10,  9-Mar-78 00:00:34, Edit by MCLEAN
;<3A.MONITOR>PHYM2.MAC.9,  8-Mar-78 23:56:40, Edit by MCLEAN
;MOVE INIUNI CALL SO IT DOESN'T BREAK MULTIPLE UNITS
;AND ISN'T CALLED AS OFTEN
;<2BOSACK>PHYM2.MAC.53, 24-Feb-78 01:49:19, EDIT BY BOSACK
;<2BOSACK>PHYM2.MAC.52, 24-Feb-78 01:36:56, EDIT BY BOSACK
;REWORK ERROR INTERFACE WRT DATA/DEVICE ERRORS
;<4.MONITOR>PHYM2.MAC.7,  1-Feb-78 14:51:28, Edit by MCLEAN
;FIX FOR NEW PHYALC,PHYUDB CALLING SEQ
;<4.MONITOR>PHYM2.MAC.6, 31-Jan-78 00:16:42, Edit by MCLEAN
;<4.MONITOR>PHYM2.MAC.5, 30-Jan-78 21:31:17, Edit by MCLEAN
;ADD CREATION OF UDB FOR UNIT GOING ON LINE
;<3.SM10-RELEASE-3>PHYM2.MAC.3, 15-Jan-78 18:24:04, Edit by MCLEAN
;<3.SM10-RELEASE-3>PHYM2.MAC.2, 13-Jan-78 16:09:53, Edit by MCLEAN
;FIX FCE FOR READ
;<3-MONITOR>PHYM2.MAC.50, 11-Nov-77 01:01:42, EDIT BY BOSACK
;CLEAR TM02 IF NOT ALL RECORDS IN A SKIP COMMAND WERE DONE
;<3-MONITOR>PHYM2.MAC.49,  9-Nov-77 09:56:41, EDIT BY KIRSCHEN
;MORE COPYRIGHT UPDATING...
;<3-MONITOR>PHYM2.MAC.48, 12-Oct-77 14:08:56, EDIT BY KIRSCHEN
;UPDATE COPYRIGHT FOR RELEASE 3
;<2BOSACK>PHYM2.MAC.47, 18-Sep-77 05:35:31, EDIT BY BOSACK
;<2BOSACK>PHYM2.MAC.46, 10-Sep-77 21:05:41, EDIT BY BOSACK
;<2BOSACK>PHYM2.MAC.45,  6-Sep-77 04:44:11, EDIT BY BOSACK
;<2BOSACK>PHYM2.MAC.44,  6-Sep-77 01:57:45, EDIT BY BOSACK
;<2BOSACK>PHYM2.MAC.43,  5-Sep-77 06:42:05, EDIT BY BOSACK
;<SM10-MONITOR>PHYM2.MAC.42, 12-Aug-77 12:06:30, Edit by MCLEAN
;<SM10-MONITOR>PHYM2.MAC.41, 12-Aug-77 11:12:11, Edit by MCLEAN
;MAKE FCE ERROR LEGAL FOR EOF ONLY
;<2BOSACK>PHYM2.MAC.40, 28-Jun-77 17:48:49, EDIT BY BOSACK
;<2BOSACK>PHYM2.MAC.39, 10-Jun-77 14:55:35, EDIT BY BOSACK
;FIX  CLOBBERED REGISTER IN FTLCHK
;<2BOSACK>PHYM2.MAC.38,  9-Jun-77 15:03:59, EDIT BY BOSACK
;FIX LOW CORE CLOBBER IF STARTIO FAILS DURING ERROR RECOVERY
;<3-MONITOR>PHYM2.MAC.37,  2-May-77 18:48:26, EDIT BY HURLEY
;<2BOSACK>PHYM2.MAC.36,  7-Apr-77 22:06:02, EDIT BY BOSACK
;<2BOSACK>PHYM2.MAC.35,  2-Apr-77 19:58:25, EDIT BY BOSACK
;<2BOSACK>PHYM2.MAC.34,  1-Apr-77 22:01:50, EDIT BY BOSACK
;<2BOSACK>PHYM2.MAC.33,  1-Apr-77 21:54:39, EDIT BY BOSACK
;ADD BLOCKTYPE CODE, START SUPPORT FOR TM03
;<3-MONITOR>PHYM2.MAC.32,  2-Mar-77 14:17:21, EDIT BY BOSACK
;TCO 1748 - FIX WTM ERROR RECOVERY
;<3-MONITOR>PHYM2.MAC.31, 27-Dec-76 17:35:52, EDIT BY HURLEY
;<3-MONITOR>PHYM2.MAC.30, 27-Dec-76 17:27:38, EDIT BY HURLEY
;<2BOSACK>PHYM2.MAC.1, 22-Dec-76 17:53:57, EDIT BY BOSACK
;<2-MONITOR>PHYM2.MAC.28, 29-Nov-76 17:14:40, EDIT BY BOSACK
;TCO 1672 - FIX MTINDX BUG
;<1B-MONITOR>PHYM2.MAC.27, 11-JUN-76 10:24:47, EDIT BY OSMAN
;INILP NOW LEAVES MTINDX CONTAINING NUMBER OF PHYSICAL MTA'S ON SYSTEM
;<2MONITOR>PHYM2.MAC.26, 23-JAN-76 17:59:07, EDIT BY BOSACK
;MCO 22 - ACCOUNT TAPE READ/WRITES IN FRAMES
;<2MONITOR>PHYM2.MAC.25, 19-JAN-76 12:23:57, EDIT BY MURPHY
;<2MONITOR>PHYM2.MAC.24,  9-JAN-76 11:25:44, EDIT BY HURLEY


;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1976, 1977, 1978 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.

	SEARCH PROLOG,PHYPAR,SERCOD ;SYSTEM PARAMETERS
	TTITLE (PHYM2,,< - DEVICE DEPENDENT CODE FOR TM02/TU45 MAGTAPES VER 62>)

	SUBTTL P.KINZELMAN 25 JULY 75
	TM2VER==62		;EDIT VERSION

		ENTRY TM2DSP	;FOR LIBRARY SEARCH


;NEED TO PUT IN NOISE RECORD STUFF?
	SUBTTL PARAMETERS

;DRIVE REGISTERS USED IN DATAO'S

	DO.CS1==0B5		;DRIVE CONTROL REGISTER
	DO.DS==1B5		;STATUS REGISTER
	DO.ER==2B5		;ERROR REGISTER
	DO.MR==3B5		;MAINTENANCE REGISTER
	DO.AS==4B5		;ATTENTION SUMMARY
	DO.FC==5B5		;FRAME COUNTER
	DO.DT==6B5		;DRIVE TYPE
	DO.CK==7B5		;CHECK CHARACTER REGISTER
	DO.SN==10B5		;SERIAL NUMBER
	DO.TC==11B5		;TAPE CONTROL REGISTER

;DRIVE FUNCTIONS LOADED INTO DRIVE CONTROL REGISTER

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


	DXES==200000		;DISABLE XFER ON ERROR STOP BIT
;DRIVE STATUS REGISTER

	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
				;SPARE
	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


;DRIVE ERROR REGISTER

	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		;REGISTER MODIFICATION REFUSED
	ER.ILR==1B34		;ILLEGAL REGISTER ADDRESS
	ER.ILF==1B35		;ILLEGAL FUNCTION

;DRIVE TYPE BITS NEEDED:

	DT.SPR==1B25		;A SLAVE IS SELECTED
	SUBTTL DEVICE DEPENDANT TABLE DEFS

;****************************
;UDB EXTENSIONS

	TU6EPS==UDBDDP		;ERROR POSITION
	TU6EBP==TU6EPS+1	;ERROR BYTE POINTER
	TU6EBC==TU6EBP+1	;ERROR BYTE COUNTER
	TU6ECL==TU6EBC+1	;TAPE CLEANER FLAG

	LU.TM2==TU6ECL+1	;LENGTH OF TM02 UDB


;****************************
;KDB DEVICE DEPENDANT PORTION

	KDBUDB==KDBDDP		;UDB TABLE (FOR 8 UNITS)
	TM2ADR==KDBUDB+^D8	;MASSBUS ADDRESS OF TM02
	SAVUDB==TM2ADR+1	;CURRENT UDB (0 IF NONE)
	TM.CNI==SAVUDB+1	;CONI OF RH GOES HERE
	TM.CS1==TM.CNI+1	;DATAI RH CONTROL REGISTER
	TM.DBF==TM.CS1+1	;DATAI RH DATA REGISTER

	TM2REG==TM.DBF+1	;DRIVE REGISTERS GO HERE

	DR.CS1==0		;DRIVE CONTROL REGISTER
	DR.DS==1		;STATUS REGISTER
	DR.ER==2		;ERROR REGISTER
	DR.MR==3		;MAINTENANCE REGISTER
	DR.AS==4		;ATTENTION SUMMARY
	DR.FC==5		;FRAME COUNTER
	DR.DT==6		;DRIVE TYPE
	DR.CK==7		;CHECK CHARACTER REGISTER
	DR.SN==10		;SERIAL NUMBER
	DR.TC==11		;TAPE CONTROL REGISTER

	LK.TM2==TM2REG+12	;LENGTH OF KDB
	SUBTTL TM02 ERROR RECOVERY DEFS

;PRESENTLY, IF YOU BACKSPACE INTO BOT, YOU MUST WAIT 8 SEC
;TO REGAIN CONTROL OF THE DRIVE AGAIN (OPI TIMEOUT) BY GETTING AN INT.
;THE DRIVES WILL HOPEFULLY BE FIXED SOMEDAY. UNTIL THEN,
;THIS HANDLER TRIES VERY HARD TO KEEP FROM HITTING BOT
;ON A TAPE CLEAN SEQUENCE IF OPIFIX = 0. MAKE OPIFIX NOT 0
;WHEN THE DRIVES ARE FIXED TO GIVE AN INTERRUPT AS SOON AS THEY
;HIT BOT. (TAPE WILL CLEAN BETTER IF YOU LET THE DRIVE HIT
;BOT.)
	OPIFIX==0

;RETRY COUNTS:
	CLNREC==5		;SP REVERSE THIS NR RECORDS TO HIT CLEANER
	RTYOP==5		;RETRY OPERATION THIS MANY TIMES BEFORE TAPE CLEAN SEQUENCE
	RTYCLN==5		;RETRY CLEAN SEQUENCE THIS MANY TIMES ON READ
				;BEFORE GIVING UP
				;THE TOTAL NR OF RD RETRIES = RTYOP*(RTYCLN+1)

	RTYWRT==^D20		;# WRITE RETRIES MAXIMUM BEFORE ABORT


;ERROR WORDS

;	TU6EBC		;ERR BYTE COUNTER (USED IF WE HIT BOT
				;DURING TAPE CLEAN SEQUENCE)
;	TU6EBP	;ERR BYTE POINTER
;	TU6ECL	;-1= IN TAPE CLN SEQUENCE, 0= NOT
;	UDBERR(RH)		;CURRENT FUNCTION (1 - 17)
				;ON RETRY OF ORIGINAL OPERATION, THIS LOC
				;MUST BE SET TO THE ORIGINAL OPERATION

;	UDBERC ;RETRY COUNT
				;CONVERTED TO # RETRIES DONE AT END
;	TU6EPS	;WE SHOULD BE HERE WHEN WE'RE
				;READY TO RETRY OPERATION
	SUBTTL DISPATCH FOR TM02

TM2DSP::JRST TM2INI		;0 - INITIALIZATION
	JRST TM2SIO		;1 - START I/O
	JRST TM2INT		;2 - HANDLE INTERRUPT (DATA OPERATION OR SPACE)
	JRST TM2ERR		;3 - ERROR RECOVERY
	JRST TM2HNG		;4 - HUNG DEVICE
	RET			;5 - NOT USED
	RET			;6 - NOT USED
	JRST TM2SIO		;7 - START POSITION OPERATION
	JRST TM2ATN		;10 - ATTENTION INTERRUPT (CALLED AS MANY
				;TIMES AS THERE ARE TM02 DRAS BITS UP)
	JRST TM2PRQ		;11 - SKIP IF POSITION REQUIRED
	RET			;12 - STACK SECOND COMMAND, FAIL FOR TM02/3

TM2HNG:	MOVX T1,IS.NRT!IS.ERR!IS.DVE ;SET FATAL BITS
	IORM T1,IRBSTS(P4)	;AND REFRESH IT
	RET

;HERE TO DETERMINE IF THIS REQUEST SHOULD GO ON PWQ OR TWQ

TM2PRQ:	LDB T1,IRYFCN		;GET FUNCTION
	MOVE T1,TM2FTB(T1)	;GET TABLE ENTRY
	TXNN T1,TB.DOP		;DATA OPERATION?
	RETSKP			;NO - POSITION ALWAYS REQUIRED
	HRRZ T2,UDBPWQ(P3)	;YES - ANY PENDING POSITION OPERATIONS?
	JUMPE T2,R		;NONE - APPEND TO TWQ
	CAIN T2,(P4)		;AT HEAD OF PWQ?
	RET			;YES - NEXT TRANSFER
	RETSKP			;APPEND TO PWQ


;ROUTINE TO READ ALL TM02 REGISTERS INTO TM2REG IN THE KDB
TM2RDR:	MOVSI T4,-LK.TM2+TM2REG	;-# REGISTERS
TM2RD1:	SETZM T2		;CLEAR REGISTER ADDRESS
	DPB T4, [POINT 6,T2,5]	;SETUP REGISTER ADDRESS
	CALL RDREG		;READ THE REGISTER
	ADD T4,P2		;POINT TO KDB
	MOVEM T1,TM2REG(T4)	;STORE IT IN THE KDB
	SUB T4,P2		;BACK TO RELATIVE POINTER
	AOBJN T4,TM2RD1		;GO BACK FOR REST OF REGISTERS
	CALL ERRCNI		;GET CONI AND DATAI
	MOVEM T1,TM.CNI(P2)	;SAVE IN KDB
	MOVEM T2,TM.CS1(P2)	; ...
	MOVEM T3,TM.DBF(P2)	; ...
	RET
	SUBTTL TM02 INITIALIZING ROUTINE
;THIS ROUTINE IS CALLED ONCE PER TM02 DRIVE ON THE SYSTEM
;SET UP UDB'S - 1 PER DRIVE ON THE TM02
;INPUT  C(P1)=CDB  C(Q2)=UNIT NR; OUTPUT P2,P3
TM2INI:	SAVEQ			;SAVE REGISTERS
	MOVX T1,LK.TM2		;LENGTH OF KDB
	CALL PHYALC		;RESERVE SPACE
	RET			;RETURN IF NO SPACE FOUND
	MOVEM T1,P2		;SAVE ADDRESS IN PROPER AC
	MOVE P3,T1		;COPY KDB
	MOVEI T1,.BTKDB		;MARK AS KDB
	DPB T1,USYBKT		; ...
	MOVX T2,DO.DT		;GET DRIVE TYPE REG
	CALL RDREG3		; ...
	ANDI T1,777		;GET JUST TYPE CODE
	CAIG T1,TY.T2H		;IS THIS A TM02?
	CAIGE T1,TY.T2L		; ???
	SKIPA T1,[EXP .UTTM3]	;NO - IS TM03
	MOVX T1,.UTTM2		;YES - SET UP UNIT TYPE IN KDB
	STOR T1,USTYP,(P2)	;...
UNINI:	MOVSI T1,-10		;SET UP AOBJN INDEX LH
	HRRI T1,KDBUDB(P2)	;MAKE RH POINT TO UDB ENTRIES IN KDB
	MOVEM T1,KDBIUN(P2)	;INITIAL POINTER
	MOVEM T1,KDBCUN(P2)	;CURRENT POINTER
	HRRZM Q2,TM2ADR(P2)	;SAVE KDB ADDRESS
	MOVEI T1,TM2DSP		;INSERT DISPATCH VECTOR
	MOVEM T1,KDBDSP(P2)	; ...
	MOVSI Q1,-10		;SLAVE INDEX
INILP:	CALL INIUNI		;INITIALIZE A SINGLE UNIT
	JFCL			;IGNORE ERROR RETURN
NODRV:	AOBJN Q1,INILP		;TRY NEXT SLAVE
TOORET:	MOVE T1,P2		;TELL RETURN TO PUT KDB INTO CDB
	RET


;THIS ROUTINE IS CALLED TO INITIALIZE A SPECIFIC SLAVE
;INPUT C(P1)=CDB  C(Q1)=UNIT C(P2)KDB  NR; OUTPUT P3

INIUNI:	HRRZ T2,Q1		;GET CURRENT SLAVE #
	HRLI T2,(DO.TC)		;SET UP FOR TAPE CNTL REGISTER
	CALL WTREG3		;DO IT
	MOVX T2,DO.DT		;GET DRIVE TYPE
	CALL RDREG3
	TXNN T1,DT.SPR		;DOES IT EXIST?
	RET			;NOPE
	HRLOI T3,-MTAN-1	;IF 1ST TIME THRU
INIUN1:	AOBJP T3, [BUG(INF,TM2N2S,<PHYM2 - MORE DRIVES THAN TABLE SPACE, EXCESS IGNORED>)
		JRST TOORET]	;DON'T INITIALIZE ANY MORE SLAVES
	SKIPE MTCUTB(T3)	;CHECK TO SEE IF UNIT FREE
	JRST INIUN1		;NOPE TRY NEXT ONE
	MOVEM T3,MTINDX		;SAVE CURRENT LOGICAL INDEX
	MOVE T3,[TM2DSP,,LU.TM2] ;YES, SET UP ADDRESS,,LENGTH
	ADD P2,Q1		;POINT TO PROPER KDB ENTRY
	CALL PHYUDB		;AND ASK FOR UDB ALLOCATION
	RET			;RETURN IF NO SPACE FOUND
	HRRZM P3,KDBUDB(P2)	;SAVE LINK
	SUB P2,Q1		;FUDGE IT BACK
	HRRZM P2,UDBKDB(P3)	;SAVE BKWDS LINK
	MOVE T3,MTINDX		;GET CURRENT LOGICAL INDEX
	HRLZM P1,MTCUTB(T3)	;SAVE LINK TO CDB IN LOGICAL TABLE
	HRRM P3,MTCUTB(T3)	;SAVE LINK TO UDB
	MOVX T2,DO.DS		;GET DRIVE STATUS
	CALL RDREG3
	MOVX T3,US.TAP		;INDICATE A TAPE TYPE DEVICE
	TXNN T1,DS.MOL		;ON LINE?
	TXO T3,US.OFS		;NO, SET OFF LINE BIT
	TXNE T1,DS.WRL		;WRITE LOCKED?
	TXO T3,US.WLK		;YES
	HLLM T3,UDBSTS(P3)	;SAVE UDB STATUS
	MOVX T3,.UTT45		;UNIT TYPE
	STOR T3,USTYP,(P3)	;SAVE IT
	MOVX T3,UC.200!UC.556!UC.800!UC.160!UC.CD!UC.AA!UC.IC ;DENSITYS AND MODES DRIVE IS CAPABLE OF
	MOVEM T3,UDBCHR(P3)	; AND PUT THAT INFO INTO THE UDB
	MOVX T2,DO.SN		;NOW SERIAL NR
	CALL RDREG
	CALL PHCVBO		;CONVERT BCD TO OCTAL
	MOVEM T1,UDBDSN(P3)	;STORE IT
	HRRZM Q1,UDBSLV(P3)	;SET UP SLAVE ADDRESS
	AOS JB0FLG		;THIS WILL REQUEST JOB0 INCASE CALLER SETS MTAJB0
	RETSKP			;RETURN
	SUBTTL START I/O ROUTINE
;C(P4)=IORB C(P1)=CDB C(P2)=KDB C(P3)=UDB
;IF IN ERR RECOVERY, GET FN FROM RH(UDBERR)
;RET MEANS RE-CALL IN 1 MIN TO TRY AGAIN
;PUTS TM02 FN IN Q1, AND DATAO (IF NEEDED) IN T2
;RETSKP (CHSTRT) MEANS OK, IT'S STARTED

TM2SIO:	HRRZ Q1,UDBERR(P3)	;GET FUNCTION IF ERROR RECOVERY
	SKIPN Q1		;IN ERROR RECOVERY?
	LOAD Q1,ISFCN,(P4)	;NO, GET FN FROM IORB
	SKIPG Q1,TM2FTB(Q1)	;VALID FN?
	JRST BADSIO		;REFUSE TO START IT

	SKIPGE IRBSTS(P4)	;MAKE SURE PAGEM NOT SET
	JRST BADSIO		;IS SET REFUSE IT
	CALL TM2CON		;CONNECT TO DRIVE (AND CLEAR ERRORS)
	 RET			;ERROR
	MOVX T2,DO.FC		;IN CASE WE DON'T WANT TO LOAD FC
	TXNE Q1,TB.NFC		;DO WE LOAD FC WITH SOMETHING SPECIAL?
	JRST NOFC		;NO- LOAD 0
	TXNN Q1,TB.DOP		;DATA OPERATION?
	JRST TM2NDO		;NO, T2=-#RECORDS ON SPACE
	MOVN T2,IRBCNT(P4)	;BYTE COUNT FROM IORB
	LOAD T1,IRBDM,(P4)	;GET DATA MODE
	HLRZ T1,MTBFMT(T1)	;GET MULTIPLIER
	SKIPE T1		;SAVE TIME IF FRAMES=BYTES
	IMUL T2,T1		;CALCULATE # FRAMES
	JRST TM2DO		;WE'RE A DATA OPERATION

BADSIO:	BUG(CHK,PM2SIO,<PHYM2 - ILLEGAL FUNCTION AT START IO>)
	MOVX T1,IS.ERR!IS.NRT!IS.DVE	;MARK AN ERROR OCCURED
	IORM T1,IRBSTS(P4)	;IN IORB
	RET

TM2NDO:	SKIPE UDBERR(P3)	;IN ERROR RECOVERY?
	SKIPA T2,[-1]		;YES, SPACE 1 RECORD
	MOVN T2,IRBCNT(P4)	;NO, DO # RECORDS FROM IORB
TM2DO:	ANDI T2,177777		;16 BITS OF FRM COUNT
	HRLI T2,(DO.FC)		;DO FRM COUNT TO FRM COUNT REGISTER
NOFC:	ANDI Q1,77		;6 BITS OF TM02 FN
	HRRZM P3,SAVUDB(P2)	;SAVE CURRENT UDB IN KDB
	JRST CHSTRT		;NOW START THINGS MOVING
;ROUTINE TO SELECT A SLAVE, SET UP TCREG
;CHECK FOR NECESSARY STATUS BITS
;CALL IT TO BEGIN AN OPERATION WITH C(Q1)=FN TABLE ENTRY
;RET WITH BITS SET IF NOT RDY (OFF-LINE, ETC.) RETSKP IF ALL OK
TM2CON:	MOVX T2,US.IDB		;THE IDB SEEN BIT
	ANDCAM T2,UDBSTS(P3)	;CLR THE BIT IN THE UDB
	MOVX T2,DO.DS		;READY TO READ STATUS REG
	CALL RDREG		;READ IT
	TXNN T1,DS.ERR!DS.SSC	;IS ERROR IR SSC UP?
	JRST TM2CNO		;NO, DON'T DO DRIVE CLR
	MOVX T2,DO.TC		;YES, DO DRIVE CLR
	HRR T2,UDBSLV(P3)	;BUT FIRST SELECT DRIVE ABOUT TO BE USED
	CALL WTREG		;BECAUSE WE KNOW IT'S NOT BUSY
	MOVEI T4,^D10		;COUNT OF ATTEMPTS TO CLEAR ERR
CON1:	MOVX T2,DF.CLR		;FIRST CLEAR OUT DRIVE
	CALL WTREG		;DO IT
	MOVX T2,DO.DS		;SELECT STATUS
	CALL RDREG
	TXNE T1,DS.ERR		;IS ERROR UP?
	JRST [	SOJG T4,CON1	;RETRY EXHAUSTED?
		RET]		;CANT START IO
	CALL TM2POL		;CHECK FOR REWIND DONE
TM2CNO:	HRRZ T2,UDBSLV(P3)	;GET SLAVE #
	HRLI T2,(DO.TC)		;SELECT TAPE CNTL REGISTER
	LOAD T1,IRBDN,(P4)	;GET DENSITY
	CAIG T1,4		;TOO BIG?
	SKIPGE T1,MTBDEN(T1)	;OR ILLEGAL?
	JRST [MOVX T1,IS.ERR!IS.NRT!IS.DVE ;IF ILLEGAL, TREAT AS HARD ERR
		IORM T1,IRBSTS(P4) ;STORE THE STATUS
		RET]
	DPB T1,[POINT 3,T2,27]	;SET IN POSITION IN ACC
	LOAD T1,IRBPAR,(P4)	;GET PARITY
	DPB T1,[POINT 1,T2,32]	;SET IN POSITION
	LOAD T1,IRBDM,(P4)	;GET DATA MODE
	CAIG T1,4		;TOO BIG?
	SKIPGE T1,MTBFMT(T1)	;OR ILLEGAL?
	JRST [MOVX T1,IS.ERR!IS.NRT!IS.DVE ;IF ILLEGAL, TREAT AS HARD ERR
		IORM T1,IRBSTS(P4) ;STORE THE STATUS
		RET]
	DPB T1,[POINT 4,T2,31]	;SET FMT
	CALL WTREG		;FIRE 1!
	MOVX T2,DO.DS
	CALL RDREG		;GET STATUS IN T1
	SETZM T2		;STATUS COMPARISON MSK
	TXNE Q1,TB.WRT		;IS IT A WRITE OPERATION (TBL ENTRY IN Q1)
	TXO T2,DS.WRL		;YES, NEED WRL=0
	TXO T2,DS.MOL!DS.DRY	;ALWAYS REQUIRE THESE BITS
	TXC T1,DS.MOL!DS.DRY	;NEED ALL THESE BITS TO BE 1 SO INVERT
	TDNN T1,T2		;GOOD STATUS?
	RETSKP			;YES, DONE
	MOVX T2,US.WLK!US.OFS	;SET UP THESE BITS
	ANDCAM T2,UDBSTS(P3)	;1ST CLEAR THEM
	TXNN T1,DS.WRL		;WRITE LOCKED?
	TXZ T2,US.WLK		;YES
	TXNN T1,DS.MOL		;ON LINE? (WE COMPL'ED DS.MOL ABOVE)
	TXZ T2,US.OFS		;YES, CLEAR BIT
	IORM T2,UDBSTS(P3)	;SET STATUS IN UDB
	MOVX T2,IS.WLK		;FIX THIS BIT IN IORB
	ANDCAM T2,IRBSTS(P4)	;1ST CLEAR IT
	TXNE Q1,TB.WRT		;WRITE OPERATION?
	TXNN T1,DS.WRL		;AND WRITE LOCKED?
	SKIPA			;NO
	TXO T2,IS.ERR!IS.NRT!IS.DVE ;YES, SET ERROR BITS
	TXNN T1,DS.WRL		;WRITE LOCKED?
	TXZ T2,IS.WLK		;YES, CLEAR BIT
	IORM T2,IRBSTS(P4)	;DO IT
	RET			;FINISHED
	SUBTTL ENTER HERE FROM RH20 COMMAND DONE INTERRUPT
;C(P1)=CDB  C(P2)=KDB
TM2INT:	PUSH P,Q2		;LATER DON'T SAVE TILL AFTER FTLCHK
	PUSH P,Q1		;LIKEWISE, I'M SURE
	SKIPN P3,SAVUDB(P2)	;DO WE HAVE A CURRENT UDB?
	JRST TM2INU		;NO UDB
	SETZM SAVUDB(P2)	;CLEAR THE CURRENT UDB
	CALL SETIRB		;GET ACTIVE IORB
	CALL FTLCHK		;CHECK FOR FATAL ERRS AND PUT DRDS REGISTER
	 JRST [POP P,Q1		;INTO Q2, TM2FTB FN ENTRY INTO Q1
		POP P,Q2
		RET]		;FATAL ERR
	TXNN Q1,TB.WRT		;ARE WE READING?
	TXZ T1,ER.NSG		;YES, IGNORE NSG ERR
TMENTY:	TXNE Q1,TB.REV		;ARE WE BACKWARDS?
	SOSA UDBPS2(P3)		;YES, THEN SUBTRACT 1 RECORD
	AOS UDBPS2(P3)		;NO, ADD 1
	HRRM T1,Q1		;SAVE ERROR REGISTER (LH OF Q1 IS FLAGS)
	TXNN Q2,DS.TM		;IS IT TAPE MARK?
	JRST NOTM		;NOT TM
	TXNE Q1,TB.REV		;ARE WE REVERSE
	SOSA UDBPS1(P3)		;YES, BACK UP 1 FILE
	AOS UDBPS1(P3)		;NO, FORWARD 1 FILE
NOTM:	TXNN Q2,DS.BOT		;ARE WE AT BOT?
	JRST NOBOT		;NO
	SETZM UDBPS1(P3)	;YES, FILE 0
	SETZM UDBPS2(P3)	;RECORD 0
NOBOT:	TXNE Q2,DS.PES		;ARE WE IN PE MODE?
	TXNE Q1,TB.WRT		;AND READ?
	SKIPA			;NO
	TXZ Q1,ER.COR!ER.CS	;YES, THESE ARE NOT ERRORS
	TXNE Q1,TB.RD		;ON READ FCE IS LEGAL
	TXZ Q1,ER.FCE
	TXNN Q1,ER.COR!ER.CS!ER.FCE!ER.NSG!ER.LRC!ER.DPA!ER.INC ;RETRY?
	JRST CKCONI		;NO DATA RETRY ERRS HERE
DORTY:	TXNE Q1,TB.RD		;IN READ?
	TXNN Q2,DS.TM		;AND TM?
	SKIPA			;NO
	JRST NODERS		;YES, THEN DON'T RETRY
	MOVX T3,IS.ERR!IS.DTE	;YES, ERROR- DO RETRY
	IORM T3,IRBSTS(P4)	;SET IORB ERR (DATA ERR)
	CALL TM2RDR		;GET DEVICE REGISTERS
	JRST POPPOL		;POP STACK AND POLL SLAVES
				;DON'T BOTHER SETTING UP STATUS BITS

;HERE WHEN DONE INTERRUPT AND NO SAVED UDB

TM2INU:	BUG(CHK,TM2NUD,<PHYM2 - CHANNEL DONE INTERRUPT BUT NO UNIT ACTIVE>)
	JRST POPPOL		;CLEAN UP STACK
CKCONI:	TXNN Q1,TB.DOP		;DATA OPERATION?
	JRST NODERS		;NO - DONT ASK CHANNEL IF ANY ERRS
	CALL CKERR		;SEE IF ANY RETRIABLE ERRS IN CONI
	 JRST DORTY		;YES, RETRY THE TRANSFER
NODERS:	TXNN Q1,TB.RD		;ARE WE READING?
	JRST SPENTY		;NO, DON'T TELL ABT FRM COUNT
	MOVX T2,DO.FC		;GET FRM COUNT
	CALL RDREG
	ADDM T1,UDBRED(P3)	;ACCUMULATE FRAMES READ
	LOAD T3,IRBDM,(P4)	;GET DATA MODE
	CAIG T3,4		;LEGAL?
	SKIPGE T3,MTBFMT(T3)	;AGAIN?
	JRST [	BUG(CHK,TM2IDM,<PHYM2 - ILLEGAL DATA MODE AT DONE INT>)
		MOVEI T3,0	;ACT LIKE WORDS
		JRST .+1]
	HLRZ T3,T3		;#FRAMES/BYTE
	JUMPE T3,NODIV		;SAVE TIME IF FRAMES=BYTES
	IDIV T1,T3		;CALCULATE # BYTES
	SKIPE T2		;REMAINDER?
	AOS T1			;YES, ANOTHER BYTE
NODIV:	MOVEM T1,IRBCNT(P4)	;TELL HOW MANY FRAMES ON READ
SPENTY:	TXNN Q1,TB.WRT		;WRITE?
	JRST NOTWRT		;NO
	LOAD T3,IRBDM,(P4)	;GET DATA MODE
	HLRZ T3,MTBFMT(T3)	;GET FRAMES/BYTE
	SKIPN T3		;FRAMES=BYTES
	SKIPA T3,IRBCNT(P4)	;YES. JUST GET THE COUNT OF BYTES THEN
	IMUL T3,IRBCNT(P4)	;GET FRAMES
	ADDM T3,UDBWRT(P3)	;ACCUMULATE FRAMES WRITTEN
NOTWRT:	MOVX T2,IS.BOT!IS.EOT!IS.TPM!IS.WLK ;ZERO BITS
	ANDCAM T2,IRBSTS(P4)	;DO IT TO IT
	TXNN Q2,DS.BOT		;AT BOT?
	TXZ T2,IS.BOT		;NO
	TXNE Q1,TB.WRT		;ARE WE WRITING?
	TXNN Q2,DS.EOT		;AND AT EOT?
	TXZ T2,IS.EOT		;NO TO EITHER
	TXNN Q2,DS.TM		;TP MK 
	TXZ T2,IS.TPM		;NO, CLEAR TM FLAG
	TXNE Q1,TB.REV		;SPACE REVERSE OR READ REVERSE
	TXNN Q2,DS.BOT		;AND AT BOT?
	SKIPA			;NO TO EITHER
	TXO T2,IS.TPM		;YES TO BOTH, RETURN TAPE MARK
	TXNN Q2,DS.WRL		;WRITE LOCKED?
	TXZ T2,IS.WLK		;NO
	IORM T2,IRBSTS(P4)	;AND SAVE IT (LEAVE ERR SET IF IT WAS SET)
	MOVX T2,US.OFS!US.BOT	;CLEAR THESE BITS
	ANDCAM T2,UDBSTS(P3)	;DO IT
	TXNE Q2,DS.MOL		;ON LINE?
	TXZ T2,US.OFS		;YES, CLR BIT
	TXNN Q2,DS.BOT		;AT BOT?
	TXZ T2,US.BOT		;NO, CLEAR BIT
	TXNE Q2,DS.IDB		;IS THE STATUS REG IDB BIT SET?
	TXNE Q1,TB.WRT		;AND ARE WE READING?
	SKIPA			;NO, DON'T SET BIT
	TXO T2,US.IDB		;YES, DO SET BIT
	IORM T2,UDBSTS(P3)	;SAVE IT
	TXNE Q1,TB.DOP		;IF A DATA  OPERATION,
	AOS -2(P)		;SKIP RETURN TO THE CHANNEL
	JRST POPPOL		;ANYBODY DONE A REWIND?
				;AND THEN A WORD FROM OUR SPONSOR...
;COMES HERE ON AN ATA INTERRUPT (INCLUDING SPACING OPS)
;C(P1)=CDB C(P2)=KDB
;WILL SET C(P4)= 0 IF NONE
;SETS C(P3)=UDB
;ALWAYS RET (NEVER SKP RET'S)
;IF ERR, IS.ERR AND EITHER <IS.DVE OR IS.DTE> WILL BE SET
;IF IS.ERR NOT SET, WE ARE FINISHED WITH THIS IORB
TM2ATN:	PUSH P,Q2		;SAVE Q2
	MOVE Q2,TM2ADR(P2)	;GET OUR MASSBUS ADDRESS
	MOVX T2,1
	LSH T2,(Q2)		;MASK TO CLEAR OUR ATTENTION BIT
	HRLI T2,(DO.AS)		;REGISTER ADDRESS
	CALL WTREG3		;CLEAR THE BIT
	PUSH P,Q1
	HRRZ P3,SAVUDB(P2)	;GET ACTIVE UDB (IF ANY)
	JUMPE P3,CHKNEW		;IF NO UDB, JUST CHECK FOR REWS AND UNITS ON LINE
	MOVX T1,US.ACT		;UNIT ACTIVE?
	TDNE T1,UDBSTS(P3)	; ??
	JRST CKNDOP		;YES - FINISH UP THEN POLL
	HRRZ Q1,UDBADR(P3)	;GET UNIT ADDRESS
	MOVE P3,TM2ADR(P2)	;GET KONTROLLER ADDRESS
	HRRZ T1,CDBADR(P1)	;GET CHANNEL ADDRESS
	BUG(INF,TM2UNA,<PHYM2 - DONE INTERRUPT AND UDB NOT ACTIVE>,<Q1,P3,T1>)
	SETZB P3,SAVUDB(P2)	;RESET SAVED UDB
	JRST POPPOL		;AND GO POLL
CKNDOP:	CALL SETIRB		;GET CURRENT IORB
	HRRZ Q1,UDBERR(P3)	;GET FUNCTION CODE
	SKIPN Q1		;IN ERROR RECOVERY?
	LOAD Q1,ISFCN,(P4)	;NO, GET IT FROM IORB
	MOVE Q1,TM2FTB(Q1)	;GET FUNCTION ENTRY
	TXNN Q1,TB.DOP		;DATA OPERATION?
	JRST NDOP		;NO
;THE FOLLOWING COMMENTED CODE CAUSES THE 2020 TO GET INTO AN
;INTERRUPT LOOP SINCE THE OPERATION APPEARS NOT TO BE CORRECTLY TERMINATED
;	MOVX T2,DO.DS		;CHECK IF DEVICE STILL ON LINE
;	CALL RDREG		; ...
;	TXNN T1,DS.MOL		;ONLINE?
;	JRST NDOP		;NO - TREAT AS IF TERMINATING NONDATA OP
	MOVEI P4,0		;YES, ENSURE RECALL AT INTERRUPT ENTRY
	JRST TM2ATX		;AND EXIT ATN
NDOP:	SETZM SAVUDB(P2)	;CLEAR SAVED UDB
	CALL FTLCHK		;ANY FATAL ERRORS? (PUT DRIVE STATUS IN Q2,
TM2ATX:	 JRST [POP P,Q1		;YES		TM2FTB ENTRY IN Q1)
		POP P,Q2
		RET]		;FATAL ERR

	TXNE Q1,TB.TM		;WRITE TM OPERATION?
	JRST TMENTY		;YES, USE DATA ROUTINES
	TXNE Q1,TB.ERA		;ERASE OPERATION?
	JRST SPENTY		;YES, DON'T CHECK TAPE POSITION
	TXNE Q1,TB.REW		;REWIND?
	JRST REWSTA		;YES, CLEAR REC CNTRS
	MOVX T2,DO.FC
	CALL RDREG
	MOVN T3,T1		;NEGATE FRM COUNT
	ANDI T3,177777		;ITS ONLY 16 BIT NEG NR
	SKIPE T1,UDBERR(P3)	;ARE WE IN ERR RECOVERY?
	JRST RTYATN		;YES
	EXCH T3,IRBCNT(P4)	;SAVE RESIDUE (# RECORDS NOT SPACED)
	SUB T3,IRBCNT(P4)	;CALCULATE # RECORDS MOVED
	TXNE Q1,TB.REV		;IN REVERSE DIR?
	MOVNS T3		;YES, NEGATE
	ADDM T3,UDBPS2(P3)	;UPDATE REC COUNT
	MOVE T3,IRBCNT(P4)	;GET FRM COUNT AGAIN
	JUMPE T3,NOCKER		;IF ALL RECORDS SPACED, DON'T CHECK ERR
RES1:	TXNN Q2,DS.BOT!DS.EOT!DS.TM ;EARLY TERM OK IF EOT, BOT, OR TM
RESERR:	JRST [	MOVX T1,IS.ERR!IS.DVE!IS.NRT ;INDICATE ERRORS
		IORM T1,IRBSTS(P4)
		CALL TM2RDR	;GET DEVICE REGISTERS
		JRST SPENTY]

	PUSH P,Q2		;MUST EXPLICITLY CLEAR TM02 HERE
	MOVE Q2,TM2ADR(P2)	;GET DEVICE ADDRESS
	MOVX T2,DF.CLR		;CLEAR
	CALL WTREG3		; ...
	POP P,Q2
	; ...
	; ...
;ALL RECORDS SPACED, DON'T BOTHER CHKING ERROR BITS


NOCKER:	TXNN Q2,DS.TM		;TAPE MK?
	JRST NOSTM		;NO
	TXNE Q1,TB.REV		;IN REVERSE DIR?
	SOSA UDBPS1(P3)		;YES, THEN -1
	AOS UDBPS1(P3)		;NO, THEN +1 FILE
NOSTM:	TXNN Q2,DS.BOT		;AT BOT?
	JRST SPENTY		;NO
REWENT:	SETZM UDBPS2(P3)	;YES, ZERO RECORDS
	SETZM UDBPS1(P3)	;ZERO FILES
	JRST SPENTY		;NOW SET STATUS AND RET

REWSTA:	MOVX T1,US.REW		;SET REWINDING
	IORM T1,UDBSTS(P3)	; IN THE UDB
	JRST REWENT		;

POPPOL:	POP P,Q1		;RESTORE REGISTERS
	POP P,Q2
	JRST TM2POL		;AND CHECK FOR REWIND INTERRUPTS

				;COME HERE AT END OF SPACE DURING RETRY
RTYATN:	JUMPN T3,RESERR		;FRAME COUNT 0?
	TXNN Q1,TB.REV		;IN REVERSE DIRECTION?
	AOSA UDBPS2(P3)		;NO FORWARD THE RECORD COUNTER
	SOS UDBPS2(P3)		;YES, BACK IT UP
	TRNN Q2,DS.BOT		;AT BOT?
	JRST NOCKER		;NO, CONT
	JRST RESERR		;CONFUSED ERROR RECOVERY

CHKNEW:	MOVE T4,KDBIUN(P2)	;GET AOBJN POINTER
CHKNW1:	SKIPE (T4)		;EXIST?
	JRST CHKNW2		;YUP DON'T BOTHER WITH IT
	MOVE Q1,T4		;GET UNIT NUMBER
	SUB Q1,KDBIUN(P2)
	HRRZS Q1		;UNIT ONLY
	CALL INIUNI		;INITALIZE UNIT
	SKIPA			;NOT FOUND
	AOS MTAJB0		;TELL JOB0 ABOUT IT
CHKNW2:	AOBJN T4,CHKNW1		;GET NEXT UNIT
	JRST POPPOL		;DO POLLING
;ROUTINE TO CHECK FOR ANY OBVIOUS FATAL ERRORS
;RET IF ERR (WITH IORB STATUS BITS SET)
;SKP RET IF OK
;RETURNS WITH C(T1) THE ERROR REGISTER, C(Q2) DRIVE STATUS REGISTER
;AND C(Q1) THE TABLE ENTRY FOR CURRENT
;FTLCCHK MUST NOT BE CALLED UNLESS AN IORB EXISTS FOR THE UNIT

FTLCHK:	MOVX Q1,IS.DVE!IS.DTE	;READY TO CLEAR THESE BITS
	ANDCAM Q1,IRBSTS(P4)	;DO IT TO IT
	HRRZ T4,UDBERR(P3)	;GET FUNCTION IF ERROR RECOVERY
	SKIPN T4		;IN ERROR RECOVERY?
	LOAD T4,ISFCN,(P4)	;GET FN
	SKIPG Q1,TM2FTB(T4)	;VALID?
	JRST [	BUG(CHK,TM2IF2,<PHYM2 - ILLEGAL FUNCTION ON COMMAND DONE>)
		JRST FTLERR]
	MOVSI T2,(DO.ER)	;GET ERROR REGISTER
	CALL RDREG		; ...
	TXNN T1,ER.RMR!ER.UNS!ER.FMT!ER.DTE!ER.ILR!ER.ILF!ER.CPA ;FATAL ERRS
	JRST DOPCK		;NO FATAL ERRORS HERE
FTLERR:	CALL TM2RDR		;READ ALL REGISTERS
	MOVX T3,US.OFS		;GET OFF LINE
	MOVE T1,TM2REG+DR.ER(P2) ;GET ERROR REG AGAIN
	TXNE T1,ER.UNS		;UNS ERR?
	IORM T3,UDBSTS(P3)	;YES, SET OFF-LINE BIT
	MOVX T3,IS.NRT!IS.ERR!IS.DVE ;SET BITS
	IORM T3,IRBSTS(P4)	;PUT BITS IN IRBSTS
	HRRZ T1,TM2REG+DR.DS(P2) ;GET STATUS REG
	MOVX T3,IS.WLK		;CLEAR STATUS BIT
	ANDCAM T3,IRBSTS(P4)	;CLEAR WRITE LOCK BIT
	TXNE T1,DS.WRL		;WRITE LOCKED?
	IORM T3,IRBSTS(P4)	;YES, SET THE BIT AGAIN
	JRST TM2POL		;REWINDS DONE? (THEN RET)

DOPCK:	MOVE Q2,T1		;SAVE ERROR REGISTER
	MOVSI T2,(DO.DS)	;GET DRIVE STATUS REGISTER
	CALL RDREG		; ...
	EXCH Q2,T1		;PUT DS IN Q2, ER IN T1
	TXNE Q1,TB.RD		;ON READ FCE IS LEGAL (IT IS SHORT RECORD)
	JRST DOPCK1
	TXNE Q1,TB.DOP		;DATA OPERATION?
	TXNE Q2,DS.TM		;EOF ERROR (EOF CAUSES FCE ON RH11)
	JRST DOPCK1		;NON DATA OR EOF -- ALL OK
	TXNE T1,ER.FCE		;FRAME COUNT ERROR CHECK
	JRST FTLERR		;FATAL ERROR ON DATA OPERATIONS
DOPCK1:	CAIE T4,IRFRUN		;UNLOAD FUNCTION?
	TXNE Q2,DS.MOL		;NO, MEDIUM ON LINE?
	SKIPA			;YES, OK
	JRST FTLERR		;NO - QUITE FATAL.
	TXNN T1,ER.OPI!ER.NEF	;OPI OR NEF?
	RETSKP			;OK RET, NO ERR
	TXNE Q1,TB.REV		;IF ERRS, OK IF REVERSE
	TXNN Q2,DS.BOT		;AND AT BOT
	JRST FTLERR		;BAD RET
	RETSKP			;GOOD RET
	SUBTTL ERROR RETRY ENTRY POINT
;P1, P2, P3, P4 SET UP
;ROUTINE PUTS ER BLK ADDRESS IN Q1

TM2ERR:	SAVEQ
	CALL SETIRB		;GET OUR IORB
	HRRZ Q1,UDBERP(P3)	;GET ERROR BLOCK IF PRESENT
	HLLZ T1,IRBSTS(P4)	;GET IORB STATUS
;IF UNS (OFF-LINE ERR), SOMEDAY SHOULD RETRY IN A MIN OR SO.
	HRRZ T4,UDBERR(P3)	;GET FUNCTION IF ERROR RECOVERY
	SKIPN T4		;IN ERROR RECOVERY?
	LOAD T4,ISFCN,(P4)	;NO, GET FN FROM IORB
	MOVE T4,TM2FTB(T4)	;NOW TABLE ENTRY
	TXNN T1,IS.NRT!IS.IER	;FATAL OR INHIBIT ERR RECOVERY?
	JRST TMERTY		;NO, RETRY THE ERROR
	SKIPE TU6EBP(P3)	;WAS FATAL ERR DURING RETRY?
	JRST ABTNOS		;YES, WE ALREADY HAVE BEGIN DATA
	AOS (P)			;SKIP RET FROM LOD1 - DONE WITH IORB
	JRST LOD1		;LOAD UP ERR BLK FOR FATAL ERR

				;DO RETRY
TMERTY:	HLR T4,T4		;COPY LH OF FNTBL
	TRZ T4,777770		;SAVE ONLY RETRY INDEX IN RH
	SKIPE UDBERC(P3)	;1ST TIME FOR HERE?
	JRST NOT1ST		;NO
	SETZM TU6ECL(P3)	;NOT DOING TAPE CLEAN
	SKIPN T1,RTYBPT(T4)	;GET RETRY BYTE POINTER
	JRST [	BUG(INF,TM2IDX,<PHYM2 - ILLEGAL RETRY BYTE POINTER>)
		JRST ABTNOS]	;CALL IT FATAL
	MOVEM T1,TU6EBP(P3)	;SAVE IT
	MOVE T1,UDBPS2(P3)	;GET # RECORDS
	SOS T1			;CALCULATE WHERE WE SHOULD BE AFTER REPOS
	TXNE T4,TB.REV		;IF IN FORWARD, WE WANT (CUR POSITION-1)
	ADDI T1,2		;IF REVERSE, WE WANT (CUR POSITION+1)
	MOVEM T1,TU6EPS(P3)	;WHERE WE SHOULD BE SOMEDAY
	MOVEI T1,RTYWRT+1	;ON WRITE, THIS MANY RETRIES
	TXNN T4,TB.WRT		;ARE WE RIGHT (WRITE)?
	MOVE T1,[RTYCLN+1,,RTYOP+1] ;NO, THIS IS FOR READ
	MOVEM T1,UDBERC(P3)	;THE RETRY COUNTER
	CALL LOD1		;LOAD UP ERR BLK WITH BEGIN DATA
	JRST NXTBYT		;1ST TIME THRU TM2ERR
NOT1ST:	MOVE T1,TU6EBP(P3)	;GET RETRY BYTE POINTER
	ILDB T1,T1		;LOOK AT NEXT OPERATION
	CAIE T1,16		;END OF RETRY?
	JRST CKBOT		;NO
	HLLZ T1,IRBSTS(P4)	;GET IORB STATUS
	TXNN T1,IS.DTE		;WAS THERE DATA ERR?
	JRST RTYNOE		;NO, WE'VE RECOVERED!
	MOVE T1,RTYBPT(T4)	;GET BYTE POINTER
	MOVEM T1,TU6EBP(P3)	;RESET IT
	SETZM TU6ECL(P3)	;NOT DOING TAPE CLN SEQUENCE
	HRRZ T1,UDBERC(P3)	;GET ABORT COUNTER
	SOS T1			;ANOTHER RETRY - SEE IF WE'VE LOST
	HRRM T1,UDBERC(P3)	;SAVE IT
	JUMPN T1,NXTBYT		;IF NOT 0, TRY AGAIN
	TXNE T4,TB.DOP		;DATA OP?
	TXNN T4,TB.RD		;WRITE OR READ?
	JRST ABTRTY		;NONDATA OR WRITE - WE'VE FAILED
	HLRZ T1,UDBERC(P3)	;GET TAPE CLNR COUNTER
	SOJE T1,ABTRTY		;RUN OUT OF RETRIES? - YES
	HRLM T1,UDBERC(P3)	;NO, UPDATE CLN COUNTER
	MOVX T1,RTYOP+1		;NOW RESET (RH) COUNTER
	HRRM T1,UDBERC(P3)	;FOR NEXT CLEAN RETRY
	MOVE T1,RTYBPT+1(T4)	;GET CLEANER SEQ BYTE POINTER
	MOVEM T1,TU6EBP(P3)	;SAVE FOR USE LATER
	SETZM TU6EBC(P3)	;RESET COUNT FOR USE IF WE HIT BOT
	SETOM TU6ECL(P3)	;WE ARE DOING A CLEAN
	JRST NXTBYT		;NOW DO NEXT OPERATION

CKBOT:	SKIPN TU6ECL(P3)	;DOING TAPE CLEAN?
	JRST NXTBYT		;NO DON'T CHECK BOT
	HLLZ T1,IRBSTS(P4)	;GET STATUS
IFE OPIFIX,<SKIPE UDBPS2(P3)>;	ARE WE ALMOST AT BOT?
	TXNE T1,IS.BOT		;OR DID WE HIT BOT?
	SKIPA T1,[CLNREC]	;YES, FIGURE OUT HOW TO FUDGE BYTE POINTER
	JRST NXTBYT		;NO, CONTINUE NORM RETRY
	LOAD T3,ISFCN,(P4)	;GET ORIGINAL FN
	MOVE T3, TM2FTB(T3)	;GET FLAGS
	TXNE T3,TB.WRT		;IS IT A WRITE?
	JRST NXTBYT		;WRITE RETRY WON'T EVER HIT BOT SO NO FUDGE
	TXNN T3,TB.REV		;ADD 1 IF FORWARD
	AOS T1			;DO IT ON FORWARD
	SUB T1,TU6EBC(P3)	;SUBT # RECORDS SPACED
	LSH T1,1		;TIMES 2 (COMMENTS ASSUME CLNREC=5)
	AOS T1			;ON FORWARD, SKIP (6-CNT)*2+1 BYTES
	CAIL T1,1		;ON REVERSE, SKIP (5-CNT)*2+1 BYTES
IFN OPIFIX,<CAILE T1,^D9>;	RESULT MUST BE BETWEEN 1 AND 9
IFE OPIFIX,<CAILE T1,^D11>;	BETWEEN 1 AND 11 IF OPI NOT FIXED
	JSP CX,CNFERR		;BAD INCR, WE ARE CONFUSED
IFE OPIFIX,<SKIPE UDBPS2(P3)>;	IF ALMOST AT BOT, FUDGE 1 LESS
IBPLP:	IBP TU6EBP(P3)		;INCR THE POINTER
	SOJG T1,IBPLP		;ANOTHER?
NXTBYT:	AOS TU6EBC(P3)		;ANOTHER BYTE FOR THE COUNTER
	ILDB T3,TU6EBP(P3)	;GET NEXT FUNCTION
	CAIE T3,17		;IS IT CHECK POSITION OPERATION?
	JRST NOTCKP		;NO
	MOVE T1,UDBPS2(P3)	;YES, GET OUR POSITION
	CAMN T1,TU6EPS(P3)	;ARE WE WHERE WE WANT TO BE?
	JRST NXTBYT		;YES, ALL OK
	JSP CX,CNFERR		;POSITION CONFUSED,SIGNAL ERROR
	JRST ABTNOS		;BOMB OUT

NOTCKP:	CAIE T3,16		;END OF RETRY?
	SKIPG T3		;IS FUNCTION VALID?
	JRST [	BUG(INF,TM2IRF,<PHYM2 - ILLEGAL FUNCTION DURING RETRY>)
		JRST ABTNOS]	;IMAGINE FATAL
	HRRM T3,UDBERR(P3)	;SAVE FUNCTION
	HRRZ T1,CDBDSP(P1)	;GET CHANNEL DISPATCH
	CALL CDSSIO(T1)		;START IO
;SHOULD RETRY EVERY MIN OR SO
	 JRST ABTNOS		;COULDN'T START UP RETRY OPERATION
	RET			;AND WAIT


RTYNOE:	TXNE T1,IS.NRT		;HARD ERRS SHOULDN'T EVER GET HERE
	BUG(CHK,TM2HER,<TM2ERR - IS.HER SET ON SUCCESSFUL RETRY>)
	MOVX T1,IS.ERR		;WE DID IT! CLEAR ERR BIT
	ANDCAM T1,IRBSTS(P4)	;AND SKP RETURN
	TXNN T4,TB.WRT		;ARE WE WRTING?
	AOSA UDBSRE(P3)		;NO, A SOFT READ ERR
	AOS UDBSWE(P3)		;YES, A SOFT WRITE ERR
	JRST ABTNOS

;HERE WHEN ERROR RECOVERY GETS CONFUSED(FLAKEY HARDWARE W I L L DO IT)

CNFERR:	HRRZ T1,UDBADR(P3)	;GET UNIT NUMBER
	MOVE Q1,TM2ADR(P2)	;GET KNOTROLLER NUMBER
	HRRZ T3,CDBADR(P1)	;GET CHANNEL NUMBER
	BUG(CHK,TM2RFU,<PHYM2 - ERROR RECOVERY CONFUSED>,<T1,Q1,T3>)
	MOVSI T1,(IS.ERR!IS.NRT) ;INDICATE RATHER HARD ERR
	IORM T1,IRBSTS(P4)	; ...
	JRST ABTNOS		;AND ABORT
ABTRTY:				;WE RAN OUT OF RETRIES
	TXNN T4,TB.WRT		;ARE WE WRTING?
	AOSA UDBHRE(P3)		;NO, A HARD READ ERR
	AOS UDBHWE(P3)		;YES, A HARD WRITE ERR
ABTNOS:	AOS (P)			;SKIP RET FROM LODE
	HRRZ Q1,UDBERP(P3)	;GET ERROR BLOCK
	SKIPN TU6EBP(P3)	;DONE ANY RETRIES?
	JRST LODE		;NO, LOAD UP ERR BLK WITH END DATA
	TXNN T4,TB.WRT		;YES, IN A WRITE?
	JRST RDCNT		;NO
	MOVEI T1,RTYWRT+1	;YES, CALCULATE # RETRIES DONE
	SUBM T1,UDBERC(P3)	;RESIDUE
	JRST LODE		;NOW LOAD UP ERR BLK

RDCNT:	HLRZ T1,UDBERC(P3)	;GET CLN COUNTER
	IMULI T1,RTYOP		;CONVRT JUST TO # RETRIES
	ADD T1,UDBERC(P3)	;ADD IN REGULAR RETRIES
	MOVEI T2,<RTYCLN+2>*RTYOP+1 ;COUNT AT START
	SUB T2,T1
	HRRZM T2,UDBERC(P3)	;SAVE # RETRIES
	JRST LODE		;NOW LOAD UP ERR BLK
				;LOAD UP ERR BLK AT START OF ERR
				;C(Q1)=ERR BLK

LOD1:	JUMPE Q1,R		;IF NO ERROR BLOCK, PUNT
	MOVE T1,Q1		;COPY ERROR BLOCK
	MOVE T2,[-NITAB,,ITAB]	;POINTER TO INFORMATION TABLE
	CALL SEBCPY		;COPY INFORMATION
	 JFCL
	MOVS T1,UDBPS1(P3)	;GET FILE 
	HRR T1,UDBPS2(P3)	;AND RECORD (JUST AFTER ERROR)
	MOVEM T1,SEBDAT+MB%LOC(Q1) ;AND SAVE AS LOCATION OF ERROR
	MOVEI T1,SEBDAT+MB%REG(Q1) ;MOVE REGISTERS TO HERE
	MOVEM T1,T2		;SAVE FOR RH OF BLT
	ADDI T2,11		;11 WDS
	HRLI T1,TM2REG(P2)	;GET REGISTERS FROM HERE
	HRLI T2,(BLT T1,)	;SET UP INST FIELD
	XCT T2			;DO IT
	RET


				;LOAD UP ERR BLK AT END

LODE:	SETZM TU6EBP(P3)	;RESET ERROR BYTE POINTER
	JUMPE Q1,R		;IF NO ERROR BLOCK, CANT SAVE DATA
	MOVE T3,[-12,,TM2REG]	;CASE FOR START
	ADD T3,P2		;POINTS TO REGISTER DATA
	MOVEI T2,SEBDAT+MB%REG(Q1) ;REGISTER DATA GOES HERE
LDELP:	MOVE T1,(T3)		;GET REGISTER
	HRLM T1,(T2)		;PUT IT
	AOS T2			;NEXT WD
	AOBJN T3,LDELP		;DONE?
	MOVE T1,TM.CNI(P2)	;GET CONI
	MOVEM T1,SEBDAT+MB%CIF(Q1) ;SAVE
	MOVE T1,TM.CS1(P2)	;GET TCR
	MOVEM T1,SEBDAT+MB%D1F(Q1) ;SAVE
	MOVE T1,TM.DBF(P2)	;GET BAR
	MOVEM T1,SEBDAT+MB%D2F(Q1) ;SAVE
	RET


;TABLE OF ITEMS TO COPY INTO ERROR BLOCK

ITAB:	SEBPTR MB%CS0,SBTWD,CDBCS0(P1) ;CHANNEL STATUS 0
	SEBPTR MB%CS1,SBTWD,CDBCS1(P1) ;CHANNEL STATUS 1
	SEBPTR MB%CS2,SBTWD,CDBCS2(P1) ;CHANNEL STATUS 2
	SEBPTR MB%CC1,SBTWD,CDBCC1(P1) ;CCW 1
	SEBPTR MB%CC2,SBTWD,CDBCC2(P1) ;CCW 2
	SEBPTR MB%ICR,SBTWD,CDBICR(P1) ;INITIAL CONTROL REGISTER
	SEBPTR MB%CNI,SBTWD,TM.CNI(P2) ;CONI INITIAL
	SEBPTR MB%D1I,SBTWD,TM.CS1(P2) ;TCR
	SEBPTR MB%D2I,SBTWD,TM.DBF(P2) ;BAR/DBF

NITAB==.-ITAB
	SUBTTL ROUTINE TO POLL SLAVES TO SEE IF DONE REWIND

TM2POL:	PUSH P,P4		;SAVE PERMANENT ACCUMULATORS
	MOVEI P4,11		;GUARD AGAINST BROKEN HARDWARE
	PUSH P,Q2		;WE WILL CLOBBER IT
	PUSH P,P3		;IN CASE WE MUST SWITCH UNITS
	PUSH P,[0]		;VARIABLE FOR REWIND DONE
POLAGN:	MOVSI T4,-10		;#SLVS POSSIBLE
	SETOM T1		;SAYS THAT WE HAVEN'T READ A REGISTER YET
POLLP:	ADD T4,P2		;BUILD POINTER TO KDB ENTRY
	MOVE P3,KDBUDB(T4)	;GET UDB ADDRESS FOR THIS SLAVE
	SUB T4,P2		;FUDGE IT BACK
	MOVE Q2,TM2ADR(P2)	;GET TM02 ADDRESS
	JUMPE P3,TM2PNO		;UNIT NOT KNOWN
	MOVX T2,DO.TC		;READY TO LOAD TAPE CNTL REGISTER
	TRO T2,(T4)		;SELECT THIS SLAVE
	CALL WTREG3		;...
	MOVX T2,DO.DS		;NOW GET STATUS REGISTER
	CALL RDREG3
	HLLZ T2,UDBSTS(P3)	;GET STATUS OF DRIVE
	MOVX T3,US.OFS!US.BOT!US.REW!US.WLK ;CLEAR THESE BITS
	ANDCAM T3,UDBSTS(P3)	;DO IT
	TXNE T1,DS.MOL		;ON LINE?
	TXZ T3,US.OFS		;YES, CLEAR FLAG
	TXNN T1,DS.BOT		;AT BOT?
	TXZA T3,US.BOT		;NO
	JRST [SETZM UDBPS1(P3)	;YES, ZERO REC CNTRS
		SETZM UDBPS2(P3)
		JRST .+1]
	TXNN T1,DS.PIP		;REWINDING? (PIP=1?)
	TXZ T3,US.REW		;NO, CLEAR BIT
	TXNN T1,DS.WRL		;WRITE LOCKED?
	TXZ T3,US.WLK		;NO
	IORM T3,UDBSTS(P3)	;STORE THE STATUS
	TXNE T2,US.REW		;ARE WE REWINDING?(T2 IS OLD UDBSTS)
	JRST	[MOVX T2,US.REW	;OLD STATUS WAS REWINDING, CHECK
		TDNN T2,UDBSTS(P3) ;NEW STATUS FOR CHANGE
		MOVEM P3,(P)	;SAVE UDB WHICH FINISHED REWIND
		JRST .+1]	;AND CONTINUE LOOP
TM2PNO:	AOBJN T4,POLLP		;DO REST OF SLAVES
	JUMPGE T1,TM2NRD	;JUMP IF WE HAVE READ THE STATUS REGISTER
	MOVE Q2,TM2ADR(P2)	;IF NOT, READ IT NOW
	MOVX T2,DO.DS
	CALL RDREG3		;READ THE DRIVE STATUS REGISTER
TM2NRD:	TRNE T1,DS.SSC!DS.ERR	;IS SSC OR ERR UP?
	JRST FNDCLR		;YES, FIND AN INACTIVE DRIVE FOR DRIVE CLEAR
TM2BCK:	POP P,P3		;RECOVER POSSIBLE REWIND DONE UDB
	JUMPE P3,TM2NR1		;IS THERE ONE?
	SKIPN -2(P)		;YES, IS IT LEGAL TO START UP
	CALL PHYRWD		;YES, NOTIFY PHYSIO, MAY START IO
TM2NR1:	POP P,P3
	POP P,Q2
	POP P,P4
	RET
FNDCLR:	MOVE T2,KDBIUN(P2)	;GET AOBJN POINTER
FNDLP:	SKIPN P3,(T2)		;IS ENTRY 0?
	JRST RDYCLR		;YES, DO DRIVE CLEAR HERE
	MOVE T3,UDBSTS(P3)	;GET UDB STATS
	TXNE T3,US.REW		;ARE WE REWINDING?
	AOBJN T2,FNDLP		;YES, TRY NEXT DRIVE
RDYCLR:	SUB T2,KDBIUN(P2)	;SUBT AOBJN POINTER BASE
	HRLI T2,(DO.TC)		;IF ALL REWINDING, DO IT TO 7
	CALL WTREG3		;SELECT IT
	MOVX T2,DF.CLR		;SET UP TO DO CLEAR
	CALL WTREG3		;LOAD IT INTO CONTRL REGISTER (0)
	SOJN P4,POLAGN		;BEGIN POLL AGAIN (THANX TO MATEL ENG)
	BUG(CHK,TM2CCI,<PHYM2 - TM02 SSC OR SLA WONT CLEAR>)
	JRST TM2BCK		;HOPE AND HOPE
	SUBTTL TM02 FUNCTION TABLE
;EACH ENTRY MUST BE NON-0


;1B0			;ILLEGAL FUNCTION
	TB.WRT==1B1		;THIS FUNCTION WRITES ON TAPE
	TB.REV==1B2		;THIS OPERATION MOVES TAPEIN REVERSE DIRECTION
	TB.DOP==1B3		;THIS IS A DATA OPERATION
	TB.SPC==1B4		;THIS IS A SPACE OPERATION
	TB.RD==1B5		;THIS IS A READ
	TB.ERA==1B6		;ERASE OPERATION
	TB.TM==1B7		;WRITE TAPE MARK
	TB.NFC==1B8		;DON'T LOAD FRM COUNT WHEN DOING OPERATION
	TB.REW==1B9		;OPERATION IS A REWIND


;BITS 15,16,17 CONTAIN AN INDEX TO RTYBPT TO TELL US HOW
;TO RETRY AN OPERATION (0 IF NO RETRY)

;BITS 30-35 CONTAIN THE EQUIVALENT TM02 FUNCTION

TM2FTB:	1B0			;0- ILLEGAL
	TB.DOP!TB.RD!TB.NFC!2B17!DF.RDF ;1- READ FORWARD (IRFRED)
	1B0			;2- ILL (RD FMT)
	TB.WRT!TB.DOP!1B17!DF.WTF ;3- WRITE FORWARD (IRFWRT)
	1B0			;4- ILL (WRT FMT)
	1B0			;5- ILL (SEEK)
	TB.SPC!DF.SPF 		;6- SPCE FORWARD
	TB.REV!TB.SPC!DF.SPR	 ;7- SPCE REVERSE
	TB.WRT!TB.TM!6B17!DF.WTM ;10- WRITE TM
	TB.WRT!TB.ERA!TB.NFC!DF.ERA ;11- ERASE
	TB.NFC!TB.REW!DF.REW 	;12- REWIND
	TB.NFC!DF.UNL		 ;13- UNLOAD
	TB.REV!TB.DOP!TB.RD!TB.NFC!4B17!DF.RDR ;14- READ REVERSE
	1B0			;15- ILL (RECOVERY RD)
	1B0			;16- ILL (USED FOR END OF RECOVERY ACTION)
	1B0			;17- ILL (USED FOR CHECK POSITION ACTION)


;CONVT SOFTWARE MODE CODE TO TM02/3 FMT CODE (1B0 IS ILLEGAL)
;LH IS #FRAMES/BYTE (0 MEANS FRAMES=BYTES), RH IS TM02 FORMAT TYPE
MTBFMT:	1B0			;0 - ILLEGAL FMT
	5,,0			;1 - COR DMP (LH MEANS 5 FRAMES PER BYTE)
	1B0			;2 - SIXBIT (7TRK) ILLEGAL
	2			;3 - 7-BIT (ASCII)
	3			;4 - 8-BIT (COMPAT)

;CONVT SOFTWARE DENS CODE TO TM02/3 DENSITY CODE (1B0 IS ILLEGAL)
MTBDEN:	1B0			;0 - ILLEGAL DEN
	0			;1 - 200BPI
	1			;2 - 556BPI
	2			;3 - 800BPI
	4			;4 - 1600BPI
;RETRY TABLES TO TELL HOW TO RETRY

RTYBPT:	0			;ILLEGAL RETRY
	POINT 4,TBRWRT		;WRITE RETRY
	POINT 4,TBRRF		;READ FORWARD RETRY
	POINT 4,TBRRFC		;READ FORWARD TAPE CLEAN
	POINT 4,TBRRR		;READ REVERSE RETRY
	POINT 4,TBRRRC		;READ REVERSE TAPE CLEAN
	POINT 4,TBRWTM		;WRITE TAPE MARK
	0			;ILLEGAL

;THE FOLLOWING MACROS HELP ME GET AROUND SOME SHORTCOMINGS IN MACRO:
;NOTE: THE MACRO'S MUST BE FIXED IN THE UNLIKELY EVENT THAT
;SOMEBODY WANTS TO CHANGE TO A BYTE SIZE WHICH DOESN'T GO
;EVENLY INTO 36(10). RIGHT NOW IT'S 4.

	DEFINE FOO (XXA) <
		WD==0
		BYC==0
		ZZ==0		;FLIP-FLOP
	IRP XXA,<
	IFE ZZ,<RP==XXA>
	IFN ZZ,<FOO1 RP,XXA>
	ZZ==ZZ+1
	IFE ZZ-2,<ZZ==0>>
	IFN BYC,<EXP WD>>

	DEFINE FOO1 (A1,A2) <
	REPEAT A1,<
		WD==WD+<A2>B<4*BYC+3>
		BYC==BYC+1
	IFGE BYC-^D9, <
			EXP WD
			WD==0
			BYC==0>>>

TBRWRT:	BYTE (4) IRFBSB,IRFERG,17,IRFWRT,16
				;WRITE RETRY - SPACE REVERSE, ERASE, CHECK POSITION, WRITE
TBRWTM:	BYTE (4) IRFBSB,IRFERG,17,IRFWTM,16
			;WTM RETRY - SPACE REVERSE, ERASE, CHECK POS, WTM, EOR
TBRRF:	BYTE (4) IRFBSB,17,IRFRED,16
				;READ FORWARD RETRY - SPACE REVERSE, CHECK POSITION, READ FORWARD
TBRRR:	BYTE (4) IRFFSB,17,IRFRDR,16
				;READ REVERSE RETRY - SPACE FORWARD, CHECK POSITION, READ REVERSE

TBRRFC:	FOO<CLNREC+1,IRFBSB, CLNREC,IRFFSB, 1,17, 1,IRFRED, 1,16>
				;RD FORWARD TAPE CLEAN: 6 SP REVERSE, 5 SP FORWARD, CHECK POSITION, RD FORWARD
TBRRRC:	FOO<CLNREC,IRFBSB, CLNREC+1,IRFFSB, 1,17, 1,IRFRDR, 1,16>
				;RD REVERSE TAPE CLEAN: 5 SP REVERSE, 6 SP FORWARD, CHECK POSITION, RD REVERSE
	TNXEND
	END