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
/
CPM
/
BDOS
/
Z80DS231.LBR
/
Z80DDISK.ZZ0
/
Z80DDISK.Z80
Wrap
Text File
|
2000-06-30
|
45KB
|
1,688 lines
; Z80DOS - Z80 Disk Operating System Nov 15, 1988
;
; Version 2.31 Fast file lookup for random records fix
; Date: 15 Nov 88
; Update: Eugene Nolan
;
;-----------------------------------------------------------------------
;
; Version 2.3 Fast file lookup, ZRL compatibility
; 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
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
LD (DIFF),HL ; No disks changed <crw>
LD HL,RAMLOW+80H ; 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 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 <crw>
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 <crw>
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 <crw>
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
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 <crw>
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 <crw>
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 <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 to disk if stamps present <crw>
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
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
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+11) ; Reset archive bit if present
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
;
; 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: DS 0
;
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,LDFCB6 ; 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,LDFCB1 ; Yes then jump
LD A,C ; Get new extent number
CP (IX+12) ; Compare with FCB
JR NZ,LDFCB1 ; 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,LDFCB4 ; Equal then return
;
LDFCB1: BIT 7,D ; Test FCB modified (write)
JR NZ,LDFCB2 ; 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,LDFCB5 ; Error then exit
;
LDFCB2: LD (IX+12),C ; Save new extent number
LD (IX+14),B ; Save new FCB+14
CALL FINDF ; Open file old way because may not
; ; Have valid FCB+13 for fast lookup
LD A,(PEXIT) ; Get error code
INC A
JR NZ,LDFCB3 ; No error then exit
LD A,(RDWR) ; Get read/write flag
LD E,4 ; Set read empty record
INC A
JR NZ,LDFCB5 ; 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,LDFCB5 ; Error then exit
JR LDFCB4 ; No error exit (zero set)
;
LDFCB3: CALL OPENF0 ; Open file
;
LDFCB4: XOR A ; Set zero flag and clear error code
LD (PEXIT),A
RET ; And return to caller
;
LDFCB5: LD (IX+14),0C0H ; Set random record error
;
LDFCB6: 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