昔からZ80をAVRなどでコントロールすることは考えたことが何度かあった。しかしデータバスが8bitで、アドレスバスが16bitで MREQ, RD, WR, RESET, BUSREQ, BUSACKとコントロールするバスが多い。ラッチしてとか、アドレスバスはバイナリカウンタでとか、3ステートのコントロールがとか考えて複雑になりすぎて諦めていた。
ところがZ80-MBC2では思いもよらない方法でこれを回避している(アドレスバスで使っているのは1ビットだけ)
そこでブート部分を簡単に整理してみた。(S220618_IOS-LITE-Z80-MBC2.ino)
メモリは128KB
BANK0, BANK1で32KB毎のバンク
BANK0=Hの場合は通常の64KB
[0]初期状態は
CPU RESET=L、WAIT=L、INT=H、BUSREQ=H という完全停止
メモリ CE2=Hとしてアクセス可能状態
MREQ、RD、WR、AD0はavrから読み込める状態になっている
[1]メモリマップセット
BANK0=H, BANK1=L
[2]リセット(singlePulsesResetZ80())
RESET=Lとしていはいるが、CLKが停止しているのでCPUは実際にRESETされているわけではない。
この状態でクロックを入れる。(RESET=Lで6クロック、RESET=Hで2クロック)
この段階でRESETはHになっている
[3]メモリへ書き込み
スタートアドレスが0なら、そのままスタートアドレスから書き込むが、そうでなければ0〜3バイトにスタートアドレスへのJMP命令を書き込む。
[3-1]メモリへの書き込み詳細(loadHL(BootStrAddr))
・クロックを1回入れる->M1サイクルのT1ステート
・CE2=LとしてメモリをHiZ状態として、データバスに LD HL, のオペコードを書き込む
・クロックを2回入れる->M1サイクルのT2, T3ステート
・AVRのデータバスをinput状態に戻し、クロックを2回->M1サイクルのT4ステート、次のM2サイクルのT5ステート
・AVRのデータバスをoutput状態にし、BootStrAddrの下位8ビットを出力し、クロックを3回->M2サイクルT6,T7,M3サイクルT8ステート
・AVRのデータバスにBootStrAddrの上位8ビットを出力し、クロックを2回->M3サイクルT9, T10ステート
・AVRのデータバスをinput状態に戻しCE2=Hとしてメモリを有効状態とする
[3-2]メモリへの書き込み詳細(loadByteToRAM())
・クロックを1回入れる->M1サイクルのT1ステート
・CE2=LとしてメモリをHiZ状態として、データバスに LD (HL), のオペコードを書き込む
・クロックを2回入れる->M1サイクルのT2, T3ステート
・AVRのデータバスをinput状態に戻し、クロックを2回->M1サイクルのT4ステート、次のM2サイクルのT5ステート
・AVRのデータバスをoutput状態にし、メモリへ書き込むべき8ビットを出力し、クロックを2回->M2サイクルT6,T7ステート
・AVRのデータバスをinput状態に戻し、メモリを有効状態としてクロックを3回->M3サイクルのT8, T9, T10ステート
・クロックを1回入れる->M1サイクルのT1ステート
・CE2=LとしてメモリをHiZ状態として、データバスに INC HL のオペコードを書き込む
・クロックを2回入れる->M1サイクルのT2, T3ステート
・AVRのデータバスをinput状態に戻し、メモリを有効状態としてクロックを3回->M1サイクルT4, T5, T6
[4]クロックの供給
リセットして、クロックを供給して、リセット解除(Hにする)
クロックはAVRのTimer2を使用 (8MHz or 4MHz)
要するに、z80に1バイト書き込みプログラムを強制的に読み込ませ、z80自身にメモリへ書き込みをさせている。このためアドレスの管理やMREQ, RD, WR などのタイミングを含めて制御はすべてz80自身が行ってくれることになる。
その他
メモリのバンクについては、ダイオードを使っている。ちょっとわかりにくかったので調べた。
32KB単位のバンクで128KBメモリなので4つのブロックがある。00000-07FFFが1つ目のブロック、08000-0FFFFが2つ目のブロック...。CP/M3.0は、OSのある上位32KBは変化せず下位32KBだけ切り替えているので、以下のような割当になっている。
※コメント投稿者のブログIDはブログ作成者のみに通知されます