.comment %
#########################################################
#							#
#	Double density diskette format program		#
#	for the Kaypro 10 (version 1.0)			#
#	(Double Sided Double Density)			#
#	based on FORMAT by Gilbert Ohynsty (and later	#
#	updated by Jim Nickerson and myself)		#
#							#
#	Begun 24-Mar-83					#
#	by Matthew Sherman.				#
#							#
#########################################################
%

.Z80

;
; track image location is after vfyflp.

extrn	tbuff, vfyfpy, mmenu

public	fmtfpy, fmt1tk, thnsd

; vfyfpy is the verify program's entry point
;

wboot	equ	0	; restart system entry point (Warm boot)
bdos	equ	5	; bdos entry
crlf	equ	0D0AH	; new line codes
cr	equ	0DH
lf	equ	0AH
return	equ	0DH	; ascii return code
esc	equ	1BH	; ascii esc
frsttrk	equ	0	; first track #
lsttrk	equ	79	; last track #
nsects	equ	10	; last sector #
data	equ	013H	; controller data port
cmnd	equ	010H	; controller command port
status	equ	010H	; status port for controller
wrtcmd	equ	0F4H	; write track command, 15 ms delay before execution
			; for 1793, write track command, 15 ms delay before
			; execution and side select output is made zero
			; (used with head select on double sided drives,
			;  which the Kaypro-II neither has nor supports)
rdcmd   equ     0E4H    ; read track command, 15 ms delay
			; same comments as for the write track command
rstcmd	equ	003H	; restore command
seekcmd	equ	013H	; seek command
bitport	equ	20	; drive select  port

; floppy drive equates
drvmsk	equ	11111110b	; reset drive select bits
fpyon	equ	00000000b	; select floppy
fpyoff	equ	00000001b	; deselect floppy
sidmsk	equ	11111011b	; reset side select bits
sid0	equ	00000100b
sid1	equ	00000000b
denmsk	equ	11011111b	; reset density select bits
dendbl	equ	00000000b	; select double density
densgl	equ	00100000b	; select single density
mtrmsk	equ	11101111b	; reset motor bit mask
mtron	equ	00010000b	; motor on mask
mtroff	equ	00000000b	; motor off mask
maxsec  equ     010     ; maximum number of sectors
secp    equ     012H    ; sector port

; print a message
print	macro	x
	ld	c,9
	ld	de,x
	call	bdos
	endm

; get a char from console, up case
input	macro
	ld	c,1
	call	bdos
	res	5,a
	endm

; write cnt number of val bytes into memory (hl)
bytes	macro	val, cnt
	local	loop
	ld	de,cnt
loop:	ld	(hl),val
	inc	hl
	dec	de
	ld	a,d
	or	e
	jr	nz,loop
	endm

; call bios routine, x=bios jump table #, 0=wboot, 1=const, 2=conin,...
bios	macro	x
	local	retadr
	ld	hl,(1)
	ld	de,x*3
	add	hl,de
	ld	de,retadr
	push	de
	jp	(hl)
retadr:
	endm

fmtfpy:	print	son1
	input
	cp	cr
	jp	nz,mmenu	; not a carriage return, quit,
				; else format the disk
fmtdsk:	print	newline
	call	format		; format floppy,
	call	vfyfpy		; verify floppy,
	jp	mmenu		; start over

format:	call	seldsk		; select floppy
	call	home		; home disk drive
	ld	c,frsttrk	; first track #
form1:	push	bc		; save track number while printing it
	print	smsg4		; "Track number:"
	pop	bc
	call	outdec		; display track number
	call	fmtone
	inc	c		; up track count
	ld	a,c		; max track+1 reached?
	cp	lsttrk+1
	jr	nz, form1	; do another track
	ret

; enter with track number in c
fmt1tk:	push	bc
	print newline
	print smsg4
	pop	bc
	push	bc
	call	outdec	; track number
	call	home	; make sure disk is selected and running, etc.
	pop	bc
fmtone:	call	settrk		; move to track given by c
	call	maktrk		; make track image, track # in c
	call	wrttrk		; format track
	ret

maktrk:	ld	hl,tran		; sector skew table
	push	hl		; store on stack for use
	ld	hl,tbuff	; hl^ to track image in memory
	ld	b,nsects	; number of sectors to gen

	bytes	04EH,	80	; post index gap
	bytes	0,	12
	bytes	0F6H,	3	; Writes C2
	bytes	0FCH,	1	; index AM
	bytes	04EH,	16	; pre ID gap

trksec:	bytes	0,	8
	bytes	0F5H,	3	; Writes A1
	bytes	0FEH,	1	; ID AM
	ld	a,c
	srl	a
	ld	(hl),a		;	track number
	inc	hl
	bytes	0,	1	;	side number = 00
	ex	(sp),hl		;		pointer to tran table
	ld	a,(hl)		;		pick up sector number
	bit	0,c
	jr	z,mktk2
	add	a,10		; add offset for second side
mktk2:	inc	hl		;		next table entry
	ex	(sp),hl		;		back on stack
	ld	(hl),a		;	sector number
	inc	hl
	bytes	2,	1	;	sector length = 512
	bytes	0F7H,	1	;	CRC
	bytes	04EH,	22	; post ID gap
	bytes	0,	12
	bytes	0F5H,	3	; writes A1
	bytes	0FBH,	1	; data AM
	bytes	0E5H,	512	; data field
	bytes	0F7H,	1	; CRC
	bytes	04EH,	26	; post data gap / pre ID gap

	dec	b		; down sector count
	jp	nz,trksec	; another sector to do in image?

        bytes	04EH,	30	; pre index gap
        or	a		; clear carry
	ld	de, tbuff	; compute length of track
	sbc	hl,de
	ld	(trklen),hl
	ex	(sp),hl		; tran tbl adr not needed
	pop	hl
	ret			; exit with hl=len of track

tran:	;new translate table
	defb	0, 8, 3, 6
	defb	1, 9, 4, 7
	defb	2, 5
;

xlate:  push    bc
        push    hl
        ld      hl,tran
        ld      c,a             ;copy disk logical sector number
        ld      b,0
        add     hl,bc
        ld      a,(hl)          ; translated sector number
        pop     hl
        pop     bc
        ret

indec:	ld	c,0		; enter a decimal number into c
inlp:	push	bc		; save deciamal number in c
	ld	c,1		; get a console character
	call	bdos
	pop	bc
	cp	'0'
	ret	c		; ascii value less than '0'
	cp	'9'+1
	ret	nc		; ascii value gtr than '9'
	sub	'0'
	ld	b,a		; save decimal digit in b
	ld	a,c
	add	a,a		; times 2
	add	a,a		; times 4
	add	a,c		; times 5
	add	a,a		; times 10	( a=c*10 )
	add	a,b		; a=(c*10)+b
	ld	c,a
	jr	inlp		; go get another digit

outdec:	push	bc		; save number in c
	ld	a,c		; decimal print the number in c
	ld	e,'0'		; e hold decimal digit
hund:	sub	100		; any hundreds digits?
	jr	c,tens
	inc	e		; bump hundreds digit
	jr	hund
tens:	add	a,100		; put back 100
	push	af		; save number
	ld	a,e		; leading zero digit?
	cp	'0'
	jr	z,ten1
	ld	c,2
	call	bdos		; write digit
ten1:	pop	af		; recover digit
	ld	e,'0'		; tens digit
ten2:	sub	10
	jr	c,ones
	inc	e		; bump tens digit
	jr	ten2
ones:	add	a,10+'0'
	push	af		; save number, print digit
	ld	c,2
	call	bdos		; tens digit
	pop	af
	ld	e,a
	ld	c,2
	call	bdos		; ones digit
	pop	bc		; restore number to c
	ret			; done

seldsk:	push	bc
	in	a,(bitport)
	ld	c,a
	and	drvmsk		; mask out floppy bits
	and	denmsk		; mask out density bits
	and	mtrmsk
	or	fpyon		; select floppy
	or	dendbl		; select double density
	or	mtron
	out	(bitport),a
	bit	4,c
	pop	bc
	ret	nz		; motor was on, exit
	push	de		; do delay.
	push	bc
	ld	b,50
	call	thnsd
	pop	bc		; motor up to speed,
	pop	de		; restore registers
	ret			; and exit

	; delay loop
thnsd:	ld	de,1670
tlp:	dec	de
	ld	a,d
	or	e
	jr	nz,tlp
	djnz	thnsd
	ret

home:	call	seldsk		; select drive
	in	a,(bitport)
	and	sidmsk
	or	sid0		; select side 0, always
	out	(bitport),a
	ld	a,rstcmd	; re-zero disk drive
	out	(cmnd),a
	jr	busy		; wait for command done

settrk:	push	bc		; seek track
	call	seldsk		; make sure that the motor is on
	call	busy
	ld	a,c		; track #
	srl	a
	out	(data),a
	ld	c,sid0
	jr	nc,setrk2
	ld	c,sid1
setrk2:	in	a,(bitport)
	and	sidmsk
	or	c
	out	(bitport),a
	ld	a,seekcmd	; command
	out	(cmnd),a
	pop	bc
	jr	busy

busy:	call	delay		;  delay for controller to set busy bit
bsy:	in	a,(status)	; wait for not busy
	bit	0,a
	jr	nz,bsy
	ret
delay:	call	dly
dly:	ex	(sp),hl
	ex	(sp),hl
	ret

wrttrk:	push	bc
	call	seldsk
	ld	hl,(trklen)	; length of track in byte
	ex	de,hl
	ld	c,data
	ld	hl,tbuff	; hl^ to track image, de is length
	ld	a,(66H)		; save byte at nmi
	push	af
	ld	a,0C9H		; store return inst at nmi
	ld	(66H),a
	ld	a,wrtcmd	; track write command
	out	(cmnd),a	; issue command
wrtlp:	halt			; wait for controller
	outi			; issue data byte pointed to by hl
	dec	de		; count=count-1
	ld	a,d		; count zero?
	or	e
	jp	nz,wrtlp	; more bytes
	pop	af		; recover byte at nmi
	ld	(66H),a
	pop	bc
	ret

son1:	db	cr,lf,lf,'Floppy format program for the Kaypro 10'
	db	cr,lf,lf,'Press a carriage return when ready,'
	db	cr,lf,'Any other key to quit.  $'

done:	defb	cr,'DONE                    ',cr,lf,'$'
smsg2:	defw	crlf
smsg4:	defb	return, 'Formatting track:$'

smsg3:	defb	' Enter <RETURN> to format, any other key to abort $'

secmsg: defb    ' Sector ','$'


newline:defw	crlf
	defb	'$'

trklen:	defw	0	; length of track
sector: defs    2       ; sector number
adrsa:  defs    2       ; format data pointer
adrsb:  defs    2       ; read buffer pointer
bytcnt: defs    2       ; byte count
dmaadr: defw    tbuff   ; dma adrs storage area

	defw	0000h	; for L80 to play with

	end
