32KByte ROMカード編からの続きです。以下の話はPC-6001初代機に限定しますので、mkII以降のことは忘れてください。
PC-6001の拡張コネクタにつないだフラッシュメモリ[EN29F002T]のROMカード(32K ROM)の回路はこのようになりました。色々と試行錯誤した結果、ずいぶんとシンプルにまとまりました。
ここから回路に手を加えて、PC-6001からフラッシュメモリに書き込み出来るようにしたいわけです。
フラッシュメモリ側の書き込み端子はWE端子で、上記の回路図でのPGM端子(変換基板の27C020)に該当します。
PC-6001側の書き込み処理に使えそうな端子は、WRとWEの2つです。WRはZ80のWR端子で、書き込み命令を使うと変化します。メモリだけでなくI/Oポートへの書き込みでも変化します。WEは、DRAMのWE端子へ繋ぐ端子になります。DRAMは、WEの状態によって読み込み/書き込み動作が決まります。WE端子は、PC-6001本体側からメモリへの書き込み時に変化するように回路が組まれていますから、この端子を使う事にします。ただ、使いはしますが、後述する理由により、PC-6001とフラッシュメモリのWE端子同士を直接はつなげ(られ)ません。
フラッシュメモリ[EN29F002T]のCEがLOW、PGM(WE)がLOW、OEがHIGHの時に書き込み処理となります。ただし、フラッシュメモリへの書き込みは通常のRAMのようにはいきません。フラッシュメモリへの書き込みは、フラッシュメモリへのコマンド送信という意味になります。
また、フラッシュメモリに書き込む前にフラッシュメモリの内容を消去しておく必要があります。ここでの消去というのは、フラッシュメモリの内容を0xFFにするという意味です。つまり、全てのビットを1にします。この状態から、必要なビットを0に書き換えるのがフラッシュメモリへの書き込み処理です。書き込みたい内容が0xFFなら何もする必要が無く、0x00にしたいのであれば、全てのbitを0にします。EN29F002Tでは、書き込み手順に従って、書き換えたいアドレス(00000H-3FFFFH)と書き込みたいデータ(1バイト)を指定すれば書き込まれますからビット単位でどうこうする必要はありません。
書き込み手順をEN29F002Tのデータシートから引用します。
この表の、Byte Programという箇所が書き込み手順です。4段階の手順で、指定アドレスに指定データを書き込んでいきます。0x555に0xAA、0xAAAに0x55、0x555に0xA0、そして最後に書き込みたいアドレスに書き込みたいデータを指定します。端子レベルでは、CEとWEとRDをHIGHにしてから、アドレス(A0-A17)とデータ(D0-D7)をセットし、その後、CEとWEをLOWにし、再びHIGHという手続きを4回繰り返します。
書き込み処理には時間がかかります。その間、データ端子(D0-D7)は結果を返す用途に使われるので、データ端子の変化を監視します(データシートに手順が書いてあるので省略)。
書き込み手順に書かれているアドレスですが、困ったことにデータシートのページによって内容が違います。この表では、0x555と0xAAAとなっていますが、データシートの他のページでは0x5555,0x2AAAとなっていて、その手順に従って書き込み方を説明しているページもあります。[ファミコン用の自作ソフトを作って遊ぼう][H8/3069ボードの外部FLASH ROMへの書き込み]
実際に動作を確認してみたところ、0x0555と0xAAAでいいみたいです。(どうやらA0-A10のビットだけでいいようです)
先に説明したとおり、書き込み前にはフラッシュメモリの内容を消去しておく必要があり、その方法は上記の表のChip EraseもしくはSector Eraseコマンドです。
PC-6001拡張コネクタのWE端子とフラッシュメモリのPGM(WE)端子をつなげてどうにかしたいわけですが、直接つないでみたところ、ダメでした。
まず、PC-6001のWE端子の変化を調べてみたところ、内部RAMと外部RAMだけでなく、PC-6001内部のROM領域(BASIC ROM/0000H-3FFFHや外部ROM領域/4000H-7FFFH)への書き込みにも反応しました。これはうれしい話で、フラッシュメモリを書き換えるにはアドレスに0x555と0xAAAを指定する必要があり、PC-6001ではROM領域なのでROMへの書き込みとなってしまうのですが、WE信号が反応するということは、フラッシュメモリ側で反応させることができます。
問題はCS端子にありました。当初の回路は、32KByte ROMカード編の最初の回路図のように、RAS2/EXCASをRAM(DRAM)への書き込み判定に使っていたのですが、もう少し詳しく調べたところ、PC-6001の0000H-7FFFHへの書き込みではRASとCASが同時にはLOWにならないのです。8000H-FFFFHへの書き込みではRAS/CASが同時にLOWとなるので、フラッシュメモリの8000H-FFFFHへの書き込みには反応します。つまり、0000H-7FFFHへの書き込みではRAS/CASは当てにならないというわけです。
また、PC-6001のメモリ空間では、C000H-FFFFHが内部RAMに割り当てられています。ここの領域にフラッシュメモリが重なっていると内部RAMとフラッシュメモリの両方に書き込み動作をするので気持ちの悪いものです。なので、0000H-BFFFHへの書き込みがあったらフラッシュメモリへの書き込みと判断し、ついでにRAS/CASが当てにならない事と併せて、この判定にはA15/A14/MREQ/WRの信号を使う事にします。
メモリへの書き込み時にA15とA14が共に1(HIGH)の場合、それはC000H以降への書き込みです。A15とA14が共に1(HIGH)なら、フラッシュメモリのCSを1(HIGH)に、それ以外の組合せなら0(LOW)にすればよいのでAND(LS08)を使います。
MREQとWRが共に0(LOW)の時にメモリへの書き込みとなりますが、その判断は便利なことにWE端子がやってくれてるわけですから、最終的にはA14/A15/WE端子だけで0000H-BFFFHへの書き込み判定ができる(CEを有効と判断できる)わけです。
ただ、最初の回路だと、ANDが一つ足りない計算になり、また、フラッシュメモリのCEを有効にすると同時にWEも有効にする必要があるのでOR用の回路と配線が増えます。そんなわけで、よりシンプルなこのページの最初の回路の方を改めて動作確認して、これに書き込み回路を加えたものがこちらです。
Z80(PC-6001)メモリ空間とフラッシュメモリの関係は最終的にこうなりました。0000H-3FFFHへの書き込み先はフラッシュメモリになりますが、読み込みはPC-6001内部ROM(BASIC ROM)からになってしまうので、この領域だけはフラッシュメモリに書き込んだ内容をPC-6001側から確認する手段はありません。
PC-6001をフラッシュメモリから起動し、プログラム本体をRAMにコピーしてからプログラムの制御をRAMに移し、フラッシュメモリの全消去(chip erase)を実行します。このプログラムは起動後、自動的に消滅する・・・。
どうということもなく動きました。2,3秒ほどで全消去終了します。
このプログラムでは、エラーチェックをサボっています。ただの手抜きです。また、フラッシュメモリにコマンドを送り、フラッシュがコマンドを実行し終えた後は自動的にリードモード(通常の読み込みモード)になるので、PC-6001側でコマンドが終了したかどうかを監視しつつ、割込みや画面表示をしていると、知らぬ間にコマンドが終了していることがありえますから、コマンド終了監視は難しいような気がします。ただ、フラッシュメモリを全消去するということは、フラッシュメモリが0xFFで埋まるということなので、元々が0xFFではない適当なアドレスの内容を読み込みしてみて0xFFになっていたら全消去終了と見なしてもいいんじゃないでしょうか(雑だなー)。フラッシュメモリは消去終了後に通常の読み込みメモリとして動作し始めます。
テストプログラムを実行してフラッシュが全消去されたかは、フラッシュメモリをROMライターにつないで中身を確認しました。もちろん、PC-6001側でフラッシュメモリの全アドレスの内容が0xFFになっていたら消去正常終了として判断するのが本来の正しい手順だと思います。
自身のプログラムをRAMに移し、フラッシュメモリを全消去した後に、PC-6001内部のBASIC ROM 16KByte分(0000H-3FFFH)をフラッシュメモリの8000Hからの領域にコピーするプログラムです。この辺は色々な方々のプログラムを参考にさせて頂きました(実はまだ書き込み完了チェックの意味がわかってなかったりします・・・)。
結果は...
書き込んだフラッシュメモリの内容をROMライタで吸い出し、既にあるBASIC ROMと比較してみたところ、問題なく書き込みされていました。
このテストプログラムでは、フラッシュメモリの8000HからBFFFHへの書き込みとなっていますが、0000H-3FFFHと4000H-7FFFHへの書き込みも確認済みです。
BASIC ROMから16KByteを読み込んでフラッシュメモリに書き込むのに要した時間は70秒ほどでした。速くはないですが、フラッシュメモリをPC-6001から書き換えできるのは便利ですし、色々なことに応用できますね。
4000Hからの起動プログラム自身も消してしまうのは実用性が低いのでなんとかしたいところです。
もったいつけてたわけではありませんが、EN29F002TにはSector Eraseというコマンドがあります。これは、フラッシュメモリのメモリ分割し、指定した領域のみを消去するコマンドです。フラッシュメモリの分割方式はデータシートに記載されています。
EN29F002Tという型番の末尾のTは、この表の左側(TOP)を表しています。つまり、Z80メモリ空間=フラッシュメモリ空間の0000H-FFFFHはSECTOR0に該当するため、Sector Eraseで0を指定するとPC-6001からみたら全消去と一緒になるのでSector Eraseは意味を成しません、残念。EN29F002Bを調達すればいいのですが、元々が入手しやすく安価なEN29F002Tを使おうというところから始まったので、本末転倒な感じがあります。
フラッシュメモリのSector3からSector6はサイズが32,8,8,16と別れているので、PC-6001からみた時にセクタ単位での消去に意味があります。フラッシュメモリへの書き込み(コマンド送信)は、0x0AAAや0x555といったアドレスに書き込むというもので、どうやらコマンド書き込み先アドレスはA0-A11(A10)で判断しているようですから、それならA16/A17はなんでもいいように思えます。つまり、A16/A17をGNDではなく+5Vに接続して、Z80メモリ空間の0000H-FFFFHをセクタが細かく分割されているフラッシュメモリの30000H-3FFFFHに割り当てるのです。Z80から0x0AAAへ書き込むとフラッシュメモリ側では0x30AAAとして認識されるという仕組みです。ですが、実際に回路を変えて試してみたところ、これはダメでした。残念。
ここまでくると、あとはバンク切り替えです。64KByte単位でA16/A17を切り換えるのであれば、2bitのD-FFとI/Oデコードがあればいいので、IC2個程度で256KByte ROM&部分消去と書き込みを手に入れることが可能になります。配線数もさほど多くないですし、おそらくそこが、これまでの一連のフラッシュメモリで遊ぶ編の終着点になるのだと思います。ただ、面白みはないので作りません。
PC-6001は起動時にRAMが増設されているかどうか確認するため、BFFFH番地にD9Hを書き込み&読み込みをしていて、この処理は回避できません。これがフラッシュメモリへのコマンド送出になってしまいますが、EN29F002Tのデータシートをみると、不適切なコマンドは処理しないと記載されているので問題ないと思います。
よくわからないのが、EN29F002TのコマンドF0Hです。表の最初にあるRead/Resetコマンドなのですが、これの意味するところがわかりません。任意アドレスに0xF0を書き込まなければいいので、これも問題にはならないと思います。
PC-6001mkIIで使えるかどうかは未確認です。少なくとも、A14/A15で書き込み先を判別しているため、PC-6001mkIIの外部RAM64KのうちのC000H-FFFFHを通してフラッシュメモリへの書き込みができないことになります。逆に考えると、この制約(回路)を外してしまえば、PC-6001mkIIの外部RAM64KByte全てのフラッシュメモリ領域に書き込みができるようになるはずです(74LS32が不要になり、WEを直接接続できるので回路もシンプルに)。ただ、PC-6001mkIIのメモリコントローラが、どのように内部RAMと外部RAMへの書き込みを判別して出力しているのか調べていないので(WE以外にMPXを使う?)、その辺はいずれ。