.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 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: ; Create 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 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 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 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 jmp update_status ; return to stream ; Show status 'Pausing' : lda #pausing jsr update_status ; Wait for keypress get:ldx $C000 ; keyboard bpl :- inc key_state bra key unroll: lda #program sta dst stx dst+1 stz rd_count lda #skew sta wr_count lda #recv_prolog jsr copy ldx #$0100 / 7 : lda #recv_loop jsr copy dex bne :- lda #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 bra :++ : jsr scroll_patch lda #speaker : jsr copy dex bpl :+ ldx #$07 : lda scroll_row cmp #max_row bne scr fil:cpx #$07 bne :+ lda #speaker_load bra :++ : lda #speaker_nop4 : jsr copy dex bpl :+ ldx #$07 : lda rd_count bne fil cpx #$01 bne fil lda #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