222 lines
4.6 KiB
NASM
222 lines
4.6 KiB
NASM
|
; tape blkdev read-only
|
||
|
; to be included as a kernel module.
|
||
|
; In the glue.asm devices list the PutB pointer has to be unsetZ
|
||
|
|
||
|
; defines:
|
||
|
; tap_buffer = 256-byte tape loading buffer in RAM
|
||
|
; buf_pos = read position in the buffer
|
||
|
; crossing the buffer boundaries require loading or rewinding+loading
|
||
|
; tap_pos = previous read position of the block device,
|
||
|
; then the difference btw current and previous positions, both in EDLH format as throughout the kernel code
|
||
|
|
||
|
tapeblk_init:
|
||
|
; initialized CFS and a placeholder 1-block, 1-byte file in the buffer
|
||
|
; the tape fs is not default, has to be mounted
|
||
|
ld hl, .plh
|
||
|
ld de, tap_buffer
|
||
|
ld bc, 6
|
||
|
ldir
|
||
|
ret
|
||
|
.plh:
|
||
|
.db "CFS",1,1,0,'@'
|
||
|
|
||
|
tapeGetB:
|
||
|
; it gets the new position in DE/HL, has to return value in A
|
||
|
push bc
|
||
|
push ix
|
||
|
|
||
|
; First of all, is the difference between positions negative or positive?
|
||
|
push hl ; store the position
|
||
|
push de
|
||
|
ld ix, tap_pos ; previous
|
||
|
|
||
|
push de ; working copy, higher bytes
|
||
|
ld e, (ix+2) ; lower bytes of previous position
|
||
|
ld d, (ix+3)
|
||
|
scf
|
||
|
ccf
|
||
|
sbc hl,de
|
||
|
ld (ix+6), l
|
||
|
ld (ix+7), h
|
||
|
pop hl
|
||
|
ld e, (ix+0) ; higher bytes
|
||
|
ld d, (ix+1)
|
||
|
sbc hl,de
|
||
|
ld (ix+4), l
|
||
|
ld (ix+5), h
|
||
|
jp nc, .tblk_posdif
|
||
|
|
||
|
.tblk_negdif:
|
||
|
; at this point we have the negative difference
|
||
|
pop de ; restore the current position
|
||
|
pop hl
|
||
|
; store it as 'the previous'
|
||
|
ld (ix+0), e
|
||
|
ld (ix+1), d
|
||
|
ld (ix+2), l
|
||
|
ld (ix+3), h
|
||
|
|
||
|
; let's set the buffer position while we're here
|
||
|
ld a, (buf_pos)
|
||
|
add a, (ix+6) ; l
|
||
|
; the difference bytes are negative, so e.g. add 255 = sub 1
|
||
|
ld (buf_pos), a
|
||
|
; no carry would mean underflow in this case
|
||
|
jp nc, .tblk_rewind
|
||
|
; we now have a chance that the higher bytes are FF (due to lower CY)
|
||
|
xor a
|
||
|
dec a
|
||
|
and (ix+7)
|
||
|
and (ix+4)
|
||
|
and (ix+5)
|
||
|
cp 255
|
||
|
jp z, .tblk_readbyte ; a negative difference within the buffer
|
||
|
|
||
|
; we have to rewind the tape and load back to the current position,
|
||
|
; so it's safe to discard the difference and treat the current position as the positive difference
|
||
|
|
||
|
.tblk_rewind:
|
||
|
; as we will rewind to zero, at least one additional block is to be loaded
|
||
|
xor a
|
||
|
inc h
|
||
|
cp h
|
||
|
jr nz, .tblk_store
|
||
|
inc de
|
||
|
.tblk_store:
|
||
|
ld (ix+4), e ; diff
|
||
|
ld (ix+5), d
|
||
|
ld (ix+6), l ; diff
|
||
|
ld (ix+7), h
|
||
|
|
||
|
; purple border means 'rewind the tape and press enter'
|
||
|
di
|
||
|
ld a, 3
|
||
|
out (254), a
|
||
|
.tblk_key:
|
||
|
ld a, 191 ; waiting for enter
|
||
|
in a,(254)
|
||
|
rra
|
||
|
jr c, .tblk_key
|
||
|
ei
|
||
|
jr .tblk_skip
|
||
|
; we don't have to set the buffer position, done it already
|
||
|
|
||
|
.tblk_posdif:
|
||
|
; at this point we have the difference and know it is positive
|
||
|
pop de ; restore the current position
|
||
|
pop hl
|
||
|
; store it as 'the previous'
|
||
|
ld (ix+0), e
|
||
|
ld (ix+1), d
|
||
|
ld (ix+2), l
|
||
|
ld (ix+3), h
|
||
|
|
||
|
.tblk_buffer:
|
||
|
; setting the buffer position for the positive difference
|
||
|
ld a, (buf_pos)
|
||
|
add a, (ix+6) ; l
|
||
|
ld (buf_pos), a
|
||
|
jr nc, .tblk_skip
|
||
|
|
||
|
; now we increase the higher difference bytes due to overflow
|
||
|
xor a
|
||
|
inc (ix+7) ; h
|
||
|
cp (ix+7)
|
||
|
jr nz, .tblk_skip
|
||
|
inc (ix+4) ; e
|
||
|
cp (ix+4)
|
||
|
jr nz, .tblk_skip
|
||
|
inc (ix+5) ; d
|
||
|
|
||
|
.tblk_skip:
|
||
|
; Now, how many tape blocks do we have to load before the target block appears in the buffer?
|
||
|
; it is shown by the 3 higher bytes of the difference
|
||
|
; We've just set them up for the positive difference case.
|
||
|
|
||
|
; For the negative difference case, the L-byte has to be equal to the buf_pos we set earlier
|
||
|
|
||
|
; (ix+7) H, (ix+4) E, (ix+5) D is now the counter for blocks to be loaded
|
||
|
; if it's 0, the block is already at the buffer and we don't have to load anything
|
||
|
xor a
|
||
|
or (ix+7)
|
||
|
or (ix+4)
|
||
|
or (ix+5)
|
||
|
jp z, .tblk_readbyte
|
||
|
|
||
|
; well, let's play the tape
|
||
|
ld a, (ix+5)
|
||
|
ld b,a ; this is the outer cycle
|
||
|
inc b ; as we will djnz
|
||
|
ld a, (ix+7)
|
||
|
ld l, a ; lower byte of the inner counter
|
||
|
ld a, (ix+4)
|
||
|
ld h, a ; higher byte
|
||
|
dec hl ; as we know at this point that at least one block is to be loaded
|
||
|
ld c, 0 ; it's a 16-bit cycle flag used below
|
||
|
xor a
|
||
|
or h
|
||
|
or l
|
||
|
jp z, .tblk_load
|
||
|
ld c, 1 ; hl=nonzero
|
||
|
|
||
|
.tblk_load:
|
||
|
push bc ; counters
|
||
|
push hl
|
||
|
ld ix, tap_buffer ; we don't need the ix value anymore
|
||
|
ld de, 256
|
||
|
ld a, 255
|
||
|
call t_load
|
||
|
pop hl
|
||
|
pop bc
|
||
|
|
||
|
; counter
|
||
|
xor a
|
||
|
dec hl
|
||
|
or h
|
||
|
or l
|
||
|
jr nz, .tblk_ccheck
|
||
|
ld c, 0 ; on the next cycle, b has to be decremented
|
||
|
jr .tblk_load
|
||
|
.tblk_ccheck:
|
||
|
xor a
|
||
|
or c
|
||
|
jp nz, .tblk_load
|
||
|
inc c ; next 16-bit cycle
|
||
|
djnz .tblk_load
|
||
|
|
||
|
.tblk_readbyte:
|
||
|
ld hl, tap_buffer
|
||
|
ld b, 0
|
||
|
ld a, (buf_pos)
|
||
|
ld c, a
|
||
|
add hl,bc
|
||
|
ld a, (hl) ; here it is!
|
||
|
pop ix
|
||
|
pop bc
|
||
|
cp a
|
||
|
ret
|
||
|
|
||
|
t_load:
|
||
|
push iy
|
||
|
ld iy, IYBAS
|
||
|
scf
|
||
|
; one can not call directly, as RST8 is then called upon break
|
||
|
inc d
|
||
|
ex af,af'
|
||
|
dec d
|
||
|
di
|
||
|
ld a, 15
|
||
|
out (254), a
|
||
|
call 1378 ; jump into LD-BYTES
|
||
|
t_ldret:
|
||
|
ld a, (23624) ; restore border
|
||
|
and 0x38
|
||
|
rrca
|
||
|
rrca
|
||
|
rrca
|
||
|
out (254),a
|
||
|
pop iy
|
||
|
ei
|
||
|
ret
|
||
|
|
||
|
;end
|