basic loading and saving
This commit is contained in:
+339
-173
@@ -4616,6 +4616,14 @@ FULLSETTOP:
|
|||||||
FULLMSG:
|
FULLMSG:
|
||||||
.BYTE "[FULL MEMORY]",CR,LF,0,0
|
.BYTE "[FULL MEMORY]",CR,LF,0,0
|
||||||
|
|
||||||
|
; Every tape block starts with a type byte followed by 128 data bytes.
|
||||||
|
; Header data contains a little-endian block count, byte length and filename.
|
||||||
|
TAPE_TYPE_RAW .equ 0
|
||||||
|
TAPE_TYPE_BINARY .equ 1
|
||||||
|
TAPE_TYPE_BAS_PROG .equ 2
|
||||||
|
TAPE_TYPE_BAS_ARR .equ 3
|
||||||
|
TAPE_DATA_SIZE .equ 128
|
||||||
|
|
||||||
CLOAD: ld a,(hl) ; get byte after "CLOAD"
|
CLOAD: ld a,(hl) ; get byte after "CLOAD"
|
||||||
cp ZTIMES ; "*" token? ("CLOAD*")
|
cp ZTIMES ; "*" token? ("CLOAD*")
|
||||||
jp z,FCERR ; yes - array load (ARRLD1)
|
jp z,FCERR ; yes - array load (ARRLD1)
|
||||||
@@ -4624,8 +4632,54 @@ CLOAD: ld a,(hl) ; get byte after "CLOAD"
|
|||||||
cp '#' ; 'cload#'?
|
cp '#' ; 'cload#'?
|
||||||
jp z,CLOADB ; yes - load binary
|
jp z,CLOADB ; yes - load binary
|
||||||
; just cload - load basic
|
; just cload - load basic
|
||||||
jp FCERR
|
or a ; no arguments allowed
|
||||||
|
jp nz,FCERR
|
||||||
|
ld hl,CLSTARTMSG ; ask the user to start the tape
|
||||||
|
call PRS ; print the prompt
|
||||||
|
ld b,TAPE_TYPE_BAS_PROG ; expect a BASIC program header
|
||||||
|
call CLREADHEADER ; bc = blocks, de = length, hl = filename
|
||||||
|
call CLPRINTHEADER ; print block count and filename
|
||||||
|
ld b,d ; move exact length to bc
|
||||||
|
ld c,e ; bc = exact program length
|
||||||
|
ld a,b ; check the high byte of the length
|
||||||
|
or a ; 256 bytes or more is always valid here
|
||||||
|
jr nz,1$ ; skip the minimum-length check
|
||||||
|
ld a,c ; check a short program's low byte
|
||||||
|
cp 2 ; an empty program still has its end marker
|
||||||
|
jp c,FCERR ; less than two bytes is not a program
|
||||||
|
1$: ld hl,(BASTXT) ; get the program load address
|
||||||
|
add hl,bc ; calculate the exact program end
|
||||||
|
jp c,OMERR ; reject a wrapped end address
|
||||||
|
ld de,40 ; keep BASIC's minimum working space free
|
||||||
|
add hl,de ; include the working-space margin
|
||||||
|
jp c,OMERR ; reject a wrapped limit address
|
||||||
|
ld de,(STRSPC) ; get the bottom of string/stack space
|
||||||
|
call CPDEHL ; compare required memory with available RAM
|
||||||
|
jp nc,OMERR ; program would enter BASIC's working area
|
||||||
|
ld hl,(BASTXT) ; calculate the exact end once more
|
||||||
|
add hl,bc ; hl = address following the program
|
||||||
|
push hl ; preserve exact program end
|
||||||
|
ld de,(BASTXT) ; load the program at the BASIC text area
|
||||||
|
call CLLOADBLOCKS ; copy only the exact number of bytes
|
||||||
|
pop hl ; restore the exact program end
|
||||||
|
dec hl ; point to the last program byte
|
||||||
|
ld a,(hl) ; get the last end-marker byte
|
||||||
|
or a ; it must be zero
|
||||||
|
jp nz,FCERR ; reject an invalid program terminator
|
||||||
|
dec hl ; point to the first end-marker byte
|
||||||
|
ld a,(hl) ; get the first end-marker byte
|
||||||
|
or a ; it must also be zero
|
||||||
|
jp nz,FCERR ; reject an invalid program terminator
|
||||||
|
push hl
|
||||||
|
ld hl,CLCLRF ; print newline
|
||||||
|
call PRS
|
||||||
|
ld hl,OKMSG
|
||||||
|
call PRS ; print ok message
|
||||||
|
pop hl
|
||||||
|
inc hl ; restore the address after the program
|
||||||
|
inc hl
|
||||||
|
ld (PROGND),hl ; install the new program end
|
||||||
|
jp SETPTR ; clear variables, relink and return to prompt
|
||||||
CLOADB: inc hl ; skip #
|
CLOADB: inc hl ; skip #
|
||||||
call GETNUM ; evaluate numeric expression
|
call GETNUM ; evaluate numeric expression
|
||||||
call DEINT ; convert FPREG to de
|
call DEINT ; convert FPREG to de
|
||||||
@@ -4634,71 +4688,124 @@ CLOADB: inc hl ; skip #
|
|||||||
push hl
|
push hl
|
||||||
push bc
|
push bc
|
||||||
push de
|
push de
|
||||||
|
|
||||||
ld hl,CLSTARTMSG
|
ld hl,CLSTARTMSG
|
||||||
call PRS
|
call PRS
|
||||||
|
ld b,TAPE_TYPE_BINARY
|
||||||
; Load block
|
call CLREADHEADER ; bc = blocks, de = length, hl = filename
|
||||||
call CLREADBLOCK
|
call CLPRINTHEADER
|
||||||
; hl contains block, check block type
|
ld b,d
|
||||||
ld a,(hl)
|
ld c,e ; bc = exact file length
|
||||||
cp 1 ; first block needs to be a header
|
pop de ; destination address
|
||||||
jp nz,CLNOHDR ; First block is not a header
|
call CLLOADBLOCKS
|
||||||
; first block is a header, get nr of blocks
|
|
||||||
inc hl
|
|
||||||
ld de,(hl)
|
|
||||||
; print number of blocks to load
|
|
||||||
push de
|
|
||||||
push hl
|
|
||||||
ex de,hl
|
|
||||||
call PRNTHL
|
|
||||||
ld hl,CLBLOCKSMSG
|
|
||||||
call PRS
|
|
||||||
pop hl
|
|
||||||
inc hl
|
|
||||||
inc hl ; get filename
|
|
||||||
; TODO filename always null terminated?
|
|
||||||
call PRS ; print filename
|
|
||||||
; de contains the nr of blocks to load
|
|
||||||
; TODO check de>0
|
|
||||||
pop de
|
|
||||||
1$: push de ; save repeat counter
|
|
||||||
call CLREADBLOCK ; hl = new data
|
|
||||||
; TODO check block type
|
|
||||||
inc hl ; goto start of data
|
|
||||||
pop de ; get repeat counter
|
|
||||||
push hl ; save stored data
|
|
||||||
exx
|
|
||||||
pop hl ; get stored data back
|
|
||||||
pop de ; get destination
|
|
||||||
ld bc,128 ; block size
|
|
||||||
ldir ; copy data to memory
|
|
||||||
push de ; store destination address
|
|
||||||
exx
|
|
||||||
dec de
|
|
||||||
ld a,e
|
|
||||||
cp 0
|
|
||||||
jr nz,1$ ; repeat if not done yet
|
|
||||||
ld a,d
|
|
||||||
cp 0
|
|
||||||
jr nz,1$ ; repeat if not done yet
|
|
||||||
pop de
|
|
||||||
pop bc
|
pop bc
|
||||||
pop hl
|
pop hl
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
; -------------------------------------------------------
|
||||||
|
; Read and decode a tape header
|
||||||
|
; needs b (type of header to expect)
|
||||||
|
; returns bc (number of following blocks), de (byte length), hl (filename)
|
||||||
|
; errors do not return
|
||||||
|
; uses a
|
||||||
|
; -------------------------------------------------------
|
||||||
|
CLREADHEADER:
|
||||||
|
push bc
|
||||||
|
call CLREADBLOCK
|
||||||
|
ld a,(hl)
|
||||||
|
pop bc
|
||||||
|
cp b
|
||||||
|
jp nz,CLNOHDR
|
||||||
|
inc hl
|
||||||
|
ld c,(hl) ; block count is little-endian
|
||||||
|
inc hl
|
||||||
|
ld b,(hl)
|
||||||
|
inc hl
|
||||||
|
ld e,(hl) ; byte length is little-endian
|
||||||
|
inc hl
|
||||||
|
ld d,(hl)
|
||||||
|
inc hl ; point to filename
|
||||||
|
ret
|
||||||
|
|
||||||
|
; -------------------------------------------------------
|
||||||
|
; Print the block count and filename from a tape header
|
||||||
|
; needs bc (number of blocks), hl (filename)
|
||||||
|
; preserves bc,de
|
||||||
|
; uses a,h,l
|
||||||
|
; -------------------------------------------------------
|
||||||
|
CLPRINTHEADER:
|
||||||
|
push bc
|
||||||
|
push de
|
||||||
|
push hl
|
||||||
|
ld h,b
|
||||||
|
ld l,c
|
||||||
|
call PRNTHL
|
||||||
|
ld hl,CLBLOCKSMSG
|
||||||
|
call PRS
|
||||||
|
pop hl
|
||||||
|
call PRS
|
||||||
|
pop de
|
||||||
|
pop bc
|
||||||
|
ret
|
||||||
|
|
||||||
|
; -------------------------------------------------------
|
||||||
|
; Load tape data into memory, including a partial final block
|
||||||
|
; needs bc (file length in bytes), de (destination address)
|
||||||
|
; returns de (first address after loaded data)
|
||||||
|
; returns bc (zero)
|
||||||
|
; uses a,h,l
|
||||||
|
; -------------------------------------------------------
|
||||||
|
CLLOADBLOCKS:
|
||||||
|
ld a,b
|
||||||
|
or c
|
||||||
|
ret z
|
||||||
|
1$: push bc
|
||||||
|
push de
|
||||||
|
call CLREADBLOCK
|
||||||
|
inc hl ; skip block type
|
||||||
|
pop de
|
||||||
|
pop bc ; remaining byte count
|
||||||
|
ld a,b
|
||||||
|
or a
|
||||||
|
jr nz,2$ ; at least 256 bytes remain
|
||||||
|
ld a,c
|
||||||
|
cp TAPE_DATA_SIZE
|
||||||
|
jr nc,2$
|
||||||
|
ldir ; copy the partial final block
|
||||||
|
ret
|
||||||
|
2$: push bc
|
||||||
|
ld bc,TAPE_DATA_SIZE
|
||||||
|
ldir
|
||||||
|
pop bc
|
||||||
|
ld a,c ; subtract one full block
|
||||||
|
sub TAPE_DATA_SIZE
|
||||||
|
ld c,a
|
||||||
|
ld a,b
|
||||||
|
sbc a,0
|
||||||
|
ld b,a
|
||||||
|
jr 1$
|
||||||
|
|
||||||
|
; -------------------------------------------------------
|
||||||
|
; Read one of two redundant copies of a tape block
|
||||||
|
; returns hl (block buffer)
|
||||||
|
; errors do not return
|
||||||
|
; uses a,b,c,d,e,h,l
|
||||||
|
; -------------------------------------------------------
|
||||||
CLREADBLOCK:
|
CLREADBLOCK:
|
||||||
call BIOS_CAS_READ_BLOCK
|
call BIOS_CAS_READ_BLOCK
|
||||||
jr c,3$
|
jr c,3$
|
||||||
|
push hl ; preserve the first copy
|
||||||
ld a,'.' ; block read correctly
|
ld a,'.' ; block read correctly
|
||||||
call OUTC
|
call OUTC
|
||||||
jr 1$
|
ld a,'o' ; skip redundant copy
|
||||||
|
call OUTC
|
||||||
|
call BIOS_CAS_READ_BLOCK_DRY
|
||||||
|
jr 2$
|
||||||
3$: ld a,'x' ; block failed, try redundant block
|
3$: ld a,'x' ; block failed, try redundant block
|
||||||
call OUTC
|
call OUTC
|
||||||
call BIOS_CAS_WAIT_SILENCE
|
call BIOS_CAS_WAIT_SILENCE
|
||||||
call BIOS_CAS_READ_BLOCK
|
call BIOS_CAS_READ_BLOCK
|
||||||
push hl
|
|
||||||
jr c,4$
|
jr c,4$
|
||||||
|
push hl ; preserve the redundant copy
|
||||||
ld a,'.' ; redundant block read correctly
|
ld a,'.' ; redundant block read correctly
|
||||||
call OUTC
|
call OUTC
|
||||||
jr 2$
|
jr 2$
|
||||||
@@ -4710,12 +4817,7 @@ CLREADBLOCK:
|
|||||||
call BIOS_CAS_WAIT_SILENCE
|
call BIOS_CAS_WAIT_SILENCE
|
||||||
pop bc
|
pop bc
|
||||||
pop af
|
pop af
|
||||||
jr CLERR
|
jp CLERR
|
||||||
1$: push hl ; save hl
|
|
||||||
ld a,'o' ; skip redundant block
|
|
||||||
call OUTC
|
|
||||||
call BIOS_CAS_READ_BLOCK_DRY
|
|
||||||
; Ignore errors on this block
|
|
||||||
2$: ; but make sure it is silent again
|
2$: ; but make sure it is silent again
|
||||||
call BIOS_CAS_WAIT_SILENCE
|
call BIOS_CAS_WAIT_SILENCE
|
||||||
pop hl
|
pop hl
|
||||||
@@ -4731,20 +4833,17 @@ CLERR: cp 1
|
|||||||
cp 4
|
cp 4
|
||||||
jr z,CLECHS
|
jr z,CLECHS
|
||||||
jp FCERR ; Unknown error
|
jp FCERR ; Unknown error
|
||||||
CLECAL: ld h,0
|
CLECAL: ld hl,CLECALMSG
|
||||||
ld l,b ; get specific error code
|
jr CLDETAIL
|
||||||
call PRNTHL ; print specific error code
|
CLESYN: ld hl,CLESYNMSG
|
||||||
ld hl, CLECALMSG
|
jr CLDETAIL
|
||||||
jr CLEPRINT
|
CLERED: ld hl,CLEREDMSG
|
||||||
CLESYN: ld h,0
|
CLDETAIL:
|
||||||
ld l,b ; get specific error code
|
push hl
|
||||||
call PRNTHL ; print specific error code
|
ld h,0
|
||||||
ld hl, CLESYNMSG
|
ld l,b ; print specific error code
|
||||||
jr CLEPRINT
|
call PRNTHL
|
||||||
CLERED: ld h,0
|
pop hl
|
||||||
ld l,b ; get specific error code
|
|
||||||
call PRNTHL ; print specific error code
|
|
||||||
ld hl, CLEREDMSG
|
|
||||||
jr CLEPRINT
|
jr CLEPRINT
|
||||||
CLECHS: ld hl,CLECHSMSG
|
CLECHS: ld hl,CLECHSMSG
|
||||||
jr CLEPRINT
|
jr CLEPRINT
|
||||||
@@ -4752,9 +4851,6 @@ CLNOHDR:
|
|||||||
ld hl,CLNOHDRMSG
|
ld hl,CLNOHDRMSG
|
||||||
CLEPRINT:
|
CLEPRINT:
|
||||||
call PRS
|
call PRS
|
||||||
pop de
|
|
||||||
pop bc
|
|
||||||
pop hl
|
|
||||||
jp FCERR
|
jp FCERR
|
||||||
|
|
||||||
CLSTARTMSG: .db "Play tape...",0ah,0dh,00h
|
CLSTARTMSG: .db "Play tape...",0ah,0dh,00h
|
||||||
@@ -4768,123 +4864,193 @@ CLCLRF: .db 0ah,0dh,00h
|
|||||||
|
|
||||||
CSAVE: ld a,(hl) ; get byte after "CSAVE"
|
CSAVE: ld a,(hl) ; get byte after "CSAVE"
|
||||||
cp ZTIMES ; "*" token? ("CSAVE*")
|
cp ZTIMES ; "*" token? ("CSAVE*")
|
||||||
jp z,FCERR ; yes - array load (ARRLD1)
|
jp z,FCERR ; yes - array save
|
||||||
cp ZPRINT ; "?" ("PRINT token") verify
|
cp ZPRINT ; "?" ("PRINT token") verify
|
||||||
jp z,FCERR ; yes - flag "verify"
|
jp z,FCERR ; yes - flag "verify"
|
||||||
cp '#' ; 'csave#'?
|
cp '#' ; 'csave#'?
|
||||||
jp z,CSAVEB ; yes - save binary
|
jp z,CSAVEB ; yes - save binary
|
||||||
; just cload - load basic
|
; just csave - save basic program
|
||||||
jp FCERR
|
CSAVE1: call EVAL ; evaluate filename expression
|
||||||
|
push bc
|
||||||
CSAVEB: inc hl ; skip #
|
push de ; preserve bc and de
|
||||||
push bc ; save bc
|
push hl ; preserve command buffer position
|
||||||
push de ; save de
|
|
||||||
CALL GETNUM ; Get start address
|
|
||||||
CALL DEINT ; Convert it to 16 bits
|
|
||||||
PUSH DE ; Save start address
|
|
||||||
CALL CHKSYN ; Make sure "," follows
|
|
||||||
.BYTE ','
|
|
||||||
CALL GETNUM ; Get length
|
|
||||||
CALL DEINT ; Convert it to 16 bits
|
|
||||||
PUSH DE ; Save length
|
|
||||||
CALL CHKSYN ; Make sure "," follows
|
|
||||||
.BYTE ','
|
|
||||||
; hl points to the first character of the string expression
|
|
||||||
call EVAL
|
|
||||||
push hl ; save command buffer pos
|
|
||||||
exx
|
exx
|
||||||
call GETSTR
|
call GETSTR
|
||||||
call LOADFP ; bc' = addr, e' = length
|
call LOADFP ; bc' = filename, e'=length
|
||||||
exx
|
exx
|
||||||
pop hl ; get back command buffer pos
|
; get the program length
|
||||||
pop bc ; get length
|
ld de,(BASTXT) ; program source address
|
||||||
pop de ; get start address
|
ld hl,(PROGND) ; address after prog mem
|
||||||
push hl
|
or a ; clear carry
|
||||||
|
sbc hl,de ; hl = prog length
|
||||||
|
ld b,h
|
||||||
|
ld c,l ; prog length in bc
|
||||||
|
ld a,TAPE_TYPE_BAS_PROG
|
||||||
|
jp CSOUT ; Write the file to tape
|
||||||
|
CSAVEB: inc hl ; skip #
|
||||||
|
push bc ; save BASIC registers
|
||||||
push de
|
push de
|
||||||
call BIOS_CAS_GET_BUFFER
|
call GETNUM ; get start address
|
||||||
; hl=buffer, bc=lenght, de=start address
|
call DEINT ; convert FPREG to de
|
||||||
; Write header block
|
push de ; save start address
|
||||||
ld a,1 ; block type header
|
call CHKSYN ; require a comma
|
||||||
ld (hl),a
|
.BYTE ','
|
||||||
inc hl
|
call GETNUM ; get length
|
||||||
|
call DEINT ; convert FPREG to de
|
||||||
|
push de ; save length
|
||||||
|
call CHKSYN ; require a comma
|
||||||
|
.BYTE ','
|
||||||
|
call EVAL ; evaluate filename expression
|
||||||
|
push hl ; preserve command buffer position
|
||||||
|
exx
|
||||||
|
call GETSTR
|
||||||
|
call LOADFP ; bc' = filename, e' = length
|
||||||
|
exx
|
||||||
|
pop hl
|
||||||
|
pop bc ; length in bytes
|
||||||
|
pop de ; start address
|
||||||
|
push hl
|
||||||
|
ld a,TAPE_TYPE_BINARY
|
||||||
|
CSOUT: call CSWRITEHEADER ; bc = block count, preserves de
|
||||||
|
call CSWRITEBLOCKS
|
||||||
|
ld hl,CLCLRF
|
||||||
|
call PRS
|
||||||
|
pop hl
|
||||||
|
pop de
|
||||||
|
pop bc
|
||||||
|
ret
|
||||||
|
|
||||||
|
; -------------------------------------------------------
|
||||||
|
; Build and write a header and its redundant copy
|
||||||
|
; needs bc (file length in bytes)
|
||||||
|
; needs bc' (filename address), e' (filename length)
|
||||||
|
; returns bc (number of data blocks)
|
||||||
|
; preserves de
|
||||||
|
; uses a,h,l and the alternate register set
|
||||||
|
; -------------------------------------------------------
|
||||||
|
CSWRITEHEADER:
|
||||||
|
push de
|
||||||
|
push af ; preserve header type
|
||||||
|
push bc ; preserve exact byte length
|
||||||
call BYTESTOBLOCKS
|
call BYTESTOBLOCKS
|
||||||
push bc
|
pop hl ; exact byte length for the header
|
||||||
ld a,c ; nr of blocks low byte
|
pop af
|
||||||
ld (hl),a
|
call CSMAKEHEADER
|
||||||
inc hl
|
push bc ; preserve block count over delay
|
||||||
ld a,b ; nr of blocks high byte
|
call CSWRITEPAIR
|
||||||
ld (hl),a
|
call CSHEADERGAP
|
||||||
inc hl
|
pop bc
|
||||||
push hl
|
pop de
|
||||||
exx
|
ret
|
||||||
1$: push bc
|
|
||||||
pop hl ; get str addr to hl
|
; -------------------------------------------------------
|
||||||
ld a,(hl)
|
; Write consecutive raw data blocks
|
||||||
inc hl
|
; needs bc (number of blocks), de (source address)
|
||||||
push hl
|
; returns bc (zero), de (first address after written data)
|
||||||
pop bc ; get str addr+1 back into bc
|
; uses a,h,l
|
||||||
pop hl ; get hl to hl'
|
; -------------------------------------------------------
|
||||||
ld (hl),a ; save character to buffer
|
CSWRITEBLOCKS:
|
||||||
inc hl
|
|
||||||
push hl
|
|
||||||
dec e ; count down str len
|
|
||||||
ld a,e
|
|
||||||
cp 0
|
|
||||||
jr nz,1$ ; repeat for the whole string
|
|
||||||
exx
|
|
||||||
pop hl ; get back buffer addr
|
|
||||||
ld a,0 ; NULL terminate string
|
|
||||||
ld (hl),a
|
|
||||||
inc hl
|
|
||||||
; Header block complete (rest of block is accepted garbage)
|
|
||||||
call BIOS_CAS_WRITE_BLOCK
|
|
||||||
ld a,'.'
|
|
||||||
call OUTC
|
|
||||||
call BIOS_CAS_WRITE_BLOCK
|
|
||||||
ld a,'.'
|
|
||||||
call OUTC
|
|
||||||
ld a,250
|
|
||||||
call BIOS_DELAY_MS
|
|
||||||
ld a,250
|
|
||||||
call BIOS_DELAY_MS
|
|
||||||
ld a,250
|
|
||||||
call BIOS_DELAY_MS ; add a 750ms delay
|
|
||||||
pop bc ; get back block count
|
|
||||||
pop de ; get back start address
|
|
||||||
ld a,b
|
ld a,b
|
||||||
or c
|
or c
|
||||||
jr z,3$ ; no data blocks for a zero length
|
ret z
|
||||||
2$:
|
1$: push bc
|
||||||
; load data into buffer
|
ld a,TAPE_TYPE_RAW
|
||||||
push bc
|
call CSWRITEDATA
|
||||||
call BIOS_CAS_GET_BUFFER
|
|
||||||
ld bc,128 ; block size
|
|
||||||
ld a,0 ; raw type
|
|
||||||
ld (hl),a
|
|
||||||
inc hl
|
|
||||||
ex de,hl ; hl=src,de=dest
|
|
||||||
ldir ; copy the bytes
|
|
||||||
ex de,hl ; de back to being the src addr
|
|
||||||
call BIOS_CAS_WRITE_BLOCK
|
|
||||||
ld a,'.'
|
|
||||||
call OUTC
|
|
||||||
call BIOS_CAS_WRITE_BLOCK
|
|
||||||
ld a,'.'
|
|
||||||
call OUTC
|
|
||||||
pop bc
|
pop bc
|
||||||
dec bc
|
dec bc
|
||||||
ld a,b
|
ld a,b
|
||||||
or c
|
or c
|
||||||
jr nz,2$ ; repeat if not done
|
jr nz,1$
|
||||||
3$:
|
ret
|
||||||
; All blocks are written
|
|
||||||
|
|
||||||
ld hl,CLCLRF
|
; -------------------------------------------------------
|
||||||
call PRS
|
; Build a header in the tape block buffer
|
||||||
|
; needs bc (number of data blocks)
|
||||||
|
; needs hl (file length in bytes)
|
||||||
|
; needs bc' (filename address), e' (filename length)
|
||||||
|
; needs a (type of header)
|
||||||
|
; preserves bc,de
|
||||||
|
; uses a,h,l and the alternate register set
|
||||||
|
; -------------------------------------------------------
|
||||||
|
CSMAKEHEADER:
|
||||||
|
push de ; preserve data source address
|
||||||
|
push hl ; preserve byte length
|
||||||
|
push af
|
||||||
|
call BIOS_CAS_GET_BUFFER
|
||||||
|
pop af
|
||||||
|
ld (hl),a ; store header type
|
||||||
|
inc hl
|
||||||
|
ld (hl),c ; block count is little-endian
|
||||||
|
inc hl
|
||||||
|
ld (hl),b
|
||||||
|
inc hl
|
||||||
|
pop de ; byte length
|
||||||
|
ld (hl),e ; byte length is little-endian
|
||||||
|
inc hl
|
||||||
|
ld (hl),d
|
||||||
|
inc hl ; filename destination
|
||||||
|
|
||||||
pop hl
|
push bc ; preserve block count
|
||||||
pop de
|
push hl
|
||||||
|
exx
|
||||||
|
ld h,b ; hl = filename source
|
||||||
|
ld l,c
|
||||||
|
ld c,e ; bc = filename length
|
||||||
|
ld b,0
|
||||||
|
pop de ; de = filename destination
|
||||||
|
ld a,b
|
||||||
|
or c
|
||||||
|
jr z,1$
|
||||||
|
ldir
|
||||||
|
1$: xor a
|
||||||
|
ld (de),a ; terminate filename
|
||||||
|
exx
|
||||||
pop bc
|
pop bc
|
||||||
|
pop de ; restore data source address
|
||||||
|
ret
|
||||||
|
|
||||||
|
; -------------------------------------------------------
|
||||||
|
; Copy and write one 128-byte data block
|
||||||
|
; needs a (block type), de (source address)
|
||||||
|
; returns de (source address advanced by 128 bytes)
|
||||||
|
; uses a,b,c,h,l
|
||||||
|
; -------------------------------------------------------
|
||||||
|
CSWRITEDATA:
|
||||||
|
call BIOS_CAS_GET_BUFFER
|
||||||
|
ld (hl),a
|
||||||
|
inc hl
|
||||||
|
ld bc,TAPE_DATA_SIZE
|
||||||
|
ex de,hl ; hl = source, de = buffer
|
||||||
|
ldir
|
||||||
|
ex de,hl ; de = next source address
|
||||||
|
call CSWRITEPAIR
|
||||||
|
ret
|
||||||
|
|
||||||
|
; -------------------------------------------------------
|
||||||
|
; Write the current tape buffer twice and show progress
|
||||||
|
; preserves bc,de,hl
|
||||||
|
; uses a
|
||||||
|
; -------------------------------------------------------
|
||||||
|
CSWRITEPAIR:
|
||||||
|
call BIOS_CAS_WRITE_BLOCK
|
||||||
|
ld a,'.'
|
||||||
|
call OUTC
|
||||||
|
call BIOS_CAS_WRITE_BLOCK
|
||||||
|
ld a,'.'
|
||||||
|
call OUTC
|
||||||
|
ret
|
||||||
|
|
||||||
|
; -------------------------------------------------------
|
||||||
|
; Leave 750 ms between a header pair and its data
|
||||||
|
; uses a,b,c
|
||||||
|
; -------------------------------------------------------
|
||||||
|
CSHEADERGAP:
|
||||||
|
ld a,250
|
||||||
|
call BIOS_DELAY_MS
|
||||||
|
ld a,250
|
||||||
|
call BIOS_DELAY_MS
|
||||||
|
ld a,250
|
||||||
|
call BIOS_DELAY_MS
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; -------------------------------------------------------
|
; -------------------------------------------------------
|
||||||
|
|||||||
+9
-4
@@ -10,7 +10,9 @@ from pathlib import Path
|
|||||||
|
|
||||||
BLOCK_SIZE = 128
|
BLOCK_SIZE = 128
|
||||||
TYPE_RAW = 0
|
TYPE_RAW = 0
|
||||||
TYPE_HEADER = 1
|
TYPE_BINARY = 1
|
||||||
|
TYPE_BAS_PROG = 2
|
||||||
|
TYPE_BAS_ARR = 3
|
||||||
|
|
||||||
def crc16(data: bytes) -> int:
|
def crc16(data: bytes) -> int:
|
||||||
"""Calculate CRC-16/CCITT-FALSE."""
|
"""Calculate CRC-16/CCITT-FALSE."""
|
||||||
@@ -107,9 +109,12 @@ class PulseWriter:
|
|||||||
def header(pulses: PulseWriter, path:Path) -> None:
|
def header(pulses: PulseWriter, path:Path) -> None:
|
||||||
fname = path.name
|
fname = path.name
|
||||||
fsize = os.path.getsize(path)
|
fsize = os.path.getsize(path)
|
||||||
data = struct.pack("<H", math.ceil(fsize/BLOCK_SIZE)) + fname.encode()[:32].ljust(32, b' ')
|
data = (
|
||||||
pulses.block(TYPE_HEADER, data)
|
struct.pack("<HH", math.ceil(fsize/BLOCK_SIZE), fsize)
|
||||||
pulses.block(TYPE_HEADER, data)
|
+ fname.encode()[:32].ljust(32, b' ')
|
||||||
|
)
|
||||||
|
pulses.block(TYPE_BINARY, data)
|
||||||
|
pulses.block(TYPE_BINARY, data)
|
||||||
|
|
||||||
def raw(pulses: PulseWriter, data:bytes) -> None:
|
def raw(pulses: PulseWriter, data:bytes) -> None:
|
||||||
pulses.block(TYPE_RAW, data)
|
pulses.block(TYPE_RAW, data)
|
||||||
|
|||||||
Reference in New Issue
Block a user