	.title	'Tape test Utility - '
	.sbttl	'TESTCART'
version	==	1
revision==	4
patch	==	'b'
	.pabs
	.phex
	.loc	100h
	JMP	START
;----------
; Harddisk Backup Utility to tape
;
; Written by David Stein,   Aug  1981
;
; 	This program is a streaming tape exercizer.
;A 512 byte block is generated in memory in one of
;3 patterns: linear,random, & fixed.
;This block is written to the tape consecutively
;for 'TAPxfr' number of times.The first two bytes
;of each block is labeled with a two byte number
;for counting/individualizing each block.  A file
;mark is then put on the tape and the blocks are read
;back in. The block pattern is changed, and then the
;process is repeated ad nauseam.
; 	The program contains a timer which lets the 
;program run and rest for a specified number of 
;minutes.
;	The program also contains a write-status-bytes-
;to-buffer option (defaulted on).  This option will 
;load the status bytes up into high memory when ever
;the status bytes are displayed to the console. See
;prtRSTAT and prtWSTAT for the code.
;	This program has been designed to be as 
;flexible as possible.  Most important variables can
;be found/modified in the patch area.  This allows
;technicians to modify and customize the program to
;a great extent without needing the source code you
;are reading now.  A '-D100' from DDT will display
;out the patch area complete with ASCII labels.  (An-
;other 'D' will display the rest of the patch area.)
;
; Error Detection
; A message is printed if:
;
;  A file mark is found too early or not at all.
;	Message: 	File mark not found
;		 	File mare found early
;	Aftermath:	Test continues.
;
;  A byte in the read buffer is different from the
;   block pattern that was written.
;	Message: EXXXXh where XXXXh is offset into the
;			buffer of the compare error.
;	Aftermath:	Test continues.
;
;  If the EXECPTION line is raised after a read or
;   write command, and the error is not expected.
;   (i.e. If error is not a detected file mark.)
;	Message: ***Unrecoverable Read/Write error:
;	         	(Archive error message)
;	Aftermath:	Loop is then restarted.

; Update histoire

; 1.0	(08/15/81)  Initial version
; 1.1	(08/24/81)  Cleaned-up 1.0 
; 1.2	(08/26/81)  Installed time on/off duty
;		     cycle.
; 1.4   (09/03/81)  Installed write-status-bytes-to-
;		    buffer option.
.page
; Important constants

cr	==	0Dh	; carriage return
lf	==	0Ah	; linefeed
ctrlC	==	03h	; abort
ctrlH	==	08h	; backspace
del	==	07Fh	; delete
DMA	==	38h	; DMA data port
PIOAD	==	08h	; PIO channel A, data
PIOBD	==	09h	; PIO channel B, data
HARD	==	01h	; hard disk data port
TAPE	==	02h	; cassette tape port
STROBE	==	00h	; strobe for tape status
BDOS	==	5	; address of BDOS call
BIOStim	==	41h	; Start of BIOS maintained time

DEBUG	=	0
.page
; Vital statistic storage area.
; From DDT enter: -D100
;----------

; Tape status bytes - See archive manual
	.ascii	'TP STAT'
TPstat:	.byte	0FFh,0FFh,0FFh,0FFh,0FFh,0FFh

; Test loops completed
	.ascii	'LOOPS COMPLETE:'
loopcnt:.byte	00h	; number of loops completed

; Read/write error counters
	.ascii	'   READ ERRORS:'
rdERRcnt:
	.byte	0
	.ascii	'  WRITE ERRORS:'
wrERRcnt:
	.byte	0

; File mark error counter
	.ascii	'FILE MARK ERRS:'
fmERRcnt:
	.byte	0
; Number of blocks to transfer to and from tape drive
	.ascii	'# OF I/O BLKS:'
TAPxfr:	.word	9000h	;defaulted to 9000h blocks

; Number of blocks currently read or written.
	.ascii	'CURRENT BLOCK:'
curblk:	.word	0000h

; 512 byte Read buffer location
	.ascii	'READ BUF ADDR:'
RDbuff:	.word	2300h

; 512 byte Write buffer location
	.ascii	'WRITE BUF ADR:'
WRbuff:	.word	2000h

; Fixed pattern byte for fixed pattern testing
	.ascii	'FIXED PAT BYTE:'
fixbyt:	.byte	0A5h

; Number of minutes for test to be running
	.ascii	'  MINS TO  RUN:'
RUNmin:	.byte	30
; Number of minutes inbetween testing 
	.ascii	'  MINS TO REST:'
RESTmin:.byte	30
; Time for test to change from one mode to another
	.ascii	'TRIG TIM SMH:'
TRIGtim:.byte	0,0,0
; Flag to set for writing status bytes to the buffer
	.ascii	'BUF FLG  0=OFF:'
BUFflg:	.byte	0FFh
; Start of stat-byte-write buffer
	.ascii	'STAT BUF STRT:'
STATbuf:.word	3000h
; Maximum allowed buffer addr
	.ascii	' TOP MEM PNTR:'
TOPmem:	.word	0C000h		; just under CCP
; Current stat buffer addr
	.ascii	'CUR BUFF ADDR:'
bufaddr:.word	0000h
.page
START:
;----------
; Set the stack
	ei
	lxi	SP,stack

; Setup DMA vector at base of BIOS
	lhld	1
	mvi	L,0
	mvi	M,DMAdone&0FFh
	inx	H
	mvi	M,(DMAdone>8)&0FFh
; Ask user what he/she wants to do
SELASK:
	lxi	H,hello$
	call	prtmsg	; greet the user
	lxi	H,info$
	call	prtmsg	; more greetings
	lxi	H,select$
	call	PRTMSG	; print out options
..ask:	call	CONIN
	cpi	'B'	; check for BOOT
	jrz 	BOOT 
	cpi	'D'	; check for DDT
	jrz	DDT	; 
	cpi	'T'	; START TAPE TEST
	jrz	TSTSTART
	cpi	'R'	; check for resume
	jz	TEST	; resume test--dont initialize
	lxi	H,error$; Bad entry. Inform user
	call	PRTMSG	; and ask again.
	jmpr	..ask
.page
BOOT:	jmp	0	; JUMP to WARM BOOT
DDT:	RST	6	; JUMP INTO DDT
;----------
; Initialize buffers, counters, timers
TSTSTART:
	call	MNTWRT	; mount a writeable tape
	lxi	H,strtmsg
	call	prtmsg
	call	waitCR	; wait for CR to start
;Status-byte-holder buffer initialization
	lhld	TOPmem	; TOP of memory addr
	lbcd	STATbuf	; Start of buffer addr
	ora	A
	dsbc	B	; Subtract the two
	mov	B,H
	mov	C,L	; BC = length of stat buffer
	lhld	STATbuf
	shld	bufaddr	; initialize status write-buf
	mov	D,H
	mov	E,L	; HL=start of stat buffer
	inx	D	; DE=2nd byte in stat buffer
	mvi	M,0FFh
	LDIR		; fill stat buffer with FF's
; Initialize error counters to 0
	lxi	H,rdERRcnt
	mvi	M,0
	lxi	H,wrERRcnt
	mvi	M,0
	lxi	H,fmERRcnt
	mvi	M,0
;Set the length time the test will run (before resting)
	lda	RUNmin	; num of minutes to run
	call	calcTIM	; make it a time in HMS
;--------------------------------------------------
;               Infinite Command Loop
;--------------------------------------------------
TEST:	lxi	sp,stack; start with a fresh stack

	lxi	H,LINmsg
	call	prtmsg
	call	makLINbuf  ; Make a linear write buffer
	call	TSTLOOP	   ; Write,Read and test

	call	compTIM	; is it time to rest?
	cz	REST	; Yes.

	lxi	H,RANmsg
	call	prtmsg
	call	makRANbuf  ; Make a random write buffer
	call	TSTLOOP	   ; Write,Read and test

	call	compTIM	; is it time to rest?
	cz	REST	; Yes.

	lxi	H,FIXmsg
	call	prtmsg
	call	makFIXbuf  ; Make a fixed write buffer
	call	TSTLOOP	   ; Write,Read and test

;Increment and report loopcount
	lxi	H,loopmsg
	call	prtmsg	; print "loops completed:"
	lxi	H,loopcnt ; Load loop counter and
	inr	M	  ; increment it
	mov	A,M	  ; and
	call	prtbyt	; display it to the console.

	call	compTIM	; is it time to rest?
	cz	REST	; yes. Rest.
	JMP	TEST	; Loop ad nauseum

;----------
; Subroutine:   REST
;
; CompTIM has set the zero flag indicating that
;the test has run for its specified length of time.
;We will now enter the REST phase, where the test
;will be idle for a specified length of time.
;Runtime and resttime are obtained from the patch area.

REST:	nop
	nop
	nop
	nop
	lda	RESTmin	; get num of mins to rest
	call	calcTIM	; and make it a time in HMS
	lxi	H,crlf$
	call	prtmsg	; space down a line
..wait:	call	prtINF	; print cur time & rsrt time

; Delay a second or so after printing out time data
	mvi	D,04
	mvi	C,0FFh	
	mvi	B,00	
..delay:djnz	..delay
	dcr	C
	jrnz	..delay ; delay 1 second or so
	dcr	D
	jrnz	..delay

	call	compTIM	; Time to restart?
	jrnz	..wait	; No. Keep waiting

	lda	RUNmin	; Yes. Get num of mins to run
	call	calcTIM	; and make it a time in HMS
	ret		; and resume the test.
	nop
	nop
	nop
	nop
.page
;------------------------------------------------------
;  Subroutine:	TEST LOOP
;
;	Rewind -> Write -> Rewind -> Read -> Return
;
;------------------------------------------------------
TSTLOOP:call	REMTAPE	; rewind the tape
	lxi	H,WRmsg	; Tell user 'Writing'
	call	prtmsg
	lhld	TAPxfr	; 'XXXXh blocks to tape'
	mov	A,H
	push	H
	call	prtbyt
	pop	H
	mov	A,L
	call	prtbyt
	lxi	H,WRendmsg
	call	prtmsg

;---------
; Enable tape to receive write commands.
; Initialize the block counter, label the 512 byte
; buffer (WRbuff) with the new block count-1.
	NOP
	NOP
	NOP
	mvi	A,wrTAPE
	call	SENDCMD	; send tape the write command
.ife	DEBUG,	[
	lxi	H,crlf$
	call	prtmsg
	mvi	C,'{'
	call	CONOUT	]
	NOP
	NOP
	NOP
	lxi	H,0	; current block num minus 1
	shld	curblk	; Mark the WRite buffer with
	lded	WRbuff	; current block.
	xchg
	mov	M,D
	inx	H
	mov	M,E
	xchg

; Write the 512 byte buffer to the tape.
; Test if 'TAPxfr' num of blocks have been written.
; Jump to the Read and Compare section if done, else
; write the WRbuff buffer to the tape and loop.
WRloop:	inx	H
	shld	curblk	; label it as our current block

; markWR buf with new blk number
	lded	WRbuff	
	xchg
	mov	M,D
	inx	H
	mov	M,E
	xchg

	push	H	; save til after end-loop test
	call	WRblk	; WRITE 1 BLOCK
.ife	DEBUG,	[
	mvi	C,'!'
	call	CONOUT	]
	lhld	curblk	; HL=blocks written
	lded	TAPxfr	; DE=num of blocks to write
	dsbc	D	; Does TAPxfr=curblk ?
	pop	H	; (Meanwhile restore blk num)
	jrnz	WRloop	; Keep writing if not equal

;Write file mark
	mvi	A,wrfmTP
	call	SENDCMD
.ife	DEBUG,	[
	mvi	C,'}'
	call	CONOUT	]

;STATUS BYTES MUST BE READ AFTER DATA TRANSFER
;Read and Print out status
	nop
	lxi	H,crlf$
	call	prtmsg
	call	RDSTAT
	call	prtHMS
	call	prtWSTAT
	lxi	H,crlf$
	call	prtmsg
;Rewind the tape
	NOP
	NOP
	NOP
	call	REMTAPE
	NOP
	NOP
	NOP

;Tell the user we are going to READ XXXXh blocks
	lxi	H,RDmsg	; Tell user 'Reading'
	call	prtmsg
	lhld	TAPxfr	; 'XXXXh blocks from tape'
	mov	A,H
	push	H
	call	prtbyt
	pop	H
	mov	A,L
	call	prtbyt
	lxi	H,RDendmsg
	call	prtmsg

;---------
; Initialize the block counter. 
; Tell the tape were going to read.
	NOP
	NOP
	NOP
	mvi	A,rdTAPE
	call	SENDCMD	; get ready to read
.ife	DEBUG,	[
	lxi	H,crlf$
	call	PRTMSG
	call	CONOUT
	mvi	C,'{'
	call	CONOUT	]
	NOP
	NOP
	NOP
	lxi	H,0	; current block-1
;----------
; READ 'TAPxfr' number of blocks one at a time.
; COMPARE each 512 byte block that is read with
; what is stored in the 512 byte write buffer.
RDloop:	inx	H
	shld	curblk	; increment current blk number

; mark WR buf with new incremented blk number
	lded	WRbuff	
	xchg
	mov	M,D
	inx	H
	mov	M,E
	xchg

	push	H	; save num of blocks read
	call	RDblk	; READ 1 BLOCK
	jz	..FLmrk	; ERR file mark found early
.ife	DEBUG,	[
	mvi	C,'!'
	call	CONOUT	]
	call	COMPBUF	; COMPARE READ DATA/WRITE DATA
	pop	H	; HL=blocks read
	push	H	; save for after 'done' check
	lded	TAPxfr	; DE=num of blocks to read
	dsbc	D	; Does TAPxfr=curblk ?
	pop	H	; (Meanwhile restore blk num)
	jrnz	RDloop	; Keep reading if not equal


;Read the expected filemark
;Trap the error if not found.
	lhld	RDbuff
	call	RDblk
	jz	..cont	; file mark found
	lxi	H,TRURerr
	call	prtmsg
	lxi	H,..FMmsg
	call	prtmsg
	lxi	H,fmERRcnt
	inr	M	; increment file mark err cnt.
..FMmsg:.asciz [cr][lf]'File mark not found after read.'
	jmp	TSTLOOP	; restart this loop

; File mark detected early.
..FLmrk:.ife	DEBUG,	[
	mvi	C,'}'
	call	CONOUT	]
	lxi	H,TRURerr
	call	prtmsg
	lxi	H,..FLmsg
	call	prtmsg
	lxi	H,fmERRcnt
	inr	M	; increment file mark err cnt
	jmp	TSTLOOP	; restart this loop
..FLmsg:.ascii	[cr][lf]'File mark found before all'
	.asciz	'512-byte blocks read.'

..cont:
.ife	DEBUG,	[
	mvi	C,'}'
	call	CONOUT	]
;STATUS BYTES MUST BE READ AFTER DATA TRANSFER
;Print status
	nop
	lxi	H,crlf$
	call	prtmsg
;*******call	RDSTAT	; this is being called already
	call	prtHMS
	call	prtRSTAT
	lxi	H,crlf$
	call	prtmsg

;Rewind the tape
	NOP
	NOP
	NOP
	call	REMTAPE
	NOP
	NOP
	NOP


	RET		; loop indefinitely
.page
;-----------------------------------------------------
; 	S U B R O U T I N E S
;-----------------------------------------------------


;----------
;
; Tape I/O buffer pattern subroutines
;

; Create a 512 byte buffer at WRbuff (4F00h).
;The first 2 bytes are reserved for holding the
;block number.  This allows block identification.
;This buffer will be used for writing each block
;to the tape.  The byte sequence is pseudo-random.
makRANbuf:
	lhld	WRbuff		; HL= write buffer addr
	inx	H
	inx	H		; HL= starting data adr
	lxi	B,510		; BC= num bytes to fill
..ranfil:
	call	MAKERAN		; A = randomized number
	mov	M,A		; number is now in buf
	inx	H		; next buffer address
	dcx	B		; decrement byte count
	mov	A,B	
	ora	C		; B=C=0 ?
	jrnz	..ranfil 	; keep filling buffer
	ret
;----------
; Create a 512 byte buffer at WRbuff (4F00h).
;The first 2 bytes are reserved for holding the
;block number.  This allows block identification.
;This buffer will be used for writing each block
;to the tape.  The byte sequence is linear.
makLINbuf:
	lhld	WRbuff		; HL= write buff addr
	inx	H
	inx	H		; HL= starting data adr
	lxi	B,510		; BC= num bytes to fill
	mvi	D,0		; D holds linear number
..linfil:
	mov	M,D		; number is now in buf
	inr	D		; next linear number
	inx	H		; next buffer address
	dcx	B		; decrement byte count
	mov	A,B	
	ora	C		; B=C=0 ?
	jrnz	..linfil	; keep filling buffer
	ret

;----------
; Create a 512 byte buffer at WRbuff (4F00h).
;The first 2 bytes are reserved for holding the
;block number.  This allows block identification.
;This buffer will be used for writing each block
;to the tape.  The byte pattern is fixed.
makFIXbuf:
	lhld	WRbuff		; HL= write buf addr
	inx	H
	inx	H		; HL= strting data addr
	lxi	B,510		; BC= num bytes to fill
..fixfil:
	lda	fixbyt
	mov	M,A		; number is now in buf
	inx	H		; next buffer address
	dcx	B		; decrement byte count
	mov	A,B	
	ora	C		; B=C=0 ?
	jrnz	..fixfil	; keep filling buffer
	ret

; Subroutine: 	MAKERAN
; Regs in:	none
; Regs out:	A = pseudo-random number
; Generate a pseudo-random byte based on the
;previous byte.
MAKERAN:
	lda	..lastran
	adi	31
	xri	11010001b
	rrc
	sta	..lastran
	ret
..lastran:
	.byte	123


;----------
; Subroutine: 	COMPBUF
; Regs  in:	none
; Regs out:	none
;Compare write and read buffers
;If a pair ob bytes do not match,
;print offset of byte-in-error into the buffer.
COMPBUF:
	lhld	WRbuff	; HL=write buffer address
	lded	RDbuff	; DE=read buffer address
	mvi	C,02	; outer loop
	mvi	B,00h	; inner loop  (B*C=512)
..cmploop:
	ldax	D
	cmp	M
	cnz	..ERROR	  ; COMPARE ERROR
	inx	H	  ; next addr in WR buffer
	inx	D	  ; next addr in RD buffer
	djnz	..cmploop ; do this 256 times
; Decrement C and see if all 512 bytes have been tested
	dcr	C
	jrnz	..cmploop ; more bytes to compare
	ret
;----------
; A pair of bytes in the read and write buffers did
;not correspond.  Tell the user.
..ERROR:
	push	B
	push	D
	push	H
	mvi	C,'E'
	call	CONOUT ; Print E (for error)
	pop	H
	push	H
	lded	WRbuff
	dsbc	D	; HL=offset into write buffer
	mov	A,H
	call	prtbyt
	pop	H
	push	H
	mov	A,L
	call	prtbyt
	mvi	C,' '
	call	CONOUT	; output the offset to the user
	pop	H
	pop	D
	pop	B
	NOP
	NOP
	NOP
	NOP
	ret
;******************************************************
;*						      *
;*            Runtime and resttime routines           *
;*						      *
;******************************************************

;----------
;Subroutine:	prtHMS
;  Regs  in:	none
;  Regs out:	none
; Print the current time in Hours, Minutes, and Seconds
;
prtHMS:	lxi	H,banner$
	call	prtmsg	   ; Print our header
	lxi	H,space4
	call	prtmsg
	lxi	H,timmsg
	call	prtmsg	   ; Print 'current time is'
	lxi	H,BIOStim
	lxi	D,seconds
	lxi	B,3	   ; load our bytes with the
	LDIR		   ; current time.
	call	prttime	   ; Print the time.
	ret

;----------
;Subroutine:	prtTRIG
;  Regs  in:	none
;  Regs out:	none
; Print the time as indicated by the bytes 
;stored at location TRIGtim.
;
prtTRIG:
	lxi	H,TRIGtim
	lxi	D,seconds
	lxi	B,3	   ; load our bytes with the
	LDIR		   ;start up time.
	call	prttime	   ; Print that time and
	ret		   ; return.

;----------
;Subroutine:	prttime
;  Regs  in:	none
;  Regs out:	none
; Print (in hours and minutes and seconds)
; as represented by these bytes:
seconds:.byte	00
minutes:.byte	00
hours:	.byte	00
;seconds	=	41h
;minutes	=	42h
;hours		=	43h

timmsg: .asciz	' Current Time is '
restmsg:.asciz	'. Resting until '
space4:	.asciz	'    '

;----------
; Print the time on the DSC/3 or DSC/4.
; This program is used in conjunction with the TIMERopt
; option of the BIOS on the DSC/3 and DSC/4.
;
prttime:
; Print the hours
	lda	hours
;	lxi	H,hours
;	mov	A,M	;get hours in A
	call	cvtbcd
	call	prtbyt
	mvi	C,':'
	call	CONOUT	
;
; Print the minutes
prtmin:	lda	minutes
;	lxi	H,minutes
;	mov	A,M	;get minutes in A
	call	cvtbcd
	;
	call	prtbyt
	mvi	C,':'
	call	CONOUT
;
; Print the seconds
prtsec:	lda	seconds
;	lxi	H,seconds
;	mov	A,M
	call	cvtbcd
	call	prtbyt
	ret		; time is printed out

;----------
; Subroutine:	calcTIM
; Regs in:	A = minutes from now (mfn)
; Regs out:	none
; Calculate and store the time it will be in
;<reg A>'s minutes from now.  The current time 
;is provided by the BIOS. The mfn time will be
;stored in TRIGtim.
;
calcTIM:lxi	H,BIOStim
	lxi	D,TRIGtim
	lxi	B,3	  ; Copy current time
	LDIR		  ; into TRIGGER time
	
;Now add reg A amount of minutes to the time
;and store that time in the three bytes at TRIGtim.
	mov	B,A	    ; mfn goes in B
	lxi	D,TRIGtim+1 ; DE= addr of min
	ldax	D	    ; A = current min
	add	B	    ; min=min+mfn
	cpi	60	  ; Do Mins add up over 60?
	stax	D	  ; (store mins just in case)
	rc		  ; No. Were done
	sbi	60	  ; Yes. min+mfn >= 60
			  ; So min+mfn-60 = new min
	stax	D	  ; save minutes

	inx	D	  ; get to addr of hours
	ldax	D	  ; A=hours
	inr	A	  ; increment hours.
	cpi	24	  ; Is it midnite?
	jrnz	..1	  ; no.
	sub	A	  ; Yes. Reset hrs.
..1:	stax	D	  ; save hours
	ret

;----------
; Subroutine:	prtINF
;   Regs  in:	none
;   Regs out:	none
; Print current time followed by startup time.
;
prtINF:	lxi	H,timmsg
	call	prtmsg	  ; Print 'TIME IS'
	lxi	H,BIOStim
	lxi	D,seconds
	lxi	B,3
	LDIR		  ; load current time
	call	prttime	  ; and print it.
	lxi	H,restmsg
	call	prtmsg	  ; print 'resting until'
	lxi	H,TRIGtim
	lxi	D,seconds
	lxi	B,3
	LDIR
	call	prttime
	mvi	C,' '
	call	CONOUT
	mvi	C,0Dh
	call	CONOUT	; and force only a CR
	ret		; and return
;----------
; Subroutine:	compTIM
;   Regs  in:	none
;   Regs out:	zero flag set/reset
; Compare TRIG's time with the current BIOS time.
; If BIOS time is after the time indicated by TRIGtime,
; then return with the zero flag set.
compTIM:
	lxi	D,TRIGtim+2 ; DE points to hours
	lxi	H,BIOStim+2 ; HL points to BIOS hours
	ldax	D	    ; A = Trigger hours
	mov	B,M	    ; B = BIOS hours
	ora	A	    ; are trig hours 0?
	jrnz	..chkdone   ; No. Bypass check
;Trigger time is set during the zero hour. Check if
;BIOS time is in the 20th,21st,22nd, or 23rd hour.
;Make trigger time in the 24th hour if this is so.
	mov	C,A	    ; save trigger time
	mov	A,B	    ; A = BIOS hours
	CPI	20
	mov	B,A
	mov	A,C
	JRC	..chkdone
	mvi	A,24	    ; new trigger hour
..chkdone:		    ; A = trigger hours
			    ; B = BIOS hours
	cmp	B	    ; Trigger hours>BIOShours?
	jrc	..ret0	    ; Yes. Set zero flag, & ret
	rnz		    ; NO.If BIOS<TRIG ret not 0
; BIOShours = hours. We must compare the minutes.
	dcx	D	    ; DE points to minutes
	dcx	H	    ; HL points to BIOS minutes
	ldax	D
	cmp	M	    ; BIOSmins <= Trigger mins?
	rnc		    ; No. Return non-zero
; BIOSmins = mins.  We must compare the seconds.
	dcx	D	    ; DE points to seconds
	dcx	H	    ; HL points to BIOS seconds
	ldax	D
	cmp	M	    ; BIOSsecs <= Trigger secs?
	rnc		    ; No. Return non-zero
..ret0:	sub	A	    ; Yes. Return zero.
	ret	

;----------
; Convert binary to BCD
;  Regs in:   A = byte to be converted
;  Regs out:  A = byte, in BCD format
;  Destroyed: B
cvtbcd:
	ora	A
	rz
	mov	B,A
	xra	A
..1:	inr	A
	daa
	djnz	..1
	ret

;************************************************
;*						*
;* TAPE DATA, DEFS, and CONTROLLING SUBROUTINES	*
;*           courtesy of Robert Kavaler		*
;************************************************
MNTWRT:	call	NEWTAPE	; mount a new tape
	call	RDSTAT	; read the status
	lda	TPstat	; make sure it is writeable
	bit	4,A
	rz
	lxi	H,writp$; print error message
	call	PRTMSG
	jmpr	MNTWRT	; and loop
; Handle new tape
NEWTAPE:
	lxi	H,newt$ ; print message
	call	PRTMSG
..ask:	call	CONIN	; get response
	push	PSW	; save the char
	call	RESETT	; reset the controller
	call	RDSTAT
	pop	PSW	; restore the char
	cpi	'R'	; look it up
	jrz	..rwd
	cpi	'T'
	jrz	..ret
	cpi	'E'
	jrz	..era
	lxi	H,error$; print error
	call	PRTMSG
	jmpr	..ask
..rwd:	mvi	A,rwdTAPE ; rewind command
	jmpr	..pos
..ret:	mvi	A,retTAPE ; retension command
	jmpr	..pos
..era:	mvi	A,eraTAPE ; erase command
..pos:	call	SENDCMD	; send the command
..loop:	call	ckstat	; loop until done or error
	.word	..done
	.word	..err
	jmpr	..loop
..done:	ret		; return if no error

..err:	call	RDSTAT	; if error, read the status
	lxi	H,notap$; no tape, probably
	call	PRTMSG
	jmpr	NEWTAPE	; ask again
;---------------
; Remove a tape, rewind it first.
REMTAPE:
	mvi	A,rwdTAPE ; send rewind command
	call	SENDCMD
	lxi	H,endtp$; print a message
	call	PRTMSG
	call	RDSTAT	; read the status
	ret
;-----------------
; Routines for TAPE
RESETT:
	in	STROBE	; strobe RESET
	mvi	A,11010b
	out	TAPE
	in	STROBE
	mvi	A,11011b
	out	TAPE
	ret
;
; Check READY and EXCEPTION, return to first
; parameter if READY, second if EXCEPTION
; continue if neither
ckstat:
	pop	H	; get return addr.
	in	STROBE	; read status
	in	TAPE
	bit	1,A	; check READY
	jrz	..rdy
	bit	2,A	; check EXCEPTION
	jrz	..exc
	inx	H	; skip params
	inx	H	
	inx	H
	inx	H
	pchl		; return
..exc:	inx	H	; skip first parameter
	inx	H
..rdy:	mov	A,M	; get lsb
	inx	H
	mov	H,M	; get msb
	mov	L,A	; move in lsb
	pchl		; go to the routine
;
SENDCMD:
	push	PSW	; save the command
..wait:	call    ckstat  ; loop until READY or EXCEPT
	.word   ..RDY
	.word   ..EXCPT
	jmpr	..wait
..EXCPT:
	.ife	DEBUG,	[
	mvi	C,'*'
	call	CONOUT	]
..RDY:	in	STROBE
	mvi	A,11011b
	out     TAPE    ; set up RR protocol
	pop	PSW	; restore the command
	cma		; active low
	out	TAPE	; send command to buffer
	in	STROBE
	mvi	A,11001b
	out 	TAPE	; assert REQUEST
..loop:	in	STROBE	; loop until READY
	in	TAPE
	bit	1,A
	jrnz	..loop
	in	STROBE
	mvi	A,11011b
	out     TAPE  	; turn REQUEST off
	mvi	B,32	; wait for 100 Usec
	djnz	.
	ret		; return
;
RDSTAT:
	mvi	A,stTAPE; send the command
	call	SENDCMD ; to get status
	lxi	H,TPstat; set up to read 6 status
	mvi	B,6	; bytes
..1:	in	STROBE	; wait for READY
	in	TAPE
	bit	1,A
	jrnz	..1
	in	TAPE	; read the status byte
	cma		; active low
	mov	M,A	; store it
	in	STROBE	; assert REQUEST
	mvi	A,11001b
	out     TAPE    ; assert REQUEST
..2:	in	STROBE	; wait for READY not
	in	TAPE
	bit	1,A
	jrz	..2
	in	STROBE	; assert REQUEST not
	mvi	A,11011b
	out	TAPE
	inx	H	; next byte
	djnz	..1
	mvi	B,8	; wait for 20 Usec
	djnz	.
.ife	DEBUG,	[
	mvi	C,'S'
	call	CONOUT	; signal stat bytes read
]
	ret		; return
;
;----------
; Subroutine: 	eatSTbt
;   Regs  in:	none
;   Regs out:	none
;  Destroyed:	none
; Eat the 6 status bytes.

eatSTbt:push	PSW
	push	B
	push	H
	call	RDSTAT	; call the read status routine
	pop	H
	pop	B
	pop	PSW
	ret

wrblk:	lhld	WRbuff	;HL=WRITE BUFFER ADDRESS
	push	H	; HL is address
..loop: call    ckstat  ; loop until READY
	.word   ..cont
	.word   wrex	; if EXCEPTION, then error
	jmpr	..loop
..cont:	pop	H	; restore HL
	shld	wrtadr	; save it
	in	STROBE
	mvi	A,01011b; clear XFER-ACK FF
	out	TAPE
	in	STROBE
	mvi	A,10011b
	out	TAPE	; XFER-ACK protocol

	mvi	A,7	; multiplex STATB to DMA
	out	8
	lxi	H,DMAwrt; set up DMA chip
	lxi	B,lenwrt<8+DMA
	outir		; run the DMA
	jmp	WAITdma
;
rdblk:	lhld	RDbuff  ; HL=READ BUFFER ADDRESS
	push	H	; save HL
..loop:	call	ckstat	; loop for READY
	.word	..cont
	.word	rdex	; EXCEPTION implies error
	jmpr	..loop
..cont:	pop	H	; restore HL
	shld	rdtadr	; put it into DMA
	in	STROBE	; XFER-ACK protocol
	mvi	A,10011b
	out	TAPE
	
	mvi	A,7	; multiplex STATB to DMA
	out	8
	lxi	H,DMArdt; set up DMA chip
	lxi	B,lenrdt<8+DMA
	outir		; run the DMA
	call	WAITdma
	mvi	A,0FFh	; return non-zero
	ora	A
	ret
	.page
;----------
; Exception during write : EOT or error
wrex:	call	RDSTAT	; get the status
	lda	TPstat	; check for EOT
	bit	3,A
	jrnz	..eot
	pop	H	 ; rebalance stack
	lxi	H,TRUWerr; unrecoverable tape write err
	jmp	wrERROR
..eot:	mvi	A,wrfmTP; write a file mark
	call	SENDCMD
	lxi	H,eot$	; print a message
	call	PRTMSG
	call	REMTAPE	; remove the tape
	call	MNTWRT  ; mount a new tape
	mvi	A,'-'	; continuation is '-'
;	sta	size%
;	call	BACKb	; write tape header
	pop	H	; pop previous block
	jmp	wrblk	; and continue
;----------
; Exception during read : EOF or error
rdex:
	call	RDSTAT	; read the status
	lda	TPstat
	bit	3,A	; look for EOT
	jrnz	..eot
	bit	0,A	; then EOF
	jrnz	..eof
	pop	H	 ; rebalance stack
	lxi	H,TRURerr; unrecoverable tape read err
	jmp	rdERROR
..eof:	sub	A	; return A=0 for EOT
	pop	H	; remove HL from stack
	ret
..eot:	lxi	H,eot$	; get next TAPE
	call	PRTMSG
	pop	H	; rebalance stack
	lxi	H,TRURerr
	jmp	rdERROR
;----------
; Wait for an interrupt from the DMA chip
WAITDMA:
	sub	A
	sta	DMAflag
	ei		; make sure interrupts enabled
..wait:	lda	DMAflag
	ora	A
	jrz	..wait
	ret
;----------
; Process an interrupt from the DMA chip
DMAflag:.byte	0	; non-zero signals DMA complete
DMAdone:
	push	PSW
	mvi	A,0C3h
	out	DMA	; reset the DMA chip
	sta	DMAflag	; signal DMA completion
	pop	PSW
	ei
	ret
;----------
; Divide HL by BC, put result in DE and remainder in HL
;  (Use a very simple algorithm - speed isnt important)
DIVIDE:
	lxi	D,0
	ora	A
..div:	dsbc	B	; subtract BC from HL
	jrc	..ret
	inx	D	; increment result each pass
	rz
	jmpr	..div
..ret:	dad	B	; compute correct remainder
	ret
.page
;******************************************************
;*                                                    *
;*               ERROR SUBROUTINES                    *
;*                                                    *
;******************************************************
;----------
; Process a general error
; If we are using the DEBUG option, print out the
;callers address and jump into DDT. Otherwise, rewind 
;the tape and jump back into CPM.
ERROR:
	call	PRTMSG	; print the error

	xthl
	shld	..here
	xthl
	lxi	H,..ERRmsg
	call	prtmsg	; print "ERROR detected at"
	lhld	..here
	push	H
	mov	A,H
	call	prtbyt
	pop	H
	mov	A,L
	call	prtbyt
	lxi     H,..end
	call	prtmsg	; print callers addr: XXXXh
	lxi	H,loopmsg
	call	prtmsg
	lda	loopcnt
	call	prtbyt
	lxi	H,..end	; print loops completed
	rst	6	; and jump into DDT

..here:  .word	0000h	; callers address
..ERRmsg:.asciz	[cr][lf]'ERROR detected at '
..end:	 .asciz	'h. '[cr][lf]

	call	REMTAPE	; remove the tape
	jmp	0	; go back to CPM
;----------
; Routine:	rdERROR
; Regs  in:	none
; Regs out:	none
; Print out an error header, then analyze the 1st 2
;status bytes and print out error messages for respec-
;tive high bits. Bit 7 of both bytes is used as a flag
;to indicate whether any of the other bits are set.
;Next, the tape status bytes themselves are printed.
;The next two bytes of the tape status are then dis-
;played - this is a 16 bit counter of soft read errors.
;The last two bytes of the tape status are then dis-
;played - this is a 16 bit counter of read buffer
;underruns.  See the ARCHIVE manual for details.
; The routine concludes by jumping to CPM (00h).
rdERROR:

	lda	TPstat	  ; tape status byte number 0
	bit	7,A	  ; Is error held in this byte?
	jrz	..byt1test; No. Test next byte.

	lxi	H,TRURerr
	call	prtERR	  ; Print tru read err msg

	bit	6,A	  ; A = tape status byte 0
	lxi	H,CARTerr
	cnz	prtERR    ; Cartridge not in place
	bit	5,A
	lxi	H,DRIVerr
	cnz	prtERR    ; Drive not on line
	bit	2,A
	lxi	H,DATAerr
	cnz	prtERR    ; Unrecoverable data error
	bit	1,A
	lxi	H,BIEerr
	cnz	prtERR    ; BIE not located
	lxi	H,ERbyt0info
	call	prtmsg	  ; print closing info 

..byt1test:
	lxi	H,TPstat+1; get 2nd status byte
	mov	A,M	  ; into the accumulator
	bit	7,A	  ; Is an error flagged
			  ; in this byte?
	jrz	..1	  ; No. just print status data
	
	lxi	H,TRURerr
	call	prtERR	  ; print error header
	
	bit	6,A
	lxi	H,COMerr  ; Illegal command
	cnz	prtERR
	bit	5,A
	lxi	H,NODATerr; No data detected
	cnz	prtERR
	bit	0,A
	lxi	H,RESerr
	cnz	prtERR	  ; Reset occurred
	lxi	H,ERbyt1info
	call	prtmsg	  ; print closing info
..1:	lxi	H,rdERRcnt
	inr	M	  ; increment read error cnt
	call	prtRSTAT  ; Print error statuses
	JMP	TSTLOOP	  ; and try this loop over

;Display the 2 status bytes to the console
prtRSTAT:
	lxi	H,rdERRmsg
	call	prtmsg
	lda	rdERRcnt
	call	prtbyt
	lxi	H,stat0msg
	call	prtmsg
	lda	TPstat
	call	prtbyt
	lxi	H,endmsg
	call	prtmsg
	lxi	H,stat1msg
	call	prtmsg
	lda	TPstat+1
	call	prtbyt
	lxi	H,endmsg
	call	prtmsg
	jmpr	..around

;Print next 2 pairs of status bytes and their
;headers.

..sofmsg:.asciz	[cr][lf][9]'Soft read errors: '
..urunmsg:
	.asciz	[cr][lf][9]'Read buffer underruns: '

..around:
	lxi	H,..sofmsg ; Print soft read
	call	prtmsg	   ; error message.
	lxi	H,TPstat+2 ; addr of 1st byte of 
	mov	A,M	   ; Data error counter
	push	H
	call	prtbyt	
	pop	H
	inx	H
	mov	A,M
	call	prtbyt	   ; Print num of soft
			   ; read errors.
	
	lxi	H,endmsg
	call	prtmsg	   ; and space down.

	lxi	H,..urunmsg; Print read buffer
	call	prtmsg	   ; underruns message.
	lxi	H,TPstat+4 ; addr of 1st byte of 
	mov	A,M	   ; underrun error counter
	push	H
	call	prtbyt	
	pop	H
	inx	H
	mov	A,M
	call	prtbyt	   ; Print num of 
			   ; underrun errors.

	lxi	H,endmsg
	call	prtmsg	   ; and space down.
; Test for write buffer flag
	lda	BUFflg	   ; Do we write
	ora	A	   ; the status bytes to the
	rz		   ; status buffer? 0 = OFF.
; Load the 6 status bytes into the status write-buffer
	lhld	bufaddr	   ; Yes. Get current buf addr
	lda	loopcnt	   ; A=Current loop
	mov	M,A	   ; put loop num in memory
	inx	H	   ; get to next buf addr
	mvi	M,'R'	   ; and put in a R for READ
	inx	H
	lxi	D,TPSTAT   ; get tape status addr
	xchg		   ; HL=tape stat addr
			   ; DE=curr stat buf addr
	lxi	B,6
	LDIR		   ; Copy 6 stat bytes into mem
	ora	A
	lhld	TOPmem
	dsbc	D	   ; Are we at the top of buf?
	jrnc	..1	   ; No. TOPmem-cur addr >0
	lded	STATbuf	   ; Yes. Re-init stat buffer
..1:	xchg		   ; HL=next stat buf addr
	shld	bufaddr	   ; save for next stat write
	ret

;----------
; Routine:	wrERROR
; Regs  in:	none
; Regs out:	none
; Print out an error header, then analyze the 1st 2
;status bytes and print out error messages for respec-
;tive high bits. Bit 7 of both bytes is used as a flag
;to indicate whether any of the other bits are set.
;Next, the tape status bytes themselves are printed.
;The next two bytes of the tape status are then dis-
;played - this is a 16 bit counter of block rewrites.
;The last two bytes of the tape status are then dis-
;played - this is a 16 bit counter of extended gaps.
;See the ARCHIVE manual for details.
; The routine concludes by jumping to CPM (00h).
wrERROR:

	lda	TPstat	  ; tape status byte number 0
	bit	7,A	  ; Is error held in this byte?
	jrz	..byt1test; No. Test stat byte 1

	lxi	H,TRURerr
	call	prtERR	  ; print error header
	
	bit	6,A
	lxi	H,CARTerr
	cnz	prtERR    ; Cartridge not in place
	bit	5,A
	lxi	H,DRIVerr
	cnz	prtERR    ; Drive not on line
	bit	2,A
	lxi	H,DATAerr
	cnz	prtERR    ; Unrecoverable data error
	bit	1,A
	lxi	H,BIEerr
	cnz	prtERR    ; BIE not located
	lxi	H,ERbyt0info
	call	prtmsg	  ; print closing info 

..byt1test:
	lxi	H,TPstat+1; get 2nd status byte
	mov	A,M	  ; into the accumulator
	bit	7,A	  ; Is error held in this byte?
	jrz	..1	  ; No. just print status data
	
	lxi	H,TRURerr
	call	prtERR	  ; print error header
	
	bit	6,A
	lxi	H,COMerr  ; Illegal command
	cnz	prtERR
	bit	5,A
	lxi	H,NODATerr; No data detected
	cnz	prtERR
	bit	0,A
	lxi	H,RESerr
	cnz	prtERR	  ; Reset occurred
	lxi	H,ERbyt1info
	call	prtmsg	  ; print closing info
..1:	lxi	H,wrERRcnt
	inr	M	  ; increment error cnt
	call	prtWSTAT  ; Print statuses
	JMP	TSTLOOP	  ; and try this loop over

prtWSTAT:
	lxi	H,wrERRmsg
	call	prtmsg
	lda	wrERRcnt
	call	prtbyt
	lxi	H,endmsg
	call	prtmsg
	lxi	H,stat0msg
	call	prtmsg
	lda	TPstat
	call	prtbyt
	lxi	H,endmsg
	call	prtmsg
	lxi	H,stat1msg
	call	prtmsg
	lda	TPstat+1
	call	prtbyt
	lxi	H,endmsg
	call	prtmsg
	jmpr	..around

;Print next 2 pairs of status bytes and their
;headers.

..rewrmsg:
	.asciz  [cr][lf][9]'Blocks rewritten: '
..urunmsg:.asciz [cr][lf][9]'Extended gaps: '

..around:
	lxi	H,..rewrmsg ; Print soft read
	call	prtmsg	   ; error message.
	lxi	H,TPstat+2 ; addr of 1st byte of 
	mov	A,M	   ; Data error counter
	push	H
	call	prtbyt	
	pop	H
	inx	H
	mov	A,M
	call	prtbyt	   ; Print num of soft
			   ; read errors.
	
	lxi	H,endmsg
	call	prtmsg	   ; and space down.

	lxi	H,..urunmsg; Print read buffer
	call	prtmsg	   ; underruns message.
	lxi	H,TPstat+4 ; addr of 1st byte of 
	mov	A,M	   ; underrun error counter
	push	H
	call	prtbyt	
	pop	H
	inx	H
	mov	A,M
	call	prtbyt	   ; Print num of 
			   ; underrun errors.
	
	lxi	H,endmsg
	call	prtmsg	   ; and space down.
; Test for write buffer flag
	lda	BUFflg	   ; Do we write
	ora	A	   ; the status bytes to the
	rz		   ; status buffer? 0 = OFF.
; Load the 6 status bytes into the status write-buffer
	lhld	bufaddr	   ; Yes. Get current buf addr
	lda	loopcnt	   ; A=Current loop
	mov	M,A	   ; put loop num in memory
	inx	H	   ; get to next buf addr
	mvi	M,'W'	   ; and put in a W for WRITE
	inx	H
	lxi	D,TPSTAT   ; get tape status addr
	xchg		   ; HL=tape stat addr
			   ; DE=curr stat buf addr
	lxi	B,6
	LDIR		   ; Copy 6 stat bytes into mem
	ora	A
	lhld	TOPmem
	dsbc	D	   ; Are we at the top of buf?
	jrnc	..1	   ; No. TOPmem-cur addr >0
	lded	STATbuf	   ; Yes. Re-init stat buffer
..1:	xchg		   ; HL=next stat buf addr
	shld	bufaddr	   ; save for next stat write
	ret
.page
;******************************************************
;*                                                    *
;*             General I/O Subroutines                *
;*                                                    *
;******************************************************
;----------
; Print a message on the console
;  Regs in:   HL = address of message
;  Regs out:  none
;  Destroyed: all
PRTMSG:
	mov	A,M
	ora	A
	rz
	mov	C,A
	push	H
	call	CONOUT
	pop	H
	inx	H
	jmpr	PRTMSG

;----------
; Print an error message on the console
;  Regs in:   HL = address of message
;  Regs out:  none
;  Destroyed: all
prtERR:
	push	PSW	; save tape status
	call	prtmsg
	pop	PSW
	ret		; restore tape status

;----------
;		Subroutine: prtbyt
; Regs  in:	A=byte to be printed
; Regs out:	none
; Destroyed:	A,B,C
;Print a byte on the console
prtbyt:
	push	PSW	; save the chr
	rlc
	rlc
	rlc
	rlc
	call	prtnbl
	pop	PSW
	call	prtnbl
	ret
prtnbl:	ani	0Fh
	adi	'0'
	mov	C,A	; chr goes out in C
	cpi	'9'+1
	jc	CONOUT
	adi	'A'-('9'+1)
	mov	C,A	; chr goes out in C
	jmp	CONOUT

;----------
; Wait for a cr to be typed
;
waitCR:	call	PRTMSG	; print message
..loop:	call	CONIN	; read a char
	cpi	cr	; loop if not cr
	jrnz	..loop
	ret		; return if cr
;----------
; Ask yes/no question
;
askynq:	call	PRTMSG	; print message
	call	CONIN	; read a char
	cpi	'Y'	; 'Y' and 'N' are valid
	rz
	cpi	'N'
	rz
	lxi	H,error$; else error
	jmpr	askynq	; and loop
;----------
; Input a string from the console
;
lencon	==	10	; buffer length
	.byte	lencon,0
conbuf:	.blkb	lencon  ; console buffer
INSTRING:
	lxi	D,conbuf-2; let BDOS do work
	mvi	C,10
	call	BDOS
	lxi	H,conbuf; convert lower to upper
	lda	conbuf-1; case
	mov	B,A
	ora	A
	jrz	..fill
..lp1:	mov	A,M
	call	CVTluc
	mov	M,A
	inx	H
	djnz	..lp1
..fill:	lda	conbuf-1; fill rest of buffer
	sui	lencon
	neg	
	rz  
	mov	B,A
..lp2:	mvi	M,' '
	inx	H
	djnz	..lp2
	ret
;----------
; Compare two strings for equal
;  Regs in:  B = length
;	     HL -> string1
;	     DE -> string2
;  Regs out: HL -> after string1
;	     DE -> string2
;	     Z-flag  cleared if equal
;	     A = 0FFh if equal 0 else
STRCOMP:
	push	B
	push	D
	mvi	C,0FFh
..cmp:	ldax	D
	cmp	M
	jrz	..same
	mvi	C,0	; not the same
..same:	inx	D
	inx	H
	djnz	..cmp
	mov	A,C
	ora	A	; set Z-flag
	pop	D
	pop	B
	ret
;---------
; get character from console (using BDOS) then
; convert lower to upper case.
; Abort on CTRL-C, restart on ESC
CONIN:	mvi	C,1	; command 1
	call	BDOS	; read a char
	cpi	ctrlC
	jz	0	; abort if ctrlC
	cpi	1Bh
	jrz	..DDT	; jump into DDT if ESC
	call	CVTluc	; convert to upper case
	ret		; and return
..DDT:	rst	6	

;---------
; print char in C (using BDOS)
;
CONOUT:	push	PSW	; save A
	mov	E,C	; char is in C
	mvi	C,2	; command 2
	call	BDOS	; print the char
	pop	PSW	; get A back
	ret		; thats all
;
CVTluc:	cpi	'a'	; convert upper to lower case
	jm	..up
	cpi	'z'+1
	jp	..up	
	sui	'a'-'A'
..up:	ret
	.page
;----------
; DMA commands
;
; Read 512 bytes from tape to memory
DMArdt:
	.byte	0C3h
	.byte	0C7h
	.byte	0CBh
	.byte	7Dh
rdtadr:	.word	0	; DMA address
	.word	511	; DMA length - 1
	.byte	14h
	.byte	28h
	.byte	95h
	.byte	TAPE
	.byte	12h
	.byte	0	; DMA vector
	.byte	9Ah
	.byte	0CFh
	.byte	1
	.byte	0CFh
	.byte	0ABh
	.byte	87h
lenrdt	==	.-DMArdt
;----------
; Write 512 bytes from memory to tape
DMAwrt:
	.byte	0C3h
	.byte	0C7h
	.byte	0CBh
	.byte	79h
wrtadr:	.word	0	; DMA address
	.word	511	; DMA length - 1
	.byte	14h
	.byte	28h
	.byte	95h
	.byte	TAPE
	.byte	12h
	.byte	0	; DMA vector
	.byte	92h
	.byte	0CFh
	.byte	5
	.byte	0CFh
	.byte	0ABh
	.byte	87h
lenwrt	==	.-DMAwrt
	.page
;----------
; Messages

hello$:	.ascii	[cr][lf]'TAPE diagnostic program '
banner$:.ascii	[cr][lf]'TESTCART '
	.ascii	' ver '
	.byte	version+'0','.',revision+'0'
	.byte	patch,0

info$:	.ascii	[cr][lf][lf]"Use CTRL-C"
	.ascii	" to boot, ESCAPE to jump into DDT."
	.ascii [cr][lf]'LEGEND: { = R/W command issued'
	.ascii [cr][lf]'        ! = R/W 512 bytes completed'
	.ascii [cr][lf]'        } = R/W command completed'
	.ascii [cr][lf]'        * = EXCEPTION line raised'
	.ascii [cr][lf]'        S = Status bytes read'
	.asciz [cr][lf]

strtmsg:.asciz	[cr][lf]'Hit RETURN to start the test '
loopmsg:.asciz	[cr][lf]'LOOPS COMPLETED: '

LINmsg:	.asciz	[cr][lf]'512 byte pattern: LINEAR '
RANmsg:	.asciz	[cr][lf]'512 byte pattern: RANDOM '
FIXmsg:	.asciz	[cr][lf]'512 byte pattern: FIXED '

WRmsg:	.asciz	[cr][lf]' Writing '
Wrendmsg:
	.asciz	'h blocks to tape. '[cr]

RDmsg:	.asciz	[cr][lf]' Reading '
RDendmsg:
	.asciz	'h blocks from the tape. '[cr]

select$:.ascii	[cr][lf][lf]
	.ascii	'Select one of the following options:'
	.ascii	[cr][lf]
	.ascii	[cr][lf]'  T = Tape write/read infinit'
	.ascii	'e test'
	.ascii	[cr][lf]'  R = resume testing without '
	.ascii	'reinitializing '
	.ascii	[cr][lf]'  B = Warm BOOT'
	.ascii	[cr][lf]'  D = jump to DDT'
	.asciz	[cr][lf][lf]'Enter choice: '

crlf$:	.asciz	[cr][lf]

newt$:	.ascii	[cr][lf]'Insert cassette, then '
	.ascii	'select one of the following:'
	.ascii	[cr][lf]
	.ascii	[cr][lf]' R - Rewind'
	.ascii	[cr][lf]' T - Retension'
	.ascii	[cr][lf]' E - Erase'
	.ascii	[cr][lf]
	.asciz	[cr][lf]'Enter Choice: '

wrERRmsg:
	.asciz	[cr][lf][9]'WRITE ERRORS: '
rdERRmsg:
	.asciz	[cr][lf][9]'READ ERRORS: '
stat0msg:
	.asciz	[cr][lf][9]'Tape status byte 0: '
stat1msg:
	.asciz	[cr][lf][9]'Tape status byte 1: '
endmsg:.asciz	'h '

error$:	.ascii	[cr][lf]"Incorrect entry.  Use CTRL-C"
	.ascii	" to boot, ESCAPE to jump into DDT."
	.asciz	[cr][lf]"Please re-enter :"

writp$:	.ascii	[cr][lf]'The tape cartridge is write '
	.ascii	'protected or not inserted correctly.'
	.asciz	[cr][lf]

notap$:	.ascii	[cr][lf]'No tape in drive.'
	.asciz	[cr][lf]

backw$:	.ascii	[cr][lf]'Type RETURN to write system'
	.asciz	' software and partition 0.'

backa$:	.ascii	[cr][lf]'Type RETURN to backup '
	.asciz	'entire disk.'

eot$:	.ascii	[cr][lf][7]'End of TAPE, please '
	.asciz	'mount next cassette.'

reld$:	.ascii	[cr][lf][lf]
	.ascii	'If correct tape type RETURN, '
	.asciz	'otherwise type anything else. '

allwr$:	.ascii	[cr][lf]'All partitions written'
	.asciz	' to TAPE.'

endtp$:	.ascii	[cr][lf]'Tape is being rewound.'
	.asciz	[cr][lf]

etmsg$:	.asciz	[cr][lf]'End Of Tape data. '


TSFerr:	.asciz	[cr][lf]'Short file encountered.'

TRURerr:.ascii	[cr][lf][lf][7]
	.asciz	'*** Unrecoverable TAPE read error: '

TRUWerr:.ascii	[cr][lf][lf][7]
	.asciz	'*** Unrecoverable TAPE write error: '

CARTerr:.asciz	'CARTRIDGE NOT IN PLACE.  '
DRIVerr:.asciz	'DRIVE NOT ON LINE.  '
DATAerr:.asciz	'UNRECOVERABLE DATA ERROR.  '
BIEerr:	.asciz	'B I E  NOT LOCATED.  '
ERbyt0info:
	.ascii	[cr][lf]'Error(s) detected from byte 0'
	.asciz	' of the 6 tape status bytes.'
COMerr:	.asciz	'ILLEGAL COMMAND.  '
NODATerr:
	.asciz	'NO DATA DETECTED.  '
RESerr:	.asciz	'RESET OCCURRED.  '
ERbyt1info:
	.ascii	[cr][lf]'Error(s) detected from byte 1'
	.asciz	' of the 6 tape status bytes.'


DISKerr:.ascii	[cr][lf][lf][7]
	.ascii	'Unrecoverable DISK read/write '
	.asciz	'error.'
	.page
;----------
; Strings for compare
;
all$:	.ascii	'*ALL    '
end$:	.ascii	'*END    '
blnk$:	.ascii	'        '
rwnd$:	.ascii	'*REWIND '
cart$:	.ascii	'*CART   '
part0$:	.ascii	'*PART0  '
list$:	.ascii	'*LIST   '

;----------
; Tape commands
;
rwdTAPE	==	21h	; rewind command
eraTAPE	==	22h	; erase command
retTAPE ==	24h	; retension command
rdTAPE  ==	80h	; read the tape
wrTAPE	==	40h	; write the tape
stTAPE	==	0C0h	; read status
wrfmTP  ==	60h	; write file mark
 
;----------
; TAPE information
;
MAXtrk:	.byte	0	; last track
MAXhead:.byte	0	; last head
MAXsect:.byte	0	; last sect

	.blkw	100	; stack room
stack	==	.
	.end

