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
/
ZSYS
/
SIMTEL20
/
SYSLIB
/
SLIB2.LBR
/
SFXIO.Z80
< prev
next >
Wrap
Text File
|
2000-06-30
|
13KB
|
537 lines
;
; SYSLIB Module Name: SFXIO
; Author: Richard Conn
; SYSLIB Version Number: 3.6
; Module Version Number: 1.3
public fxi$open,fx$get,fxi$close
public fxo$open,fx$put,fxo$close
; Date: 28 Apr 85
; Revised: Al Dunsmuir
; Changes: - FX$GET and FX$PUT routines optimized for speed
; (PUTADR/GETADR not used if disk I/O not required)
; - Use direct DMA vs DMA to TBUFF and software move.
; Makes byte I/O a bit faster AND safer.
; - Some misc. code optimization also performed.
;
; Previous Version: 1.0 (16 Jan 84)
;
; SFXIO provides a group of routines which can perform byte-oriented
; file I/O with a user-defined buffer size. All of these routines work with
; an I/O Control Block which is structured as follows:
;
; Byte Length (Bytes) Function
; 0 1 Number of 128-byte pages in
; working buffer (set by user)
; 1 1 End of File Flag (set and used
; by SFXIO)
; 2 2 Byte Counter (set and used by SFXIO)
; 4 2 Next Byte Pointer (set and used by
; SFXIO)
; 6 2 Address of Working Buffer (set by user)
; 8 36 FCB of File (FN and FT Fields set by
; user, rest set by SFXIO)
;
; The following DB/DS structure can be used in the calling program
; to implement the I/O Control Block:
;
; IOCTL: DB 8 ; Use 8 128-byte pages (1K)
; DS 1 ; Filled by SFXIO
; DS 2 ; Filled by SFXIO
; DS 2 ; Filled by SFXIO
; DW WORKBF ; Address of Working Buffer
;
; IOCFCB: DB 0 ; Current Disk (Inited by SFXIO)
; DB 'MYFILE ' ; File Name
; DB 'TXT' ; File Type
; DS 24 ; Fill Out 36 Bytes
;
; WORKBF: DS 1024 ; Working Buffer
;
; All uses of the routines contain the address of IOCTL in DE.
; Note that if you use a buffer for input, DO NOT use it for output also!
;
;
; External SYSLIB References
;
EXT F$OPEN ;Open File
EXT F$MOPEN ;Open/Create file
EXT INITFCB ;Init FCB
EXT F$CLOSE ;Close file
EXT SHFTRH ;Shift HL right one bit.
EXT SHFTLH ;Shift HL left one bit.
; CP/M Equates and ASCII Constants
;
TBUFF EQU 80H ;Temporary File I/O buffer
CTRLZ EQU 'Z'-'@' ;^Z
BDOS EQU 5 ;BDOS entry point
B$CL EQU 16 ; Close file
B$RD EQU 20 ; Read next record
B$WR EQU 21 ; Write next record
B$DMA EQU 26 ; Set DMA address
; **** Macro Routines for FXIO ****
;
PUTRG MACRO ;Save BC, DE, HL
PUSH BC
PUSH DE
PUSH HL
ENDM
GETRG MACRO ;Restore BC, DE, HL
POP HL
POP DE
POP BC
ENDM
; **** Support Routines for FXIO ****
;
;
; FXIO0 - Routine to read next buffer-full from disk
;
FXIO0: LD A,(EOF) ;Check for EOF
OR A ;Abort if already at EOF
RET NZ ;NZ is error code
;
LD HL,(BUFADR) ;Get address of input buffer
LD A,(BCNT) ;Get block count
LD B,A ;... in B
FXIO1: PUSH BC ;Save remaining block count.
PUSH HL ;Save current Input buffer ptr
EX DE,HL ;Get buffer addr in DE
LD C,B$DMA ;Point BDOS DMA ptr to input buffer
CALL BDOS
;
LD HL,(FCB) ;Get FCB address
EX DE,HL ;... IN DE
LD C,B$RD ;Read block via BDOS
CALL BDOS
POP HL ;Restore input buffer ptr
POP BC ;Restore remaining block count
OR A ;Check Read return code.
JP NZ,FXIO2 ;Br if End-of-File
;
LD DE,128 ;Get block length
ADD HL,DE ;Update buffer addr to point to next block
;
DEC B ;One more block processed
JP NZ,FXIO1 ;Loop until all blocks written.
JP FXIO3 ;Done.
FXIO2: LD A,0FFH ;Set "EOF" condition
LD (EOF),A ;Set EOF flag
;
FXIO3: LD HL,(BUFADR) ;Pt to first byte in buffer
LD (BYTENXT),HL ; as "next byte" address
;
LD A,(BCNT) ;Get block count
SUB B ;Adjust by # empty blocks
LD H,A ;Convert to bytes
LD L,0
CALL SHFTRH
LD (BYTECNT),HL ;Set byte count
;
PUSH HL ;Save byte count
LD DE,TBUFF ;Reset DMA address (for compatability)
LD C,B$DMA
CALL BDOS
POP HL ;Get byte count
;
LD A,H ;Set EOF return code based on byte count
OR L
JP Z,FXIO4
XOR A ;Set no error (data available)
RET
FXIO4:
OR 0FFH ;Set error (no data available)
RET
;
; FXOO0 - Routine to flush buffer to disk and set up for next write
;
FXOO0: LD HL,(BYTECNT) ;Get # of bytes yet to go
CALL SHFTLH ;Convert to blocks
LD A,(BCNT) ;Get # of blocks in buffer
SUB H ;Compute number to write
LD B,A ;Get final block count in B
LD HL,(BUFADR) ;Pt to first byte to write
;
FXOO1: LD A,B ;Check if write complete
OR A ;0=Done
JP Z,FXOO2
;
DEC B ;Decrement block counter
PUSH BC ;Save remaining block count
PUSH HL ;Save current Output buffer ptr
EX DE,HL ;Get buffer addr in DE
LD C,B$DMA ;Point BDOS DMA ptr to output buffer
CALL BDOS
;
LD HL,(FCB) ;Get FCB address
EX DE,HL ;... IN DE
LD C,B$WR ;Write block via BDOS
CALL BDOS
POP HL ;Restore output buffer ptr
POP BC ;Restore remaining block count
;
LD DE,128 ;Get block length
ADD HL,DE ;Update buffer addr to point to next block
;
OR A ;Check Write return code.
JP Z,FXOO1 ;If OK, Loop until all blocks have been written
;
OR 0FFH ;Set error code
RET
; FXOO2 - Routine to init buffers for next write
;
FXOO2: LD HL,(BUFADR) ;Pt to first byte in buffer
LD (BYTENXT),HL ; as "next byte" address
;
XOR A ;SET NO EOF
LD (EOF),A
;
LD A,(BCNT) ;Get block count
LD H,A ;Convert to bytes
LD L,0
CALL SHFTRH
LD (BYTECNT),HL ;Set byte count
;
LD DE,TBUFF ;Reset DMA address (for compatability)
LD C,B$DMA
CALL BDOS
;
XOR A ;No Error
RET
; **** Base Routines for FXIO ****
;
;
; FXI$OPEN - Open file/buffers for Byte-Oriented Input (GET)
; on input, DE pts to I/O Control Block
; on output, A=0 and Zero flag set if error (File not found)
;
FXI$OPEN:
PUTRG ;Save registers
CALL PUTADR ;Copy I/O Control Block data
XOR A ;Set no EOF
LD (EOF),A
LD HL,(FCB) ;Get FCB address
EX DE,HL ;... in DE
CALL INITFCB ;Init FCB
CALL F$OPEN ;Attempt to open file
JP NZ,ERRET ;NZ = Error (File not found)
;
CALL FXIO0 ;OK - Fill buffer with data
;
; Normal return
;
OKRET: CALL GETADR ;Update I/O Control Block data
GETRG ;Restore regs
OR 0FFH ;Indicate success
RET
; Error return
;
ERRET: GETRG ;Restore regs
XOR A ;Indicate Error
RET
; FXO$OPEN - Open file/buffers for Byte-Oriented Output (PUT)
; on input, DE pts to I/O Control Block
; on output, A=0 and Zero flag set if error (No Directory space)
;
FXO$OPEN:
PUTRG ;Save registers
CALL PUTADR ;Copy I/O Control Block data
CALL FXOO2 ;Init buffers
LD HL,(FCB) ;Get FCB address
EX DE,HL ;... in DE
CALL INITFCB ;Init FCB
CALL F$MOPEN ;Open and/or Create file
JP NZ,ERRET ;NZ = Error (No Directory Space)
JP OKRET ;OK- Return and update I/O Control Block
; FX$GET - Get next byte from buffer/file
; on input, DE pts to I/O Control Block
; on output, A=Char and Zero flag set if past EOF
;
FX$GET:
PUTRG ;Save registers
;
; Check if data byte is in buffer.
;
EX DE,HL ;HL -> I/O Control Block data
INC HL ;Get caller's BYTECNT in DE
INC HL
LD E,(HL)
INC HL
LD D,(HL)
DEC HL ;Pt to caller's BYTECNT again.
LD A,D ;Is the data byte in the buffer?
OR E
JP Z,FXGET1 ;No - Fill buffer and GET byte.
;
; It is. GET it and update BYTECNT, BYTENXT as quickly as possible.
;
DEC DE ;Update byte count
LD (HL),E ;Update caller's BYTECNT.
INC HL
LD (HL),D
;
INC HL ;Get caller's BYTENXT.
LD E,(HL)
INC HL
LD D,(HL)
;
LD A,(DE) ;GET data byte from buffer
LD (BYTE),A ;Save for return.
;
INC DE ;Update caller's BYTENXT.
LD (HL),D
DEC HL
LD (HL),E
;
GETRG ;Restore regs
OR 0FFH ;Indicate success
LD A,(BYTE) ;Get data byte
RET
;
; Data byte not in buffer - Fill buffer from file first
;
FXGET1: EX DE,HL ;DE -> I/O Control Block data.
DEC DE
DEC DE
CALL PUTADR ;Copy I/O Control Block data
CALL FXIO0 ;Fill buffer from file
JP NZ,ERRET ;NZ = Error (End of File)
;
LD HL,(BYTENXT) ;Pt to first byte in buffer
LD A,(HL) ;GET from buffer
LD (BYTE),A ;Save it
INC HL ;Pt to next byte
LD (BYTENXT),HL ;Update next byte pointer
LD HL,(BYTECNT) ;One less byte in buffer
DEC HL
LD (BYTECNT),HL ;Update byte count
;
; Normal return
;
OKRET1: CALL GETADR ;Update I/O Control Block data
GETRG ;Restore regs
OR 0FFH ;Indicate success
LD A,(BYTE) ;Get data byte
RET
; FX$PUT - Put next byte into buffer/file
; on input, A=char and DE pts to I/O Control Block
; on output, A=Char and Zero flag set if write error
;
FX$PUT:
PUTRG ;Save registers
LD (BYTE),A ;Save byte to output
;
; Check if data byte will fit in buffer.
;
EX DE,HL ;HL -> I/O Control Block data
INC HL ;Get caller's BYTECNT in DE
INC HL
LD E,(HL)
INC HL
LD D,(HL)
DEC HL ;Pt to caller's BYTECNT again.
LD A,D ;Will the data byte fit in the buffer?
OR E
JP Z,FXPUT1 ;No - Flush buffer to file and PUT byte.
;
; It is. PUT it and update BYTECNT, BYTENXT as quickly as possible.
;
DEC DE ;Update byte count
LD (HL),E ;Update caller's BYTECNT.
INC HL
LD (HL),D
;
INC HL ;Get caller's BYTENXT.
LD E,(HL)
INC HL
LD D,(HL)
;
LD A,(BYTE) ;Get data byte
LD (DE),A ;PUT data byte in buffer
;
INC DE ;Update caller's BYTENXT.
LD (HL),D
DEC HL
LD (HL),E
;
GETRG ;Restore regs
OR 0FFH ;Indicate success
LD A,(BYTE) ;Get data byte
RET
;
; Data byte will not fit in buffer - Flush buffer to file first.
;
FXPUT1: EX DE,HL ;DE -> I/O Control Block data.
DEC DE
DEC DE
CALL PUTADR ;Copy I/O Control Block data
CALL FXOO0 ;NO - Flush buffer to file
JP NZ,ERRET ;NZ = Error (Write error)
;
LD HL,(BYTENXT) ;Pt to first byte in buffer
LD A,(BYTE) ;Get next byte
LD (HL),A ;PUT in buffer
INC HL ;Pt to next byte
LD (BYTENXT),HL ;Update next byte pointer
LD HL,(BYTECNT) ;One less byte of free space in buffer
DEC HL
LD (BYTECNT),HL ;Update byte count
JP OKRET1 ;OK-return with byte and updated control block
; FXI$CLOSE - Close file/buffers for Byte-Oriented Input (GET)
; on input, DE pts to I/O Control Block
; on output, A=0 and Zero flag set if error (Error in closing file)
;
FXI$CLOSE:
PUTRG ;Save registers
CALL PUTADR ;Copy I/O Control Block data
LD HL,(FCB) ;Get FCB address
EX DE,HL ;... in DE
CALL F$CLOSE ;Close file
JP NZ,ERRET ;NZ = Error (Close file error)
JP OKRET ;OK- Return and update I/O Control Block
; FXO$CLOSE - Close file/buffers for Byte-Oriented Output (PUT)
; on input, DE pts to I/O Control Block
; on output, A=0 and Zero flag set if error (Error in closing file)
;
FXO$CLOSE:
PUTRG ;Save registers
CALL PUTADR ;Copy I/O Control Block data
;
; Fill last block with ^Z
;
FXOCL1: LD HL,(BYTECNT) ;Get free space count.
LD A,L ;If on page boundary, done
AND 7FH
JP Z,FXOCL2
DEC HL ;One less byte of free space in buffer
LD (BYTECNT),HL ;Update byte count
LD HL,(BYTENXT) ;Pt to next byte
LD (HL),CTRLZ ;Store EOF char
INC HL
LD (BYTENXT),HL
JP FXOCL1 ;Loop until last block is full
;
; Close file and exit
;
FXOCL2: CALL FXOO0 ;Flush buffers to disk
LD HL,(FCB) ;Get FCB address
EX DE,HL ;... in DE
CALL F$CLOSE ;Close file
JP NZ,ERRET ;NZ = Error (Close file error)
JP OKRET ;OK- Return and update I/O Control Block
; PUTADR - Copy I/O Control Block data to local storage
;
PUTADR: EX DE,HL ;Get I/O Control Block addr in HL
LD (BUFFER),HL ;Save I/O Control Block address
;
LD A,(HL) ;Get block count
LD (BCNT),A
;
INC HL
LD A,(HL) ;Get eof flag
LD (EOF),A
;
INC HL
LD E,(HL) ;Get low count
INC HL
LD D,(HL)
EX DE,HL
LD (BYTECNT),HL ;Put byte count
;
EX DE,HL
INC HL
LD E,(HL) ;Get low address
INC HL
LD D,(HL)
EX DE,HL
LD (BYTENXT),HL ;Put next byte ptr
;
EX DE,HL
INC HL
LD E,(HL) ;Get low address
INC HL
LD D,(HL)
EX DE,HL
LD (BUFADR),HL ;Put buffer address ptr
;
EX DE,HL
INC HL
LD (FCB),HL ;Save address of FCB
RET
; GETADR - Update I/O Control Block data from local storage
;
GETADR: LD HL,(BUFFER) ;Get I/O Control Block address
;
INC HL ;Skip block count
;
LD A,(EOF) ;Get EOF flag
LD (HL),A
;
EX DE,HL
LD HL,(BYTECNT) ;Get byte count
EX DE,HL
INC HL
LD (HL),E ;Set low count
INC HL
LD (HL),D
EX DE,HL
;
LD HL,(BYTENXT) ;Get next byte pointer
EX DE,HL
INC HL
LD (HL),E ;Set low address
INC HL
LD (HL),D
RET
;
; BUFFERS
;
BYTE: DS 1 ;Data byte
BUFFER: DS 2 ;Starting address of I/O control block
; The following mirrors the structure of the I/O Control Block
;
BCNT: DS 1 ;Number of blocks in buffer
EOF: DS 1 ;EOF flag (0=not at EOF, 0FFH=at EOF)
BYTECNT: DS 2 ;Number of bytes to go yet
BYTENXT: DS 2 ;Address of next byte to PUT/GET
BUFADR: DS 2 ;Address of working buffer
FCB: DS 2 ;Address of FCB
END