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

●NMI(その2)

Z80のNMI(Non Maskable Interrupt)については[第437回]で説明をいたしました。
説明をすることはしたのですけれど、引用したZilog社のZ80CPU User Manualの説明文がなんともいいかげんな説明文で、肝心のところがいまひとつはっきりしませんでした。

ということで、[第437回]はあいまいな説明のままで終わってしまいました。
その時点では、その次の回に引き続きNMIについて、もう少しはっきりした説明を書くつもりでおりました。
ところがZ80版TK80ボードの試作基板が出来てきてしまったものですから、そのままその説明に入ってしまって、NMIの続きなどもうどこかに行ってしまいました。

そういうことだったのですけれど、まあしかし、INTと違って普通の用途ではNMIなどを使うことは余り無いとも思われますし、事実私自身も何かにNMIを利用したという記憶はありません。

もともとNMIなどというものは8080にはありませんでしたし、当然のことながらTK80のモニタプログラムには関係がありません。
NMIのエントリアドレスといいますか、スタートアドレスは0066番地に固定されていますから、Z80を使ってTK80互換ボードを作ることを考えると、そのアドレスはTK80モニタプログラムが書かれているアドレスですから、もしもNMIの機能を利用しようとすれば、TK80モニタプログラムの、その部分を書き換えなくてはなりません。
それまでしてNMIを使う必要は無いと思いますから、そうするといまさらNMIなど持ち出さなくてもよいではないか、ということになるかもしれません。

しかし、Z80版TK80ボードの試作基板の説明に移ってしまったものですから、完全に宙に浮いてしまったのですけれど、実は、次の回あたりで説明をするつもりで、NMIについてロジアナを使って動作を確認した資料なども準備していたのです。
せっかくそこまでしても、またいつものことで、そのままにしておいたらどうせすっかり忘れてしまいます。
ですので、これもこの機会にここでまとめておきたいと思います。

[第437回]のUser ManualのNMIの説明でははっきりしないところがありますけれど、NMIも普通のINTも、割込みの動作そのものは基本的には同じです。
割込み信号は、実行中の命令の最後のクロックのときにCPUに認識され、Z80CPU User Manualの説明によると、その次にデータバスに読み込まれた命令は無視されて、そのときのPC(プログラムカウンタ)の値が外部スタックに保存されたあと、0066番地の命令が実行される、ということのようです。

●NMIテストプログラム

そのあたりの動作を、[第374回]でご紹介しましたカメレオンUSB+ロジアナで観測して確認してみることにしました。
割込みプログラムの開始アドレスは0066番地ですから、プログラムはROMに書くしか仕方がありません。
今回はTK80モニタプログラムは無視です。
ROMの先頭アドレス0000番地から簡単なテストプログラムを書きました。

2010/2/20  9:40  NMITEST.TXT
END=006C
              ;;; Z80 NMI TEST 10.2.20
              ;
                ORG $0000
0000 3100E0     LXI SP,$E000
0003 3E90       MVI A,90;82C55 A=IN,B,C=OUT
0005 D383       OUT 83
0007 3EFF       MVI A,FF
0009 D382       OUT 82
000B DB80     LOOP1:IN 80
000D FEFF       CPI FF
000F CA0B00     JZ LOOP1
0012 3E00     LOOP2:MVI A,00
0014 D382       OUT 82
0016 3EFF       MVI A,FF
0018 D382       OUT 82
001A C31200     JMP LOOP2
              ;
                ORG $0066
0066 D381       OUT 81
0068 3EFF       MVI A,FF        
006A D382       OUT 82
006C C9         RET
              ;END
LOOP1        =000B  LOOP2        =0012  

むむむ。
NMIはZ80の機能ですから、Z80ニーモニックで書くところなのですが、どういうわけか、8080ニーモニックで書いてしまいました。
プログラムだけを見ても、これのどこが割込みのテストプログラムじゃ、という感じになりますが、もちろんシカケがあります。

LOOP2のところで82C55のCポート(I/Oアドレス82)に00とFFを交互に出力しています。
実は、そのCポートのビット0(PC0)の出力をZ80のNMI入力に接続してあるのです。
ですから0014番地のOUT命令が実行された直後にNMI割込みが発生するはずです。
それをロジアナで観測しよう、ということなのです。

なお、その上のLOOP1は、リセットまたはPOWER ONによっていきなりLOOP2にエントリさせると、起動時の不安定な状態のときにCPUから出力される信号によってロジアナのトリガが働いてしまうのを防止するためのものです。
82C55のAポート(I/Oアドレス80)のビットのどれかをGNDに落とすことで、LOOP2のプログラムが実行され、そこではじめてNMI割込みが発生する、という仕掛けです。

●ロジアナでの観測結果

ロジアナで観測した結果です。

今回のテストプログラムは短いプログラムで実行範囲が限られていますから、アドレスバスの上位8ビット(A8〜A15)はロジアナには入力しませんでした。
PROBE07のラインにデータバス(D0〜D7)の値を書き加えてあります。
またPROBE12のラインにアドレスバスの下位8ビット(A0〜A7)の値を書き加えてあります。
PROBE08がNMI入力です。

24μsのところでD3 82(OUT 82)が実行されて、アドレスバスが82、データバスが00になっています。
WR信号(このときは実はIOWR)の立ち上がりで82C55のCポートから00が出力され、その結果NMIがLになっています。
NMI入力はその次の3E FF(MVI A,FF)の実行の終わりに受付けられます。
データバスには、その次の命令コードのD3がメモリから読み出されていますが、その命令コードは無視されて、その次のタイミングで、このときのアドレス、つまりPC(プログラムカウンタ)の値(0018)が、スタックに退避されています。

そのあとアドレスバスが66になっていて、ここで0066番地の割込みプログラムが実行されたことがわかります。
割込みプログラムはアドレス006CのC9(RET)で処理を終わり、もとのプログラムに戻ります。
スタックに保存されていたアドレス0018がPC(プログラムカウンタ)に戻され、そしてあらためて、さきほど無視された、0018のD3 82(OUT 82)が実行されています。

2010.3.31upload

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