前回お手製の「DMA3重塔」を使い、ラズパイPicoのMicroPythonで、Z80(TMPZ84C015BF)のバスの制御権を奪ってプログラムROMの内容のダンプを試みました。しかし何か変。ちゃんとダンプできてる感じがしない。今回再トライ、正常にダンプできるようにはなりました。しかしイマイチ釈然としないです。
※「MicroPython的午睡」投稿順 Indexはこちら
まずはノスタルジーに浸るために購入させていただいた「Z80」ボードへのリンクはこちら(秋月電子通商殿)。多分在庫販売の一品。なお、申し訳ないことに当時最速であったらしい12MHz動作用のクリスタルを勝手に4MHzに「デチューン」しています。
ボードはZ80に加えてZ80CTC/SIO/PIOなどのザイログ純正のペリフェラル群をワンチップ化したTMPZ84C015BFを搭載した「名刺サイズ」のボードです。私にとってのノスタルジックなZ80は残念ながら純正品ではなく、NECのμPD780CD-1(NEC製のZ80互換チップ)を頭にいただくPC-8001だったりするので、まずボードサイズの小ささに驚いたりします(いつの時代の人だ。)購入したボードも実際には30年くらい前の設計のボードです。それでも90年代前半には32KバイトのROM1個、RAM1個で64Kバイトの主記憶を構成できています。その昔のPC-8001はといえば、標準のRAM容量16Kバイトでしたが、16KbitのDRAMを8個で構成してました。さらに空のICソケットが8個並んでいました。当時、私は秋葉原で16KbitのDRAM8個を購入(受給ひっ迫で入荷数か月待ちだった)し、PC-8001のDRAMソケットに差し込んで主記憶DRAMを32Kバイトに拡張した記憶があります。16KbitDRAMが16個ならぶといっちょ前のコンピュータって感じがしました。ちなみに16Kbit DRAMの製造ではインテルが首位。そのころはまだメモリ主力のメーカでした。パッケージ材料の微量の放射性物質でビットがひっくり返る問題はインテルが見つけて解決した筈。
閑話休題。さて、前回の0番地付近のメモリダンプ(UV-EPROM)試行結果、納得がいきません。昔は16進ダンプをみればアセンブラが頭に浮かびましたが、流石に忘れてます。でも、0番地あたりにはリセットとリスタート(RST)命令のためにジャンプ命令が置かれている筈。
DMA3重塔の結線ミスか、それともMicroPythonのコーディングのバグか、ゆるゆると調べてみました。
誤っているのが、アドレスなのか、データなのか、それとも制御手順なのか絞れていないです。まずは動作確認用に「この番地にこんなデータがある」という「正解」を実機の上で見つけることにいたしました。『冥界のLSI(9)』で Analog Discovery2のロジアナ機能を使って、モニタROMでLチカ中のZ80の「ウエイトループ」を読み取って「ハンド逆アセンブル」してみています。ただ、その時はAnalog Discovery2のロジアナ機能は16chしか信号線がとれないため、アドレスは下4ビットだけ取得でした。またZ80ボードに直結で観察していました。
今回はデバッグのため、DMA3重塔のテッペンに出ている「配線通過の」アドレス、データ端子に接続して観察します。まずはここのアドレス16ビットをフルに取り出すことにいたします。ターゲットのモニタROMはシールで型番が見えませんが27256(32Kバイト容量)だと思われるので、アドレス15ビット+MEMREQ信号1ビットで観察します。結果、このループは0x18E番地から0x192番地(80系標準のインテル式表記であれば、18Eh番地から192h番地)にあることが分かりました。アドレスバスの結線間違えてなかったみたい。今度はデータ8ビット+アドレス下7ビット+MEMREQ信号1ビットでデータバスも確認しました(アイキャッチ画像。)あれあれデータバスも問題なさそうだね。
ご存じの通り(若者、いや中年でも知らない?)Z80にはDRAMリフレッシュサイクルという「凄い便利な」(といってこのボードのようにROMとSRAMで主記憶が全部できてしまえば無用の長物)機能があり、そいつが挟まってくるので、アイキャッチ画像のようなシーケンスの解読には注意が要ります。リフレッシュ信号も観察すれば容易に判別できるのですが、信号本数足らないので割愛せざるを得ません。アイキャッチ画像のシーケンスの場合アドレスh54からインクリメンタルなアドレスがメモリからのフェッチに順番に挟まっているのが、DRAMリフレッシュサイクルです。
たかだか5番地分ですが、検証用の「正解」が決まりました。こいつと一致する結果が得られればOKというテキトーです。いよいよラズパイPicoのMicroPythonでZ80にBUSREQ(DMAリクエスト)をかけ、バスの制御権を奪ってメモリダンプを行ってみます。あれあれ、メモリ・ダンプ成功してなくない?
前回のMicroPythonコードから変更したのは、以下のメモリダンプの関数と、やたら時間を食っている「10秒待ち」をコメントアウトしただけです。
def testMemoryRead(adr): letADRbusOutput() letDATAbusInput() enableControl() for j in range(1024): print("0x{0:04x} : ".format(adr), end="") for _ofs in range(32): outputADRbus(adr) print("{0:02x} ".format(memoryRD()), end="") adr += 1 print(" ") letADRbusInput() disableControl()
Thonny IDEから見えたメモリ・ダンプ結果はこんな感じ。0番地にちゃんとJMP命令があるし、そのとび先のコードも予想どおりな感じ。使っていない番地はFFh(UV-EPROM)だし、RST命令のところも「それなり」、そして「お手本」の5番地分、ロジアナ機能で観察したのと同じバイト列が読めてます。OKだね。
何で前回うまく行かなかったのか、考えてみたのです。思いついたのは、
IOExpanderがRESET後初期値でない状態で操作していた
ということです。何度も動作試行させながら動かしていたので何か中途半端な設定になっていたままトライしてしまったか?IOExpanderのリセット端子をラズパイPicoから操作できるようにボード側面に出してはあったのです。しかし、パワーONでRESETかかるから、いいんじゃね、という感じで省略していました。
ラズパイPicoのMicroPythonの実行を途中で打ち切ったりするとIOExpanderとの通信が途中で切れて、挙動が不審になります。IOExpanderはラズパイPicoとは別電源のZ80と同じ電源で動いています。Z80側の電源を入れなおすとIOExpanderにもパワーONリセットがかかります。この状態でラズパイPicoからダンプを試みるとOK。ううむ、状況証拠ではあるわな。