Author Topic: How to Read/Write a File "Byte by Byte" Using Firmware, BUT MUCH Faster!  (Read 407 times)

0 Members and 1 Guest are viewing this topic.

Offline ikonsgr

  • CPC6128
  • ****
  • Posts: 280
  • Country: gr
    • ikonsgr 80's Home Micros WorkBench
  • Liked: 183
  • Likes Given: 30
Hi everyone,


  As you probably already know, amstrad CPC, offers only two "extreme" firmware methods of read/write a file, either use CAS_DIRECT which read/write the entire file at once, or CAS_CHAR which do it, byte by byte.
 The first method is fast, but it has the major drawback of needing the hole file to be in ram at once, so any file with size of ~42kb (which unfortunately it's very common with many games) takes up all the available ram, leaving no room for any other program to be executed.
The second method solves this problem, but is rather slow (~3-4 times slower...)
 Fortunately, there is another way to do it, using the second method, but MUCH faster!
I develop this method in order to use it, in file transfer utilities which will utilize a Serial port interface  i'm developing , which will be rather cheap and easy to make, and i hope soon i'll be able to make a presantation here.
I originally took the idea from here , which roughly explains the "how to" fast read a file byte by byte, using firmware, but it doesn't give a complete example of how exactly to do this, and also, it doesn't include the method of doing the opposite, e.g. fast writing a file byte by byte.
 So, below i give you an assembly code example of how exaclty you can do this. The code first fast reads a file "byte by byte", place it in ram, and then reads back ram to fast write a file copy of the file with different name. In the code, you will also find a method of reading/writing the hole 128byte of file header and not only the first &45 bytes which the typical method offers. Note also that in order to use this method, file must have header (either binary or basic), but fortunately ascii files rarely used in games and most programs so i don't think this would be a problem.
The increase in speed by using this method is REALLY awesome! To give you some numbers, Reading/writing an 8Kb file using standard byte by byte method, needs ~21seconds, where fast read/write needs only ~8.5 seconds, about 2.5times faster!  ;) , (and only ~20-25% slower than using cas_direct method ,which is the fastest read/write you can get).
So, enough of tallking, here is the code:


;;This is an example of
;;Read/Write a file Byte by Byte
;;Using firmware, BUT MUCH FASTER!
;;File must have header,named "test.bin"
;;And don't be more than 10K.
;;Use MAXAM to assemble
;;load"Fastcopy",&4000:call &4000 to run

.CAS_OUT_OPEN EQU &BC8C
.CAS_OUT_CHAR EQU &BC95
.CAS_OUT_CLOSE EQU &BC8F
.CAS_IN_OPEN EQU &BC77
.CAS_IN_CHAR EQU &BC80
.CAS_IN_CLOSE EQU &BC7A

ORG &4000
NOLIST
write"FASTCOPY.BIN"

LD B,END_FLNAME-FLNAME
LD HL,FLNAME
LD DE,TWO_K_BUFFER
CALL CAS_IN_OPEN

DEC HL
DEC HL
PUSH HL
POP IY ;;IY=ADDR OF 2KBUF CURRENT POSITION
PUSH BC ;;BC=DATASIZE OF FILE

;;FIND ADDR FOR 128BYTES OF HEADER
;;THIS METHOD COPIES THE ENTIRE 128Byte
;;OF HEADER,AND NOT ONLY FIRST &45 BYTES
LD HL,(&be7d)
LD BC,&e4
ADD HL,BC ;; HL = start of header   
;;COPY HEADER TO RAM BUFFER
LD BC,&8000
LD D,0
.HEAD_LOOP
LD A,128
CP D
JP Z,HEAD_EXIT
LD A,(HL)
LD (BC),A
INC HL
INC D
INC BC
JP HEAD_LOOP
.HEAD_EXIT
;;SAVE FILE SIZE TO &7002,
;;START ADDR OF READED FILE TO MEMORY &8000
POP HL
LD (&7002),HL
DEC HL
PUSH HL
LD HL,&8080
LD (&7000),HL;;&7000=REMAINING BYTES TO READ

;;CAS_IN_CHAR FILLS THE 2K.BUFFER,
;;SET SYSTEM VARIABLES
.READ_2K
CALL CAS_IN_CHAR
LD (HL),A
INC HL
LD (&7000),HL
PUSH IY
POP HL
LD E,(HL)
INC HL
LD D,(HL)
LD BC,2047

;;LOOP FOR READING THE HOLE BUFFER
.READ_BYTE
;;COPY CURRENT BYTE TO RAM BUFFER
LD HL,(&7000)
LD A,(DE)
LD (HL),A
INC DE
INC HL
LD (&7000),HL
POP HL
DEC HL
LD A,H;;CHECK IF ALL DATA READED
OR L
JR Z,CLOSE_FILE

;;CHECK IF 2K.BUFFER IS FULL
LD A,B
OR C
JR Z,NEXT_2K
PUSH HL
JR READ_BYTE

.NEXT_2K
;;SET SYTEM'S ADDR OF CURRENT BYTE
;;READED FROM FILE
LD (IY+0),E
LD (IY+1),D
;;ADDR OF DATA RECORDS TO BE READ
;;IS SET TO ZERO
XOR A
LD (IY+21),A
LD (IY+22),A
JR READ_2K

.CLOSE_FILE
CALL CAS_IN_CLOSE

;;NOW FASTWRITE THE RAMBUFFER TO FILE

LD HL,(&7002);;READ FILE SIZE FROM &7002
;;ADD HEADER TO FILE'S DATASIZE
LD BC,128
ADD HL,BC
DEC HL
LD (&7002),HL

LD B,END_FWNAME-FWNAME
LD HL,FWNAME
LD DE,TWO_K_BUFFER
CALL CAS_OUT_OPEN
DEC HL
DEC HL
PUSH HL
POP IY ;;IY=ADDR.OF.CUR.POS.2KBUF
LD HL,&8000
LD A,(HL)

;;CAS_OUT_CHAR FILLS THE 2K.BUFFER,
;;SET SYSTEM VARIABLES
.WRITE_2K
CALL CAS_OUT_CHAR
INC HL
PUSH HL
PUSH IY
POP HL
LD E,(HL)
INC HL
LD D,(HL)
LD BC,2047
POP HL

;;LOOP FOR WRITING THE HOLE BUFFER
.WRITE_BYTE
LD A,(HL)
LD (DE),A
DEC BC
INC DE
INC HL
PUSH HL
LD HL,(&7002)
DEC HL
LD A,H;;;;CHECK IF ALL DATA WRITEN
OR L
JR Z,CLOSE_WFILE

;;CHECK IF 2K.BUFFER IS FULL
LD (&7002),HL
LD A,B
OR C
JR Z,NEXT_W2K
POP HL
JR WRITE_BYTE

.NEXT_W2K
LD (IY+0),E
LD (IY+1),D
LD A,0
LD (IY+21),A
LD A,&08
LD (IY+22),A
POP HL
JR WRITE_2K

.CLOSE_WFILE
LD HL,2048
SCF
CCF
SBC HL,BC
LD (IY+21),L
LD (IY+22),H
LD (IY+0),E
LD (IY+1),D
CALL CAS_OUT_CLOSE
RET

;;FILENAME TO READ
.FLNAME
DEFB "TEST.BIN"
.END_FLNAME

;;FILENAME TO WRITE
.FWNAME
DEFB "FILECOPY.BIN"
.END_FWNAME

.TWO_K_BUFFER DEFS 2048

And maybe would be a good idea to place it in programming source codes too , for everyone want to use it! :)
« Last Edit: 13:52, 27 June 18 by ikonsgr »