Last active
August 18, 2021 18:31
-
-
Save mistificator/2692b23c17166ce16e2000f942645aca to your computer and use it in GitHub Desktop.
ZX Spectrum demo tape loader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; | |
; Demo tape loader by Mist Poryvaev. | |
; | |
; Loads two-section tape: e.g. BASIC loader and one code block. | |
; Look the .TAP file image at location 0x9000. | |
; | |
; start in non-contended memory, or tape input latency will be unpredictable | |
org 0x8000 | |
di | |
restart: | |
ld sp, stack | |
ld bc, msg_start_tape | |
call print_str | |
ld ix, values ; start loading address | |
call wait_pilot ; wait pilot and load header | |
ld bc, 19 | |
ld (ix + 0), c | |
inc ix | |
ld (ix + 0), b | |
inc ix | |
call read_block | |
jp nz, checksum_error | |
call wait_pilot ; wait pilot and load data block | |
ld c, (ix - 7) | |
ld b, (ix - 6) ; get code block size from header | |
inc bc | |
inc bc | |
ld (ix + 0), c | |
inc ix | |
ld (ix + 0), b | |
inc ix | |
call read_block | |
jp nz, checksum_error | |
call wait_pilot ; wait pilot and load another header | |
ld bc, 19 | |
ld (ix + 0), c | |
inc ix | |
ld (ix + 0), b | |
inc ix | |
call read_block | |
jp nz, checksum_error | |
call wait_pilot ; wait pilot and load data another block | |
ld c, (ix - 7) | |
ld b, (ix - 6) ; get code block size from header | |
inc bc | |
inc bc | |
ld (ix + 0), c | |
inc ix | |
ld (ix + 0), b | |
inc ix | |
call read_block | |
jp nz, checksum_error | |
ld bc, msg_all_loaded | |
call print_str | |
halt ; check memory in debugger at 0x9000 now, it contains well-formed .TAP file | |
jp restart | |
checksum_error: ; rotate border colors forever | |
inc a | |
and 0x07 | |
out (0xFE), a | |
jr checksum_error | |
read_block: ; in: bc - count, ix - start address, l - PWM threshold | |
ld h, 0 ; checksum | |
read_block_loop: | |
push bc | |
call read_byte | |
ld a, (ix + 0) | |
xor h | |
ld h, a ; update checksum | |
inc ix | |
pop bc | |
dec bc | |
ld a, b | |
or c | |
jr nz, read_block_loop | |
ld a, h | |
or a ; check checksum | |
ret | |
read_byte: ; in: l - PWM threshold, ix - address | |
xor a | |
ld (ix + 0), a ; reset byte value | |
ld b, 8 | |
loop_8_bit: | |
ld a, e | |
and 0x05 | |
out (0xFE), a ; set crazy border colors | |
call get_bit_length | |
ld c, e | |
call get_bit_length | |
ld a, e | |
add a, c | |
srl a ; a = (e + c) / 2 - kind of average bit length | |
cp l ; compare average length with PWM threshold | |
jr c, set_0 | |
set_1: | |
set 7, (ix + 0) | |
set_0: | |
rlc (ix + 0) | |
djnz loop_8_bit | |
ret | |
wait_pilot: ; out: l - detected PWM threshold | |
push bc | |
call wait_for_start | |
ld l, e | |
ld bc, 1000 ; detect leader minimum 1000 times (I think this will be enough) | |
wait_pilot_loop: | |
push bc | |
call get_bit_length | |
ld a, l | |
add a, e | |
srl a ; (length + prev_length) / 2 | |
ld l, a ; store leader PWM threshold | |
pop bc | |
dec bc | |
ld a, b | |
or c | |
jr nz, wait_pilot_loop | |
wait_leader_tail: | |
call get_bit_length ; look for sync-1 | |
ld a, e | |
sll a | |
cp l ; (2 x sync1) will be under PWM threshold | |
jr nc, wait_leader_tail | |
ld l, a ; update PWM threshold to (2 x sync1) | |
call get_bit_length ; get sync2 | |
pop bc | |
ret | |
wait_for_start: ; out: d - initial value | |
ld a, 0x7F | |
in a, (0xFE) ; initial read | |
and 0x41 | |
ld d, a | |
get_bit_length: ; in: d - initial value, out: e - bit length, d - new initial value | |
ld e, 0 | |
loop_bit: | |
inc e | |
ld a, 0x7F | |
in a, (0xFE) | |
and 0x41 | |
cp d | |
jr z, loop_bit | |
bit 0, a | |
jr z, space_key_pressed | |
ld d, a | |
ret | |
space_key_pressed: | |
ld bc, msg_loading_is_stopped | |
call print_str | |
halt | |
jp restart | |
print_str: ; in: bc - string address | |
ld a, (bc) | |
or a | |
ret z | |
push bc | |
call 0x09F4 ; "print-out" | |
pop bc | |
inc bc | |
jr print_str | |
defs 32 | |
stack: | |
msg_start_tape defb "Start the tape", 0x0D, 0 | |
msg_all_loaded defb "Tape is loaded, check memory at 0x9000", 0x0D, 0 | |
msg_loading_is_stopped defb "Loading is stopped", 0x0D, 0 | |
org 0x9000 | |
values: | |
END 0x8000 |
Author
mistificator
commented
Aug 15, 2021
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment