標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第460回]
●MYCPU80のご注文をいただきました
埼玉県草加市のTS様からMYCPU80組立キットのご注文をいただきました。
TS様、ご注文有難うございました。
さっそくパーツの手配をいたしました。
準備ができますまでの間、しばらくお待ちいただきますようお願いいたします。
●Z80 User’s Manualのミスプリント
前回の終わりに「追記」しましたように、最初はいいかげんに飛ばし読みをしていたものですから気がつかなかったのですが、翌日になってから読み直していましたら、引用しました「Z80 User’s Manual」の「RFSH」の説明文にミスプリントがあることに気がつきました。
そのままでは意味が通りませんので念のために説明を加えることにいたします。
その部分を下に再掲いたします。
2行目の終わり近く、「tindicating」と書いてありますが、こんな単語はありません。
英文法とか英作文とかというものは昔から苦手でしたので、こういう場合に本当はどう書くのが正しいのかは定かではないのですが、文意からすると、
@the RFSH signal becomes active indicating that …
というふうにするか、あるいは’t’が最初にありますから、このドキュメントの作成者は、
Athe RFSH signal becomes active to indicate that …
と書くつもりだったのかもしれません。
多分上記@かAのどちらかだと思います。
●RFSH期間の上位アドレスバスに出力されるデータは?
[2010.3.22追記]
前回書きましたように、8080ではうまく動作するステップ回路とほぼ同じ考え方の回路が、Z80ではうまく働いてくれません。
結論から先に書いてしまいますと、その原因はZ80の「リフレッシュ動作」にあるらしいことがわかりました。
Z80にはステップ動作に必要なINTE信号がありませんから、その代わりにROMselect信号を使います。
ステップ動作は、ROMのモニタプログラムからRAMのユーザープログラムに移った直後の1命令をCPUが実行したときに割込み信号が発生することで実現しています。
ですから、CPUがROMをアクセスしているときには、INT信号を発生させるためのD−FFをクリア状態にしておいて、CPUのアクセスがRAMに移ったときにD−FFをイネーブルにすることで、INT信号を出力させるように考えたのです。
ところがRAMをアクセスしているはずなのに、D−FFがクリアされてしまうのです。
Z80はメモリから命令コードを読み込んで実行するOPコードフェッチサイクル(M1サイクル)で、OPコードを読み込んでCPU内部で処理をしているT3、T4のときに、再びMREQ信号をアクティブにするとともにRFSH信号をアクティブにして、アドレスバスに、DRAM(ダイナミックメモリ)のデータ維持に必要な「リフレッシュアドレス」を出力します。
このときは通常のメモリアクセスのようにメモリからデータバスにデータが読み出されてしまわないようにRD信号はアクティブにはなりません。
どうやらこのリフレッシュのときに、ROMselectがアクティブになってしまうようなアドレス(アドレスバスのA15が0になるようなアドレス)が出力されているようなのです。
そのために、CPUがOPコードフェッチでRAMをアクセスしてD−FFからINT信号が出力されたのに、その直後のT3のタイミングで再びD−FFがクリアされてしまうために、せっかく出力されたINT信号がクリアされてしまいます。
INT信号は命令の最後のクロックのときに確認されます。
最短の命令ではT4のときですから、このときにはすでにINT信号はクリアされてしまっていることになります。
ところが、これも前回書きましたように、「Z80 User’s Manual」をさらによく読んでみますと、リフレッシュ期間中には、アドレスバスの「下位7ビット」にリフレッシュアドレスが出力される、と書いてありました。
それじゃあアドレスバスの上位ビットにはどういう値が出力されるのか、そこのところを知ろうとして、User’s Manualを調べてみたのですが、なかなか見つかりません。
というところまでが、前回のお話でした。
[追記ここまで]
Zilog社「Z80 User’s Manual」をあちこち探っていましたら、こんなところにちらりと書いてあるのが、やっとみつかりました。
下線は筆者がつけ加えました。
Rレジスタというのはリフレッシュアドレスを出力するための8ビットのレジスタで、そのうち下位7ビットがRFSH期間中にアドレスバスの下位7ビット(A6〜A0)に出力されます。
Rレジスタの下位7ビットの値はCPUがOPコードをフェッチするたびにオートマチックにインクリメントされます(are automatically incremented)。
上記引用文はそのRレジスタについての説明文なのですが、その説明文の終わりにアドレスバスの上位8ビットに出力されるデータについての説明があります。
アドレスバスの上位8ビット(A15〜A8)には、Iレジスタの値が出力されるのだそうです。
そういうことを、こんなところに書いておいていただいても、ねえ。
●Iレジスタ
んじゃあ、ということで、Iレジスタの説明文を下記に引用いたします。
[出典]Zilog社 Z80 User’s Manual
IレジスタはZ80のモード2の割込みで使われます。
8080の割込みはINT信号の入力とともにデータバスに乗せるRST命令によって、0000、0008、0010、…、0038の8通りのアドレスのいずれかから始まる割込み処理プログラムが実行されるというものでしたが、Z80にはその8080の割込みと同じ割込み(これをモード0といいます)のほかに、モード1、モード2という割込みモードがあります。
Z80の割込みモードについてはまだ説明していませんでしたので、ここで簡単に説明をしておくことにいたします。
●モード0の割込み
これは上にも書きましたように8080のもっていた割込みモードです。
INT信号とともにデータバスにRST0〜RST7のOPコードを乗せることで、メモリアドレスの0000から8番地飛びに置かれた割込み処理プログラムが実行されます。
TK80モニタプログラムのステップ動作は、「このRST7割込み」を使っています。
同じようにND80Zモニタプログラムでも、モード0の「RST7割込み」を使います。
モード0〜モード2のいずれのモードの割込みもEI命令の実行によってはじめて受付け可能になります。
リセット後、またはDI命令の実行後はINT信号が入力されても割込みは受付けられません。
これらの割込みはEI、DIによって受付け可能、不能にすることができますから、「マスク可能な割込み」であるといいます。
これに対して、Z80のもうひとつの割込み、NMI信号の入力によって無条件で0066番地からの処理プログラムが実行される、NMI割込みは「マスク不能な割込み」です。
NMIはNon Maskable Interruptの意味です。
●モード1の割込み
これは「RST7割込み」を簡略化したものである、といえます。
モード0の割込みのうち、0038番地からのプログラムを実行する「RST7割込み」はOPコードがFFであることから、データバスをプルアップしておいて、そこに何も出力しないことで、結果的にFFコードが割込み命令としてCPUに認識されるという簡便さから、簡単な割込み処理としてよく使われますが、それでもあくまでデータバスの状態を全ビットが1であるようにしておく必要があります。
それに対してモード1の割込みは、データバスの状態には関係無く、ただINT信号を入れさえすれば、0038番地からの処理プログラムが実行されます。
EI、DIによってマスクされることを除けば、NMI信号を入れさえすれば0066番地からの処理プログラムが実行されるNMI割込みと同じ割込み動作である、とも考えることができます。
●モード2の割込み
これがさきほど出てきたIレジスタを使う割込みです。
HLレジスタにアドレスを入れておいて、そのアドレスにジャンプする間接ジャンプという命令があります。
8080のニーモニックではPCHLで、Z80ニーモニックではJP (HL)という命令です。
モード2の割込みはその間接ジャンプ命令に似ています。
割込みは基本的にはサブルーチン動作ですから、「間接ジャンプ」ではなくて「間接CALL」ということになります。
モード2の割込みでは、HLレジスタの代わりに任意のメモリアドレスを使います。
たとえば9000番地にジャンプ先アドレスの下位バイトが書いてあり、9001番地にジャンプ先アドレスの上位バイトが書いてあるものとします。
INT信号を入力するとともに、ジャンプ先が書かれている「テーブルアドレス」の9000をデータバスに与えることで、そのテーブルを参照して、指定されているアドレスの処理ルーチンを実行する、という動作をします。
しかしデータバスは8ビットですから、16ビット2バイトのテーブルアドレスを与えることはできません。
そこで、そのときに、Iレジスタが使われるのです。
モード0の割込みと同じように、データバスには8ビットのデータが乗せられます。その8ビットのデータは「ジャンプテーブルアドレス」の下位バイトです。
そしてあらかじめ、Iレジスタには「ジャンプテーブルアドレス」の上位バイトを入れておくことによって、Iレジスタの値とデータバスの値を合わせて得られる16ビットのジャンプテーブルアドレスを参照して、そこに指定されているアドレスのプログラムが実行される、というのがモード2の割込みです。
CPUがリセットされた直後はモード0が選択されます。
つまり8080と同じ割込みモードになります。
モード0〜モード2はプログラムによって自由に切り換えることができます。
そのための命令として、IM0、IM1、IM2が用意されています。
●Iレジスタの初期値は?
そのようにして使われるIレジスタなのですが、上のところで引用したIレジスタの説明文には、Iレジスタの値がRFSHのタイミングでアドレスバスの上位8ビットに出力されることについては全くなにも書かれておりません。
初期値についても触れられておりません。
まったく、ひどいものです。
Iレジスタの初期値については、こんなところに書かれていました。
[出典]Zilog社 Z80 User’s Manual
2行目、
clears the PC and registers I and R
と書いてあります。
リセット後はIレジスタはクリアされて00になる、ということですから、やっとステップ動作が実行されない理由がわかりました。
RFSHのときにもMREQがアクティブになりますから、そのときアドレスバスの上位8ビットは00なので、ROMselectがアクティブになってしまうのです。
このときRD信号はアクティブにはなりませんから、ROMが選択されていても、ROMからデータは読み出されません。
しかしそれによって、RAMの命令を実行していても、ステップ回路のD−FFがクリアされてしまうため、INT信号は出力されないのです。
以上のようなわけで、[第457回]の回路のように、RFSH期間中のROMselectによってD−FFがクリアされてしまわないようにしないとステップ回路が機能してくれないことがわかりました。
およそ30年前にND80Zの回路を考えたときに、そこまでのことを理解して、そのようなステップ回路にしたのか、あるいはカットアンドトライによってその回路にいきついたのかは、今となっては不明です。
しかしそのような回路にすることによって、Z80CPUのもとで、TK80と同じステップ動作をさせることができることに間違いはありません。
ですけれど。
それなら、もっと簡単にできるじゃありませんか。
●ステップ回路が簡単になってしまいました
最初Z80でステップ回路がうまく機能しなかったそもそもの原因は、リセットによってIレジスタに00が入ってしまうことでした。
そのために、RFSHのときにROMselectがアクティブになって、D−FFがクリアされてしまうのです。
ならばIレジスタに、ビット7が0ではないような値を入れておけばよい、ではありませんか。
(MREQがアクティブで)アドレスバスの最上位ビットA15が0のときにROMselectがアクティブになります。
RFSHの期間はMREQもアクティブになって、そのときにアドレスバスの上位8ビットにはIレジスタの値がそのまま出力されます。
ですからそのときにA15が1になるような値、つまりIレジスタのビット7が1になるような値を、Iレジスタに与えておけば、[第457回]のような回路にしなくても、ステップ回路は働いてくれるはずです。
で、モニタプログラムの先頭のところで、
LD A,FF
LD I,A
という命令を書いておいたところ、
前回([第459回])でお見せした簡単なステップ回路でも問題無く動作してくれました。
めでたし、めでたしです。
じつは、モニタプログラムの先頭でIレジスタにFFを与えておくことで、ステップ回路が簡単にできる、ということは、今回のZ80版TK80ボード(ND80ZH)の試作基板をテストしている過程で気がつきましたので、ND80ZHの本番基板では、ちゃんとそのような回路にしてあります。
なお今回のステップ回路は、Iレジスタにビット7が1であるような値を入れておかないと正しく動作してくれません。
モニタプログラムの先頭ではIレジスタ=FFにしていますが、ビット7=1になる値なら構わないので、Iレジスタの値としては80〜FFが使えることになります。
まあ、モード2の割込みはかなり高度なプログラムテクニックに属しますから、TK80互換のトレーニングボードでのプログラムではまず使われることは無いと思われますし、もし使うことがあるとしても、そのときIレジスタのビット7を0にしなければ使えない、という理由はまずないだろうと思いますから、このようにIレジスタの値を80〜FFの範囲に制限したとしても、特別支障はないだろうと判断いたしました。
2010.3.21upload
2010.3.22追記
前へ
次へ
ホームページトップへ戻る