Google
 

Trailing-Edge - PDP-10 Archives - bb-jr93d-bb - 7,6/ap015/t78kon.x15
There are 2 other files named t78kon.x15 in the archive. Click here to see a list.
TITLE T78KON - RH20/TM78/TU78 DRIVER FOR TAPSER   V063
SUBTTL	T WACHS/TW	22 JUL 86
	SEARCH	F,S,ICHPRM
	$RELOC
	$HIGH



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


;
XP VT78KN,063
	SALL

ENTRY	T78KON
	;OFFSETS INTO TKBCCL
	TKBSCW==TKBCCL##+1		;SAVED CHANNEL WORD
	TKBFLG==TKBCCL##+2		;FLAGS FROM FNCTBL
	TKBCHR==TKBCCL##+3		;CHARACTER (FRAME) COUNT
	TKBSCH==TKBCCL##+4		;-1 IF A SCHEDULE CYCLE

T78KON::

T78DSP::IFIW	T78INI		;00 - INITIALIZE
	IFIW	T78RES		;01 - RESET ACTIVE I/O
	IFIW	T78SIO		;02 - START IO
	IFIW	T78INT		;03 - INTERRUPT SERVICE
	EXP	0		;04 - SET DEVICE COMMAND
	IFIW	CPOPJ##		;05 - KONTROLLER IS IDLE
	IFIW	T78ONL		;06 - TEST IF CTL IS ON-LINE
	IFIW	T78SCH		;07 - FORCE A SCHEDULE CYCLE
	IFIW	T78INR		;10 - RE-INITIALIZATION
	IFIW	CPOPJ##		;11 - LOAD MICROCODE
	IFIW	CPOPJ##		;12 - ENABLE/DISABLE MICROCODE LOADING
IFN FTAUTC,<IFIW T78CFG>	;13 - AUTO CONFIGURE
	SUBTTL	PARAMETERS

	;DRIVE REGISTERS USED IN DATAO'S

	.DOCR==0B5		;DRIVE CONTROL REGISTER
	.DOICD==1B5		;INTERRUPT CODE (DATA XFER)
	   DO.ICD==77		;INTERRUPT CODE
	   DI.FCD==176000	;FAILURE CODE
	.DOFMT==2B5		;RECORD COUNT/FORMAT
	   DO.SER==100000	;SUPRESS ERROR RETRY
	   DO.RC1==4		;RECORD COUNT RIGHTMOST BIT
	.DOER==3B5		;ERROR REGISTER
	.DOAS==4B5		;ATTENTION SUMMARY
	.DOBC==5B5		;BYTE COUNT
	.DODT==6B5		;DRIVE TYPE
	.DOSR==7B5		;STATUS REGISTER
	   DI.RDY==100000	;READY
	   DI.PRS==40000	;PRESENT
	   DI.PE==4000		;PHASE ENCODED
	   DI.BOT==2000		;BOT
	   DI.FPT==400		;FILE PROTECTED
	   DI.AVL==200		;AVAILABLE
	   DI.MNT==40		;IN MAINTENANCE MODE
	.DOSN==10B5		;SERIAL NUMBER
	.DODG==11B5		;DIAGNOSTIC
	.DODG2==12B5		;DIAGNOSTIC
	 ICNREG==13
	.DOICN==13B5		;INTERRUPT CODE (NON DATA-XFER)
	   DI.DRV==1400		;DRIVE NUMBER
	.DOND0==14B5		;NON DATA-XFER COMMAND, UNIT 0
	   DO.NDC==177400	;COUNT FIELD
	   DO.NDF==77		;FUNCTION CODE
	   NDCSHF==^D8		;SHIFT VALUE FOR COUNT
	.DOND1==15B5		;COMMAND, UNIT 1
	.DOND2==16B5		;COMMAND, UNIT 2
	.DOND3==17B5		;COMMAND, UNIT 3
	.DOIA==20B5		;INTERNAL ADDRESS
	.DOTMS==21B5		;TM STATUS
	   DI.TMR==1B20		;TM READY
	   DO.TMC==1B21		;TM CLEAR
	   DO.HLA==1B26		;HOLD ACKNOWLEDGED
	   DO.HLD==1B27		;HOLD
	;DRIVE FUNCTIONS
	DF.NOP==3		;NO-OP
	DF.UNL==5		;UNLOAD
	DF.REW==7		;REWIND
	DF.SNS==11		;SENSE
	DF.DSE==13		;DATA SECURITY ERASE
	DF.WTM==15		;WRITE TAPE MARK (PE)
	DF.SPF==21		;SPACE FORWARD RECORD
	DF.SPR==23		;SPACE REVERSE RECORD
	DF.SFF==25		;SPACE FORWARD FILE
	DF.SRF==27		;SPACE REVERSE FILE
	DF.SFE==31		;SPACE FORWARD RECORD OR FILE
	DF.SRE==33		;SPACE REVERSE RECORD OR FILE
	DF.ERG==35		;ERASE 3 INCHES OF TAPE (PE)
	DF.CLF==41		;CLOSE FILE (PE) - 2 EOFS, BACKSP 1
	DF.LET==45		;SKIP TO LOGICAL EOT

	DF.WRT==61		;WRITE (PE)
	DF.RED==71		;READ
	DF.RRV==77		;READ REVERSE
	DF.XSN==73		;EXTENDED SENSE

;BYTE POINTER TO FAILURE CODE IN EXTENDED SENSE DATA
TUYECD:	POINT	8,T78REG##+30(U),35
	SUBTTL	START IO
;HERE TO START IO
T78SIO:	PUSHJ	P,CHKIRB##	;GET IORB FOR THIS OP
	  JRST	TAPDIS##	;NONE, GO AWAY
	PUSHJ	P,SAVE1##	;SAVE P1
	LDB	T4,PRBFCN##	;FUNCTION
	SKIPN	T78RRO##(W)	;ARE WE IN RETRY OPPOSITE?
	JRST	T78SI1		;NO
	CAIN	T4,RB.FRB	;YES, TRYING TO DO A REVERSE READ?
	MOVEI	T4,RB.FRD	;YES, RETRY FORWARD
	CAIN	T4,RB.FCR	;DOING A CORRECTIVE READ?
	MOVEI	T4,RB.FRB	;YES, READ BACKWARDS
T78SI1:	SKIPN	P1,FNCTBL(T4)	;LEGAL?
	JRST	ILLFNC		;NO
	SKIPGE	T2,TRBRCT(T1)	;IF POSITIVE IN ERROR RECOVERY
	MOVEM	T2,T78UVA##(W)	;REAL IOWD - SAVE IT
	SKIPGE	T78ACT##(W)	;DID WE SHUT OFF TM TO PREVENT EXCESSIVE INTERRUPTS?
	PUSHJ	P,CLRHLD	;YES, CLEAR HOLD SO WE CAN TALK TO IT AGAIN
	SETZM	T78ACT##(W)	;CLEAR ASYNC INTERRUPT COUNT
	LDB	T4,PRBDEN##	;GET DENSITY
	CAIGE	T4,RB.D16	;TOO LOW?
	MOVEI	T4,RB.D16
	CAILE	T4,RB.D62	;TOO HIGH?
	MOVEI	T4,RB.D62
	DPB	T4,PRBDEN##	;TELL THE REST OF THE WORLD
	CAIN	T4,RB.D62	;6250?
	TLNN	P1,(TB.WRT)	;YES, WRITE?
	JRST	T78SI2		;NO
	TROA	P1,WT.GCR	;YES, SET 6250 IN FUNCTION
ILLFNC:	MOVE	P1,FNCNOP	;ILLEGAL FNCN - JUST GET AN INTERRUPT
	JRST	T78SI2		;GO START THE OPERATOIN
SENSE:	MOVEM	P1,T78SNS##(U)	;TELL INTERRUPT SERVICE WE ARE DOING A SENSE
T78SI2:	MOVEI	T3,CO.MBE	;ENABLE THE MASSBUS, DISABLE INTERRUPTS
	XCT	T78COS##(W)
	LDB	T3,[POINT 2,TUBADR##(U),35] ;GET UNIT NUMBER
	SKIPE	T78SNS##(U)	;SENSE?
	JRST	[MOVEI T2,DF.SNS ;YES, DO IT
		 JRST T78SI3]
	JUMPL	P1,T78SI4	;NO, GO IF A DATA OP
	MOVE	T2,TRBXCW(T1)	;SENSE OR NON-DATA. GET COUNT
	LSH	T2,NDCSHF	;POSITION IT
	ANDI	T2,DO.NDC	;MASK OUT GARBAGE
	TRO	T2,(P1)		;SET FUNCTION FROM TABLE
T78SI3:	ADDI	T3,<(.DOND0)>_-14 ;GET RIGHT REGISTER (14=DRIVE 0, 15=DRIVE 1,...)
	DPB	T3,[POINT 4,T2,5] ;SAVE REGISTER IN FUNCTION
	JRST	T78SI6		;GO START UP THE WORLD
;HERE TO START A DATA OPERATION
T78SI4:	LDB	T4,PRBMOD##	;GET MODE
	SKIPGE	T4,MODTBL(T4)	;LEGAL?
	JRST	ILLFNC		;NO
	MOVEI	T2,(T4)		;YES. SET MODE IN COMMAND
	TRO	T2,DO.RC1(T3)	;RECORD COUNT=1, SET UNIT
	TLNE	S,IOSRTY##	;IF NOT DOING RETRIES
	TRO	T2,DO.SER	;INFORM THE HARDWARE
	HRLI	T2,(.DOFMT)	;TELL MODE, COUNT, UNIT
	PUSHJ	P,WTREG
	MOVS	T2,T78UVA##(W)	;GET WORD COUNT
	HLRZS	T4		;NO OF FRAMES PER WORD
	TLOE	T2,-1		;DO WE ALREADY HAVE FRAME COUNT ?
	IMULI	T2,(T4)		;COMPUTE FRAME COUNT
	MOVNM	T2,TKBCHR(W)	;SAVE IN KDB
	MOVNS	T2		;+FRAME COUNT
	ANDI	T2,DO.ERD	;ONLY 16 BITS WORTH
	HRLI	T2,(.DOBC)
	PUSHJ	P,WTREGX	;TELL BYTE COUNT REGISTER
	HRRZ	T2,TKBICP##(W)	;INITIAL CNTRL WORD ADDRESS
	HRRZ	T3,TRBXCW(T1)	;LOC OF FIRST IOWD
	TLO	T3,RH2JMP##	;MAKE A JUMP TO IT
	MOVEM	T3,(T2)		;STORE IN ICWA
	HRRZ	T2,P1		;FUNCTION (READ/WRITE, PE/GCR)
T78SI5:	TDO	T2,[.DOSTC!DO.RCP!DO.SCS!DO.CNT]
T78SI6:	SKIPN	T78SNS##(U)	;IF NOT DOING A SENSE
	MOVEM	T2,T78REG##+5(U);SAVE FUNCTION IN UDB FOR SYSERR
	MOVE	T3,T2		;COPY FUNCTION WORD
	ANDI	T3,77		;MASK TO FUNCTION BYTE
	CAIE	T3,DF.SNS	;IF NOT DOING A SENSE,
	MOVEM	P1,TKBFLG(W)	;SAVE WHAT THE KONTROLLER IS DOING
	PUSHJ	P,WTREG		;START UP THE WORLD
	PUSHJ	P,SETIVI	;SET UP INTERRUPT VECTOR
	MOVEI	T3,TAPCHN##+CO.AIE+CO.MBE
	XCT	TKBCIS##(W)	;CONI
	TRNE	T2,CI.RAE	;REGISTER ACCESS ERROR?
	MOVEI	T3,TAPCHN##+CO.MBE+CO.STP ;YES, GET TO INTERRUPT LEVEL RIGHT AWAY
	XCT	T78COS##(W)	;NO, ENABLE FOR INTERRUPTS
	SKIPE	T78SNS##(U)	;SENSE?
RTZER:	SETZ	T1,		;YES, ANOTHER INTERRUPT COMING
	POPJ	P,		;RETURN TO TAPSER
	SUBTTL	INTERRUPT PROCESSING

T78INT:	PUSHJ	P,SAVE3##	;SAVE SOME ACS
	MOVE	P1,TKBFLG(W)	;GET COMMUNICATION/FLAGS WORD
	XCT	TKBCIS##(W)	;CONI
	MOVE	P2,T2		;SAVE IT IN P2
	TRNE	T2,CI.RAE	;REGISTER ACCESS ERROR?
	JRST	NOATT1		;YES, HANDLE IT
	MOVSI	T2,(.DOAS)	;NO, READ ATTEN SUMMARY
	PUSHJ	P,RDREG
	ANDI	T2,377		;JUST REAL ATTENTIONS
	TDNN	T2,TKBUNI##(W)	;ATTENTION FOR THIS KDB?
	JRST	NOATTN		;NO
	PUSHJ	P,ATTEN		;GO HANDLE IT
	  POPJ	P,		;ASYNC EVENT - RETURN 0 OR -1 TO TAPSER
	JUMPE	T1,INTREW	;REW COMPLETE IF T1=0
	SKIPN	T78SNS##(U)	;COMPLETE A SENSE?
	TLNN	P1,(TB.DAT)	;NO, DATA OPERATION IN PROGRESS?
	JRST	CHEKIT		;SENSE OR NON-DATA
	TLO	T1,RB.SDE	;DATA OPERATION + ATTENTION - CANT HAPPEN
	JRST	DONE		;SO LIGHT AN ERROR AND RETURN
;HERE IF NO ATTENTIONS
NOATTN:	TRNN	P2,CI.DON	;DONE?
	JRST	RTZER		;NO, ERROR (NO ATTEN, NOT DONE = RH20 GOOFED)
NOATT1:	SKIPE	T1,TKBSCH(W)	;SCHEDULE CYCLE?
	JRST	SCHDON		;YES, TELL TAPSER ABOUT IT
	MOVEI	T3,CO.CCD!CO.MBE;NO, CLEAR DONE
	XCT	T78COS##(W)
	MOVE	U,TKBCUN##(W)	;UNIT WE ARE TALKING TO
	MOVE	U,(U)
	SKIPE	T78SNS##(U)	;DOING A SENSE?
	TLNN	P1,(TB.XSN)	;YES, AN EXTENDED SENSE?
	JRST	NOATT2		;NO
	MOVE	T2,TKBSCW(W)	;YES, RESTORE REAL CHAN GOTO WORD
	MOVEM	T2,@TKBICP##(W)
	SETZM	TKBSCW(W)	;INDICATE WE DON'T HAVE A REAL IOWD ANY MORE
	PUSHJ	P,ATTEN3	;FINISH UP INTERRUPT PROCESSING
	  JRST	CLRCTL		;ASYNC
	JRST	CHEKIT		;KEEP ON TRUCKIN
NOATT2:	MOVSI	T2,(.DOICD)	;GET INTERRUPT CODE
	PUSHJ	P,RDREG
	MOVE	P3,T2		;WHERE ATTEN6 WANT IT
	PUSHJ	P,T78STS	;READ WLK, BOT, AND DENSITY
	PUSHJ	P,ATTEN6	;CHECK IT FOR GOODNESS
	  PJRST	CLRCTL		;ASYNC EVENT (!)
	TLNE	T4,RB.SER!RB.SED ;IF AN ERROR,
	JRST	CHEKIT		; DON'T BOTHER CHECKING CHANNEL FOR ERRORS
	MOVE	T3,TKBICP##(W)	;GET LOC OF LOGOUT AREA
	HLL	P2,1(T3)	;GET RH20 LH FLAGS
	TLC	P2,(CS.NAE)
	TLNE	P2,(CS.SWC)	;IF SHORT WORDCOUNT (RECORD TOO LONG)
	TRZ	P2,CI.OVR	;THEN OVERRUN CAME UP ERRONEOUSLY
	TDNE	P2,[CS.ERR!CI.ERR] ;CHANNEL ERROR?
	JRST	CHNERR		;TOO BAD

CHEKIT:	LDB	T4,[POINT 4,P1,17] ;GET INDEX INTO FUNCTION TABLE
	HLL	T1,TRBSTS(T1)	;GET ERROR BITS
	TLNN	P1,(TB.ERA!TB.REW) ;ERASE OR REWIND?
	TLNE	T1,RB.SNM!RB.SAP ;NO, ANY TAPE MOTION
	JRST	NOTM		;DON'T UPDATE TUBREC/FIL
	MOVEI	T2,1		;ASSUME FORWARD
	TLNE	P1,(TB.REV)	;IS IT?
	MOVNI	T2,1		;NO
	ADDM	T2,TUBREC##(U)	;UPDATE TUBREC
	TLNN	P1,(TB.WTM)	;JUST WRITE AN EOF?
	TLNE	T1,RB.STM	; OR JUST SEE AN EOF?
	CAIA			;YES
	JRST	NOTM		;NO
	ADDM	T2,TUBFIL##(U)	;UPDATE TUBFIL
	SETZM	TUBREC##(U)	;AT 0TH RECORD
NOTM:	MOVSI	T2,TUSBOT##	;ASSUME NOT AT BOT
	ANDCAM	T2,TUBSTS##(U)
	TLNE	T1,RB.SBT	;ARE WE?
	IORM	T2,TUBSTS##(U)	;YES, TELL THE REST OF THE WORLD
	PJRST	@INTABL(T4)	;THE LEAP OF FAITH
;SUBROUTINE TO HANDLE ATTENTION INTERRUPTS
;EXIT T1=ERROR BITS,,IORB  OR T1=0 IF REWIND JUST FINISHED
;NON-SKIP IF ASYNCHRONOUS EVENT, SKIP-RETURN NORMALLY
ATTEN:	MOVSI	T2,(.DOICN)	;READ THE INTERRUPT CODE
	PUSHJ	P,RDREG
	MOVE	P3,T2		;SAVE IT (IT DISAPPEARS AFTER CLEARING ATTENTION)
	HRRZ	T2,TKBUNI##(W)	;GET BIT FOR ATTENTIONS ON THIS UNIT
	HRLI	T2,(.DOAS)
	PUSHJ	P,WTREGX	;CLEAR THIS ATTENTION, LEAVE ANY OTHERS ALONE
	LDB	T1,[POINT 2,P3,27] ;GET UNIT
	HRLS	T1		;IN BOTH HALVES
	ADD	T1,TKBIUN##(W)	;POINT AT RIGHT UDB
	SKIPE	U,(T1)		;SET UP U TO UDB
	JRST	ATTEN2		;YES, PUSH ON

;HERE IF NO UDB IS FOUND FOR THE INTERRUPT ADDRESS
	LDB	T1,[POINT 5,P3,35] ;GET INTERRUPT CODE
	CAIE	T1,ICDND1	;IS IT ONE FOR WHICH THE ADDRESS ISNT VALID?
	CAIN	T1,ICDND2
	SKIPA	T1,TKBCUN##(W)	;YES, BLAME IT ON THE CURRENT UNIT
	JRST	ATTE15		;NO,NEW UNIT
	SKIPN	U,(T1)		;SET U TO CURRENT UDB
	JRST	CLRINT
ATTEN2:	SKIPN	T78SNS##(U)	;DOING A SENSE?
	JRST	[PUSHJ P,T78STS	;NO--READ WLK, BOT, AND DENSITY
		 JRST  ATTEN6]	;ONWARD
	MOVE	P1,T78SNS##(U)	;SET P1 FOR THIS FUNCTION
	TLZN	P1,(TB.RRG)	;SENSE WHILE READING REGISTERS?
	JRST	ATTEN4		;NO, CARRY ON
	PUSHJ	P,RDREG2	;YES, READ REGS 7, 10, 11
	SKIPGE	T78ESD##(U)	;SENSE AFTER AN RH20 ERROR?
	JRST	ATTEN3		;NO
	MOVE	T4,[IC.BST!RB.SED] ;YES, CAUSE AN ERROR BIT TO GET LIT IN IORB
	JRST	ATTEN9
ATTEN3:	MOVE	T4,T78ESD##(U)	;RESTORE ERROR BITS
	TLNE	T4,(IC.XSN)	;NEED EXTENDED SENSE INFO?
	TLOE	P1,(TB.XSN)	;YES, HAVE WE DONE IT ALREADY?
	JRST	ATTEN9		;FINISH UP INTERRUPT
	JRST	ATTE14		;GO CRANK UP EXTENDED SENSE
ATTEN4:	MOVSI	T2,(.DOSR)	;READ THE STATUS REGISTER
	PUSHJ	P,RDREG
	JUMPL	P1,ATTEN5	;GO IF A DATA OP
	MOVSI	T4,TUSWTL##!TUSBOT## ;NON-DATA, CLEAR WRITE-LOCK BIT, BOT
	ANDCAM	T4,TUBSTS##(U)
	TRNN	T2,DI.FPT	;AND SET IT AGAIN IF TAPE REALLY IS WRITE LOCKED
	TLZ	T4,TUSWTL##	;NOT WRITE-LOCKED
	TRNN	T2,DI.BOT
	TLZ	T4,TUSBOT##	;NOT AT LOAD-POINT
	IORM	T4,TUBSTS##(U)
	JRST	ATTEN6		;PUSH ON
;HERE ON SENSE WHILE DOING A DATA OP - AFTER READ OF 1ST RECORD ON TAPE
ATTEN5:	MOVE	T3,T2		;PRESERVE STATUS REG
	PUSHJ	P,CHKIRB##	;SET T1
	  JRST	TAPDIS##	;NONE??????
	MOVEI	T4,RB.D16
	TRNN	T3,DI.PE	;SET MODE/DENSITY CORRECTLY
	MOVEI	T4,RB.D62
	DPB	T4,PRBDEN##	;AND TELL THE REST OF THE WORLD

;HERE ON NORMAL ATTENTION INTERRUPT
ATTEN6:	LDB	T2,[POINT 5,P3,35] ;GET INTERRUPT CODE
	CAIE	T2,ICDND1	;ASYNC INTERRUPT WHERE REGS NOT READ?
	CAIN	T2,ICDND2
	JRST	[MOVEI T1,T78REG##+7(U)	;YES. CLEAR OUT OLD INFO
		 HRLI T1,-1(T1)	; SO AS NOT TO CONFUSE FIELD-SERVICE
		 SETZM -1(T1)	; SINCE WE CAN'T GET ANY OTHER INFORMATION
		 BLT T1,T78REG##+47(U)
		 MOVEM	P3,T78REG##+6+ICNREG(U) ;SAVE INTERRUPT CODE
		 JRST .+1]
	CAILE	T2,MAXICD	;LEGAL?
	MOVEI	T2,0		;NO
	SKIPN	P3,T78RRO##(W)	;DOING RETRY OPPOSITE?
	JRST	ATTEN8		;NO
	TLC	P1,(TB.REV)	;YES, THE OPERATION IS REALLY IN THE OTHER DIRECTION
	SETZM	T78RRO##(W)	;EITHER WIN OR RETRY IN ORIGINAL DIRECTION - CLEAN UP
	PUSH	P,T2
	PUSHJ	P,CHKIRB##	;GET IORB
	  JRST	ATTEN7		;NONE (!)
	LDB	T3,PRBFCN##	;GET FUNCTION
	HLRZ	T2,TUBCHR##(U)	;GET WORDCOUNT OF RECORD
	SKIPL	FNCTBL(T3)	;IF A DATA OPERATION
	JRST	ATTEN7		;NOT A DATA OP!
	PUSHJ	P,REVCCW##	;RE-REVERSE THE IO LIST
	HLLM	P3,(P3)		;RESTORE ORIGINAL LH OF CHANGED IOWD
ATTEN7:	POP	P,T2
ATTEN8:	SKIPL	T4,ICDTBL(T2)	;GET BITS/DISPATCH ADDRESS
	JRST	ATTEN9		;NO ERROR, KEEP ON
	SKIPE	TUBERR##(U)	;ERROR. FIRST TIME WE'VE SEEN IT?
	TRNN	T4,RB.SAP	;YES. DOES TM REPOSITION ON THIS ERROR?
	JRST	ATTE13		;1ST TIME OR NO REPOS, READ REGISTERS
ATTEN9:	TLNN	T4,(IC.RRG)	;WIN WITH NO ERRORS?
	SKIPN	TUBERR##(U)	;YES, IN ERROR RETRY?
	CAIA
	PUSHJ	P,RDREG3	;GOOD RETRY - READ WINNING REGISTERS
	TLNN	T4,(IC.ASY)	;ASYNC INTERRUPT?
	AOS	(P)		;NON ASYNC - SKIP RETURN
	TLNE	T4,(IC.DSP)	;DISPATCH ON THIS CONDITION?
	PJRST	(T4)		;YES, GO TO SUBROUTINE
ATTE10:	TLNN	T4,(IC.BST)	;NO, SET A BIT?
	TDZA	T4,T4		;NO
	HRLZS	T4		;YES
	PUSHJ	P,CHKIRB##	;NO, POINT T1 AT IORB
	  SETZ	T1,		;NO IORB
	MOVE	T2,TUBSTS##(U)	;GET STATUS
	TLNE	T2,TUSREW##	;WAS IT REWINDING?
	JRST	ATTE11		;YES, PROBABLY ASYNC INTERRUPT AT BOT
	JUMPE	T1,ATTE12	;GO IF NO IORB
	IORM	T4,TRBSTS(T1)	;LIGHT BIT IN LH(T1)
	POPJ	P,		;AND RETURN
;HERE IF TUSREW IS ON IN TUB
ATTE11:	JUMPE	T1,CPOPJ##	;AT BOT IF NO IORB
	LDB	T2,PRBFCN##	;IORB - IS IT THE REWIND?
	CAIE	T2,RB.FRU
	CAIN	T2,RB.FRW
	POPJ	P,		;YES. REW WHEN WE'RE AT BOT (IMMEDIATE DONE INTERRUPT)
	JRST	RTZER		;NO, ANOTHER IORB HAS BEEN QUEUED. WE'RE AT BOT

;HERE WITH NO IORB, TAPE WAS NOT REWINDING
ATTE12:	SOS	(P)		;NON-SKIP RETURN
	SETZB	T1,T78SNS##(U)	;PROBABLY SENSE AFTER ON-LINE
	POPJ	P,		;RETURN WITH T1=0

;HERE ON AN ERROR WHICH REQUIRES READING THE DRIVE REGISTERS
ATTE13:	SETZM	T78RRO##(W)	;CLEAN UP FLAGS
	PUSHJ	P,RDREGS	;READ REGS (7-10 AREN'T CORRECT)
	TLO	P1,(TB.RRG)	;INDICATE WHY WE'RE DOING THE SENSE
	MOVEM	T4,T78ESD##(U)	;SAVE ERROR BITS FOR WHEN SENSE FINISHES
	PJRST	SENSE		;DO A SENSE SO WE CAN READ REGS 7-10

;HERE WHEN WE NEED TO START AN EXTENDED SENSE OPERATION TO READ ERROR INFO
ATTE14:	MOVEM	P1,T78SNS##(U)	;UPDATED FLAGS WORD
	MOVEI	T2,TKBCCL##(W)	;WHERE TO DO THE SENSE
	MAP	T2,(T2)		;CONVERT TO PHYSICAL ADDRESS
	TLZ	T2,777760
	TLO	T2,RH2JMP##	;MAKE AN RH20 JUMP WORD
	EXCH	T2,@TKBICP##(W)	;SAVE CURRENT ICWA, SET UP JUMP TO TEMP
	MOVEM	T2,TKBSCW(W)
	MOVE	T2,T78XIW##(W)	;IOWD TO READ SENSE BYTES INTO TUB
	ADDI	T2,(U)		;POINT AT RIGHT TUB
	HLLZM	T2,TKBCCL##(W)	;SAVE WHERE ICWA POINTS
	MAP	T2,(T2)		;COMPUTE PHYSICAL ADDRESS
	TLZ	T2,777760	;CLEAR EXTRANEOUS BITS
	IORM	T2,TKBCCL(W)	;COMPLETE THE IOWD
	LDB	T2,[POINT 2,TUBAKA##(U),17]
	TRO	T2,DO.RC1	;SET UP FORMAT REGISTER
	HRLI	T2,(.DOFMT)	; ONLY NEEDS UNIT NUMBER
	PUSHJ	P,WTREGX
	MOVEI	T2,DF.XSN	;FUNCTION IS EXTENDED SENSE
	PJRST	T78SI5		;GO CRANK IT UP AND RETURN 0 TO TAPSER

;HERE ON AN INTERRUPT OF A NEW (UNKNOWN) UNIT
ATTE15:
IFN FTAUTC,<
	LDB	T2,[POINT 2,P3,27] ;SLAVE NUMBER
	PUSHJ	P,INISNS	;IS IT REAL (DRIVE AVAILABLE)?
	  JRST	CLRTMI		;IF WE GOT HERE FOR A REALLY NON-EXISTANT SLAVE,
				; WE WILL PROBABLY GET AGAIN AND AGAIN AND ...
				; SO REALLY HAVE TO DO SOMETHING DRASTIC TO CLEAR IT
	MOVSI	T2,(.DIDTR)
	PUSHJ	P,RDREGX	;READ THE DRIVE TYPE
	MOVE	T1,T2		;WHERE AUTCON WANTS IT
	LDB	T2,[POINT 2,P3,27] ;SLAVE NUMBER
	SETZ	T3,		;NO SPECIAL BITS IN TUBCNF
	PUSHJ	P,NEWTAP##	;TELL THE WORLD A NEW TAPE IS HERE
>
	JRST	RTZER		;AND CHUCK THE INTERRUPT
; HERE TO READ DRIVE STATUS AND SET WLK, BOT, AND DENSITY FOR
; ALL FUNCTIONS EXCEPT REWIND AND UNLOAD IF THE TAPE IS NOT
; ALREADY AT BOT
T78STS:	MOVSI	T2,TUSBOT##	;BIT TO TEST
	TDNN	T2,TUBSTS##(U)	;AT BOT?
	PUSHJ	P,CHKIRB##	;NO--HAVE AN IORB?
	  POPJ	P,		;NOTHING TO DO
	LDB	T2,PRBFCN##	;GET FUNCTION CODE FROM IORB
	CAIE	T2,RB.FRW	;REWIND?
	CAIN	T2,RB.FRU	;UNLOAD?
	POPJ	P,		;GO AWAY
	MOVSI	T2,(.DOSR)	;REGISTER
	PUSHJ	P,RDREG		;READ STATUS
	MOVSI	T3,TUSWTL##!TUSBOT## ;BITS TO CLEAR
	ANDCAM	T3,TUBSTS##(U)	;CLEAR WLK AND BOT
	TRNN	T2,DI.FPT	;WRITE LOCKED?
	TLZ	T3,TUSWTL##	;NO
	TRNN	T2,DI.BOT	;AT BOT?
	TLZ	T3,TUSBOT##	;NO
	IORM	T3,TUBSTS##(U)	;UPDATE
	MOVEI	T3,RB.D16	;ASSUME 1600 BPI
	TRNN	T2,DI.PE	;PHASE ENCODED?
	MOVEI	T3,RB.D62	;NO--MUST BE GCR (6250 BPI)
	DPB	T3,PRBDEN##	;UPDATE IORB (TAPSER WILL PROPAGET TO TUB)
	POPJ	P,		;RETURN
;HERE ON READ INTERRUPT
INTRD:	SKIPN	T78SNS##(U)	;IF WE HAVEN'T DONE A SENSE
	TLNE	T1,-1		; AND HAVE HAD NO ERRORS ON THE READ
	TDZA	T2,T2
	MOVE	T2,TUBREC##(U)	; IF THIS IS THE 1ST RECORD
	SKIPN	TUBFIL##(U)	; IN THE FIRST FILE
	SOJE	T2,SENSE	;DO A SENSE TO GET MODE/DENSITY RIGHT IN TUB
	MOVSI	T2,(.DOBC)	;READ BYTE COUNT
	PUSHJ	P,RDREG
	MOVEM	T2,TRBRCT(T1)	;SAVE BYTE COUNT IN IORB
	MOVEM	T2,TUBCCR##(U)	; AND IN TUB
	TLZ	T2,-1		;CLEAR POSSIBLE FLAG
	TLNN	T1,-1		;IF NO ERROR
	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
	JRST	DONE


;HERE ON WRITE INTERRUPT
INTWRT:	MOVE	T2,TKBCHR(W)	;NO OF FRAMES WE WROTE
	ADDM	T2,TUBCWR##(U)	;UPDATE STATS
	ADDM	T2,.CPTFO##
	JRST	DONE		;AND FINISH UP

;HERE ON A REREAD OPPOSITE INTERRUPT
INTRRO:	PUSHJ	P,CHKIRB##	;SET T1 TO IORB
	  JRST	INTRR1		;NONE(!)  CALL IT A HARD ERROR
	MOVSI	T2,(.DOBC)	;READ THE BYTE COUNT REGISTER
	PUSHJ	P,RDREG
	JUMPE	T2,INTRR1	;THE TM78 BLEW IT IF BYTE COUNT IS 0
	MOVN	T3,T2		;-VE BYTE COUNT
	HRLZM	T3,T78UVA##(W)	;TO TELL THE TM78 THE RIGHT BYTE COUNT
	LDB	T3,PRBMOD##	;MODE
	IDIV	T2,TMODTB##(T3)	;CONVERT BYTES TO WORDS
	JUMPN	T3,INTRR1	;LOSE IF A NON-INTEGRAL NUMBER OF WORDS
	PUSHJ	P,REVCCW##	;GOODNESS. REVERSE THE IO LIST
	MOVEM	T2,T78RRO##(W)	;SAVE ORIGINAL IOWD ADDR AND LH
	MOVE	T4,[IC.BST!RB.SED!RB.SDE!RB.SAP] ;SOME ERROR BITS TO SET
	JRST	ATTE10		;AND KEEP GOING WITH ANALYSIS (WILL EVENTUALLY RETRY)
INTRR1:	MOVE	T4,NRTERD	;CANT RETRY OPPOSITE
	JRST	ATTEN9		;READ REGISTERS AND GIVE NON-RECOVERABLE ERROR
INTRWP:	MOVSI	T2,TUSREW##	;SAY WE'RE REWINDING
	IORM	T2,TUBSTS##(U)
	HRRZ	T1,TUBQUE##(U)	;SET T1 TO IORB (OR 0)
	TLZ	P1,17		;SO WE DON'T GO TO INTREW NOW
	JRST	CPOPJ1##	;SKIP RETURN TO T78INT

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:	PUSHJ	P,REWDON##	;TELL WORLD WE'RE THROUGH REWINDING
	SETZM	TUBREC##(U)	;CLEAR STATS
	SETZM	TUBFIL##(U)
	JUMPE	T1,CLRCTY	;JUST RETURN TO TAPSER IF WE WEREN'T AT BOT ALREADY
	JRST	DONE		;AND FINISH UP

;HERE ON ANY FLAVOR OF OFF-LINE/NOT AVAILABLE TO THIS MASSBUS INTERRUPT
INTOFL:	PUSHJ	P,CHKIRB##	;DOING AN OPERATION?
	  JRST	OFLUNI		;NO, ASYNC. RETURN 0 TO TAPSER
	MOVSI	T2,RB.SOL!RB.SER!RB.SNM ;YES, TELL WORLD NOTHING HAPPENED
	IORM	T2,TRBSTS(T1)

OFLUNI:	MOVSI	T2,TKSOFL##	;LET REST OF WORLD KNOW
	IORM	T2,TUBSTS##(U)	; THAT THE DRIVE IS OFF-LINE
	POPJ	P,

;HERE ON BAD TAPE INTERRUPT
BADTAP:	LDB	T1,TUYECD	;PICK UP FAILURE CODE
	MOVE	T4,NRTERD	;LOAD BAD DATA ERROR
	CAIN	T1,14		;BAD TAPE AT OR BEYOND EOT?
	 TRO	T4,RB.SET	;YES, NOTE NEED TO SET EOT AS WELL
	PJRST	ATTE10		;AND GO HANDLE SETTING THE BITS

;HERE ON TU FAULT A INTERRUPT
TUFLTA:	MOVE	T4,NRTERV	;GET BAD DRIVE ERROR BITS
	LDB	T1,TUYECD	;GET ERROR CODE
	CAIE	T1,44		;31/44 (PREVIOUS RECORD DESTROYED)?
	JRST	ATTEN9		;NO, JUST SET BITS AS REQUESTED
	MOVSI	T1,TUSFLT##	;YES, LOAD NEW ERROR BIT
	IORM	T1,TUBSTS##(U)	;TELL WORLD THAT TU IS BAD
	PJRST	RTZER		;AND PITCH THE INTERRUPT (USER GETS HUNG DEV)

;HERE ON ON-LINE INTERRUPT
INTONL:	MOVSI	T2,TKSOFL##	;CLEAR OFF-LINE BIT
	ANDCAM	T2,TUBSTS##(U)
	PUSHJ	P,TPMONL##	;TELL MDA A DRIVE JUST CAME UP
	MOVEI	P1,DF.SNS	;NON-DATA TYPE SENSE
	SETZ	T1,		;TELL TAPSER THIS IS ASYNC
	PJRST	SENSE		;GO START A SENSE AND RETURN
SCHDON:	SETZM	TKBSCH(W)
	JRST	CLRCTL


;HERE AFTER AN OPERATION IS THROUGH
DONE:	HLLZ	T2,T1		;FLAGS WHICH GOT SET AFTER ATTEN6
	IORB	T2,TRBSTS(T1)	;PLUS FLAGS WHICH GOT SET AT ATTEN6
	HLL	T1,T2		;IN LH(T1)
	MOVSI	T2,RB.EXC
	TLZE	T1,-1		;ANY FUNNY THINGS?
	IORM	T2,TRBLNK(T1)	;YES, AN EXCEPTION HAS OCCURRED
	SETZM	T78SNS##(U)
CLRCTL:	MOVEI	T3,CO.CLR
	XCT	T78COS##(W)
	MOVEI	T3,CO.MBI
	XCT	TKBCIS##(W)	;SOMETIMES RAE WON'T CLEAR
	TRNE	T2,CI.RAE	;IS IT STILL UP?
	XCT	T78COS##(W)	;YES - ZAP IT
	SETZM	TKBFLG(W)	;NOTHING HAPPENING NOW
CLRCTY:	MOVEI	T3,TAPCHN##+CO.AIE+CO.MBE ;ENABLE FOR INTERRUPTS
	XCT	T78COS##(W)
	POPJ	P,		;AND RETURN

;HERE TO CLEAR THE TM78
CLRTMI:	MOVEI	T3,CO.CLR!CO.MBE;CLEAR THE RH20 OF ALL ERRORS, DONE
	XCT	T78COS##(W)
	CAIA

CLRTMO:	TAPON
CLRTM:	MOVE	T2,[.DOTMS!DO.TMC] ;DO AN INIT OF THE TM78
	PUSHJ	P,WTREG
	MOVEI	T4,40000	;HOW LONG TO WAIT
CLRTM1:	MOVSI	T2,(.DOTMS)	;READ TM78 STATUS
	PUSHJ	P,RDREGX
	TRNN	T2,DI.TMR	;TM READY?
	SOJG	T4,CLRTM1	;NO, TRY AGAIN
	PJRST	RTZER		;YES (OR TIMEOUT) RETURN
;HERE ON CONI ERROR BIT
CHNERR:	TRNN	P2,CI.RAE	;REGISTER ACCESS ERROR?
	JRST	NORAE		;NO
	TLO	T1,RB.SNM!RB.SED ;YES, NO TAPE MOTION+ERROR
	JRST	DONE
NORAE:	TLNN	P2,(CS.MPE!CS.NXM)
	JRST	CHNRTY		;NO, JUST RETRY
	MOVEI	T3,CHNNXM##	;SET TO CALL RIGHT ROUTINE
	MOVSI	T4,IOCHNX	;ASSUMING NXM
	TLNN	P2,(CS.NXM)	;NXM?
	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
	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
CHNRTY:	MOVEI	T4,-1		;SET T78ESD=0,,-1 AS A FLAG
	JRST	ATTE13		;AND GO CRANK UP A SENSE
	SUBTTL	INITIALIZATION
;HERE TO INITIALIZE THE TM78
T78INI:	PUSHJ	P,CLRTMI	;CLEAR THE TM78
	PUSHJ	P,SAVE2##
	SETO	P1,		;ASSUME NO TM78
	PUSHJ	P,T78ONL	;IS THE TM78 WITH US?
	  JRST	T78IN1		;NO
	MOVSI	T2,(.DODT)	;MAYBE. READ DRIVE TYPE
	PUSHJ	P,RDREG
	ANDI	T2,170377	;IS IT A TM78
	MOVEI	P1,-140101(T2)	;P1=0 IF A READY TM78
	MOVE	T2,[.DOAS!377]	;CLEAR GARBAGE FROM ATTEN SUMMARY REG
	PUSHJ	P,WTREGX
T78IN1:	MOVEI	T1,TUCIRD##	;TELL TAPUUO WE GET AN INTERRUPT
	MOVE	T2,TKBCUN##(W)	; WHEN A REWIND FINISHES
T78IN2:	SKIPE	T3,(T2)		;NEXT DRIVE
	IORM	T1,TUBSTS##(T3) ;SET BIT IN IT
	AOBJN	T2,T78IN2
	MOVE	T4,TKBIUN##(W)	;SET TO LOOP OVER ALL UNITS
T78IN3:	SKIPN	U,(T4)		;GET A UNIT
	JRST	T78IN6		;NOT THERE
	HRRZ	T2,TUBADR##(U)	;GET UDB
	HRLM	T2,TUBAKA##(U)	;WTREG WANTS UNIT HERE
	JUMPN	P1,T78IN6	;GO IF THE TM78 ISN'T RUNNING
	HLRZ	T3,TKBUNI##(W)	;SET UP RH UNIT NUMBER
	HRRZ	T2,TUBADR##(U)	;UNIT NUMBER
	PUSHJ	P,INISNS	;SENSE TO SEE IF THE DRIVE IS THERE
	  JRST	T78IN6		;NO, IT ISNT
	MOVSI	T2,(.DOSN)	;READ SERIAL NUMBER
	PUSHJ	P,RDREG		;AND STORE IN UDB
	MOVEM	T2,T78REG##+14(U) ;FOR DIAGNOSTICS
	MOVSI	T2,(.DOSR)	;READ STATUS REG
	PUSHJ	P,RDREG
	MOVSI	T3,TKSOFL##
	TRNN	T2,DI.RDY	;IF NOT READY
	IORM	T3,TUBSTS##(U)	; THE DRIVE IS OFF-LINE
	MOVSI	T3,TUSWTL##
	ANDCAM	T3,TUBSTS##(U)	;ASSUME TAPE IS NOT WRITE-LOCKED
	TRNE	T2,DI.FPT
	IORM	T3,TUBSTS##(U)	;WRONG - IT IS WRITE LOCKED
	MOVE	T2,[.DOAS!377]	;CLEAR THE ATTEN BIT WE JUST LIT
	PUSHJ	P,WTREG
T78IN6:	AOBJN	T4,T78IN3
T78IN7:	PUSHJ	P,T78ONL	;IF NOT THERE
	  JRST	T78I13		; DON'T SET UP CONSO MASK
	MOVE	U,TKBIUN##(W)	;POINT U AT 1ST UDB ON CONTROLLER
	MOVE	U,(U)
	SKIPE	T78REG##(U)	;ALREADY READ ROM REV LEVELS?
	JRST	T78I12		;YES, SKIP THIS
	PUSHJ	P,SETHLD	;SET HOLD IN TM SO WE CAN READ REV LEVELS
	  JRST	T78I12		;LOSE IF IT DIDNT SET
	MOVEI	P1,T78REG##(U)	;POINT AT ..U?0 UDB
	HRLI	P1,441100	;MAKE A BYTE POINTER
	MOVE	P2,[.DOIA!3776]	;POINT AT LOC FOR 1ST ROM REV LEVEL
T78IN9:	MOVE	T2,P2
	PUSHJ	P,WTREG		;LOC WE WANT TO READ
	MOVSI	T2,(.DOTMS)
	PUSHJ	P,RDREG		;READ THE LOCATION
	ANDI	T2,377		;ONLY 8 BITS ARE OF INTEREST
	IDPB	T2,P1		;SAVE IN ..U?0 UDB
	ADDI	P2,4000		;STEP TO NEXT REV LEVEL LOC
	TRNN	P2,40000
	JRST	T78IN9		;GO READ IT
	DMOVE	T3,[POINT 9,T78REG##(U)	;POINT TO WHAT WE GOT
		    POINT 9,T78REV]	;AND WHAT WE EXPECT FOR EACH ROM
	MOVSI	P1,-^D8		;NUMBER OF ROMS TO CHECK
T78I9A:	ILDB	T1,T3		;GET NEXT ROM WE GOT
	ILDB	T2,T4		;AND WHAT WE EXPECT
	CAML	T1,T2		;SEE IF AT LEAST WHAT WE EXPECT
	 AOBJN	P1,T78I9A	;OK, CONTINUE
	SKIPGE	P1		;SKIP IF ALL OK
	 PUSHJ	P,T78I14	;NO, COMPLAIN ABOUT BEING DOWN REV
	PUSHJ	P,CLRHLD	;CLEAR HOLD
	SKIPA	T1,TKBIUN##(W)
T78I10:	SKIPN	T2,(T1)		;POINT AT NEXT UDB
	JRST	T78I11
	DMOVE	T3,T78REG##(U)	;MOVE REV LEVELS FROM 0'S UDB
	DMOVEM	T3,T78REG##(T2)	; TO THIS UDB
T78I11:	AOBJN	T1,T78I10	;DO ALL UDBS
T78I12:	MOVEI	T3,CO.MBE!CO.RAE ;CLEAR POSSIBLE REG ACCESS ERROR
	XCT	T78COS##(W)	; (ON IF NON-EX DRIVE)
	PUSHJ	P,SETIVI	;SET UP INTERRUPT VECTOR
	JRST	CLRCTL		;CLEAR RH20 AND RETURN

;HERE IF THE CONTROL DIDN'T RAISE ATTENTION
T78I13:	MOVSI	T1,TKSOFL##	;MARK THE CONTROL AS OFF LINE
	IORM	T1,TKBSTS##(W)
	POPJ	P,

;TWO WORDS FOR PATCHING IN NEW TM78 ROM REV LEVELS
T78REV:	BYTE (9) 6,5,6,4
	BYTE (9) 2,3,8,3

;HERE IF THE CONTROLLER ROM IS BELOW REQUIRED REV LEVELS
T78I14:	HRROI	T2,[ASCIZ /Ask field service to install the new TM78 microcode ROMs/]
	PJRST	TAPREV##	;LET TAPSER TYPE A MESSAGE

;HERE ON KONTROLLER ONLINE. SKIP THE CODE TO RESET THE DDB NAMES.
T78INR:	PUSHJ	P,CLRTMI
	JRST	T78IN7		;JOIN COMMON CODE
;SUBROUTINE TO SET HOLD IN THE TM78
;RETURNS CPOPJ IF HOLD DIDN'T SET, CPOPJ1 NORMALLY
SETHLD:	PUSHJ	P,SAVE1##
	MOVE	T2,[.DOIA!3776]	;POINT INTERNAL ADDR AT A READ-ONLY LOCATION
	PUSHJ	P,WTREG		;IN CASE TM78 DECIDES TO WRITE WHEN HOLD SETS
	MOVE	T2,[.DOTMS!DO.HLD]
	PUSHJ	P,WTREG		;SET HOLD
	MOVEI	P1,40000	;HOW LONG TO WAIT
SETHL1:	MOVSI	T2,(.DOTMS)	;READ STATUS
	PUSHJ	P,RDREG
	TRNN	T2,DO.HLA	;HOLD ACKNOWLEDGED?
	SOJG	P1,SETHL1	;NO, WAIT SOME MORE
	JUMPN	P1,CPOPJ1##	;SKIP-RETURN IF HOLD ACKNOWLEDGED
	POPJ	P,		;COULDN'T SET HOLD - NON SKIP RETURN

;SUBROUTINE TO CLEAR HOLD
CLRHLD:	MOVSI	T2,(.DOTMS)
	PUSHJ	P,WTREG		;CLEAR HOLD
	MOVE	T2,[.DOTMS!DO.TMC]
	PUSHJ	P,WTREG		;CLEAR POSSIBLE ERROR
	POPJ	P,		;AND RETURN
;ROUTINE TO DO A SENSE TO SEE IF A SLAVE IS PRESENT
;ENTER T3=RH UNIT NUMBER,  T2= DRIVE NUMBER
;RETURNS CPOPJ IF NOT THERE, CPOPJ1 IF IT IS
INISNS:	ADDI	T2,<(.DOND0)>_-14 ;SET RIGHT DRIVE
	ROT	T2,-6
	HRRI	T2,DF.SNS	;DO A SENSE ON THAT DRIVE
	PUSHJ	P,WTREGX
	MOVEI	T1,40000	;HOW LONG TO WAIT
INISN1:	MOVSI	T2,(.DOAS)
	PUSHJ	P,RDREGX	;READ ATTEN SUMMARY
	TRNN	T2,377		;SENSE OP COMPLETE?
	SOJG	T1,INISN1	;NO, WAIT SOME MORE
	JUMPE	T1,CPOPJ##	;GO IF WE TIMED OUT
	MOVSI	T2,(.DOSR)	;READ STATUS REGISTER
	PUSHJ	P,RDREGX
	TRNE	T2,DI.AVL+DI.MNT ;IS IT THERE?
	AOS	(P)		;YES
	POPJ	P,		;RETURN

IFN FTAUTC,<
;ROUTINE TO DETERMINE WHAT SLAVES ARE PRESENT
;ENTER P3= LAST SLAVE WE'VE SEEN,  LH(P2) = RH UNIT NUMBER
;RETURN P3=NEXT SLAVE, 0 IF NO MORE
T78CFG:	HLRZ	T3,P2		;SET UP RH20 UNIT NUMBER
	JUMPGE	P3,T78CF1	;GO IF NOT THE 1ST TIME
	PUSHJ	P,CLRTM		;RESET THE TM78
	PUSHJ	P,T78ONL	;IS THE TM WITH US?
	  POPJ	P,		;NO
T78CF1:	AOS	T2,P3		;NEXT UNIT
	TRZE	P3,4		;OVER THE TOP?
	SOJA	P3,T78CF2	;YES, RETURN P3=-1
	PUSHJ	P,INISNS	;SEE IF THE NEXT SLAVE IS THERE
	  TDZA	T1,T1		;NOT THERE
	SETO	T1,		;YUP, IT'S THERE
	MOVE	T2,[.DOAS!377]	;CLEAR THE ATTENTION
	PUSHJ	P,WTREGX
	JUMPE	T1,T78CF1	;NOT THERE, TRY NEXT SLAVE
	SETZ	T3,		;INDICATE NO TUBCNF CHANGES
	POPJ	P,		;RETURN P3 = SLAVE NUMBER

T78CF2:	MOVEI	T2,CO.MBI	;DO A MASSBUS INIT
	XCT	T78COS##(W)	; DO GET RID OF ANYTHING THAT GOT GRONKED
	MOVEI	T3,CO.MBE	;DO A MASSBUS ENABLE TO LET
	XCT	T78COS##(W)	; AUTCON TALK TO THE RH AGAIN
	POPJ	P,		;AND RETURN SAYING NO MORE SLAVES ON THIS UNIT
>
;HERE TO CHECK IF ON-LINE
T78ONL:	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 ALREADY
	MOVSI	T2,(<DO.DRE>!.DOTMS)
	TAPOFF			;PREVENT INTERRUPT CODE FROM CHANGING PREPERATION REGISTER
	PUSHJ	P,RDREG		;IS THE TM78 ALIVE?
	TRNE	T2,DO.HLA	;DID WE STOP IT?
	JRST	T78ON2		;YES, OFF-LINE
	TRNE	T2,DI.TMR
	JRST	T78ON1		;YES
	XCT	TKBCIS##(W)	;NO, IS THE UNIT THERE AT ALL?
	TRNN	T2,CI.RAE
	PJRST	CLRTMO		;YES, TRY TO GET IT GOING AGAIN
	MOVEI	T3,CO.RAE+CO.MBE+CO.AIE+TAPCHN## ;NO, CLEAR THE RAE
	XCT	T78COS##(W)	; (NON-EX UNIT)
	CAIA
T78ON1:	AOS	(P)
T78ON2:	TAPON
	POPJ	P,		;AND TAKE THE NON-SKIP RETURN

;HERE TO CAUSE A SCHEDULE CYCLE
T78SCH:	SETOM	TKBSCH(W)	;SET FLAG

;HERE TO RESET AN ACTIVE DRIVE (HUNG)
T78RES:	SKIPE	T2,TKBSCW(W)	;LOSE DURING AN EXTENDED SENSE?
	MOVEM	T2,@TKBICP##(W)	;YES, RESET ICWA TO WHAT IT SHOULD BE
	SETZM	TKBSCW(W)
	SETZM	T78RRO##(W)	;NO LONGER IN READ-OPPOSITE
	MOVEI	T3,CO.MBE	;MAKE SURE THE
	XCT	T78COS##(W)	; RH IS LISTENING
	PUSHJ	P,SETIVI	;SET UP INTERRUPT VECTOR
	MOVEI	T3,CO.STP!CO.MBE ;CLEAR BUSY, SET DONE
	XCT	T78COS##(W)	;DO IT
	SKIPE	TKBSCH(W)
	JRST	CLRCTY
	JRST	CLRCTL		;CLEAR RH20 AND RETURN
;HERE ON AN INTERRUPT WHICH REQUIRES RESETING THE TM78
CLRINT:	PUSHJ	P,CLRTM		;RESET THE CONTROLLER
	JUMPE	U,CLRIN1
	MOVSI	T1,(1B1)	;MARK AS A HARD ERROR FOR DAEMON
	IORM	T1,TUBTRY##(U)
	MOVSI	T1,T78REG##(U)	;COPY FROM "AT END"
	HRRI	T1,T78ICS##(U)	; TO "AT ERROR"
	BLT	T1,T78ISE##(U)	; FOR SYSERR
	SKIPN	F,TUBCUR##(U)	;IF DDB USE IT
CLRIN1:	MOVEI	F,MT0DDB##	;NO - USE MT0DDB
	MOVEI	T1,.ERTAP	;ERROR TYPE TO DAEMON
	HRL	T1,F		;DDB
	PUSHJ	P,DAEERR##	;TELL DAEMON
	SKIPN	P1,TKBFLG(W)	;WAS ANYTHING HAPPENING?
	JRST	CLRIN2		;NO, RETURN A ZERO
	HRRZ	T1,TUBQUE##(U)	;POINT T1 AT IORB
	JUMPE	T1,CLRIN2	;NONE????
	JUMPL	P1,T78SI1	;RETRY THE COMMAND IF IT WAS A DATA OPERATION
	MOVE	T4,NRTERV	;POSITIONING OP - CALL IT A HARD DEVICE ERROR
	JRST	ATTEN9		;FINISH UP PROCESSING

;HERE IF NOTHING WAS HAPPENING
CLRIN2:	AOS	T1,T78ACT##(W)	;BUMP ASYNC INTERRUPT COUNT
	CAIG	T1,T78AMX##	;GONE OVER THE THRESHOLD?
	JRST	RTZER		;NO, RETURN A ZERO
	PUSHJ	P,SETHLD	;YES. SET HOLD IN THE TM (STOP THE MICROCODE)
	  JFCL			; TO STOP THESE INTERRUPTS FROM CLOGGING THE SYSTEM
	SETOM	T78ACT##(W)	;INDICATE HOLD IS SET
	JRST	RTZER		;AND KEEP ON GOING (RETURN 0 TO TAPSER)
;READ A REGISTER - ENTER, EXIT WITH FNCN IN T2
;RESPECTS T1,T4
RDREG:	HLRZ	T3,TKBUNI##(W)	;TM78 UNIT NUMBER
RDREGX:	TLO	T2,<(DO.DRE)>(T3)
	XCT	TKBDOS##(W)	;SAY WHAT WE WANT TO READ
	XCT	TKBDIS##(W)	;READ IT
	ANDI	T2,177777	;ONLY 16 BITS
	POPJ	P,		;AND RETURN

;ROUTINE TO WRITE A REGISTER
;ENTER T2=WHAT TO DO THE DATAO WITH
;RESPECTS T1, T4
WTREG:	HLRZ	T3,TKBUNI##(W)	;TM78 UNIT NUMBER
WTREGX:	TLO	T2,<(DO.LDR!DO.DRE)>(T3)	;LIGHT LR AND UNIT
	XCT	TKBDOS##(W)	;DATAO
	POPJ	P,		;AND RETURN

;ROUTINE TO READ REGISTERS ON ERROR
RDREGS:	MOVEM	P2,T78REG##+2(U) ;SAVE CONI
	MOVSI	T2,(.DOPTC)
	PUSHJ	P,RDREG
	MOVEM	T2,T78REG##+3(U)	;DATAI PRIMARY TRANSFER CONTROL REG
	MOVSI	T2,(.DOPBA)
	PUSHJ	P,RDREGX
	MOVEM	T2,T78REG##+4(U)	;DATAI PRIMARY BLOCK ADDR REG
	PUSH	P,T1
	MOVEI	T1,T78REG##+6(U)	;(REG+5 = LAST COMMAND)
	HRLI	T1,-22		;READ ALL REGISTERS
	SETZ	T2,		; STARTING AT 0
RDREG1:	PUSH	P,T2
	PUSHJ	P,RDREGX
	MOVEM	T2,(T1)		;STORE DATA IN UDB
	POP	P,T2
	ADD	T2,[010000,,0]	;SET FOR NEXT REGISTER
	AOBJN	T1,RDREG1
	JRST	TPOPJ##

;ROUTINE TO SET UP INTERRUPT VECTOR, JSR
SETIVI:	MOVEI	T2,TKBVIN##(W)	;SET UP JSR IN ICWA+3
	HRLI	T2,(XPCW)

	MOVE	T3,TKBICP##(W)
	MOVEM	T2,3(T3)	;FOR VECTORED INTERRUPTS
	MOVE	T2,TKBIVI##(W)	;RESET INTERRUPT VECTOR ADDRESS
	XCT	TKBDOS##(W)
	POPJ	P,		;AND RETURN
;HERE AFTER SENSE COMPLETES WHICH WAS DONE TO READ REGS 7-10
RDREG2:	MOVSI	T1,T78REG##+6+22(U) ;ZERO THE EXTENDED SENSE AREA
	HRRI	T1,T78REG##+6+23(U) ; IN CASE WE DONT DO AN EXTENDED SENSE
	SETZM	-1(T1)		    ; OR WE DO ONE AND IT FAILS
	BLT	T1,T78REG##+6+22+16(U)
	MOVEI	T1,T78REG##+6+7(U)
	HRLI	T1,-3		;WHAT TO READ
	MOVSI	T2,070000
	PUSH	P,T1		;RDREG1 EXITS TPOPJ
	PJRST	RDREG1

;HERE TO READ REGS ON SUCCESSFUL READ
RDREG3:	PUSH	P,T2
	PUSHJ	P,RDREGS	;READ (MOST) REGISTERS
	MOVSI	T2,T78ICS##+6+7(U) ;COPY REGS 7-10 FROM WHERE WE READ THEM
	HRRI	T2,T78REG##+6+7(U) ; TO THE FEP AREA (ELSE WE HAVE TO SENSE AGAIN)
	BLT	T2,T78REG##+6+11(U) ; AND THESE REGISTERS DON'T CHANGE
	JRST	T2POPJ##
;TABLES TO CONTROL IO
TB.DAT==1B0
TB.WRT==1B1
TB.REV==1B2
TB.SPC==1B3
TB.RD==1B4
TB.ERA==1B5
TB.WTM==1B6
TB.REW==1B7
TB.RRG==1B8	;NOT IN TABLE, LIGHTS ON SENSE FROM RDREG
TB.XSN==1B9	;NOT IN TABLE, LIGHTS AFTER SENSE IF WE DO EXTENDED SENSE

FNCTBL:	0				;0 - ILLEGAL
	TB.DAT!TB.RD!DF.RED!1B17	;1 - READ FORWARD
	TB.WRT!TB.DAT!DF.WRT!2B17	;2 - WRITE
	TB.DAT!TB.RD!TB.REV!DF.RRV!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!DF.ERG!10B17	;10 - ERASE
	TB.WRT!DF.DSE!11B17		;11 - DATA SECURITY ERASE
	TB.REW!TB.REV!DF.REW!12B17	;12 - REWIND
	DF.UNL!13B17			;13 - REW, UNLOAD
	TB.WRT!TB.WTM!DF.WTM!14B17	;14 - WRITE TAPE MARK
FNCNOP:	TB.SPC!DF.NOP!15B17		;15 - YELLOW BALL
	TB.DAT!TB.RD!DF.RED!16B17	;16 - CORRECTION READ
	TB.DAT!TB.RD!DF.RED!17B17	;17 - LOW THRESHOLD READ

	WT.GCR==2			;TURN WRITE PE INTO WRITE GCR

;FRAMES/WORD,,MODE BITS
MODTBL:	-1			;0 - ILLEGAL
	5,,30000		;1 - CORE DUMP
	4,,20000		;2 - INDUSTRY COMPAT
	-1			;3 - SIXBIT
	-1			;4 - 7 BIT (ASCII)
	-1			;5 - 7-TRACK CORE DUMP

;MISC BIT DEFINITIONS

;RH20 COMPOSITE BITS
	CI.ERR==CI.DBP!CI.LWC!CI.DRE!CI.RAE!CI.OVR ;CONI ERROR BITS
	CO.CLR==CO.RAE!CO.TEC!CO.CCD ;CONO BITS TO CLEAR ERRORS
	CS.ERR==CS.MPE!CS.NAE!CS.NXM!CS.RHE!CS.OVR ;LOGOUT-AREA ERROR BITS
IC.RRG==1B0			;READ REGISTERS
IC.BST==1B1			;SET A BIT IN TKBSTS
IC.DSP==1B2			;DISPATCH TO AN ADDRESS
IC.ASY==1B3			;ASYNCH EVENT (RETURN 0 TO TAPSER)
IC.XSN==1B4			;DO AN EXTENDED SENSE TO GET MORE INFO


ICDTBL:	IC.BST!RB.SER!RB.SED	;0 - UNDEFINED
	0			;1 - DONE
	IC.BST!RB.STM		;2 - UNEXPECTED TAPE MARK
	IC.BST!RB.SBT!RB.SNM	;3 - UNEXPECTED BOT
	IC.BST!RB.SET		;4 - END OF TAPE
	IC.BST!RB.STM		;5 - UNEXPECTED LOGICAL EOT
	IC.BST!RB.SER!RB.SIL	;6 - NO OP COMPLETED
	IC.ASY!IC.DSP!INTRWP	;7 - REWIND IN PROGRESS
	IC.BST!RB.SLK!RB.SER!RB.SNM ;10 - WRITE TO A WRITE-LOCKED TAPE
	IC.DSP!INTOFL!IC.RRG	;11 - NOT READY
	IC.DSP!INTOFL!IC.RRG	;12 - DRIVE NOT AVAILABLE (ON OTHER PORT)
	IC.DSP!INTOFL!IC.RRG	;13 - OFF LINE
	IC.DSP!INTOFL!IC.RRG	;14 - NON-EXISTENT DRIVE
	IC.BST!RB.SER!RB.SED!IC.RRG ;15 - NOT CAPABLE
	IC.BST!RB.SER!RB.SED!IC.RRG ;16 - UNDEFINED
	IC.ASY!IC.DSP!INTONL	;17 - DRIVE HAS COME ON LINE
	IC.BST!RB.STL!RB.SER!IC.RRG ;20 - LONG RECORD
	0			;21 - SHORT RECORD
	IC.BST!IC.RRG!IC.XSN!RB.SDE!RB.SED!RB.SAP ;22 - RETRY THE INITIAL OPERATION
	IC.DSP!INTRRO			   ;23 - REREAD IN OPPOSITE DIRECTION
NRTERD:	IC.BST!RB.SER!RB.SED!RB.SDE!IC.RRG!IC.XSN ;24 - UNREADABLE
NRTERV:	IC.BST!RB.SER!RB.SED!IC.RRG!IC.XSN ;25 - ERROR, SER IS SET
	IC.BST!RB.SET!RB.SER!RB.SED!IC.RRG!IC.XSN ;26 - ERROR AFTER EOT, SER IS SET
	IC.DSP!IC.BST!BADTAP!IC.RRG!IC.XSN	;27 - BAD TAPE
	IC.BST!RB.SED!RB.SNM!IC.RRG!IC.XSN	;30 - TM FAULT A
	IC.DSP!IC.ASY!TUFLTA!IC.RRG!IC.XSN	;31 - TU FAULT A
	IC.ASY!IC.DSP!CLRINT 		;32 - TM FAULT B
ICDND1==.-ICDTBL-1
	IC.ASY!IC.DSP!CLRINT!IC.RRG!IC.XSN ;33 - TU FAULT B
	IC.ASY!IC.DSP!CLRINT		 ;34 - MASSBUS FAULT
ICDND2==.-ICDTBL-1
MAXICD==.-ICDTBL-1
REVERR==23

INTABL:	DONE
	INTRD			;(1)READ FORWARD
	INTWRT			;(2)WRITE
	INTRD			;(3)READ BACKWARDS
	DONE			;(4)SKIP RECORD
	DONE			;(5)BACKSPACE RECORD
	TAPIFI##		;(6)SKIP FILE
	TAPIFI##		;(7)BACKSPACE FILE
	DONE			;(10)ERASE GAP
	DONE			;(11)DATA SECURITY ERASE
	INTREW			;(12)REWIND
	INTUNL			;(13)UNLOAD
	DONE			;(14)WRITE TAPE MARK
	DONE			;(15)YELLOW BALL/ILLEGAL FUNCTIONS
	INTRD			;(16)CORRECTION READ
	INTRD			;(17)LOW-THRESHOLD READ
T78END:	END