home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
ENTERPRS
/
CPM
/
UTILS
/
S
/
Z80DOS10.ARC
/
Z80DDISK.Z80
< prev
next >
Wrap
Text File
|
1989-09-15
|
44KB
|
1,524 lines
; 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