memory base driver for 6280 2/3

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 時間がだめなのでしょうか?