;************************************************
;						*
;		FOX hard disk test		*
;						*
;************************************************
;
	.ident	HD5hlp
;

version ==	3	; version number
revision==	4	; revision number
xvision ==	6	; change every time
;
;
; Revision history
;
; 3.40	06/29/83  Make sector size 512 in preparation
;		   for DMS-15 release
; 3.41	06/29/83  Change it right back again.
;		  Change interleave to 11, not 11h
; 3.42	07/08/83  Clean and tidy messages
; 3.43	10/04/83  Bug fix for unnumbered SCR: check
;		   SASIstat after each sector on
;		   multiple-sector xfers -- else we
;		   may read error bytes as data then
;		   hang up waiting for 254 more.
;		  Sector skew changed to 6.
; 3.44	10/06/83  Format has option to save Bad Track
;		   information, i.e. preserves table
;		   and reformats bad tracks according
;		   to it.  This replaces the old
;		   "save first 17k" option.  Asks user
;		   whether to re-initialize firmware
;		   after a format.
; 3.45	10/18/83  Changed some comments, variable names 
; 3.46	01/04/83  Response to unnumbered SCR:  move
;		   command buffer initilization to end
;		   of program, eliminating need for
;		   .reloc.  The .reloc is not handled
;		   right by LOAD.COM, so we had to use
;		   DDT to make the .COM file.   In at 
;		   least one case this was done wrong
;	 	   -- too little was SAVEd so the 
;		   command buffer was not initialized.

	.page
	.pabs
	.phex
	.loc	100H

	lxi	sp,stack
	ei			;enable interrupts
	jmp	START		;104	restart program  
	nop
	call	RESET		;108	reset HDC
	rst	6
	call	READsect	;10C
	rst	6
	call	WRTsect 	;110
	rst	6
	call	RVERIFY 	;114	verify whole dsk
	rst	6
	call	FORME5		;118	format whole dsk
	rst	6
	call	FORM1TK 	;11C	format one track
	rst	6
	call	DISKTEST	;120	w/r/cmp test
	rst	6
	call	SEEKTEST	;124
	rst	6
	call	no		;128	get volume size
	rst	6
	call	VOLINIT 	;12C	set up firmware
	rst	6
	call	INTRFACE	;130	intrface test
	rst	6
	call	INTTEST 	;134	HDC RAM test
	rst	6
	call	no		;138	get HDC mem blk
	rst	6
	call	no		;13C	repeat read
	rst	6
	call	doRD$WR 	;140	repeat w/r/cmp
	rst	6
	call	no		;144	send 40h
	rst	6
	call	BYE		;148	warmboot
	rst	6
	call	READ1k		;14C
	rst	6
	call	no		;150	rd dsply cntnuus
	rst	6
	call	no		;154	read & display
	rst	6
	call	getBTT		;158	get bad trak tbl
	rst	6
	call	zroBTT		;15C	zro bad trak tbl
	rst	6
	call	comPARE 	;160
	rst	6
	call	no		;164   cpm partition sel
	rst	6
	call	no		;168	boot volume
	rst	6
	call	ERRdesc 	;16C
	rst	6
	call	VOLINFO 	;170	get vol info
	rst	6
	call	no		;174	multi  vol seek
	rst	6
	call	no		;178	cpm 128b read
	rst	6
	call	no		;17C	mlt vol random w  
	rst	6
	call	no		;180	cpm 128b write
	rst	6
	call	BUFDESC 	;184 
	rst	6
	call	no		;188	flush buffers
	rst	6
	call	no		;18C	voltest
	rst	6
	call	typeset 	;190	set disk size
	rst	6
	call	sizedefault	;194  dsk siz frm fmware
	rst	6

	.page
;	-- miscellaneous equates --
pattern 	==	0E5h	; format pattern to write
WCbyte		==	0B6h	; worst-case test pattern
dlayval 	==	01000h	; delay for RVERIFY loop

space		==	20H	; space
cr		==	0Dh	; carriage return
lf		==	0Ah	; linefeed
qmark		==	3Fh	; question mark
ctlC		==	03h	; abort
bspace		==	08h	; backspace
delete		==	07Fh	; delete
RST6		==	0F7H	; Z-80 opcoad

;	-- hardware equates --
PIOAD		==	08h	; PIO channel A, data
PIOBD		==	09h	; PIO channel B, data 

;	-- cp/m equates --
BDOS		==	5	; address of BDOS call
tFCB		==	5Ch	; default FCB location

cpmGET		==	1	; bdos conin
cpmPUT		==	2	; bdos conout
cpmDIO		==	6	; bdos direct con IO 
cpmLIN		==	10	; line input
cpmCST		==	11	; console status
cpmOPEN 	==	15	
cpmCLOSE	==	16
cpmFIND 	==	17
cpmERASE	==	19
cpmREAD 	==	20	; sequential read
cpmWRIT 	==	21
cpmCREAT	==	22
cpmDMA		==	26
recsize 	==	80h	; cp/m record size

;	-- interface equates --
CMDMODE 	==	00011b	; command mode
WRTMODE 	==	00001b	; write mode
RDDATMODE	==	01001b	; read data mode
RDERRMODE	==	01011b	; read error mode
errmode 	==	01011B	; ret error byte mode
LASTMODE	==	01111b	; ret zero byte mode
YESFRMT 	==	0	; turns off format 
	

      ;       -- controller command equates --

busy		==	00	; busy true high
DRVREADY	==	0H	; test drive ready
RECAL		==	01H	; recalibrate head
SENSE		==	03H	; status sense 
FORMAT		==	04H	; format command code
FTRACK		==	06H	; format one track
READ		==	08H	; read command code
WRITE		==	0AH	; write command code
SEEK		==	0BH	; seek command code
INITL		==	0CH	; initialize drive
FALT		==	0Eh	; format alternate track

WSECBUF 	==	0Fh	; write to sector buffer

RAMDIAG 	==	0E0h	; ram diagnostic
DRVDIAG 	==	0E3h	; drv diagnostics
INTDIAG 	==	0E4h	; internal "
ERROR		==	02H	; illegal command 

idle		==	40h	; idle command
init$cont	==	00	; reset HD command
sel$cont	==	0C0h	; select controller
desel$cont	==	40h	; deselect controller
dat$cmd$port	==	01	; mode set by toggle
toggle$port	==	0	
; output to port 0 toggles between status and data modes


;	-- buffer assignments --
combuf	==	2300h		; command to controller
statbuf ==	2BF8h		; mss from controller (2
				; flags+four bytes of
				; xebec status)
RBUFFER ==	2C00h		; read from disk
lRBUFF	==	400h
WBUFFER ==	2700h		; write to disk here
lWBUFF	==	 400h
errbuf	==	6000h		; error buffer
lerrbuf ==	1000h
safearea==	7000h		; 1k all-purpose buffer
hugebuf ==	7400h		; big buffer for shenani
				; gans
;
;	-- hard disk --
SKEWFACTOR	==	6	; iinterleave
sectsize	==	100h	; size of sector
SperT		==	2000h/sectsize ; sects per track
SperK		==	1024/sectsize ; sects per K
bufsize 	==	1024
$256Kmask	==	#((256*SperK)-1)
SperDRIVE:	.word	secMIN	; default Miniscribe
DSperDRIVE:	.word	(secMIN-1)& $256Kmask
disktyp:	.word	chrMIN
maxvol	==	4	; number of volumes allowed

;	-- offsets into HD param area ----
vlipresent  == 0   ;is volume present (true or false)
vlicurtrack == 1   ;current track for volume
vlitracks   == 2   ;tracks on volume
vlitype     == 3   ;sectors/track
vlisize     == 4   ;head mask (more "TYPE" then vlitype 
vlibiastable == 5  ; location of partition offset table
vlibadtable  == 7  ;location of bad sector table for vol
vlidirty     == 9  ;location of bad table dirty flag
vliopenerr  == 11  ;failure in volume open(init)
vlivollabel == 12  ; 10 byte volume name
vliDRinfo   == 22  ; physical info for xebec; step optio
vlibufsiz   == 32  ;size of info in volume table entry

inbuf:
	.blkb	80d;

	.page
      
START:	
	lxi	h,hello$
	call	out$string
	call	RESET
	call	doINIT
	call	qREADY
	call	doRECAL
	call	clrERR
	xra	A
	sta	volume	; default select volume 0

	mvi	A,call	; make jmp to menu
	sta	100H
	lxi	H,MENU
	shld	101h
	mvi	A,RST6
	sta	103h

..1:	lxi	H,PREmenu
	call	out$string
	call	conin
	cpi	'0'
	jz	100h
	cpi	'1'
	jrnz	..2
	call	FORME5
	jmp	0

..2:	cpi	'2'
	jrnz	..3
	call	VOLINIT
	jmp	0

..3:	cpi	'3'
	jrnz	..4
	call	GETBTT
..4:	cpi	ctlC
	jz	0
	jmpr	..1

;--------------------------
MENU:
	lxi	H,LOGMSG
	call	out$string
	ret

BYE:	lxi	H,goodbye$
	call	out$string
	jmp	0

NO:	lxi	H,noDAVEyet
	call	out$string
	ret

;--------------------------
ERRDESC:lxi	H,mbf4
	call	out$string
	ret

BUFDESC:lxi	H,mbf6
	call	out$string
	ret
;----------------------------
; Perform Drive / Interface Test.
; The controller sends recalibrate and seek
; commands, and verifies sector 0 of each
; track.  No writes are done.  Good.

INTRFACE:
	lxi	H,g130msg
	call	out$string
	mvi	A,DRVDIAG
	call	sendcom
	call	readstat
	call	iferr
	ret

;----------------------------
; Run controller internal test. Two parts;
; one tests RAM and the other tests ECC,
; processor, program memory & the like.

INTTEST:
	lxi	H,tRAMmsg
	call	out$string
	call	tstRAM 
	lxi	H,tINTmsg
	call	out$string
	call	tstINT 
	ret
;----------------------------
; Test xebec RAM.

tstRAM:
	mvi	A,RAMDIAG
	call	sendcom
	call	readstat
	call	iferr
	ret
;----------------------------
; Internal diagnostics on controller.

tstINT:
	mvi	A,INTDIAG
	call	sendcom
	call	readstat
	call	iferr
	ret
;----------------------------
VOLINIT:
	mvi	B,maxvol; up to four volumes this way
..next: call	stftyp
	djnz	..next
	call	pntFIRM  ; point to sect 0
	call	WRTSECT
	ret

;----------------------------
VOLINFO:
	call	pntFIRM  ; physical sect 0
	call	READsect; get firmware

	mvi	B,maxvol; up to four
..next: call	pultyp
	djnz	..next

	ret
;----------------------------
; Stuff the write buffer with vol info
; Regs in:   B = (maxvol-volume)
; Regs out:  same
; Trashed:   everything else

stftyp:
	mvi	A,maxvol
	sub	B	    ; volume number
	lxi	H,WBUFFER    ; begin of buffer
	call	pntVinfo    ; point at right place
	mvi	vlipresent(x),0
	call	fndtyp
	push	B	    ; find which vol
	call	stufem	    ; stuff info in right place
	pop	B	    ; loop ctr
	ret

;--------------------------------
pultyp:
	mvi	A,maxvol
	sub	B
	lxi	H,RBUFFER
	call	pntVinfo
	push	B
	call	prttyp
	call	prtlabl
	pop	B
	ret
;--------------------------------
; Get the disk type for one volume
; Regs in:  B = maxvol-volume
; Regs out: A = head mask 
; Trashed:  all except BC

fndtyp:
	push	B
..find:
	lxi	H,typm1 	; "volume"
	call	out$string
	pop	B
	push	B
	mvi	A,maxvol
	sub	B
	call	prtbyt
	lxi	H,typm2 	; rest of msg
	call	out$string
	call	conin		; get it
	sui	'0'		; number, not numeral
	call	validtyp
	jrnz	..find
	pop	B
	ret
;-----------------------
; Get a ten-character volume label
; and put into appropriate vol area.
; Regs in:  X = ptr to volume info area
; Regs out: none		   
; Trashed: all except PSW
getlabl:
	push	PSW
	lxi	H,lablmsg
	call	out$string
	push	X	    ; pointer
	pop	H	    ; copied to HL
	mvi	E,vlivollabel
	mvi	D,0
	dad	D
	push	H	    ; label pointer

	mvi	B,10 
..blnk: mvi	M,' '
	inx	H
	djnz	..blnk

	lxi	D,volabel
	mvi	C,10		; BDOS line in
	call	BDOS
	pop	D		; destination
	lda	volabel+1
	ora	A		; see if any input!
	jrz	..none		; give up if not
	mov	C,A
	mvi	B,0		; bytes to move
	lxi	H,volabel+2	; where from
	ldir
..none: pop	PSW
	ret

;------------------------
; Initialize one volume's info for writing
; Regs in:  B = (maxvol-volume number)
;	    A = head mask (zero if absent)
;	   DE = adr of volabel string
;	    X = adr of volume firmware in WRTBUFF
; Regs out: none
; Thrashed: all

stufem:
	mvi	vlipresent(x),0
	ora	A	    ; see if it's present
	rz		    ; nothing else to do
	mvi	vlipresent(x),0FFh; volume present
	mov	vlisize(x),A; head mask (dsk type)
	call	getlabel

	push	X
	pop	H		; beginning of block
	mvi	E,vliDRinfo	; offset to params
	mvi	D,0
	dad	D		; destination
	xchg
	call	pntDRinfo	; seven bytes of drive 
	lxi	B,8		; info plus one for
	ldir			; xebec step option
	ret
;--------------------------------
; Print the disk type for one volume
; Regs in:  X = ptr to info block
;	    B = maxvol - volume #
; Regs out: none
; Trashed:  all

prttyp:
	push	B
	lxi	H,VolVolmsg
	call	out$string
	pop	B
	mvi	A,maxvol
	sub	B
	call	prtbyt
	call	blank
	mov	A,vlipresent(x)
	ora	A
	jrz	..none
	mov	A,vlisize(x)
	call	validtyp
	jrnz	..bad
..none: lxi	H,typtabl
	ral			; word value
	mov	E,A
	mvi	D,0
	dad	D		; H points to
	mov	E,M		; message address
	inx	H		; and now D points
	mov	D,M		; to message.
	xchg			; get it to H
	jmpr	..prnt 
..bad:	lxi	H,typBAD
..prnt: call	out$string	; print about it
	ret
;-----------------------
; Print oot the label for a volume.
; Regs in: none
; Regs out: none		   
; Trashed: all except PSW
prtlabl:
	push	PSW
	mov	A,vlipresent(x)
	ora	A
	jrz	..none 
	mov	C,vlivolabel+0(x)
	call	CONOUT
	mov	C,vlivolabel+1(x)
	call	CONOUT	      
	mov	C,vlivolabel+2(x)
	call	CONOUT
	mov	C,vlivolabel+3(x)
	call	CONOUT
	mov	C,vlivolabel+4(x)
	call	CONOUT
	mov	C,vlivolabel+5(x)
	call	CONOUT
	mov	C,vlivolabel+6(x)
	call	CONOUT
	mov	C,vlivolabel+7(x)
	call	CONOUT
	mov	C,vlivolabel+8(x)
	call	CONOUT
	mov	C,vlivolabel+9(x)
	call	CONOUT
	pop	PSW
	ret
..none: lxi	H,nolabel
	call	out$string
	pop	PSW
	ret
nolabel:.asciz	'          '
;--------------------------
; determine if valid disk type
; Regs in:  A = type (head mask)
; Regs out: same, Z set iff valid
; Trashed:  none

validtyp:
	cpi	CMImask ; cmi 15 meg
	rz 
	cpi	MINmask ; miniscribe 16 meg
	rz
	cpi	RMSmask ; rms 13 meg
	rz
	cpi	SYQmask ; Syquest 5 meg
	rz
	cpi	RODmask ; Rodime 16 meg
	rz
 
	ora	A	; zero is always ok though
	ret

;------------------------
; Aim HL and IX at part of buffer where info
; for a particular volume lies.
; Regs in:  HL = beginning of buffer
;	     A = volume number
      ; Regs out: HL = ptr to volume info area
;	     X = ptr to volume info area
; Trashed:  A, HL

pntVinfo:
	ral	; mult A by 32
	ral
	ral
	ral
	ral
	push	D
	mov	E,A
	mvi	D,0
	dad	D
	push	H
	pop	X
	pop	D
	ret


;-------------------------
; Reset the Hard Disk Controller.
; Also, zero the address field.
; Regs in:  none
; Regs out: none
; Trashed:  A, HL

RESET:
	mvi	A,init$cont    ; byte for reset
	out	toggle$port    ; get into status mode
	out	dat$cmd$port   ; Output reset byte
	mvi	A,idle	       ; byte for idle
	out	dat$cmd$port   ; output idle byte
	out	toggle$port    ; return to data mode
	call	pntFIRM        ; point to sector 0000
	ret

;----------------------------
pntFIRM:
	xra	A
	sta	high   
	sta	middle
	sta	low
	ret

;----------------------------
; initialize the drive characteristics:
typeset:
doINIT: call	init		;initialize drive
	call	READSTAT	
	call	iferr		; was there an error
	ret

;----------------------------
; initialize the drive characteristics
; using the disk type in firmware
sizedefault:
	call	pntFIRM
	call	READsect
	lxi	H,RBUFFER
	lda	volume		; current vol only
	call	pntVinfo
	mov	A,vlipresent(X) ; it has to be there!
	ora	A
	jrz	..none
	mov	A,vlisize(X)
	call	validtype
	jrnz	..bad
	call	pntDRinfo	; get disk params
	shld	disktyp 	; store for ourselves
	call	RESET		; now we're in for it
	call	REINIT		; send to disk
	call	readstat
	call	iferr
	call	qREADY
	ret

..none: call	newline
	lxi	H,typNONE
	jmpr	..bad2

..bad:	lxi	H,typBAD
..bad2: call	out$string
	call	newline
	ret
;--------------------------------
;see if the drive is ready:
qREADY:
	mvi	A,DRVREADY
	call	SENDCOM
	call	READSTAT	
	call	iferr
	ret

;---------------------------
;recalibrate the heads:
doRECAL:
	lda	oktoseek   ; if drive is initialized,
	ora	A	   ; we can do a seek to track
	jrz	..rcal	   ; 0 first to speed ourselves

	lxi	H,0	   ; along.
	call	sectSK
..rcal: mvi	A,RECAL
	call	SENDCOM
	call	READSTAT	
	call	iferr
	mvi	A,0FFh	   ; if at least one real recal
	sta	oktoseek   ; has been done then a pre-
	ret		   ; seek is ok next time

;---------------------------
; Repeat test a sector, until error.
;
doRD$WR:

	lxi	H,TnoEmsg     ; tests sans error
	call	out$string
	call	newline
	lxi	H,0
	shld	Ecounter
	xra	A
	sta	yeserr
..redo:
	call	rantst	    ; random pattern
	call	$1Stest
	jrnz	..done	    ; return on error
	mvi	C,cr
	call	conout
	lhld	Ecounter
	inx	H
	shld	Ecounter      ; print # of passes
	call	prtWORD
	call	ABRTtest
	jrz	..redo

	lxi	H,abreq
	call	out$string
..done: call	newline
	ret

Ecounter:.word	0
;--------------------------
; One-sector wr/rd/cmp using both a
; "worst-case" pattern and a random one
; Return Z if no error
$1Stest:
	call	setWCP
	call	$1SWRC
	rnz
	call	rantst
	call	$1SWRC
	ret

;--------------------------------
; Write, read, compare one sector
$1SWRC:
	call	WRTsect
	rnz		; can't read if no write
	call	READsect
	rnz		; can't compare if no read
	call	comPARE
	ret
;
;-------------------------------------
; HARDHELP-style full disk w/r test
;
DISKTEST:
	call	okdestroy
	rnz
	call	stmax		; set highest track to
	lda	tstalt		;   test
	ora	A		; testing alternates...
	cz	saveBTT 	; if not, save table
	call	clrERR
	lxi	H,0		; start at begin
..loop:

	call	setSECT
	push	H	; save address
	xra	A
	sta	yeserr	; no error yet
	call	$1Ktest
	call	ABRTtest
	pop	H
	jrnz	..abrt
	push	H
	call	prntSK
	call	ABRTtest
	pop	H
	jrnz	..abrt
	lxi	D,SperK ; bump up 1k each time
	dad	D      
	call	testmax ; see if past end 
	jc	..done
	jmpr	..loop	; do next k

..abrt: call	abort
..done: call	newline

	lda	tstalt	; did we have to save the BTT 
	ora	A     
	cz	restBTT
	ret

;---------------------------------
; 1K worst-case and random wr-rd-cmp test
;
$1Ktest:
	call	setWCP
	call	$1KWRC 
	call	rantst
	call	$1KWRC 
	ret

;---------------------
; 1K write-read-compare
$1KWRC:
	call	WRT1k
	rnz		; can't read if no write
	call	READ1k
	rnz		; can't compare if no read
	call	comPARE
	ret

;-------------------------------
; Set up worst-case test pattern
setWCP:
	lhld	WCpat
	slar	L
	ralr	H
	jrnc	..2
	inx	H
..2:	shld	WCpat
	xchg		; put pattern in DE to
	call	FILLW	; fill write buffor
	ret
WCpat:	.word	0B6D9h

;------------------------------
; Fill write buffer with pattern in DE
FILLW:
	lxi	H,wbuffer
	mov	M,D
	inx	H
	mov	M,E
	dcx	H
	lxi	D,wbuffer+2	; move words
	lxi	B,lWBUFF-2
	ldir
	ret
;------------------------------
; fill write buffer with pattern in A
FILLB:
	lxi	H,wbuffer
	mov	M,A
	lxi	D,wbuffer+1
	lxi	B,lWBUFF-1	; move bytes
	ldir
	ret

;---------------------------------
; Fill wbuffer with random pattern
rantst:
	lxi	D,wbuffer
	lxi	B,lWBUFF
rant2:	call	RANDOM
	stax	D
	inx	D
	dcx	B
	mov	A,C
	ora	B
	jrnz	rant2
	ret

;--------------------------------------
; Print current absolute sector address;
;  install new one if desired.
;
;
;getsec:
;	lxi	H,csecmsg	; 'current sector:'
;	call	out$string
;	call	paddr
;
;..get:  lxi	 H,gsecmsg	 ; get a valid sector #
;	call	out$string
;	call	getadr		; go get it
;	jrnz	..get		; nonzero means bad inp
;	bit	0,B		; one if something was i
;	rz			; default to old value i
;	call	testmax
;	jrc	..tbig
;	xchg			; sector # is in DE now
;	lxi	H,middle
;	mov	M,D
;	lxi	H,low
;	mov	M,E		; now it's in middle & l
;	ret
;..tbig: lxi	 H,tbigmsg
;	call	out$string
;	jmpr	getsec
;-----------------------------------
; Set the number of valid sectors depending
; on whether we are including the ones reserved
; for bad track substitution.
; Regs out:  A = 0FFh if testing whole disk
;	      or 'N' if not testing alternate tracks
stmax:
	xra	A
	sta	tstalt		; default data only
	lxi	H,askmax
	call	out$string
	call	yorn
	push	PSW
	call	newline
	pop	PSW
	cpi	'Y'
	rnz
	ori	0FFh
	sta	tstalt
	ret
;-----------------------------------
; test HL against maximum # of sectors on disk.
;
testmax:
	push	D
	xchg
	lhld	SperDRIVE    
	lda	tstalt	   ; alternate tracks too 
	ora	A
	jrnz	..go
	lhld	DSperDRIVE ; no, just data tracks.
..go:	dcx	H		; they start at zero
	stc
	cmc			; make sure carry is zer
	dsbc	D		; HL now has max minus r
	xchg			; get sector # back into
	pop	D
	ret			; HL, and return
;----------------------------------
; Make sure it's ok to cream the disk
okdestroy:
	lxi	H,deathmsg
	call	out$string
	call	yorn
	cpi	'Y'
	push	PSW
	call	newline
	pop	PSW
	ret
;---------------------------------
; Get a yes/no answer
;
yorn:
	call	conin
	ani	5Fh		; make uppor case
	cpi	'Y'
	rz 
	cpi	'N'
	rz
	lxi	H,yornmsg
	call	out$string
	jmpr	yorn
;----------------------------------
;
RVERIFY:			; read every sector
	call	stmax		; which top is top
	call	clrERR		; clear error buffer
	call	newline
	lxi	H,0	    
..loop: xra	A
	sta	yeserr		; no error here yet
	call	$1Kread 	; read 1K here
	push	PSW
	call	prntSK
	pop	PSW		; abort flag is here  
	jrnz	..abrt		; nonzero if abort reque
	lxi	D,SperK 	; restore & increment
	dad	D		; by four each time
	call	testmax 	; test whether ONE OVER 
	jc	..done
	jmpr	..loop

..abrt: call	abort
..done: call	newline
	ret

$1Kread: 
	push	H
	call	setSECT
	call	READ1K
	call	ABRTtest
	pop	H
	ret

;-------------------------------
ABRTtest:
	call	dirCONin	; see if a char has
	ora	A		; been hit
	rz			; no char
	call	ctlStest	; see whether control-S
	ret			; zero if ok to go

ctlStest:
	cpi	'S'-40h
	rnz			   ; not pause, real abo
..get:	call	dirCONin	   ; ctl-S: get another 
	ora	A
	jrz	..get
	xra	A		; set go-on flag
	ret

abort:
	lxi	H,abreq
	call	out$string
	ret
;--------------------------------
SEEKTEST:
	call	stmax	; set max legal sector
	call	clrERR	; set up error buffer
	lxi	H,SKmsg
	call	out$string
..get:	call	dirCONin
	ora	A
	jrz	..get
	push	PSW
	call	newline
	pop	PSW

	cpi	'1'	; seek 0, max
	jrz	longsk
	cpi	'2'
	jrz	lsk2 
	cpi	'3'
	jrz	skrand

	jmpr	seektest

longsk:
	lxi	H,0
	xra	A
	sta	yeserr
	call	sectSK	; seek 0
	call	prntSK	; display
	jrnz	..abrt 
	lhld	SperDRIVE	; number of sectors
	dcx	H		; sects start at 0
	xra	A
	sta	yeserr
	call	sectSK
	call	prntSK
	jrnz	..abrt
	jmpr	longsk		; repeat until aborted

	call	newline
	ret
..abrt: call	abort
	ret


lsk2:
	lxi	H,0		; start w/ beginning
..loop: push	H
	xra	A
	sta	yeserr
	call	sectSK
	call	prntSK
	pop	H
	jrnz	..abrt
	lxi	D,SperT 	; bump one track
	dad	D
	call	testmax
	jrnc	..loop

	call	newline
	ret

..abrt: call	abort
	ret

skrand:
..rnd:	call	randW		 ; get random word into 
				 ; HL
	call	testmax 	 ; make sure it's an ok 
				 ; address
	jrc	..rnd
	xra	A
	sta	yeserr		; no error yet
	call	sectSK
	call	prntSK
	jrz	..rnd		; nonzero if abort reqd 
	call	abort
	ret

;--------------------------
; Put a random word into HL
randW: 
	call	RANDOM
	mov	H,A
	lda	40h		; ticks, you see
	xri	01101011b	; just for grins
	add	H
	call	RANDOM
	mov	L,A
				; pretty random
	ret

;------------------------
; Put a random byte into A
RANDOM:
	push	B
	lda	lastran
	adi	31
	xri	011010001b
	rrc			; now we hop it along a 
	mov	B,A		; tad using the refresh
	ldar
	xra	B
	sta	lastran
	pop	B
	ret

lastran:.byte	6Bh
;-------------------------------
; Set up sector address from HL
; Regs in:  HL = sector
; Regs out: same
; trashed:  DE

setSECT:push	H
	xchg

	lxi	H,middle
	mov	M,D
	lxi	H,low
	mov	M,E
	pop	H
	ret
;--------------------------------
; Seek a track containing a sector
; Regs in:  HL = sector
; Regs out: same
; Ruined:   all else

sectSK: call	setSECT ; say it
	push	H
	call	READSECT; do it
	pop	H
	ret
;---------------------------------
prntSK: 		; say what was sought
	push	H
	mvi	C,cr
	call	conout
	lda	yeserr
	ora	A
	jrz	..ok
	mvi	C,lf	; leave room for err msg
	call	conout
..ok:	call	paddr
	call	ABRTtest
	pop	H
	ret
;----------------------------------
; Compare 1K buffers, not just one sector
  CMP1k:
	lxi	B,1024
	jmpr	cmpx

;----------------
; Compare RBUFFER and WBUFFER; report errors.
; Modified 6/22/83 to only report the FIRST error since
; every compare error we've ever seen results from the
; whole sector being wrong.
comPARE:
	lxi	B,sectsize
cmpx:	lxi	H,RBUFFER
	lxi	D,WBUFFER
..loop: 
	push	H
	push	D
	ldax	D
	cmp	M
	jrnz	..err
	inx	H
	inx	D
	dcx	B
	mov	A,B
	ora	C
	pop	D
	pop	H
	jrnz	..loop
	jmpr	..out

..err:	call	comperror
..out:	lda	yeserr
	ora	A
	ret

;------------------------------------
; Report & record a compare error.  We'll treat it
; as though it were a Xebec error code '40' since 
; real Xebec errors only go through 3F.
; Regs in:  A = what we wrote
;	    M = what we got back

comperror:
	sta	statbuf+6  ; there's no applicable com-
	mov	A,M	   ; mand byte so we use these
	sta	statbuf+7  ; to show results of compare
	lxi	H,combuf+1	; address fld in command
	lxi	D,statbuf+3	; addr fld in statbuf
	lxi	B,3		; 3 bytes to move
	ldir			; install the address
	mvi	A,40h		; secret fake error code
	sta	statbuf+2	; errcode space in statb
	lda	task		; put the read command
	sta	statbuf+6	; just for something to 
				; put
	mvi	B,6		; errcode, 3 byte addr,
				; byte out, byte in
	call	dumpstat	; throw to screen
	call	addERR		; and to buffer
	ret
;---------------------------------------------
; Get an address (up to 3 bytes) into adrbuf
; We can actually take 6 to allow for backspacing
;  but only the low 3 are there on return.
; Put the lower two bytes into HL for backwards
;   compatibility
; Regs in:  none
; Regs out:  HL = input (lower word)
;	     B	= 1 if input isn't empty
;	     Z = good,	which it always is.

getadr:
	lxi	H,adrbuf  ; clear first
	mvi	B,6
..cler: mvi	M,0
	inx	H
	djnz	..cler
	mvi	B,0	    ; initialize to no input
..loop: push	B
	call	getnib	    ; returns 0-F or FF if end.

	pop	B
	cpi	0FFh
	jrz	..done
	call	shifter     ; load new nibble in
	mvi	B,1
	jmpr	..loop	    ; get until all got

..done: push	B
	lxi	H,adrbuf+3  ; move most recent 3
	lxi	D,adrbuf    ; bytes to start of
	lxi	B,3	    ; buffer.
	ldir
	lxi	H,adrbuf+2  ; low byte
	mov	A,M
	dcx	H	    ; high byte
	mov	H,M
	mov	L,A
	pop	B	; show if empty
	xra	A	; zero flag for good
	ret

getnib:
	mvi	C,1
	call	BDOS
	cpi	cr	; cr means end
	jrz	..cr
	cpi	bspace	; bs = del
	jrz	..bs 
	cpi	delete
	jrz	..bs
	call	cvthex	; hex the nibble
	rnc
	lxi	H,BSPSBSP
	call	out$string
	jmpr	getnib

..cr:	mvi	A,0FFh
	ret
..bs:	lxi	H,spbs 
	call	out$string
	mvi	A,delete
	ret

cvthex:
	cpi	'9'+1
	jrnc	..let

	sui	'0'	; convert a num digit
	ret		; carry set if bad

..let:	ani	05Fh	; upper kaese
	sui	'A'
	rc		; bad if bad
	adi	10
	cpi	16 
	cmc		; carry if no carry
	ret

shifter:
	push	B
	cpi	delete
	jrz	..back
	lxi	H,adrbuf+5
	mvi	B,6
..shft: rld 
	dcx	H
	djnz	..shft
	pop	B
	ret		; toss last carry

..back: 		; back out the last entry
	xra	A	; shift 0 into top nibble
	lxi	H,adrbuf
	mvi	B,6
..bsh:	rrd
	inx	H
	djnz	..bsh
	pop	B
	ret

;--------------------------------------
; Print a message on the console
;  Regs in:   HL = address of message
;  Regs out:  none
;  Destroyed: all
out$string:
	mov	A,M
	ora	A
	rz
	mov	C,A
	push	H
	call	CONOUT
	pop	H
	inx	H
	jmpr	out$string

;--------------------------
; Format one track with E5's.
FORM1TK:
	lxi	H,high		; confirm track address
	lxi	D,adrbuf	; by printing sectors it
	lxi	B,3		; encompasses
	ldir
	call	eventrk 	; here's beginning
	lxi	H,okft1
	call	out$string
	lxi	H,adrbuf
	push	H
	call	prt3byts
	lxi	H,okft2
	call	out$string
	lda	adrbuf+2
	adi	SperT-1 	; here's end
	sta	adrbuf+2
	pop	H
	call	prt3byts
	lxi	H,okft3
	call	out$string
	call	yorn
	cpi	'Y'
	rnz

	call	FillE5
	lxi	H,cntfld
	set	5,M		; say to use the data
	push	H		; we put into the buffer
	call	FORMTK
	pop	H
	res	5,M
	ret
FORMTK:
	mvi	A,SKEWFAC
	sta	intlv
	mvi	A,FTRACK
	call	sendcom
	call	waitreq
	call	SASIstat	;get the status of the 
				;    SASI bus
	cpi	errmode
	rnz		 
	call	readstat
	call	iferr
	ret
;--------------------------
; Format whole disk with E5's.
FORME5:
	call	FillE5
	lxi	H,cntfld	; set flag to show we're
	set	5,M		; using the sector buffe
	push	H		; rather than 6C's
	call	FORMALL
	pop	H
	res	5,M
	ret

FillE5:
	mvi	A,0E5h
	call	FILLB		; get E5's into our buf
	mvi	A,WSECBUF	; send that buffer to
	call	sendcom 	; controller's sect buf

	lxi	H,WBUFFER
	lxi	B,sectsize
	mvi	A,1
	jmp	wrtout		; send the data
;-----------------
; Format the hard disk.
;
;
FORMALL:

	lda	blkcnt		; save block count
	sta	savblk

	lxi	H,FORMQ1
	call	out$string	; do warning
	call	okdestroy	; quit if no permission
	rnz
	call	pntFIRM 	; start at beginning.
				; unless told not to
..ask2: lxi	H,FORMQ2	; save bad track info
	call	out$string
	call	yorn
	sta	permit
	cpi	'N'
	jrz	..nsav
	call	saveBTT 	; (else save it)
..nsav: mvi	A,SKEWFAC	; interleave factor
	sta	intlv
	lxi	H,BSYMSG
	call	out$string
	mvi	a,format
	call	sendcom
	call	waitreq
	call	SASIstat	;get the status of the 
				;    SASI bus
	cpi	errmode
	jrnz	..cont
	call	readstat
	call	iferr

..cont: lda	permit
	cpi	'Y'	    ; did we save BTT
	cz	resBTI	    ; if so there's more
			    ; formatting to do
	lxi	H,DONMSG
	call	out$string

	lda	savblk
	sta	blkcnt

	lxi	H,FORMQ3    ; maybe we want to put
	call	out$string  ; firmware back, seeing as
	call	yorn	    ; we've just trashed it.
	cpi	'N'
	rz 
	jmp	VOLINIT
;---------------------------------
; Format a bad track/alternate track pair.
ALTFORM:
	call	FillE5
	lxi	H,cntfld
	set	5,M
	push	H
	call	FORM2TK
	pop	H
	res	5,M
	ret
FORM2TK:
	mvi	A,FALT
	mvi	B,9		; nine bytes!
	call	sendodd 	; (not six)
	call	waitreq
	call	SASIstat	;get the status of the 
				;    SASI bus
	cpi	errmode
	rnz		   ; back if no error bytes
	call	readstat   ; (actually I think there
	call	iferr	   ; always will be)
	ret
;---------------------------------
; Send a command to the controller
; Regs in:  A = command
; Regs out:  none
; Thrashed:  all

SENDCOM:
	mvi	B,6h		; to send six bytes.
SENDodd:			; enter here to send
				; other than 6 bytes
	push	PSW		; save command whilst
	lxi	H,high		; we figure volume to
	res	5,M		; put into address fld
	lda	volume
	ani	01		; (each xebec can talk
	jrz	..even		; to 2 disks.)
	set	5,M
..even:       
	pop	PSW
	lxi	H,task		; point
	mov	M,A		; put command in place
	call	select		; select controller
	call	waitreq
getstat:
	call	SASIstat	;get SASI bus status
	cpi	CMDMODE 	;if in the command mode
	jrz	oksend		;then OK to send
	lxi	H,ERR1		;else there was an err
	call	EXIT		;set the error message

oksend: call	deselect
	lxi	H,COMBUF
..send: call	waitreq
	mov	A,M		; get command byte
	out	dat$cmd$port	; send it oot		 
				; b3 clocked at end of
				; this instruction to
				; activate -ACK.
	inx	H		; next byte to send
	djnz	..send		; 1 less byte to go out
	ret		      ;return if all bytes sent

;------------------
waitreq:
..try:	
	ei
	in	PIOAD		; PIO PORT A
	bit	4,A		
	jrz	..try		
	ret
	  
 ;---------------------------
; Select or deselect a volume.	Each controller can
; talk to 2 volumes; a controller is addressed by
; activating one data line (in addition to D7 and D6
; which contain the sel/desel command).  For example
; D0 selects controller 0 which addresses volumes 0
; and 1.

select: 
	call	wbusy
	call	contbit
	adi	sel$cont
	out	toggle$port	; get into status mode
	out	dat$cmd$port	; SELECT CONTROLLER
	out	toggle$port	; return to data mode
	call	wBUSYnot
	ret
deselect:
	; deselect a controller
	; SEE NOTE ON PAGE 34 IN THE XEBEC MANUAL.
	call	contbit
	adi	desel$cont	;byte to deselect
				; a controller
	out	toggle$port	;get into status mode
	out	dat$cmd$port	;deselect it
	out	toggle$port	;return to data mode
	ret

; Activate the right data line for one controller.
contbit:
	push	B	; save cmd byte count
	lda	volume
	res	0,A
	rrc		; controller number
	inr	A	; start with 1
	mov	B,A
	mvi	A,80h	; 1 rotated right 1
..rlc:	rlc		; crank it around
	djnz	..rlc
	ani	3Fh	; 6 bits only!
	pop	B
	ret
;----------------------------------------
; Get the status of the SASI Interface bus
; Regs in: none
; Regs out: A = controller mode
;
SASIstat:
	out	toggle$port	; get into status mode
	in	dat$cmd$port	; I/O, MSG, C/D, BUSY
	out	toggle$port	; return to data mode
	ani	0FH		
	ret

;------------------	     
wbusy:	
	call	SASIstat
	bit	busy,a
	jrnz	wbusy
	ret
;
wBUSYnot:
	call	SASIstat
	bit	busy,a
	jrz	wBUSYnot
	ret
;------------------------------------------------
;
INIT:		;this subroutine initializes the 
		; drive characteristics in the
		; controller.

	mvi	B,4		; (reqd by asktyp)
	call	asktyp		; initially user must
				; tell us.
REINIT:
	mvi	a,initl
	call	sendcom 	; send the command
	mvi	b,8
	lhld	disktyp 	; disk parameters
..send: call	WAITREQ 	; (disktyp has address
	call	SASIstat	; of HD param block)
	cpi	WRTMODE 	; we're "writing" now
	jrnz	..err
	mov	A,M
	out	dat$cmd$port
	inx	H
	djnz	..send

	mov	A,M		; set buffered step
	sta	cntfld
	inx	H
	lxi	D,SperDRIVE	; we COULD figure this
	lxi	B,2		; out but why bother
	ldir
	lxi	D,DSperDRIVE
	lxi	B,2
	ldir
	ret

..err:	push	B
	lxi	H,err8
	call	out$string
	pop	B
	mov	A,B
	call	prtbyt
	ret
;-------------------
; Ask the user for the HD type and store
; the parameter block address in disktyp.
; Regs in:  B = maxvol - vol number
; Regs out:  HL = parameter block address
; Trashed: all

asktyp:
	call	fndtyp	    ; initially user
			    ; must tell us.
	call	pntDRinfo   ; get charactersitics
	shld	disktyp
	ret
;--------------------------
; Point at a harddisk parameter block
; Regs in:   A = disk type
; Regs out: HL = addr of beginning of block
; Trashed:  A, BC, HL

pntDRinfo:
	sui	1	    ; start with 0, not 1
	ral		    ; word values coming
	mov	C,A
	mvi	B,0
	lxi	H,chartabl
	dad	B	    ; HL points to table addr
	mov	A,M
	inx	H
	mov	H,M
	mov	L,A	    ; now HL HAS table addr
	ret
;
;-------------------------------------
;Subroutine: READSECT
;Action: read data from the disk through the controller
;Regs in:  none
;Regs out: At the end of the routine HL points 
;	   to the memory location after the last byte.
;Regs destroyed: all
;	   

READsect:
	lxi	H,RBUFFER
	lxi	D,RBUFFER+1
	mvi	M,0	; put 0 in RBUFFER
	lxi	B,sectsize; make more copies
	ldir
	mvi	A,1	; one sector
	call	RDDISK
	ret

;------------------------------------
; Subroutine READ1k
; this does what its name says	 
			
READ1K:
	lxi	H,RBUFFER
	lxi	D,RBUFFER+1
	mvi	M,0	; put 0 in RBUFFER
	lxi	B,1023	; make 1023 more copies
	ldir
	mvi	A,SperK ; how many sectors
	call	RDDISK
	ret
;-------------------------------------
; Read the disk.
; Regs in:  A = sector count
; Regs out: none except by fortunate coincidence
; Trashed: all
RDDISK:
	push	PSW
	lxi	H,blkcnt
	mov	A,M
	sta	savblk
	pop	PSW
	mov	M,A		; read one sector only

	lxi	H,RBUFFER
readin: 			; ISSUE COMMAND
	push	H		; save buffer ptr
	mvi	A,read
	call	sendcom
	lda	blkcnt		; block count is
	mov	B,A		; outer loop counter
	pop	H
..outr: push	B
	call	waitreq
	call	SASIstat
	cpi	RDDATMODE	; DATA XFER MODE...
	pop	B		; if we die, at least
	jrnz	..death 	; die with an even
	push	B		; stack.
	lxi	B,sectsize
..innr:
	in	dat$cmd$port   ;get byte of data.
	mov	M,A	       ;store it at the loca-  
			       ;tion indicated by HL.
	inx	H	       ;pnt at next location
	dcx	B	       ;1 less byte to read
	mov	A,B	       ;see if BC is zero yet
	ora	C
	jrnz	..innr	       ; until a sector is got
							 
	pop	B	       ; get outer loop counter
	djnz	..outr	       ; input the next sector.

..death:
	push	B	    ; save loop ctr
	push	H	    ; save memory loc
	call	readstat
	call	iferr
	pop	H
	pop	B	    ; blocks to go.
	mov	A,B
	ora	A
	jrz	..out	    ; none left.
	sta	blkcnt	    ; some left. Must have been
	lda	statbuf+2   ; an error.  See if it was
	ani	3Fh	    ; a data error.
	cpi	18h
	jrz	..derr	    ; correctable
	cpi	11h	    ; non-correctablie
	jrnz	..out	    ; neither, give up.
	dcr	B	    ; if non-correctable, data
	jrz	..out
	lxi	D,sectsize  ; wasn't xferred, so dcr
	dad	D	    ; loop counter here instead
			    ; and bump the buffer ptr.

..derr: lda	statbuf+5   ; data err refers to sector
	inr	A	    ; just xferred.  Get set to
	sta	low	    ; xfer the NEXT one.
	mov	A,B	    ; remaining to be moved
	sta	blkcnt	    ; this is now block count
	jmpr	readin	    ; go try & get the rest

..out:	lda	savblk		; we're done with block 
	sta	blkcnt		; count now
	ret

;------------------
; Get error status bytes from the controller.
; Assume controller has been selected and the
; command has been set up.
; Regs in:  none
; Regs out:  HL = ptr to location after
;		 the last byte
; Trashed:  all
	
readstat:
	mvi	B,2	       ;number of bytes to read

	lxi	H,STATBUF      ;buffer for status bytes

	call	waitreq
	call	SASIstat
	cpi	errmode
	jrz	..read
	lxi	H,ERR4
	call	exit
..read: 
	in	01H		; (next-to-last or
				; last) byte of status.
	mov	M,A
	inx	H
	dcr	B	; return if last one gotten
	rz
	
	    
	call	waitreq
	call	SASIstat	
	cpi	LASTMODE
	jrz	..read
	lxi	H,ERR5
	call	EXIT

;------------------
EXIT:	
	call	out$string
	rst	6
;
;---------------
;
iferr:
	;routine to see if completion status
	;byte indicates an error.

	lda	STATBUF 
	bit	1,a
	rz			;no error

	lxi	H,errat
	call	out$string
	call	paddr
	call	prtstat
	call	addERR		; add to error buffer
	lda	yeserr
	ora	A
	ret
;-------------------------------------
; clear the error buffer & reset pointer
 clrERR:
	lxi	H,errbuf
	push	H
	lxi	D,errbuf+1
	lxi	B,lerrbuf-1
	mvi	M,0
	ldir
	pop	H
	shld	errptr
	ret
;-------------------------------------
; Add most recent error to the error buffer;
;  return to DDT if buffer becomes full.

addERR:
	mvi	A,0FFh	; caller can use this
	sta	yeserr	; to see an error was caught

	lxi	H,statbuf
	lded	errptr
	lxi	B,8	; length to move
	ldir
	sded	errptr	; ptr for next time
	sub	A	; reset carry
	lxi	H,(errbuf+lerrbuf)-1
	dsbc	D	; see if past end
	rp		; if ok, just return

	lxi	H,errfull
	call	EXIT

yeserr: .byte	0
;-------------------------------------
; Get status and dump it oot

prtstat:
	lda	combuf		; save PREVIOUS command
	sta	statbuf+6	; for printing later 

	mvi	A,SENSE 	; get HD status report
	call	sendcom
	lxi	H,sense$req
	call	out$string
	mvi	B,4		; 4 bytes to read in
	lxi	H,statbuf+2
..in:	call	waitreq 	; wait for req 
	in	dat$cmd$port
	mov	M,A		; put byte away
	inx	H
	djnz	..in
	
	call	READSTAT	; better be ok now!
	mvi	B,5		; 4 bytes from troller
				; plus 1 for command
	call	dumpstat	; throw to screen
	ret

dumpstat:
	lxi	H,statbuf+2
..print:	
	mov	A,M
	exx
	call	prtbyt
	mvi	C,space
	call	conout
	exx
	inx	H
	djnz	..print
	ret
;---------------------------------
; Write 1k to the disk
; Regs in: none
; Regs out: none
; Trashed: all
WRT1k:
	mvi	A,SperK
	call	WRTDISK
	ret
;---------------------------------
; Write 256 bytes to the disk
; Regs in: none
; Regs out: none
; Trashed: all

WRTsect:
	mvi	A,1
	call	WRTDISK
	ret
 ;----------------------------------------
; Do a disk write
; Regs in:  A  = number of 256-byte sectors
; Regs out: none
; Thrashed: all

WRTDISK:
	push	PSW
	lxi	H,blkcnt
	mov	A,M
	sta	savblk
	pop	PSW
	mov	M,A	; number of sectors to write

	mvi	A,write
	call	sendcom
	lxi	H,WBUFFER
	lda	blkcnt

wrtout: 		; entry pt for format
	mov	B,A	; sectors = outer loop ctr.
..outr:
	call	waitreq
	call	SASIstat
	cpi	wrtmode
	jrz	..writ	
			       ; drop through if error
	cpi	errmode        ; any clues?
	jrz	..stat	       ;if so, continue
	lxi	H,ERR7	       ;if not, we may be s.o.l
	call	exit	       

..writ:
	push	B
	lxi	B,sectsize
..innr:
	mov	A,M
	out	dat$cmd$port
	inx	H
	dcx	B
	mov	A,B
	ora	C
	jrnz	..innr
	pop	B		; outer loop
	djnz	..outr
..stat: 
	call	readstat
	call	iferr 
	lda	savblk	; done with block size 
	sta	blkcnt
	ret			; hope this works

;-------------------------------------		
; Display and add to the Bad Track Table.
; Regs in: none
; Regs out: none
; Trashed: all
getBTT:
	call	showBTT
	call	makeBTT
	jrnz	getBTT
	ret

;-------------------------------------
; Subroutine: showBTT 
; Action: read and display Bad Track Table.
; Regs in:  none
; Regs out: HL = ptr to first available
;		 entry in table.
; Trashed:   all

showBTT:
	call	pntBTT	  ; aim at the table on disk
	call	READ1K
	call	newline
	lxi	H,BTT$head
	call	out$string	; print beet head
			
	lxi	H,RBUFFER	; got it, now print it
..line: push	H
	call	newline
	pop	H
	ei
	mov	A,M
	bit	7,A	    ; a legitimate number.
	jrz	..ok
      ; cpi	0E5h	    ; check for uninitialized
      ; cz	zroBTT	    ; zero out 'cause it's new
	jmpr	..eot	    ; that's all for this table.

..ok:	call	prt3byts	; print it on out
	call	blank
	call	blank
	call	prt3byts	; print its alternator
				; next
	jmpr	..line
			
..eot:	push	H
	lxi	H,EOTmsg
	call	out$string
	pop	H
	ret
			
;------------------------------------
; Rewrite the bad track table, optionally
; adding entries to it, or clearing it.
; Regs in:  HL = ptr to 1st available entry
;		 in BTT in read buffer
; Regs out: NZ if changes made
; Trashed:  all
makeBTT:
	call	askBTT	; assemble in RBUFFER
	rz		; no changes, return
	call	movBTT	; move to WBUFFER
	call	wrtBTT	; changes, write'em
	ori	0FFh	; show change made
	ret
;------------------------------------
; Ask for new defective sectors to add to the
; table.  Empty return ends procedure.
; Regs in:  HL = ptr to 1st available entry
; Regs out: Z if no changes, NZ if changes
; Trashed: all
askBTT:
	push	H
..ask:	lxi	H,NBTTMSG
	call	out$string
	call	getadr
	bit	0,B	; anything there
	pop	H
	rz		; done w/Z flag

	push	H
	call	eventrk
	lxi	H,adrbuf; move into safe place
	lxi	D,tmpBTT
	lxi	B,3
	ldir

..nalt: lxi	H,NALT1MSG; get alternate track
	call	out$string
	lhld	DSperDRIVE; print legal range
	call	prtWORD
	lxi	H,NALT2MSG
	call	out$string
	lhld	SperDRIAVE
	dcx	H
	call	prtWORD
	lxi	H,NALT3MSG
	call	out$string
	call	getadr	  ; if no alternate, no
	bit	0,B	  ; operation performed.
	jrz	..nalt

	lxi	H,adrbuf
	call	tALTrange ; see if within ok range
	jrnz	..nalt

	call	eventrk   ; So now we have the alleged
			  ; bad track # in tmpBTT and
	call	askokbst  ; its replacement in adrbuf.
	jrnz	..ask	  ; Ask if they're right.

	pop	H
pairform:		; (entry pt for auto restore)
	push	H
	lxi	H,tmpBTT; Try and format the alternate. 
	lxi	D,high	; If this fails we can do nothing.
	lxi	B,3
	ldir		; put bad track addr in place
	lxi	H,adrbuf
	lxi	D,althigh
	lxi	B,3
	ldir		; put alt track in place
	xra	A
	sta	yeserr
	call	ALTFORM ; formalternate track
	lda	yeserr
	ora	A
	pop	D	; place in bad table
	jrnz	..no
			; The format went ok so we can
			; put the entry in the table.
	lxi	H,tmpBTT; we saved bad track here
	lxi	B,3	; bytes to move
	ldir		; do it.
	lxi	H,adrbuf; also alternate
	lxi	B,3
	ldir
	ori	0FFh	; show we made a difference
	ret

..no:	lxi	H,cantmsg
	call	out$string
	xra	A	; no change!
..done:
	ret

;------------------------------------------
; Test whether address in buffer is within the
; legal range for alternate sectors.
; Regs in:  HL = ptr to buffer containing address
; Regs out: Z if ok, NZ if out of range

tALTrange:
	inx	H	; high byte not used yet
	mov	D,M	; get mid
	inx	H
	mov	E,M	; low
	xchg		; it's in H
	push	H	; save it
	xra	A
	sta	tstalt	; see if in data range
	call	testmax ; carry if above it
	pop	H
	jrnc	..low
	ori	0FFh	; see if in alt range
	sta	tstalt
	call	testmax
	jrc	..high
	xra	A	; Z if ok
	ret
..low:
..high: ori	0FFh
	ret
;-----------------------------------------------
; Ask for audience reaction to bad sector proposal
askokbst:
	lxi	H,okbst1  ; "Bad track: sectors "
	call	out$string
	lxi	H,tmpBTT
	call	prt3byts   ;"XXXXx0"
	lxi	H,okbst2   ;" through "
	call	out$string
	lda	tmpBTT+2
	adi	SperT-1    ; (figure upper bound)
	sta	tmpBTT+2
	lxi	H,tmpBTT
	call	prt3byts   ;"XXXXxF"
	lda	tmpBTT+2
	sui	SperT-1
	sta	tmpBTT+2   ; (restore lower bound)
	lxi	H,okbst3
	call	out$string  ;" Alternate "
	lxi	H,adrbuf
	call	prt3byts    ; "XXXXx0"
	lxi	H,okbst4    ; " through "
	call	out$string
	lda	adrbuf+2
	adi	SperT-1     ; (figure upper end)
	sta	adrbuf+2
	lxi	H,adrbuf
	call	prt3byts    ;"XXXXxF"
	call	eventrk     ; (restore address)
	lxi	H,okbst5    ; " --- OK? (Y/N) "
	call	out$string

	call	yorn	; make sure we got it right
	cpi	'Y'	; before we format it!!!!
	ret
;-----------------------------------
; Get the addr in adrbuf to a track boundary.
eventrk:
	lda	adrbuf+2
	ani	(#(SperT-1))&0FFh ; even track bndry
	sta	adrbuf+2
	ret
;------------------------------------
; Zero out the bad sector table
; Regs in: none
; Regs out: none
; Trashed: all

zroBTT:
	call	fill80	; fill wbuff w/80h
	call	wrtBTT
	ret
;------------------------------------
; Fill the write buffer with 80h, which for
; a Fox means an empty bad sector table.
; Regs in: none
; Regs out: none
; Trashed:  all
fill80:
	mvi	A,80h
	call	fillB
	ret

;------------------------------------
; Move the BTT from the read buffer to the
; write buffer.

; Regs in:  none
; Regs out: none
; Trashed: BC, DE, HL
movBTT:
	lxi	H,RBUFFER
	lxi	D,WBUFFER
	lxi	B,1024
	ldir
	ret
;------------------------------------
; Write the BTT out to the disk
;
; Regs in: none
; Regs out: none
; Trashed:  all
wrtBTT:
	call	pntBTT	; aim at it
	call	WRT1k	; write out
	ret
;--------------------------------------
; point the controller at the bad sector table
; Regs in:  none
; Regs out: none
; Trashed: all
pntBTT:
	lxi	H,high
	mvi	M,0	; logical track 1, sector 1
	inx	H	; is the first (i.e. 0th)
	mvi	M,0	; sector on phys trk 1.
	inx	H	; Phys tracks are half the
	mvi	M,2*SperT; size of CP/M tracks tho.
	ret
;----------------------------------------
; Save the Bad Track Table during a full disk test.
;
saveBTT:
	call	pntBTT
	call	READ1K	; get it to RBUFFER
	lxi	H,RBUFFER
	lxi	D,safearea
	lxi	B,1024
	ldir		; then move to safe area
	ret
;----------------------------
; Restore the Bad Track Table after a full disk test.
;
restBTT:
	lxi	H,safearea
	lxi	D,WBUFFER
	lxi	B,1024
	ldir		; move from safe place to
	call	wrtBTT	; WBUFFER, and write it.
	ret
;----------------------------
; Restore all bad-track information, including the
; formats, after a full-disk format operation.

resBTI:
	lxi	H,safearea ; table is put here
..loop: mov	A,M	   ; see if anything
	bit	7,A
	jrnz	..done
	lxi	D,tmpBTT   ; move into buffers as
	lxi	B,3	   ; though they'd been
	ldir		   ; input by the user in
	lxi	D,adrbuf   ; askBST, then let that
	lxi	B,3	   ; askBST do the work
	ldir
	push	H
	lxi	H,RBUFFER  ; assemble new table here
	call	pairform
	pop	H	   ; addr of next entry
	jmpr	..loop
..done: call	restBTT    ; restore old table.
	ret
;----------------------------

PRTTIME:
	lda	42h
	call	prtbyt
	call	blank
	lda	41h 
	call	prtbyt
	call	blank
	lda	40h
	call	prtbyt
	call	blank
	call	newline
	ret
;-------------------------------------
blank:
	push	B
	push	H
	mvi	C,space
	call	conout
	pop	H
	pop	B
	ret
;---------------------------
newline:
	lxi	H,crlf$
	call	out$string
	ret

;----------------------------------------
; Get a character if one is available, else
; return a zero.  Do not use BDOS call 6
; beacuse it louses up future Constats.

dirCONin:
	mvi	C,cpmCST
	call	BDOS
	ora	A
	rz
	call	conin
	ret

conin:
	mvi	C,cpmGET
	call	BDOS
	ret
;----------------------------------------
; print char in C using BDOS
;

CONOUT:
	push	PSW
	mov	E,C
	mvi	C,cpmPUT
	call	BDOS
	pop	PSW
	ret
;--------------------------------
; Get a line input through the BDOS.
;  Regs in: none
;  Regs out: A = char count
; Trashed: all

getline:
	lxi	D,linebuf
	mvi	C,cpmLIN
	call	BDOS
	lxi	H,linebuf+2
	shld	curchar
	lda	linebuf+1
	ora	A
	ret
;-------------------------------
; Pluck a character from the input buffer.
; Regs in:  none
; Regs out: A = char if present
;		carry flag set if no more
; Trashed:  all

nxtchar:
	lxi	H,linebuf+1
	dcr	M
	jm	..empt
	lhld	curchar
	mov	A,M	; get it
	inx	H
	shld	curchar
	ora	A
	ret

..empt: xra	A
	stc
	ret

;---------------------------------
; make a character upper case
; Regs in:  A = the character
; Regs out: A = same, upper case
; Trashed:  A, only

ucase:
	cpi	'a'
	rm
	cpi	'z'+1
	rp
	sui	'a'-'A'
	ret
;----------------------------------
; routine to print the current address
; in the disk command block
 
paddr:
	lxi	H,high	
	call	prt3byts
	ret
;--------------------
; Print any old word in HL
prtWORD:
	mov	A,H
	push	H
	call	prtbyt	      ; with no error
	pop	H
	mov	A,L
	call	prtbyt
	ret

;-------------------------------
; Print a three-byte string
; Regs in:  HL = ptr to 1st byte (high)
; Regs out: HL = (ptr to last byte)+ 1
prt3byts:
	push	B
	mvi	B,3
..loop: push	B
	mov	A,M
	call	prtbyt
	inx	H
	pop	B
	djnz	..loop
	pop	B
	ret
;---------------------------------
; Print a byte
; Regs in:  A = byte to print
; Regs out: none
; Thrashed: A,B,C at least

prtbyt:
	push	H
	push	PSW	; save the chr
	rlc		
	rlc
	rlc
	rlc
	call	prtnbl
	pop	PSW
	call	prtnbl
	pop	H
	ret
prtnbl: ani	0Fh	;clear high order nibble
	adi	'0'	; make it ascii
	mov	C,A	; chr goes out in C
	cpi	'9'+1	; if a digit it`s OK as is
	jc	CONOUT
	adi	'A'-('9'+1)
	mov	C,A	; chr goes out in C
	jmp	CONOUT

;------------------------
; Disk characteristic blocks for Xebec controller
;  Each has 7 bytes to send to controller and one
;  more so Joel knows which step option is best;
;  a word with the number of physical sectors, and
;  a word with the number of sectors that ALLOC can
;  allocate.

secCMI	==	14688*SperK  ; 58752 
secMIN	==	15360*SperK  ; 61440
secRMS	==	12288*SperK  ; 49152
secSYQ	==	 4896*SperK  ; 19584
secROD	==	15408*SperK  ; 61632
secIMI	==	14688*SperK  ; 58752

dsecCMI  ==	(secCMI-(20*SperT)) & $256Kmask
dsecMIN  ==	(secMIN-(20*SperT)) & $256Kmask
dsecRMS  ==	(secRMS-(20*SperT)) & $256Kmask
dsecSYQ  ==	(secSYQ-(20*SperT)) & $256Kmask
dsecROD  ==	(secROD-(20*SperT)) & $256Kmask
dsecIMI  ==	(secIMI-(29*SperT)) & $256Kmask

CHARTABL:
	.word	chrCMI
	.word	chrMIN
	.word	chrRMS
	.word	chrSYQ
	.word	chrROD
	.word	chrIMI

chrCMI: 		 ; 15 Megabyte CMI 5619.
	.byte	01h	 ; maximum number of
	.byte	(306-256);  cylinders
	.byte	06h	 ; number of heads
	.byte	01h	 ; reduce write
	.byte	(306-256);   current cylinder
	.byte	01	 ; write precomp cyl
	.byte	(306-256)
	.byte	04	 ; maximum ECC burst
			 ;  length
	.byte	07h	 ; step option
	.word	secCMI	 ; sectors on disk
	.word	dsecCMI  ; data sectors

chrMIN: 		 ; 16 Megabyte Miniscribe 4020.
	.byte	01h	 ; maximum number of
	.byte	(480-256);  cylinders
	.byte	04	 ; number of heads
	.byte	00	 ; reduce write
	.byte	128	 ;   current cylinder (ignored)
	.byte	00	 ; write precomp cyl
	.byte	00	 ; (i.e. always)
	.byte	11	 ; maximum ECC burst
			 ;  length
	.byte	00h	 ; step option
	.word	secMIN	 ; sectors
	.word	dsecMIN  ; data sectors

chrRMS: 		 ; 13 Megabyte RMS drive
	.byte	01h	 ; maximum number of
	.byte	00	 ;  cylinders (256)
	.byte	06h	 ; number of heads
	.byte	01h	 ; reduce write
	.byte	00	 ;   current cylinder
	.byte	01	 ; write precomp cyl
	.byte	00	   
	.byte	11	 ; maximum ECC burst
			 ;  length
	.byte	00h	 ; step option
	.word	secRMS	 ; sectors
	.word	dsecRMS
			
chrSYQ: 		 ; 5 Mbyte Syquest SQ306R
	.byte	01h	 ; maximum number of
	.byte	(306-256);  cylinders
	.byte	02h	 ; number of heads
	.byte	01h	 ; reduce write
	.byte	(306-256);   current cylinder
	.byte	01	 ; write precomp cyl
	.byte	(306-256)
	.byte	11	 ; maximum ECC burst
			 ;  length
	.byte	00h	 ; step option
	.word	secSYQ	 ; sectors
	.word	dsecSYQ

chrROD: 		 ; 16 Mbyte Rodime RO 203.
	.byte	01h	 ; maximum number of
	.byte	(321-256);  cylinders
	.byte	06h	 ; number of heads
	.byte	00h	 ; reduce write
	.byte	132	 ;   current cylinder
	.byte	01	 ; write precomp cyl
	.byte	(321-256); (i.e. never do it)
	.byte	11	 ; maximum ECC burst
			 ;  length
	.byte	00h	 ; step option
	.word	secROD	 ; sectors
	.word	dsecROD

chrIMI: 		 ; 16 Mbyte IMI 5018H.
	.byte	01h	 ; maximum number of
	.byte	(306-256);  cylinders
	.byte	06h	 ; number of heads
	.byte	00h	 ; reduce write
	.byte	214	 ;   current cylinder
	.byte	01	 ; write precomp cyl
	.byte	00 
	.byte	11	 ; maximum ECC burst
			 ;  length
	.byte	00h	 ; step option
	.word	secIMI	 ; sectors
	.word	dsecIMI

CMImask ==	1
MINmask ==	2
RMSmask ==	3
SYQmask ==	4
RODmask ==	5
IMImask ==	6
;----------------------------
; table of disk description messages

typtabl:
	.word	typNONE
	.word	typCMI
	.word	typMIN
	.word	typRMS
	.word	typSYQ
	.word	typROD
	.word	typIMI
;-----------------------------
volabel:.byte	10,0	; area for BDOS line read
	.blkb	10
linebuf:.byte	20,0
	.blkb	20
adrbuf: .byte	0,0,0,0,0,0 ; buffer stuffed by getadr
tmpBTT: .byte	0,0,0	; used by makeBTT
curchar:.word	0	; next char in linebuf
errptr: .word	0	; error buffer pointer
hugeptr:.word	hugebuf ; keeps track of save/restore
oktoseek:.byte	0	; disk init flag
permit: .byte	0	; Y,N, ctl-X in format
tstalt: .byte	0	; test alternate tracks too
savblk: .byte	1	; save block count
;
; Messages

mode6:	.asciz	[cr][lf]'error mode:                    
     '

SASImsg:.asciz	[cr][lf]'SASI status -- '
msg2:
ABORT$: .asciz	[cr][lf]'program aborted'
crlf$:	.asciz	[cr][lf]''
err1:	.ascii	[cr][lf]'SENDCOM: after selecting drive'
	.ascii	', the controller'
	.asciz	' was not in the command mode'
err2:	.ascii	[cr][lf]'READATA: controller not in'
	.asciz	' read data mode'
err3:	.ascii	[cr][lf]'READSTAT: controller not in'
	.asciz	' read status mode'
err4:	.ascii	[cr][lf]'READSTAT: controller not in'
	.asciz	' NXTLAST mode'
err5:	.ascii	[cr][lf]'READSTAT: controller not in'
	.asciz	' LAST mode'
err6:	.ascii	[cr][lf]'WRTSECT: controller not in'
	.asciz	' WRITE mode'
err7:	.ascii	[cr][lf]'WRTSECT: not in write mode, '
	.asciz 'nor in status byte mode. '
err8:	.ascii	[cr][lf]'INIT: not in write mode; '
	.asciz 'bytes left to send: '
;-----------------------
abreq:
	.asciz	[cr][lf]'Abort requested'
restart$:
	.asciz	[cr][lf]'restarting program '
errat:
	.asciz	[cr][lf]"Error at sector "
sense$req:
	.asciz	[cr][lf]'errcode,adrH,adrM,adrL,command: '
tbigmsg:
	.asciz	[cr][lf]'Out of range -- re-enter:'
cantmsg:
	.ascii	[cr][lf][lf]'THE PROPOSED ALTERNATE TRACK'
	.ascii	' IS ALREADY MARKED AS A BAD OR ALTERNATE TRACK.'
	.asciz	[cr][lf]
not$coded:
noDAVEyet:
	.asciz	[cr][lf]'Subroutine not implemented.'
goodbye: 
	.asciz	[cr][lf]'Goodbye'



PREmenu:
	.ascii	[cr][lf][lf]
	.ascii	"SELECT ONE OF THE FOLLOWING FUNCTIONS:"
	.ascii	[cr][lf]
	.ascii	"0 - ACCESS DIAGNOSTIC ROUTINES "
	.ascii	"(MUST BE EXECUTED UNDER DDT OR ZDTI)"[cr][lf]
	.ascii	"1 - FORMAT"[cr][lf]
	.ascii	"2 - INITIALIZE FIRMWARE"[cr][lf]
	.ascii	"3 - DISPLAY/ADD TO BAD SECTOR TABLE"[cr][lf]
	.asciz	[cr][lf]"ENTER 0,1,2 OR 3 - "

mbf4:	.ascii	[cr][lf]
	.ascii	[cr][lf]"ERROR NUMBER DESCRIPTIONS"
	.ascii	[cr][lf]"(SAME MEANING IF HIGH BIT IS ALSO SET)"[cr][lf]
	.ascii	[cr][lf]"01H  NO INDEX DETECTED               15H  SEEK ERROR" 
	.ascii	[cr][lf]"02H  SEEK NOT COMPLETED              18H  CORRECTABLE DATA ERR"
	.ascii	[cr][lf]"03H  WRITE FAULT                     19H  BAD TRACK"
	.ascii	[cr][lf]"04H  DRIVE NOT READY AFTER SELECT    1AH  FORMAT ERROR"
	.ascii	[cr][lf]"06H  TRACK 00 NOT FOUND              20H  UNKNOWN COMMAND"
	.ascii	[cr][lf]"10H  ID FIELD READ ERROR             21H  ILLEGAL ADDRESS"
	.ascii	[cr][lf]"11H  UNCORRECTABLE DATA ERROR        30H  RAM DIAGNOSTIC FAILURE"
	.ascii	[cr][lf]"12H  ADDRESS MARK NOT FOUND          31H  MEMORY CHECKSUM ERR"
	.ascii	[cr][lf]"14H  TARGET SECTOR NOT FOUND         32H  ECC DIAGNOSTIC FAILURE"
	.ascii	[cr][lf]"                                     40H  COMPARE ERROR"
	.asciz	[cr][lf]

deathmsg:
	.ascii	"THIS ROUTINE DESTROYS DATA ON THE DISK."[cr][lf]
	.ascii	"DO YOU WISH TO CONTINUE"
	.byte	qmark
	.asciz	" (Y/N) "

askmax: .asciz	[cr][lf]"Test alternate tracks too? (Y/N) "

mbf6:
	.ascii	[cr][lf]"BUFFER LOCATIONS AND DESCRIPTIONS:"
	.ascii	[cr][lf]"2300H  COMMAND BUFFER (task,addrH,addrM,addrL,"
	.ascii		"intrlv/blkcount,cntrl)"
	.ascii	[cr][lf]"2700H  WRITE BUFFER"
	.ascii	[cr][lf]"2BF8H  STATUS BUFFER (flag,00,errcode,addrH,addrM,"
	.ascii		"addrL,command)"
	.ascii	[cr][lf]"2C00H  READ BUFFER"
	.ascii	[cr][lf]"6000H  ERROR BUFFER"
	.asciz	[cr][lf]
;
hello$:
VERMSG: .ascii	"DMS/15 HARD DISK UTILITY PROGRAM VER "
	.byte	20H,30H+VERSION,".",30H+REVISION,30H+XVISION
	.byte	20H,cr,lf,0
LOGMSG: .ascii	[cr][lf]"THE FOLLOWING ENTRY POINTS ARE IMPLEMENTED:"[cr][lf]
	.ascii	"100H  PRINT THIS MESSAGE                "
	.ascii	[cr][lf]
	.ascii	"104H  RESTART PROGRAM                   "
	.ascii	"14CH  READ 1K"[cr][lf]
	.ascii	"108H  RESET HDC                         "
	.ascii	"158H  GET BAD TRACK TABLE"[cr][lf]
	.ascii	"10CH  ABSOLUTE SECTOR READ              "
	.ascii	"15CH  ZERO BAD TRACK TABLE"[cr][lf]
	.ascii	"110H  ABSOLUTE SECTOR WRITE             "
	.ascii	"160H  COMPARE"[cr][lf]
	.ascii	"114H  VERIFY READ ENTIRE DISK           "
	.ascii	"164H  CPM VOLUME/PARTITION SELECT"[cr][lf]
	.ascii	"118H  FORMAT ENTIRE DISK                "
	.ascii	"16CH  ERROR NUMBER DESCRIPTION"[cr][lf]
	.ascii	"11CH  FORMAT ONE TRACK                  "
	.ascii	"170H  GET VOLUME INFO"[cr][lf]
	.ascii	"120H  RUN WRITE, READ, COMPARE TEST     "
	.ascii	"184H  BUFFER LOCATIONS/DESCRIPTIONS"[cr][lf]
	.ascii	"124H  RUN SEEK TEST                     "
	.ascii	"190H  SET DISK TYPE"[cr][lf]
	.ascii	"12CH  INITIALIZE VOLUME INFO            "
	.ascii	"194H  DEFAULT DISK TYPE(FROM FIRMWARE)"[cr][lf]
	.ascii	"130H  HDC INTERFACE/DRIVE TEST"[cr][lf]
	.ascii	"134H  HDC INTERNAL DIAGNOSTICS"[cr][lf]
	.ascii	"140H  REPEAT TEST SECTOR UNTIL ERROR"[cr][lf]
	.ascii	"148H  WARMBOOT"[cr][lf]
	.asciz	[cr][lf]
 
WSdoing:.asciz	[cr][lf]"Writing sector:"
RSdoing:.asciz	[cr][lf]"Reading sector:"
CMPdoing:.asciz [cr][lf]"Comparing buffers:"
tRAMmsg:.asciz	[cr][lf]"Testing RAM buffer"
tINTmsg:.ascii	[cr][lf]"Testing internal circuitry"
	.asciz	[cr][lf]
g130msg:.ascii	[cr][lf]"Xebec controller is now testing"
	.asciz	" 1st sector of each track."
BTT$head:.ascii [cr][lf]"Sector, Alternate"
	.asciz	[cr][lf]"-----------------"
eotmsg: .asciz	[cr][lf]"---End of table--"[cr][lf]
NBTTMSG: .ascii [cr][lf][lf]"ADD NEW BAD TRACK ADDRESS"
	.asciz	[cr][lf]"(RETURN TO STOP) - "
NALT1MSG:.asciz [cr][lf]"ALTERNATE TRACKS ARE "
NALT2MSG:.asciz " THROUGH "
NALT3MSG:.asciz  [cr][lf]"ENTER ALTERNATE TRACK ADDRESS - "
okbst1: .asciz	[cr][lf][lf]"BAD TRACK: sectors "
okbst2: .asciz	" through "
okbst3: .asciz	[cr][lf]"ALTERNATE: sectors "
okbst4	==	okbst2
okbst5: .ascii	[cr][lf]"CAUTION - THESE TRACKS WILL BE REFORMATTED!"
okbst6: .asciz	[cr][lf]"OK TO PROCEED? (Y/N) "

okft1:	.asciz	"THIS ROUTINE WILL FORMAT SECTORS "
okft2	==	okbst2 ; "through "
okft3	==	okbst6 ; "ok to proceed?"

GHERMSG: .byte	7,qmark,cr,lf,0
BSPSBSP: .byte	7,8	      ;BELL,BSP,
spbs:	.byte	20H,8,0       ; SP,BSP
IERRMSG: .asciz "ERROR ENCOUNTERED"[cr][lf]   
TnoEmsg: .asciz [cr][lf]"CYCLES WITHOUT ERROR:"
;
ERRFUL: .asciz	[cr][lf]"ERROR BUFFER FULL "
;
SKMSG:	.ascii	[cr][lf]  
	.ascii	"1 - SEEK 0, MAX"[cr][lf]
	.ascii	"2 - SEEK 0, INCREMENTING TRACK"[cr][lf]
	.ascii	"3 - RANDOM SEEK"[cr][lf]
	.asciz	"ENTER 1,2, OR 3 - "

FORMQ1: .ascii	[cr][lf][lf]
	.ascii	"HARD DISK FORMAT "
	.asciz	[cr][lf]
FORMQ2: .ascii	[cr][lf]
	.asciz	"DO YOU WISH TO PRESERVE THE BAD TRACK INFORMATION (Y/N)? "
yornmsg:.asciz	[cr][lf]"Please answer with Y or N: "
BSYMSG: .asciz	[cr][lf][lf]"BUSY FORMATTING.... "
DONMSG: .asciz	"DONE. "
FORMQ3: .ascii	[cr][lf]"THE FORMATTING PROCESS ERASED THE FIRMWARE."
	.asciz	[cr][lf]"DO YOU WISH TO RE-INITIALIZE FIRMWARE NOW (Y/N)? "

TYPM1:	.ascii	[lf]
VolVolmsg:.asciz  [cr][lf]"Volume "
TYPM2:	.ascii	[cr][lf]"Possible device types:"
	.ascii	[cr][lf]"1 = CMI 5619"
	.ascii	[cr][lf]"2 = Miniscribe 4020"
	.ascii	[cr][lf]"3 = RMS 13 Mb"
	.ascii	[cr][lf]"4 = Syquest SQ306-R"
	.ascii	[cr][lf]"5 = Rodime RO 203"
	.ascii	[cr][lf]"6 = IMI 5018H"
	.asciz	[cr][lf][lf]"Enter volume type (0 if none present)- "
LABLMSG:.asciz	[cr][lf]"Enter volume label (10 chars max) - "
typNONE:.asciz	"No volume present         "
typCMI: .asciz	"CMI 5619  (15 M.)         "
typMIN: .asciz	"Miniscribe 4020  (16 M.)  "
typRMS: .asciz	"RMS harddisk (13 M.)      "
typSYQ: .asciz	"Syquest SQ306-R (5 M.)    "
typROD: .asciz	"Rodime  RO 203  (16 M.)   "
typIMI: .asciz	"IMI 5018H  (??M)          "
typBAD: .asciz	[cr][lf]"BAD FIRMWARE FOR THIS VOLUME "
ERRMSG: .asciz	[cr][lf]"ERROR TYPE "

;
	.byte	76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
	.byte	76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
	.byte	76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
	.byte	76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
	.byte	76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
	.byte	76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
stack:

	.loc	combuf
task:	.byte	00H
high:	.byte	00H
middle: .byte	00H
low:	.byte	00H
blkcnt:
intlv:	.byte	01H
cntfld: .byte	80H	; no retries, 3 msec step
althigh:.byte	00H	; alternate track assignments
altmid: .byte	00H
altlow: .byte	00H
volume: .byte	00H	; (not sent to controller)

	.end





