標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第37回]

●まずは、メモリテストから始めましょう

ここ2〜3日、大急ぎで、ほとんど結果のみお知らせしてきました。
とりあえず簡単な動作テストのみ行って、期待通りに動作することが確認できましたので、あとはじっくり落ち着いてテストすることにいたします。
ということで、駆け足で飛ばしてきてしまったところを、あらためて説明していくことにしましょう。

第35回]で、即席で作ったデバッグ回路の回路図と写真をお見せしました。
まずはこの回路について見ていくことにいたします。
あ。また戻るのも面倒ですねぇ。もう一度回路図をお見せします。


メモリボードとして利用したのは、当社製品ZB21Kの基板です。ちょうど手ごろだったので利用することにしました。
32KBのSRAM62256は日立の品名ですが、もうとうの昔に製造中止になってしまいました。
いま使っているのは、輸入品です。ピンコネクションや動作は同じですので、”62256”と言うことにします(62256互換とはいえ、今の石は当時の62256などに比べると、アクセスタイムはめちゃめちゃ速いです)。
端子番号は面倒なので、省略、です。

この回路基板でなにをするか、というと、まずメモリにプログラムを書いておいて、次に今回作ったCPUボードでそのプログラムを実行させ、最後にその結果をメモリから読み取ろう、というテスト作業をします。

なんたってCPUボードなのですから、プログラムを実行させてみないことには、まったくテストにも何にもなりません。
プログラムはメモリに書いておかねばなりません。
いずれ将来全部の基板が完成したあかつきには、ROMも実装して、スタンドアローンで動作させてみたいものですけれど、それは先の話。今はRAMがあれば十分です。というより、RAMでなければ、ことが面倒になるだけです。ここはRAMが必須です。

CPUボードは”8080互換”ですからアドレスはA0−A15までの64KBをアクセスできます。
しかし、今回はテストですから、そんなにたくさんのメモリがあったって仕方が無いですし、配線するのも面倒なので、A8−A15の上位8ビットは無視して、A0−A7の下位8ビットだけを有効にしています。
アクセスできるアドレスは0000〜00FFの256バイトです。

テスト回路として必要なのは、このメモリ基板に、今回作ったCPUボードと、そのメモリ基板やCPUボードを自由に制御できるデバッグ用回路(当社のBASIC制御基板、ZB25K)を同時に接続しておいて、ZB25Kからメモリへのプログラム、データの読み書きと、CPUボードからメモリへのプログラム、データの読み書きをそれぞれ、ZB25Kからの制御下で必要に応じて行える、機能です。

というと難しいようですが、回路にしてしまえば、こんなに簡単になってしまいます。
図の左側はBASIC制御ボードZB25Kの82C55に接続されています。
82C55はプログラマブルな8ビット×3ポートのI/Oポートで、入力/出力の向きをプログラムで指定することができます。

図を見ると、アドレスバスA0−A7とデータバスD0−D7がCPUボード側とZB25K側(82C55)との両方につながっています。
きちんとコントロールしないと信号がぶつかってしまいます。
ZB25Kがメモリをアクセスするときには、CPUボード側のアドレス線、データ線、制御線はハイインピーダンスである必要があります。逆にCPUボードがメモリをアクセスするときには、ZB25Kがそれを妨げてはいけません。その間はZB25K側がハイインピーダンスである必要があります。

こういうアクセス方式をDMA(ダイレクトメモリアクセス)といいます。
8080にはそのための制御線、BUSRQとBUSAKがあるのですが、ここではそんな面倒くさいことはやらず、もっとダイレクトにCPUボードのRESET信号を制御することでやってしまいます。

RESETがアクティブな間、CPUボードの全ての出力はハイインピーダンスになりますから、RESETさえアクティブにしておけば、ZB25Kは自由にメモリをアクセスすることができます。
ZB25Kがメモリに対して必要な作業を完了したら、82C55のポートの向きを入力にすると同時に、RESETをハイにすれば、CPUボードが動き出して、メモリに書かれたプログラムを実行してくれる、わけです。

回路図でMEMRD、MEMWRに対する82C55の出力PC4、PC5が74HC126によるスリーステートの反転出力になっているのは、82C55がポートの向きを設定するたびに、(向きを変更しない出力ポートの)出力までリセットされてL出力になってしまうという、まことに困った仕様に対する対策のためです(こうしておかないと、ポートの向きを変えるたびに、WR信号が出てしまう)。
RD信号はもとから配線があったので、オマケです。
74HC126を使ったのは、利用したZB21Kに74HC126の回路がついていたから、それを利用しただけで、もちろんここは、74HC05で構いません。

回路を作ったら、念のため、正しく機能するかどうかを確認しておく必要があります。
まずは、肝心のメモリテストです。
0000〜00FFに正しくアクセスできて、リード、ライトできるかどうかのテストです。
BASICなら簡単です。
テストしたときのログをお見せします。
こちらをクリックするとテキストファイルが開きます。

BASICのいいところは、プログラムが理解しやすいところです。
最初にまず、アドレス00〜FFに、00、01、02…、FE、FFと順番にデータを書いて行って、次にそれをまた00〜FFの順に読み出して、アドレスとデータをPRINT文で表示しています。
間違い無く、読み書きできていますね。

●いよいよお待ちかね、の本番テスト、です

その前に。
今回製作した基板は全3枚組のうちの、最初の1枚です。ボードの上には、クロック回路、プログラムカウンタ回路、外部入出力回路、プログラム解読(OPコードフェッチ)回路、レジスタ回路、のほかには、命令回路としては、MOV、MVI、HLT(これは必然的副産物です)しかありません。

ですけれど、たったMOVだけ、ということなかれ、です。
8080のマシンコード、00〜FFの256命令(一部未割当命令があるので実際は256よりも少ない)のうち、なんと25%、実に1/4をMOVだけで占めているのです。
MOVはレジスタ間、レジスタメモリ間のデータ転送なので、他の命令に対しても基礎となるべき動作であると言えます。ここがしっかりと動けば、「はじめの1歩」は成功したと言えるでしょう。

●最初はクロックを入力して1マシンサイクルずつ実行

いきなり実行しても、あっという間に終わってしまい、途中の動きを確認することができません。
そこでパソコンのキーを押すたびに、1クロックパルスを出力するようにBASICでプログラムしておいて、1マシンクロックずつ動作させてみました。
BASICプログラムと、実行の結果を記録したログをお見せします。
こちらをクリックするとテキストファイルが開きます。

BASICプログラムの説明です。

30 DATA $26,$00,$2E,$07,$3E,$76,$77,$AA

メモリに書き込むマシン語プログラムです。
メモリには次のように書き込まれることになります。
マシン語コードだけでは、何がなんだかわからないので、後ろにニーモニックをつけて示します。
0000 2600     MVI H,00
0002 2E07     MVI L,07
0004 3E76     MVI A,76
0006 77       MOV M,A
0007 AA       ”AA”

これはどういうプログラムかというと、まずHレジスタに00を、次にLレジスタに07を入れます。
次にAレジスタに76を入れたあと、Aレジスタの値(つまり76)を、メモリに書き込みます。
何?それ?わからないよー。

解説します。
8080はメモリをアクセスするアドレスを直接指定する方法のほかに、Hレジスタの値をメモリアドレスの上位8ビット、Lレジスタの値を下位8ビットとしてメモリをアクセスすることができます。
このように直接メモリアドレスを指定する代わりに、レジスタの値によって示すようなアクセス方法を間接アドレッシングといいます。
ニーモニックでMと示したメモリアドレスは、HLレジスタの値で示されます。
Hに00、Lに07を入れたということは、MOV M,AでAレジスタの値が書き込まれるメモリアドレスは0007番地になります。
0007番地には、CPUがプログラムを実行する前に、適当な値(ここではAA)をいれておきます。
すると、CPUが正しく命令を実行すると、0007番地の内容はAAから76に書き変えられるはずです。
CPUを走らせたあとで、もう一度メモリを読んでみて、0007番地が76になっていたら、CPUが正しく命令を実行した証拠になります。

実は、このテストにはまだ続きがあります。
CPUによって、0007番地に書き込まれるはずのコード、76はHLT命令なのです。
CPUは0006番地のMOV M,Aを実行して、0007番地に76を書き込みます。
しかし、0007番地はデータアドレスとしてアクセスするだけなので、プログラムの実行の流れは変わりません。
今回は目的があってわざと0007番地を選んで76を書き込むようにしていますが、0007番地に書き込む代わりに別のアドレス、たとえば0050番地に書き込むようにしたとしても、0006番地のMOV M,Aの次に実行されるのは、順序として次の0007番地になります。

だからこそ、次に実行されるように、わざわざ最後のMOV命令の次のアドレスに76を書くようにしたのです。
プログラムカウンタが0006まで進むと、CPUは0006番地のMOV命令を読み、その命令にしたがって0007番地に76を書きこみます。
次にプログラムカウンタが+1されて、0007になると、CPUは次の命令として、自分がデータとして書き込んだばかりの76を、今度は命令として読み出して実行しようとします([注意]プログラムカウンタの値が0007になるのは、0007番地に対するMOV命令が実行されたからではなくて、ただ単にプログラムカウンタが+1されたからです)。
ところが76はさきほど書きましたようにHLT命令ですから、そこで停止してそこから先へは進まなくなります。
ここから先には命令が書いてありませんから、どんどん先まで進んでもらっては困るので、それを停止させるために、わざと最後に76(HLT命令)を書くようにしたのです。
同時にCPUの動作テストとしての役も果たせますから、一石二鳥です。

BASICプログラムは、まず、メモリにマシン語命令を書き(行番号40〜70)、念のため最初から書いた内容を読み出して確認し(行番号80〜110)、そのあとRESETをHにして、リセットを解除しますが、CPUクロックとしては外部クロックセレクトをイネーブルにしていますから(EXCLKE)、いきなり実行はされずに入力される外部クロックにしたがって実行されていきます。
外部クロックは82C55のPC0から出力されます。

OUT $83,1で外部クロックがHになり、OUT $83,0で外部クロックがLになります。
キーボードの”Z”を押すたびに、外部クロックがH、Lと変化し、1パルスがCPUボードにCPUクロックとして与えられます(行番号120〜190)。
”Z”キーを押しながらCPUの動作をモニタし、HLT命令まで実行されたところで、”M”キーを入力します。
”M”キーを入力すると、RESETをLにしてCPUボードの外部アドレス出力ラインを非アクティブにしておいて、メモリの中身を読み出します(行番号200〜280)。

プログラムリストの表示の次に、RUNコマンドで実行した結果の記録があります。
RUNのあと、00〜07まで書き込んだデータの読み出しを行っています。
そのあとのEXCLK ONで、外部クロックモードになり、外部クロックとして”Z”キーを押すたびに1クロックをCPUボードに与えていっています。
CPU RESET & MEMORY CHECKで、再びメモリを読み出しています。
最後の07番地がAAから76に書き変えられていることがわかります。

●今度はいよいよ、本番中の本番、通常のクロック(4MHz)で一気に実行させます

BASICプログラムと、実行の結果を記録したログをお見せします。
こちらをクリックするとテキストファイルが開きます。
さきほどのプログラムと基本動作は同じです。
さきほどはCPUを実行させるのに、外部から1パルスずつ与えながら、ステップ動作をさせました。
今度はリセットを解除して一気に実行させます。
実行は一瞬で終わりますが、CPUが実行を完了するのに十分なだけの時間をウェイトした後に、メモリの中身を読み出しています。
今回の実行によっても、アドレス07の中身はAAから76に書き変えられていて、通常のスピードでも正しく命令が実行されたことがわかります。

最後のHLT命令(76)を実行して停止した状態のCPUボードの写真です。

Hレジスタに00、Lレジスタに07が、Aレジスタには76が保持されています。
アドレスバス出力は0007になっており、外部データバスには0007番地のメモリの内容76が表示されていて、その値がOPコードレジスタにラッチされ、同時に内部バスにも流れています。

写真右上にLEDが4個と集合抵抗が追加されているのが、気になりませんか?
これは命令ごとにカウントアップされるマシンクロックカウンタの出力表示のために追加したものです。
デバッグを進めるうえでどうしても欲しくなって追加しました(うーん。これはあるといいですねぇ)。
マシンクロックカウンタは今回のシステムのキモ中のキモです。全ての動作はこのカウンタに依存しています。
マシンクロックカウンタについては、回路の説明を進める中で、多分近日中に紹介することができると思います。
2008.8.15upload
2008.8.16一部加筆

前へ
次へ
ホームページトップへ戻る