.code ; Written by Joel Yliluoma in 2013. http://iki.fi/bisqwit/ ; Contains no relocations. ; src_addr and dst_addr must be two zeropage pointers. ppu_send_rleinc: ; Copy stream from CPU memory @ src_addr -> PPU dst_addr ; src_addr need not be aligned in any particular way ; stream is terminated by indication within stream ; src_addr is updated to point after the data. ; dst_addr is not modified. ; Data format: ; LIT: Input byte c = 0..3F: ; Put next c+0x01 bytes verbatim, except BACKWARDS ; END: Input byte c = 40: ; End stream ; SEQ: Input byte c = 41..7F: ; Read byte b, put byte b ; Put next c-0x40 bytes increasing b by 1 before every write ; DBL: Input byte c = 80..9F: ; Read byte b1 ; Read byte b2 ; Put b1, (c-0x7F) times; swap b2 and b1 after each iteration ; RUN: Input byte c = A0..FF: ; Read byte b ; Put b, (0x101-c) times bit $2002 ; Load the destination address lda dst_addr+1 sta $2006 lda dst_addr+0 sta $2006 ldy #0 beq @loop @do_dbl: ; Input: A = 00..3E, representing 80..9F. lsr ; Output: A = 00..1F. tax inx inx lda (src_addr),y pha iny lda (src_addr),y tay pla @dbl_loop: sta $2007 dex bmi @done_dbl_loop sty $2007 dex bpl @dbl_loop @done_dbl_loop: ; Add 3 to the pointer. (2 + carry) sec bcs @add2_loop @do_run: ; 80..FF. Carry is set. ; Currently our input byte is mapped as follows: ; 80..9F = 00..3E ; A0..BF = 40..7E ; C0..FF = 80..FE cmp #$40 bcc @do_dbl ; So we have A = 40..FE ror ; Clears carry. Output: A = A0..FF. tax dex lda (src_addr),y @rle_loop: sta $2007 inx bne @rle_loop ; Carry is still clear. ;jmp @add2_loop @add2_loop: lda #2 ldy #0 @add_loop: adc src_addr sta src_addr bcs @src_wrap @loop: lda (src_addr),y iny asl a bcs @do_run ; bit 7 was set. Was 80..FF. bmi @do_seq_or_end ; bit 6 was set. Was 40..7F. ;@do_lit: lsr a ; clears carry ; 0..3F adc #1 tay ; Y = value+1 tax @lit_loop: ; Literal text is sent BACKWARDS! lda (src_addr),y sta $2007 dey bne @lit_loop ; terminate when Y=0 inx txa ; A = value+2 bne @add_loop @src_wrap: inc src_addr+1 bne @loop @do_seq: tax ; Get first byte, put it in Y lda (src_addr),y tay @inc_loop: sty $2007 iny dex bpl @inc_loop ; Carry is still clear. bmi @add2_loop @do_seq_or_end: ; 40..7F. Carry is clear. ror a ; Clears carry. and #$3F bne @do_seq inc src_addr+0 bne @ok inc src_addr+1 @ok: rts