305 lines
5.0 KiB
NASM
305 lines
5.0 KiB
NASM
.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
|