なんちゃってROM用変態プログラム

  • 投稿日:
  • 更新日:2015/03/09
  • by
  • カテゴリ:

ATtiny2313 ROMエミュレータを使ってみる

なんちゃってROMの動きを確実に確かめるために、なにかよいアプリケーションはないかと考えました。 そこで、Joystick版のSDカードアダプタからの読み込みをすることにしました。

とはいっても、Joystick版の場合、SPIの動作をすべてAY-3-8910のI/Oで実現する必要があるため、非常に多くのコードが必要になります。 たとえば、1ビットの何かを出力するためにも、

ld	a, #0x0f
out	(#0xa1), a
ld	a, #value
out	(#0xa2), a

といった具合に、愚直に実現すると8バイトもかかってしまいます。

なんちゃってROMに許されたアドレス空間は、アドレス線の本数の制約により128バイト。 先頭の4バイトはBIOSがROMの判別とジャンプアドレスを得るために必要なため、実際は124バイトしかありません。

そこで、ファイルを読み込むのは最初からあきらめ(FATなんてとても入らない)、セクタ0を読み込むことにしました。 もともとセクタ0の最初の446バイトは、ブートアップのためのコードを格納する領域ですしね。

それでも、電源ON->初期化->読み込みとあるため、結構大変です。 リリース済みのドライバを見てみたら、398バイトもありました。

それを削りに削りました。 エラーチェックやらレジスタの使い回しやら、それはもう、あらゆる手を使って。 で、なんとか124バイトの枠内に収めました。

Z80変態プログラム

で、できたものがこれです。 これから先は変態プログラムです。 よい子は見てはいけません。

SDDRV_DI  = 0x10		; output, pin8
SDDRV_CS  = 0x02		; output, pin7
CMD_READ	= 17 | 0x40	; command for read
REG		= 0xa0		; I/O port AY-3-8910 register latch
WRITE		= 0xa1		; I/O port AY-3-8910 write
READ		= 0xa2		; I/O port AY-3-8910 read
REG_SEL		= 0x07		; AY-3-8910 I/O select
REG_IOA		= 0x0e		; AY-3-8910 I/O A (input)
REG_IOB		= 0x0f		; AY-3-8910 I/O B (output)

	.org	0x4000
	.db	0x41		; 'A'
	.db	0x42		; 'B'
	.db	0x04
	.db	0x40		; start from 0x4004

	;; from 0x0083, Z=1, Cy=0, StackTop=0x0084
	;; A=0x42, B=0x00, C=0x3d, D=0xfb, E=0x61, H=0x40, L=0x04
_boot_start::
	ld	de, #0x0f08	; REG_IOB, counter
	ld	a, #REG_SEL	; 0x07
	out	(#REG), a
	rrca			; 0x83
 	out	(#WRITE), a	; setup AY-3-8910 I/O
	ld	a, d		; 0x0f
	out	(#REG), a
	ld	a, #(SDDRV_DI | SDDRV_CS) ;0x12
 	out	(#WRITE), a
_boot_init_loop:
 	out	(#WRITE), a	; DI | CS
	inc	a
 	out	(#WRITE), a	; DI | CS | CLK
	dec	a
	djnz	_boot_init_loop
	call	_boot_cmd	; H=0x40 (reset), H is set by caller
	inc	h
_boot_init_cmd1:	
	call	_boot_cmd	; H=0x41 (init)
	dec	c
	jr	nz, _boot_init_cmd1
	ld	h, #CMD_READ
	call	_boot_cmd	; H=0x52 (read)
	call	_boot_wait

	ld	h, #0xe2	; L=0
_boot_read_loop:
	call	_boot_bytein
	ld	(hl), c
	inc	l
	jr	nz, _boot_read_loop	; fall through

	;; AFBC________
	;; out C=input byte, B=0, A=0or1
_boot_bytein:
	ld	b, e
_boot_bytein_loop:
	;; 8 times of bit read
	ld	a, d		; 0x0f
	out	(#REG), a
	inc	a
	out	(#WRITE), a	; DI
	inc	a
	out	(#WRITE), a	; DI | CLK
	ld	a, #REG_IOA	; 0x0e
	out	(#REG), a
	in	a, (#READ)	; if A[0]=1, then data=1
	rrca			; A[0]->CY
	rl	c		; cy<-[7<-0]<-cy
	djnz	_boot_bytein_loop
	ret

	;; AFB_________
	;; in C=output byte
	;; out B=0, A=0x01/0x11
_boot_byteout:
	ld	b, e
_boot_byteout_loop:
 	ld	a, d		; 0x0f
 	out	(#REG), a
 	inc	a		; 0x10
	rlc	c
	jr	c, _boot_byteout_data
	xor	a
_boot_byteout_data:
 	out	(#WRITE), a	; (DI)
	inc	a
 	out	(#WRITE), a	; (DI) | CLK
	djnz	_boot_byteout_loop
	ret			; B=0, A=0x01/0x11, Cy=0, Z=0

	;; AFBC___L____
	;; in: H=cmd (must have 0x40 offset)
	;; out: C=result+1 (1, 2, 0xff), B=0, L=0, A=0x00/0x01, Z=0, Cy=0
_boot_cmd:
 	ld	c, #0xff
	call	_boot_byteout	; dummy
	ld	c, h		; A=0x11
	call	_boot_byteout	; cmd
	ld	c, b		; 0x00
	ld	l, #0x04
_boot_cmd_loop:
	call	_boot_byteout	; arg
	dec	l
	jr	nz, _boot_cmd_loop
	ld	c, #0x95
	call	_boot_byteout	; CRC (for CMD0)
_boot_wait:			; L=0, A=0x11
	call	_boot_bytein
 	inc	c
	ret	nz		; bytein != 0xff (0, 1, 0xfe), Z=0
	jr	_boot_wait

実際にはプログラムは122バイト(全体で126バイト)で済んでいます。 なお、タイムアウト判定を省略しているので、正常にSDカードが挿さっていないと無限ループします。 そのチェックは容量内ではできませんでした。 また、セクタ0の最初の256バイトのみ読んでいます。

まぁ、言うほど変態チックじゃないかな?

動かしてみると、正常に読んでいるため、20MHz動作なら問題ないみたいです。