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

復活!CP/M ワンボードマイコンでCP/Mを!
CP/MがTK−80互換のワンボードマイコンの上で復活します
ND80ZVとMYCPU80の上でCP/Mが走ります

[第285回]


前回の訂正です。
Z80で追加された命令コードのうちCBと書くべきところをうっかりCDと書いてしまいました。
読者の方からメールでご指摘をいただいて、誤りに気が付きました。
CDはCALLですものね。もうぼけてしまっております。
さっそく訂正をいたしました。
AM様。ご指摘いただき有難うございました。
今後ともよろしくお願いいたします。

●アドレスセット、インクリメントの仕組みについてもう一度

前回はIMSAI8080のフロントパネルの回路を踏襲したE−80(仮称)ミニコンの回路がCPUがZ80系(Z8S180)であるがために誤動作する可能性があります、と書きました。
それが一体どういうことなのか、について説明をはじめます前に、今一度E−80(仮称)ミニコンのフロントパネルのアドレスセット、アドレスインクリメントの仕組みについて整理しておくことにいたします。

すでに説明しておりますように、その仕組みの基本的な考え方は、CPUを停止させておいて、データバスに強制的に命令コードを書き込みながら、CPUを1〜3ステップ動かすことで、アドレスセット、またはアドレスインクリメントを実現するというものです。
データバスにJP命令のコードC3Hを乗せ、続いてパネルスイッチの下位8ビット、上位8ビットを乗せることで、CPUにパネルスイッチで指定したアドレスにジャンプさせ、結果としてアドレスバスにパネルスイッチの値を乗せることができます。
またデータバスにNOP命令のコード00Hを乗せて、それをCPUに実行させることで、現在表示されているアドレスバスの値を+1することができます。

ここでもっとも基本的なことは、操作に先立ってまずCPUをWAIT信号で停止させておかなければならない、ということです。
E−80(仮称)ミニコンをフロントパネルから操作するモード(パネルモード)に設定した状態で起動(電源ONまたはリセット)すると、メモリにまだプログラムが書き込まれていない状態ならばCPUは初期的に暴走状態になります。
E−80(仮称)ミニコンはRAMの内容をバッテリーバックアップしていますから、もしもそれ以前に0000番地から始まる何らかのプログラムが書かれていた場合には、起動すると同時にCPUはそのプログラムを実行します。
いずれの場合でも、フロントパネルからアドレスセットやメモリ内容の読み出しや書き込みなどの操作を行うためには、STOPスイッチを押して、まずCPUを停止させなければなりません。

このときに大切なことは、必ずM1サイクル(OPコードフェッチサイクル)で停止させなければならない、ということです。
CPUを停止させるにはWAIT信号を使います。
CPUの命令は1個以上のマシンサイクルで構成されます。
そして1個のマシンサイクルは数クロックからなります。
各命令のマシンサイクルは必ず命令コード(OPコード)を読み込むOPコードフェッチサイクルが最初に来ます。
OPコードフェッチサイクルだけで終わる命令もありますし、その後にデータを読んだり書いたりするためのマシンサイクルが続く命令もあります。

もともとWAIT信号は速度の遅いデバイスに対して読み書きするために用意されたもので、デバイスの速度に合わせて十分な待ち時間をとれるように、各マシンサイクルの実行中にWAIT信号の入力を検出して、その信号がなくなるまで、現在の状態を継続する、という働きをします。
つまりWAIT信号は、命令のどのマシンサイクルにでも利かせることができるのです。

たとえばOUT (FF),Aという命令の動作を考えてみます。
この命令をマシン語で書くと、D3FFになります。
この命令は3個のマシンサイクルからなります。
最初にOPコードフェッチサイクルが実行され、メモリからD3が読み込まれます。
そのコードは直ちにCPUによって解読され、続いてI/Oアドレスを読み込むためのメモリリードサイクルが実行され、FFが読み込まれます。
最後はI/Oアウトサイクルです。
I/OアドレスFFにAレジスタの値が出力されます。
この3つのマシンサイクルのいずれのタイミングにでもWAIT信号をアクティブにすることで、CPUをそのマシンサイクルを実行中のまま停止(ウエイト)させておくことができます。

以上の説明によって、STOPスイッチによってCPUを停止させるのは、必ずOPコードフェッチサイクル(M1サイクル)でなければならない、という理由がお分かりいただけたことと思います。
E−80(仮称)ミニコンのフロントパネルのアドレスセット、アドレスインクリメントの機能は、STOPスイッチの入力によってCPUがメモリからOPコードを読み込もうとしているところで停止させておいて、横から強制的に命令コードC3または00を読み込ませなければならないからです。

たとえば上のD3FFの例で、CPUがD3を読むタイミング(M1、OPコードフェッチサイクル)ではなくて、次に来るメモリリードサイクルでメモリからFFを読んでいるときに停止させて、C3を読み込ませたとしたらどうなるでしょうか。
その結果は容易に想像がつくと思います。
CPUはD3FFを実行する代わりにD3C3を実行してしまいます。
当然のことながら、C3+パネルスイッチアドレス(パネルスイッチアドレスへのJP)は実行されず、期待に反する結果がパネルLEDに表示されることになるでしょう。

そのように、STOPスイッチの入力によって、CPUを必ずOPコードフェッチサイクルで停止させなければなりませんから、E−80(仮称)ミニコンのSTOP回路にはそのための回路が組み込んであります。
下の図は[第274回]の回路図からSTOP回路のみを取り出したものです。

OPコードフェッチサイクルでは、MREQとM1(およびRD)がアクティブになります。
そのMREQとM1が同時にアクティブになったときにSTOPスイッチの状態が74HC73にラッチされて、同時にそのQ_出力がWAIT信号になります。
以上長々と説明をしてきましたことが、「Z80では不都合なことがおきる」ということの説明の伏線でありますから、皆様、上記の説明をよーくご理解願います。

さて、そこでいよいよ前回の○○○の答えです。

●Z80で追加された命令が問題

誤動作のもとになってしまうのは、Z80で追加された命令群の存在です。
○○○には命令群が入ります。
Z80では8080にはなかった非常に沢山の命令が追加されています。
その追加された命令のほとんどは8080では未定義だったマシン語コードCB、DD、ED、FDで始まります。
たくさんの命令をその4つのコードだけでは表現することはできませんから、Z80はこの4つのコードで始まる命令を2バイトに拡張しました。
2バイトの命令は8080にもありますが、たとえば上で説明しましたOUT (FF),A マシン語コードD3FF は、命令コードはD3の1バイトだけで、FFは単なるデータ部分で命令コードではありません。
これに対してたとえばZ80で追加された命令 IN A,(C) マシン語コードED78 は、EDも78もともに命令コード(OPコード)です。

ここまでの説明をお読みいただいて、察しのよい読者諸賢でしたならば、すでに全ての事情をご理解いただけたことと思います。

さきほどCPUが命令コードを読み込むOPコードフェッチサイクルではMREQとM1がアクティブになります、と書きました。
では、Z80で追加された命令コードが2バイトの命令をCPUが読むときには、いったいMREQとM1はどのように出力されるのでしょうか?

そう。
そのときCPUは2回、MREQとM1をアクティブして、連続する2バイトの命令コードを読み込むのです。
おそらく2度目のM1出力は、先行するCB、DD、ED、FDをCPUが読み込んだときに決定されるのだと思います。
すると。
一体何が問題なのでしょうか。

こういう状況を想像してみてください。
CPUがすでにメモリに書かれているプログラムを(あるいはでたらめに書かれているメモリデータをプログラムだと解釈して)実行しているときに、STOPスイッチを押したら、たまたま先ほど例にあげました IN A,(C) マシン語コードED78 をCPUが読み込んだところで停止したとします。

一番目のOPコードEDを読み込み中にウエイトした場合には、そのEDがC3に置き換えられますから問題は発生しません。
しかしたまたまその次の78を読み込み中に(このときもM1がアクティブになります)ウェイトしたとしたら、一体どういうことがおきるでしょうか?

78の代わりにC3を読み込んだとき、CPUはそれをJP命令だと解読するでしょうか?
そんなことはありえません。
CPUはすでに第一OPコードEDを読み込み済みです。
するとその次にCPUが読み込んだC3はJP命令としてではなく、EDC3という拡張命令として解読されることになります。
その結果は?

実は、Z80にはEDC3という命令コードは存在しません。
Z80の場合、未定義の命令コードでも、おそらくその設計過程で派生的に存在することになった何らかの「隠し命令」として実行されることが知られています。
Z80でEDC3がどのように実行されるのか、試してみたことがありませんので、私は知りません。
E−80(仮称)ミニコンのCPU、Z8S180はZ80互換ですが、このような未定義の命令は実行されずに未定義命令割り込みが発生します。
その結果CPUは現在の実行アドレスをスタックに退避したあと、アドレス0000に無条件にジャンプしてしまいます。
当然のことながら、予期に反してC3+パネルスイッチは実行されず、パネルLEDにパネルスイッチの値が反映されることはありません。

一般にこのようなことが発生する頻度はそれほど高くはないと思われます。
しかし、たとえばプログラムに次のような部分があって、それを繰り返し実行中にSTOPスイッチが入力された場合には、かなりの頻度で発生することが推測されます。

LOOP:IN A,(C)
     JP Z,LOOP

このような不都合な問題を避けるひとつの解決法は、STOPスイッチで停止させたあと、すぐにアドレスセットの操作を行うのではなくて、必ずRESETスィツチを押してCPUをアドレス0000で停止させてから、アドレスセットの操作をするというルールにすることです。
それによってCPUは必ず最初のM1で停止しますから、上の説明のような誤動作は発生しないことになります。

実は、上記の誤動作は実際にロジアナで観測して確かめてあります。
そのロジアナの観測波形もお見せするつもりだったのですが、本日は時間がなくなってしまいました。
次回「ロジアナでとらえた実際の誤動作波形」、必見です。

ワンボードマイコンでCP/Mを![第285回]
2013.1.6upload
2013.1.7誤記訂正

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