mirror of
https://github.com/oliverschmidt/Stream-PDM.git
synced 2024-12-22 15:31:08 +00:00
406a0628bd
LDY <absolute>,X without page-crossing (sort of surprisingly) requires only 4 cycles, so there's after all no need at all to resort to LDY <zeropage>,X to stay inside the 4 cycle budget.
685 lines
14 KiB
ArmAsm
685 lines
14 KiB
ArmAsm
.export _streamafterexit
|
|
.import done, abort_key
|
|
|
|
.include "apple2.inc"
|
|
.macpack apple2
|
|
.pc02
|
|
|
|
; free zero page locations according to ProDOS TechRefMan A.4
|
|
src := $CE
|
|
dst := $D6
|
|
rd_count := $EB
|
|
wr_count := $EC
|
|
scroll_row := $ED
|
|
scroll_col := $EE
|
|
scroll_opc := $EF
|
|
|
|
program := $100B ; adressed via jmp_table !
|
|
buffer := $9000
|
|
physical := $9100
|
|
|
|
px = $8F ; force page crossing
|
|
silence = $FF
|
|
skew = 3
|
|
end_mark = $FF
|
|
rd_mark = $FE
|
|
wr_mark = $FD
|
|
max_row = 15
|
|
max_column = 39
|
|
|
|
scroll_ldx = $AE
|
|
scroll_ldy = $AC
|
|
scroll_stx = $8E
|
|
scroll_sty = $8C
|
|
|
|
_streamafterexit:
|
|
asl
|
|
asl
|
|
asl
|
|
asl
|
|
tax
|
|
clc
|
|
adc #px
|
|
sta slot
|
|
txa
|
|
ora #%10001111
|
|
sta slot_mask
|
|
|
|
lda abort_key
|
|
sta quit_key
|
|
|
|
lda #<stream
|
|
ldx #>stream
|
|
sta done+1
|
|
stx done+2
|
|
rts
|
|
|
|
|
|
.segment "LOWCODE"
|
|
|
|
|
|
slot:
|
|
.res 1
|
|
|
|
slot_mask:
|
|
.res 1
|
|
|
|
quit_key:
|
|
.res 1
|
|
|
|
key_state:
|
|
.res 1
|
|
|
|
jmp_table:
|
|
.byte $0B, $10, $10 ; second byte used both as high and low !
|
|
|
|
lowres_lo:
|
|
.byte $00, $80, $00, $80, $00, $80, $28, $A8
|
|
.byte $28, $A8, $28, $A8, $28, $A8, $50
|
|
|
|
lowres_hi:
|
|
.byte $05, $05, $06, $06, $07, $07, $04, $04
|
|
.byte $05, $05, $06, $06, $07, $07, $04
|
|
|
|
streaming:
|
|
scrcode "Streaming... [Space] - Pause [Esc] - Stop"
|
|
.byte $00
|
|
|
|
pausing:
|
|
scrcode "Pausing... [Space] - Stream"
|
|
.byte $00
|
|
|
|
waiting:
|
|
scrcode "Waiting... "
|
|
.byte $00
|
|
|
|
|
|
update_status:
|
|
sta update_status+9
|
|
stx update_status+10
|
|
ldx #$00
|
|
chr:lda a:$0000,x ; patched
|
|
bne :+
|
|
rts
|
|
: tay
|
|
txa
|
|
lsr ; even cols go into aux mem
|
|
tax
|
|
tya
|
|
bcs :+
|
|
bit $C055 ; aux mem
|
|
: sta $07D0,x
|
|
bcs :+
|
|
bit $C054 ; main mem
|
|
: txa
|
|
rol
|
|
tax
|
|
inx
|
|
bra chr
|
|
|
|
|
|
stream:
|
|
; Crate unrolled loop program
|
|
jsr unroll
|
|
|
|
; Create socket 0 physical read memory lookup table
|
|
ldx #$00
|
|
: txa
|
|
and #>$1FFF
|
|
ora #>$6000
|
|
sta physical,x
|
|
inx
|
|
bne :-
|
|
|
|
; Init part of ring buffer that is played before first data is available
|
|
ldx #skew-1
|
|
lda #silence
|
|
: sta buffer,x
|
|
dex
|
|
bpl :-
|
|
|
|
; Show status 'Streaming'
|
|
lda #<streaming
|
|
ldx #>streaming
|
|
jsr update_status
|
|
|
|
; Run unrolled loop program
|
|
jsr program
|
|
|
|
; Switch to text screen
|
|
bit $C051
|
|
|
|
; Clear screen
|
|
jsr $FC58 ; HOME
|
|
|
|
; Check ProDOS system bit map
|
|
lda $BF6F ; protection for pages $B8 - $BF
|
|
cmp #%00000001 ; exactly system global page is protected
|
|
beq :+
|
|
jmp DOSWARM
|
|
|
|
; Quit to ProDOS dispatcher
|
|
: jsr $BF00 ; MLI call entry point
|
|
.byte $65 ; quit
|
|
.word par
|
|
|
|
; MLI parameter list for quit
|
|
par:.byte $04 ; param_count
|
|
.byte $00 ; quit_type
|
|
.word $0000 ; reserved
|
|
.byte $00 ; reserved
|
|
.word $0000 ; reserved
|
|
|
|
|
|
disconnect:
|
|
ldx slot
|
|
lda #$04 ; socket 0
|
|
sta $C085-px,x
|
|
lda #$01 ; command register
|
|
sta $C086-px,x
|
|
lda #$08 ; DISCON
|
|
sta $C087-px,x
|
|
rts
|
|
|
|
|
|
check_connect:
|
|
; Show status 'Waiting'
|
|
lda #<waiting
|
|
ldx #>waiting
|
|
jsr update_status
|
|
|
|
; Check if still connected at all
|
|
ldx slot
|
|
chk:lda #$04 ; socket 0
|
|
sta $C085-px,x
|
|
lda #$03 ; status register
|
|
sta $C086-px,x
|
|
lda $C087-px,x
|
|
cmp #$17 ; SOCK_ESTABLISHED
|
|
beq :+
|
|
pla ; completely ...
|
|
pla ; quit ...
|
|
rts ; stream
|
|
|
|
; Check if at least one page available
|
|
: lda #$04 ; socket 0
|
|
sta $C085-px,x
|
|
lda #$26 ; received size register
|
|
sta $C086-px,x
|
|
lda $C087-px,x ; high byte
|
|
beq :+
|
|
|
|
; Show status 'Streaming'
|
|
lda #<streaming
|
|
ldx #>streaming
|
|
jsr update_status
|
|
ldx #$04 ; socket 0
|
|
rts ; return to stream
|
|
|
|
; Check keyboard
|
|
: lda $C000
|
|
bpl chk
|
|
bit $C010
|
|
cmp quit_key
|
|
beq :+
|
|
cmp #$9B ; Esc
|
|
beq :+
|
|
bra chk
|
|
|
|
: pla ; completely ...
|
|
pla ; quit ...
|
|
jmp disconnect ; stream
|
|
|
|
|
|
check_keyboard:
|
|
stz key_state
|
|
|
|
key:bit $C010 ; keyboard strobe
|
|
cpx quit_key
|
|
beq :+
|
|
cpx #$9B ; Esc
|
|
beq :+
|
|
cpx #$A0 ; Space
|
|
beq :++
|
|
|
|
ldx key_state
|
|
bne get
|
|
rts ; return to stream
|
|
|
|
: pla ; completely ...
|
|
pla ; quit ...
|
|
jmp disconnect ; stream
|
|
|
|
: lda key_state
|
|
beq :+
|
|
|
|
; Show status 'Streaming'
|
|
lda #<streaming
|
|
ldx #>streaming
|
|
jmp update_status ; return to stream
|
|
|
|
; Show status 'Pausing'
|
|
: lda #<pausing
|
|
ldx #>pausing
|
|
jsr update_status
|
|
|
|
; Wait for keypress
|
|
get:ldx $C000 ; keyboard
|
|
bpl :-
|
|
inc key_state
|
|
bra key
|
|
|
|
|
|
unroll:
|
|
lda #<program
|
|
ldx #>program
|
|
sta dst
|
|
stx dst+1
|
|
|
|
stz rd_count
|
|
lda #skew
|
|
sta wr_count
|
|
|
|
lda #<recv_prolog
|
|
ldy #>recv_prolog
|
|
jsr copy
|
|
|
|
ldx #$0100 / 7
|
|
: lda #<recv_loop
|
|
ldy #>recv_loop
|
|
jsr copy
|
|
dex
|
|
bne :-
|
|
|
|
lda #<recv_epilog
|
|
ldy #>recv_epilog
|
|
jsr copy
|
|
|
|
stz scroll_row
|
|
lda #max_column
|
|
sta scroll_col
|
|
lda #scroll_ldx
|
|
sta scroll_opc
|
|
ldx #$07
|
|
scr:cpx #$07
|
|
bne :+
|
|
lda #<speaker_load
|
|
ldy #>speaker_load
|
|
bra :++
|
|
: jsr scroll_patch
|
|
lda #<speaker
|
|
ldy #>speaker
|
|
: jsr copy
|
|
dex
|
|
bpl :+
|
|
ldx #$07
|
|
: lda scroll_row
|
|
cmp #max_row
|
|
bne scr
|
|
|
|
fil:cpx #$07
|
|
bne :+
|
|
lda #<speaker_load
|
|
ldy #>speaker_load
|
|
bra :++
|
|
: lda #<speaker_nop4
|
|
ldy #>speaker_nop4
|
|
: jsr copy
|
|
dex
|
|
bpl :+
|
|
ldx #$07
|
|
: lda rd_count
|
|
bne fil
|
|
cpx #$01
|
|
bne fil
|
|
|
|
lda #<speaker_loop
|
|
ldy #>speaker_loop
|
|
jsr copy
|
|
rts
|
|
|
|
|
|
copy:
|
|
sta src
|
|
sty src+1
|
|
ldy #$00
|
|
nxt:lda (src),y
|
|
cmp #end_mark
|
|
bne :++
|
|
tya
|
|
clc
|
|
adc dst
|
|
sta dst
|
|
bcc :+
|
|
inc dst+1
|
|
: rts
|
|
: cmp #rd_mark
|
|
bne :+
|
|
lda rd_count
|
|
inc rd_count
|
|
bra put
|
|
: cmp #wr_mark
|
|
bne :+
|
|
lda wr_count
|
|
inc wr_count
|
|
bra put
|
|
: cmp #$F5 ; slot mask
|
|
bcc put
|
|
and slot_mask
|
|
put:sta (dst),y
|
|
iny
|
|
bne nxt
|
|
inc src+1
|
|
inc dst+1
|
|
bra nxt
|
|
|
|
|
|
scroll_patch:
|
|
lda scroll_opc
|
|
sta speaker ; opcode
|
|
ldy scroll_row
|
|
lda lowres_lo,y
|
|
clc
|
|
adc scroll_col
|
|
sta speaker+1 ; operand low
|
|
lda lowres_hi,y
|
|
sta speaker+2 ; operand high
|
|
|
|
lda scroll_opc
|
|
cmp #scroll_ldx
|
|
bne :+
|
|
dec scroll_col
|
|
lda #scroll_ldy
|
|
sta scroll_opc
|
|
rts
|
|
|
|
: cmp #scroll_ldy
|
|
bne :+
|
|
inc scroll_col
|
|
lda #scroll_sty
|
|
sta scroll_opc
|
|
rts
|
|
|
|
: cmp #scroll_sty
|
|
bne :++
|
|
dec scroll_col
|
|
beq :+
|
|
dec scroll_col
|
|
lda #scroll_ldy
|
|
sta scroll_opc
|
|
rts
|
|
|
|
: lda #scroll_stx
|
|
sta scroll_opc
|
|
rts
|
|
|
|
: lda #scroll_ldx
|
|
sta scroll_opc
|
|
lda #max_column
|
|
sta scroll_col
|
|
inc scroll_row
|
|
rts
|
|
|
|
|
|
; 2 bytes, 2 cycles
|
|
.macro nop2
|
|
bit #$00
|
|
.endmacro
|
|
|
|
|
|
; 2 bytes, 3 cycles
|
|
.macro nop3
|
|
bit $00
|
|
.endmacro
|
|
|
|
|
|
; 3 bytes, 4 cycles
|
|
.macro nop4
|
|
bit a:$0000
|
|
.endmacro
|
|
|
|
|
|
; 13 bytes, 9 cycles
|
|
.macro spkr
|
|
lsr a ; 2
|
|
bcs :+ ; 2 3
|
|
nop ; 2
|
|
bra :++ ; 3
|
|
.res 4
|
|
: bit $C030 ; 4
|
|
:.endmacro
|
|
|
|
|
|
; 9 bytes, 9 cycles
|
|
.macro spkr_short
|
|
lsr a ; 2
|
|
bcs :+ ; 2 3
|
|
nop ; 2
|
|
bra :++ ; 3
|
|
: bit $C030 ; 4
|
|
:.endmacro
|
|
|
|
|
|
; 13 bytes, 9 cycles
|
|
.macro spkr_jsr addr
|
|
lsr a ; 2
|
|
bcs :+ ; 2 3
|
|
nop ; 2
|
|
bra :++ ; 3
|
|
.res 1
|
|
jsr addr
|
|
: bit $C030 ; 4
|
|
:.endmacro
|
|
|
|
|
|
; 16 bytes, 13 cycles
|
|
.macro spkr_load
|
|
lda buffer | rd_mark ; 4
|
|
lsr a ; 2
|
|
bcs :+ ; 2 3
|
|
nop ; 2
|
|
bra :++ ; 3
|
|
.res 4
|
|
: bit $C030 ; 4
|
|
:.endmacro
|
|
|
|
|
|
; 22 bytes, 20 cycles (= 2 * 13 - 6 used by speaker_loop)
|
|
.macro spkr_init
|
|
nop4 ; 4 $100B (bit 7 is 0)
|
|
bra :+ ; 3
|
|
nop3 ; 3 $1010 (bit 7 is 1)
|
|
bit $C030 ; 4
|
|
: lda buffer | rd_mark ; 4
|
|
lsr a ; 2
|
|
bcs :+ ; 2 3
|
|
nop ; 2
|
|
bra :++ ; 3
|
|
: bit $C030 ; 4
|
|
:.endmacro
|
|
|
|
|
|
recv_prolog:
|
|
spkr_init ; bit 0
|
|
ldx #$04 ; socket 0
|
|
nop
|
|
spkr_short ; bit 1
|
|
stx $C0F5 ; socket 0
|
|
spkr ; bit 2
|
|
ldy #$26 ; received size register
|
|
nop
|
|
spkr ; bit 3
|
|
sty $C0F6 ; received size register
|
|
spkr ; bit 4
|
|
ldy $C0F7 ; high byte
|
|
spkr ; bit 5
|
|
dey ; at least one page available
|
|
bmi *+9 ; branch to jsr
|
|
spkr_jsr check_connect ; bit 6
|
|
stx $C0F5 ; socket 0
|
|
spkr ; bit 7
|
|
spkr_load ; bit 0
|
|
ldx #$28 ; read pointer register
|
|
nop
|
|
spkr ; bit 1
|
|
stx $C0F6 ; read pointer register
|
|
spkr ; bit 2
|
|
ldx $C0F7 ; high byte
|
|
spkr ; bit 3
|
|
ldy physical,x ; high byte -> physical
|
|
spkr ; bit 4
|
|
ldx $C0F7 ; low byte
|
|
spkr ; bit 5
|
|
sty $C0F5 ; read addr high
|
|
spkr ; bit 6
|
|
stx $C0F6 ; read addr low
|
|
spkr ; bit 7
|
|
.byte end_mark
|
|
|
|
|
|
recv_loop:
|
|
spkr_load ; bit 0
|
|
ldx $C0F7 ; data
|
|
spkr ; bit 1
|
|
stx buffer | wr_mark
|
|
spkr ; bit 2
|
|
ldx $C0F7 ; data
|
|
spkr ; bit 3
|
|
stx buffer | wr_mark
|
|
spkr ; bit 4
|
|
ldx $C0F7 ; data
|
|
spkr ; bit 5
|
|
stx buffer | wr_mark
|
|
spkr ; bit 6
|
|
ldx $C0F7 ; data
|
|
spkr ; bit 7
|
|
spkr_load ; bit 0
|
|
stx buffer | wr_mark
|
|
spkr ; bit 1
|
|
ldx $C0F7 ; data
|
|
spkr ; bit 2
|
|
stx buffer | wr_mark
|
|
spkr ; bit 3
|
|
ldx $C0F7 ; data
|
|
spkr ; bit 4
|
|
stx buffer | wr_mark
|
|
spkr ; bit 5
|
|
ldx $C0F7 ; data
|
|
spkr ; bit 6
|
|
stx buffer | wr_mark
|
|
spkr ; bit 7
|
|
.byte end_mark
|
|
|
|
|
|
recv_epilog:
|
|
; $0100 % 7 = 4 -> 4 data bytes left
|
|
spkr_load ; bit 0
|
|
ldx $C0F7 ; data
|
|
spkr ; bit 1
|
|
stx buffer | wr_mark
|
|
spkr ; bit 2
|
|
ldx $C0F7 ; data
|
|
spkr ; bit 3
|
|
stx buffer | wr_mark
|
|
spkr ; bit 4
|
|
ldx $C0F7 ; data
|
|
spkr ; bit 5
|
|
stx buffer | wr_mark
|
|
spkr ; bit 6
|
|
ldx $C0F7 ; data
|
|
spkr ; bit 7
|
|
spkr_load ; bit 0
|
|
stx buffer | wr_mark
|
|
|
|
; Commit recv
|
|
spkr ; bit 1
|
|
ldx #$04 ; socket 0
|
|
nop
|
|
spkr ; bit 2
|
|
stx $C0F5 ; socket 0
|
|
spkr ; bit 3
|
|
ldy #$28 ; received size register
|
|
nop
|
|
spkr ; bit 4
|
|
sty $C0F6 ; received size register
|
|
spkr ; bit 5
|
|
ldy $C0F7 ; high byte
|
|
spkr ; bit 6
|
|
iny ; commit one page
|
|
nop2
|
|
spkr ; bit 7
|
|
spkr_load ; bit 0
|
|
stx $C0F5 ; socket 0
|
|
spkr ; bit 1
|
|
ldx #$28 ; received size register
|
|
nop
|
|
spkr ; bit 2
|
|
stx $C0F6 ; received size register
|
|
spkr ; bit 3
|
|
sty $C0F7 ; high byte
|
|
spkr ; bit 4
|
|
ldx #$04 ; socket 0
|
|
nop
|
|
spkr ; bit 5
|
|
stx $C0F5 ; socket 0
|
|
spkr ; bit 6
|
|
ldx #$01 ; command register
|
|
nop
|
|
spkr ; bit 7
|
|
spkr_load ; bit 0
|
|
stx $C0F6 ; command register
|
|
spkr ; bit 1
|
|
ldx #$40 ; RECV
|
|
nop
|
|
spkr ; bit 2
|
|
stx $C0F7 ; RECV
|
|
spkr ; bit 3
|
|
|
|
; Check keyboard
|
|
ldx $C000 ; keyboard
|
|
spkr ; bit 4
|
|
inx ; prepare for N flag
|
|
bit #$00 ; 2 byte nop
|
|
spkr ; bit 5
|
|
dex ; set N flag
|
|
bmi *+9 ; branch to jsr
|
|
spkr_jsr check_keyboard ; bit 6
|
|
|
|
; Filler
|
|
nop4
|
|
spkr ; bit 7
|
|
.byte end_mark
|
|
|
|
|
|
; 16 bytes, 13 cycles
|
|
speaker:
|
|
.res 3 ; patched
|
|
spkr
|
|
.byte end_mark
|
|
|
|
|
|
; 16 bytes, 13 cycles
|
|
speaker_load:
|
|
spkr_load
|
|
.byte end_mark
|
|
|
|
|
|
; 16 bytes, 13 cycles
|
|
speaker_nop4:
|
|
nop4
|
|
spkr
|
|
.byte end_mark
|
|
|
|
|
|
; 14 bytes, 13 cycles (+ 6 cycles)
|
|
speaker_loop:
|
|
lsr a ; 2 bit 6
|
|
tax ; 2 bit 7
|
|
nop ; 2
|
|
bcs :+ ; 2 3
|
|
nop ; 2
|
|
bra :++ ; 3
|
|
: bit $C030 ; 4
|
|
: jmp (jmp_table,x) ; 6
|
|
.byte end_mark
|