Stream-PDM/stream.s
Oliver Schmidt 406a0628bd Removed unnecessary zero page usage.
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.
2020-05-12 23:01:21 +02:00

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