; ; Z80DOS - Z80 Disk Operating System ; ; Version 2.4 Maskable disk reset's using variable fixdrv ; Now can assemble with Z80MR if Z80MR equate ; set to -1. ; Gene Nolan 4/9/89 ; ; ;------------------------------------------------------ ; ; Version 2.31 Fast file lookup for random records fix ; Date 15 Nov 88 ; Update Eugene Nolan ; ; Version 2.3 Fast file lookup ; Date: 4 Nov 88 ; Update: Eugene Nolan ; ;------------------------------------------------------------- ; Version 2.0a - BETA TEST VERSION - 6 Nov 87 by Carson Wilson ; ; Support file: Z80DDISK.Z80 ; Version: 2.0 ; Date: 6 Nov 87 ; Author: Carson Wilson ; Description: DOS Return CP/M Version, Disk Functions ; ; Changes: -------- ; Changed Readr and Writer to use a common error function, ; RWErr, which displays "Data error on d:". ; ; new disk will be overwritten, data from the first file will ; probably be lost. ; ; -------- ; Command 37 (reset individual disk) now resets the disk changed ; vector instead of the drive R/O vector. ; ; -------- ; Removed code which made public files read-only from ; other user areas. The user must now manually set public ; files to read-only using the R/O attribute (t1). This ; change was made because some applications must write to ; public files. ; ; -------- ; System files are now R/W unless referenced by wildcards. ; ; ----------------------- ; ; Return version number ; ; ----------------------- cmnd12: ld a,22h ; Set version number ld ix,3800h ; this will put an '8' into D ; register upon return, saying ; Z80DOS operating jp cmd25a ; And exit ; ----------------------------- ; ; Disk functions ; ; ----------------------------- ; ; Reset disk system ; cmnd13: ; ld hl,0 ; Load zero ld hl,(login) ; Get login vector ld de,(fixdrvs) ; get drive mask ld a,h and d ld h,a ld a,l and e ld l,a ; HL now has selective drives ; logged out ld (login),hl ld hl,0 ld (dskro),hl ; All drives read/write ld (diff),hl ; No disks changed ld hl,RamLow+80h ; Set up DMA address ld (DMA),hl ; And save it call stDMA ; Do BIOS call ld a,ResDsk+1 ; When selective logout enabled ; the call to seldk below requires ; defdrv and the drive to select in ; the A reg to be different ld (defdrv),a ; Save it ld a,ResDsk ; 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 from vector in DE ; 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,(diff) ; Get disk changed 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 (diff),hl ; Save disk changed 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 ld d,a 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,d 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 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 ld de,dirbuf ; Load dirbuf pointer ld bc,8 ; Copy pointers to dirbuf, ldir ; ..csv (wacd), alv from BIOS 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 dec hl 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 from (defdrv) in HL ; Exit: DE = HL before setting bit (if any) ; 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,a ; 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 ; ; Exit: Zero flag set and A = 0 if filcnt = 0ffffh ; 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 filcnt-(temp0) sub (hl) inc hl ld a,d sbc a,(hl) ; Carry means (temp0) > filcnt 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 a,h or l ret Z 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 hl,(diff) ; Get disk changed vector call sdrvb ; Include drive bit ld (diff),hl ; Save disk changed bit jp setfn ; Set # files to maximum chkdr1: ld (hl),a ; Update checksum ret ; And exit ; ; Read sector from drive ; readr: call read ; BIOS call read sector jr write0 ; Test exit code ; ; Write sector on drive ; writer: call write ; BIOS call write sector write0: or a ; Test exit code ret Z ; Exit if ok ld hl,(StRW) ; Point to data error routine ld (retflg),a ; Allow retry for read/write errors jp (hl) ; Display "Data error on d:" ; ; 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: 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 de,9 ; Offset to file R/O bit add hl,de ; Add offset bit 7,(hl) ; Test file R/O jr NZ,chkfr2 ; Yes then error ; ; System files are R/O if referenced with wildcards: ; ld a,(searqu) ; Test if question mark used 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) ; ; Entry point to search for a file that is currently open ; sear0: ld a,15 ; Match first 15 bytes sear01: ld (searnb),a ; Save number of bytes ld a,(ix+13) ; Check if =FF, if was, use normal inc a ; search routine jr Z,sr1 call home ; Force BIOS directory read ld l,(ix+13) ; Get sector of directory file was on ld h,0 ; *4 to satisify internal data base sla l rl h sla l rl h ld (filcnt),hl ; Place in internal data base push hl call stdir ; Get sec-trk of directory entry call readdr ; Read it to memory pop hl dec hl ; -1, will be +1 in readdr ld (filcnt),hl jr sear1 ; ; Find file name only ; findfn: ld a,12 jr search ; ; Find file ; findf: ld a,15 ; Number of bytes to search for ; ; Search for file name ; Entry: A = number of bytes to search for ; search: ld (searnb),a ; Save number of bytes sr1: call setfct ; Initiate file counter call home ; Force BIOS directory read sear1: ld a,0ffh ; Set exit code to 0ffh (not found) ld (searex),a ld (dcopy),ix ; Copy FCB pointer to ram (search next) ; ; ..after disk change ; Search next file name ; SearcN: xor a ; Clear accu, check checksum dir. ld (searqu),a ; Clear question mark detected flag ld (searpu),a ; Clear public 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 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 call findfn 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 call findfn 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 call findfn 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 call findfn 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 ; ; Calculate sector of file opened in FCB ; cmd15: call tstfct ; Look for ffff jr Z,cmd151 ; yes, save ff, can't do fast lookup srl h ; HL=(filcnt)/4-1 rr l srl h rr l dec l cmd151: ld (ix+13),l ; Save in FCB+13 for use in SEAR0 ret ; ; Open file ; cmnd15: call seldrv ; Select drive from FCB ld (ix+14),0 ; Clear FCB+14 openf: call findf ; Find file call tstfct ; Test file found ret Z ; No then exit openf0: ld a,(ix+12) ; Get extent number from FCB push af ; Save it call caldir ; Get directory entry push hl ; Save it ld e,8 ; Set access date/time call stime ; Zero flag set if stamps present pop hl ; Get directory entry 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 to disk if stamps present 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 call cmd15 ; Fill in FCB+13,fast lookup 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 findf call sear0 ; Use fast search 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 inc hl inc hl push hl call cmd15 ; Fill in FCB+13 for next fast lookup ld a,l pop hl ld (hl),a 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 ; ; Entry point to use fast lookup to 'MAKE' next FCB entry for open file ; maker: call mak0 push af ld a,1 call sear01 jr mak1 ; ; Common code for MAKE/MAKER ; mak0: call chkro ; Check drive R/O ld a,(ix+0) ; Get first byte FCB ld (ix+0),0e5h ; Set first byte to empty file ret ; ; Make file command ; cmnd22: call seldrv ; Select drive from FCB ld (ix+14),0 ; Clear FCB+14 ; ; Make file ; make: call mak0 push af ; Save it ld a,1 ; Search for 1 byte call search ; Search empty file mak1: 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 call stime res 7,(ix+11) ; Reset archive bit if present ; call cmd15 ; Fill in FCB for fast lookup ; call caldir ; Get directory entry ; push ix ; Save FCB entry ; pop de ; Get it in de call caldir ; get directory entry push hl ; save directory pointer push ix ; put fcb pointer on stack call cmd15 ; fill in FCB+13 pop de ; fcb pointer to DE pop hl ; directory entry pointer 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: call sear0 ; Use fast lookup to find next extent 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 maker ; 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 NC,openx0 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 ; ld c,30h ; call conout ; ; 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 ; ; Write random record commands ; cmnd34: cmnd40: call seldrv ; 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 seldrv ; 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 ; Check for changed disk. ; If disk changed: ; If file modified, abort. ; Else reset disk and disk changed bit. ; ; Test disk changed ; ld hl,(diff) ; Get drive changed vector call sdrvb ; Set current drive bit sbc hl,de ; Test extra bit added jr NZ,writsa ; Bit added, so disk not changed ; Test file modified ; bit 7,(ix+14) ; File modified? jp Z,chgerr ; Yes, abort and warm boot ; Reset disk and disk changed bit. ; HL = 0 from SBC, DE = (diff) from SDRVB above ; push de ; Save (diff) call sdrvb ; Set current bit only in HL pop de ; Get (diff) push hl ; Save current drive bit for reset ld a,d xor h ld d,a ; Mask current bit in DE ld a,e xor l ld e,a ld (diff),de ; Reset disk changed bit in (diff) pop de ; Get current bit for disk reset call cmnd37 ; No, reset drive: ld a,(defdrv) ; Get drive call seldk ; ..and log it in again writsa: 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: ; call sear0 ; File was opened for writing, so ; the close filled in FCB+13 for fast ; lookup, so do it ; jr ldFCB4 ; Jump ldFCB3: call findf ; Open file old way because may not ; have valid FCB+13 for fast lookup 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 maker ; Make new FCB using fast lookup 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