version	==	2
revision==	3
	.title	'FLOPPY DISK TEST PROGRAM FOR DSC3/4'
	.sbttl	'FDTEST'
	.pabs
	.phex
;
;-------------------------------------
;
;     Multiple floppy disk test program
;
;     This program tests up to eight drives. There are
; 3 write patterns:  Linear,Random, and fixed.  After
; a write has been performed on all drives, each drive
; read tested in two successive patterns:  Linear and
; Random.  The user selects the density, as well as the
; order in which the drives are tested.  Control-C will
; abort the program at any time.  Console 'in progress'
; commands are F,R,S,T, and Q and are described below.
;
; F -  Initiate FIXTEST.  This turns off the disk-write
;     (if its enabled), sets the test pattern to fixed,
;     and enables the user to Read test or Write test
;     at will to any disk, any track, for any length of
;     time.
;
; R  - Read out the 'error' buffer.  The program keeps
;     track of all write patterns and loop numbers, by
;     writing them to a buffer located at 7000h. All
;     errors are written to this buffer, also. When
;     the buffer fills past B000h the buffer is des-
;     troyed and re-initialized to 7000h.
;
; S  - Print the current status to console. This in-
;     the user immediately as to what function is
;     currently being performed, the amount of errors
;     that have been detected, as well as the current
;     drive and current time 
;
; T  - Stop the current test in progress and select
;     a new set of disks to test.  The buffer-write
;     disk is kept the same, and the buffer-file's
;     contents are not destroyed.
;
; Q  - Quit the program.  The program then asks the
;     user if an exit is really desired.  If no 'Y'
;     is entered, the test resumes as if not inter-
;     rupted.  If a 'Y' is entered the test will
;     then terminate.
;
; ?  - Any other character is received from the console
;     a menu of acceptable commands is printed out.
;
; Flexibilities
;
;     Changeable fixed byte. Change 'wrstbyt'.
; If a change of the worst byte ( read and
; written in the 'fixed' mode ) is desired,
; change the value of the byte at 103h to the
; desired value.  This can be done in ZDT if desired.
;
;     Changeable error overflow.  Change 'maxerrs'.
; If any drive accumulates a 'maxerrs' number of errors
; of any one type, FDTEST will automatically log that
; drive out of the test. 'Maxerrs' is defaulted to 10
; and can be set by changing the byte at 104h to any
; desired value.  This also can be done through ZDT.
;
;     Disk write option.  This writes the contents
; of the error buffer ( which begins at 7000h ) to
; a user-selected disk. When 128 bytes are collected
; the sectors worth of data is written to CONFILE.TXT
; (this file is chosen by default if no file name is 
; found on the command line) and the buffer is cleared.
; This will continue forever, or until the disk is
; full.
;
;     Fixed track testing.  See 'F' command above.
;
; Please note: Both CP/M and BIOS calls are used.
; The disk write feature uses CP/M file management,
; while the test reads & writes are performed through
; BIOS calls.
;
;                                 David Stein 12/10/80
;
;  Update History:
;
;	Version 2.03 - Condensed error buffer info.
; 		       Neatened error messages.
;					   DS  3/26/81
;	GIBSFD	removed disk buffer option and simplified
;		error summary for test purposes
;					  kgh 7/14/82		
	.loc	100h
	jmp	start

; Patch area
wrstbyt:.byte	0B6h	; special worst case test
			;byte for fixed pattern reading
maxerrs:.byte	0Ah	; Maximum number of Sector or
			;Track errors allowed on each
			;drive before logging drive out

; Define some constants:
cr	=	0Dh	; define carraige return
lf	=	0Ah	; define line feed
retry	=	10	; number of error retries
BIOSrty =	4Eh	; memory location of # retries
comline	=	80h	; CP/M command line location
DFCB	=	5Ch	; CP/M com line FCB addr
;
;----------
; Main Program
start:
; Start with a fresh stack, initialize buffer and flags
	lxi	sp,stack
	mvi	A,0
	sta	errflg	  ; turn off error flag
	lxi	H,erbuffer
	shld	errbufadr ; initialize err buffer
	call	putEOF	  ; label end of err buffer
; Set up the 'worst byte' for being printed to console
setup:
	lda	wrstbyt
	push	PSW	  ; Split up the 'worst byte'
	rlc		  ;into two chrs and save
	rlc		  ;for 'Writing XXh fixed'
	rlc		  ;in summary print-outs.
	rlc
	call	savnbl
	sta	wbchr1	  ; 1st chr of wrstbyt
	pop	PSW
	call	savnbl
	sta	wbchr2	  ; 2nd chr of wrstbyt
	jmp	BEGIN	  ; preliminaries finished
;----------
;  		Subroutine: savnbl
; Save a nibble
savnbl:	ani	0Fh
	cpi	10
	jm	chr
	adi	07
chr:	adi	'0'
	ret
.page
;--------------------
; MAIN BODY - First - Initialize and obtain initial
;	       instructions on which density and
;	       which disks to test, and whether
;	       or not to save the errors on disk
;	       or network.
;
BEGIN:	ei		  ; enable interrupts
	mvi	A,0	  ; disable auto retries
	sta	BIOSrty	  ; in BIOS
	call	stoMAPbyt ; Save current disk select
	lxi	H,crlf	  ; space down a line.
	call	prtmsg
	lxi	H,initMSG ; print initial message
	call	prtmsg

; Clear the error count locations.
clrERR:	lxi	H,Terrors
	lxi	D,Terrors+1
	lxi	B,10
	mvi	M,0
	LDIR		; Clear Track error locs

	lxi	H,Serrors
	lxi	D,Serrors+1
	lxi	B,10
	mvi	M,0
	LDIR		; Clear Sector error locs


; Get the density.
findden:lxi	H,denmsg
	call	prtmsg	    ; Ask user the density
	call	CONIN	    ; fetch console chr
	push	PSW
	sta	retdsk	    ; place chr in message
	lxi	H,retMSG
	call	prtmsg      ; echo chr and space down
	pop	PSW
	mvi	B,SDbyt	    ; Prepare for sing density
	cpi	'S'	    ; Single density?
	jrz	stodens     ; Yes. Save register B
	mvi	B,DDbyt     ; No. Prepare for doub dens
	cpi	'D'	    ; Double density?
	jrz	stodens	    ; Yes. Save register B
	lxi	H,errmsg    ; No. Load error message
	call	prtmsg	    ; Print error message
	jmpr	findden	    ; and ask again.
stodens:mov	A,B
	sta	DENSbyt	    ; Store flop dens code.
	lxi	H,26*128    ; set BUFLEN for sing dens
	jrz	..0	    ; 0 is sing density
	lxi	H,26*256    ; set BUFLEN for doub dens
..0:	shld	BUFLEN

; Get the test disks.
findTD:	lxi	H,tstmsg  ; 'Test Disk:' msg
	call	prtmsg
	lxi	H,TstUnits ; List of Units to test
..1:	push	H	  ; Save the list addr
	lxi	H,dskQST  ; ask which disk
	call	prtmsg
	call	getdsk	  ; get a disk number to test
			  ; FF returned = car ret
	pop	H
	mov	M,A	  ; Meanwhile load in disk num
	inx	H	  ; And get to next list addr.
	cpi	0FFh	  ; More units?
	jrz	..3	  ; No. All data collected.
	sta	DSKNAME	  ; store latest valid disk nam
	mvi	B,2
	push	H
	call	chaMAPbyt ; Select latest disk
	pop	H
	jmpr	..1	  
;
;
..3:	lxi	H,crlf
	call	prtmsg	  ; Space down
; Build a linear table.
	lxi	H,lintab  ; build a linear table
	lxi	B,76<8+1
	call	FILLTAB
	lxi	H,wrtab	  ; build pseudo random table
	lxé	B,76<8+21
	call	FILLTAB
	lxi	H,rdtab	  ; build pseudo random table
	lxi	B,76<8+31
	call	FILLTAB
; Print a command summary.
	call	waitcr	  ; wait for a cr
	lxi	H,HELPmsg
	call	prtmsg	  ; print command summary
	lxi	H,crlf
	call	prtmsg	  ; and space down a line
; Start the test.
	call	TEST
.page
;******************************************
;*   PRE-TEST messages and subroutines    *
;******************************************

exit:	lxi	H,exitMSG ; print exit message
	call	prtmsg
	call	resMAPbyt ; Restore original disk.
	jmp	0	  ; WBOOT

errexit:
	push	H	  ; save err msg address
	mvi	A,0
	sta	errflg	  ; turn off error flag
	call	prtmsg
	pop	H
..1:	call	prtsum
	jmpr	..1
;----------
; Fill a table (b=length, c=increment)
FILLTAB:
	mvi	A,1	; start at 1
	mov	D,B	; save length
..1:	mov	M,A	; put into memory
	add	C	; add the increment
	cmp	D	; test for overflow
	jm	..2
	jrz	..2
	sub	D	; if so, get back into range
..2:	inx	H	; update HL
	djnz	..1	; loop until done
	ret

exitMSG:.asciz	[cr][lf]'EXIT FDTEST'[cr][lf]
dskerr:	.asciz	[cr][lf]'Cannot access disk.'
denmsg:	.ascii	[cr][lf]'Test in Single or Double '
	.asciz	'density? (S/D) '
tstmsg:	.ascii	[cr][lf]'Test which drives? (Carria'
	.asciz	'ge return to terminate)'[cr][lf]
errmsg:	.ascii	[cr][lf]'Incorrect Entry. '
	.asciz	' Please try again.'[cr][lf]
; Header for the CP/M file which will hold errors.
hdfile:	.ascii	[cr][lf]'FLOPPY DISK SUMMARY FILE'
	.ascii	'                                '
	.ascii	[cr][lf]'****** **** ******* ****'
	.ascii	'                                '
	.asciz	'        '[cr][lf]'  '

.page
;----------
; TEST the disk
TEST:
	mvi	A,0
	sta	fixflg	; flag: fixed pattern off
	mvi	A,1	; start test at loop 1
tstloop:sta	LOOPS	; store it away
	rlc
	sta	RANSEED	; calculate first seed
	call	loopsum

;Write and test in a linearly-written pattern
tststrt:lxi	H,wrlnMSG ; first write linearly
	shld	dskfunc	  ; save current function
	call	prtmsg
	lxi	H,lintab
	call	wrtest
	lxi	H,rdlnMSG ; then read linearly
	shld	dskfunc	  ; save current function
	call	prtmsg
	lxi	H,lintab
	call	rdtest
	lxi	H,rdrnMSG ; then read randomly
	shld	dskfunc	  ; save current function
	call	prtmsg
	lxi	H,rdtab
	call	rdtest

	lda	RANSEED	; change the seed
	inr	A
	sta	RANSEED

;Write and test a randomly-written pattern
	lxi	H,wrrnMSG ; next, write randomly
	shld	dskfunc   ; save current function
	call	prtmsg
	lxi	H,wrtab
	call	wrtest
	lxi	H,rdrnMSG ; then read randomly
	shld	dskfunc	  ; save the current function	
	call	prtmsg
	lxi	H,rdtab
	call	rdtest
	lxi	H,rdlnMSG ; then read linearly
	shld	dskfunc	  ; save current function
	call	prtmsg
	lxi	H,lintab
	call	rdtest

;Write and test the worst byte in a fixed pattern
	sta	fixflg	; set fixed pattern flag
	lxi	H,wrwrstMSG ; write worst byte linearly
	shld	dskfunc	    ; save current function
	call	prtmsg
	lxi	H,lintab
	call	wrtest

	lxi	H,rdlnMSG ; then read linearly
	shld	dskfunc	  ; save current function
	call	prtmsg
	lxi	H,lintab
	call	rdtest
	mvi	A,0
	sta	fixflg	; turn off fixed pattern

	lda	LOOPS
	inr	A
	jmp	tstloop	  ; read and write again

loopsum:
	lxi	H,loopMSG ; print the loop message
	call	prtmsg
	lda	LOOPS
	call	prtA
	lxi	H,space5
	call	prtmsg
	call	prttime	  ; print the time & date
	ret

initMSG:.ascii	' Floppy Disk Test '
	.byte	version+'0','.'
	.byte	revision/10+'0',revision@10+'0'
	.ascii	' for the DSC3 and DSC4'
	.asciz	[cr][lf][lf]
dskQSTº .asciú	'Disë Number (°-7© º '
loopMSG:.asciz	'LOOP '
wrlnMSG:.asciz	'Writing linearly.'[cr][lf]
rdlnMSG:.asciz	'Reading linearly.'[cr][lf]
wrrnMSG:.asciz	'Writing randomly.'[cr][lf]
rdrnMSG:.asciz	'Reading randomly.'[cr][lf]
wrwrstMSG: .ascii 'Writing '
wbchr1:	.byte	'0'	; worst byte chr 1
wbchr2:	.byte	'0'	; worst byte chr 2
	.asciz	'h fixed.'[cr][lf]
.page
;-----------
; Subroutine:	wrtest
;
; This subroutine supervises the write procedure.
; A list of units under test is stored at TstUnits.
; The list is terminated by an FFh.
wrtest:
	shld	wrparameter	; Save test parameter
; First we check that indeed there are units to test
	lxi	H,TsTUnits	; Get addr of test list
	mvi	B,0		; Zero out register B
..test:	mov	A,M
	inx	H		; Get to next list addr
	cpi	0FFh		; End of list?
	jrz	..check		; Yes.
	cpi	80h		; Is this Logged out?
	jrz	..test		; Yes. Keep looking
	mvi	B,0FFh		; No. Set flag in B
..check:mov	A,B		; Check for flag
	cpi	0FFh		; Is it set?
	lxi	H,TermLOG	; Get err msg ready
	jnz	errexit		; No. Die.

; At least one unit is logged in. Proceed with test.
	lxi	H,TstUnits
..wr1:	mov	A,M		; Get unit num to test
	inx	H		; and get next list addr
	cpi	0FFh		; Is this last unit?
	rz			; Yes.  Return.
	cpi	80h		; Is unit logged out?
	jrz	..wr1		; Yes. Get the next one
	push	H		; No. Save unit addr
	sta	DSKNAME		; No. Save unit num
	mvi	B,2		; Write thru CP/M 'C'
	call	chaMAPbyt	; Select that unit
	lhld	wrparameter	; Restore test paramtr
	call	wr1unit		; Write to that unit,
	pop	H		; Restore unit address
	jmpr	..wr1		; and write again.
;----------
; Write tracks from table
wr1unit:
	push	H	; save HL
	call	HOME	; home the disk
	pop	H	; restore HL
	mvi	B,76	; table has 76 entries
..1:	push	B	; save BC and HL
	push	H	
	mov	A,M	; get track from table
	sta	TRACK	; store in track
	call	wrtrk	; write it
	cnz	wrerr	; check for errors
	pop	H	; restore BC and HL
	pop	B
	inx	H	; update HL
	djnz	..1	; repeat until no more tracks
	ret

;-----------
; Subroutine:	rdtest
;
; This subroutine supervises the read procedure and
; reads from each unit under test.
; A list of units under test is stored at TstUnits.
; The list is terminated by an FFh.
rdtest:
	shld	rdparameter	; Save test parameter
; First we check that indeed there are units to test
	lxi	H,TsTUnits	; Get addr of test list
	mvi	B,0		; Zero out register B
..test:	mov	A,M
	inx	H		; Get to next list addr
	cpi	0FFh		; End of list?
	jrz	..check		; Yes.
	cpi	80h		; Is this Logged out?
	jrz	..test		; Yes. Keep looking
	mvi	B,0FFh		; No. Set flag in B
..check:mov	A,B		; Check for flag
	cpi	0FFh		; Is it set?
	lxi	H,TermLOG	; Get err msg ready
	jnz	errexit		; No. Die.
; At least one unit is logged in. Proceed with test.
	lxi	H,TstUnits
..rd1:	mov	A,M		; Get unit num to test
	inx	H		; Get to next list addr
	cpi	0FFh		; Is this last unit?
	rz			; Yes.  Return.
	cpi	80h		; Is unit logged out?
	jrz	..rd1		; Yes. Get another one.
	push	H		; No. Save unit addr
	sta	DSKNAME		; No. Save unit num
	mvi	B,2		; Write thru CP/M 'C'
	call	chaMAPbyt	; Select that unit
	lhld	rdparameter	; Restore test paramtr
	call	rd1unit		; Write to that unit
	pop	H		; Restore list addr
	jmpr	..rd1		; and write again.

;----------
; Read tracks from table and test.
rd1unit:
	push	H	; home the disk
	call	HOME
	pop	H
	mvi	B,76	; the table has 76 entries
..1:	push	B	; save BC and HL
	push	H
	mov	A,M	; store table number from table
	sta	TRACK
	lxi	H,wrbuffer ; fill the wrbuffer for
	lbcd	BUFLEN	; compares
	call	FILLPAT
	call	rdtrk	; read 3 times and check for
	jrnz	..2	; errors
	call	rdtrk
	jrnz	..2
	call	rdtrk
	jrz	..3
..2:	call	rderr	; error has occured
..3:	pop	H	; restore BC and HL
	pop	B	
	inx	H	; update HL
	djnz	..1	; repeat until no more tracks
	ret
.page
; A non-zero accumulator has been returned from wrtrk 
; or rdtrk.  This number is an offset into the BIOS.
; We use it as an offset into our error table. Error
; flages are turned on, our current function (read or
; write) is saved in ERRtry,and we read in and save the
; NEC765 Error buffer (saved in the BIOS) and print
; it out.

;----------
; Write and Read Error Routines
wrerr:
	push	PSW	; save error code
	lxi	H,wrtrk ; set up retry address
	shld	ERRtry
	mvi	A,0FFh	; turn on err flag
	sta	errflg
	lxi	H,wrerMSG ; print error message
	call	prtmsg
	lda	DSKNAME
	adi	'0'
	sta	sumAnm
     	lxi	H,sumA
	call	prtmsg	; print 'DISK' and disk number
	lxi	H,sumAtrk
	call	prtmsg
	lda	TRACK	; print track number
	call	prtA
	jmpr	errrtn	; jump to common section

rderr:
	push	PSW	; save error code
	lxi	H,rdtrk	; set up retry address
	shld	ERRtry
	mvi	A,0FFh	; turn on err flag
	sta	errflg
	lxi	H,rderMSG ; print error message
	call	prtmsg
	lda	DSKNAME
	adi	'0'
	sta	sumAnm
     	lxi	H,sumA
	call	prtmsg	; print 'DISK' and disk number
	lxi	H,sumAtrk
	call	prtmsg
	lda	TRACK	; print track number
	call	prtA

; Print out the current function (Writing linearly,
; Reading randomly, etc)
; Print out the NEC765 Flop Controller Chip
; 16 chr buffer (kept in BIOS).
; Restore error offset value (returned from
; BIOS during Read/Write) and use it to jump
; to appropriate location in the error table.
errrtn:
	lxi	H,space5
	call	prtmsg	   ; space over 5
	call	prttime	   ; and print the time

	lhld	WBOOT
	lxi	D,0A0h-3
	dad	D	   ; HL = Bios command buf addr
	lxi	D,BIOSbuf  ; DE = Our buf holder
	lxi	B,16	   ; BC = num of bytes to copy
	LDIR		   ; Load in NEC765 err buf
	lxi	H,BIOSbuf  ; into our buffer.
	call	prt16	   ; Print 16 byte NEC buffer
	pop	PSW	   ; restore error offset numb

	lxi	H,errtab-3 ; jump to appropriate
	mov	E,A	   ; routine
	mvi	D,0
	dad	D
	pchl

wrerMSG:.asciz	[cr][lf]' WRITE ERROR '
rderMSG:.asciz	[cr][lf]' READ ERROR '

errtab:
	jmp	SEEKerr
	jmp	SYNCerr
	jmp	DATAerr
	jmp	TRACerr
	jmp	ENDTerr
	jmp	IDerr
	jmp	ORUNerr
	jmp	SECTerr
	jmp	PROTerr
	jmp	DENSerr
	jmp	MADRerr
	jmp	IOerr
	jmp	COMPerr

SEEKerr:
	lxi	H,seekMSG ; Track error
	jmp	Ttypeerr
seekMSG:.asciz	'ERROR: equipment check '

SYNCerr:
	lxi	H,syncMSG ; Chip and BIOS out of sync
	jmp	errexit	  ; Terminal error
syncMSG:.asciz	'SYNC error - CPU and FDC out of sync '

DATAerr:
	lxi	H,dataMSG ; Sector type error
	jmp	Stypeerr
dataMSG:.asciz	'DATA CRC error '

TRACerr:
	lxi	H,tracMSG ; Track type error
	jmp	Ttypeerr
tracMSG:.asciz	'TRAC error - head over wrong cylinder '

ENDTerr:
	lxi	H,endtMSG ; DMA type error
	jmp	Dtypeerr
endtMSG:.asciz	'ENDT error - read beyond end of cylinder '

IDerr:
	lxi	H,idMSG	; Sector type error
	jmp	Stypeerr
idMSG:	.asciz	'ID CRC error '

ORUNerr:
	lxi	H,orunMSG ; DMA type error
	jmp	Dtypeerr
orunMSG:.asciz	'DMA ORUN - controller not seviced in time '

SECTerr:
	lxi	H,sectMSG ; Sector type error
	jmp	Stypeerr
sectMSG:.asciz	'SECT error - Cannot find sector '

PROTerr:
	lxi	H,protMSG ; Write protected
	call	prtmsg	; print a message
	jmp	start	; and restart
protMSG:.asciz	'PROT error - disk write-protected. RESTART'[cr][lf]

DENSerr:
	lxi	H,densMSG ; Track type error
	jmp	Ttypeerr
densMSG:.asciz	'DENS error - wrong density (missing ID address mark) '

MADRerr:
	lxi	H,madrMSG ; Track type error
	jmp	Ttypeerr
madrMSG:.asciz	'MADR error - missing data address mark '

IOerr:
	lxi	H,ioMSG	; Undefined error assume
	jmp	Ttypeerr ; Track type error
ioMSG:	.asciz	'INDETERMINABLE error: '

COMPerr:
	lxi	H,compMSG ; Sector type error
	jmp	Stypeerr
compMSG:.asciz	'COMPARE error: '

;----------
; TRACK type error
Ttypeerr:
	call	prtmsg	   ; print callers message
	lxi	H, Terrors ; 
	call	incerr	   ; update Track errors
	lxi	B,retry<8 ; retry the I/O
..1:	push	B
	call	HOME	; rehome then retry
	call	rdwrtrk
	pop	B
	jz	..2	; retry a fixed number of times
	inr	C
..2:	djnz	..1	; and see how many were ok
	mov	A,C	; save the answer
	cpi	retry
	jz	badtrack ; if none then bad track
	call	ratioc	 ; otherwise print ratio
	push	PSW	 ; Save OK retry attempts
	lxi	H,CUR2msg  ; 'Current function: ' msg
	call	prtmsg
	lhld	dskfunc	   ; The cur func msg addr
	call	prtmsg	
	mvi	A,0
	sta	errflg	; turn off the err flag
	call	putEOF
	pop	PSW	; Restore OK retry attempts
	ret		; and return

Stypeerr:
	call	prtmsg	  ; print callers message
	call	HOME	  ; rehome the disk
	lxi	H,Serrors ; update Terrors
	call	incerr
	lxi	B,retry<8 ; retry the I/O
..1:	push	B
	call	rdwrtrk	; just retry
	pop	B
	jrz	..2	; retry a fixed number of times
	inr	C
..2:	djnz	..1	; and see how many were ok
	mov	A,C	; save the answer
	cpi	retry
	jz	badtrack ; if none then bad track
	call	ratioc	 ; otherwise print ratio
	push	PSW	 ; Save OK retry attempts
	lxi	H,CUR2msg  ; 'Current function: ' msg
	call	prtmsg
	lhld	dskfunc	   ; The cur func msg addr
	call	prtmsg	
	mvi	A,0	; turn off the err flag
	sta	errflg
	call	putEOF
	pop	PSW	; restore OK retry attempts
	ret		; and return

Dtypeerr:
	jmpr	Stypeerr ; just call is a Sector error

badtrack:
	lxi	H,badtMSG ; print bad track message
	call	prtmsg
	lda	TRACK
	call	prtA	  ; print bad track number
	lxi	H,bad1MSG ; print next part of msg
	call	prtmsg
	mvi	A,retry
	call	prtA	  ; print amount of retries	
	lxi	H,bad2MSG ; print last part of msg
	call	prtmsg
	lxi	H,CUR2msg  ; 'Current function: ' msg
	call	prtmsg
	lhld	dskfunc	   ; The cur func msg addr
	call	prtmsg	
	mvi	A,0
	sta	errflg	  ; turn off error flag
	call	putEOF	  ; and mark end of buffer
	ret

badtMSG:.asciz	[cr][lf]'BAD TRACK FOUND: TRACK '
bad1MSG:.asciz	' FAILED ALL '
bad2MSG:.asciz	' RETRY ATTEMPTS.'[cr][lf]

;----------
; Subroutine: 	incerr
; Regs in:	HL = addr of error list
; Increment the error count and log out the
; disk from the test list if it shows FF errors.
; We use the disknumber (DSKNAME) as an offset
; into the list.
incerr:
	lda	DSKNAME	  ; get current disk
	mvi	D,0
	mov	E,A	  ; DE = current disk number
	dad	D	  ; HL = Byte addr in error
			  ; list used by current disk.
	mov	B,M	  ; B = S or T errors on disk
	inr	B	  ; so far.
	lda	maxerrs	  ; Get max allowable errors
	cmp	B	  ; max errs-current errs <= 0?
	jrc	..1	  ; Yes. Overflow. Log drv out.
	jrz	..1	  ; Yes. Overflow. Log drv out.
	inr	M	  ; No. Increment error count
	ret		  ; and return.

; Log out the present disk due to error overflow
..1:
	lxé	H,oflowMSÇ 
	call	prtmsg	     ; print overflow message
	mvi	A,0	     ; and turn off error flag
	sta	errflg
	call	putEOF
	lxi	H,TstUnits-1 ; get test list addr
	lda	DSKNAME	 
	mov	B,A	  ; get current disk name in B
..loop: inx	H	  ; get to next list addr
	mov	A,M	  ; get disk name from list
	cpi	0FFh	  ; end of list?
	jz	tststrt	  ; Yes. Restart main test loop
	sub	B	  ; A = A - B
	cpi	0	  ; Are list entry and dsk name
			  ; identical?
	jrnz	..loop	  ; No. Keep looking for match
	mvi	M,80h	  ; Yes Log out that disk
	jmpr	..loop	  ; and look for another match.

	oflowMSG:
	.ascii	[cr][lf]'ERROR OVERFLOW - LOGGING'
	.asciz	' OUT DISK'[cr][lf]

rdwrtrk:
	lhld	ERRtry	; load correct call address
	pchl		; and go there

;----------
; Subroutine : 	prtdki
; Regs  in:	none
; Regs out:	none
; Print the summary of all units under test.
prtdki:
	mvi	A,0	  ; Make error flag is
	sta	errflg	  ; off during summary.
	lxi	H,FDmsg	  ; Print 'FDTEST' and
	call	prtmsg	  ; space down a line.
	call	loopsum	  ; print out the time & date
	lxi	H,TstUnits
..prt1:	mov	A,M	  ; Get entry in list
	inx	H	  ; Get to next addr
	cpi	0FFh	  ; End of table?
	jz	prtcur	  ; Yes. Print current function
	cpi	80h	  ; Is unit logged out?
	push	PSW	  ;----
	push	H
	lxi	H,LOGoutMSG
	cz	prtmsg	  ; Print logged out message
	pop	H	  ; IF unit is logged out.
	pop	PSW	  ;----
	jrz	..prt1	  ; Yes. Skip it.
	sta	tmpDSK	  ; No. Valid unit name found.
	push	H	  ; Save table addr
	call	prt1unit  ; Print out that units info.
	pop	H
	jmpr	..prt1	  ; Print next units info.


; Print the summary for one unit
prt1unit:
	lda	tmpDSK    ; print disk name
	adi	'0'	  ; make it ascii
	sta	sumAnm
	lxi	H,sumA
	call	prtmsg
	lxi	H,sumB
	call	prtmsg
	lxi	H,Serrors
	lda	tmpDSK
	mvi	D,0
	mov	E,A
	dad	D
	mov	A,M	; A = Sector errors on cur disk
	call	prtA	; Print A
	lxi	H,sumC
	call	prtmsg
	lxi	H,Terrors
	lda	tmpDSK
	mvi	D,0
	mov	E,A
	dad	D
	mov	A,M	; A = Track errors on cur disk
	call	prtA	; Print A
	lxi	H,crlf
	call	prtmsg	; Space down a line.
	ret

LOGoutMSG:
	.ascii	'** THE UNIT HERE WAS LOGGED '
	.asciz	'OUT DUE TO ERROR OVERFLOW. **'[cr][lf]
TermLOGout:
	.asciz	'** ERROR OVERFLOW ON ALL DRIVES **'
FDmsg:	.ascii	[cr][lf]' FDTEST VER '
	.byte	version+'0','.'
	.byte	revision/10+'0',revision@10+'0'
	.asciz	'    '
CUR1msg:.asciz	'Currently Testing: '
CUR2msg:.asciz	'Current Function : '
sumA:	.ascii	'DISK: '
sumAnm:	.asciz	'X'
sumAtrk:.asciz	', track: '
sumB:	.asciz	', R/W ERRORS: '
sumC:	.asciz	', TRACK ERRORS: '

; Print the summary for the unit currently under test.
prtcur:
	lxi	H,CUR1msg
	call	prtmsg	 ; Print current info header
	lda	DSKNAME  ; print disk name
	adi	'0'	  ; make it ascii
	sta	sumAnm
	lxi	H,sumA
	call	prtmsg
	lxi	H,sumAtrk
	call	prtmsg
	lda	TRACK
	call	prtA
	lxi	H,crlf
	call	prtmsg	; Space down.
	lxi	H,CUR2msg
	call	prtmsg
	lhld	dskfunc	; current disk function
	call	prtmsg
	lxi	H,crlf
	call	prtmsg	; Space down a line.
	ret		; And finally return.

prtsum:
	call	CONST	; has a char been read?
	cpi	0FFh	; if not return
	rnz
	call	CONIN	; else get it
	cpi	'F'	; Fixed test wanted?
	jz	FIXTEST ; Yes.
	cpi	'R'	; R? print the error buffer?
	jrnz	..1
	call	prtbuf  ; if 'R' then print error buf
	ret
..1:	cpi	'S'	; is it an 'S' (summary?)
	jrnz	..2
	call	prtdki	; if 'S' then print disk status
	ret
..2:	cpi	'T'	; If 'T' get new test disks
	jrz	..4	; Clear err counters and restrt
	cpi	'Q'	; Is it a 'Q'? (quit)
	jrnz	..3	; if not prt help msg & return
	lxi	H,verMSG ; verify
	call	prtmsg
	call	CONIN
	sta	retdsk
	lxi	H,retMSG ; print answer
	call	prtmsg
	lda	retdsk	; restore A
	cpi	'Y'	; is answer yes?
	rnz
	jmp	exit
..3:			; Bad entry. Print HELP message
	lxi	H,HELPmsg
	call	prtmsg
	ret
..4:	mvi	A,0ffh
	sta	errflg
	lxi	H,tmsg
	call	prtmsg
	mvi	A,0
	sta	errflg
	call	puteOF
	jmp	clrERR
tmsg:	.asciz  [cr][lf][cr][lf]'     **************     '
verMSG:	.asciz	'EXIT FDTEST (Y/N)? '

ratioc:
	push	B	; save C
	lxi	H,..A
	call	prtmsg	; print ratio message
	pop	B	; restore C
	mov	A,C	; into A
	call	prtA	; and print it
	lxi	H,..B	; and print the rest of the
	call	prtmsg	; message
	mvi	A,retry
	call	prtA
	lxi	H,..C
	call	prtmsg
	ret
..A:	.asciz	[cr][lf]'Retry Failures: '
..B:	.asciz	' out of '
..C:	.asciz	'.'[cr][lf]

;----------
; Write a single track
wrtrk:
	call	prtsum	; print summary if requested
	lxi	H,wrbuffer ; fill wrbuffer pattern
	lbcd	BUFLEN
	call	FILLPAT
	lda	DSKNAME
	mvi	B,2
	call	chaMAPbyt
	lda	TRACK
	mov	C,A	; first track
	call	SETTRK
	mvi	C,1	; then sector
	call	SETSEC
	lxi	B,wrbuffer
	call	SETDMA	; then buffer address
	lbcd	BUFLEN
	call	SETBYT	; and finally buffer length
	call	WRITE	; write the buffer
	cpi	36	; check for errors
	jm	..0
	mvi	A,36	; any out of range are ?
..0:	ora	A
	ret

;----------
; Read a track and compare
rdtrk:
	call	prtsum	; print summary if requested
	lda	DSKNAME
	mvi	B,2
	call	chaMAPbyt
	lda	TRACK	; set up bios calls
	mov	C,A	; first track
	call	SETTRK
	mvi	C,1	; then sector
	call	SETSEC
	lxi	B,rdbuffer ; then buffer address
	call	SETDMA
	lbcd	BUFLEN	; finally buffer length
	call	SETBYT	
	call	READ	; and read the track
	cpi	36	; check for errors
	jm	..1
	mvi	A,36	; any out of range are ?
..1:	ora	A
	rnz
	call	COMPARE	; and compare the data
	ret

;----------
; Compare read and write buffers
COMPARE:
	lxi	H,rdbuffer
	lxi	D,wrbuffer
	lbcd	BUFLEN
..1:	ldax	D	; get byte at (DE)
	cmp	M	; compare with byte at (HL)
	jrnz	..2	; check for error !!!
	inx	H	; update HL and DE
	inx	D
	dcx	B	; check for end of compare
	mov	A,C
	ora	B
	jrnz	..1	; loop back for more
	ret
..2:	mvi	A,39	; compare error is 39 in table
	ret

;----------
; Fill buffer with a pattern (random or fixed)
; HL = Buffer address, BC = number of bytes to fill
FILLPAT:
	lda	fixflg	
	cpi	0FFh	; fixed pattern desired?
	jz	FIXFILL ; use second routine
	lda	RANSEED	; seed with ranseed and track
	rlc
	rlc
	rlc
	mov	D,A
	lda	TRACK
	add	D
..1:	mov	M,A	; write byte to memory
	adi	2Fh	; get next random #
	xri	0D1h
	rrc
	mov	D,A	; save random #
	inx	H	; update HL
	dcø	B	; and BC
	mov	A,C	; test for end of loop (BC=0)
	ora	B
	mov	A,D	; restore random # to A
	jrnz	..1	; and loop
	ret
;fill entire buffer with 'wrstbyt'
FIXFILL:
	lda	wrstbyt
	mov	M,A       ; put worst byte into buf
	inx	H	  ; get to next buf addr
	dcx	B
	mov	A,C
	cpi	0	  
	jrnz	fixfill	  ; loop back
	mov	A,B
	cpi	0
	jrnz	fixfill	  ; loop back 
	ret
.page
;*******************************************
;*                                         *
;*      FIXED TRACK TESTING SECTION        *
;*					   *
;*******************************************

fixmsg:	.ascii	[cr][lf]'FDTEST fixed track '
	.ascii	'Read/Write Option'[cr][lf][lf]
	.ascii	' This sub-program allows interact'
	.ascii	'ive R/W testing on a single track.'
	.ascii	'  All'[cr][lf]'Writes use only the'
	.ascii	' fixed pattern byte; '
	.ascii	"displayed during 'Writing XXh fixed'."
	.ascii	[cr][lf]'After each Read or Write is '
	.ascii	'executed, a hex number is printed to'
	.ascii	' the console.'[cr][lf]
	.ascii	'The number will be 0 if no errors are'
	.ascii	' detected, or it will be the offset '
	.ascii	'into'[cr][lf]'the FDTEST error table.'
	.ascii	'  In the event the number is not a 0, '
	.ascii	'the 16 byte NEC765'[cr][lf]'Floppy con'
	.ascii	'troller error buffer will be'
	.ascii	' displayed.'
	.asciz	[cr][lf][lf]
offmsg:	.ascii	[cr][lf]'The buffer-to-disk write'
	.ascii	' is temporarily disabled.'
	.asciz	[cr][lf]
contmsg:.asciz	[cr][lf]'Wish to continue? (Y/N) '
commsg:	.ascii	[cr][lf][lf]
	.ascii	'  Commands are:    R - Read and test'
	.ascii	[cr][lf]
	.ascii	'                   W - Write and test'
	.ascii	[cr][lf]
	.ascii	'                   S - Summary'
	.ascii	[cr][lf]
	.ascii	'                   T - Test a new '
	.ascii	'track'[cr][lf]
	.ascii	'                   D - Done, resume '
	.ascii	'regular testing'[cr][lf]
	.ascii	'                   X - Done, eXit to'
	.asciz	' system.'[cr][lf][lf]
fxRDmsg:.asciz	' Fixed Track Reading.'[cr][lf]
fxWRmsg:.asciz	' Fixed Track Writing.'[cr][lf]

tmpflg:	.byte	00
fxtrack:.byte	00
fxdisk:	.byte	00

; Inform user he has selected fixed track testing.
FIXTEST:
	lxi	H,fixmsg
	call	prtmsg  ; Tell user he's in fixed mode
	lxi	H,contmsg
	call	prtmsg	; Ask user if he wants to cont
..0:	call	CONIN	; Get console chr
	push	PSW
	sta	retdsk
	lxi	H,retMSG
	call	prtmsg	; Echo the chr
	pop	PSW
	cpi	'N'	; Chickened out?
	rz		; Yes. Resume testing.
	cpi	'Y'	; Brave?
	jrz	fxstart	; Yes. Start initialization
	lxi	H,errmsg
	call	prtmsg	; Wrong entry. Print message
	jmpr	..0	; and ask again.

; Initialize. Save users current disk-write option.
; Disable disk-write option if enabled. Set fixed
; pattern flag. (used in FILLPAT by wrtrk/rdtrk.
fxstart:mvi	A,0FFh
	sta	fixflg  ; Set fixed pattern write flag
	jmpr	..1	; get test info

..dskmsg:
	.asciz	[cr][lf]'Input disk number to test :'
..trkmsg:
	.ascii	[cr][lf]'Input track number'
	.asciz	' to test (in hex) and <CR> :'
..rdymsg:
	.asciz	[cr][lf]'Enter first command '

; Get disk and track number to test.
..1º	lxé	H,..dskmsg
	call	prtmsg
	call	getdsk
	lxi	H,errmsg
	cpi	0FFh	; Just carriage return?
	cz	prtmsg	; Yes. Print error message
	jrz	..1	; and ask again.
	sta	DSKNAME	; No. Its valid. Store it.
..2:	lxi	H,..trkmsg
	call	prtmsg
	call	putBUF	; Get ascii chrs in conbuf
; A = length of users chr string.
	lxi	H,errmsg; Get error message ready
	cpi	0	; Just carriage return?
	cz	prtmsg	; Yes. Print error message
	jrz	..2	; and ask again.
	call	makHBYT	; No. Make chrs into a byte.
	sta	TRACK	; Store it as the track.
	lxi	H,commsg	
	call	prtmsg	; Print command summary
	lxi	H,..rdymsg
	call	prtmsg	; Tell user to input first
			; command.
..wait:	call	readCON	; Wait for the first command
	jmpr	..wait

;----------
; All data collected for FIXTEST
;----------
	
readCON:
	call	CONST	; Check for console input
	cpi	0FFh	; Console chr ready?
	rnz		; No. Resume to rding/wrting
	call	CONIN	; Yes. Read the chr.
	push	PSW
	sta	retdsk
	lxi	H,retmsg
	call	prtmsg	; Echo the character to console
	pop	PSW

	cpi	'R'	; Read and test?
	jrnz	..Wchk	; No. Check for W
	lxi	H,fxRDmsg
	shld	dskfunc ; Put cur func in summary
	jmp	fxread

..Wchk:	cpi	'W'	; Write and test?
	jrnz	..Schk	; No. Check for S
	lxi	H,fxWRmsg
	shld	dskfunc	; Put cur func in summary
	jmp	fxwrite

..Schk:	cpi	'S'	; Summary wanted?
	jrnz	..Dchk	; No. Check for D
	call	prtcur	; Yes. Print it 
	ret		; and return.

..Dchk:	cpi	'D'	; Done?
	jrz	fxreturn

	cpi	'T'	; Test New track?
	jz	fxstart

	cpi	'X'	; Abort test?
	jrz	fxabort

; Invalid chr entered.
	lxi	H,commsg;Bad entry. Print
	call	prtmsg	;help summary
	jmp	readCON	;and return.

;----------
; Fixed test operating routines
fxwrite: 
	lxi	H,lintab
	call	wrtrk	; 0 = AOK write
	push	PSW	; Save error code
	call	prtA	; Print 00 console
	mvi	C,' '	; and space over.
	call	CONOUT
	pop	PSW
	cpi	00	; Did write go OK?
	cnz	fxprtbuf; No. Print NEC error buffer
	call	readCON	; Check for new con command
	jmpr	fxwrite	; Write again and again....

fxread:
	lxi	H,lintab
	call	rdtrk
	push	PSW	; Save error code
	call	prtA	; Print 00 console
	mvi	C,' '	; and space over.
	call	CONOUT
	pop	PSW
	cpi	00	; Did write go OK?
	cnz	fxprtbuf; No. Print NEC error buffer
	call	readCON	; Check for new con command.
	jmpr	fxread	; Read again and again....

fxabort:jmp	exit

fxreturn:
	lxi	H,..rtnMSG
	call	prtmsg	; Tell user were leaving
	lxi	sp,stack; Re-initiate stack
	jmp	clrERR	; Restart FDTEST

..rtnMSG:
	.ascii	[cr][lf][lf]
	.asciz	'Returning to FDTEST'[cr][lf][lf]
conbuf:	.byte	5		    ; CPM buffer length
	.byte	20h,20h,20h,20h,20h ; CP/M buffer space

;--------------
; Fixtest Subroutines
;

;---------
; Subroutine: fxprtbuf
; Load the NEC765 Flop Cont Chip Error buffer
; into memory and print it out.
fxprtbuf:
	lhld	WBOOT
	lxi	D,0A0h-3
	dad	D	   ; HL = Bios command buf addr
	lxi	D,BIOSbuf  ; DE = Our buf holder
	lxi	B,16	   ; BC = num of bytes to copy
	LDIR		   ; Load in NEC765 err buf
	lxi	H,BIOSbuf  ; into our buffer.
	call	prt16	   ; Print 16 byte NEC buffer
	ret

;----------
;		Subroutine: makHBYT
; Regs  in:	A=length of console buffer
; Regs out:	A=hex byte made from console buffer
;Destroyed:	HL,A,B,C
;Make a hex byte from one or two buffer chrs
makHBYT:
	cpi	1	   ; just one chr?
	mvi	B,0
	lxi	H,conbuf+2 ; load 1st chr addr
	jrz	..a1	   ; process 1st chr only
;multiply first chr by 16 and save in B
	mov	A,M	; get 1st chr
	inx	H	; get to next chr
	cpi	'A'
	jrc	..a2
	ani	0DFh	; make all letters upper case
	sui	'A'-'9'-1
..a2:	sui	'0'
	cpi	0
	jrz	..a1	; skip mult if nibble is 0
	ora	A	; reset carry flag
	rlc
	rlc
	rlc
	rlc
	mov	B,A	;save 16*firstnumber in B
..a1:	mov	A,M	; get 2nd chr
	cpi	'A'
	jm	..a3
	ani	0DFh	; make all letters upper case
	sui	'A'-'9'-1
..a3:	sui	'0'
	ora	A	; reset the flags
	add	B	; add the two chrs
	ret

;----------
;		Subroutine: putBUF
; Regs  in:	HL=address of message to print
; Regs out:	A =number of chrs put in buffer
;Destroyed:
;Put console input in a buffer
putBUF:
	mvi	C,bufread
	lxi	D,conbuf
	call	BDOS	 ; put console input in buffer
	lxi	H,conbuf+1
	mov	A,M	 ; put num of buffer chrs in A
	ret

.page
;************************************************
;*						*
;*   CONSOLE I/0 SUBOUTINES AND BIOS PRIMITIVES *
;*						*
;************************************************
;----------
; Get disk name, return 0FFh if cr
getdsk:
	call	CONIN	; get a char
	cpi	cr	; Carriage return?
	jrz	..3	; Yes. Handle it specially.
	cpi	'8'	; Is it legal?
	jrnc   	getdsk	; No. Fetch next chr.
	cpi	'0'	; Is it legal?
	jrc	getdsk	; No. Fetch next chr.

..2:	push	PSW	; save the char
	sta	retdsk	; echo char then crlf
	lxi	H,retMSG
	call	prtmsg
	pop	PSW	; restore PSW
	sui	'0'	; get disk select number
	ret

..3:	mvi	A,0FFh	; Put flag into reg A
	ret

;----------
; Get CP/M disk name (A, B, C, or D) from user
;
getCPMdsk:
	call	CONIN		; get console chr
	cpi	3		; Is chr a ctrl-C?
	jz	exit		; Yes. Abort.
	cpi	'D'+1		; Is it too large?
	jrnc	getCPMdsk	; Yes. Fetch next chr
	cpi	'A'		; Is it too small?
	jrc	getCPMdsk	; Yes. Fetch next chr
	push	PSW		; No. Echo valid chr
	sta	retdsk
	lxi	H,retMSG
	call	prtmsg
	pop	PSW
	sui	'A'		; Make it 0,1,2, etc
	ret			; and return.


;----------
; Wait for a cr
waitcr:
	lxi	H,waitMSG ; print a message
	call	prtmsg
..1:	call	CONIN	; get a char
	cpi	cr	; loop if cr
	jrnz	..1
	lxi	H,crlfMSG ; print crlf
	call	prtmsg
	ret

;----------
; Print a message addressed by HL.
; Return on a null ( 00 ).  A null is automatically
; tagged onto the end of any '.asciz' command.
prtmsg:
	mov	A,M	; get next char
	ora	A
	rz		; return if zero
	push	H	; save HL
	mov	C,A	; output the char
	call	CONOUT
	pop	H	; restore HL
	inx	H	; increment to next char
	jmpr	prtmsg	; print it

retMSG:
retdsk:	.byte	'A'
crlfMSG:.asciz	[cr][lf]
waitMSG:.asciz	'Type RETURN '

;----------
; Print the A register as a hex number
prtA:
	push	PSW	; save A
	rlc		; get upper nibble
	rlc
	rlc
	rlc
	call	prtnib	; print it
	pop	PSW	; restore A
	call	prtnib	; print lower nibble
	ret
;----------
; Print a nibble
prtnib:
	ani	0Fh	; mask to get nibble
	cpi	10	; convert to ASCII
	jm	..1
	adi	7
..1:	adi	'0'
	mov	C,A
	call	CONOUT
	ret
;-----------
; Subroutine: prt16
; Print header and 16 chracters to the console.
; Used for printing out NEC765 BIOS error buffer.
; Regs  in:  	HL = address of 1st chr
prt16:	
	push	H
	lxi	H,Headmsg
	call	prtmsg
	pop	H
	mvi	A,16
..cnt:	push	PSW
	push	H
	mov	A,M
	call	prtA
	mvi	C,' '
	call	CONOUT
	pop	H
	inx	H
	pop	PSW
	dcr	A
	cpi	0
	jrz	..rest
	jmpr	..cnt
..rest: lxi	H,crlf
	call	prtmsg
	ret
headmsg: .asciz	'NEC765 Error Flag Buffer '
;----------
; Call bios directly using WBOOT in low memory
WBOOT	=	1

CONST:
	lhld	WBOOT
	lxi	D,03h
	dad	D
	pchl

CONIN:
	lxi	H,..1	; return to ..1
	push	H
	lhld	WBOOT
	lxi	D,06h
	dad	D
	pchl

..1:	cpi	3	; 3 is Control-C
	jz	exit	; Wboot if Control-C
	cpi	'a'	; make result UPPER CASE
	rc
	cpi	'z'+1
	rnc
	sui	'a'-'A'
	ret

CONOUT:
;The chr arrives in Reg C.
	lda	errflg	; is this part of an err msg?
	cpi	0FFh
	jrnz	chrout	; just output the chr
	call	wrtbuf	; put chr in error buffer (R)

chrout:	lhld	WBOOT
	lxi	D,09h
	dad	D
	pchl

HOME:
	lhld	WBOOT
	lxi	D,15h
	dad	D
	pchl
	
SELDSK:
	lhld	WBOOT
	lxi	D,18h
	dad	D
	pchl

SETTRK:
	lhld	WBOOT
	lxi	D,1Bh
	dad	D
	pchl

SETSEC:
	lhld	WBOOT
	lxi	D,1Eh
	dad	D
	pchl

SETDMA:
	lhld	WBOOT
	lxi	D,21h
	dad	D
	pchl

READ:
	lhld	WBOOT
	lxi	D,24h
	dad	D
	pchl

WRITE:
	lhld	WBOOT
	lxi	D,27h
	dad	D
	pchl

CPMMAP:
	lhld	WBOOT
	lxi	D,60h
	dad	D
	pchl

SETBYT:
	lhld	WBOOT
	lxi	D,66h
	dad	D
	pchl

DSKNAME: .byte	00
TRACK:	 .byte	00
BUFLEN:	 .word	00
LOOPS:	 .byte	00
RANSEED: .byte	00
Terrors: .byte	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
Serrors: .byte	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
ERRtry:	 .word	0000
fixflg:	 .word	0000	; flag: fixed or random pattern
dskfunc: .word	0000	; current R/W func under test

lintab	=	2000h
wrtab	=	lintab+76
rdtab	=	wrtab+76

wrbuffer=	3000h
rdbuffer=	5000h
stack	=	7000h

wrparameter:   .word	0000h   ; Temp holder for read 
rdparameter:   .word	0000h	; & write parameters.
TstUnits:
	.blkb	128		; Space for list of
				; units under test.
				; FFh terminates list.
.page
;**********************************************
;*                                            *
;*  ERROR BUFFER DATA, DEFS, AND SUBROUTINES  *
;*                                            *
;**********************************************

erbuffer=	7000h
EOF	=	1Ah
errbufadr: .word 00h	; Current spot in err buffer.
errflg:	.byte	0	; Write flag for error buffer.
ERRDSK:	.byte	0	; Holder of error disk number.
tmpDSK:	.byte	0	; Temp holder of a disk number.
orgdriv:.byte	0	; Drive to boot to when done.

; The NEC765 Error buffer results are stored here.
BIOSbuf:.byte	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

; Output messages
truncmsg:.asciz [cr][lf]'***TRUNCATED TEST LISTING***'
HELPmsg:.ascii [cr][lf][lf]'     Command Summary'
	.ascii [cr][lf]'     ------- -------'
	.ascii [cr][lf]' F - Fixed track testing'
	.ascii [cr][lf]' R - Read out the error buffer'
	.ascii [cr][lf]' S - Print the current summary'
	.ascii [cr][lf]' T - Restart the test '
	.ascii [cr][lf]' Q - Optional Halt/Stop'
	.asciz [cr][lf]

bufchr:	.word	0	; filled in at START
bufcnt:	.byte	0	; updated by stobyt,Diskit


;------------------
;		Subroutine: wrtbuf
; Regs  in:
; Regs out:
; Destroyed:
;Write a character to the error buffer
WRTBUF:
	push	H
	lhld	errbufadr
	mov	M,C
	inx	H
	mvi	M,EOF	; tag on an EOF (1Ah)
	shld	errbufadr
	pop	H
	ret
;------------------
;		Subroutine: prtbuf
; Regs  in:
; Regs out:
; Destroyed:
;
;Print out the error buffer to the console
PRTBUF:
	lxi	H,crlf
	call	prtmsg	;space down
	mvi	A,0
	sta	errflg	;make sure err flag is off
	lxi	H,erbuffer ; load err buf addr
outchr:	mov	A,M	;get chr in A
	cpi	1Ah	;EOF?
	rz
	mov	C,A	;get chr in C
	inx	H	;get to next buf adr
	push	H	;save buffer address
	call	CONOUT
	call	CONST
	cpi	0FFh	;chr ready?
	pop	H	;restore buffer addr
	jnz	outchr	;if not, out next chr
	push	H	;save buffer addr
	call	CONIN	;eat the chr
..1:	call	CONST	;ready to resume?
	cpi	0FFh
	jrnz	..1	;wait for next chr
	call	CONIN	;eat the chr
	pop	H	;save buffer addr
	jmp	outchr	;resume outputting buffer
;------------------
;		Subroutine: putEOF
; Regs  in:	none
; Regs out:	none
; Destroyed:	none
;Put an End of File marker (1Ah) at end of buffer.
putEOF:
	push	H
;Check the error buffer to see if weve passed B000h.
	lhld	errbufadr ; get current err buf addr
	mvi	A,0B0h
	cmp	H	  ; have we passed B000h?
	jp	resume	  ; No, errbuf is not full.
;Error buffer is full.  Reset it. Leave 'truncate' msg.
	lxi	H,erbuffer
	shld	errbufadr
	mvi	A,0FFh
	sta	errflg	  ; turn on err buf write flag
	lxi	H,truncmsg
	call	prtmsg	  ; 'buffer truncated' 
	mvi	A,0
	sta	errflg	  ; turn off err buf write flag
;----------
;Rebalance the stack and resume testing
resume:	
	lhld	errbufadr
	mvi	A,EOF
	mov	M,A
	inx	H
	mov	M,A
	inx	H
	mov	M,A
	pop	H
	ret

.page
;************************************************
;*                                              *
;* DISK WRITE (OF CONSOLE OUTPUT) DEFS AND SUBS *
;*                                              *
;************************************************

BDOS	=	05h
bufread	=	0Ah
reset	=	0Dh
logdsk	=	0Eh
open	=	0Fh
close	=	10h
kill	=	13h
create	=	16h
wnr	=	15h  	  ; write next record
dma	=	1Ah
SDbyt	=	00000000b ; SD flop device code
DDbyt	=	01000000b ; DD flop device code
DENSbyt:.byte	00h	  ; Density for test
MAPbyt:	.byte	00h	  ; Users current MAPbyte
;
; File Control Block Address.  (Either below or 5Ch)

;----------
;Subroutine:	stoMAPbyt
; Regs  in:	A = disk number of MAPbyte to store
; Regs out:	none
;Destroyed:	any and/or all registers

; Save the current assignment for restoration.
stoMAPbyt:
	lda	04	; get current drive
	sta	orgdriv	; and save for restoration.
	call	CPMmap	; get current assignment
; BIOS address of the byte returns in HL
	sta	MAPbyt	; save it for later restoration
	ret		; and return.

;----------
;Subroutine:	chaMAPbyt
; Regs  in:	A = unit number to assign to
;		B = CP/M device number to assign from
; Regs out:	none
;Destroyed:	any and/or all registers

; Change the assignment of the CP/M drive number
; (received in B) to that of a floppy disk on the
; unit number received in the accumulator.
chaMAPbyt:
	push	PSW	; Save unit number
	mov	C,B
	call	SELDSK	; select unit 0 f
	call	CPMmap	; get current MAPbyte byte addr
; Current unit 0 assignment (network,etc) returns in A
; BIOS address of the byte returns in HL
	pop	B	  ; Restore unit number in B
	lda	DENSbyt	  ; Get floppy density code
	ora	B	  ; A = A <or> B = New MAPbyte
	mov	M,A	  ; Store it in the BIOS
	ret

;----------
;Subroutine:  resMAPbyt
; Regs  in:	A = disk number of MAPbyte to restore.
; Regs out:	none
;Destroyed:	any and/or all registers

; Restore the error disk assignment
resMAPbyt:
	lda	orgdriv	; Get our original disk
	mov	C,A	; and put it in C
	call	SELDSK	; and select buffer-write unit.
	call	CPMmap	; get BIOSmap addr
;Current unit assignment returns in A
;BIOS address of the byte returns in HL
	lda	MAPbyt	; original assignment
	mov	M,A	; restore previous assignment
	ret		; and return.

.page
;***********************************************
;*					       *
;*  TIME PRINT-OUT DATA,DEFS, AND SUBROUTINES  *
;*					       *
;***********************************************
;----------(From Utility Program 'TIME'.)
; Get the date from 44h,45h, & 46h
; and print out in months (J-F),days
; (1-31), and year (00-99).	D.Stein 09/05/80
;
month	=	44h
day	=	45h
year	=	46h
;
prttime:
;print the date message
	lxi	H,datmsg
	call	prtmsg
;out the month,day and year (XXX-DD-YY)
	lxi	H,month
	mov	A,M	;1-12 in A
	lxi	H,Janmsg
	cpi	1	;January?
	jz	prmnth
	lxi	H,Febmsg
	cpi	2	;February?
	jz	prmnth
	lxi	H,Marmsg
	cpi	3	;March?
	jz	prmnth
	lxi	H,Aprmsg
	cpi	4	;April?
	jz	prmnth
	lxi	H,Maymsg
	cpi	5	;May?
	jz	prmnth
	lxi	H,Junmsg
	cpi	6	;June?
	jz	prmnth
	lxi	H,Julmsg
	cpi	7	;July?
	jz	prmnth
	lxi	H,Augmsg
	cpi	8	;August?
	jz	prmnth
	lxi	H,Sepmsg
	cpi	9	;September?
	jz	prmnth
	lxi	H,Octmsg
	cpi	10	;October?
	jz	prmnth
	lxi	H,Novmsg
	cpi	11	;November?
	jz	prmnth
	lxi	H,Decmsg
	cpi	12	;December?
	jz	prmnth
;error trap
	lxi	H,XXXmsg
prmnth:	call	prtmsg
;
prtday:	lxi	H,day
	mov	A,M
	call	cvtbcd
	;is leading 0 necessary?
	cpi	10
	jp	aa2
	push	PSW
	mvi	C,'0'	; out a leading 0
	call	CONOUT
	pop	PSW
	;
aa2:	call	prtbyt	; out the day
	mvi	C,'-'
	call	CONOUT	;
;
	lxi	H,year
	mov	A,M
	call	cvtbcd
	;is leading 0 necessary?
	cpi	10
	jp	aa3
	push	PSW
	mvi	C,'0'
	call	CONOUT
	pop	PSW
	;
aa3:	call	prtbyt	; date is all out.
;space over
	lxi	H,space5
	call	prtmsg
;----------
; Print the real time (in hours and minutes and seconds)
; as represented by these bytes:
seconds	=	41h
minutes	=	42h
hours	=	43h
;----------
; 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.
; The BIOS maintains the time in locations 40h-43h.
;
; Print the time message
	lxi	H,timmsg
	call	prtmsg
; Print the hours
	lxi	H,hours
	mov	A,M	;get hours in A
	call	cvtbcd
	;is leading 0 necessary?
	cpi	10
	jp	bb1
	push	PSW
	mvi	A,'0'
	call	CONOUT
	pop	PSW
	;
bb1:	call	prtbyt
	mvi	C,':'
	call	CONOUT	
;
; Print the minutes
prtmin:	lxi	H,minutes
	mov	A,M	;get minutes in A
	call	cvtbcd
	;is leading 0 necessary?
	cpi	10
	jp	bb2
	push	PSW
	mvi	C,'0'
	call	CONOUT
	pop	PSW
	;
bb2:	call	prtbyt
	mvi	C,':'
	call	CONOUT
;
; Print the seconds
prtsec:	lxi	H,seconds
	mov	A,M
	call	cvtbcd
	;is leading 0 necessary?
	cpi	10
	jp	bb3
	push	PSW
	mvi	C,'0'
	call	CONOUT
	pop	PSW
	;
bb3:	call	prtbyt
	lxi	H,crlf
	call	prtmsg	; space down
	ret		; finished printing time
;----------
; 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
;----------
; Print a byte on the console
;  Regs in:   A = byte to be printed
;  Regs out:  none
;  Destroyed: A
prtbyt:
	push	PSW
	rrc
	rrc
	rrc
	rrc
	ani	0Fh	; don't print leading zeros
	jrz	..1
	call	prtnbl
..1:	pop	PSW
prtnbl:	ani	0Fh
	adi	'0'
	cpi	'9'+1
	mov	C,A	; get the chr in C
	push	PSW
	cc	CONOUT
	pop	PSW
	rc
	adi	'A'-('9'+1)
	mov	C,A
	call	CONOUT
	ret
;----------
; Messages
datmsg:	.asciz	'Date  '
timmsg: .asciz	'Time  '
space5:	.asciz	'      '
crlf:	.asciz	[cr][lf]
janmsg:	.asciz	'Jan-'
febmsg:	.asciz	'Feb-'
marmsg:	.asciz	'Mar-'
aprmsg:	.asciz	'Apr-'
maymsg:	.asciz	'May-'
junmsg:	.asciz	'Jun-'
julmsg:	.asciz	'Jul-'
augmsg:	.asciz	'Aug-'
sepmsg:	.asciz	'Sep-'
octmsg:	.asciz	'Oct-'
novmsg:	.asciz	'Nov-'
decmsg:	.asciz	'Dec-'
XXXmsg:	.asciz	'XXX-'

.end
