Added start of csave command and bios write block

This commit is contained in:
Joppe Blondel
2026-10-09 16:13:50 +02:00
parent c84b3fdc97
commit a34ad82444
4 changed files with 296 additions and 3 deletions
+111 -1
View File
@@ -427,7 +427,7 @@ WORDTB: .WORD PEND
.WORD LIST .WORD LIST
.WORD CLEAR .WORD CLEAR
.WORD CLOAD .WORD CLOAD
.WORD FCERR ; csave .WORD CSAVE
.WORD NEW .WORD NEW
; RESERVED WORD TOKEN VALUES ; RESERVED WORD TOKEN VALUES
@@ -4772,4 +4772,114 @@ CLNOHDRMSG: .db "HE", 0ah,0dh,00h
CLBLOCKSMSG: .db " blocks", 0ah,0dh,00h CLBLOCKSMSG: .db " blocks", 0ah,0dh,00h
CLCLRF: .db 0ah,0dh,00h CLCLRF: .db 0ah,0dh,00h
CSAVE: ld a,(hl) ; get byte after "CSAVE"
cp ZTIMES ; "*" token? ("CSAVE*")
jp z,FCERR ; yes - array load (ARRLD1)
cp ZPRINT ; "?" ("PRINT token") verify
jp z,FCERR ; yes - flag "verify"
cp '#' ; 'csave#'?
jp z,CSAVEB ; yes - save binary
; just cload - load basic
jp FCERR
CSAVEB: inc hl ; skip #
push bc ; save bc
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
call GETSTR
call LOADFP ; bc' = addr, e' = length
exx
pop hl ; get back command buffer pos
pop bc ; get length
pop de ; get start address
push hl
push de
call BIOS_CAS_GET_BUFFER
; hl=buffer, bc=lenght, de=start address
; Write header block
ld a,1 ; block type header
ld (hl),a
inc hl
call BYTESTOBLOCKS
push bc
ld a,b ; nr of blocks low byte
ld (hl),a
inc hl
ld a,c ; nr of blocks high byte
ld (hl),a
inc hl
push hl
exx
1$: push bc
pop hl ; get str addr to hl
ld a,(hl)
inc hl
push hl
pop bc ; get str addr+1 back into bc
pop hl ; get hl to hl'
ld (hl),a ; save character to buffer
inc hl
push hl
dec e ; count down str len
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
pop bc ; get back block count
pop de ; get back start address
pop hl
pop de
pop bc
ret
; -------------------------------------------------------
; Convert byte count to required number of 128-byte blocks
; needs bc (length in bytes)
; returns bc (number of blocks)
; uses a
; -------------------------------------------------------
BYTESTOBLOCKS:
ld a,c
and 07fh ; remember partial-block remainder
srl b ; BC = BC / 128
rr c
srl b
rr c
srl b
rr c
srl b
rr c
srl b
rr c
srl b
rr c
srl b
rr c
or a
ret z ; exact multiple of 128
inc bc ; include partial final block
ret
.end .end
+28 -1
View File
@@ -106,6 +106,12 @@ boot_copy:
jp wait_silence jp wait_silence
.ORG BIOS_CAS_READ_BLOCK_DRY .ORG BIOS_CAS_READ_BLOCK_DRY
jp read_block_dry jp read_block_dry
.ORG BIOS_CAS_GET_BUFFER
jp get_buffer
.ORG BIOS_CAS_WRITE_BLOCK
jp write_block
.ORG BIOS_DELAY_MS
jp delay_ms
; ------------------------------------------------------- ; -------------------------------------------------------
; BIOS ENTRY ; BIOS ENTRY
@@ -528,6 +534,27 @@ bank:
out (SYSTEM_REGISTER),a out (SYSTEM_REGISTER),a
jr 2$ jr 2$
; -------------------------------------------------------
; Delay a certain miliseconds
; needs a (ms, zero returns immediately)
; uses b,c
; @1MHz each iteration takes 1000T plus 23T overhead
; -------------------------------------------------------
delay_ms:
or a ; 4T
ret z ; 5T when not taken
ld b,a ; 4T
1$:
ld c,61 ; 7T
2$:
dec c ; 4T
jr nz,2$ ; 12/7T, loop takes 971T
nop ; 4T
nop ; 4T
dec b ; 4T
jp nz,1$ ; 10T
ret
; ------------------------------------------------------- ; -------------------------------------------------------
; Strings ; Strings
; ------------------------------------------------------- ; -------------------------------------------------------
@@ -536,4 +563,4 @@ msg_header: .db "BIOS v1.0 - Joppe Blondel",00dh,00ah,000h
; ------------------------------------------------------- ; -------------------------------------------------------
; Other files ; Other files
; ------------------------------------------------------- ; -------------------------------------------------------
#include "tape.asm" #include "tape.asm"
+4 -1
View File
@@ -7,4 +7,7 @@ BIOS_ROM .equ 0c05fh
BIOS_BANK .equ 0c062h BIOS_BANK .equ 0c062h
BIOS_CAS_READ_BLOCK .equ 0c065h BIOS_CAS_READ_BLOCK .equ 0c065h
BIOS_CAS_WAIT_SILENCE .equ 0c068h BIOS_CAS_WAIT_SILENCE .equ 0c068h
BIOS_CAS_READ_BLOCK_DRY .equ 0c06bh BIOS_CAS_READ_BLOCK_DRY .equ 0c06bh
BIOS_CAS_GET_BUFFER .equ 0c06eh
BIOS_CAS_WRITE_BLOCK .equ 0c071h
BIOS_DELAY_MS .equ 0c074h
+153
View File
@@ -557,6 +557,159 @@ wait_silence:
ret ret
; ------------------------------------------------------- ; -------------------------------------------------------
; Return the buffer address in hl
; -------------------------------------------------------
get_buffer:
ld hl,BLOCK_BUFFER
ret
; -------------------------------------------------------
; Generate a short pulse halve
; needs d (output state)
; uses a
; before edge 20T
; after edge 402T
; -------------------------------------------------------
gen_short:
ld a,d ; 4T
xor 1 ; 7T
out (TAPE_PORT),a ; 12T
ld d,a ; 4T
ld a,18 ; 7T
1$: ; loop: 21*a
dec a ; 4T
cp 0 ; 7T
jp nz,1$ ; 10T
ret ; 10T
; -------------------------------------------------------
; Generate a long pulse
; needs d (output state)
; uses a
; before edge 20T
; after edge 801T
; -------------------------------------------------------
gen_long:
ld a,d ; 4T
xor 1 ; 7T
out (TAPE_PORT),a ; 12T
ld d,a ; 4T
ld a,37 ; 7T
1$: ; loop: 21*a
dec a ; 4T
cp 0 ; 7T
jp nz,1$ ; 10T
ret ; 10T
; -------------------------------------------------------
; Generate a bit
; needs carry (bit value)
; needs d (output state)
; uses a
; -------------------------------------------------------
gen_bit:
jr c,1$ ; carry set: generate a one
call gen_short ; zero: short, then long
jp gen_long ; tail call returns to caller
1$:
call gen_long ; one: long, then short
jp gen_short ; tail call returns to caller
; -------------------------------------------------------
; Generate a byte
; needs a (byte to generate)
; needs d (output state)
; uses a,b,c
; -------------------------------------------------------
gen_byte:
ld c,a ; preserve the byte
ld b,8 ; 8 bits
1$:
sla c ;shift bit 7 into carry
call gen_bit
djnz 1$ ; repeat till b=0
ret
; -------------------------------------------------------
; Generate the leader
; needs d (output state)
; uses a,b,c
; -------------------------------------------------------
gen_leader:
; short leader
ld b,50 ; generate 50 short pulses
1$:
call gen_short
dec b
ld a,b
cp 0
jr nz,1$ ; repeat if not done
; long leader
ld b,50 ; generate 50 long pulses
2$:
call gen_long
dec b
ld a,b
cp 0
jr nz,2$ ; repeat if not done
; marker
ld b,8 ; generate 8 short pulses
3$:
call gen_short
dec b
ld a,b
cp 0
jr nz,3$ ; repeat if not done
; training byte
ld a,055h
call gen_byte
ret
; -------------------------------------------------------
; Write a block
; Writes the block stored in the block buffer
; -------------------------------------------------------
write_block:
push de
push bc
; calculate the crc16 over the block
ld hl, BLOCK_BUFFER
ld a, BLOCK_SIZE-2 ; dont use crc value in block
call crc16
ex de,hl
ld hl, BLOCK_BUFFER+BLOCK_SIZE-2
ld (hl),de ; save crc to block
; Write the block
ld a,0 ; Start with a low output
ld d,a
out (TAPE_PORT),a
call gen_leader
; Generate synchronization bytes
ld a,05ah
call gen_byte
ld a,0c3h
call gen_byte
; write the block buffer
ld hl, BLOCK_BUFFER
ld e, BLOCK_SIZE
1$:
ld a,(hl) ; get byte from buffer
inc hl
call gen_byte
dec e
ld a,e
cp 0
jr nz,1$ ; repeat till done
; Done with buffer, write 0 byte at last
ld a,0
call gen_byte
; Generate space
ld a,200
call delay_ms
pop bc
pop de
ret
; -------------------------------------------------------
; Strings ; Strings
; ------------------------------------------------------- ; -------------------------------------------------------
msg_start: .db "PLAY TAPE", 0ah,0dh,00h msg_start: .db "PLAY TAPE", 0ah,0dh,00h