なんちゃって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バイトの枠内に収めました。
で、できたものがこれです。
これから先は変態プログラムです。
よい子は見てはいけません。
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動作なら問題ないみたいです。