write driver は RAM の data をまるまるコピーではなく通信経路からの fifo のコピーとしたかったのですが、既存の機能を使い回すということで前者でてっとりばやく実装することにしました.
書き込みルーチン
先日の serial_send を使ったら処理時間がえらいおそかったので早い物をつくりました。
write_start: cly write_byte_next: lda (<mb128_destsrc),y write_shift: temp eval 0 rept 8 if temp <> 7 tax endif and #1 sta joypad ora #1<<1 sta joypad if temp <> 7 txa lsr a endif temp eval temp+1 endm iny bne write_byte_next write_pointer_update: inc <mb128_destsrc+1 inc <mb128_length+0 bne write_byte_next inc <mb128_length+1 bne write_byte_next rts
今回は RAM を使わず a,x,y で回すことにしましたので bit 単位のループをなくして rept でコードを繰り返してます. tax と txa がまどろっこしいので削りたいのですが削れるのは最後だけみたいです.
あとコード量が増えるので bne が届くのがギリギリになってきました.
1bit 単位でループを回すなら下記でしょうか. 2bit 単位でもそんなに悪くないかも.
write_byte_next: lda (<mb128_destsrc),y phy ldy #8/2 write_shift: rept 2 tax and #1 sta joypad ora #1<<1 sta joypad txa lsr a endm dey bne write_shift ply iny bne write_byte_next
さらなる高速化の失敗
送信したい data が 8'h00 である場合は %00 と %10 を交互に送るだけであること, address 0x1fff000-0x1fff3ff が mirror であることを利用して tai 命令を使ってみました.
write_byte_next: lda (<mb128_destsrc),y bne write_shift tai data00,joypad,2*8 iny bne write_byte_next bra write_pointer_update write_shift: (snip) data00: byt %00,%10 dataff: byt %01,%11
結果は memory base 側へデータが正しくかけてませんでした. *1 csl; tai; csh とすれば正しく転送できますが、手計算では先述のループより遅いみたいです.
8bit 単位の転送ではオーバーヘッドが大きいのでたくさん 0 で埋める場合には使えそうです. mirror 領域が 0x400 byte なので1つの tai 命令での最大転送量は 0x400 / 8 / 2 で 0x40 bytes なのに注意してください.
data 0xff の転送もできそうなんですが inc a; beq がやりづらくその関わりに cmp #$ff; beq を書くのがまどろこっしくて実用化は難しそうでした.
*1:hold 時間がだめなのでしょうか?