; Z80DOS - Z80 Disk Operating System
;
; Version 1.0 - 05 Sept. 87 by Carson Wilson
;

; -------------------------------------------------------------------
;
; Z80DDISK.Z80 - Return CP/M Version, Disk Functions
;
; -------------------------------------------------------------------

;
; Return version number
;
cmnd12:	ld	a,22h			; Set version number
	jr	cmd25a			; And exit
;
; -----------------------------
;
;	Disk functions
;
; -----------------------------
;
; Reset disk system
;
cmnd13:	ld	hl,0			; Load zero
	ld	(login),hl		; All drives logged out
	ld	(dskro),hl		; All drives read/write
	xor	a
	ld	(diff),a		; Disk changed flag
	ld	hl,RamLow+00080h	; Set up DMA address
	ld	(DMA),hl		; And save it
	call	stDMA			; Do BIOS call
	xor	a			; Set default drive = 'A'
	ld	(defdrv),a		; Save it
	ld	a,ResDsk		; <crw>
	call	seldk			; Select drive 0=A, 1=B, etc.
	ld	a,(subflg)		; Get submit flag
	jr	cmd25a			; Exit
;
; Search for file
;
cmnd17:	call	seldrv			; Select drive from FCB
	ld	a,(ix+0)		; Get drive number from FCB
	sub	'?'			; Test if '?'
	jr	z,cmd17b		; If so all entries match
	ld	a,(ix+14)		; Get system byte
	cp	'?'			; Test if '?'
	jr	z,cmd17a		; Yes, jump
	ld	(ix+14),0		; Load system byte with zero
cmd17a:	ld	a,15			; Test first 15 items in FCB
cmd17b:	call	search			; Do search
cmd17c:	ld	hl,(dirbuf)		; Copy directory buffer
	ld	de,(DMA)		; To DMA address
	ld	bc,128			; Directory=128 bytes
	ldir
	ret				; Exit
;
; Search for next occurrence of file
;
cmnd18:	ld	ix,(dcopy)		; Get last FCB used by search
	call	seldrv			; Select drive from FCB
	call	searcn			; Search next file match
	jr	cmd17c			; And copy directory to DMA address
;
; Delete file
;
cmnd19:	call	seldrv			; Select drive from FCB
	call	delete			; Delete file
cmd19a:	ld	a,(searex)		; Get exit byte 00=file found,0ffh not
	jr	cmd25a			; And exit
;
; Rename file
;
cmnd23:	call	seldrv			; Select drive from FCB
	call	renam			; Rename file
	jr	cmd19a			; And exit
;
; Return login vector
;
cmnd24:	ld	hl,(login)		; Get login vector
cmd24a:	ld	(pexit),hl		; Save it
	ret				; And exit
;
; Return current drive
;
cmnd25:	ld	a,(defdrv)		; Get current drive
cmd25a:	jp	exit			; And exit
;
; Return allocation vector
;
cmnd27:	ld	hl,(alv)		; Get allocation vector
	jr	cmd24a			; And exit
;
; Return disk R/O vector
;
cmnd29:	ld	hl,(dskro)		; Get disk R/O vector
	jr	cmd24a			; And exit
;
; Set file attributes
;
cmnd30:	call	seldrv			; Select drive from FCB
	call	cstat			; Change status
	jr	cmd19a			; And exit
;
; Get Disk Parameter Block Address
;
cmnd31:	ld	hl,(ixp)		; get drive table
	jr	cmd24a			; And exit
;
; Set/get user code
;
cmnd32:	ld	a,e			; Get user code
	inc	a			; Test if 0ffh
	ld	a,(user)		; Get old user code
	jr	z,cmd25a		; If 0ffh then exit
	ld	a,e			; Get new user code
	and	01fh			; Mask it
	ld	(user),a		; Save it
	ret				; And exit
;
; Compute file size
;
cmnd35:	call	seldrv			; Select drive from FCB
	call	filsz			; Compute file size
	jr	cmd19a			; And exit
;
; Set random record count
;
cmnd36:	ld	hl,32			; Set pointer to next record
	call	calrrc			; Calculate random record count
ldrrc:	ld	(ix+33),d		; And save random record count
	ld	(ix+34),c
	ld	(ix+35),b
	ret				; And exit
;
; Reset individual disk drives
;
cmnd37:	ld	a,e			; Get mask LSB
	cpl				; Complement it
	ld	e,a
	ld	a,d			; Get mask MSB
	cpl				; Complement it
	ld	d,a
	ld	hl,(login)		; Get login vector
	ld	a,e			; Mask login vector
	and	l			; LSB
	ld	l,a
	ld	a,d			; Mask login vector
	and	h			; MSB
	ld	h,a
	ld	(login),hl		; Save login vector
	ex	de,hl			; Use login vector as mask
	ld	hl,(dskro)		; Get drive R/O vector
	ld	a,e			; Mask drive R/O vector
	and	l			; LSB
	ld	l,a
	ld	a,d			; Mask drive R/O vector
	and	h			; LSB
	ld	h,a
	ld	(dskro),hl		; Save drive R/O vector
	ret				; And exit
;
; Select disk from FCB
;
seldrv:	ld	a,0ffh			; Set disk select done flag
	ld	(fldrv),a
	ld	a,(defdrv)		; Get current drive
	ld	(drive),a		; Save it in memory
	ld	e,a			; Save it in register e
	ld	a,(ix+0)		; Get drive from FCB
	ld	(fcb0),a		; Save it
	cp	'?'			; Test if '?'
	jr	z,cmnd14		; Yes, then select drive from register e
	and	01fh			; Mask drive
	ld	a,e			; Test if zero
	jr	z,seldr0		; Select drive from register e
	ld	a,(ix+0)		; Get drive from FCB
	dec	a			; Decrement drive
seldr0:	call	seldk			; Select drive
	ld	a,(ix+0)		; Get drive from FCB
	and	0e0h			; Remove drive bits
	ld	b,a			; Save register
	ld	a,(user)		; Get user number
	or	b			; Insert user number in FCB
	ld	(ix+0),a
	ret				; And exit
;
; Select disk
;
cmnd14:	ld	a,e			; Copy drive number
;
seldk:	and	0fh			; Mask drive number to 0-15
	ld	b,a			; Save counter
	ld	de,(login)		; Get login vector
	or	a			; Test drive 'a'
	jr	z,seldk1		; Yes then jump
seldk0:	rr	d			; Shift login vector
	rr	e			; Until bit 0 register e
	djnz	seldk0			; Is current drive
seldk1:	ld	hl,defdrv		; Get pointer last drive
	bit	0,e			; Test if drive logged in
	jr	z,seldk2		; No, login drive
	cp	(hl)			; Test same drive
	ret	z			; Yes then exit
seldk2:	ld	(hl),a			; Save new current drive
	push	de			; Save drive logged in flag
	ld	c,a			; Copy drive number
	call	SelDsk			; Do BIOS select
	ld	a,h			; Test if error
	or	l
	jr	z,seldk3		; Yes, illegal drive number
	ld	e,(hl)			; Get LSB translation vector
	inc	hl			; Increment pointer
	ld	d,(hl)			; Get MSB translation vector
	inc	hl			; Increment pointer
	ld	(trans),de		; Save translation vector
	ld	(temp0),hl		; Save address temp0

	ld	de,6
	add	hl,de			; Point to dirbuf pointer <crw>

	ld	de,dirbuf		; Load dirbuf pointer
	ld	bc,8			; Copy 8 bytes pointers to
					; ..dirbuf, csv (wacd), allocation
	ldir				; ..vector pointer for this disk
	ld	hl,(ixp)		; Get drive parameter address
	ld	c,15			; Copy 15 bytes
	ldir
	pop	de			; Get drive logged in flag
	bit	0,e			; Test it
	ret	nz			; Drive logged in so return
	ld	hl,(login)		; Get login vector
	call	sdrvb			; Set drive bit in login vector
	ld	(login),hl		; Save login vector
	jr	initdr			; And setup drive tables
seldk3:
	ld	hl,(StSel)		; Load error message address
	jp	(hl)			; And display error

;
; Init drive
;  Clear allocation vector bit buffer after drive reset
;
initdr:	ld	de,(maxlen)		; Get length alv buffer-1 (bits)
	ld	a,3			; Divide by 8
initd0:	srl	d			; To get bytes
	rr	e
	dec	a
	jr	nz,initd0
	inc	de			; Increment, so all bits are cleared
	ld	hl,(alv)		; Get pointer alv buffer
	push	hl
initd1:	ld	(hl),0			; Clear 8 bits
	inc	hl			; Increment pointer
	dec	de			; Decrement counter
	ld	a,d			; Test if counter zero
	or	e
	jr	nz,initd1		; Not then jump
	pop	hl			; Get alv pointer
	ld	de,(ndir0)		; Get first two bytes alv buffer
	ld	(hl),e			; Save LSB
	inc	hl			; Increment pointer
	ld	(hl),d			; Save MSB
	ld	hl,(temp0)		; Clear number of files
	xor	a			; On this drive
	ld	(hl),a			; Clear LSB
	inc	hl			; Increment pointer
	ld	(hl),a			; Clear MSB
	ld	(subflg),a		; Clear submit flag (reset disk command)
	call	setfct			; Set file count
initd2:	ld	a,0ffh			; Update directory checksum
	call	rddir			; Read FCB's from directory
	call	tstfct			; Test last FCB
	ret	z			; Yes then exit
	call	caldir			; Calculate entry point FCB
	ld	a,(hl)			; Get first byte FCB
	cp	0e5h			; Test empty directory entry
	jr	z,initd2		; Yes then get next FCB
	cp	021h			; Test time stamp
	jr	z,initd2		; Yes then get next FCB
	ld	a,(user)		; Get user number
	cp	(hl)			; Test if user is same
	jr	nz,initd3		; No then jump
	inc	hl			; Point to file name
	ld	a,(hl)			; Get first char filename
	sub	'$'			; Test if '$'
	jr	nz,initd3		; Not then jump
	dec	a			; Load a with 0ffh
	ld	(subflg),a		; Save it in subflg
initd3:	ld	c,1			; Set bit in alv buffer
	call	fillbb			; Set bits from FCB in alv buffer
	call	setlf			; Update last file count
	jr	initd2			;
;
; Set drive bit in HL
;
sdrvb:	ex	de,hl			; Copy hl=>de
	ld	hl,1			; Get mask drive "a"
	ld	a,(defdrv)		; Get current drive
	or	a			; Test if drive "a"
	jr	z,sdrvb1		; Yes then done
sdrvb0:	add	hl,hl			; Get next mask
	dec	a			; Decrement drive counter
	jr	nz,sdrvb0		; And test if done
sdrvb1:	ld	a,d			; Hl=hl or de
	or	h
	ld	h,a
	ld	a,e
	or	l
	ld	l,a
	ret				; Exit
;
; Calculate sector/track directory
;
stdir:	ld	hl,(filcnt)		; Get FCB counter directory
	srl	h			; Divide by 4
	rr	l			; (4 FCB's / sector)
	srl	h
	rr	l
	ld	(recdir),hl		; Save value (used by checksum)
	ex	de,hl			; Copy it to de
	ld	hl,0			; Clear hl
;
; Calculate sector/track
;	Entry:	hl,de = sector number (128 byte sector)
;	Exit:	set track  = hl,de  /  maxsec
;		set sector = hl,de mod maxsec
;
calst:	ld	bc,(maxsec)		; Get sectors/track
	ld	a,17			; Set up loop counter
calst0:	or	a			; Test hl>=bc
	sbc	hl,bc
	ccf
	jr	c,calst1		; Yes then jump
	add	hl,bc			; No then restore hl
	or	a			; And clear carry
calst1:	rl	e			; Shift result in de
	rl	d
	dec	a			; Test last bit done
	jr	z,calst2		; Yes then exit
	rl	l			; Shift next bit in hl
	rl	h
	jr	calst0			; Continue
calst2:	push	hl			; Save sector number
	ld	hl,(nftrk)		; Get first track
	add	hl,de			; Add track number
	ld	b,h			; Copy it to bc
	ld	c,l
	call	SetTrk			; BIOS call set track
	pop	bc			; Restore sector number
	ld	de,(trans)		; Get translation table address
	call	SecTrn			; BIOS call sector translation
	ld	b,h			; Copy result to bc
	ld	c,l
	jp	SetSec			; BIOS call set sector
;
; Get disk map block number from FCB
;
; Exit: HL = address FCB
;	DE = disk map
;	BC = offset in disk map
;
getdm:	ld	c,(ix+32)		; Get next record
	ld	a,(nblock)		; Get number of blocks
	ld	b,a			; Save it
getdm0:	srl	c			; Shift next record
	djnz	getdm0			; Number of blocks times
getdm1:	cpl				; Complement number of blocks
	add	a,9			; Add 9
	ld	b,a			; B=8-number of blocks
	ld	a,(nextnd)		; Get extend mask
	and	(ix+12)			; Mask with extend
	rrca				; Rotate one right
getdm2:	rlca				; Rotate one left
	djnz	getdm2			; 8-number of blocks times
getdm3:	add	a,c			; Add the two values to get entry FCB
getdm4:	push	ix			; Get FCB address
	pop	hl
	ld	c,16			; Add offset 16 to point to dm
	add	hl,bc
	ld	c,a			; Add entry FCB
	add	hl,bc
	ld	a,(maxlen+1)		; Test 8 bits/16 bits FCB entry
	or	a
	jr	nz,getdm5		; 16 bits => jump
	ld	e,(hl)			; Get 8 bit value
	ld	d,0			; Make MSB zero
	ret				; And exit
getdm5:	add	hl,bc			; Add twice (16 bit values)
	ld	e,(hl)			; Get LSB
	inc	hl			; Increment pointer
	ld	d,(hl)			; Get MSB
	dec	hl			; Decrement pointer
	ret				; And exit
;
; Calculate sector number
;  entry: de=block number from FCB
;
calsec:	ld	hl,0			; Clear MSB sector number
	ld	a,(nblock)		; Get loop counter
	ld	b,a			; Save it in b
calsc0:	sla	e			; Shift l,d,e
	rl	d
	rl	l
	djnz	calsc0			; B times
calsc1:	ld	a,(nmask)		; Get sector mask
	and	(ix+32)			; And with next record
	or	e			; Set up LSB sector number
	ld	e,a
	ret				; And exit
;
; Calculate dirbuf entry point
;
caldir:	ld	hl,(dirbuf)		; Get start address dirbuf
	ld	a,(secpnt)		; Get sector pointer
	add	a,l			; Add l=l+a
	ld	l,a
	ret	nc			; No carry exit
	inc	h			; Increment h
	ret				; And exit
;
; Init file count
;
setfct:	ld	hl,-1			; Set up file count
	ld	(filcnt),hl		; Save it
	ret				; And exit
;
; Test file count
;
tstfct:	ld	hl,(filcnt)		; Test file count=0ffffh
	ld	a,h			; Get MSB
	and	l			; And LSB
	inc	a			; Test if result=0ffh
	ret				; And exit
;
; Set last file
;
setlf:	call	tstlf			; Test last file
	ret	c			; No then exit
	inc	de			; Increment last file
	ld	(hl),d			; Save it in temp0
	dec	hl
	ld	(hl),e
	ret				; And exit
;
; Test last file
;
tstlf:	ld	hl,(temp0)		; Get pointer to last file
	ld	de,(filcnt)		; Get file counter
	ld	a,e			; Subtract de-(hl)
	sub	(hl)
	inc	hl
	ld	a,d
	sbc	a,(hl)
	ret				; Exit
;
; Get next FCB from drive
;	Entry:	A = 0 check checksum
;		A = 0ffh update checksum
;
rddir:	ld	c,a			; Save checksum flag
	ld	hl,(filcnt)		; Get file counter
	inc	hl			; Increment it
	ld	(filcnt),hl		; And save it
	ld	de,(nfiles)		; Get maximum number of files
	or	a			; Clear carry
	sbc	hl,de			; Test if last file
	add	hl,de
	jr	z,rddir0		; No jump
	jr	nc,setfct		; Yes set file count to 0ffffh
rddir0:	ld	a,l			; Get file count LSB
	add	a,a			; *32
	add	a,a
	add	a,a
	add	a,a
	add	a,a
	and	060h			; Mask it
	ld	(secpnt),a		; Save it for later use
	ret	nz			; Return if not first FCB sector
	push	bc			; Save checksum flag
	call	stdir			; Calculate sector/track directory
	call	readdr			; Read sector directory
	pop	bc			; Restore checksum flag
;
; Update/check checksum directory
; entry c=0 check checksum, c=0ffh update checksum
;
chkdir:	ld	hl,(ncheck)		; Get number of checked records
	ld	de,(recdir)		; Get current record
	or	a			; Clear carry
	sbc	hl,de			; Test current record
	ret	z			; Exit if zero
	ret	c			; Exit if greater then ncheck
	ld	hl,(dirbuf)		; Get dirbuf
	ld	b,128			; Set up counter
	xor	a			; Clear checksum
chkdr0:	add	a,(hl)			; Add checksum
	inc	hl			; Increment pointer
	djnz	chkdr0			; 128 times
	ld	hl,(csv)		; Get pointer checksum directory
	add	hl,de			; Add current record
	inc	c			; Test checksum flag
	jr	z,chkdr1		; 0ffh=> update checksum
	cp	(hl)			; Test checksum
	ret	z			; Exit if ok
	ld	a,true
	ld	(diff),a		; Set disk changed flag
	jp	setfn
chkdr1:	ld	(hl),a			; Update checksum
	ret				; And exit
;
; Read sector from drive
;
; readr and writer modified to give separate error message--b.h.
;
readr:	call	read			; BIOS call read sector
	ld	hl,(rderr)
	jr	write0			; Test exit code
;
; Write sector on drive
;
writer:	call	write			; BIOS call write sector
	ld	hl,(wrterr)
write0:	or	a			; Test exit code
	ret	z			; Exit if ok
	ld	(retflg),a		; Allow retry for read/write errors
	jp	(hl)			; DOS error on d: write error
;
; Read directory from drive
;
readdr:	call	DMAdir			; Set up DMA directory
	call	readr			; Read record
	jr	stDMA			; Set up DMA user
;
; Write directory on drive
;
writdr:	ld	c,0ffh			; Update checksum directory
	call	chkdir
	call	DMAdir			; Set up DMA directory
	ld	c,1			; Write directory flag
	call	writer			; Write record
	jr	stDMA			; Set up DMA user
;
; Set DMA address command
;
cmnd26:	ld	(DMA),de		; Save DMA address
;
stDMA:	ld	bc,(DMA)		; Get DMA address
	jr	DMAdr0			; And do BIOS call
;
; Set DMA address directory
;
DMAdir:	ld	bc,(dirbuf)		; Get DMA address directory
DMAdr0:	jp	setDMA			; BIOS call set DMA

;
; Get bit from allocation vector buffer
;
;	Entry:	DE = block number
;	Exit:	A  = bit in LSB
;		B  = bitnumber in a
;		HL = pointer in alv buffer
;
getbit:	ld	a,e			; Get bit number
	and	7			; Mask it
	inc	a			; Add 1
	ld	b,a			; Save it
	ld	c,a			; Twice
	srl	d			; Get byte number
	rr	e			; De=de/8
	srl	d
	rr	e
	srl	d
	rr	e
	ld	hl,(alv)		; Get start address alv buffer
	add	hl,de			; Add byte number
	ld	a,(hl)			; Get 8 bits
getbt0:	rlca				; Get correct bit
	djnz	getbt0
	ld	b,c			; Restore bit number
	ret				; And return to caller
;
; Set/reset bit in allocation vector buffer
;	Entry	DE = block number
;		 C = 0 reset bit, c=1 set bit
;
setbit:	push	bc			; Save set/reset bit
	call	getbit			; Get bit
	and	0feh			; Mask it
	pop	de			; Get set/reset bit
	or	e			; Set/reset bit
setbt0:	rrca				; Rotate bit in correct position
	djnz	setbt0
	ld	(hl),a			; Save 8 bits
	ret				; And return to caller
;
; Fill bit buffer from FCB in dirbuf
;	Entry:	C = 0 reset bit
;		C = 1 set bit
;
fillbb:	call	caldir			; Get directory entry
	ld	de,16			; Get offset dm block
	add	hl,de			; Add offset
	ld	b,e			; Get block counter
fillb0:	ld	e,(hl)			; Get LSB block number
	inc	hl			; Increment pointer
	ld	d,0			; Reset MSB block number
	ld	a,(maxlen+1)		; Test >256 blocks present
	or	a
	jr	z,fillb1		; No then jump
	dec	b			; Decrement block counter
	ld	d,(hl)			; Get correct MSB
	inc	hl			; Increment pointer
fillb1:	ld	a,d			; Test block number
	or	e
	jr	z,fillb2		; Zero then get next block
	push	hl			; Save pointer
	push	bc			; Save counter and set/reset bit
	ld	hl,(maxlen)		; Get maximum lenght alv buffer
	or	a			; Reset carry
	sbc	hl,de			; Test de<=maxlen alv buffer
	call	nc,setbit		; Yes then insert bit
	pop	bc			; Get counter and set/reset bit
	pop	hl			; Get pointer
fillb2:	djnz	fillb0			; Repeat for all dm entries
	ret				; And return to caller
;
; Set write protect disk
;
cmnd28:
setwpd:	ld	hl,(dskro)		; Get disk R/O vector
	call	sdrvb			; Include drive bit
	ld	(dskro),hl		; Save disk R/O bit
setfn:	ld	de,(nfiles)		; Get maximum number of files-1
	inc	de			; Increment it
	ld	hl,(temp0)		; Get pointer to disk parameter block
	ld	(hl),e			; And save number of files
	inc	hl
	ld	(hl),d
	ret				; And return to caller
;
; Check file R/O bit
;
chkfro:	call	caldir			; Get directory entry
	ld	a,(searpu)		; Test if public file
	ld	b,a			; Save it
	ld	a,(searqu)		; Test if question mark used in file name
	or	b			; A=public file or question mark used
chkfr0:	ld	de,2			; Offset to public file bit
	add	hl,de			; Add offset
	or	a			; Test question mark used
	jr	z,chkfr1		; No then don't test public file bit
	bit	7,(hl)			; Test public file
	jr	nz,chkfr2		; Yes then error
chkfr1:	ld	e,7			; Offset to file R/O bit
	add	hl,de			; Add offset
	bit	7,(hl)			; Test file R/O
	jr	nz,chkfr2		; Yes then error
	or	a			; Test question mark used
	ret	z			; No then don't test system file bit
	inc	hl			; Increment to system file
	bit	7,(hl)			; Test system file
	ret	z			; No system file then ok
chkfr2:
	ld	hl,(sfilro)		; Get pointer to file R/O message
	jp	(hl)			; Display message

;
; Check drive read only
;
chkro:	ld	hl,(dskro)		; Get drive R/O vector
	call	sdrvb			; Set drive bit
	sbc	hl,de			; Test extra bit added
	ret	nz			; Yes then drive not R/O
	ld	hl,(stro)		; Get pointer to drive R/O message
	jp	(hl)			; Display message

;
; Get free block from allocation vector buffer
;	Entry:	DE = old block number
;	Exit:	DE = new block number (0 if no free block)
; HL counts up
; DE counts down
;
getfre:	ld	h,d			; Copy old block to hl
	ld	l,e
getfr0:	ld	a,d			; Test down counter is zero
	or	e
	jr	z,getfr1		; Yes then jump
	dec	de			; Decrememt down counter
	push	hl			; Save up/down counter
	push	de
	call	getbit			; Get bit from alv buffer
	rra				; Test if zero
	jr	nc,getfr3		; Yes then found empty block
	pop	de			; Get up/down counter
	pop	hl
getfr1:	ld	bc,(maxlen)		; Get maximum alv lenght-1 in bc
	or	a			; Clear carry
	sbc	hl,bc			; Test hl>=lenght alv-1
	add	hl,bc			; Restore hl (flags are not affected)
	jr	nc,getfr2		; End buffer then jump
	inc	hl			; Increment up counter
	push	de			; Save down/up counter
	push	hl
	ex	de,hl			; Save up counter in de
	call	getbit			; Get bit from alv buffer
	rra				; Test if zero
	jr	nc,getfr3		; Yes then found empty block
	pop	hl			; Get down/up counter
	pop	de
	jr	getfr0			; And test next block
getfr2:	ld	a,d			; Test if last block tested
	or	e
	jr	nz,getfr0		; No then test next block
	ret				; Exit (de=0)
getfr3:	scf				; Set block number used
	rla				; Save bit
	call	setbt0			; Put bit in alv buffer
	pop	de			; Get correct counter
	pop	hl			; Restore stack pointer
	ret				; Exit (de=block number)
;
; Search for file name
;	Entry:	A = number of bytes to search for
;
search:	ld	(searnb),a		; Save number of bytes
	ld	a,0ffh			; Set exit code to 0ffh (not found)
	ld	(searex),a
	ld	(dcopy),ix		; Copy FCB pointer to ram (search next)
	call	setfct			; Initiate file counter
;
; Mod. 0.1 had a bug in which the directory of a changed disk would not be
; read. Adding call home forces a directory read--b.h.
;
	call	home			; Call BIOS procedure
;
; Search next file name
;
SearcN:	xor	a			; Clear accu, check checksum dir.

; Next 3 lines moved here from SEARC1: to clear flags
; when last file in dir. is a public file. - C.W. 2/87

	ld	(searqu),a		; Clear question mark detected flag
	ld	(searpu),a		; Clear public file flag
	res	7,(ix+8)		; Reset public/system file flag
;
	call	rddir			; Get FCB from directory
	call	tstfct			; Test if past last entry
	jp	z,searc8		; Yes then jump
	ld	de,(dcopy)		; Get FCB pointer
	ld	a,(de)			; Get first byte
	cp	0e5h			; Test if searching empty directory
	jr	z,searc1		; Yes then jump
	push	de			; Save FCB pointer
	call	tstlf			; Test last file on this drive
	pop	de			; Restore FCB pointer
	jr	nc,searc8		; Yes then jump
searc1:	call	caldir			; Get entry in directory
	ld	a,(hl)			; Get first byte directory entry
	cp	021h			; Test time stamp
	jr	z,searcn		; Yes then get next directory entry
	ld	a,(searnb)		; Get number of bytes to search for
	ld	b,a			; Save it in counter
	xor	a			; Clear accu
	ld	c,a			; Clear counter
searc2:	ld	a,b			; Test if counter is zero
	or	a
	jr	z,searc9		; Yes then jump
	ld	a,(de)			; Get byte from FCB
	xor	'?'			; Test if question mark
	and	07fh			; Mask it (remove high bit)
	jr	z,searc6		; Yes then jump
	ld	a,c			; Get FCB counter
	or	a			; Test whether first byte
	jr	nz,searc3		; No
	ld	a,(flags)		; Yes. get flag byte
	bit	0,a			; Test public file enable
	jr	z,searc3		; No
	inc	hl			; Yes. get pointer to public bit
	inc	hl
	bit	7,(hl)			; Test public bit directory
	dec	hl			; Restore pointer
	dec	hl
	jr	z,searc3		; No public file then jump
	ld	a,(de)			; Get first byte FCB
	cp	0e5h			; Test if searching empty directory
	jr	z,searc3		; Yes then jump
	xor	(hl)			; Test FCB=directory entry
	and	07fh			; Mask it
	jr	z,searc5		; Yes then jump
	and	0e0h			; Mask user number
	jr	nz,searc3		; Not the same then jump
	dec	a			; A=0ffh
	ld	(searpu),a		; Set public file found
	set	7,(ix+8)		; Set public/system file flag
	jr	searc5			; Jump found
searc3:	ld	a,c			; Get FCB counter
	cp	13			; Test if at user code
	jr	z,searc5		; Yes then no test
	cp	12			; Test if at extend number
	ld	a,(de)			; Get byte from FCB
	jr	z,searc7		; Jump if extent number
	xor	(hl)			; Test byte FCB=byte directory entry
	and	07fh			; Mask it
searc4:	jr	nz,searcn		; Not the same then get next entry
searc5:	inc	de			; Increment pointer FCB
	inc	hl			; Increment pointer directory entry
	inc	c			; Increment counter
	dec	b			; Decrement counter
	jr	searc2			; Test next byte
searc6:	dec	a			; Set question mark found flag
	ld	(searqu),a
	jr	searc5			; Jump found
searc7:	push	bc			; Save counters
	xor	(hl)			; Test extends
	ld	b,a			; Save it
	ld	a,(nextnd)		; Get extent mask
	cpl				; Complement it
	and	01fh			; Mask it
	and	b			; Mask extents
	pop	bc			; Restore counters
	jr	searc4			; And test result
searc8:	call	setfct			; Error set file counter
	ld	a,0ffh			; And set exit code
	ld	(pexit),a
	ret				; Return to caller
searc9:	ld	a,(searqu)		; Get question mark found flag
	ld	b,a			; Save it
	ld	a,(searpu)		; Get public file flag
	and	b			; Test if public file and question mark
	jr	nz,searc4		; Yes then search for next entry
	call	setlf			; Update last file count (empty FCB)
	ld	a,(filcnt)		; Get file counter
	and	3			; Mask it
	ld	(pexit),a		; And set exit code
	xor	a			; Clear exit code search
	ld	(searex),a
	ret				; And return to caller
;
; Delete file
;
delete:	call	chkro			; Check disk R/O
	ld	a,12			; Number of bytes to search for
	call	search			; Search file
del0:	call	tstfct			; Test if file found
	ret	z			; Not then exit
	call	chkfro			; Check file R/O
	call	caldir			; Get entry point directory
	ld	(hl),0e5h		; Remove file
	ld	c,0			; Remove bits alv buffer
	call	fillbb
	call	wrFCB			; Write directory buffer on disk
	call	searcn			; Search next entry
	jr	del0			; And test it
;
; Rename file
;
renam:	call	chkro			; Check disk R/O
	ld	a,12			; Number of bytes to search for
	call	search			; Search file
renam0:	call	tstfct			; Test if file found
	ret	z			; Not then exit
	call	chkfro			; Check file R/O
	push	ix			; Save FCB entry
	pop	hl			; Get it in hl
	ld	de,16			; Offset to new name
	add	hl,de			; Add offset
	ex	de,hl			; Copy hl=>de
	call	caldir			; Get directory entry
	ld	b,11			; Set up loop counter
renam1:	inc	hl			; Increment directory pointer
	inc	de			; Increment FCB pointer
	ld	a,(de)			; Get character from FCB
	and	07fh			; Mask it
	cp	'?'			; Test if question mark
	jr	z,renam2		; Yes then do not change char. on disk
	ld	c,a			; Save it in c
	ld	a,(hl)			; Get character from directory
	and	080h			; Mask status bit
	or	c			; Or with new character
	ld	(hl),a			; Save in directory
renam2:	djnz	renam1			; Loop until done
	call	wrFCB			; And write directory on disk
	call	searcn			; Search next file
	jr	renam0			; And test it
;
; Change status file
;
cstat:	call	chkro			; Check disk R/O
	ld	a,12			; Number of bytes to search for
	call	search			; Search file
cstat0:	call	tstfct			; Test if file found
	ret	z			; Not then exit
	push	ix			; Save FCB entry
	pop	de			; Get it in hl
	call	caldir			; Get directory entry
	ld	b,11			; Set up loop counter
cstat1:	inc	hl			; Increment directory pointer
	inc	de			; Increment FCB pointer
	ld	a,(de)			; Get status bit from FCB
	and	080h			; Mask it
	ld	c,a			; Save it in c
	ld	a,(hl)			; Get character from directory
	and	07fh			; Mask it
	or	c			; Or with new status bit
	ld	(hl),a			; Save in directory
	djnz	cstat1			; Loop until done
	call	wrFCB			; And write directory to disk
	call	searcn			; Search next file
	jr	cstat0			; And test it
;
; Compute file size
;
filsz:	ld	bc,0			; Reset file size lenght
	ld	d,c
	call	ldrrc			; Save it in FCB+33,34,35
	ld	a,12			; Number of bytes to search for
	call	search			; Search file
filsz0:	call	tstfct			; Test if file found
	ret	z			; Not then exit
	call	caldir			; Get directory entry
	ex	de,hl			; Copy to de
	ld	hl,15			; Offset to next record
	call	calrrc			; Calculate random record count
	ld	a,d			; Test LSB < (ix+33)
	sub	(ix+33)
	ld	a,c			; Test isb < (ix+34)
	sbc	a,(ix+34)
	ld	a,b			; Test MSB < (ix+35)
	sbc	a,(ix+35)
	call	nc,ldrrc		; Write new maximum
	call	searcn			; Search next file
	jr	filsz0			; And test it
;
; Write FCB on disk
;
wrFCB:	call	stdir			; Calculate sector/track directory
	jp	writdr			; Write directory on disk
;
; Find file
;
findf:	ld	a,15			; Number of bytes to search for
	JP	search			; Search file
;
; Open file command
;
cmnd15:	call	seldrv			; Select drive from FCB
	ld	(ix+14),0		; Clear FCB+14
;
; Open file
;
openf:	call	findf			; Find file
	call	tstfct			; Test file found
	ret	z			; No then exit
openf0:	ld	a,(ix+8)		; Get public/system file bit
	push	af			; Save it
	ld	a,(ix+12)		; Get extent number from FCB
	push	af			; Save it
	call	caldir			; Get directory entry
	push	hl			; Save it <crw>
	ld	e,8			; Set access date/time <crw>
	call	stime			; Zero flag set if stamps present <crw>
	pop	hl			; Get directory entry <crw>
	push	ix			; Save FCB entry
	pop	de			; Get in in de
	ld	bc,32			; Number of bytes to move
	ldir				; Move directory to FCB
	call	z,wrFCB			; Write directory to disk if stamps
					; ..Present <crw>
nowrit:	set	7,(ix+14)		; Set FCB/file not modified
	ld	b,(ix+12)		; Get extent number
	ld	c,(ix+15)		; Get next record number
	pop	af			; Get old extent number
	ld	(ix+12),a		; Save it
	cp	b			; Compare old and new extent number
	jr	z,openf1		; Same then jump
	ld	c,0			; Set next record count to 0
	jr	nc,openf1		; Old extent >= new extent then jump
	ld	c,80h			; Set next record count to maximum
openf1:	ld	(ix+15),c		; Save next record count
	pop	af			; Get public/system file bit
	rl	(ix+8)			; Remove MSB from ix+8
	rla				; Set new MSB in carry
	rr	(ix+8)			; Save carry in ix+8
	ret				; And return to caller
;
; Close file command
;
cmnd16:	call	seldrv			; select drive from FCB
;
; Close file
;
close:	bit	7,(ix+14)		; test FCB/file modified
	ret	nz			; not then no close required
	call	chkro			; test disk R/O
	ld	a,15			; number of bytes to search for
	call	search			; search file
	call	tstfct			; test file present
	ret	z			; no then exit
	call	chkfro			; check file R/O
	call	caldir			; get directory entry
	ld	bc,16			; offset to dm block
	add	hl,bc			; add offset
	ex	de,hl			; save hl in de
	push	ix			; save FCB pointer
	pop	hl			; get it in hl
	add	hl,bc			; add offset
	ld	a,(maxlen+1)		; test number of block >= 256
	or	a
	jr	z,close0		; no then jump
	dec	b			; set flag
close0:	call	copydm			; copy and test blocks
	ex	de,hl			; exchange copy direction
	call	copydm			; copy and test blocks
	ex	de,hl			; exchange copy direction
	jr	nz,close4		; block not the same then error
	inc	hl			; increment pointer FCB
	inc	de			; increment pointer directory
	bit	0,b			; test number of block >= 256
	jr	z,close1		; no then jump
	inc	hl			; increment pointer FCB
	inc	de			; increment pointer directory
	dec	c			; decrement counter
close1:	dec	c			; decrement counter
	jr	nz,close0		; not ready then jump
	ld	hl,-20			; add -20 to get extent number
	add	hl,de			; hL contains pointer to extent number
	ld	a,(ix+12)		; get extent number FCB
	cp	(hl)			; compare with extent number directory
	jr	c,close3		; fCB < directory then jump
	ld	(hl),a			; save extent number in directory
	inc	hl			; get pointer to next record
	inc	hl
	inc	hl
	ld	a,(ix+15)		; get next record FCB
close2:	ld	(hl),a			; save next record in directory
close3:	ld	e,4			; Set last update date/time
	call	stime			; Update time
	call	caldir			; Get directory entry
	ld	bc,11			; Point to archive byte
	add	hl,bc
	res	7,(hl)			; reset archive bit
	res	7,(ix+11)		; reset bit in FCB
	jp	wrFCB			; write FCB on disk
;
close4:	ld	a,0ffh			; flag error
	ld	(pexit),a
	ret				; and return to caller
;
; Copy and test disk map
;
;	Entry:	HL = pointer to first FCB
;		DE = pointer to second FCB
;		 B = 000h if less then 256 blocks
;		     0ffh if more or equal to 256 blocks
;	Exit:	Z  blocks are the same
;		NZ blocks are not the same
;
copydm:	ld	a,(hl)			; get byte first FCB
	bit	0,b			; test number of blocks >=256
	jr	z,copyd0		; No then jump
	inc	hl			; Increment pointer
	or	(hl)			; Test byte =0
	dec	hl			; Decrement pointer
copyd0:	or	a			; Test block number is zero
	jr	nz,copyd1		; No then compare blocks
	ld	a,(de)			; Copy block from other FCB in empty location
	ld	(hl),a
	bit	0,b			; Test number of blocks >=256
	ret	z			; No then exit
	inc	hl			; Increment to MSB block numbers
	inc	de
	ld	a,(de)			; Copy block from other FCB in empty location
	ld	(hl),a
	jr	copyd2			; Jump trick to save space
copyd1:	ld	a,(de)			; Get block number first FCB
	sub	(hl)			; Test if the same
	ret	nz			; Not then return
	or	b			; Test if >=256 blocks
	ret	z			; No then return
	inc	hl			; Increment to MSB block numbers
	inc	de
copyd2:	ld	a,(de)			; Get block number first FCB
	sub	(hl)			; Test if the same
	dec	hl			; Decrement block FCB pointers
	dec	de
	ret				; And exit to caller
;
; Make file command
;
cmnd22:
	call	seldrv			; Select drive from FCB
	ld	(ix+14),0		; Clear FCB+14
;
; Make file
;
make:	call	chkro			; Check drive R/O
	ld	a,(ix+0)		; Get first byte FCB
	push	af			; Save it
	ld	(ix+0),0e5h		; Set first byte to empty file
	ld	a,1			; Search for 1 byte
	call	search			; Search empty file
	pop	af			; Get first byte FCB
	ld	(ix+0),a		; Restore it
	call	tstfct			; Test empty file found
	ret	z			; No then return error
	xor	a			; Clear FCB+13
	ld	(ix+13),a
	push	ix			; Save FCB pointer
	pop	hl			; Get it back in hl
	ld	de,15			; Prepare offset
	add	hl,de			; Add it
	ld	b,17			; Set loop counter
make0:	ld	(hl),a			; Clear FCB+15 up to FCB+31
	inc	hl			; Increment pointer
	djnz	make0			; And clear all bytes
	ld	e,2			; Set creation date
	call	stime			; Update time in directory
	ld	e,4			; Set last update date/time
	call	stime			; Update time in directory
	ld	e,8			; Set access date/time <crw>
	call	stime
	res	7,(ix+8)		; Reset public/system file bit
	res	7,(ix+11)		; Reset archive bit if present
	call	caldir			; Get directory entry
	push	ix			; Save FCB entry
	pop	de			; Get it in de
	ex	de,hl			; Exchange FCB and directory entry
	ld	bc,32			; Number of bytes to move
	ldir				; Move bytes
	call	wrFCB			; Write FCB on disk
	set	7,(ix+14)		; Set FCB/file not modified
	ret				; And return to caller
;
; Open next extent
;
openex:	bit	7,(ix+14)		; Test if FCB/file modified (write)
	jr	nz,openx2		; Not then jump
	call	close			; Close current FCB
	ld	a,(pexit)		; Get exit code
	inc	a			; Test if error
	ret	z			; Yes then exit
	call	calnex			; Calculate next extent
	jr	c,openx3		; Error then jump
	jr	nz,openx5		; fCB present from close then jump
openx0:	ld	a,15			; Search first 15 bytes
	call	search			; Search for file
openx1:	call	tstfct			; Test if file found
	jr	nz,openx5		; Yes then jump
	ld	a,(rdwr)		; Test read/write flag
	or	a			; Test if read
	jr	z,openx3		; Yes then error
	call	make			; Make new extent if write
	call	tstfct			; Test if succesfull
	jr	nz,openx6		; Yes then exit
	jr	openx3			; No then error
openx2:	call	calnex			; Calculate next extent
	jr	c,openx3		; Error then jump
	bit	7,(ix+10)		; Test system file bit
	jr	z,openx0		; No system file then jump
	call	findf			; Search for file
	jr	openx1			; Use same routine
openx3:	set	7,(ix+14)		; Set FCB/file not modified
	ld	a,0ffh			; Set exit code
openx4:	ld	(pexit),a
	ret				; And return to caller
openx5:	call	openf0			; Open file
openx6:	xor	a			; And clear exit code
	jr	openx4			; Use same routine
;
; Calculate next extent
;
;	Exit:	C  overflow detected
;		Z  search next extent
;		NZ next extent present (close)
;
calnex:	ld	b,(ix+12)		; Get extent number
	ld	c,(ix+14)		; Get FCB+14
	bit	6,c			; Test error bit random record
	scf				; Set error flag
	ret	nz			; Non zero then error exit
	inc	b			; Increment extent number
	ld	a,b			; Get extent number
	and	01fh			; Mask it
	ld	b,a			; Save it in b
	jr	nz,calnx0		; Non zero then jump
	inc	c			; Increment FCB+14
	ld	a,c			; Get it in a
	and	03fh			; Mask it
	ld	c,a			; Save it in c
	scf				; Set error flag
	ret	z			; And return if file overflow
	xor	a			; Clear zero flag (not same extent)
	jr	calnx1			; And save extent number and FCB+14
calnx0:	ld	a,(nextnd)		; Get next extent mask
	and	b			; Test if same extent (close)
calnx1:	ld	(ix+12),b		; Save extent number
	ld	(ix+14),c		; Save FCB+14
	ret				; And return to caller
;
; Read random record command
;
cmnd33:	call	seldrv			; Select drive from FCB
;
; Read random sector
;
rdran:	xor	a			; Set read/write flag
	call	ldFCB			; Load random record in FCB
	jr	z,reads			; No error then read sector
	ret				; Return error
;
; Read sequential
;
cmnd20:	call	seldrv			; Select drive from FCB
;
; Read sector
;
reads:	xor	a			; Set read/write flag
	ld	(rdwr),a		; Save it
	ld	a,(ix+32)		; Get record counter
	cp	080h			; Test if last record this extent
	jr	nc,reads1		; Yes then open next extent
	cp	(ix+15)			; Test if greater then current record
	jr	c,reads2		; No then get record
reads0:	ld	a,1			; Set end of file flag
	ld	(pexit),a		; Save it
	ret				; And return to caller
reads1:
	call	openex			; ..To open next extent
	ld	a,(pexit)		; Get exit code
	or	a
	jr	nz,reads0		; Yes then end of file
	ld	(ix+32),0		; Clear record counter
reads2:	call	getdm			; Get block number from dm in FCB
	ld	a,d			; Test block number = 0
	or	e
	jr	z,reads0		; Yes then end file
	call	calsec			; Calculate sector number (128 bytes)
	call	calst			; Calculate sector/track number
	call	readr			; Read data
	ld	a,(funct)		; Get function number
	cp	20			; Test if read sequential
	ret	nz			; No then return
	inc	(ix+32)			; Increment next record counter
	ret				; And return to caller
;
; ClrDsk - Reset Login Vector if disk change detected, and select drive
;		from FCB. <crw>
;
;    Instead of setting disks to read-only, "diff" flag is set by
;    calls to wrFCB from Delete, Rename, Change Status, Open, Close,
;    Select, and Make if the disk in use has changed.  Next call to
;    write sequential or random then resets all disks.	Two
;    consecutive calls to write between which a disk was changed may
;    overwrite data, as is also the case with CP/M.
;
clrdsk:
	ld	a,(diff)		; Disk changed flag
	or	a
	jr	z,clrd0
	xor	a
	ld	(diff),a		; Clear flag
	ld	h,a
	ld	l,a
	ld	(login),hl		; Clear all drives
					; ..(crude but effective)
clrd0:
	call	seldrv			; Select disk from FCB
	ret
;
; Write random record commands
;
cmnd34:
cmnd40:
	call	clrdsk			; Reset disks if changed
					; ..and select drive from FCB
;
; Write random sector
;
wrran:	ld	a,0ffh			; Set read/write flag
	call	ldFCB			; Load FCB from random record
	jr	z,writes		; No error then write record
	ret				; Return error
;
; Write sequential
;
cmnd21:
	call	clrdsk			; Reset disks if changed
					; ..and select drive from FCB
;
; Write sector
;
writes:
	ld	a,0ffh			; Set read/write flag
	ld	(rdwr),a		; And save it
	call	chkro			; Check disk R/O
	bit	7,(ix+9)		; Test if file R/O
	jp	nz,chkfr2		; Yes then file R/O message
	bit	7,(ix+8)		; Test if public or system file
	jp	nz,chkfr2		; Yes then file R/O message
	ld	a,(ix+32)		; Get record count
	cp	080h			; Test if end this extent
	jr	c,writs0		; Yes then open next extent
	call	openex			; Open next extent
	ld	a,(pexit)		; Get error code
	or	a
	jp	nz,writs9		; Error then directory full error
	ld	(ix+32),0		; Clear record counter
writs0:	call	getdm			; Get block number from FCB
	ld	a,d			; Test if block number = 0
	or	e
	jr	nz,writs5		; No then write sector
	push	hl			; Save pointer to block number
	ld	a,c			; Test first block number in extent
	or	a
	jr	z,writs1		; Yes then jump
	dec	a			; Decrement pointer to block number
	call	getdm4			; Get previous blocknumber
writs1:	call	getfre			; Get nearest free block
	pop	hl			; Get pointer to block number
	ld	a,d			; Test if blocknumber = 0
	or	e
	jr	z,writs8		; Yes then disk full error
	res	7,(ix+14)		; Reset FCB/file modified
	ld	(hl),e			; Save blocknumber
	ld	a,(maxlen+1)		; Get number of blocks
	or	a			; Test if <256
	jr	z,writs2		; Yes then jump
	inc	hl			; Increment to MSB block number
	ld	(hl),d			; Save MSB block number
writs2:	ld	c,2			; Set write new block flag
	ld	a,(nmask)		; Get sector mask
	and	(ix+32)			; Mask with record counter
	jr	z,writsx		; Zero then ok (at start new record)
	ld	c,0			; Else clear new block flag
writsx:	ld	a,(funct)		; Get function number
	sub	40			; Test if write rr with zero fill
	jr	nz,writs6		; No then jump
	push	de			; Save blocknumber
	ld	hl,(dirbuf)		; Use directory buffer for zero fill
	ld	b,128			; 128 bytes to clear
writs3:	ld	(hl),a			; Clear directory buffer
	inc	hl			; Increment pointer
	djnz	writs3			; Clear all bytes
	call	calsec			; Calculate sector number (128 bytes)
	ld	a,(nmask)		; Get sector mask
	ld	b,a			; Copy it
	inc	b			; Increment it to get number of writes
	cpl				; Complement sector mask
	and	e			; Mask sector number
	ld	e,a			; And save it
	ld	c,2			; Set write new block flag
writs4:	push	hl			; Save registers
	push	de
	push	bc
	call	calst			; Calculate sector/track
	call	DMAdir			; Set DMA directory buffer
	pop	bc			; Get write new block flag
	push	bc			; Save it again
	call	writer			; Write record on disk
	pop	bc			; Restore registers
	pop	de
	pop	hl
	ld	c,0			; Clear write new block flag
	inc	e			; Increment sector number
	djnz	writs4			; Write all blocks
	call	stDMA			; Set user DMA address
	pop	de			; Get block number
writs5:	ld	c,0			; Clear write new block flag
writs6:	res	7,(ix+14)		; Reset FCB/file modified flag
	push	bc			; Save it
	call	calsec			; Calculate sector number (128 bytes)
	call	calst			; Calculate sector/track
	pop	bc			; Get write new block flag
	call	writer			; Write record on disk
	ld	a,(ix+32)		; Get record counter
	cp	(ix+15)			; Compare with next record
	jr	c,writs7		; If less then jump
	inc	a			; Increment record count
	ld	(ix+15),a		; Save it on next record position
	res	7,(ix+14)		; Reset FCB/file modified flag
writs7:	ld	a,(funct)		; Get function number
	cp	21			; Test write sequential
	ret	nz			; Not then return
	inc	(ix+32)			; Increment record count
	ret				; And return to caller
writs8:	ld	a,2			; Set disk full error
	ld	(pexit),a
	ret				; And return to caller
writs9:	ld	a,1			; Set directory full flag
	ld	(pexit),a
	ret				; And return to caller
;
; Load FCB for random read/write
;
;	Exit:	Z  no error
;		NZ error occured
;
ldFCB:	ld	(rdwr),a		; Save read/write flag
	ld	a,(ix+33)		; Get first byte random record
	ld	d,a			; Save it in d
	res	7,d			; Reset MSB to get next record
	rla				; Shift MSB in carry
	ld	a,(ix+34)		; Load next byte random record
	rla				; Shift carry
	push	af			; Save it
	and	01fh			; Mask next extent
	ld	c,a			; Save it in c
	pop	af			; Get byte
	rla				; Shift 4 times
	rla
	rla
	rla
	and	0fh			; Mask it
	ld	b,a			; Save FCB+14
	ld	a,(ix+35)		; Get next byte random record
	ld	e,6			; Set random record to large flag
	cp	4			; Test random record to large
	jr	nc,ldFCB8		; Yes then error
	rlca				; Shift 4 times
	rlca
	rlca
	rlca
	add	a,b			; Add byte
	ld	b,a			; Save FCB+14 in b
	ld	(ix+32),d		; Set next record count
	ld	d,(ix+14)		; Get FCB+14
	bit	6,d			; Test error random record
	jr	nz,ldFCB0		; Yes then jump
	ld	a,c			; Get new extent number
	cp	(ix+12)			; Compare with FCB
	jr	nz,ldFCB0		; Not equal then open next extent
	ld	a,b			; Get new FCB+14
	xor	(ix+14)			; Compare with FCB+14
	and	03fh			; Mask it
	jr	z,ldFCB6		; Equal then return
ldFCB0:	bit	7,d			; Test FCB modified (write)
	jr	nz,ldFCB1		; No then jump
	push	de			; Save registers
	push	bc
	call	close			; Close extent
	pop	bc			; Restore registers
	pop	de
	ld	e,3			; Set close error
	ld	a,(pexit)		; Get exit code
	inc	a
	jr	z,ldFCB7		; Error then exit
ldFCB1:	ld	(ix+12),c		; Save new extent number
	ld	(ix+14),b		; Save new FCB+14
	bit	7,d			; Test FCB modified (previous FCB)
	jr	nz,ldFCB3		; No then jump
ldFCB2:	ld	a,15			; Set number of bytes to search for
	call	search			; Search next FCB
	jr	ldFCB4			; Jump
ldFCB3:	bit	7,(ix+10)		; Test if system file
	jr	z,ldFCB2		; No use search
	call	findf			; Open file
ldFCB4:	ld	a,(pexit)		; Get error code
	inc	a
	jr	nz,ldFCB5		; No error then exit
	ld	a,(rdwr)		; Get read/write flag
	ld	e,4			; Set read empty record
	inc	a
	jr	nz,ldFCB7		; Read then error
	call	make			; Make new FCB
	ld	e,5			; Set make error
	ld	a,(pexit)		; Get error code
	inc	a
	jr	z,ldFCB7		; Error then exit
	jr	ldFCB6			; No error exit (zero set)
ldFCB5:	call	openf0			; Open file
ldFCB6:	xor	a			; Set zero flag and clear error code
	ld	(pexit),a
	ret				; And return to caller
ldFCB7:	ld	(ix+14),0c0h		; Set random record error
ldFCB8:	ld	a,e			; Get error code
	ld	(pexit),a		; And save it
	set	7,(ix+14)		; Set FCB/file not modified
	or	a			; Clear zero flag
	ret				; And return to caller
;
; Calculate random record
;	Entry:	HL = offset in FCB
;		DE = FCB pointer
;	Exit:	D  = LSB random record
;		C  = ISB random record
;		B  = MSB random record
;
calrrc:	add	hl,de			; Pointer to FCB+15 or FCB+32
	ld	a,(hl)			; Get byte
	ld	hl,12			; Offset to extent number
	add	hl,de			; Get pointer to extent byte
	ld	d,a			; Save first byte
	ld	a,(hl)			; Get extent byte
	and	01fh			; Mask it
	rl	d			; Shift MSB in carry
	adc	a,0			; Add carry
	rra				; Shift 1 time (16 bits)
	rr	d
	ld	c,a			; Save isb
	inc	hl			; Increment to FCB+14
	inc	hl
	ld	a,(hl)			; Get FCB+14
	rrca				; Shift 4 times
	rrca
	rrca
	rrca
	push	af			; Save it
	and	03h			; Mask MSB
	ld	b,a			; Save it
	pop	af			; Get LSB
	and	0f0h			; Mask it
	add	a,c			; Add with isb
	ld	c,a			; Save isb
	ret	nc			; No carry then return
	inc	b			; Increment MSB
	ret				; And return to caller

; END Z80DDISK.Z80

arry
	rra				; Shift 1 time (16 bits)
	rr	d
	ld	c,a			; Save isb
	inc	hl			; Increment to FCB+14
	inc	hl
	ld	a,(hl)			; Geееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее; Z80DOS - Z80 Disk Operating System
;
; Version 1.0 - 05 Sept. 87 by Carson Wilson
;

; -------------------------------------------------------------------
;
; Z80DDISK.Z80 - Return CP/M Version, Disk Functions
;
; -------------------------------------------------------------------

;
; Return version number
;
cmnd12:	ld	a,22h			; Set version number
	jr	cmd25a			; And exit
;
; -----------------------------
;
;	Disk functions
;
; -----------------------------
;
; Reset disk system
;
cmnd13:	ld	hl,0			; Load zero
	ld	(login),hl		; All drives logged out
	ld	(dskro),hl		; All drives read/write
	xor	a
	ld	(diff),a		; Disk changed flag
	ld	hl,RamLow+00080h	; Set up DMA address
	ld	(DMA),hl		; And save it
	call	stDMA			; Do BIOS call
	xor	a			; Set default drive = 'A'
	ld	(defdrv),a		; Save it
	ld	a,ResDsk		; <crw>
	call	seldk			; Select drive 0=A, 1=B, etc.
	ld	a,(subflg)		; Get submit flag
	jr	cmd25a			; Exit
;
; Search for file
;
cmnd17:	call	seldrv			; Select drive from FCB
	ld	a,(ix+0)		; Get drive number from FCB
	sub	'?'			; Test if '?'
	jr	z,cmd17b		; If so all entries match
	ld	a,(ix+14)		; Get system byte
	cp	'?'			; Test if '?'
	jr	z,cmd17a		; Yes, jump
	ld	(ix+14),0		; Load system byte with zero
cmd17a:	ld	a,15			; Test first 15 items in FCB
cmd17b:	call	search			; Do search
cmd17c:	ld	hl,(dirbuf)		; Copy directory buffer
	ld	de,(DMA)		; To DMA address
	ld	bc,128			; Directory=128 bytes
	ldir
	ret				; Exit
;
; Search for next occurrence of file
;
cmnd18:	ld	ix,(dcopy)		; Get last FCB used by search
	call	seldrv			; Select drive from FCB
	call	searcn			; Search next file match
	jr	cmd17c			; And copy directory to DMA address
;
; Delete file
;
cmnd19:	call	seldrv			; Select drive from FCB
	call	delete			; Delete file
cmd19a:	ld	a,(searex)		; Get exit byte 00=file found,0ffh not
	jr	cmd25a			; And exit
;
; Rename file
;
cmnd23:	call	seldrv			; Select drive from FCB
	call	renam			; Rename file
	jr	cmd19a			; And exit
;
; Return login vector
;
cmnd24:	ld	hl,(login)		; Get login vector
cmd24a:	ld	(pexit),hl		; Save it
	ret				; And exit
;
; Return current drive
;
cmnd25:	ld	a,(defdrv)		; Get current drive
cmd25a:	jp	exit			; And exit
;
; Return allocation vector
;
cmnd27:	ld	hl,(alv)		; Get allocation vector
	jr	cmd24a			; And exit
;
; Return disk R/O vector
;
cmnd29:	ld	hl,(dskro)		; Get disk R/O vector
	jr	cmd24a			; And exit
;
; Set file attributes
;
cmnd30:	call	seldrv			; Select drive from FCB
	call	cstat			; Change status
	jr	cmd19a			; And exit
;
; Get Disk Parameter Block Address
;
cmnd31:	ld	hl,(ixp)		; get drive table
	jr	cmd24a			; And exit
;
; Set/get user code
;
cmnd32:	ld	a,e			; Get user code
	inc	a			; Test if 0ffh
	ld	a,(user)		; Get old user code
	jr	z,cmd25a		; If 0ffh then exit
	ld	a,e			; Get new user code
	and	01fh			; Mask it
	ld	(user),a		; Save it
	ret				; And exit
;
; Compute file size
;
cmnd35:	call	seldrv			; Select drive from FCB
	call	filsz			; Compute file size
	jr	cmd19a			; And exit
;
; Set random record count
;
cmnd36:	ld	hl,32			; Set pointer to next record
	call	calrrc			; Calculate random record count
ldrrc:	ld	(ix+33),d		; And save random record count
	ld	(ix+34),c
	ld	(ix+35),b
	ret				; And exit
;
; Reset individual disk drives
;
cmnd37:	ld	a,e			; Get mask LSB
	cpl				; Complement it
	ld	e,a
	ld	a,d			; Get mask MSB
	cpl				; Complement it
	ld	d,a
	ld	hl,(login)		; Get login vector
	ld	a,e			; Mask login vector
	and	l			; LSB
	ld	l,a
	ld	a,d			; Mask login vector
	and	h			; MSB
	ld	h,a
	ld	(login),hl		; Save login vector
	ex	de,hl			; Use login vector as mask
	ld	hl,(dskro)		; Get drive R/O vector
	ld	a,e			; Mask drive R/O vector
	and	l			; LSB
	ld	l,a
	ld	a,d			; Mask drive R/O vector
	and	h			; LSB
	ld	h,a
	ld	(dskro),hl		; Save drive R/O vector
	ret				; And exit
;
; Select disk from FCB
;
seldrv:	ld	a,0ffh			; Set disk select done flag
	ld	(fldrv),a
	ld	a,(defdrv)		; Get current drive
	ld	(drive),a		; Save it in memory
	ld	e,a			; Save it in register e
	ld	a,(ix+0)		; Get drive from FCB
	ld	(fcb0),a		; Save it
	cp	'?'			; Test if '?'
	jr	z,cmnd14		; Yes, then select drive from register e
	and	01fh			; Mask drive
	ld	a,e			; Test if zero
	jr	z,seldr0		; Select drive from register e
	ld	a,(ix+0)		; Get drive from FCB
	dec	a			; Decrement drive
seldr0:	call	seldk			; Select drive
	ld	a,(ix+0)		; Get drive from FCB
	and	0e0h			; Remove drive bits
	ld	b,a			; Save register
	ld	a,(user)		; Get user number
	or	b			; Insert user number in FCB
	ld	(ix+0),a
	ret				; And exit
;
; Select disk
;
cmnd14:	ld	a,e			; Copy drive number
;
seldk:	and	0fh			; Mask drive number to 0-15
	ld	b,a			; Save counter
	ld	de,(login)		; Get login vector
	or	a			; Test drive 'a'
	jr	z,seldk1		; Yes then jump
seldk0:	rr	d			; Shift login vector
	rr	e			; Until bit 0 register e
	djnz	seldk0			; Is current drive
seldk1:	ld	hl,defdrv		; Get pointer last drive
	bit	0,e			; Test if drive logged in
	jr	z,seldk2		; No, login drive
	cp	(hl)			; Test same drive
	ret	z			; Yes then exit
seldk2:	ld	(hl),a			; Save new current drive
	push	de			; Save drive logged in flag
	ld	c,a			; Copy drive number
	call	SelDsk			; Do BIOS select
	ld	a,h			; Test if error
	or	l
	jr	z,seldk3		; Yes, illegal drive number
	ld	e,(hl)			; Get LSB translation vector
	inc	hl			; Increment pointer
	ld	d,(hl)			; Get MSB translation vector
	inc	hl			; Increment pointer
	ld	(trans),de		; Save translation vector
	ld	(temp0),hl		; Save address temp0

	ld	de,6
	add	hl,de			; Point to dirbuf pointer <crw>

	ld	de,dirbuf		; Load dirbuf pointer
	ld	bc,8			; Copy 8 bytes pointers to
					; ..dirbuf, csv (wacd), allocation
	ldir				; ..vector pointer for this disk
	ld	hl,(ixp)		; Get drive parameter address
	ld	c,15			; Copy 15 bytes
	ldir
	pop	de			; Get drive logged in flag
	bit	0,e			; Test it
	ret	nz			; Drive logged in so return
	ld	hl,(login)		; Get login vector
	call	sdrvb			; Set drive bit in login vector
	ld	(login),hl		; Save login vector
	jr	initdr			; And setup drive tables
seldk3:
	ld	hl,(StSel)		; Load error message address
	jp	(hl)			; And display error

;
; Init drive
;  Clear allocation vector bit buffer after drive reset
;
initdr:	ld	de,(maxlen)		; Get length alv buffer-1 (bits)
	ld	a,3			; Divide by 8
initd0:	srl	d			; To get bytes
	rr	e
	dec	a
	jr	nz,initd0
	inc	de			; Increment, so all bits are cleared
	ld	hl,(alv)		; Get pointer alv buffer
	push	hl
initd1:	ld	(hl),0			; Clear 8 bits
	inc	hl			; Increment pointer
	dec	de			; Decrement counter
	ld	a,d			; Test if counter zero
	or	e
	jr	nz,initd1		; Not then jump
	pop	hl			; Get alv pointer
	ld	de,(ndir0)		; Get first two bytes alv buffer
	ld	(hl),e			; Save LSB
	inc	hl			; Increment pointer
	ld	(hl),d			; Save MSB
	ld	hl,(temp0)		; Clear number of files
	xor	a			; On this drive
	ld	(hl),a			; Clear LSB
	inc	hl			; Increment pointer
	ld	(hl),a			; Clear MSB
	ld	(subflg),a		; Clear submit flag (reset disk command)
	call	setfct			; Set file count
initd2:	ld	a,0ffh			; Update directory checksum
	call	rddir			; Read FCB's from directory
	call	tstfct			; Test last FCB
	ret	z			; Yes then exit
	call	caldir			; Calculate entry point FCB
	ld	a,(hl)			; Get first byte FCB
	cp	0e5h			; Test empty directory entry
	jr	z,initd2		; Yes then get next FCB
	cp	021h			; Test time stamp
	jr	z,initd2		; Yes then get next FCB
	ld	a,(user)		; Get user number
	cp	(hl)			; Test if user is same
	jr	nz,initd3		; No then jump
	inc	hl			; Point to file name
	ld	a,(hl)			; Get first char filename
	sub	'$'			; Test if '$'
	jr	nz,initd3		; Not then jump
	dec	a			; Load a with 0ffh
	ld	(subflg),a		; Save it in subflg
initd3:	ld	c,1			; Set bit in alv buffer
	call	fillbb			; Set bits from FCB in alv buffer
	call	setlf			; Update last file count
	jr	initd2			;
;
; Set drive bit in HL
;
sdrvb:	ex	de,hl			; Copy hl=>de
	ld	hl,1			; Get mask drive "a"
	ld	a,(defdrv)		; Get current drive
	or	a			; Test if drive "a"
	jr	z,sdrvb1		; Yes then done
sdrvb0:	add	hl,hl			; Get next mask
	dec	a			; Decrement drive counter
	jr	nz,sdrvb0		; And test if done
sdrvb1:	ld	a,d			; Hl=hl or de
	or	h
	ld	h,a
	ld	a,e
	or	l
	ld	l,a
	ret				; Exit
;
; Calculate sector/track directory
;
stdir:	ld	hl,(filcnt)		; Get FCB counter directory
	srl	h			; Divide by 4
	rr	l			; (4 FCB's / sector)
	srl	h
	rr	l
	ld	(recdir),hl		; Save value (used by checksum)
	ex	de,hl			; Copy it to de
	ld	hl,0			; Clear hl
;
; Calculate sector/track
;	Entry:	hl,de = sector number (128 byte sector)
;	Exit:	set track  = hl,de  /  maxsec
;		set sector = hl,de mod maxsec
;
calst:	ld	bc,(maxsec)		; Get sectors/track
	ld	a,17			; Set up loop counter
calst0:	or	a			; Test hl>=bc
	sbc	hl,bc
	ccf
	jr	c,calst1		; Yes then jump
	add	hl,bc			; No then restore hl
	or	a			; And clear carry
calst1:	rl	e			; Shift result in de
	rl	d
	dec	a			; Test last bit done
	jr	z,calst2		; Yes then exit
	rl	l			; Shift next bit in hl
	rl	h
	jr	calst0			; Continue
calst2:	push	hl			; Save sector number
	ld	hl,(nftrk)		; Get first track
	add	hl,de			; Add track number
	ld	b,h			; Copy it to bc
	ld	c,l
	call	SetTrk			; BIOS call set track
	pop	bc			; Restore sector number
	ld	de,(trans)		; Get translation table address
	call	SecTrn			; BIOS call sector translation
	ld	b,h			; Copy result to bc
	ld	c,l
	jp	SetSec			; BIOS call set sector
;
; Get disk map block number from FCB
;
; Exit: HL = address FCB
;	DE = disk map
;	BC = offset in disk map
;
getdm:	ld	c,(ix+32)		; Get next record
	ld	a,(nblock)		; Get number of blocks
	ld	b,a			; Save it
getdm0:	srl	c			; Shift next record
	djnz	getdm0			; Number of blocks times
getdm1:	cpl				; Complement number of blocks
	add	a,9			; Add 9
	ld	b,a			; B=8-number of blocks
	ld	a,(nextnd)		; Get extend mask
	and	(ix+12)			; Mask with extend
	rrca				; Rotate one right
getdm2:	rlca				; Rotate one left
	djnz	getdm2			; 8-number of blocks times
getdm3:	add	a,c			; Add the two values to get entry FCB
getdm4:	push	ix			; Get FCB address
	pop	hl
	ld	c,16			; Add offset 16 to point to dm
	add	hl,bc
	ld	c,a			; Add entry FCB
	add	hl,bc
	ld	a,(maxlen+1)		; Test 8 bits/16 bits FCB entry
	or	a
	jr	nz,getdm5		; 16 bits => jump
	ld	e,(hl)			; Get 8 bit value
	ld	d,0			; Make MSB zero
	ret				; And exit
getdm5:	add	hl,bc			; Add twice (16 bit values)
	ld	e,(hl)			; Get LSB
	inc	hl			; Increment pointer
	ld	d,(hl)			; Get MSB
	dec	hl			; Decrement pointer
	ret				; And exit
;
; Calculate sector number
;  entry: de=block number from FCB
;
calsec:	ld	hl,0			; Clear MSB sector number
	ld	a,(nblock)		; Get loop counter
	ld	b,a			; Save it in b
calsc0:	sla	e			; Shift l,d,e
	rl	d
	rl	l
	djnz	calsc0			; B times
calsc1:	ld	a,(nmask)		; Get sector mask
	and	(ix+32)			; And with next record
	or	e			; Set up LSB sector number
	ld	e,a
	ret				; And exit
;
; Calculate dirbuf entry point
;
caldir:	ld	hl,(dirbuf)		; Get start address dirbuf
	ld	a,(secpnt)		; Get sector pointer
	add	a,l			; Add l=l+a
	ld	l,a
	ret	nc			; No carry exit
	inc	h			; Increment h
	ret				; And exit
;
; Init file count
;
setfct:	ld	hl,-1			; Set up file count
	ld	(filcnt),hl		; Save it
	ret				; And exit
;
; Test file count
;
tstfct:	ld	hl,(filcnt)		; Test file count=0ffffh
	ld	a,h			; Get MSB
	and	l			; And LSB
	inc	a			; Test if result=0ffh
	ret				; And exit
;
; Set last file
;
setlf:	call	tstlf			; Test last file
	ret	c			; No then exit
	inc	de			; Increment last file
	ld	(hl),d			; Save it in temp0
	dec	hl
	ld	(hl),e
	ret				; And exit
;
; Test last file
;
tstlf:	ld	hl,(temp0)		; Get pointer to last file
	ld	de,(filcnt)		; Get file counter
	ld	a,e			; Subtract de-(hl)
	sub	(hl)
	inc	hl
	ld	a,d
	sbc	a,(hl)
	ret				; Exit
;
; Get next FCB from drive
;	Entry:	A = 0 check checksum
;		A = 0ffh update checksum
;
rddir:	ld	c,a			; Save checksum flag
	ld	hl,(filcnt)		; Get file counter
	inc	hl			; Increment it
	ld	(filcnt),hl		; And save it
	ld	de,(nfiles)		; Get maximum number of files
	or	a			; Clear carry
	sbc	hl,de			; Test if last file
	add	hl,de
	jr	z,rddir0		; No jump
	jr	nc,setfct		; Yes set file count to 0ffffh
rddir0:	ld	a,l			; Get file count LSB
	add	a,a			; *32
	add	a,a
	add	a,a
	add	a,a
	add	a,a
	and	060h			; Mask it
	ld	(secpnt),a		; Save it for later use
	ret	nz			; Return if not first FCB sector
	push	bc			; Save checksum flag
	call	stdir			; Calculate sector/track directory
	call	readdr			; Read sector directory
	pop	bc			; Restore checksum flag
;
; Update/check checksum directory
; entry c=0 check checksum, c=0ffh update checksum
;
chkdir:	ld	hl,(ncheck)		; Get number of checked records
	ld	de,(recdir)		; Get current record
	or	a			; Clear carry
	sbc	hl,de			; Test current record
	ret	z			; Exit if zero
	ret	c			; Exit if greater then ncheck
	ld	hl,(dirbuf)		; Get dirbuf
	ld	b,128			; Set up counter
	xor	a			; Clear checksum
chkdr0:	add	a,(hl)			; Add checksum
	inc	hl			; Increment pointer
	djnz	chkdr0			; 128 times
	ld	hl,(csv)		; Get pointer checksum directory
	add	hl,de			; Add current record
	inc	c			; Test checksum flag
	jr	z,chkdr1		; 0ffh=> update checksum
	cp	(hl)			; Test checksum
	ret	z			; Exit if ok
	ld	a,true
	ld	(diff),a		; Set disk changed flag
	jp	setfn
chkdr1:	ld	(hl),a			; Update checksum
	ret				; And exit
;
; Read sector from drive
;
; readr and writer modified to give separate error message--b.h.
;
readr:	call	read			; BIOS call read sector
	ld	hl,(rderr)
	jr	write0			; Test exit code
;
; Write sector on drive
;
writer:	call	write			; BIOS call write sector
	ld	hl,(wrterr)
write0:	or	a			; Test exit code
	ret	z			; Exit if ok
	ld	(retflg),a		; Allow retry for read/write errors
	jp	(hl)			; DOS error on d: write error
;
; Read directory from drive
;
readdr:	call	DMAdir			; Set up DMA directory
	call	readr			; Read record
	jr	stDMA			; Set up DMA user
;
; Write directory on drive
;
writdr:	ld	c,0ffh			; Update checksum directory
	call	chkdir
	call	DMAdir			; Set up DMA directory
	ld	c,1			; Write directory flag
	call	writer			; Write record
	jr	stDMA			; Set up DMA user
;
; Set DMA address command
;
cmnd26:	ld	(DMA),de		; Save DMA address
;
stDMA:	ld	bc,(DMA)		; Get DMA address
	jr	DMAdr0			; And do BIOS call
;
; Set DMA address directory
;
DMAdir:	ld	bc,(dirbuf)		; Get DMA address directory
DMAdr0:	jp	setDMA			; BIOS call set DMA

;
; Get bit from allocation vector buffer
;
;	Entry:	DE = block number
;	Exit:	A  = bit in LSB
;		B  = bitnumber in a
;		HL = pointer in alv buffer
;
getbit:	ld	a,e			; Get bit number
	and	7			; Mask it
	inc	a			; Add 1
	ld	b,a			; Save it
	ld	c,a			; Twice
	srl	d			; Get byte number
	rr	e			; De=de/8
	srl	d
	rr	e
	srl	d
	rr	e
	ld	hl,(alv)		; Get start address alv buffer
	add	hl,de			; Add byte number
	ld	a,(hl)			; Get 8 bits
getbt0:	rlca				; Get correct bit
	djnz	getbt0
	ld	b,c			; Restore bit number
	ret				; And return to caller
;
; Set/reset bit in allocation vector buffer
;	Entry	DE = block number
;		 C = 0 reset bit, c=1 set bit
;
setbit:	push	bc			; Save set/reset bit
	call	getbit			; Get bit
	and	0feh			; Mask it
	pop	de			; Get set/reset bit
	or	e			; Set/reset bit
setbt0:	rrca				; Rotate bit in correct position
	djnz	setbt0
	ld	(hl),a			; Save 8 bits
	ret				; And return to caller
;
; Fill bit buffer from FCB in dirbuf
;	Entry:	C = 0 reset bit
;		C = 1 set bit
;
fillbb:	call	caldir			; Get directory entry
	ld	de,16			; Get offset dm block
	add	hl,de			; Add offset
	ld	b,e			; Get block counter
fillb0:	ld	e,(hl)			; Get LSB block number
	inc	hl			; Increment pointer
	ld	d,0			; Reset MSB block number
	ld	a,(maxlen+1)		; Test >256 blocks present
	or	a
	jr	z,fillb1		; No then jump
	dec	b			; Decrement block counter
	ld	d,(hl)			; Get correct MSB
	inc	hl			; Increment pointer
fillb1:	ld	a,d			; Test block number
	or	e
	jr	z,fillb2		; Zero then get next block
	push	hl			; Save pointer
	push	bc			; Save counter and set/reset bit
	ld	hl,(maxlen)		; Get maximum lenght alv buffer
	or	a			; Reset carry
	sbc	hl,de			; Test de<=maxlen alv buffer
	call	nc,setbit		; Yes then insert bit
	pop	bc			; Get counter and set/reset bit
	pop	hl			; Get pointer
fillb2:	djnz	fillb0			; Repeat for all dm entries
	ret				; And return to caller
;
; Set write protect disk
;
cmnd28:
setwpd:	ld	hl,(dskro)		; Get disk R/O vector
	call	sdrvb			; Include drive bit
	ld	(dskro),hl		; Save disk R/O bit
setfn:	ld	de,(nfiles)		; Get maximum number of files-1
	inc	de			; Increment it
	ld	hl,(temp0)		; Get pointer to disk parameter block
	ld	(hl),e			; And save number of files
	inc	hl
	ld	(hl),d
	ret				; And return to caller
;
; Check file R/O bit
;
chkfro:	call	caldir			; Get directory entry
	ld	a,(searpu)		; Test if public file
	ld	b,a			; Save it
	ld	a,(searqu)		; Test if question mark used in file name
	or	b			; A=public file or question mark used
chkfr0:	ld	de,2			; Offset to public file bit
	add	hl,de			; Add offset
	or	a			; Test question mark used
	jr	z,chkfr1		; No then don't test public file bit
	bit	7,(hl)			; Test public file
	jr	nz,chkfr2		; Yes then error
chkfr1:	ld	e,7			; Offset to file R/O bit
	add	hl,de			; Add offset
	bit	7,(hl)			; Test file R/O
	jr	nz,chkfr2		; Yes then error
	or	a			; Test question mark used
	ret	z			; No then don't test system file bit
	inc	hl			; Increment to system file
	bit	7,(hl)			; Test system file
	ret	z			; No system file then ok
chkfr2:
	ld	hl,(sfilro)		; Get pointer to file R/O message
	jp	(hl)			; Display message

;
; Check drive read only
;
chkro:	ld	hl,(dskro)		; Get drive R/O vector
	call	sdrvb			; Set drive bit
	sbc	hl,de			; Test extra bit added
	ret	nz			; Yes then drive not R/O
	ld	hl,(stro)		; Get pointer to drive R/O message
	jp	(hl)			; Display message

;
; Get free block from allocation vector buffer
;	Entry:	DE = old block number
;	Exit:	DE = new block number (0 if no free block)
; HL counts up
; DE counts down
;
getfre:	ld	h,d			; Copy old block to hl
	ld	l,e
getfr0:	ld	a,d			; Test down counter is zero
	or	e
	jr	z,getfr1		; Yes then jump
	dec	de			; Decrememt down counter
	push	hl			; Save up/down counter
	push	de
	call	getbit			; Get bit from alv buffer
	rra				; Test if zero
	jr	nc,getfr3		; Yes then found empty block
	pop	de			; Get up/down counter
	pop	hl
getfr1:	ld	bc,(maxlen)		; Get maximum alv lenght-1 in bc
	or	a			; Clear carry
	sbc	hl,bc			; Test hl>=lenght alv-1
	add	hl,bc			; Restore hl (flags are not affected)
	jr	nc,getfr2		; End buffer then jump
	inc	hl			; Increment up counter
	push	de			; Save down/up counter
	push	hl
	ex	de,hl			; Save up counter in de
	call	getbit			; Get bit from alv buffer
	rra				; Test if zero
	jr	nc,getfr3		; Yes then found empty block
	pop	hl			; Get down/up counter
	pop	de
	jr	getfr0			; And test next block
getfr2:	ld	a,d			; Test if last block tested
	or	e
	jr	nz,getfr0		; No then test next block
	ret				; Exit (de=0)
getfr3:	scf				; Set block number used
	rla				; Save bit
	call	setbt0			; Put bit in alv buffer
	pop	de			; Get correct counter
	pop	hl			; Restore stack pointer
	ret				; Exit (de=block number)
;
; Search for file name
;	Entry:	A = number of bytes to search for
;
search:	ld	(searnb),a		; Save number of bytes
	ld	a,0ffh			; Set exit code to 0ffh (not found)
	ld	(searex),a
	ld	(dcopy),ix		; Copy FCB pointer to ram (search next)
	call	setfct			; Initiate file counter
;
; Mod. 0.1 had a bug in which the directory of a changed disk would not be
; read. Adding call home forces a directory read--b.h.
;
	call	home			; Call BIOS procedure
;
; Search next file name
;
SearcN:	xor	a			; Clear accu, check checksum dir.

; Next 3 lines moved here from SEARC1: to clear flags
; when last file in dir. is a public file. - C.W. 2/87

	ld	(searqu),a		; Clear question mark detected flag
	ld	(searpu),a		; Clear public file flag
	res	7,(ix+8)		; Reset public/system file flag
;
	call	rddir			; Get FCB from directory
	call	tstfct			; Test if past last entry
	jp	z,searc8		; Yes then jump
	ld	de,(dcopy)		; Get FCB pointer
	ld	a,(de)			; Get first byte
	cp	0e5h			; Test if searching empty directory
	jr	z,searc1		; Yes then jump
	push	de			; Save FCB pointer
	call	tstlf			; Test last file on this drive
	pop	de			; Restore FCB pointer
	jr	nc,searc8		; Yes then jump
searc1:	call	caldir			; Get entry in directory
	ld	a,(hl)			; Get first byte directory entry
	cp	021h			; Test time stamp
	jr	z,searcn		; Yes then get next directory entry
	ld	a,(searnb)		; Get number of bytes to search for
	ld	b,a			; Save it in counter
	xor	a			; Clear accu
	ld	c,a			; Clear counter
searc2:	ld	a,b			; Test if counter is zero
	or	a
	jr	z,searc9		; Yes then jump
	ld	a,(de)			; Get byte from FCB
	xor	'?'			; Test if question mark
	and	07fh			; Mask it (remove high bit)
	jr	z,searc6		; Yes then jump
	ld	a,c			; Get FCB counter
	or	a			; Test whether first byte
	jr	nz,searc3		; No
	ld	a,(flags)		; Yes. get flag byte
	bit	0,a			; Test public file enable
	jr	z,searc3		; No
	inc	hl			; Yes. get pointer to public bit
	inc	hl
	bit	7,(hl)			; Test public bit directory
	dec	hl			; Restore pointer
	dec	hl
	jr	z,searc3		; No public file then jump
	ld	a,(de)			; Get first byte FCB
	cp	0e5h			; Test if searching empty directory
	jr	z,searc3		; Yes then jump
	xor	(hl)			; Test FCB=directory entry
	and	07fh			; Mask it
	jr	z,searc5		; Yes then jump
	and	0e0h			; Mask user number
	jr	nz,searc3		; Not the same then jump
	dec	a			; A=0ffh
	ld	(searpu),a		; Set public file found
	set	7,(ix+8)		; Set public/system file flag
	jr	searc5			; Jump found
searc3:	ld	a,c			; Get FCB counter
	cp	13			; Test if at user code
	jr	z,searc5		; Yes then no test
	cp	12			; Test if at extend number
	ld	a,(de)			; Get byte from FCB
	jr	z,searc7		; Jump if extent number
	xor	(hl)			; Test byte FCB=byte directory entry
	and	07fh			; Mask it
searc4:	jr	nz,searcn		; Not the same then get next entry
searc5:	inc	de			; Increment pointer FCB
	inc	hl			; Increment pointer directory entry
	inc	c			; Increment counter
	dec	b			; Decrement counter
	jr	searc2			; Test next byte
searc6:	dec	a			; Set question mark found flag
	ld	(searqu),a
	jr	searc5			; Jump found
searc7:	push	bc			; Save counters
	xor	(hl)			; Test extends
	ld	b,a			; Save it
	ld	a,(nextnd)		; Get extent mask
	cpl				; Complement it
	and	01fh			; Mask it
	and	b			; Mask extents
	pop	bc			; Restore counters
	jr	searc4			; And test result
searc8:	call	setfct			; Error set file counter
	ld	a,0ffh			; And set exit code
	ld	(pexit),a
	ret				; Return to caller
searc9:	ld	a,(searqu)		; Get question mark found flag
	ld	b,a			; Save it
	ld	a,(searpu)		; Get public file flag
	and	b			; Test if public file and question mark
	jr	nz,searc4		; Yes then search for next entry
	call	setlf			; Update last file count (empty FCB)
	ld	a,(filcnt)		; Get file counter
	and	3			; Mask it
	ld	(pexit),a		; And set exit code
	xor	a			; Clear exit code search
	ld	(searex),a
	ret				; And return to caller
;
; Delete file
;
delete:	call	chkro			; Check disk R/O
	ld	a,12			; Number of bytes to search for
	call	search			; Search file
del0:	call	tstfct			; Test if file found
	ret	z			; Not then exit
	call	chkfro			; Check file R/O
	call	caldir			; Get entry point directory
	ld	(hl),0e5h		; Remove file
	ld	c,0			; Remove bits alv buffer
	call	fillbb
	call	wrFCB			; Write directory buffer on disk
	call	searcn			; Search next entry
	jr	del0			; And test it
;
; Rename file
;
renam:	call	chkro			; Check disk R/O
	ld	a,12			; Number of bytes to search for
	call	search			; Search file
renam0:	call	tstfct			; Test if file found
	ret	z			; Not then exit
	call	chkfro			; Check file R/O
	push	ix			; Save FCB entry
	pop	hl			; Get it in hl
	ld	de,16			; Offset to new name
	add	hl,de			; Add offset
	ex	de,hl			; Copy hl=>de
	call	caldir			; Get directory entry
	ld	b,11			; Set up loop counter
renam1:	inc	hl			; Increment directory pointer
	inc	de			; Increment FCB pointer
	ld	a,(de)			; Get character from FCB
	and	07fh			; Mask it
	cp	'?'			; Test if question mark
	jr	z,renam2		; Yes then do not change char. on disk
	ld	c,a			; Save it in c
	ld	a,(hl)			; Get character from directory
	and	080h			; Mask status bit
	or	c			; Or with new character
	ld	(hl),a			; Save in directory
renam2:	djnz	renam1			; Loop until done
	call	wrFCB			; And write directory on disk
	call	searcn			; Search next file
	jr	renam0			; And test it
;
; Change status file
;
cstat:	call	chkro			; Check disk R/O
	ld	a,12			; Number of bytes to search for
	call	search			; Search file
cstat0:	call	tstfct			; Test if file found
	ret	z			; Not then exit
	push	ix			; Save FCB entry
	pop	de			; Get it in hl
	call	caldir			; Get directory entry
	ld	b,11			; Set up loop counter
cstat1:	inc	hl			; Increment directory pointer
	inc	de			; Increment FCB pointer
	ld	a,(de)			; Get status bit from FCB
	and	080h			; Mask it
	ld	c,a			; Save it in c
	ld	a,(hl)			; Get character from directory
	and	07fh			; Mask it
	or	c			; Or with new status bit
	ld	(hl),a			; Save in directory
	djnz	cstat1			; Loop until done
	call	wrFCB			; And write directory to disk
	call	searcn			; Search next file
	jr	cstat0			; And test it
;
; Compute file size
;
filsz:	ld	bc,0			; Reset file size lenght
	ld	d,c
	call	ldrrc			; Save it in FCB+33,34,35
	ld	a,12			; Number of bytes to search for
	call	search			; Search file
filsz0:	call	tstfct			; Test if file found
	ret	z			; Not then exit
	call	caldir			; Get directory entry
	ex	de,hl			; Copy to de
	ld	hl,15			; Offset to next record
	call	calrrc			; Calculate random record count
	ld	a,d			; Test LSB < (ix+33)
	sub	(ix+33)
	ld	a,c			; Test isb < (ix+34)
	sbc	a,(ix+34)
	ld	a,b			; Test MSB < (ix+35)
	sbc	a,(ix+35)
	call	nc,ldrrc		; Write new maximum
	call	searcn			; Search next file
	jr	filsz0			; And test it
;
; Write FCB on disk
;
wrFCB:	call	stdir			; Calculate sector/track directory
	jp	writdr			; Write directory on disk
;
; Find file
;
findf:	ld	a,15			; Number of bytes to search for
	JP	search			; Search file
;
; Open file command
;
cmnd15:	call	seldrv			; Select drive from FCB
	ld	(ix+14),0		; Clear FCB+14
;
; Open file
;
openf:	call	findf			; Find file
	call	tstfct			; Test file found
	ret	z			; No then exit
openf0:	ld	a,(ix+8)		; Get public/system file bit
	push	af			; Save it
	ld	a,(ix+12)		; Get extent number from FCB
	push	af			; Save it
	call	caldir			; Get directory entry
	push	hl			; Save it <crw>
	ld	e,8			; Set access date/time <crw>
	call	stime			; Zero flag set if stamps present <crw>
	pop	hl			; Get directory entry <crw>
	push	ix			; Save FCB entry
	pop	de			; Get in in de
	ld	bc,32			; Number of bytes to move
	ldir				; Move directory to FCB
	call	z,wrFCB			; Write directory to disk if stamps
					; ..Present <crw>
nowrit:	set	7,(ix+14)		; Set FCB/file not modified
	ld	b,(ix+12)		; Get extent number
	ld	c,(ix+15)		; Get next record number
	pop	af			; Get old extent number
	ld	(ix+12),a		; Save it
	cp	b			; Compare old and new extent number
	jr	z,openf1		; Same then jump
	ld	c,0			; Set next record count to 0
	jr	nc,openf1		; Old extent >= new extent then jump
	ld	c,80h			; Set next record count to maximum
openf1:	ld	(ix+15),c		; Save next record count
	pop	af			; Get public/system file bit
	rl	(ix+8)			; Remove MSB from ix+8
	rla				; Set new MSB in carry
	rr	(ix+8)			; Save carry in ix+8
	ret				; And return to caller
;
; Close file command
;
cmnd16:	call	seldrv			; select drive from FCB
;
; Close file
;
close:	bit	7,(ix+14)		; test FCB/file modified
	ret	nz			; not then no close required
	call	chkro			; test disk R/O
	ld	a,15			; number of bytes to search for
	call	search			; search file
	call	tstfct			; test file present
	ret	z			; no then exit
	call	chkfro			; check file R/O
	call	caldir			; get directory entry
	ld	bc,16			; offset to dm block
	add	hl,bc			; add offset
	ex	de,hl			; save hl in de
	push	ix			; save FCB pointer
	pop	hl			; get it in hl
	add	hl,bc			; add offset
	ld	a,(maxlen+1)		; test number of block >= 256
	or	a
	jr	z,close0		; no then jump
	dec	b			; set flag
close0:	call	copydm			; copy and test blocks
	ex	de,hl			; exchange copy direction
	call	copydm			; copy and test blocks
	ex	de,hl			; exchange copy direction
	jr	nz,close4		; block not the same then error
	inc	hl			; increment pointer FCB
	inc	de			; increment pointer directory
	bit	0,b			; test number of block >= 256
	jr	z,close1		; no then jump
	inc	hl			; increment pointer FCB
	inc	de			; increment pointer directory
	dec	c			; decrement counter
close1:	dec	c			; decrement counter
	jr	nz,close0		; not ready then jump
	ld	hl,-20			; add -20 to get extent number
	add	hl,de			; hL contains pointer to extent number
	ld	a,(ix+12)		; get extent number FCB
	cp	(hl)			; compare with extent number directory
	jr	c,close3		; fCB < directory then jump
	ld	(hl),a			; save extent number in directory
	inc	hl			; get pointer to next record
	inc	hl
	inc	hl
	ld	a,(ix+15)		; get next record FCB
close2:	ld	(hl),a			; save next record in directory
close3:	ld	e,4			; Set last update date/time
	call	stime			; Update time
	call	caldir			; Get directory entry
	ld	bc,11			; Point to archive byte
	add	hl,bc
	res	7,(hl)			; reset archive bit
	res	7,(ix+11)		; reset bit in FCB
	jp	wrFCB			; write FCB on disk
;
close4:	ld	a,0ffh			; flag error
	ld	(pexit),a
	ret				; and return to caller
;
; Copy and test disk map
;
;	Entry:	HL = pointer to first FCB
;		DE = pointer to second FCB
;		 B = 000h if less then 256 blocks
;		     0ffh if more or equal to 256 blocks
;	Exit:	Z  blocks are the same
;		NZ blocks are not the same
;
copydm:	ld	a,(hl)			; get byte first FCB
	bit	0,b			; test number of blocks >=256
	jr	z,copyd0		; No then jump
	inc	hl			; Increment pointer
	or	(hl)			; Test byte =0
	dec	hl			; Decrement pointer
copyd0:	or	a			; Test block number is zero
	jr	nz,copyd1		; No then compare blocks
	ld	a,(de)			; Copy block from other FCB in empty location
	ld	(hl),a
	bit	0,b			; Test number of blocks >=256
	ret	z			; No then exit
	inc	hl			; Increment to MSB block numbers
	inc	de
	ld	a,(de)			; Copy block from other FCB in empty location
	ld	(hl),a
	jr	copyd2			; Jump trick to save space
copyd1:	ld	a,(de)			; Get block number first FCB
	sub	(hl)			; Test if the same
	ret	nz			; Not then return
	or	b			; Test if >=256 blocks
	ret	z			; No then return
	inc	hl			; Increment to MSB block numbers
	inc	de
copyd2:	ld	a,(de)			; Get block number first FCB
	sub	(hl)			; Test if the same
	dec	hl			; Decrement block FCB pointers
	dec	de
	ret				; And exit to caller
;
; Make file command
;
cmnd22:
	call	seldrv			; Select drive from FCB
	ld	(ix+14),0		; Clear FCB+14
;
; Make file
;
make:	call	chkro			; Check drive R/O
	ld	a,(ix+0)		; Get first byte FCB
	push	af			; Save it
	ld	(ix+0),0e5h		; Set first byte to empty file
	ld	a,1			; Search for 1 byte
	call	search			; Search empty file
	pop	af			; Get first byte FCB
	ld	(ix+0),a		; Restore it
	call	tstfct			; Test empty file found
	ret	z			; No then return error
	xor	a			; Clear FCB+13
	ld	(ix+13),a
	push	ix			; Save FCB pointer
	pop	hl			; Get it back in hl
	ld	de,15			; Prepare offset
	add	hl,de			; Add it
	ld	b,17			; Set loop counter
make0:	ld	(hl),a			; Clear FCB+15 up to FCB+31
	inc	hl			; Increment pointer
	djnz	make0			; And clear all bytes
	ld	e,2			; Set creation date
	call	stime			; Update time in directory
	ld	e,4			; Set last update date/time
	call	stime			; Update time in directory
	ld	e,8			; Set access date/time <crw>
	call	stime
	res	7,(ix+8)		; Reset public/system file bit
	res	7,(ix+11)		; Reset archive bit if present
	call	caldir			; Get directory entry
	push	ix			; Save FCB entry
	pop	de			; Get it in de
	ex	de,hl			; Exchange FCB and directory entry
	ld	bc,32			; Number of bytes to move
	ldir				; Move bytes
	call	wrFCB			; Write FCB on disk
	set	7,(ix+14)		; Set FCB/file not modified
	ret				; And return to caller
;
; Open next extent
;
openex:	bit	7,(ix+14)		; Test if FCB/file modified (write)
	jr	nz,openx2		; Not then jump
	call	close			; Close current FCB
	ld	a,(pexit)		; Get exit code
	inc	a			; Test if error
	ret	z			; Yes then exit
	call	calnex			; Calculate next extent
	jr	c,openx3		; Error then jump
	jr	nz,openx5		; fCB present from close then jump
openx0:	ld	a,15			; Search first 15 bytes
	call	search			; Search for file
openx1:	call	tstfct			; Test if file found
	jr	nz,openx5		; Yes then jump
	ld	a,(rdwr)		; Test read/write flag
	or	a			; Test if read
	jr	z,openx3		; Yes then error
	call	make			; Make new extent if write
	call	tstfct			; Test if succesfull
	jr	nz,openx6		; Yes then exit
	jr	openx3			; No then error
openx2:	call	calnex			; Calculate next extent
	jr	c,openx3		; Error then jump
	bit	7,(ix+10)		; Test system file bit
	jr	z,openx0		; No system file then jump
	call	findf			; Search for file
	jr	openx1			; Use same routine
openx3:	set	7,(ix+14)		; Set FCB/file not modified
	ld	a,0ffh			; Set exit code
openx4:	ld	(pexit),a
	ret				; And return to caller
openx5:	call	openf0			; Open file
openx6:	xor	a			; And clear exit code
	jr	openx4			; Use same routine
;
; Calculate next extent
;
;	Exit:	C  overflow detected
;		Z  search next extent
;		NZ next extent present (close)
;
calnex:	ld	b,(ix+12)		; Get extent number
	ld	c,(ix+14)		; Get FCB+14
	bit	6,c			; Test error bit random record
	scf				; Set error flag
	ret	nz			; Non zero then error exit
	inc	b			; Increment extent number
	ld	a,b			; Get extent number
	and	01fh			; Mask it
	ld	b,a			; Save it in b
	jr	nz,calnx0		; Non zero then jump
	inc	c			; Increment FCB+14
	ld	a,c			; Get it in a
	and	03fh			; Mask it
	ld	c,a			; Save it in c
	scf				; Set error flag
	ret	z			; And return if file overflow
	xor	a			; Clear zero flag (not same extent)
	jr	calnx1			; And save extent number and FCB+14
calnx0:	ld	a,(nextnd)		; Get next extent mask
	and	b			; Test if same extent (close)
calnx1:	ld	(ix+12),b		; Save extent number
	ld	(ix+14),c		; Save FCB+14
	ret				; And return to caller
;
; Read random record command
;
cmnd33:	call	seldrv			; Select drive from FCB
;
; Read random sector
;
rdran:	xor	a			; Set read/write flag
	call	ldFCB			; Load random record in FCB
	jr	z,reads			; No error then read sector
	ret				; Return error
;
; Read sequential
;
cmnd20:	call	seldrv			; Select drive from FCB
;
; Read sector
;
reads:	xor	a			; Set read/write flag
	ld	(rdwr),a		; Save it
	ld	a,(ix+32)		; Get record counter
	cp	080h			; Test if last record this extent
	jr	nc,reads1		; Yes then open next extent
	cp	(ix+15)			; Test if greater then current record
	jr	c,reads2		; No then get record
reads0:	ld	a,1			; Set end of file flag
	ld	(pexit),a		; Save it
	ret				; And return to caller
reads1:
	call	openex			; ..To open next extent
	ld	a,(pexit)		; Get exit code
	or	a
	jr	nz,reads0		; Yes then end of file
	ld	(ix+32),0		; Clear record counter
reads2:	call	getdm			; Get block number from dm in FCB
	ld	a,d			; Test block number = 0
	or	e
	jr	z,reads0		; Yes then end file
	call	calsec			; Calculate sector number (128 bytes)
	call	calst			; Calculate sector/track number
	call	readr			; Read data
	ld	a,(funct)		; Get function number
	cp	20			; Test if read sequential
	ret	nz			; No then return
	inc	(ix+32)			; Increment next record counter
	ret				; And return to caller
;
; ClrDsk - Reset Login Vector if disk change detected, and select drive
;		from FCB. <crw>
;
;    Instead of setting disks to read-only, "diff" flag is set by
;    calls to wrFCB from Delete, Rename, Change Status, Open, Close,
;    Select, and Make if the disk in use has changed.  Next call to
;    write sequential or random then resets all disks.	Two
;    consecutive calls to write between which a disk was changed may
;    overwrite data, as is also the case with CP/M.
;
clrdsk:
	ld	a,(diff)		; Disk changed flag
	or	a
	jr	z,clrd0
	xor	a
	ld	(diff),a		; Clear flag
	ld	h,a
	ld	l,a
	ld	(login),hl		; Clear all drives
					; ..(crude but effective)
clrd0:
	call	seldrv			; Select disk from FCB
	ret
;
; Write random record commands
;
cmnd34:
cmnd40:
	call	clrdsk			; Reset disks if changed
					; ..and select drive from FCB
;
; Write random sector
;
wrran:	ld	a,0ffh			; Set read/write flag
	call	ldFCB			; Load FCB from random record
	jr	z,writes		; No error then write record
	ret				; Return error
;
; Write sequential
;
cmnd21:
	call	clrdsk			; Reset disks if changed
					; ..and select drive from FCB
;
; Write sector
;
writes:
	ld	a,0ffh			; Set read/write flag
	ld	(rdwr),a		; And save it
	call	chkro			; Check disk R/O
	bit	7,(ix+9)		; Test if file R/O
	jp	nz,chkfr2		; Yes then file R/O message
	bit	7,(ix+8)		; Test if public or system file
	jp	nz,chkfr2		; Yes then file R/O message
	ld	a,(ix+32)		; Get record count
	cp	080h			; Test if end this extent
	jr	c,writs0		; Yes then open next extent
	call	openex			; Open next extent
	ld	a,(pexit)		; Get error code
	or	a
	jp	nz,writs9		; Error then directory full error
	ld	(ix+32),0		; Clear record counter
writs0:	call	getdm			; Get block number from FCB
	ld	a,d			; Test if block number = 0
	or	e
	jr	nz,writs5		; No then write sector
	push	hl			; Save pointer to block number
	ld	a,c			; Test first block number in extent
	or	a
	jr	z,writs1		; Yes then jump
	dec	a			; Decrement pointer to block number
	call	getdm4			; Get previous blocknumber
writs1:	call	getfre			; Get nearest free block
	pop	hl			; Get pointer to block number
	ld	a,d			; Test if blocknumber = 0
	or	e
	jr	z,writs8		; Yes then disk full error
	res	7,(ix+14)		; Reset FCB/file modified
	ld	(hl),e			; Save blocknumber
	ld	a,(maxlen+1)		; Get number of blocks
	or	a			; Test if <256
	jr	z,writs2		; Yes then jump
	inc	hl			; Increment to MSB block number
	ld	(hl),d			; Save MSB block number
writs2:	ld	c,2			; Set write new block flag
	ld	a,(nmask)		; Get sector mask
	and	(ix+32)			; Mask with record counter
	jr	z,writsx		; Zero then ok (at start new record)
	ld	c,0			; Else clear new block flag
writsx:	ld	a,(funct)		; Get function number
	sub	40			; Test if write rr with zero fill
	jr	nz,writs6		; No then jump
	push	de			; Save blocknumber
	ld	hl,(dirbuf)		; Use directory buffer for zero fill
	ld	b,128			; 128 bytes to clear
writs3:	ld	(hl),a			; Clear directory buffer
	inc	hl			; Increment pointer
	djnz	writs3			; Clear all bytes
	call	calsec			; Calculate sector number (128 bytes)
	ld	a,(nmask)		; Get sector mask
	ld	b,a			; Copy it
	inc	b			; Increment it to get number of writes
	cpl				; Complement sector mask
	and	e			; Mask sector number
	ld	e,a			; And save it
	ld	c,2			; Set write new block flag
writs4:	push	hl			; Save registers
	push	de
	push	bc
	call	calst			; Calculate sector/track
	call	DMAdir			; Set DMA directory buffer
	pop	bc			; Get write new block flag
	push	bc			; Save it again
	call	writer			; Write record on disk
	pop	bc			; Restore registers
	pop	de
	pop	hl
	ld	c,0			; Clear write new block flag
	inc	e			; Increment sector number
	djnz	writs4			; Write all blocks
	call	stDMA			; Set user DMA address
	pop	de			; Get block number
writs5:	ld	c,0			; Clear write new block flag
writs6:	res	7,(ix+14)		; Reset FCB/file modified flag
	push	bc			; Save it
	call	calsec			; Calculate sector number (128 bytes)
	call	calst			; Calculate sector/track
	pop	bc			; Get write new block flag
	call	writer			; Write record on disk
	ld	a,(ix+32)		; Get record counter
	cp	(ix+15)			; Compare with next record
	jr	c,writs7		; If less then jump
	inc	a			; Increment record count
	ld	(ix+15),a		; Save it on next record position
	res	7,(ix+14)		; Reset FCB/file modified flag
writs7:	ld	a,(funct)		; Get function number
	cp	21			; Test write sequential
	ret	nz			; Not then return
	inc	(ix+32)			; Increment record count
	ret				; And return to caller
writs8:	ld	a,2			; Set disk full error
	ld	(pexit),a
	ret				; And return to caller
writs9:	ld	a,1			; Set directory full flag
	ld	(pexit),a
	ret				; And return to caller
;
; Load FCB for random read/write
;
;	Exit:	Z  no error
;		NZ error occured
;
ldFCB:	ld	(rdwr),a		; Save read/write flag
	ld	a,(ix+33)		; Get first byte random record
	ld	d,a			; Save it in d
	res	7,d			; Reset MSB to get next record
	rla				; Shift MSB in carry
	ld	a,(ix+34)		; Load next byte random record
	rla				; Shift carry
	push	af			; Save it
	and	01fh			; Mask next extent
	ld	c,a			; Save it in c
	pop	af			; Get byte
	rla				; Shift 4 times
	rla
	rla
	rla
	and	0fh			; Mask it
	ld	b,a			; Save FCB+14
	ld	a,(ix+35)		; Get next byte random record
	ld	e,6			; Set random record to large flag
	cp	4			; Test random record to large
	jr	nc,ldFCB8		; Yes then error
	rlca				; Shift 4 times
	rlca
	rlca
	rlca
	add	a,b			; Add byte
	ld	b,a			; Save FCB+14 in b
	ld	(ix+32),d		; Set next record count
	ld	d,(ix+14)		; Get FCB+14
	bit	6,d			; Test error random record
	jr	nz,ldFCB0		; Yes then jump
	ld	a,c			; Get new extent number
	cp	(ix+12)			; Compare with FCB
	jr	nz,ldFCB0		; Not equal then open next extent
	ld	a,b			; Get new FCB+14
	xor	(ix+14)			; Compare with FCB+14
	and	03fh			; Mask it
	jr	z,ldFCB6		; Equal then return
ldFCB0:	bit	7,d			; Test FCB modified (write)
	jr	nz,ldFCB1		; No then jump
	push	de			; Save registers
	push	bc
	call	close			; Close extent
	pop	bc			; Restore registers
	pop	de
	ld	e,3			; Set close error
	ld	a,(pexit)		; Get exit code
	inc	a
	jr	z,ldFCB7		; Error then exit
ldFCB1:	ld	(ix+12),c		; Save new extent number
	ld	(ix+14),b		; Save new FCB+14
	bit	7,d			; Test FCB modified (previous FCB)
	jr	nz,ldFCB3		; No then jump
ldFCB2:	ld	a,15			; Set number of bytes to search for
	call	search			; Search next FCB
	jr	ldFCB4			; Jump
ldFCB3:	bit	7,(ix+10)		; Test if system file
	jr	z,ldFCB2		; No use search
	call	findf			; Open file
ldFCB4:	ld	a,(pexit)		; Get error code
	inc	a
	jr	nz,ldFCB5		; No error then exit
	ld	a,(rdwr)		; Get read/write flag
	ld	e,4			; Set read empty record
	inc	a
	jr	nz,ldFCB7		; Read then error
	call	make			; Make new FCB
	ld	e,5			; Set make error
	ld	a,(pexit)		; Get error code
	inc	a
	jr	z,ldFCB7		; Error then exit
	jr	ldFCB6			; No error exit (zero set)
ldFCB5:	call	openf0			; Open file
ldFCB6:	xor	a			; Set zero flag and clear error code
	ld	(pexit),a
	ret				; And return to caller
ldFCB7:	ld	(ix+14),0c0h		; Set random record error
ldFCB8:	ld	a,e			; Get error code
	ld	(pexit),a		; And save it
	set	7,(ix+14)		; Set FCB/file not modified
	or	a			; Clear zero flag
	ret				; And return to caller
;
; Calculate random record
;	Entry:	HL = offset in FCB
;		DE = FCB pointer
;	Exit:	D  = LSB random record
;		C  = ISB random record
;		B  = MSB random record
;
calrrc:	add	hl,de			; Pointer to FCB+15 or FCB+32
	ld	a,(hl)			; Get byte
	ld	hl,12			; Offset to extent number
	add	hl,de			; Get pointer to extent byte
	ld	d,a			; Save first byte
	ld	a,(hl)			; Get extent byte
	and	01fh			; Mask it
	rl	d			; Shift MSB in carry
	adc	a,0			; Add carry
	rra				; Shift 1 time (16 bits)
	rr	d
	ld	c,a			; Save isb
	inc	hl			; Increment to FCB+14
	inc	hl
	ld	a,(hl)			; Get FCB+14
	rrca				; Shift 4 times
	rrca
	rrca
	rrca
	push	af			; Save it
	and	03h			; Mask MSB
	ld	b,a			; Save it
	pop	af			; Get LSB
	and	0f0h			; Mask it
	add	a,c			; Add with isb
	ld	c,a			; Save isb
	ret	nc			; No carry then return
	inc	b			; Increment MSB
	ret				; And return to caller

; END Z80DDISK.Z80

