Added old tape routines and started with cload
This commit is contained in:
@@ -0,0 +1,530 @@
|
||||
BLOCK_SIZE .equ 1+64+2 ; type + 64 bytes + crc-16
|
||||
BLOCK_ERROR_CALIBRATION .equ 1
|
||||
BLOCK_ERROR_SYNC .equ 2
|
||||
BLOCK_ERROR_READ .equ 3
|
||||
BLOCK_ERROR_CHSUM .equ 4
|
||||
|
||||
TAPE_WORKSPACE .equ END_OF_BIOS_WS
|
||||
SHORT_AVG .equ TAPE_WORKSPACE + 000h ; byte
|
||||
SHORT_MIN .equ TAPE_WORKSPACE + 001h ; byte
|
||||
SHORT_MAX .equ TAPE_WORKSPACE + 002h ; byte
|
||||
LONG_AVG .equ TAPE_WORKSPACE + 003h ; byte
|
||||
LONG_MIN .equ TAPE_WORKSPACE + 004h ; byte
|
||||
LONG_MAX .equ TAPE_WORKSPACE + 005h ; byte
|
||||
BLOCK_BUFFER .equ TAPE_WORKSPACE + 006h ; BLOCK_SIZE
|
||||
|
||||
; -------------------------------------------------------
|
||||
; Measure edge-to-edge pulse
|
||||
; needs d (comparator state)
|
||||
; returns b (loop count)
|
||||
; carry is timeout
|
||||
; uses a
|
||||
; loop is 36T extra 22T (0.6 loops)
|
||||
; -------------------------------------------------------
|
||||
measure_pulse:
|
||||
ld b,0 ; 4T
|
||||
1$:
|
||||
; use b as timeout counter (246 loops)
|
||||
inc b ; 4T
|
||||
jr z,9$ ; 12/7T
|
||||
in a,(TAPE_PORT) ; 11T
|
||||
cp d ; 4T
|
||||
jp z,1$ ; 10T
|
||||
; loop has 36T
|
||||
; edge found
|
||||
ld d,a ; 4T
|
||||
or a ; 4T, clear carry
|
||||
ret ; 10T
|
||||
9$:
|
||||
scf
|
||||
ret
|
||||
|
||||
; -------------------------------------------------------
|
||||
; Ignore one pulse and then measure the next
|
||||
; needs d (comparator state)
|
||||
; returns b (loop count)
|
||||
; carry is timeout
|
||||
; uses a
|
||||
; loop is 36T extra 26T (0.7 loops)
|
||||
; -------------------------------------------------------
|
||||
sample_pulse:
|
||||
ld b,0 ; 4T
|
||||
1$:
|
||||
; use b as timeout counter (246 loops)
|
||||
inc b ; 4T
|
||||
jr z,9$ ; 12/7T
|
||||
in a,(TAPE_PORT) ; 11T
|
||||
cp d ; 4T
|
||||
jp z,1$ ; 10T
|
||||
; loop has 36T
|
||||
; edge found
|
||||
ld d,a ; 4T
|
||||
; start timing from now
|
||||
ld b,0 ; 4T
|
||||
2$:
|
||||
; use b as timeout counter (246 loops)
|
||||
inc b ; 4T
|
||||
jr z,9$ ; 12/7T
|
||||
in a,(TAPE_PORT) ; 11T
|
||||
cp d ; 4T
|
||||
jp z,2$ ; 10T
|
||||
; loop has 36T
|
||||
; edge found
|
||||
ld d,a ; 4T
|
||||
or a ; 4T, clear carry
|
||||
ret
|
||||
9$:
|
||||
scf
|
||||
ret
|
||||
|
||||
; -------------------------------------------------------
|
||||
; Average 8 pulse measurements
|
||||
; needs d (comparator state)
|
||||
; returns a (average)
|
||||
; cary is timeout
|
||||
; uses b,e,h
|
||||
; -------------------------------------------------------
|
||||
average8:
|
||||
ld e,0
|
||||
ld h,8
|
||||
1$:
|
||||
; synchronize to next pulse and ignore measurement
|
||||
call sample_pulse
|
||||
ret c ; return when timeout
|
||||
call sample_pulse
|
||||
ret c ; return when timeout
|
||||
ld a,e ; add loop count to e
|
||||
add b
|
||||
ld e,a
|
||||
dec h
|
||||
jr nz,1$ ; repeat this 8 times
|
||||
ld a,e
|
||||
srl a
|
||||
srl a
|
||||
srl a ; divide by 8
|
||||
or a ; cear carry
|
||||
ret
|
||||
|
||||
; -------------------------------------------------------
|
||||
; Make a +/-25% window around a
|
||||
; needs a
|
||||
; returns b (minimum) c (maximum)
|
||||
; uses e,h
|
||||
; NOTE: USES 8 BIT COUNTER
|
||||
; @1MHZ t_long<1.14ms
|
||||
; @2MHZ t_long<571us
|
||||
; @4MHZ t_long<285us
|
||||
; TODO: Check feasibility of using 16bit accumulator
|
||||
; -------------------------------------------------------
|
||||
make_window:
|
||||
ld e,a
|
||||
srl a
|
||||
srl a
|
||||
ld h,a ; h = a/4
|
||||
ld a,e
|
||||
sub h
|
||||
ld b,a ; b = a-25%
|
||||
ld a,e
|
||||
add h
|
||||
ld c,a ; c = a+25%
|
||||
ret
|
||||
|
||||
; -------------------------------------------------------
|
||||
; Calibration
|
||||
; d needs to be kept from now on
|
||||
; uses a,b,c,e,h,l
|
||||
; carry is error
|
||||
; -------------------------------------------------------
|
||||
calibrate:
|
||||
ld a,(TAPE_PORT) ; get current state
|
||||
ld d,a
|
||||
call sample_pulse ; make sure we start in silence
|
||||
jp nc,cal_err ; should timeout
|
||||
; wait for the first edge
|
||||
ld l,0
|
||||
1$:
|
||||
call sample_pulse
|
||||
jr nc,2$
|
||||
; use l as timout counter
|
||||
; inc l
|
||||
; jr nx,1$
|
||||
jr 1$
|
||||
; timeout
|
||||
jp cal_err ; TODO ignored timeout for now
|
||||
2$:
|
||||
; edge found
|
||||
; get short leader timing
|
||||
call average8
|
||||
jr c,cal_err ; timeout
|
||||
ld (SHORT_AVG),a
|
||||
call make_window
|
||||
ld a,b
|
||||
ld (SHORT_MIN),a
|
||||
ld a,c
|
||||
ld (SHORT_MAX),a
|
||||
; find the long leader
|
||||
; need 8 consecutive pulses > short*1.5
|
||||
ld a,(SHORT_AVG)
|
||||
ld c,a
|
||||
srl a
|
||||
add c ; a = 1.5*short
|
||||
ld c,a
|
||||
; TODO no overall timeout here
|
||||
3$:
|
||||
ld e,4 ; repeat 4 times, each first pulse
|
||||
; is ignored
|
||||
4$:
|
||||
call sample_pulse
|
||||
jr c,cal_err
|
||||
call sample_pulse
|
||||
jr c,cal_err
|
||||
ld a,b
|
||||
; try again if its a short pulse
|
||||
cp c
|
||||
jr c,3$
|
||||
; we found a long pulse
|
||||
dec e
|
||||
jr nz,4$ ; repeat this 4 times
|
||||
; long leader found
|
||||
call average8
|
||||
jr c,cal_err ; timeout
|
||||
ld (LONG_AVG),a
|
||||
call make_window
|
||||
ld a,b
|
||||
ld (LONG_MIN),a
|
||||
ld a,c
|
||||
ld (LONG_MAX),a
|
||||
; A quick sanity check: long>1.5*short
|
||||
ld a,(SHORT_AVG)
|
||||
ld c,a
|
||||
srl a
|
||||
add c
|
||||
ld c,a ; c = 1.5*short
|
||||
ld a,(LONG_AVG)
|
||||
cp c
|
||||
jr c,cal_err
|
||||
; Find the marker. marker is 2*long
|
||||
; threshold is 1.5*long
|
||||
ld a,(LONG_AVG)
|
||||
ld c,a
|
||||
srl a
|
||||
add c
|
||||
ld c,a ; c = 1.5*long
|
||||
; Find two consecutive marker-width intervals
|
||||
5$:
|
||||
ld e,0
|
||||
6$:
|
||||
call measure_pulse
|
||||
jr c,cal_err ; timeout
|
||||
ld a,b
|
||||
cp c
|
||||
jr c,5$ ; not a marker
|
||||
inc e ; marker interval found
|
||||
ld a,e
|
||||
cp 2 ; we need two of them
|
||||
jr c,6$ ; not 2 yet, measure next
|
||||
; both marker halves found
|
||||
; we are at the beginning of the first data pulse
|
||||
; next 8 bytes is the training byte 0x55
|
||||
call read_byte
|
||||
jr c,cal_err
|
||||
cp a,055h
|
||||
jr nz,cal_err ; training byte not 0x55
|
||||
; calibration complete
|
||||
or a ; clear carry
|
||||
ret
|
||||
cal_err:
|
||||
scf
|
||||
ret
|
||||
|
||||
; -------------------------------------------------------
|
||||
; Read a single bit
|
||||
; needs d (comparator state)
|
||||
; valid: z=1 c=bit
|
||||
; error: z=0
|
||||
; uses a,b,c
|
||||
; -------------------------------------------------------
|
||||
read_bit:
|
||||
; entry may be late into first pulse
|
||||
; wait for first edge to measure
|
||||
ld b,0
|
||||
1$:
|
||||
inc b
|
||||
jr z,bit_bad
|
||||
in a,(TAPE_PORT)
|
||||
cp d
|
||||
jp z,1$
|
||||
ld d,a
|
||||
; ignored first edge
|
||||
; measure second pulse
|
||||
ld b,0
|
||||
2$:
|
||||
inc b
|
||||
jr z,bit_bad
|
||||
in a,(TAPE_PORT)
|
||||
cp d
|
||||
jp z,2$
|
||||
ld d,a
|
||||
; if in short window (second half is short pulse)
|
||||
; 1
|
||||
ld a,(SHORT_MIN)
|
||||
ld c,a
|
||||
ld a,b
|
||||
cp c
|
||||
jr c,bit_bad ; pulse<SHORT_MIN
|
||||
ld a,(SHORT_MAX)
|
||||
ld c,a
|
||||
ld a,b
|
||||
cp c
|
||||
jr c,bit_one
|
||||
jr z,bit_one ; pulse<=SHORT_MAX
|
||||
; test long window (second half is long pulse)
|
||||
ld a,(LONG_MIN)
|
||||
ld c,a
|
||||
ld a,b
|
||||
cp c
|
||||
jr c,bit_bad ; pulse<LONG_MAX
|
||||
ld a,(LONG_MAX)
|
||||
ld c,a
|
||||
ld a,b
|
||||
cp c
|
||||
jr c,bit_zero
|
||||
jr z,bit_zero ; pulse<=LONG_MAX
|
||||
bit_bad:
|
||||
ld a,1
|
||||
or a
|
||||
ret
|
||||
bit_zero:
|
||||
xor a
|
||||
ret
|
||||
bit_one:
|
||||
xor a
|
||||
scf
|
||||
ret
|
||||
|
||||
; -------------------------------------------------------
|
||||
; Read byte, MSB first
|
||||
; returns a (byte)
|
||||
; carry means error
|
||||
; needs d (comparator state)
|
||||
; uses e,h,b,c
|
||||
; -------------------------------------------------------
|
||||
read_byte:
|
||||
ld e,0
|
||||
ld h,8
|
||||
1$:
|
||||
call read_bit
|
||||
jr nz,9$
|
||||
; shift in the carry bit
|
||||
rl e
|
||||
; repeat 8 times
|
||||
dec h
|
||||
jr nz,1$
|
||||
; byte done,
|
||||
ld a,e
|
||||
or a
|
||||
ret
|
||||
9$:
|
||||
scf
|
||||
ret
|
||||
|
||||
; -------------------------------------------------------
|
||||
; Read and check sync bytes
|
||||
; carry is error
|
||||
; -------------------------------------------------------
|
||||
read_sync:
|
||||
call read_byte
|
||||
ret c
|
||||
cp 05ah
|
||||
jr nz,9$
|
||||
call read_byte
|
||||
ret c
|
||||
cp 0c3h
|
||||
jr nz,9$
|
||||
or a
|
||||
ret
|
||||
9$:
|
||||
scf
|
||||
ret
|
||||
|
||||
; -------------------------------------------------------
|
||||
; Read a block into BLOCK_BUFFER
|
||||
; needs d (comparator state)
|
||||
; uses b,c,d,e,h,l
|
||||
; returns error code in a
|
||||
; returns start of block in hl
|
||||
; carry is fail
|
||||
; -------------------------------------------------------
|
||||
read_block:
|
||||
; Block reading uses de' and hl' so preserve them
|
||||
exx
|
||||
push de
|
||||
push hl
|
||||
exx
|
||||
; calibrate reader
|
||||
call calibrate
|
||||
jr nc,1$ ; if no error jump
|
||||
ld a,BLOCK_ERROR_CALIBRATION
|
||||
scf
|
||||
jr 101$
|
||||
1$:
|
||||
; calibrated, read sync bytes
|
||||
call read_sync
|
||||
jr nc,2$ ; if no error jump
|
||||
ld a,BLOCK_ERROR_SYNC
|
||||
scf
|
||||
jr 101$
|
||||
2$:
|
||||
; reader initialized, start reading bytes
|
||||
exx
|
||||
ld e,0
|
||||
ld hl,BLOCK_BUFFER
|
||||
exx
|
||||
4$:
|
||||
call read_byte
|
||||
jr nc,5$
|
||||
; read error
|
||||
exx
|
||||
ld a,BLOCK_ERROR_READ
|
||||
scf
|
||||
jr 101$
|
||||
5$:
|
||||
exx
|
||||
ld (hl),a
|
||||
inc hl
|
||||
inc e
|
||||
ld a,e
|
||||
cp BLOCK_SIZE
|
||||
exx
|
||||
jr nz,4$
|
||||
|
||||
; Block is in BLOCK_BUFFER
|
||||
; calculate crc16
|
||||
ld hl, BLOCK_BUFFER
|
||||
ld a, BLOCK_SIZE-2 ; dont use received crc value
|
||||
call crc16
|
||||
; todo compare received crc with hl
|
||||
ld bc, (BLOCK_BUFFER+BLOCK_SIZE-2)
|
||||
or a ; clear carry
|
||||
sbc hl,bc ; do hl-bc-c
|
||||
jr z,6$ ; if the same jump
|
||||
; crc error
|
||||
ld a,BLOCK_ERROR_CHSUM
|
||||
scf
|
||||
jr 101$
|
||||
6$:
|
||||
; Block received correctly
|
||||
ld hl,BLOCK_BUFFER
|
||||
or a ; clear carry
|
||||
101$:
|
||||
exx
|
||||
pop hl
|
||||
pop de
|
||||
exx
|
||||
ret
|
||||
|
||||
; -------------------------------------------------------
|
||||
; Read a block but do not store
|
||||
; needs d (comparator state)
|
||||
; uses b,c,d,e,h,l
|
||||
; returns error code in a
|
||||
; carry is fail
|
||||
; -------------------------------------------------------
|
||||
read_block_dry:
|
||||
; Block reading uses de' and hl' so preserve them
|
||||
exx
|
||||
push de
|
||||
push hl
|
||||
exx
|
||||
; calibrate reader
|
||||
call calibrate
|
||||
jr nc,1$ ; if no error jump
|
||||
ld a,BLOCK_ERROR_CALIBRATION
|
||||
scf
|
||||
jr 101$
|
||||
1$:
|
||||
; calibrated, read sync bytes
|
||||
call read_sync
|
||||
jr nc,2$ ; if no error jump
|
||||
ld a,BLOCK_ERROR_SYNC
|
||||
scf
|
||||
jr 101$
|
||||
2$:
|
||||
; reader initialized, start reading bytes
|
||||
exx
|
||||
ld e,0
|
||||
exx
|
||||
4$:
|
||||
call read_byte
|
||||
jr nc,5$
|
||||
; read error
|
||||
exx
|
||||
ld a,BLOCK_ERROR_READ
|
||||
scf
|
||||
jr 101$
|
||||
5$:
|
||||
exx
|
||||
inc hl
|
||||
inc e
|
||||
ld a,e
|
||||
cp BLOCK_SIZE
|
||||
exx
|
||||
jr nz,4$
|
||||
; Block fully received
|
||||
or a ; clear carry
|
||||
101$:
|
||||
exx
|
||||
pop hl
|
||||
pop de
|
||||
exx
|
||||
ret
|
||||
; -------------------------------------------------------
|
||||
; CRC16
|
||||
; CRC-16/CCITT-FALSE (polynomial 1021h, initial value 0ffffh)
|
||||
; needs hl (pointer to memory buffer)
|
||||
; needs a (length of buffer)
|
||||
; returns hl (crc16)
|
||||
; uses a,b,c,d,e
|
||||
; -------------------------------------------------------
|
||||
crc16:
|
||||
ld b,a
|
||||
ld de,0ffffh
|
||||
or a
|
||||
jr z,4$
|
||||
1$:
|
||||
ld a,(hl)
|
||||
inc hl
|
||||
xor d
|
||||
ld d,a
|
||||
ld c,8
|
||||
2$:
|
||||
sla e
|
||||
rl d
|
||||
jr nc,3$
|
||||
ld a,e
|
||||
xor 021h
|
||||
ld e,a
|
||||
ld a,d
|
||||
xor 010h
|
||||
ld d,a
|
||||
3$:
|
||||
dec c
|
||||
jr nz,2$
|
||||
djnz 1$
|
||||
4$:
|
||||
ex de,hl
|
||||
ret
|
||||
|
||||
; -------------------------------------------------------
|
||||
; Wait for silence
|
||||
; uses a,b,d
|
||||
; -------------------------------------------------------
|
||||
wait_silence:
|
||||
call sample_pulse
|
||||
jr nc,wait_silence ; no timeout -> no silence
|
||||
ret
|
||||
|
||||
; -------------------------------------------------------
|
||||
; Strings
|
||||
; -------------------------------------------------------
|
||||
msg_start: .db "PLAY TAPE", 0ah,0dh,00h
|
||||
Reference in New Issue
Block a user