	dw	alvmf0		;scratch pad for allocation information
;
dphmf1:	dw	0		;translation table address
	dw	0
	dw	0
	dw	0
	dw	dirbuf		;directory buffer
	dw	dpbmf1		;pointer to disk parameter block
	dw	csvmf1		;scratch pad area for checking changed disks
	dw	alvmf1		;scratch pad for allocation information
;
dphmf2:	dw	0		;translation table address
	dw	0
	dw	0
	dw	0
	dw	dirbuf		;directory buffer
	dw	dpbmf2		;pointer to disk parameter block
	dw	csvmf2		;scratch pad area for checking changed disks
	dw	alvmf2		;scratch pad for allocation information
;
dphmf3:	dw	0		;translation table address
	dw	0
	dw	0
	dw	0
	dw	dirbuf		;directory buffer
	dw	dpbmf3		;pointer to disk parameter block
	dw	csvmf3		;scratch pad area for checking changed disks
	dw	alvmf3		;scratch pad for allocation information

;disk parameter buffers
;----------------------
;
dpbmf0:	dw	20	;SPT
	db	3	;BSH
	db	7	;BLM
	db	0	;EXM
	dw	79	;DSM
	dw	63	;DRM
	db	0C0h	;AL0
	db	0	;AL1
	dw	16	;CKS
	dw	3	;OFF
	db	2	;SECSIZ
;
dpbmf1:	dw	40	;SPT
	db	3	;BSH
	db	7	;BLM
	db	0	;EXM
	dw	164	;DSM
	dw	63	;DRM
	db	0C0h	;AL0
	db	0	;AL1
	dw	16	;CKS
	dw	2	;OFF
	db	3	;SECSIZ
;
dpbmf2:	dw	40	;SPT
	db	4	;BSH
	db	15	;BLM
	db	1	;EXM
	dw	81	;DSM
	dw	63	;DRM
	db	080h	;AL0
	db	0	;AL1
	dw	16	;CKS
	dw	2	;OFF
	db	3	;SECSIZ
;
dpbmf3:	dw	40	;SPT
	db	4	;BSH
	db	15	;BLM
	db	1	;EXM
	dw	169	;DSM
	dw	63	;DRM
	db	080h	;AL0
	db	0	;AL1
	dw	16	;CKS
	dw	2	;OFF
	db	3	;SECSIZ
;
dpbmf4:	dw	40	;SPT
	db	4	;BSH
	db	15	;BLM
	db	1	;EXM
	dw	94	;DSM
	dw	127	;DRM
	db	0C0h	;AL0
	db	0	;AL1
	dw	32	;CKS
	dw	2	;OFF
	db	4	;SECSIZ

dpbmf5:	dw	40	;SPT
	db	4	;BSH
	db	15	;BLM
	db	1	;EXM
	dw	194	;DSM
	dw	191	;DRM
	db	0E0h	;AL0
	db	0	;AL1
	dw	48	;CKS
	dw	2	;OFF
	db	4	;SECSIZ

	page
	endif			;End of 5" drive's unique code section
;=====================================================================
;Common routines for the DJDMA with 8 and 5.25" drives
;=====================================================
;
;Set up the disk controller
;--------------------------
;
dminit:	lxi	h,dmchan		;See if the controller will halt
	mvi	m,dmhalt
	inx	h
	mvi	m,0
	out	dmkick			;Start controller
	lxi	d,0			;Set up timeout counter
dminwt:	mov	a,m			;Test for status returned
	ora	a
	jnz	dmiok			;Controller has responded
	dcx	d			;Bump timeout counter
	mov	a,d
	ora	e
	jnz	dminwt
	stc				;Set error flag
	ret

dmiok:	call	dmparm			;Set the drive parameters
	lxi	h,dmsetu		;Set more parameters
	lxi	d,6
	call	dmdoit
	ret				;Return no error (C reset)

;Drivå selecô two®
;-----------------
;	1) 8¢ driveó arå driveó 0-3¬ 5.25¢ driveó arå driveó 4-7.
;
dmsel2:	sta	dmdriv			;Save the drive name
	sta	dmgsta+1		;(for sense status command)
	call	dmsptr			;Get status pointer
	mov	a,m
	sta	dmpsta			;Save current status
	ret

;Seek to track 0
;---------------
;
dmhome:	call	dmdpar			;Get the drive parameter address
	inx	h
	mvi	m,0			;Decalibrate the drive
	call	dmparm
	ret

;Set track
;---------
;
dmseek:	mov	a,c			;Set up DJDMA track
	sta	dmtrck
	ret

;Set sector
;----------
;
dmsec:	mov	a,c			;Set the sector number + side bit
	ora	b
	sta	dmsctr
	ret

;Set the DMA pointer
;-------------------
;
dmdma:	mov	h,b			;Set the DMA address
	mov	l,c
	shld	dmcdma
	ret

;Read/write a sector.
;--------------------
;	1) Notice that the carry is returned set if there were any
;	   errors otherwise it is returned cleared. Also notice that
;	   the accm is equal to the djdma returned status (e.g. 40=no_error)
;
dmread:	mvi	a,dmrsec		;Read sector command
	jmp	dmsrw

dmwrit:	mvi	a,dmwsec		;Write sector command

dmsrw:	sta	dmrwcm			;Set the disk command byte
	lxi	h,dmrdwr		;Read/write command channel address
	lxi	d,10
	call	dmcmd			;Do the read/write
	stc				;if (error eq true)
	rnz				;	return (carry_set=ERROR)
 	cmc				;else
	ret				;	return (carry_cleared=NO_ERROR)

;Seô floppù drivå parameters®
;----------------------------
;	1) Thió routinå inspectó thå DPARAÍ tablå anä iæ thå á drivå
;	  	call	fdside
wrmfail:call	fdhome		;Track 0, single density
	jc	wrmfail		;Loop if error

				;The next block of code re-initializes
				;   the warm boot loader for track 0
	mvi	a,5-2		;Initialize the sector to read - 2
	sta	newsec
	lxi	h,ccp-100h	;First revolution DMA - 100h
	shld	newdma
				;Load all of track 0

t0boot:	mvi	a,5-2		;First sector - 2
newsec	equ	$-1
	inr	a		;Update sector #
	inr	a
	cpi	27		;Size of track in sectors + 1
	jc	nowrap		;Skip if not at end of track
	jnz	t1boot		;Done with this track
	sui	27-6		;Back up to sector 6
	lxi	h,ccp-80h	;Memory address of sector - 100h
	shld	newdma
nowrap:	sta	newsec		;Save the updated sector #
	mov	c,a
	call	fdsec		;Set up the sector
	lxi	h,ccp-100h	;Memory address of sector - 100h
newdma	equ	$-2
	lxi	d,100h		;Update DMA address
	dad	d
nowrp:	shld	newdma		;Save the updated DMA address
	mov	b,h
	mov	c,l
	call	fddma		;Set up the new DMA address
	lxi	b,retries*100h+0;Maximum # of errors, track #
wrmfred:push	b
	call	fdseek		;Set up the proper track
	call	fdread		;Read the sector
	pop	b
	jnc	t0boot		;Continue if no error
	dcr	b
	jnz	wrmfred		;Keep trying if error
	jmp	fderr		;Too many errors, flash the light

;Load track 1, sector 1, sector 3 (partial), sector 2 (1024 byte sectors)

t1boot:	mvi	c,1		;Track 1
	call	fdseek
	lxi	b,ccp+0b00h	;Address for sector 1
	lxi	d,10*100h+1	;Retry count + sector 1
	call	wrmread
	lxi	b,ccp+0f00h	;Address for sector 2
	lxi	d,10*100h+3	;Retry count + sector 3
	call	wrmread

	lxi	b,0300h		;Size of partial sector
	lxi	d,ccp+1300h	;Address for sector 3
	lxi	h,ccp+0f00h	;Address of sector 3

wrmcpy:	mov	a,m		;Get a byte and
	stax	d		;   save it
	inx	d		;Bump pointers
	inx	h
	dcx	b		;Bump counter
	mov	a,b		;Check if done
	ora	c
	jnz	wrmcpy		;   if not, loop

	lxi	b,ccp+0f00h	;Address for sector 2
	lxi	d,10*100h+2	;Retry count + sector 2
	call	wrmread

	xra	a		;Clear error indicator
	ret

wrmread:push	d
	call	fddma		;Set DMA address
	pop	b
	call	fdsec		;Set sector
wrmfrd:	push	b		;Save error count
	call	fdread		;Read a sector
	jc	wrmerr		;Do retry stuff on error
	call	fdstat		;Sector size must be 1024 bytes
	ani	0ch		;Mask length bits
	sui	0ch		;Carry (error) will be set if < 0c0h
wrmerr:	pop	b		;Fetch retry count
	rnc			;Return if no error
	dcr	b		;Bump error count
	jnz	wrmfrd
	jmp	fderr		;Error, flash the light

	endif			;end of DJ2D/B warm boot routine

;DJ2D/B Sector Translate Routine
;-------------------------------
;
fdtran:	inx	b
	push	d		;Save table address
	push	b		;Save sector #
	call	fdget		;Get DPH for current drive
	lxi	d,10		;Load DPH pointer
	dad	d
	mov	a,m
	inx	h
	mov	h,m
	mov	l,a
	mov	a,m		;Get # of CP/M sectors/track
	ora	a		;Clear carry
	rar			;Divide by two
	sub	c		;Subtract sector number
	push	psw		;Save adjusted sector
	jm	sidetwo
sidea:	pop	psw		;Discard adjusted sector
	pop	b		;Restore sector requested
	pop	d		;Restore address of xlt table
sideone:xchg			;hl <- &(translation table)
	dad	b		;bc = offset into table
	mov	l,m		;hl <- physical sector
	mvi	h,0
	ret

sidetwo:call	fdgsid		;Check out number of sides
	jz	sidea		;Single sided
	pop	psw		;Retrieve adjusted sector
	pop	b
	cma			;Make sector request positive
	inr	a
	mov	c,a		;Make new sector the requested sector
	pop	d
	call	sideone
	mvi	a,80h		;Side two bit
	ora	h		;	and sector
	mov	h,a
	ret

;DJ2D/B First Time Drive Select Routine
;--------------------------------------
;
fdldrv:	sta	fdlog		;Save logical drive
	mov	c,a		;Save drive #
	mvi	a,0		;Have the floppies been accessed yet ?
flopflg	equ	$-1
	ana	a
	jnz	flopok

	mvi	b,17		;Floppies havn't been accessed
	lxi	h,fdboot	;Check if 2D controller is installed
	mvi	a,(jmp)
clopp:	cmp	m		;Must have 17 jumps
	jnz	zret
	inx	h
	inx	h
	inx	h
	dcr	b
	jnz	clopp
	lxi	d,fdinit	;Initialization sequence
	lxi	h,fdorig+7e2h	;Load address
	lxi	b,30		;Byte count
	call	movbyt		;Load controller RAM
	mvi	a,0ffh		;Start 1791
	sta	dreg
	mvi	a,clrcmd	;1791 reset
	sta	cmdreg
	mvi	a,1		;Set 2D initialized flag
	sta	flopflg

flopok:	call	flush		;Flush buffer since we are using it
	lda	fdlog		;Select new drive
	mov	c,a
	call	fdsel
	call	fdlhome		;Recalibrate the drive
	lxi	h,1		;Select sector 1 of track 2
	shld	truesec
	inx	h
	shld	cpmtrk
	xra	a		;Make sure we are doing a read
	sta	rdwr
	call	fill		;Fill in buffer with sector
	jc	zret		;Test for error return
	call	fdstat		;Get status on current drive
	sta	fdldst		;Save drive status
	ani	0ch		;Mask in sector size bits
	push	psw		;Used to select a DPB
	rar
	lxi	h,xlts		;Table of XLT addresses
	mov	e,a
	mvi	d,0
	dad	d
	push	h		;Save pointer to proper XLT
	call	fdget		;Get pointer to proper DPH
	pop	d
	lxi	b,2		;Copy XLT pointer into DPH
	call	movbyt
	lxi	d,8		;Offset to DPB pointer in DPH
	dad	d		;HL <- &DPH.DPB
	push	h
	call	fdgsid		;Get pointer to side flag table entry
	lda	fdldst		;Get drive status
	ani	dblsid		;Check double sided bit
	mov	m,a		;Save sides flag
	lxi	d,dpb128s	;Base for single sided DPB's
	jz	sideok
	lxi	d,dpb128d	;Base of double sided DPB's
sideok:	xchg
	pop	d		;(HL) -> DPB base, (DE) -> &DPH.DPB
	pop	psw		;Offset to correct DPB
	ral
	ral			;Make 0, 10, 20, 30
	mov	c,a
	mvi	b,0		;Make offset
	dad	b		;(hl) is now a DPB pointer
	xchg			;Put proper DPB address in DPH.DPB
	mov	m,e
	inx	h
	mov	m,d
	lxi	h,15		;Offset to DPB.SIZ
	dad	d
	mov	c,m		;Fetch sector size code
fdget:	lda	fdlog		;Return proper DPH
	lxi	d,dphfd0
	jmp	retdph

;DJ2D/B Non-Initial Drive Select Routine
;---------------------------------------
;
fdsel2:	sta	fdlog
	mov	c,a
	jmp	fdsel

;DJ2D/B Home Drive Routine
;-------------------------
;
fdlhome:mvi	c,0		;Select side 0
	call	fdside
	jmp	fdhome		;Do actual home

;DJ2D/B Set Sector Routine
;-------------------------
;
fdssec:	push	b		;Save sector number
	mov	a,b		;Check side select bit
	rlc			;Move high bit to bit zero
	ani	1
	mov	c,a
	call	fdside		;Call select side 0 = side A, 1 = Side B
	pop	b
	jmp	fdsec

fdgsid:	lxi	h,fdlsid	;Side flag table
	lda	fdlog		;Drive number
	push	d
	mov	e,a		;Make offset
	mvi	d,0
	dad	d		;Offset to proper entry
	pop	d
	mov	a,m		;Set up flags
	ora	a
	ret

fdinit:	dw	0		;Initialization bytes loaded onto 2D/B
	dw	1800h		;Head loaded timeout
	dw	0		;DMA address
	db	0		;Double sided flag
	db	0		;Read header flag
	db	07eh		;Drive select constant
	db	0		;Drive number
	db	8		;Current disk
	db	0		;Head loaded flag
	db	9		;Drive 0 parameters
	db	0ffh		;Drive 0 track address
	db	9		;Drive 1 parameters
	db	0ffh		;Drive 1 track address
	db	9		;Drive 2 parameters
	db	0ffh		;Drive 2 track address
	db	9		;Drive 3 parameters
	db	0ffh		;Drive 3 track address
	db	9		;Current parameters
	db	0		;Side desired
	db	1		;Sector desired
	db	0		;Track desired

	db	0		;Header image, track
	db	0		;Sector
	db	0		;Side
	db	0		;Sector
	dw	0		;CRC

fdlog:	db	0
fdldst:	db	0		;Floppy drive status byte

fdlsid:	rept	maxfd
	db	0ffh		;Double sided flag 0 = single, 1 = double
	endm
	endif
	page

	if	(maxfd ne 0) or (maxdm ne 0)	;DJDMA or DJ2DB present?
;***********************************************************************
; Begin Common Floppy Disk Translation tables and DPB's
;******************************************************
;
;Sector translation pointer table
;--------------------------------
;	1) Xlts is a table of address that point to each of the xlt
;	   tables for each sector size.
;
xlts:	dw	xlt128		;Xlt for 128 byte sectors
	dw	xlt256		;Xlt for 256 byte sectors
	dw	xlt512		;Xlt for 512 byte sectors
	dw	xlt124		;Xlt for 1024 byte sectors

;Sector translation tables
;-------------------------
;
;	1) Xlt tables (sector skew tables) for CP/M 2.0. These tables
;	   define the sector translation that occurs when mapping CP/M
;	   sectors to physical sectors on the disk. There is one skew
;	   table for each of the possible sector sizes. Currently the
;	   tables are located on track 0 sectors 6 and 8. They are
;	   loaded into memory in the Cbios ram by the cold boot roumvi	h,0
	dad	h
	dad	h
	dad	h
	dad	h
	dad	d		;(hl) = pointer to DPH
	mvi	c,4		;Return sector size of 1024
	ret

;HDDMA Non-Initial Drive Select Routine
;--------------------------------------
;
mwdrv:	sta	mwcurl
	call	mwdlog
	mov	a,c
	sta	mwdrive		;Save new selected drive
mwsel:	mvi	a,dmanoop
	jmp	mwprep		;Execute disk command

mwdlog:	mvi	c,0
mwllx:	sui	mwlog
	rc
	inr	c
	jmp	mwllx

mwstat:	mvi	a,dmassta	;Sense status operation code
	jmp	mwprep		;Execute disk command

;HDDMA Home Drive Routine
;------------------------
;
mwhome:	call	mwreset		;Reset controller, do a load constants
	lxi	h,dmarg1	;Load arguments
	mvi	m,steprcl	;Load step delay (slow rate)
	inx	h
	mvi	m,headdly	;Head settle delay
	call	mwissue		;Do load constants again
	call	mwptr		;Get pointer to current cylinder number
	mvi	m,0ffh		;Fake at cylinder 65535 for max head travel
	inx	h
	mvi	m,0ffh
	lxi	b,0		;Seek to cylinder 0
	call	mwseek		;Recal slowly
	jmp	mwreset		;Back to fast stepping mode

;HDDMA Return Bad Map Position Routine
;-------------------------------------
;
mwbad:	lxi	h,mwbtab	;Return pointer to bad sector location
	ret

mwbtab:	dw	0		;Track 0
	dw	19		;Head 2, sector 0  = (2 * SPT + 0) + 1

;HDDMA Set Track Routine
;-----------