Google
 

Trailing-Edge - PDP-10 Archives - BB-J724A-SM_1980 - sources/dup11.p11
There are 2 other files named dup11.p11 in the archive. Click here to see a list.
.SBTTL	DUP11 DRIVER
;
; THIS SECTION CONTAINS SUBROUTINES TO DRIVE THE DUP11.
;  THESE ARE:
;
;	DQINIT		INITIALIZE THE DUP11
;	DQREAD		CONDITION THE DUP11 FOR INPUT
;	DQWRIT		CONDITION THE DUP11 TO OUTPUT A DATA MESSAGE
;	DQCNTL		CONDITION THE DUP11 TO OUTPUT A CONTROL MESSAGE
;	DQKILL		CEASE ANY DUP11 OPERATIONS
;
; THIS SECTION ALSO CONTAINS THE INTERRUPT CODE FOR THE DUP11,
;  AND A "ONCE-PER-CLOCK-TICK" SUBROUTINE
;  TO PROVIDE DELAYED MODEM CONTROL SINCE A MODEM INTERRUPT
;  CANNOT BE CAUSED BY THE PROGRAM.
;
.REPT 0


                          COPYRIGHT (c) 1980, 1979
            DIGITAL EQUIPMENT CORPORATION, maynard, mass.

THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
ONLY  IN  ACCORDANCE  WITH  THE  TERMS  OF  SUCH  LICENSE AND WITH THE
INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE OR  ANY  OTHER
COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
TRANSFERRED.

THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE  WITHOUT  NOTICE
AND  SHOULD  NOT  BE  CONSTRUED  AS  A COMMITMENT BY DIGITAL EQUIPMENT
CORPORATION.

DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR  RELIABILITY  OF  ITS
SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.

.ENDR
;
;
;
;
;		REVISION HISTORY
;
;
; 4(001) BS	ADDED EDIT NUMBERS
; 4(002)	Remove chunk ownership trace in DUP receiver interrupt code
;
;
;
VDUP11=002
;
VEDIT=VEDIT+VDUP11
;
;
;
; SPECIFY THE NUMBER OF TRAILING PADS REQUIRED ON
;  DATA MESSAGES.
;
DQTRLP=1		;TO BE SURE THE LAST CHAR MAKES IT
;
;
; SPECIFY THE TYPE OF LINE INTERFACE, WHICH IS REPORTED TO THE -10
;
DQTYPE=3		;1 = DQ11, 2 = KMC11/DUP11, 3 = DUP11 ALONE
;
;
; INITIALIZATION
;
; R4 = POINTER TO LINE CONTROL BLOCK FOR DUP11 TO BE
;	INITIALIZED.
;
DQINIT:	TRACE	TRCDQF,R4	;TRACE "DUP11 INITIALIZATION"
	MOV	LB.SLA(R4),R3	;GET DUP11 LINE HARDWARE ADDRESS
	MOV	#UP.INI,UP.XSR(R3) ;INITIALIZE THE DUP11
11$:	BIT	#UP.INI,UP.XSR(R3) ;HAS IT FINISHED INITIALIZATION?
	BNE	11$		;NO, WAIT FOR IT.
	MOV	#UP.CCI!UP.DMD!EBCSYN,UP.PAR(R3) ;SET UP PARMS
				; FOR BISYNC
	MOV	#UP.HDX,UP.XSR(R3) ;BLIND RECEIVER DURING TRANSMISSIONS
	MOV	#UP.SSY,UP.RSR(R3) ;STRIP LEADING SYNC FROM MESSAGES
	RTS	PC		; AND RETURN.
;
;
; START RECEIVER
;
; R4 = POINTER TO LINE CONTROL BLOCK
;
; RETURNS C BIT SET IF ERROR, CLEAR IF OK.
;  (ONLY ERROR IS CHUNKS DEPLETED)
;
DQREAD:	TRACE	TRCDQF,R4	;TRACE ENTRY TO "DQ READ"
	MOV	LB.SLA(R4),R3	;GET HARDWARE ADDRESS
.IF NE,FT.CHK
	BIT	#LS.RGO!LS.RRN,(R4) ;IS DUP11 ALREADY READING?
	BEQ	11$		;NO, GOOD.
	STOPCD	QRN		;DUP11 SUBR WITH DUP11 RUNNING
11$:	MOV	LB.TC1(R4),R0	;POINT TO BSC TASK
	TST	TCCHK1(R0)	;DOES IT HAVE ANY CHUNKS?
	BEQ	12$		;NO, OK
	STOPCD	QRN		;YES, SOMETHING'S WRONG.
12$:	TST	LB.CCH(R4)	;IS THERE A "CURRENT CHUNK"?
	BEQ	13$		;NO, ALL IS WELL.
	STOPCD	QRN		;YES, THERE SHOULD NOT BE.
13$:
.ENDC ;.IF NE,FT.CHK
	MOV	CHLST,R0	;GET A CHUNK
	JSR	PC,GETCHK
	BCS	14$		;NO MORE CHUNKS
	MOV	R0,LB.CCH(R4)	;STORE CHUNK ADDRESS
	ADD	#CHLEN,R0	;POINT TO LENGTH FIELD
	MOV	R0,LB.CCR(R4)	;STORE FOR INPUT INTERRUPT ROUTINES
	ADD	#CHDAT-CHLEN,R0	;POINT TO DATA FIELD
	MOV	R0,LB.CCD(R4)	;STORE FOR INPUT INTERRUPT ROUTINES
	CLR	LB.CRD(R4)	;CLEAR COUNT OF CHARACTERS READ
;
;			; CONTINUED ON NEXT PAGE
;
;
; HERE WHEN EVERYTHING IS READY.
;  WE MUST START THE RECEIVER NOW, SINCE SOME DUP11'S
;  DON'T INTERRUPT ON CARRIER, AND IF WE WAIT UP TO
;  16 MILLISECONDS BEFORE STARTING THE RECEIVER AFTER
;  GETTING CARRIER, WE WILL FREQUENTLY LOSE THE FIRST
;  CHARACTER OF THE MESSAGE.
;
	MOV	LB.TC1(R4),R1	;GET TCB OF BSC TASK
	MOV	LB.CCH(R4),R0	;GET CURRENT CHUNK
	JSR	PC,QUECHK	;SEND CHUNK TO DRIVER WHILE WE FILL IT
	MFPS	-(SP)		;SAVE CPU PRIORITY LEVEL
	MTPS	#BR7		;DISABLE CPU INTERRUPTS
	BIS	#UP.DIE!UP.RIE!UP.REN,UP.RSR(R3) ;START THE DUP11 NOW
	BIS	#LS.RRN,(R4)	;RECEIVER IS NOW RUNNING
	BIC	#UP.CAR,LB.DIP(R4) ;PROCESS CARRIER NEXT TIME WE SEE IT
	BIC	#LS.CAR,(R4)	;WE HAVE NOT YET SEEN CARRIER
	MTPS	(SP)+		;RESTORE CPU PRIORITY
	CLC			;FLAG NO ERROR
14$:	RTS	PC		;AND RETURN.
;
;
; SUBROUTINE TO START TRANSMITTING A DATA MESSAGE FROM LB.MSG
;
; R4 = POINTER TO LINE CONTROL BLOCK
;
; RETURNS WITH C BIT SET IF ERROR, CLEAR IF NOT.
;
DQWRIT:	TRACE	TRCDQF,R4	;TRACE ENTRY TO "DQ WRITE DATA"
	BIC	#LS.CTL,(R4)	;THIS IS A DATA, NOT A CONTROL MESSAGE
	MOV	LB.SLA(R4),R3	;GET DUP11 HARDWARE ADDRESS
.IF NE,FT.CHK
	BIT	#LS.ACT,(R4)	;IS DUP11 STILL ACTIVE?
	BEQ	11$		;NO.
	STOPCD	QRN		;YES, THIS IS NOT PROPER.
11$:
.ENDC ;.IF NE,FT.CHK
	MOV	LB.MSG(R4),R0	;POINT TO MESSAGE
	MOV	(R0),R1		;POINT TO FIRST DATA CHUNK
	MOV	R1,MSGLCH(R0)	;START WITH FIRST CHUNK
	ADD	#CHDAT,R1	;POINT TO DATA AREA
	MOV	R1,MSGPTR(R0)	;STORE POINTER TO START OF DATA
	JSR	PC,XMTSTR	;ARRANGE TO START TRANSMITTER
	RTS	PC		;RETURN.
;
;
; SUBROUTINE TO ARRANGE TO START THE TRANSMITTER
;
XMTSTR:	BIS	#LS.XGO,(R4)	;XMITTER WAITING FOR CTS
	BIC	#LS.XND,(R4)	;NOT ENDING TRANSMISSION
	MFPS	-(SP)		;SAVE INTERRUPT LEVEL
	MTPS	#BR7		;DISABLE INTERRUPTS
	BIS	#UP.RTS!UP.DIE,UP.RSR(R3) ;RAISE REQUEST TO SEND
				; AND ENABLE FOR CTS INTERRUPT
	MOV	LB.CSD(R4),LB.DEW(R4) ;WAIT A WHILE, THEN CHECK FOR CTS
				; NOTE THAT MODEM INTERRUPTS ARE IGNORED
				; UNTIL TIME IS UP.
	BNE	11$		;TIME IS NOT YET UP.
;
; HERE IF CLEAR-TO-SEND DELAY SPECIFIED IS ZERO.
;  IF CTS IS UP, START THE TRANSMITTER.  NOTE THAT
;  A ZERO CLEAR-TO-SEND DELAY SHOULD BE USED ONLY WITH MODEMS
;  THAT HAVE A CLEAR-TO-SEND DELAY OF LESS THAN 16 MILLISECONDS,
;  SINCE A LARGER DELAY CAN BE TIMED WITHOUT LOSS OF EFFICIENCY
;  AND TOO SHORT A DELAY (LESS THAN ABOUT 8 MILLISECONDS)
;  DOES NOT WORK WITH SOME IBM HOSTS.
;
	BIT	#UP.CTS,UP.RSR(R3) ;IS CTS UP?
	BEQ	11$		;NO, WAIT FOR MODEM INTERRUPT
	BIS	#UP.SND!UP.XIE,UP.XSR(R3) ;YES, START XMT
	MOV	#UP.XSM!EBCPAD,UP.XBF(R3)
	BIC	#LS.XGO,(R4)	;NOT WAITING FOR CTS
	BIS	#LS.XRN,(R4)	;NOW RUNNING
	BR	12$		;ENABLE INTERRUPTS, CLEAR C AND RETURN.
;
; HERE IF CTS DELAY IS NON-ZERO, OR IF IT IS ZERO AND CTS IS NOT UP.
;
11$:	BIC	#UP.CTS,LB.DIP(R4) ;PROCESS CTS RAISING NEXT TIME WE SEE IT
12$:	MTPS	(SP)+		;ENABLE INTERRUPTS
	CLC			;CLEAR 'C' FLAG
	RTS	PC		;RETURN.
;
;
; SUBROUTINE TO START TRANSMITTING A CONTROL MESSAGE (E.G., ACK)
;
; R4 = POINTER TO LINE CONTROL BLOCK
; R0 = POINTER TO MESSAGE TO SEND
; R1 = LENGTH OF MESSAGE TO SEND
;
; ON RETURN:
;
;	C SET IF ERROR, CLEAR IF NOT.
;
DQCNTL:	TRACE	TRCDQF,R4	;TRACE ENTRY TO "DQ WRITE CONTROL"
	MOV	R0,LB.CMA(R4)	;REMEMBER CONTROL MESSAGE ADDRESS
	MOV	R1,LB.CMC(R4)	; AND LENGTH
	BIS	#LS.CTL,(R4)	;WE ARE WORKING ON A CONTROL MESSAGE
	TRACE	TRCDQF,R0	; AND NOTE MESSAGE
	MOV	LB.SLA(R4),R3	;GET DUP11 HARDWARE ADDRESS
.IF NE,FT.CHK
	BIT	#LS.ACT,(R4)	;IS DUP11 STILL ACTIVE?
	BEQ	11$		;NO.
	STOPCD	QRN		;YES, ERROR.
11$:	TST	LB.CCH(R4)	;HAS RECEIVER STILL GOT A CHUNK?
	BEQ	12$		;NO, THAT'S GOOD.
	STOPCD	QRN		;YES, MUST SOMEHOW BE RUNNING.
12$:
.ENDC ;.IF NE,FT.CHK
	JSR	PC,XMTSTR	;ARRANGE TO START TRANSMITTER
	RTS	PC		;RETURN.
;
;
; THIS IS THE COMMON INTERRUPT CODE FOR DUP11 RECEIVER INTERRUPTS.
;  IT IS CALLED WITH PS CONTAINING THE LINE NUMBER.
;  MODEM INTERRUPTS ALSO COME HERE.
;
DQAINT:	JSR	R4,(PC)		;SAVE R4 WITHOUT CHANGING PS
	MFPS	R4		;GET PS
	BIC	#177760,R4	;REMOVE ALL BUT LINE NUMBER
	ASL	R4		;LINE NUMBER * 2
	MOV	DQLCB(R4),R4	;GET POINTER TO LCB
	MOV	R3,-(SP)	;SAVE R3
	MOV	R1,-(SP)	;SAVE R1
	MOV	R0,-(SP)	;SAVE R0
.IF NE,FT.CHK
	TST	R4		;HAVE WE A LINE BLOCK?
	BNE	11$		;YES.
	STOPCD	UQR		;UNKNOWN DUP11 RECEIVER INTERRUPT
11$:
.ENDC ;.IF NE,FT.CHK
	MOV	LB.SLA(R4),R3	;GET HARDWARE ADDRESS OF DUP11
	INC	LB.RCT(R4)	;ONE MORE RECEIVER INTERRUPT
	TRACE	TRCDQF,R4	;TRACE DUP11 "A" INTERRUPT
;
;
; HERE TO CHECK FOR (ANOTHER) DUP11 RECEIVER INTERRUPT BIT
;
RCVTST:	MOV	UP.RSR(R3),R0	;GET RECEIVER STATUS REGISTER
	MOV	R0,LB.RST(R4)	;STORE LAST RECEIVER STATUS
	TRACE	TRCDQF,R0	;TRACE INTERRUPT STATUS
	BIT	#UP.RDN,R0	;IS RECEIVER DONE?
	BEQ	11$		;NO, CHECK FOR DATASET FLAG
	MOV	UP.RBF(R3),R1	;YES, GET CHARACTER
	BLT	12$		;ERROR.
	MOVB	R1,@LB.CCD(R4)	;STORE BYTE IN CURRENT CHUNK
	INC	LB.CCD(R4)	;ADVANCE POINTER
	INC	@LB.CCR(R4)	;INCREMENT LENGTH FIELD OF CHUNK
	CMP	@LB.CCR(R4),#CHDATL ;IS CHUNK FULL?
	BNE	11$		;NO.
;
;
; WE HAVE FILLED THE CURRENT CHUNK.  GET ANOTHER ONE SO WE CAN FILL IT.
;
	MOV	CHFST,R0	;GET ANOTHER CHUNK.
	CMP	R0,CHLST	;IS THERE ONLY ONE CHUNK LEFT?
	BEQ	13$		;YES, WE ARE OUT OF CHUNKS
	MOV	(R0),R1		;NO, GET NEXT CHUNK
	BIC	#1,R1		;CLEAR "FREE" FLAG
	MOV	R1,CHFST	;NEXT IS NOW FIRST CHUNK
	CLR	(R0)		;CLEAR "FREE" BIT
	CLR	2(R1)		;CLEAR NEW FIRST CHUNK'S BACK POINTER
	DEC	CHFREC		;ONE FEWER FREE CHUNK
	TRACE	TRCCNK,R0	;TRACE CHUNK MANIPULATION
.IF NE,CHOWNR
;[4(002)]	MOV	PC,R1		;CHUNK OWNER IS HERE
;[4(002)]	JSR	PC,CHOWNG	;RECORD CHUNK OWNER
.ENDC ;.IF NE,CHOWNR
	MOV	R0,LB.CCH(R4)	;IT IS NOW CURRENT
	BIC	#UP.RIE,UP.RSR(R3) ;DISABLE RECEIVER INTERRUPTS FOR THIS LINE
	MTPS	#BR4		;ALLOW XMT AND RCV INTS FROM OTHER LINES
	MOV	LB.TC1(R4),R1	;GET TCB OF RECEIVE CHUNK HANDLER
	JSR	PC,QUECHK	;SEND HIM THE CHUNK
	ADD	#CHLEN,R0	;POINT TO LENGTH FIELD
	MOV	R0,LB.CCR(R4)	;STORE FOR NEXT INPUT INTERRUPT
	ADD	#CHDAT-CHLEN,R0	;POINT TO DATA FIELD
	MOV	R0,LB.CCD(R4)	;STORE FOR NEXT INPUT INTERRUPT
	ADD	#CHDATL,LB.CRD(R4) ;INCREMENT COUNT OF CHARACTERS READ
	MTPS	#BR7		;DISABLE INTERRUPTS
	BIS	#UP.RIE,UP.RSR(R3) ;ALLOW NEW RECEIVER INTERRUPTS ON THIS LINE
	CMP	LB.CRD(R4),#DQRLMT ;TOO MANY CHARACTERS IN MESSAGE?
	BGT	14$		;YES, SHUT DOWN RECEIVER.
	BR	RCVTST		;NO, LOOK FOR ANOTHER DONE INTERRUPT
;
;
; HERE IF NOT RECEIVER DONE, OR AFTER PROCESSING RECEIVER DONE.
;  (EXCEPT IN LONG RECEIVER DONE PROCESSING, WHICH CHECKS FOR ANOTHER
;  DONE FLAG.)
;
11$:	BIT	#UP.DCA!UP.DCB,LB.RST(R4) ;ANY DATASET FLAGS?
	BEQ	15$		;NO, EXIT THE INTERRUPT.
	JSR	PC,RCVDSF	;YES, PROCESS DATASET FLAGS
	BR	RCVTST		;CHECK FOR MORE FLAGS
;
; HERE ON ERROR IN RECEIVER
;
12$:	INC	LB.SE4(R4)	;RECEIVER OVERRUN
	JSR	PC,DQERRR	;RECORD AN ERROR
	BR	14$		;TERMINATE THE INTERRUPT.
;
; COME HERE IF WE ARE OUT OF CHUNKS.  WE DO NOT SET LS.ERR BECAUSE
;  WE MAY BE FILLING CORE WITH PADS IF THE BSC TASK IS SLOWER THAN
;  THE LINE.  IF WE RUN OUT OF CORE BEFORE THE MESSAGE IS ACTUALLY
;  IN THEN THE BSC TASK WILL MISS THE ETX.
;
13$:	INC	LB.CHD(R4)	;NOTE CHUNKS DEPLETED
;
; COME HERE IF WE HAVE TOO LONG A MESSAGE.  IF THIS IS ACTUALLY
;  AN ERROR AND NOT JUST READING PADS IT WILL BE CAUGHT BY
;  THE BSC TASK, AS ABOVE.
;
14$:	JSR	PC,RCVSTP	;KILL THE RECEIVER
;
; HERE ON NORMAL EXIT.  WAKE THE BSC TASK IF REQUESTED.
;
15$:	BIT	#LS.CIE,(R4)	;DOES BSC TASK WANT TO BE AWAKENED?
	BEQ	16$		;NO.
	BIC	#LS.CIE,(R4)	;YES, CLEAR FLAG
	MOV	LB.TC1(R4),R0	;POINT TO BSC TASK'S TCB
	BIT	#EBQCHK,(R0)	;IS BSC TASK WAITING FOR CHUNK DATA?
	BEQ	16$		;NO (UNLIKELY)
	BIC	#EBQCHK!EBWAIT,(R0) ;YES, UNWAIT IT.
16$:
;
; HERE TO RESTORE REGISTERS AND RETURN.
;
17$:	MOV	(SP)+,R0	;RESTORE R0
	MOV	(SP)+,R1	; AND R1
	MOV	(SP)+,R3	; AND R3
	MOV	(SP)+,R4	; AND R4
	RTI			;EXIT INTERRUPT
;
;
; SUBROUTINE TO RECORD A DUP11 ERROR.
;
DQERRR:	INC	LB.SE1(R4)	;COUNT MASTER ERROR COUNTER
	MOV	UP.RSR(R3),LB.SE2(R4) ;RECORD STATUS REG 1
	MOV	UP.XSR(R3),LB.SE3(R4) ; AND STATUS REG 2
	BIS	#LS.ERR,(R4)	;FLAG AN ERROR
	RTS	PC		;RETURN TO CALLER.
;
;
; SUBROUTINE TO STOP THE RECEIVER
;
;   R4 POINTS TO LCB, R3 TO CSR.
;
RCVSTP:	TRACE	TRCDQF,R4	;TRACE DUP11 RECEIVER STOP
.IF NE,DEBUG
	BIT	#LS.RGO!LS.RRN,(R4) ;IS RECEIVER RUNNING?
	BNE	11$		;YES.
	STOPCD	DBG		;NO, SHOULDN'T BE HERE.
11$:
.ENDC ;.IF NE,DEBUG
	BIC	#UP.REN!UP.RIE!UP.DIE,UP.RSR(R3) ;STOP THE RECEIVER
	CLR	LB.CCH(R4)	;NO CURRENT CHUNK
	BIC	#LS.RGO!LS.RRN,(R4) ;NOT RUNNING
	BIT	#EBQCHK,@LB.TC1(R4) ;IS BSC TASK WAITING FOR A CHUNK?
	BEQ	12$		;NO.
	BIC	#EBQCHK!EBWAIT,@LB.TC1(R4) ;YES, UNWAIT IT.
12$:	RTS	PC		;RETURN.
;
;
; COMMON CODE FOR DUP11 INTERRUPTS
;
DQBINT:	JSR	R4,(PC)		;SAVE R4
	MFPS	R4		;PUT PS IN R4
	BIC	#177760,R4	;REMOVE ALL BUT LINE NUMBER
	ASL	R4		;LINE NUMBER * 2
	MOV	DQLCB(R4),R4	;GET LCB POINTER
	MOV	R3,-(SP)	;SAVE R3
	MOV	R0,-(SP)	;SAVE R0
	MOV	R1,-(SP)	;SAVE R1
.IF NE,FT.CHK
	TST	R4		;IS THERE A LINE BLOCK?
	BNE	11$		;YES.
	STOPCD	UQX		;UNKNOWN DUP11 XMIT INTERRUPT
11$:
.ENDC ;.IF NE,FT.CHK
	MOV	LB.SLA(R4),R3	;GET HARDWARE ADDRESS
	INC	LB.XCT(R4)	;ONE MORE TRANSMIT INTERRUPT
	TRACE	TRCDQF,R4	;TRACE DUP11 "B" INTERRUPT
;
;
; HERE TO CHECK FOR (ANOTHER) DUP11 TRANSMITTER 
;  INTERRUPT BIT.
;
XMTTST:	MOV	UP.XSR(R3),R1	;GET TRANSMITTER STATUS BITS
	MOV	R1,LB.XST(R4)	;RECORD LAST TRANSMIT STATUS
	BMI	17$		;BRANCH IF ANY ERRORS.
	TRACE	TRCDQF,R1	;TRACE DUP11 STATUS
	BIT	#UP.XDN,R1	;IS THE INTERRUPT TRANSMIT DONE?
	BEQ	19$		;NO, TIME TO EXIT.
	BIT	#LS.XND,(R4)	;IS THIS THE EXTRA DONE INTERRUPT 
				; THAT WE GET AS THE XMITTER STOPS?
	BEQ	11$		;NO, MUST BE REAL DATA.
	JSR	PC,XMTST1	;YES, DO SECOND HALF OF XMIT STOP
	BR	19$		;WE ARE DONE.
;
; HERE WHEN WE HAVE A REAL TRANSMIT DONE INTERRUPT.
;
11$:	BIT	#LS.CTL,(R4)	;ARE WE SENDING A CONTROL MESSAGE?
	BNE	14$		;YES.
	MOV	LB.MSG(R4),R1	;NO, POINT TO DATA MESSAGE
	MOVB	@MSGPTR(R1),R0	;GET NEXT CHARACTER
	BIC	#^C<377>,R0	;REMOVE POSSIBLE SPREAD SIGN
	MOV	R0,UP.XBF(R3)	;SEND CHARACTER, CLEARING SOM
	BIC	#UP.XIE,UP.XSR(R3) ;DISABLE XMT INTERRUPTS FROM THIS LINE
	MTPS	#BR4		;ALLOW INTERRUPTS FROM OTHER LINES
	INC	MSGPTR(R1)	;POINT TO NEXT CHARACTER
	MOV	MSGPTR(R1),R0	;COMPUTE POSITION IN BUFFER
	SUB	MSGLCH(R1),R0
	SUB	#CHDAT,R0
	MOV	MSGLCH(R1),R1	;POINT TO CURRENT CHUNK
	CMP	CHLEN(R1),R0	;HAVE WE EXHAUSTED THIS CHUNK?
	BNE	12$		;NO.
;
;			; CONTINUED ON NEXT PAGE
;
;
; HERE WHEN WE HAVE SENT ALL OF THIS CHUNK.  GO ON TO NEXT.
;
	MOV	LB.MSG(R4),R1	;POINT TO MESSAGE AGAIN.
	MOV	@MSGLCH(R1),R0	;POINT TO NEXT CHUNK OF MESSAGE
	BEQ	13$		;END OF MESSAGE
	MOV	R0,MSGLCH(R1)	;STORE POINTER TO NEXT CHUNK
	ADD	#CHDAT,R0	;COMPUTE DATA ADDRESS
	MOV	R0,MSGPTR(R1)	;STORE IT FOR NEXT INTERRUPT
;	BR	12$		;DONE WITH THIS CHARACTER.
;
; HERE ON END OF CHARACTER PROCESSING.  DISABLE PROCESSOR INTERRUPTS
;  AND RE-ENABLE THIS LINE.
;
12$:	MTPS	#BR7		;DISABLE PROCESSOR INTERRUPTS
	BIS	#UP.XIE,UP.XSR(R3) ;ENABLE XMT INTS FROM THIS LINE
	BR	16$		;LOOK FOR ANOTHER DONE BIT
;
; HERE ON END OF CHUNKS FOR DATA MESSAGE
;
13$:	MTPS	#BR7		;DISABLE PROCESSOR INTERRUPTS
	BIS	#UP.XIE,UP.XSR(R3) ;WE WILL GET ONE MORE DONE INTERRUPTT
	BR	15$		;SHUT DOWN TRANSMITTER
;
; HERE IF WE ARE SENDING A CONTROL MESSAGE
;
14$:	MOVB	@LB.CMA(R4),R0	;GET NEXT CHARACTER
	BIC	#^C<377>,R0	;REMOVE POSSIBLE SPREAD SIGN
	MOV	R0,UP.XBF(R3)	;SEND CHARACTER, CLEARING SOM
	INC	LB.CMA(R4)	;ADVANCE TO NEXT CHARACTER
	DEC	LB.CMC(R4)	;DECREMENT COUNTER
	BNE	19$		;NOT END OF MESSAGE,
				; EXIT THE INTERRUPT
;
; HERE ON END OF MESSAGE
;
15$:	BIS	#UP.XEM,UP.XBF(R3) ;TELL THE DUP11 END OF MESSAGE
	JSR	PC,XMTSTP	;ARRANGE TO STOP THE TRANSMITTER
;
; HERE WHEN WE ARE DONE WITH THE TRANSMIT INTERRUPT.
;
16$:	BR	XMTTST		;BACK TO TOP OF LOOP.
;
;
; HERE ON TRANSMIT ERROR INTERRUPT
;  (THE ONLY ERROR DETECTED HERE IS TRANSMITTER DATA LATE.)
;
17$:	MOV	R1,LB.ERS(R4)	;SAVE ERROR STATUS
	TRACE	TRCDQF,R1	;TRACE ERROR INTERRUPT
	BIS	#LS.ERR,(R4)	;FLAG AN ERROR
	BIT	#LS.XND,(R4)	;IS THIS THE EXTRA DONE AFTER STOPPING?
	BEQ	18$		;NO, DO NORMAL TRANSMITTER STOP
	JSR	PC,XMTST1	;YES, DO SECOND HALF OF TRANSMITTER STOP
	BR	19$		; AND DISMISS THE INTERRUPT
;
; HERE IF THIS IS NOT THE EXTRA DONE INTERRUPT AFTER
;  STOPPING THE TRANSMITTER.
;
18$:	INC	LB.SE5(R4)	;COUNT TRANSMITTER NOT FAST ENOUGH
	JSR	PC,DQERRR	;RECORD THE ERROR
	JSR	PC,XMTSTP	;STOP THE TRANSMITTER
;	BR	15$		;DISMISS THE INTERRUPT
;
; HERE WHEN NO MORE FLAGS ARE FOUND.
;  (ALSO FROM CONTROL MESSAGE, SINCE IT DOESN'T ENABLE INTERRUPTS.
;  THIS IS TO IMPROVE BUS LATENCY.)
;
19$:	MOV	(SP)+,R1	;RESTORE R1
	MOV	(SP)+,R0	;RESTORE R0
	MOV	(SP)+,R3	;RESTORE R3
	MOV	(SP)+,R4	;RESTORE R4
	RTI			;EXIT THE INTERRUPT.
;
;
; SUBROUTINE TO STOP THE TRANSMITTER
;
; R4 POINTS TO THE LCB
; R3 POINTS TO THE CSR
;
XMTSTP:	TRACE	TRCDQF,R4	;TRACE DUP11 TRANSMITTER STOP
	BIC	#UP.SND,UP.XSR(R3) ;TELL DUP11 WE HAVE STOPPED SENDING
	BIT	#UP.XIE,UP.XSR(R3) ;ARE TRANSMIT INTERRUPTS ENABLED?
	BEQ	XMTST1		;NO, DO SECOND HALF RIGHT AWAY.
	BIS	#LS.XND,(R4)	;YES, WAIT FOR NEXT TRANSMIT
				; INTERRUPT WHEN SENDING COMPLETE
	CLC			;FLAG SUCCESS
	RTS	PC		;WAIT FOR NEXT TRANSMIT INTERRUPT
;
; SUBROUTINE CALLED ON NEXT TRANSMIT DONE INTERRUPT
;  OR BRANCHED TO FROM ABOVE WHEN TRANSMIT INTERRUPTS NOT ENABLED.
; ALSO CALLED DIRECTLY FROM TRANSMIT ERROR, SINCE IN THAT CASE
;  WE DO NOT GET ANOTHER DONE INTERRUPT.
;
XMTST1:	TRACE	TRCDQF,R4	;TRACE SECOND HALF OF TRANSMIT STOP
	BIC	#LS.XND,(R4)	;CLEAR FLAG THAT GOT US HERE
	BIC	#UP.RTS,UP.RSR(R3) ;DROP REQUEST TO SEND
	BIC	#UP.XIE,UP.XSR(R3) ;DISABLE TRANSMIT DONE INTERRUPTS
	BIC	#LS.XGO!LS.XRN,(R4) ;DUP11 TRANSMITTER NOT RUNNING
	CLR	LB.DEW(R4)	;NOT WAITING TO ENABLE MODEM
	MOV	LB.TC1(R4),R1	;GET TCB OF BSC TASK
	BIT	#EBINTR,(R1)	;IS IT WAITING?
	BEQ	11$		;NO.
	BIC	#EBINTR!EBWAIT,(R1) ;MAYBE, RESTART IT.
11$:	CLC			;MARK OK
	RTS	PC		; AND RETURN.
;
;
; SUBROUTINE TO PROCESS A DATA SET FLAG.
;
RCVDSF:	INC	LB.DIC(R4)	;COUNT DATASET INTERRUPTS
	MOV	R0,LB.DIS(R4)	;RECORD LAST MODEM INTERRUPT STATUS
	TST	LB.DEW(R4)	;WAITING FOR DATASET ENABLE?
	BNE	14$		;YES, IGNORE MODEM SIGNAL.
	BIT	#LS.ACT,(R4)	;IS THE DUP11 ACTIVE?
	BEQ	14$		;NO, IGNORE THE MODEM SIGNALS
	MOV	R0,LB.DIP(R4)	;YES, RECORD LAST MODEM SIGNALS PROCESSED
	BIT	#LS.XGO,(R4)	;WAITING TO START XMITTER?
	BEQ	11$		;NO.
	JSR	PC,15$		;YES, CHECK FOR CLEAR-TO-SEND.
11$:	BIT	#LS.XRN,(R4)	;RUNNING THE TRANSMITTER?
	BEQ	12$		;NO.
	JSR	PC,17$		;YES, BE SURE CTS STILL UP
12$:	BIT	#LS.RGO,(R4)	;WAITING TO START RECEIVER?
	BEQ	13$		;NO.
	JSR	PC,19$		;YES, SEE IF CARRIER UP YET
13$:	BIT	#LS.RRN,(R4)	;RUNNING RECEIVER?
	BEQ	14$		;NO.
	JSR	PC,21$		;YES, WORRY ABOUT CARRIER FAILURE.
14$:	RTS	PC		;RETURN TO CALLER.
;
;
; FOUR SUBROUTINES TO PROCESS DATA SET FLAGS.  THEY ARE CALLED
;  BASED ON THE CURRENT STATE OF THE DUP11.
;
; R0 = MODEM STATUS FLAGS, FROM THE DUP11.
;
; HERE IF WE ARE WAITING TO START THE TRANSMITTER
;
15$:	BIT	#UP.CTS,R0	;HAVE WE CLEAR-TO-SEND?
	BEQ	16$		;NO, WAIT FOR IT.
	BIC	#LS.XGO,(R4)	;NO LONGER WAITING TO START TRANSMITTER
	BIS	#LS.XRN,(R4)	;NOW RUNNING TRANSMITTER
	BIS	#UP.SND!UP.XIE,UP.XSR(R3) ;START THE TRANSMITTER
	MOV	#UP.XSM!EBCPAD,UP.XBF(R3) ;START OF MESSAGE
16$:	RTS	PC		;ALL DONE.
;
; HERE IF WE ARE RUNNING THE TRANSMITTER
;
17$:	BIT	#UP.CTS,R0	;IS CLEAR-TO-SEND STILL UP?
	BNE	18$		;YES, ALL OK.
	INC	LB.SE6(R4)	;NO, NOTE CLEAR-TO-SEND FAILURE
	JSR	PC,DQERRR	;NOTE ERROR
	JSR	PC,XMTSTP	;STOP THE TRANSMITTER
18$:	RTS	PC		;ALL DONE.
;
; HERE IF WE ARE WAITING TO START THE RECEIVER
;
19$:	BIT	#UP.CAR,R0	;IS CARRIER UP YET?
	BEQ	20$		;NO, KEEP WAITING FOR IT.
	BIS	#UP.RIE!UP.REN,UP.RSR(R3) ;YES, START THE RECEIVER
	BIC	#LS.RGO,(R4)	;NO LONGER WAITING TO START RECEIVER
	BIS	#LS.RRN,(R4)	;NOW RUNNING RECEIVER
20$:	RTS	PC		;ALL DONE.
;
; HERE IF THE RECEIVER IS RUNNING.
;
21$:	BIT	#UP.CAR,R0	;IS CARRIER UP?
	BNE	22$		;YES.
	BIT	#LS.CAR,(R4)	;NO, HAVE WE SEEN CARRIER YET?
	BEQ	23$		;NO, DONT WORRY ABOUT IT.
	JSR	PC,RCVSTP	;YES, STOP THE RECEIVER
	BR	23$		;ALL DONE.
;
; HERE IF CARRIER IS UP
;
22$:	BIS	#LS.CAR,(R4)	;MARK WE HAVE SEEN CARRIER
23$:	RTS	PC		;RETURN.
;
;
; SUBROUTINE TO SEE IF THE DUP11 HAS READ ANY CHARACTERS
;  RECENTLY.
;
; R5 POINTS TO THE TCB, WHICH MUST HAVE EBWAIT SET.
;  R4 AND R3 ARE NOT SET UP AND MUST BE PRESERVED.
;
; ON RETURN:
;
;	C SET: RCVSCC HAS FOUND CHARACTERS IN THE DUP11
;		(NOT POSSIBLE IN THIS VERSION)
;	C CLEAR: THE DUP11 HAS NO CHARACTERS.  IT IS NOW
;		SET TO RESTART THE BSC TASK ON THE NEXT CHARACTER.
;
DQINWQ:	MOV	R4,-(SP)	;SAVE R4
	MOV	R3,-(SP)	; AND R3
	MOV	TCLCB(R5),R4	;POINT TO LCB
	MOV	LB.SLA(R4),R3	;POINT TO DUP11 CSR
	MFPS	-(SP)		;SAVE INTERRUPT LEVEL
	MTPS	#BR7		;DISABLE INTERRUPTS
	BIS	#LS.CIE,(R4)	;FLAG AWAKEN THE BSC TASK ON NEXT CHAR
	MTPS	(SP)+		;RESTORE INTERRUPT LEVEL
	MOV	(SP)+,R3	;RESTORE R3
	MOV	(SP)+,R4	;RESTORE R4
	CLC			;FLAG NO CHARACTERS
	RTS	PC		;RETURN.
;
;
; SUBROUTINE TO KILL ANY DUP11 OPERATIONS.  
;
; R4 = LCB POINTER
; R5 = POINTER TO BSC TCB
;
; DESTROYS R0, R1 AND R3
;
DQKILL:	TRACE	TRCDQF,R4	;TRACE ENTRY TO DQKILL
	MOV	LB.SLA(R4),R3	;POINT TO CSR
	MFPS	-(SP)		;SAVE INTERRUPT LEVEL
	MTPS	#BR7		;DISABLE INTERRUPTS
	BIT	#LS.ACT,(R4)	;IS THE DUP11 DOING ANYTHING?
	BEQ	12$		;NO.
;
; CONSIDER STOPPING THE TRANSMITTER
;
	BIT	#LS.XGO!LS.XRN,(R4) ;YES, TRANSMITTER RUNNING?
	BEQ	11$		;NO.
	MOV	#EBINTR!EBTIME!EBWAIT,(R5) ;YES, SET UP FOR XMIT STOP
	ADD	#JIFSEC,TCTIM(R5) ;BE SURE TO WAIT AT LEASE ONE SEC
	JSR	PC,XMTSTP	;BEGIN STOPPING THE TRANSMITTER
	MTPS	(SP)+		;ENABLE INTERRUPTS
	MOV	R2,-(SP)	;SAVE R2
	MOV	R4,-(SP)	; AND R4 [1(717)]
	JSR	PC,WAIT		;WAIT FOR TRANSMITTER TO STOP
				; (OR FOR SOME TIME TO PASS)
	MOV	(SP)+,R4	;RESTORE R4 [1(717)]
	MOV	(SP)+,R2	;RESTORE R2
	MOV	LB.SLA(R4),R3	;RESTORE R3 [1(717)]
	MFPS	-(SP)		;SAVE INTERRUPT LEVEL
	MTPS	#BR7		;DISABLE INTERRUPTS
;
;			; CONTINUED ON NEXT PAGE
;
;
; CONSIDER STOPPING THE RECEIVER
;
11$:	BIT	#LS.RGO!LS.RRN,(R4) ;IS RECEIVER RUNNING?
	BEQ	12$		;NO.
	JSR	PC,RCVSTP	;YES, STOP THE RECEIVER
12$:	BIC	#UP.DIE,UP.RSR(R3) ;CLEAR DATASET INTERRUPT ENBALE
	MTPS	(SP)+		;RESTORE INTERRUPTS
13$:	JSR	PC,DEQCHK	;ANY CHUNKS IN RECEIVER QUEUE?
	BCS	14$		;NO.
	MOV	TCIDLE,R1	;YES, FREE THEM
	JSR	PC,QUECHK	; BY SENDING TO BACKGROUND TASK
	BR	13$		;BE SURE WE'VE GOT THEM ALL.
;
; HERE WHEN THE DUP11 HAS BEEN KILLED.
;
14$:	BIT	#LS.ACT,(R4)	;IS THE DUP11 REALLY DEAD?
	BEQ	15$		;YES.
	MOV	UP.RSR(R3),R1	;NO, GET DATASET BITS
	JSR	PC,DQINIT	;REALLY ZAP THE DUP11
	BIC	#^C<UP.DTR>,R1	;SAVE ONLY DTR
	BIS	R1,UP.RSR(R3)	;PUT BACK DTR
	BIC	#LS.ACT,(R4)	;THE DUP11 IS NO LONGER ACTIVE
15$:	RTS	PC		;RETURN.
;
;
; THREE SUBROUTINES TO INTERFACE TO THE DL10 TASK.  THESE SENSE
;  SET AND CLEAR THE MODEM SIGNALS DTR AND DSR.
;
; SUBROUTINE TO CLEAR DTR
;
; R0 = LCB ADDRESS
;
DQDTR0:	MOV	LB.SLA(R0),R0	;POINT TO CSR
	BIC	#UP.DTR,UP.RSR(R0) ;CLEAR DTR
	RTS	PC		;RETURN.
;
; SUBROUTINE TO SET DTR
;
DQDTR1:	MOV	LB.SLA(R0),R0	;POINT TO CSR
	BIS	#UP.DTR,UP.RSR(R0) ;SET DTR
	RTS	PC		;RETURN.
;
; SUBROUTINE TO RETURN VALUES OF DTR AND DSR.
;
; R0 = LCB ADDRESS
; R1 BITS 1 AND 2 ARE 0.
;
; ON RETURN:
;
;	BIT 1 OF R1 = DTR
;	BIT 2 OF R1 = DSR
;	 R1 IS OTHERWISE UNDISTURBED.
;
DQMDMS:	MOV	LB.SLA(R0),R0	;POINT TO CSR
	BIT	#UP.DTR,UP.RSR(R0) ;IS DTR SET?
	BEQ	11$		;NO.
	BIS	#B1,R1		;YES, SET FLAG IN R1
11$:	BIT	#UP.DSR,UP.RSR(R0) ;IS DSR SET?
	BEQ	12$		;NO.
	BIS	#B2,R1		;YES, SET FLAG IN R1
12$:	RTS	PC		;RETURN.
;
;
; SUBROUTINE TO INTERFACE WITH THE TRAP HANDLER.  ON A STOP CODE
;  THIS SUBROUTINE IS CALLED TO STORE THE STATUS OF THE DUP11
;  IN THE LCB FOR POST-MORTUM DEBUGGING.
;  R5 DOES NOT POINT TO A TCB, BUT IT MUST NOT BE DESTROYED.
;
; R4 = LCB ADDRESS
;
.IF NE,DEBUG
TRAPDQ:	MOV	LB.SLA(R4),R3	;GET HARDWARE ADDRESS
	MOV	UP.RSR(R3),LB.RG0(R4) ;STORE RECEIVER STATUS REGISTER
	MOV	UP.RBF(R3),LB.RG1(R4) ;STORE RECEIVER BUFFER
	MOV	UP.XSR(R3),LB.RG2(R4) ;STORE TRANSMIT STATUS REGISTER
	MOV	UP.XBF(R3),LB.RG3(R4) ;STORE TRANSMIT BUFFER
	RTS	PC		;RETURN.
;
.ENDC ;.IF NE,DEBUG
;
;
; SUBROUTINE TO CHECK ON THE DUP11S ONCE A JIFFIE
;  WE MUST COUNT THE CLEAR-TO-SEND DELAY AND
;  COMPENSATE FOR IMPROPER DUP11 JUMPERS WHICH
;  WILL PREVENT THE CARRIER SIGNAL FROM CAUSING
;  AN INTERRUPT.
;
DSPDQT:	MOV	R0,-(SP)	;SAVE R0
	MOV	R1,-(SP)	; AND R1
	MOV	R2,-(SP)	; AND R2
	MOV	R3,-(SP)	; AND R3
	MOV	R4,-(SP)	; AND R4
	CLR	R1		;R1 IS DUP11 NUMBER
11$:	MOV	DQLCB(R1),R4	;POINT TO LCB
	BEQ	15$		;NO LCB FOR THIS LINE
	MFPS	-(SP)		;YES, SAVE INTERRUPT LEVEL
	MTPS	#BR7		;DISABLE INTERRUPTS
	TST	LB.DEW(R4)	;WAITING TO SET MODEM ENABLE?
	BEQ	12$		;NO.
	DEC	LB.DEW(R4)	;YES, WAITED LONG ENOUGH?
	BNE	14$		;NO, WAIT UNTIL NEXT TIME
12$:	MOV	LB.SLA(R4),R3	;POINT TO CSR
	MOV	UP.RSR(R3),R0	;GET MODEM STATUS BITS
	BIT	#UP.DIE,R0	;ARE MODEM INTERRUPTS ENABLED?
	BEQ	14$		;NO, DONT CALL SUBROUTINE.
	BIT	#UP.DCA!UP.DCB,R0 ;ARE DATASET CHANGE FLAGS SET?
	BNE	13$		;YES, PROCESS ANY POSSIBLE CHANGES
	MOV	LB.DIP(R4),R2	;GET LAST MODEM SIGNALS PROCESSED
	XOR	R0,R2		;CHECK FOR ANY CHANGES IN SIGNALS
	BIT	#UP.CTS!UP.CAR,R2 ;ANY IMPORTANT MODEM SIGNALS CHANGED?
	BEQ	14$		;NO.
13$:	JSR	PC,RCVDSF	;YES, PROCESS ANY MODEM SIGNAL CHANGES
14$:	MTPS	(SP)+		;RESTORE INTERRUPT LEVEL
15$:	ADD	#2,R1		;INCREMENT TO NEXT LINE
	CMP	#NLINES*2,R1	;DONE ALL THE LINES?
	BNE	11$		;NO, DO THE REST
	MOV	(SP)+,R4	;YES, RESTORE R4
	MOV	(SP)+,R3	; AND R3
	MOV	(SP)+,R2	; AND R2
	MOV	(SP)+,R1	; AND R1
	MOV	(SP)+,R0	; AND R0
	RTS	PC		;RETURN TO DISPATCHER.
;
.SBTTL	CONTROL MESSAGES
;
; CONTROL MESSAGES
;
;
; ENQ MESSAGE, FOR BIDDING FOR THE LINE AND ASKING FOR A
;  REPEAT OF THE LAST RESPONSE.
;
ENQMSG:	.BYTE	EBCLPD,EBCSYN,EBCSYN
	.BYTE	EBCSYN,EBCENQ,EBCPAD
ENQLEN=.-ENQMSG
;
; ACK-0 MESSAGE, USED FOR POSITIVE ACKNOWLEDGMENT TO BID AND
;  FOR POSITIVE ACKNOWLEDGE OF EVEN DATA BLOCKS
;
AK0MSG:	.BYTE	EBCLPD,EBCSYN,EBCSYN
	.BYTE	EBCSYN,EBCDLE,EBCAK0
	.BYTE	EBCPAD
AK0LEN=.-AK0MSG
;
; ACK-1 MESSAGE, USED FOR POSITIVE ACKNOWLEDGMENT OF ODD DATA
;  BLOCKS
;
AK1MSG:	.BYTE	EBCLPD,EBCSYN,EBCSYN
	.BYTE	EBCSYN,EBCDLE,EBCAK1
	.BYTE	EBCPAD
AK1LEN=.-AK1MSG
;
; TTD MESSAGE, FOR SOLICITING A NAK BECAUSE DATA IS NOT
;  YET READY.
;
TTDMSG:	.BYTE	EBCLPD,EBCSYN,EBCSYN
	.BYTE	EBCSYN,EBCSTX,EBCENQ
	.BYTE	EBCPAD
TTDLEN=.-TTDMSG
;
;
; HASP BID SEQUENCE SOH-ENQ FOR BIDDING FOR A LINE.
;
BIDMSG:	.BYTE	EBCLPD,EBCSYN,EBCSYN
	.BYTE	EBCSYN,EBCSOH,EBCENQ
	.BYTE	EBCPAD
BIDLEN=.-BIDMSG
;
; EOT MESSAGE, USED TO TERMINATE A MESSAGE SEQUENCE.
;
EOTMSG:	.BYTE	EBCLPD,EBCSYN,EBCSYN
	.BYTE	EBCSYN,EBCSYN,EBCEOT
	.BYTE	EBCPAD,EBCPAD
EOTLEN=.-EOTMSG
;
; NAK MESSAGE, USED TO REQUEST THE RETRANSMISSION OF THE LAST
;  DATA MESSAGE AND TO REFUSE A BID.
;
NAKMSG:	.BYTE	EBCLPD,EBCSYN,EBCSYN
	.BYTE	EBCSYN,EBCNAK,EBCPAD
NAKLEN=.-NAKMSG
;
; WACK MESSAGE, USED TO ACKNOWLEDGE A DATA BLOCK BUT FORCE A WAIT
;  BEFORE THE NEXT DATA BLOCK IS SENT.
;
WAKMSG:	.BYTE	EBCLPD,EBCSYN,EBCSYN
	.BYTE	EBCSYN,EBCDLE,EBCWAK
	.BYTE	EBCPAD
WAKLEN=.-WAKMSG
;
	.EVEN		;BE SURE NEXT SECTION STARTS ON
			; A WORD BOUNDRY.
;