Google
 

Trailing-Edge - PDP-10 Archives - tops10_704_monitoranf_bb-x140c-sb - 10,7/anf10/dncdup.p11
There are 3 other files named dncdup.p11 in the archive. Click here to see a list.
.SBTTL	DNCDUP - DUP11 ROUTINES  27 MAY 82

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

VRCDDP=012			;FILE EDIT NUMBER

.SBTTL	DUP11 ROUTINES
.IF NE FTDUP11	;IF DUP SYNCHRONOUS LINES ARE PRESENT
;NOTES ON THE TRANSMIT AND RECEIVE INTERRUPT SERVICE ROUTINES

;DATA INTERRUPTS REALLY CONSIST OF 2 PHASES, SUPPLYING THE NEXT
;CHARACTER AND SETTING UP THE NEXT BUFFER. SINCE THE LATTER MAY TAKE
;SO MUCH TIME THAT DATA INTERRUPTS ARE LOCKED OUT, BOTH THESE ISR'S
;EMPLOY A TECHNIQUE TO GET AROUND THESE PROBLEMS. ONLY THE TRANSMITTER
;IS DESCRIBED HERE AS THE RECEIVER IS ESSETIALLY IDENTICAL.

;THE FIRST THING THE TRANSMIT INTERRUPT ROUTINE DOES IS TO SUPPLY
;THE HARDWARE WITH THE NEXT CHARACTER TO OUTPUT. IF THERE ARE MORE
;CHARACTERS WAITING IN THE STRING THE INTERRUPT IS DISMISSED.
;HOWEVER, IF THE STRING IS EXHAUSTED, THE DDCMP TRANSMIT COROUTINE
;MUST BE CALLED VIA @LB.XDN(J) TO GET THE NEXT STRING. SINCE THIS
;MAY TAKE A LONG TIME , THE PRIORITY
;LEVEL IN THE PS IS DECREMENTED TO ALLOW DATA INTERRUPTS FROM THE
;RECEIVER OR OTHER LINES TO BE PROCESSED. ONCE THE COROUTINE IS DONE,
;WE INCREMENT THE PS, STORE THE POINTER TO THE NEXT STRING, AND
;FINALLY DISMISS THE INTERRUPT.

;THERE ARE A COUPLE OF RACE CONDITIONS TO KEEP IN MIND. FIRST, IF A
;DATA INTERRUPT FOR A DIFFERENT LINE OCCURS WHILE IN THE COROUTINE
;AND IT DECIDES IT HAS TO CALL ITS COROUTINE, IT WILL DO SO, GET AN
;ANSWER AND EXIT BEFORE THE FIRST INTERRUPT FINISHES BEING PROCESSED!
;THEREFORE, WHILE THIS SCHEME SHORTENS RESPONSE TIME TO DATA INTERRUPTS,
;IT MAY DOUBLE (OR TRIPLE...) RESPONSE TO REQUESTS FOR A NEW STRING.
;IT DOESN'T HAPPEN OFTEN, BUT IT DOES HAPPEN.

;SECOND, THERE ARE TIMES WHEN RESPONSE IS SO SLOW THAT A DATA INTERRUPT
;WILL OCCUR FOR A LINE ALREADY IN ITS COROUTINE. IF ITS PRESENT
;STRING STILL HAS DATA, THE LINE WILL GET ITS CHARACTER AND EVERYTHING
;KEEPS PLODDING ALONG. HOWEVER, IT CAN OCCUR THAT THE CURRENT
;STRING IS EXHAUSTED. IN THIS CASE LB.SXR+6 WILL BE 0, A FLAG
;THAT SAYS WE ARE STILL INSIDE THE COROUTINE. IN THIS CASE (AND IT
;DOES HAPPEN!) ABOUT THE ONLY THING WE CAN DO IS CALL THE ERROR ROUTINE TO
;STOP THE TRANSMITTER AND LET THE DDCMP LOOP LEVEL CODE FIGURE
;OUT WHAT HAPPENED AND RESTART THE TRANSMITTER.
;HERE ONCE PER "REPSPD" JIFFYS.  BECAUSE OF A BUG IN THE
;  DUP-11, WE NEED TO KISS IT'S CSR'S ONCE IN A WHILE BEFORE
;  IT WILL DEIGN TO GIVE US A RECEIVE INTERRUPT.

DUPJIF:	CMPB	LB.DVS(J),#LS..UP	;IF THIS ISN'T A DUP
	BNE	99$			; THEN IT'S A GOOD GUY
	SAVE	R0			;CLOBBER NO REGISTERS
	MOV	@LB.SLA(J),R0		;KISS IT.
	BIC	#^CUP.REN!UP.RIE!UP.RDN,R0 	;CLEAR ALL BUT THESE 3 BITS
	CMP	#UP.REN!UP.RIE!UP.RDN,R0	;IF ALL 3 ARE SET
	BNE	10$			;THEN THE HARDWARE MISSED THE INTERRUPT
	INC	#0			;COUNT THE FACT
10$:	RESTORE	R0			;RESTORE R0
99$:	RTS	PC			; AND RETURN
;HERE TO INITIALIZE A DUP11 LINE
;ASSUMES REGISTER DQ HAS HARDWARE ADDRESS OF DUP11 DEVICE
DUPDINI:
	MOV	#UP.INI,UP.XSR(DQ)	;MASTER INITIALIZE BIT
10$:	BIT	#UP.INI,UP.XSR(DQ)	;1-2 MICRO SEC ONE SHOT
	BNE	10$			;WAIT TIL IT CLEARS
	MOV	#UP.DMD+SYN,UP.PAR(DQ)	;SET DEC MODE IE. BYTE MODE DDCMP
					;ALSO BIT9 = 0 ENABLES CRC CALCULATION
	MOV	#UP.DTR+UP.RTS,UP.RSR(DQ)	;SET DTR ON AND REST OF BITS OFF
	MOV	#UPBIDL,LB.STX(J)	;SET NULL DISPATCH JUST IN CASE THE
					; DUP-11 INTERRUPTS WITH OUT BEING
					; ENABLED (EASIER TO FIND)
	RTS	PC
;HERE TO ENABLE DUP11 RECEIVER

DUPRBEG:BIS	#LS..RG,@J		;FLAG RECEIVER HAS BEEN ENABLED
	MOV	LB.SLA(J),DQ		;GET DUP11 HDW ADR
	MOV	LB.IPT(J),R0		;GET RELATIVE INPUT BUFFER ADDR
	ADD	J,R0			;MAKE INPUT BUFFER ADR ABS
	TRACE	DUP
	MOV	R0,LB.SRR(J)		;SAVE RECEIVE ADR
	MOV	#-4,LB.SRR+2(J)		;SAVE RECEIVE COUNT
	ADD	#4,R0
	MOV	R0,LB.SRR+4(J)		;SAVE 2NDDARY BUF ADR
	MOV	#-4,LB.SRR+6(J)		;AND COUNT
	MOV	#DDRJNK,LB.RDN(J)	;WHERE TO GO WHEN HAVE RECEIVED MSG
	BIS	#UP.SSY!UP.RIE!UP.REN,@DQ ;STRIP SYN,ENABLE RECV AND RECV INTER
	RTS	PC


DUPXBEG:				;HERE TO ENABLE THE TRANSMITTER
	BIS	#LS..XG,@J		;TELL THE SOFTWARE THE LINE'S UP.
	MOV	LB.SLA(J),DQ		;GET THE HARDWARE BASE ADDRESS
	MOV	#UPBSYN,LB.STX(J)	;SET THE STATE TO 'SYNCH'
	MOV	SYNCHS,LB.SXR(J)	;PUT IMMEDIATE DATA IN SXR
	MOV	#1-FTNSYN,LB.SXR+2(J)	;PUT THE LENGTH OF THE STRING HERE
	CLR	LB.SXR+6(J)		;SIGNAL THAT WE HAVE NO OTHER BUFFER'S
	BIS	#UP.SND!UP.XIE,UP.XSR(DQ) ;ENABLE EVERYTHING.
	MOVB	LB.SXR(J),R0		;NOW GET THE FIRST CHAR TO GO.
	BIC	#^C377,R0		; (MOVB SIGN EXTENDS ...)
	BIS	#UP.XSM,R0		;SET 'START OF MESSAGE' IN IT
	MOV	R0,UP.XBF(DQ)		;AND START THE XMITTER ROLLING.
	JSR	PC,@LB.XDN(J)		;CALL THE SERVICE ROUTINE FOR A BUFFER
	MOV	R0,LB.SXR+4(J)		;STORE THE NEW BYTE POINTER
	MOV	R1,LB.SXR+6(J)		;STORE THE NEW BYTE COUNT
	RTS	PC			;AND RETURN
.IF NE 0

		DDCMP  <=>  DUP-11 RECEIVER PROTOCOL

	THE DUP-11 SIMULATES A DOUBLE BUFFERED RECEIVER BY ATTEMPTING
	TO KEEP TWO BUFFERS FOR ITS USE AT ALL TIMES.  WHEN EVER THE
	INTERRUPT ROUTINE COMPLETES THE FILLING OF A BUFFER, IT CALLS
	A SERVICE ROUTINE IN DDCMP VIA THE LINE BLOCK ENTRY LB.RDN.
	THE DDCMP ROUTINE SHOULD FIGURE OUT WHAT TO DO WITH THE
	DATA, AND WHEN IT RETURNS, R0 SHOULD POINT TO A NEW BUFFER,
	AND R1 BE THE NEGATIVE OF ITS LENGTH.  

				*** NOTE ***

	THERE IS ONE MAJOR DIFFERENCE BETWEEN THE DUP-11 INTERFACE
	TO DDCMP AND MOST OTHERS.
	   A)	THE DUP-11 SETS THE FLAG UP$RCC IN LB.STY(J)
		WHEN EVER IT CALLS THE SERVICE ROUTINE.  THIS BIT
		IF TRUE, INDICATES THAT THE BCC HAS BEEN RECEIVED
		CORRECTLY.

.ENDC ;COMMENT


.MACRO	X	Q
UPVA'Q:	SAVE	<J>
	MOV	#FLBDUP+<LB.SIZ*'Q>,J
.ENDM	X
	Z=DUPN-1
.REPT	DUPN
	X	\Z
.IIF NE Z,	BR	DUPAINT
Z=Z-1
.ENDR
DUPAINT:			;ENTRY FOR RECEIVE INTERRUPT
	SAVE	<DQ,R0>		;DQ WILL BE HARDWARE ADDRESS. R0 A TEMP
	MOV	LB.SLA(J),DQ	;GET THE DUP-11 BASE ADDRESS
	MOV	UP.RBF(DQ),R0	;GET THE STATUS WORD WITH BCC AND OVERRUN
	BIT	#UP.OVR,R0	;WAS THERE OVERRUN?
	BNE	UPAERR		; IF SO, SHUT DOWN THE LINE

;	BIC	#UP.SSY,@DQ	;STOP STRIPPING SYNC'S NOW THAT DATA IS COMMING
	MOVB	R0,@LB.SRR(J)	;STORE THE CHAR WE JUST READ
	INC	LB.SRR(J)	;ADVANCE THE BYTE POINTER
	INC	LB.SRR+2(J)	;INCREMEMT THE BYTE COUNT
	BLT	UPA.30		; AND IF IT DIDN'T OVERFLOW, DISMISS THE INT.
	BGT	UPAERR		;IF WE GOT AN EXTRA CHAR WHILE WE
				; HAD THE PI-LEVEL DOWN, IT'S OVERRUN
	DEC	LB.SRR(J)	;BACK-UP THE POINTER INCASE WE GET
				; A CHAR WHEN WE CALL DDCMP

;HERE IF WE MUST CALL THE SERVICE ROUTINE.  FIRST SET UP UP$RCC.

	BIC	#UP$RCC,LB.STY(J) ;ASSUME A BAD BCC
	BIT	#UP.RCR,R0	;AND IF IT REALLY IS BAC
	BEQ	UPA.10		; THEN DON'T CHANGE OUR MIND
	BIS	#UP$RCC,LB.STY(J) ;OTHERWISE FLAG THE BCC AS GOOD
UPA.10:				;NOW TO ADVANCE THE BUFFERS
	MOV	LB.SRR+4(J),LB.SRR(J) ;COPY THE BYTE POINTER
	MOV	LB.SRR+6(J),LB.SRR+2(J)	;COPY THE BYTE COUNT
	BEQ	UPAOFF		;BRANCH IF WE OUTRAN THE BUFFERS (RESTART RECV)
	CLR	LB.SRR+6(J)	;LEAVE NOTICE THAT LOW-LEVEL IS RUNNING
	BIT	#LS.SSY,@J	;DOES DDCMP WAN'T SYNC'S STRIPED?
	BEQ	UPA.20		; IF NOT, JUST SKIP THIS
	BIC	#LS.SSY,@J	;OTHERWISE, CLEAR THE REQUEST,
	BIC	#UP.REN!UP.RIE,@DQ ;SHUT IT DOWN
	BIS	#UP.REN!UP.RIE!UP.SSY,@DQ ; AND START IT BACK UP AGAIN
				;(ALL THIS BECAUSE SETTING 'STRIP'
				; WON'T CAUSE STRIPPING TO START
				; UNLESS RXACT IS OFF!!! IDIOTS.)
UPA.20:				;NOW CALL THE SERVICE ROUTINE
;	MOV	10(SP),PS	;*****  B E W A R E  *****
;				; GET THE OLD LEVEL (CHANGE THE '10' IF ANY
;				; MORE OR LESS PUSHES ARE DONE)
	SUB	#40,PS		;DROP THE LEVEL BACK TO 5 (LOCK OUT DZ'S)
	SAVE	<R1,R2,R4>	;DON'T TRUST DDCMP TO PRESERVE ANYTHING
	JSR	PC,@LB.RDN(J)	;CALL THE SERVICE ROUTINE AND GET NEXT BUFFER
;	BIS	#340,PS		;AND TURN THE PI SYSTEM BACK OFF

	MOV	R0,LB.SRR+4(J)	;SAVE THE NEW BYTE POINTER
	MOV	R1,LB.SRR+6(J)	;SAVE THE NEW COUNT
	RESTORE	<R4,R2,R1>	;GET THE REGISTERS BACK
	TST	LB.SRR+6(J)	;WAS COUNT 0 (I.E. WE SHOULD STOP)?
	BEQ	UPARST		;YES, RESTART IT

UPA.30:	RESTORE	<R0,DQ,J>	; THE REGISTERS
	RTI			;AND DISMISS THE INTERRUPT
UPAOFF:				;HERE IF INTERRUPT LEVEL OUT-RAN LOOP
	TWIDDLE			;COUNT IT
	BR	UPAER0		;RESTART THE LINE

UPAERR:				;HERE ON OVER-RUN ONLY <DQ,R0,J> ON STACK
.IF EQ FT.SLB			;IF NOT SMALL LINE BLOCKS (...)
	INC	LB.SLE(J)	;CHALK UP ANOTHER DEMERIT
	MOV	UP.RBF(DQ),LB.SLE+2(J) ;KEEP THE HARDWARE TILL NEXT TIME
	MOV	LB.RDN(J),LB.SLE+4(J) ;AND KEEP THE 'STATE' OF DDCMP
.ENDC; EQ FT.SLB
UPAER0:	MOVB	#NCDROV,LB.NCD(J) ;SIGNAL A RECEIVER OVER-RUN NAK
	JSR	PC,DRNAK1	; AND WAKE THE XMITTER TO SEND IT.
	JSR	PC,UPASTP	;STOP THE DUP-11
	TST	LB.SRR+6(J)	;SEE IF WE HAVE A CALL IN TO DNDCMP
	BEQ	UPA.30		;IF SO, DON'T CALL AGAIN
	BR	UPARS1		;OTHERWISE SPEED THINGS UP BY STARTING IT
				; OURSELVES
;HERE TO RESTART THE LINE BECAUSE LOW LEVEL TOLD US TO.
UPARST:	JSR	PC,UPASTP	;FIRST STOP THE LINE.
UPARS1:	SAVE	R1		;DDCMP CLOBBERS THIS
	JSR	PC,DDCIGO	;RE-START THE LINE NOW
	RESTORE	R1		;GET BACK CLOBBERED DATA
	BR	UPA.30		;AND RETURN

;HERE TO STOP THE RECEIVER
UPASTP:	MOV	LB.SLA(J),DQ	;GET DUP11 HDW ADR
	BIC	#LS..RG,@J	;TELL SOFTWARE THAT THE LINE'S STOPPED
	BIC	#UP.RIE!UP.REN,@DQ ;CONVINCE HARDWARE TOO
	QUEPUT	QI		;RE-QUEUE THE LINE
	RTS	PC		;AND RETURN

.IF NE 0
		DDCMP  <=>  TRANSMITTER INTERFACE.


			*** NOTE ***

	THERE ARE TWO THINGS TO NOTICE ABOUT THE DUP-11 TRANSMITTER.
	   A)	THE DUP-11 TRANSMITTER IS A STATE MACHINE.  IT HAS THE
		FOLLOWING STATES.  (STORED AS A DISPATCH ADDRESS IN LB.STX)
		    UPBIDL	THE DUP-11 IS NOT SENDING ANYTHING
		    UPBSYN	THE DUP-11 IS SENDING SYNCH'S.  THE
				NEGATIVE COUNT IS IN LB.SXR+2, AND THE
				SYNCH CHAR IS IN LB.SXR (NOT A POINTER)
		    UPBDAT	THE DUP-11 IS SENDING DATA (IT WILL NOT
				APPEND THE BCC AT THE END OF THE BUFFER)
		    UPBDWC	THE DUP-11 IS SENDING DATA WITH CHECKSUM.
				IT WILL APPEND THE BCC AT THE COMPLETION
				OF THE BUFFER.
	   B)	THE DUP-11 DETERMINES WHAT TYPE OF DATA TO SEND BY
		THE TWO HIGH ORDER BITS OF THE COUNT RETURNED BY THE
		SERVICE ROUTINE.  THESE BITS MEAN THE FOLLOWING

	   (00)	BOTH BITS OFF IMPLY THAT THIS DATA IS SYNCH DATA. 
		R1+140000 IS MINUS THE NUMBER TO SEND, R0 IS THE SYNCH
		CHARACTER (NOT A POINTER TO IT)
	   (01)	JUST THE SIGN BIT OFF IMPLIES THAT THIS MESSAGE SHOULD
		BE SENT WITH A BCC.  WHEN THE BYTE COUNT IS EXHAUSTED
		THE DUP-11 WILL BE COAXED INTO TRANSMITTING THE BCC
	   (11)	A NORMAL  NEGATIVE NUMBER IMPLIES THAT THIS IS DATA
		WITH OUT BCC.  THE BCC WILL NOT BE APPENDED TO THE MESSAGE.


.ENDC

.MACRO	X	Q
UPVB'Q:	SAVE	<J>
	MOV	#FLBDUP+<LB.SIZ*'Q>,J
.ENDM	X
	Z=DUPN-1
.REPT	DUPN
	X	\Z
.IIF NE Z,	BR	DUPBINT
Z=Z-1
.ENDR
DUPBINT:			;HERE ON A TRANSMIT DONE INTERRUPT
	SAVE	<R0,DQ>		;MINIMAL STORAGE REQUIREMENTS
	TRACE	DUP		;FOR THE CURIOUS
	MOV	LB.SLA(J),DQ	;GET THE HARDWARE BASE ADDRESS
	MOV	UP.XSR(DQ),R0	;GET THE STATUS
	BMI	UPBERR		;IF AN ERROR, IT WAS PROBABLY DATA UNDERRUN
	JMP	@LB.STX(J)	;DISPATCH TO PROPER ROUTINE

UPBIDL:				;SHOULDN'T GET HERE
;	TRAP			;INTERRUPT WITH INTERRUPTS OFF??
	BR	UPBXOF		;SHUT DOWN THE TRANSMITTER

UPBSYN:				;SENDING SYNCH'S. CHAR IS IN LB.SXR
	MOVB	LB.SXR(J),R0	;GET THE SYNCH CHAR
	BIC	#^C377,R0	; (MOVB SIGN EXTENDS)
	BIS	#UP.XSM,R0	;"OR" IN THE "DON'T CHECKSUM" BIT
	MOV	R0,UP.XBF(DQ)	;SEND THE CHARACTER
	BR	UPBINC		;INCREMENT THE COUNT AND RETURN

UPBDAT:				;HERE FOR DATA WITH OUT BCC AT END OF BUFFER
	MOVB	@LB.SXR(J),R0	;GET THE NEXT CHAR
	BIC	#^C377,R0	; (MOVB SIGN EXTENDS)
	MOV	R0,UP.XBF(DQ)	;AND SEND IT (THIS WAY CLEARS TSOM, TEOM)
	INC	LB.SXR(J)	;ADVANCE THE BYTE POINTER
	BR	UPBINC		;BRANCH TO COMMON INCREMENT & RETURN CODE

;UPBDWC MANAGES THE BYTE COUNT SOMEWHAT DIFFERENTLY FROM THE 3 PREVIOUS
; ROUTINES.  HERE THE BYTE COUNT IS ALLOWED TO GO TO ZERO.  WHEN THIS
; ROUTINE IS ENTERED WITH A ZERO BYTE COUNT, IT SENDS THE BCC & ADVANCES
; THE BUFFERS
UPBDWC:				;DATA WITH BCC
	TST	LB.SXR+2(J)	;CHECK TO SEE IF IT'S BCC TIME
	BGE	50$		;A ZERO COUNT SAYS THAT IT IS.

	MOVB	@LB.SXR(J),R0	;GET THE NEXT CHARACTER
	BIC	#^C377,R0	; (MOVB SIGN EXTENDS)
	MOV	R0,UP.XBF(DQ)	;SEND IT (WITH TSOM AND TEOM CLEAR)
	INC	LB.SXR(J)	;ADVANCE THE BYTE POINTER
	INC	LB.SXR+2(J)	;CHALK UP ANOTHER BYTE AS SENT
	BLE	UPBRET		;AND RETURN
	TRAP			;CAN'T HAPPEN (I HOPE!)

50$:				;HERE TO SEND THE BCC
	BIS	#UP.XEM,UP.XBF(DQ) ;SET TEOM
	BR	UPBADV		; AND ADVANCE THE BUFFERS

UPBINC:				;COMMON CODE TO INCREMENT BYTE COUNT
	INC	LB.SXR+2(J)	;COUNT OFF ANOTHER BYTE
	BLT	UPBRET		;IF COUNT HASN'T OVERFLOWED THEN RETURN
;	BR	UPBADV		; IF IT HAS, ADVANCE THE BUFFERS.

UPBADV:				;HERE TO ADVANCE THE BUFFERS
	MOV	LB.SXR+4(J),LB.SXR(J) ;COPY THE BYTE POINTER
	MOV	LB.SXR+6(J),LB.SXR+2(J)	;COPY THE BYTE COUNT
	BEQ	UPBXOF		;LOW LEVEL COULDN'T KEEP UP. SHUT DOWN
	BIS	#140000,LB.SXR+2(J) ;MAKE SURE WE DON'T GET CONFUSED WITH FLAGS
	MOV	LB.SXR+6(J),R0	;GET A COPY TO PLAY WITH
	CLR	LB.SXR+6(J)	;CLEAR THIS SO WE KNOW LOW LEVEL IS RUNNING
	TST	R0		;NOW THAT WE HAVE TIME, SEE WHAT'S GOING ON
	BMI	20$		;IF SIGN BIT, THEN DATA WITH OUT BCC
	BIT	#40000,R0 	;OTHERWISE ITS WITH BCC, OR SYNC
	BNE	30$		;IF 40000 BIT SET, THEN IT'S DATA WITH BCC
				;OTHERWISE ITS SYNCH DATA
	MOV	#UPBSYN,LB.STX(J) ;GO TO THE 'SYNCH' STATE
	BR	50$		;AND JOIN MAIN FLOW

20$:	MOV	#UPBDAT,LB.STX(J) ;GO TO DATA STATE
	BR	50$		;AND JOIN MAIN FLOW

30$:	MOV	#UPBDWC,LB.STX(J) ;GO TO DATA WITH BCC STATE
;	BR	50$		;AND JOIN MAIN FLOW

50$:
;	MOV	10(SP),PS	;RE-ENABLE THE INTERRUPTS
	SUB	#40,PS		;DROP BACK TO LEVEL 5 (LOCK OUT DZ'S)
	SAVE	<R1,R2,R4>	;DON'T TRUST DDCMP
	JSR	PC,@LB.XDN(J)	;CALL THE SERVICE ROUTINE
;	BIS	#340,PS		;PROTECT AGAINST INTS AGAIN
	MOV	R0,LB.SXR+4(J)	;SAVE NEXT BYTE POINTER
	MOV	R1,LB.SXR+6(J)	;SAVE NEXT BYTE COUNT
	RESTORE	<R4,R2,R1>	;PUT THESE BACK.

UPBRET:	RESTORE	<DQ,R0,J>	;RESTORE OUR WORKING REGISTERS
	RTI			;AND RETURN

UPBERR:				;HERE ON A HARDWARE UNDER-RUN ERROR
.IF EQ FT.SLB
	INC	LB.SLE(J)	;ANOTHER DEMERIT
	MOV	R0,LB.SLE+2(J)	;REMEMBER THE STATUS
	MOV	LB.XDN(J),LB.SLE+4(J) ;REMEMBER THE "STATE"
.ENDC

UPBXOF:				;HERE IF WE RAN INTO A ZERO LENGTH BUFFER
				; (PROBABLY LOW-LEVEL COULDN'T KEEP UP)
	TWIDDLE			;COUNT THE TIMES WE LOSE THIS WAY
	BIC	#LS..XG!LS.XCT!LS.XDT,@J ;MAKE SOFTWARE THINK IT'S DOWN
	BIC	#UP.XIE!UP.SND,UP.XSR(DQ) ;MAKE THE HARDWARE THINK SO TOO
	MOV	#UPBIDL,LB.STX(J) ;SET THE STATE TO IDLE
	QUEPUT	QO		;RE-QUEUE THE LINE
	BR	UPBRET		;RETURN FROM THE INTERRUPT

.ENDC ;.IF NE FTDUP11