; ; Set DMA address command ; cmnd26: ld (dma),de ; Save DMA address ; ; Set DMA address ; stdma: ld bc,(dma) ; Get DMA address jr dmadr0 ; And do P2bios call ; ; Set DMA address directory ; dmadir: ld bc,(dirbuf) ; Get DMA address directory dmadr0: jp setdma ; P2bios call set DMA ; ; Get bit from alv 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 alv 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 length 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 command ; cmnd28: ; ; Set write protect disk ; 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. Returns with results of caldir in HL ; chkfro: call caldir ; Get directory entry chkfr0: ; The following code added by l.h. to disable error checking for read ; operations and to prevent error reporting on physical extents after the ; first if error is overridden. ; ld a,(rdwr) ; Get the read/write flag or a ; Is a read operation in prog. ret z ; If so, just return. ld a,(passfg) ; Pass flag set? or a ret nz ; Not first extent, error already done dec a ; Set Pass flag ld (passfg),a ; And save it ; push hl ; Save directory entry ld de,2 ; Offset to public file bit add hl,de ; Add offset ld a,(flags) bit 4,a ; Public r/o flag jr z,nopub ; Public file flag off, then no check bit 7,(hl) ; Test public file jr nz,chkf.5 ; Yes then error nopub: ld e,7 ; Offset to file r/o bit add hl,de ; Add offset bit 7,(hl) ; Test file r/o jr nz,chkf.5 ; Yes then error ; System files should not be r/o for CP/M compatibility-b.h. ; inc hl ; Increment to system file ; bit 7,(hl) ; Test system file chkf.5: pop hl ; Restore directory entry pointer ret z ; No system file then ok ; Beyond this point an an error has occurred. ; chkfr1: push hl ; Save directory entry for error ret ld a,1 ld (retflg),a 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 alv 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 length-1 in bc or a ; Clear carry sbc hl,bc ; Test hl>=length 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. ; et: call home ; ; Search next file name ; searcn: xor a ; Check checksum directory 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 if dotime ld a,(hl) ; Get first byte directory entry cp 021h ; Test time stamp jr z,searcn ; Yes then get next directory entry endif ld a,(searnb) ; Get number of bytes to search for ld b,a ; Save it in counter xor a ; Clear accu ld (searqu),a ; Clear question mark detected flag ld (searpu),a ; Clear public file flag 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 sub '?' ; Test if question mark jr z,searc6 ; Yes then jump ld a,c ; Get FCB counter or a ; Test first byte jr nz,searc3 ; No then jump ld a,(flags) ; Get flag byte bit 0,a ; Test public file enable jr z,searc3 ; No then jump inc hl ; Check for public file ld a,(hl) ; Test for public '$' cp '$' jr nz,no$ dec hl jr is$ no$: inc hl bit 7,(hl) ; Test public bit directory dec hl ; Restore pointer dec hl jr z,searc3 ; No public file then jump is$: 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 user code jr z,searc5 ; Yes then no test cp 12 ; Test if extent 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 extents ld b,a ; Save it ld a,(nextnd) ; Get extent mask cpl ; Complement it and 01fh ; Mask it and b ; Mask extents pop bc ; Retore 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 hl,rdwr dec (hl) ; Yes, this is a write operation 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 ; chkfro preserves caldir results in HL, so not necessary to call again ; call caldir ; Get entry point directory ld (hl),0e5h ; Remove file ld c,0 ; Remove bits alv buffer call fillbb call wrfcb1 ; 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 ld hl,rdwr ; Get read write pointer (l.h.) dec (hl) ; Define this as a write op. (l.h.) call chkfro ; Check file r/o res 7,(ix+27) ; Don't allow archive bit on rename ld bc,12*256+16 ; Copy FCB+16 to directory+0 12 times 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, A = 0 ld bc,12*256+0 ; Copy FCB+0 to directory+0 12 times 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 length 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 caldir ; Get directory entry push hl ; Save pointer ; ld a,(funct) ; Get the function code (l.h.) ; cp 30 ; Are we resetting the status? (l.h.) ; jr z,wrfcb0 ; If so, don't reset archive bit (l.h.) ; res 7,(ix+11) ; Reset the archive bit (l.h.) wrfcb0: ld a,(hl) ; Get user code ex de,hl ; Copy to de push ix ; Save FCB entry pop hl ; Get it in hl push bc ; Save bc ld b,0 ; Reset b for add add hl,bc ; Add offset FCB pop bc ; Restore bc ld c,b ; Get number of bytes to move ld b,0 ; Reset b for ldir ldir ; Move bytes pop hl ; Get pointer user code ld (hl),a ; Restore it wrfcb1: call stdir ; Calculate sector/track directory jp writdr ; Write directory on disk ; ; Find file ; ; Modified by l.h. To access public files as well as system files in the ; search path. Now findf uses 0ffh as the path string terminator since this ; is what comes naturally to addresses 40h + when the kaypro 10 is powered up. ; findf: ld a,15 ; Number of bytes to search for call search ; Search file if ispath call tstfct ; Test if file present ret nz ; Yes then exit ld a,(rdwr) ; Test if write function or a ret nz ; Yes then exit ld a,(searqu) ; Test if question mark used or a ret nz ; Yes then exit ld hl,(path) ; Get path address ld a,h ; Test if zero (no path) or l ret z ; Yes then exit findf0: ld a,(hl) ; Get first entry path name inc hl ; Increment pointer ; inc a ; Test if last entry (l.h.) or a ; Test if last entry jp z,searc8 ; Yes then error exit and 07fh ; Mask drive number cp '$' ; Test if current drive jr nz,findf1 ; No then jump ld a,(drive) ; Get current drive inc a ; Increment drive number findf1: dec a ; Decrement drive number push hl ; Save path pointer call seldk ; Select drive pop hl ; Restore path pointer ld a,(hl) ; Get user number inc hl ; Advance pointer and 07fh ; Mask user number cp '$' ; Test if current user jr nz,findf2 ; No then jump ld a,(user) ; Get current user findf2: and 01fh ; Mask user number ld b,a ; Save it ld a,(ix+0) ; Get FCB byte 0 and 0e0h ; Remove user number or b ; Add new user number ld (ix+0),a ; And save it push hl ; Save path pointer ld a,15 ; Set number of bytes to search for call search ; Search file call tstfct ; Test if file present pop hl ; Restore path pointer jr z,findf0 ; No then test next path entry push hl ; Save path pointer call caldir ; Get directory entry inc hl ; Add offset, public bit (l.h.) ld a,(hl) cp '$' jr z,findf3 ; Test for '$' inc hl bit 7,(hl) ; Test public file jr nz,findf3 ld de,8 ; Add offset system bit add hl,de bit 7,(hl) ; Test system file findf3: pop hl ; Restore path pointer jr z,findf0 ; No system file then test next path ; entry ld a,(defdrv) ; Get current drive inc a ; Increment drive number ld (fcb0),a ; Save it in exit FCB0 endif ret ; And return to caller ; ; Open file command ; cmnd15: call seldrv ; Select drive from FCB ld (ix+14),0 ; Clear FCB+14 ; ; Open file ; openf: call findf ; Find file (use path name) 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 ix ; Save FCB entry pop de ; Get in in de ld bc,32 ; Number of bytes to move ldir ; Move directory to FCB 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 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 ; chkfro preserves results of caldir in HL ; 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 ; dec hl ; Hl points to byte with archive bit (l.h.) ; res 7,(hl) ; Reset the archive bit ; inc hl ; Put hl back 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 ; ; These lines have to be removed to let submit work correctly ; ; Jr nz,close2 ; Extents not equal then jump ; cp (hl) ; Test FCB < directory ; jr c,close3 ; If so then jump ; close2: ld (hl),a ; Save next record in directory close3: if dotime ld e,5 ; Set last update date/time call stime ; Update time endif jp wrfcb1 ; 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 less then 256 blocks ; 0ffh more or equal to 256 blocks ; exit : zero : 1 blocks are the same ; 0 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 unp to FCB+31 inc hl ; Increment pointer djnz make0 ; And clear all bytes call caldir ; Get directory entry ld a,(ix+0) ; Get first byte FCB ld (hl),a ; Save it in directory (write FCB ; needs this) if dotime ld e,1 ; Set creation date/time call stime ; Update time in directory ld e,5 ; Set last update date/time call stime ; Update time in directory endif ; ld bc,32*256+0 ; Copy FCB+0 to directoty+0 32 times 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 path 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: carry=1 => overflow detected ; zero =1 => search next extent ; zero =0 => 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 ; Open next extent ld a,(pexit) ; Get exit code or a jr nz,reads0 ; Yes then end of file ld (ix+32),a ; 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 sector with zero fill command ; cmnd40: call seldrv ; Select drive from FCB ; ; Write random sector with zero fill ; wrranz: 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 random record command ; cmnd34: 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