	.TITLE	MBTST1
	.ENABL	GBL
	.NLIST	BEX
	.ENABL	LC
;
;+
;*****
;
;	MBTST1 - CHECKS OUT SIMPLE DIALOGUE WITH MB: DRIVER...TALKS TO
;	 ITSELF VIA DEFAULT QUEUE NAMED FOR TASK NAME
;
;*****
;-
TI$EFN==1
TI$LUN==1
MB$EFN==2
MB$LUN==2
;
	.MCALL	EXST$S,QIOW$S,ALUN$S,ASTX$S,QIO$S
	.mcall	MBIO$
	MBIO$
;
	.PSECT	$IDATA,RW,D,LCL,CON,REL
;
IDAT:			; INPUT DATA ARRAY
	.BLKW	8192.		; MAKE SURE IT WRAPS OVER 4KW BOUND TO CHECK
				;  $BLXIO FUNCTIONING
	L.IDAT=.-IDAT
ODAT:			; OUTPUT DATA ARRAY
	.BLKW	8192.
	L.ODAT=.-ODAT
ISB:			; INPUT I/O STATUS BLOCK
	.BLKW	2
OSB:			; OUTPUT I/O STATUS BLOCK
	.BLKW	2
;
M0:
	.ASCII	/Start debugging MB: driver/
	L.M0=.-M0
M1:
	.ASCII	/Attempt to access queue for read-AST and write/
	L.M1=.-m1
M2:
	.ASCII	/Received data from /
M2TNAM:
	.BLKB	6			; space for sender's task name
	.BYTE	12,15			; vertical format
M2DATA:
	.BLKB	78.
	L.M2D=.-M2DATA
	L.M2=.-M2
;
	.EVEN
;
	.PSECT	$PCODE,RO,I,LCL,CON,REL
;
MBTST1::
	ALUN$S	#TI$LUN,#"TI,#0	; ASSIGN LUN TO TI:
	ALUN$S	#MB$LUN,#"MB,#0	; ASSIGN LUN TO MB:
	BCC	S0
	CALL	DSWSTA		; show directive status
	JMP	END		; and quit
;
s0::
	QIOW$S	#IO.WLB,#TI$LUN,#TI$EFN,,,,<#M0,#L.M0,#40>
	MOV	#ODAT,R0	; GET OUTPUT DATA ARRAY
	MOV	#L.ODAT,R2
	MOV	#41,R1		; INIT ARRAY WITH BYTE CHARACTERS
6$:
	MOVB	R1,(R0)+
	INC	R1
	CMPB	R1,#176
	BLOS	10$
	MOV	#41,R1		; RE-INIT PATTERN
10$:
	SOB	R2,6$
;
; *** 1ST QIO TO MAILBOX SHOULD FAIL WITH "DEVICE NOT ATTACHED" = -7.
;	 WHICH SHOULD HAPPEN IMMEDIATELY, OR TEST WILL HANG IF IT DOESN'T
;
S1::
	QIOW$S	#IO.WLB,#MB$LUN,#MB$EFN,,#OSB,#MBWAST,<#ODAT,#L.ODAT>
;
; *** NEXT TRY TO ATTACH WITH READ AND WRITE AND UNSOLICITED INPUT AST...
;	SHOULD COMPLETE WITH "IS.CLR" = 0. INDICATING NEW QUEUE CREATED
;
S2::
	QIOW$S	#IO.WLB,#TI$LUN,#TI$EFN,,,,<#M1,#L.M1,#40>
	MOV	#OSB,R0		; use output status block
	QIOW$S	#IO.ARA,#MB$LUN,#MB$EFN,,R0,,<#MBATA,#4>
	CALL	IOSTA		; display status
	TSTB	(R0)		; check status
	BPL	5$		; BRANCH IF WORKED
	JMP	END		; quit if it fails
5$:
	QIOW$S	#IO.AWR,#MB$LUN,#MB$EFN,,R0,,<#MBATA,#4>
	CALL	IOSTA		; display status
	TSTB	(R0)		; check status
	BPL	10$		; BRANCH IF WORKED
	JMP	END		; quit if it fails
10$:
;
; *** NOW TRY TO READ WITH SF.NOW QUALIFIER...SHOULD COMPLETE IMMEDIATELY
;	 WITH "DEVICE NOT READY" = -3.
;
S3::
	QIOW$S	#IO.RLB!SF.NOW,#MB$LUN,#MB$EFN,,#ISB,#MBRAST,<#IDAT,#L.IDAT>
	TSTB	ISB		; CHECK STATUS
	BMI	S4		; CONTINUE IF FAILS
	JMP	END		; QUIT IF IT WORKS
;
; *** WRITE 5 MESSAGES TO QUEUE WITH VARYING BYTE COUNTS...FIFTH MESSAGE
;	 SHOULD FAIL WITH "DEVICE FULL" = -24. BECAUSE QUEUE DEPTH WAS
;	 SET TO 4.
;
S4::
	MOV	#5,R5		; SET LOOP COUNT
	MOV	#1024.,R4	; WRITE 1K,2K,3K,4K MESSAGE BLOCKS
	MOV	#ODAT,R3	; SET START ADDRESS
3$:
	QIO$S	#IO.WLB,#MB$LUN,,,#OSB,#MBWAST,<R3,R4>
	ADD	#1024.,R4	; STEP TO NEXT MESSAGE SIZE
	ADD	#40,R3		; STEP INTO OUTPUT ARRAY
	SOB	R5,3$
;
; *** FINALLY, EMPTY QUEUE DISPLAYING PARTIAL MESSAGE CONTENTS TO TI:
;
S5::
	QIOW$S	#IO.RLB!SF.NOW,#MB$LUN,#MB$EFN,,#ISB,#MBRAST,<#IDAT,#L.IDAT>
	CMPB	#IS.SUC,ISB	; SUCCESS ??
	BNE	S6		; BRANCH IF NO...TO NEXT TEST
	MOV	ISB+2,R5	; GET BYTE COUNT READ
	SUB	#4,R5		; ADJUST FOR TASK NAME
	BGT	8$		; BRANCH ON GOOD COUNT
	JMP	END		; BRANCH IF BAD COUNT
8$:
	MOV	#IDAT,R4	; GET POINTER TO DATA
	MOV	#M2TNAM,R0	; GET PLACE FOR TASK NAME
	MOV	(R4)+,R1	; GET 1ST HALF OF NAME
	CALL	$C5TA		; CONVERT TO ASCII
	MOV	(R4)+,R1	; GET 2ND HALF OF NAME
	CALL	$C5TA		; CONVERT TO ASCII
	MOV	#M2DATA,R0	; STEP TO DATA PORTION OF MESSAGE
	MOV	#L.M2D,R3	; GET # BYTES IN MESSAGE
	CMP	R5,R3		; CHECK RCVD AGAINST MSG
	BLOS	20$		; BRANCH IF DISPLAY ALL RCVD
	MOV	R3,R5		; ELSE, TRUNCATE RCVD COUNT
20$:
	MOVB	(R4)+,(R0)+	; COPY DATA TO MESSAGE BLOCK
	SOB	R5,20$
	MOV	#M2,R1		; PICKUP MESSAGE START ADDRESS
	SUB	R1,R0		; COMPUTE BYTE COUNT		
	QIOW$S	#IO.WLB,#TI$LUN,#TI$EFN,,,,<R1,R0,#40> ; SEND TO TI:
	BR	S5		; LOOP TIL DONE
;
; *** CHECK ABILITY TO REJECT PENDING QIOS IN WRITE LIST
;
S6::
	QIO$S	#IO.WLB,#MB$LUN,,,#OSB,#MBWAST,<#ODAT,#1024.>
				; SETUP QIO TO BE KILLED, SHOULD ENTER MBWAST
	QIOW$S	#IO.REJ,#MB$LUN,#MB$EFN,,,,<#IE.CNR>
				; REJECT QIO
	QIO$S	#IO.RLB,#MB$LUN,,,#ISB,#MBRAST,<#IDAT,#L.IDAT>
				; SETUP READ QIO TO BE KILLED
	QIOW$S	#IO.REJ,#MB$LUN,#MB$EFN,,,,<#IE.CNR>
				; REJECT QIO...SHOULDN'T WORK ON READS
	QIOW$S	#IO.ABO,#MB$LUN,#MB$EFN,,,,<>
				; BUT ABORT SHOULD WORK
END:
	QIO$S	#IO.WLB,#MB$LUN,,,#OSB,#MBWAST,<#ODAT,#1024.>
				; SETUP QIO TO BE KILLED
	MOV	#ISB,R0		; SETUP STATUS BLOCK ADDRESS
	QIOW$S	#IO.DAA,#MB$LUN,#MB$EFN,,R0,,<> ; DETACH FROM ALL MAILBOXES
	CALL	IOSTA
	EXST$S	#EX$SUC		; EXIT SHOULD RE-ENTER DRIVER TO CANCEL I/O
				;  BUT WON'T DETACH FROM QUEUE !!!!!!
;
	.PAGE
	.sbttl	MBDRV Read QIO AST routines
;
; *** MBRAST - Displays I/O completion status of read-QIO
;

	.psect	$idata,rw,d,lcl,con,rel

ATRM1:
	.ascii	/Read-QIO completion AST/
	L.ATR1=.-ATRM1
	.even

	.psect	$pcode,ro,i,lcl,con,rel
;
MBRAST::			; *** Write QIO AST Service Routine	
	MOV	R1,-(SP)	; save R1
	MOV	2(SP),R1	; pickup I/O status block address
	MOV	R0,2(SP)	; free R0-R2
	MOV	R2,-(SP)
	QIOW$S	#IO.WLB,#TI$LUN,#TI$EFN,,,,<#ATRM1,#L.ATR1,#40>
	MOV	R1,R0		; replicate I/O status address
	CALL	IOSTA		; display status
	MOV	(SP)+,R2	; restore R0-R2
	MOV	(SP)+,R1
	MOV	(SP)+,R0
	ASTX$S			; exit AST
;
	.page
	.sbttl	MBDRV Write QIO AST routines
;
; *** MBWAST - Displays I/O completion status of write-QIO
;

	.psect	$idata,rw,d,lcl,con,rel

ATWM1:
	.ascii	/Write-QIO completion AST/
	L.ATW1=.-ATWM1
	.even

	.psect	$pcode,ro,i,lcl,con,rel
;
MBWAST::			; *** Write QIO AST Service Routine	
	MOV	R1,-(SP)	; save R1
	MOV	2(SP),R1	; pickup I/O status block address
	MOV	R0,2(SP)	; free R0-R2
	MOV	R2,-(SP)
	QIOW$S	#IO.WLB,#TI$LUN,#TI$EFN,,,,<#ATWM1,#L.ATW1,#40>
	MOV	R1,R0		; replicate I/O status address
	CALL	IOSTA		; display status
	MOV	(SP)+,R2	; restore R0-R2
	MOV	(SP)+,R1
	MOV	(SP)+,R0
	ASTX$S			; exit AST
;
	.page
	.sbttl	MBDRV Unsolicited input handler
;
; *** MBATA - Unsolicited input AST from Mailbox;  echo sender's name and
;	 message byte count
;
	.PSECT	$IDATA,RW,D,LCL,CON,REL
ATATMP:
	.BLKW	3			; AST temporary storage
ATAM1:
	.ASCII	<15>/Unsolicited input from /
ATNAM:	.BLKB	6			; place for sender's task name
	.ASCII	/; byte count = /
ATCNT:	.BLKB	7			; place for unsigned input data
	L.ATM1=.-ATAM1
	.EVEN
;
	.PSECT	$PCODE,RO,I,LCL,CON,REL
MBATA::			; ATTENTION AST
	MOV	(SP)+,ATATMP	; copy byte count
	MOV	(SP)+,ATATMP+2	; pop 1st half of name
	MOV	(SP),ATATMP+4	; pop 2nd half of name
	MOV	R0,(SP)		; free R0-R2
	MOV	R1,-(SP)
	MOV	R2,-(SP)
	MOV	#ATNAM,R0	; get place for ASCII task name
	MOV	ATATMP+2,R1	; get name
	CALL	$C5TA		; convert it to ascii
	MOV	ATATMP+4,R1	; get 2nd half of name
	CALL	$C5TA		; convert it to ascii
	MOV	#ATCNT,R0	; get place for byte count
	MOV	ATATMP,R1	; get byte count
	CLR	R2		; enable 0 suppression
	CALL	$CBDMG		; convert to decimal
	MOVB	#'.,(r0)	; show decimal radix
	MOV	#ATAM1,R1	; get start address of message
	SUB	R1,R0		; compute byte count
	QIOW$S	#IO.WLB,#TI$LUN,#TI$EFN,,,,<R1,R0,#40>
	MOV	(SP)+,R2	; recover registers
	MOV	(SP)+,R1
	MOV	(SP)+,R0
	ASTX$S
;
	.page
	.sbttl	Information Message Format Routines
;
; *** DSWSTA - Prints contents of directive status word to TI:
;
;	R0-R2 destroyed !!
;
	.PSECT	$IDATA,RW,D,LCL,CON,REL
DSWMSG:
	.ASCII	/Directive status = /
ADSW:	.BLKB	8.
	.EVEN
;
	.PSECT	$PCODE,RO,I,LCL,CON,REL
;
DSWSTA::
	MOV	#ADSW,R0		; get place for dsw string
	MOV	@#$DSW,R1		; get directive status word
	CLR	R2			; enable 0 suppression
	CALL	$CBDSG			; convert it decimal
	MOVB	#'.,(R0)+		; insert radix indicator
	MOV	#DSWMSG,R1		; get message start address
	SUB	R1,R0			; compute string length
	QIOW$S	#IO.WLB,#TI$LUN,#TI$EFN,,,,<R1,R0,#40>
	RETURN
;
; *** IOSTA - Reports state of I/O status block pointed to by R0.
;
;	R0-R2 destroyed !!
;
	.PSECT	$IDATA,RW,D,LCL,CON,REL
;
IOSMSG:
	.ASCII	&I/O Status Block = &
AIOSB:	.BLKB	20.
	.EVEN
;
	.PSECT	$PCODE,RO,I,LCL,CON,REL
;
IOSTA::
	MOV	R0,-(SP)		; save I/O status block address
	MOVB	(R0),R1			; pickup status byte
	MOV	#AIOSB,R0		; get place to build string
	CLR	R2			; enable 0 suppression
	CALL	$CBDSG			; convert it decimal
	MOVB	#'.,(R0)+		; insert radix indicator
	MOVB	#40,(R0)+		; insert delimiter
	MOVB	#40,(R0)+
	MOV	(SP),R1			; pickup status block address
	MOVB	1(R1),R1		; get top byte of 1st word
	MOV	PC,R2			; disable 0 suppression
	CALL	$CBTMG			; convert to unsigned octal
	MOVB	#40,(R0)+		; insert delimiter
	MOVB	#40,(R0)+
	MOV	(SP),R1			; pickup status block again
	MOV	2(R1),R1		; get 2nd word	
	MOV	PC,R2			; disable 0 suppression
	CALL	$CBOMG			; convert to unsigned octal
	MOV	#IOSMSG,R1		; get message start address
	SUB	R1,R0			; compute string length
	QIOW$S	#IO.WLB,#TI$LUN,#TI$EFN,,,,<R1,R0,#40>
	MOV	(SP)+,R0		; recover status block addr
	RETURN

	.END	MBTST1

