.include "bios.inc" .area TAPELOAD (ABS) .org TAPE_LOADER_ROM_ADDRESS TAPE_PORT = 0x18 STACK_TOP = 0xBFFF WORK_BASE = 0xB000 OLD_SP = WORK_BASE + 0x00 ; word OLD_IFF = WORK_BASE + 0x02 ; byte SHORT_LEN = WORK_BASE + 0x03 ; byte LONG_LEN = WORK_BASE + 0x04 ; byte TRESHOLD = WORK_BASE + 0x05 ; byte SHORT_COUNT = WORK_BASE + 0x06 ; byte LONG_COUNT = WORK_BASE + 0x07 ; byte ; #################################################3 ; Entry ; #################################################3 tape_loader: ld (OLD_SP),sp ; Save interrupt state. ld a,i jp po,iff_was_off ld a,#1 jr save_iff iff_was_off: xor a save_iff: ld (OLD_IFF),a di ld sp,#STACK_TOP ; Initial message. ld hl,#msg_start call print_with_irqs ; Calibrate receiver call calibrate ; Print parameters ei ld hl,#msg_short_len call print_string ld a,(SHORT_LEN) call print_hex8 call print_crlf ld hl,#msg_long_len call print_string ld a,(LONG_LEN) call print_hex8 call print_crlf ld hl,#msg_treshold call print_string ld a,(TRESHOLD) call print_hex8 call print_crlf ld hl,#msg_short_count call print_string ld a,(SHORT_COUNT) call print_hex8 call print_crlf ld hl,#msg_long_count call print_string ld a,(LONG_COUNT) call print_hex8 call print_crlf call BIOS_FLUSH di ; #################################################3 ; Exit ; #################################################3 exit: di ld sp,(OLD_SP) ; Return code 0 ld a,#0 ld c,a ; Restore caller's interrupt state. ld a,(OLD_IFF) or a ld a,c jr z,return_di ei ret return_di: ret ; #################################################3 ; Wait for next edge ; D holds current comparator state ; Returns B = loop count ; #################################################3 wait_edge: ld b,#0 1$: inc b in a,(TAPE_PORT) cp a,d jr z,1$ ld d,a ret ; #################################################3 ; Wait for a full cycle ; D holds the current comparator state ; Returns B = loop count ; #################################################3 wait_cycle: ld b,#0 1$: inc b in a,(TAPE_PORT) cp a,d jp z,1$ ld d,a 2$: inc b in a,(TAPE_PORT) cp a,d jp z,2$ ld d,a ret ; #################################################3 ; Average 16 cycle intervals ; Returns A = average loop count ; preserves bc ; #################################################3 average16: push bc ld c,#16 ld e,#0 1$: call wait_cycle ; Add loop count to e and take moving average ld a,e add a,b srl a ld e,a dec c jr nz,1$ ld a,e pop bc ret ; #################################################3 ; #################################################3 calibrate: ; establish comparator state in a,(TAPE_PORT) ld d,a ; Wait for the first edge call wait_edge ; Measure shoft pulses call average16 ld (SHORT_LEN), a ; Threshold for finding long pulse -> short*1.5 ; stored in c ld c,a srl a add a,c ld c,a ; Wait for the first long pulse 1$: call average16 cp a,c jr c,1$ ; Measure long pulses call average16 ld (LONG_LEN), a ; Calculate period treshold ld b,a ld a,(SHORT_LEN) ; Average between the two lengths add a,b srl a ld (TRESHOLD),a ; Wait for first short for training ld c,a 3$: call wait_cycle ld a,b cp a,c jr nc,3$ ; Count short cycles ld e,#1 4$: call wait_cycle ld a,b cp a,c jr nc,5$ inc e jr 4$ 5$: ld a,e ld (SHORT_COUNT),a ; Count long cycles ld e,#1 6$: call wait_cycle ld a,b cp a,c jr c,7$ inc e jr 6$ 7$: ld a,e ld (LONG_COUNT),a ret ; #################################################3 ; IO Helper functions ; #################################################3 print_with_irqs: ei call print_string call BIOS_FLUSH di ret print_string: ld a,(hl) or a ret z call BIOS_PUTC inc hl jr print_string print_crlf: ld a,#13 call BIOS_PUTC ld a,#10 jp BIOS_PUTC print_hex8: push af rrca rrca rrca rrca and #0x0F call print_hex_nibble pop af and #0x0F ; fall through print_hex_nibble: cp #10 jr c,print_hex_digit add a,#('A' - 10) jp BIOS_PUTC print_hex_digit: add a,#'0' jp BIOS_PUTC ; #################################################3 ; Strings ; #################################################3 msg_start: .ascii "TAPE DECODE TEST - PLAY TAPE" .db 13,10,0 msg_short_len: .ascii "Short len: " .db 0 msg_long_len: .ascii "Long len: " .db 0 msg_treshold: .ascii "Treshold: " .db 0 msg_short_count: .ascii "Short count: " .db 0 msg_long_count: .ascii "Long count: " .db 0