標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第246回]
●今回も割込みの回路の続きです
前回は、BASIC制御ボードを利用して、外部からRSTコマンドとINT信号を与えることで、割込み動作のテストをしているところの写真をお見せしました。
そのためのプログラムリストも見ていただきました。
とりあえずはうまく動作しましたので、めでたし、めでたし…。
のつもりだったのですけれど…。
念のために(と、いつものことながら、やらなくてもよい余計なことをやってしまいます)、INT信号を入力する間隔をせばめて、割込み回数をぐっと増やしてみました。
すると、ときたまポロリとおかしな動作をしてくれたり、どういうわけか、割込みを受付けなくなってしまったりする、という困った現象が出てきてしまいました。
いままで修正、追加の連続で、せっかくの試作基板がまたまた、くもの巣状態になってしまっていますから、あるいはそのせいで誤動作するのかなぁ、とも思いました。
しかし、それにしては、今までの他の動作テストでは誤動作もせず、けっこう安定して動いてくれましたから、ひょっとすると、回路のどこかに問題があるのかも、と思い直して、しばらく回路図をじっと眺めていましたら…。
や、や、や。
ちょっとおかしなところを見つけてしまいました。
●またしても、回路にまずいところが…
[第243回]でお見せした回路図です。
図の赤で囲ったところがおかしい、ということに気がつきました。
ここは、入力されたINT信号が、T0でラッチされて、そのあとINTRDに同期してデータバスに乗せられるRST命令がT2でOPコードレジスタにラッチされるまでの間、INT信号を保持しておくRSフリップフロップを、T4のときにリセットするための回路です。
T4のときにクリアする回路は他にもありました。
EI命令によってセットされた、割込み許可状態を維持するための2段のDフリップフロップ回路もT4のときにクリアされます。
問題は、このDフリップフロップのクリア回路にあります。
このクリア回路をよく見ると、RSフリップフロップからの信号がアクティブなときの、T4の期間にDフリップフロップをクリアするように働く、ということがわかります。
どういうことか、おわかりになりますでしょうか?
RSフリップフロップがONしていることが、クリア信号が出されるための条件で、しかもそのクリア信号はT4のときに出されるのです。
その一方で、RSフリップフロップは、T4のときにリセットされてしまいます。
もし、ゲート回路の遅延時間が0であるならば、クリア信号が出されようとする、その瞬間に、RSフリップフロップがリセットされてしまいますから、結局クリア信号は出力されないことになります。
実際には、ゲートの遅延時間は0ではありません。
ですから、T4がHになってから、3ゲート分の遅延時間(おそらく数十nsec)のみ、クリア信号が出されることになります。
動作テストの結果では、それでもなんとかDフリップフロップをクリアしているようですが、これはちょいと危ない回路です。
もっとも、Dフリップフロップがクリアされると、その瞬間に、このクリア信号もOFFになってしまうのですが、それはちゃんとシーケンスに合った動作ですから問題はありません。
そもそもRSフリップフロップのリセットとしては、DフリップフロップのQ_出力がインバートされてつながっているのですから、T4でDフリップフロップがクリアされれば、結果として、RSフリップフロップもクリアされてしまいます。
ということは、上の回路図の赤で囲ったインバータ回路は、ムダであるばかりか、むしろ危険な回路だということになります。
ひょっとすると、このインバータ回路のせいで、動作が不安定になったかもしれません。
このインバータ回路はさっそくカットすることにしました。
●テストプログラムもまずいのでは…
これは、さきほどのDフリップフロップのクリア回路の問題点に絡むことかも知れませんが、テストプログラムにも、問題点があることに気がつきました。
テストプログラムのリストは、前回([第245回])にあります。
今回のテストはRST1〜RST6を対象にしたため、RST7のための割込み処理はテストプログラムには書いてありませんでした。
しかしながら、RST7はもっとも簡単な割込みなので、何かの原因で、データバスに割込みベクタがはっきり乗らなくて、結果的にCPU回路が割込みコードをFF(11111111)、つまりRST7だと認識してしまったとすると、RST7(エントリアドレスは0038)のためのプログラムは今回のテストプログラムには書かれていませんから、何をしてくれるかわかりません。
念のため、試作基板にUSBを通じて送信した、INTTEST.HTXファイルを確認してみましたところ、アセンブラのソースプログラムでは何も定義しなかった0038からのアドレスにはでたらめなコードが入っていることがわかりました。
ひょっとすると、動作がおかしくなった原因は、このRST7に対する処理が書かれていなかったことと、さきほどのクリア回路の問題とが両方からんで起きたことかも知れません。
さきほどの回路については、問題のインバータのラインはカットしました。
あとは念のために、テストプログラムにRST7の部分を追加した上で、もういちどテストして、どうなるかを確認してみることです。
●テストプログラムも直しました
書きなおしたテストプログラムです。
2009/6/10 10:3 INTTEST2.TXT
END=0075
;;; MYCPU80 INT TEST(RST1-RST7) 09/06/08
; 09/06/10
;;;
ORG $0000
WKBF=$2000
;
0000 C35000 JMP START
;RST1
ORG $0008
0008 F5 PUSH PSW
0009 04 INR B
000A F1 POP PSW
000B FB EI
000C C9 RET
;RST2
ORG $0010
0010 F5 PUSH PSW
0011 0C INR C
0012 F1 POP PSW
0013 FB EI
0014 C9 RET
;RST3
ORG $0018
0018 F5 PUSH PSW
0019 14 INR D
001A F1 POP PSW
001B FB EI
001C C9 RET
;RST4
ORG $0020
0020 F5 PUSH PSW
0021 1C INR E
0022 F1 POP PSW
0023 FB EI
0024 C9 RET
;RST5
ORG $0028
0028 F5 PUSH PSW
0029 24 INR H
002A F1 POP PSW
002B FB EI
002C C9 RET
;RST6
ORG $0030
0030 F5 PUSH PSW
0031 2C INR L
0032 F1 POP PSW
0033 FB EI
0034 C9 RET
;RST7
ORG $0038
0038 F5 PUSH PSW
0039 3A0020 LDA WKBF
003C C601 ADI 01
003E 320020 STA WKBF
0041 F1 POP PSW
0042 FB EI
0043 C9 RET
;
ORG $0050
0050 310080 START:LXI SP,$8000
0053 AF XRA A
0054 47 MOV B,A
0055 4F MOV C,A
0056 57 MOV D,A
0057 5F MOV E,A
0058 67 MOV H,A
0059 6F MOV L,A
005A 320020 STA WKBF
005D 87 ADD A
005E FB EI
005F 3C LOOP1:INR A
0060 F25F00 JP LOOP1
0063 3E07 MVI A,07
0065 D398 OUT 98
0067 3E80 MVI A,80
0069 3C LOOP2:INR A
006A FA6900 JM LOOP2
006D 3E17 MVI A,17
006F D398 OUT 98
0071 3E00 MVI A,00
0073 C35F00 JMP LOOP1
;
LOOP1 =005F LOOP2 =0069 START =0050
WKBF =2000
0038にRST7の処理を追加したのですが、割込みの発生回数をインクリメントするためのレジスタがありません。
B〜Lのレジスタは他のRST処理で使ってしまっています。
Aレジスタはメインルーチンで使っています。
そこで、おお。
ひらめきましたよ。
観測可能なレジスタLEDは他にもありました。
ALUのレジスタ”A”、レジスタ”B”があるじゃありませんか。
これを使いましょう。
RST7割込みが発生したら、メモリ(WKBF)に一時退避させていたカウントデータをAレジスタに入れた上で、ADD命令で+1して、その結果はまたWKBFに退避させます。
ここでINR命令を使わないで、ADD命令を使うところが発想のポイントです。
こうすることで、RST7割込みが発生したら、ALUのレジスタ”A”のLEDには、その発生回数が表示されることになります。
これはその他のルーチンでALU計算回路を使用しない、ということが前提でのアイデアです。
そこで当初はメインルーチンの終りで使っていた、XRA AをMVI A,00に直しました。
●変更したテストプログラムを実行してみました
前回のテストでは、INT信号を出力するBASICボードのプログラムで、待ち時間を作って、INT信号(およびRST命令)の出力間隔を調整していました。
今回のテストでは、もっともきびしい条件でのテストになるように、INT信号はずっとアクティブのまま(つまりずっとLのまま)の出力にしておいて、RST命令のコード出力のみ1〜6の間で繰り返し変化させるようにしました。
そうすると、割込み処理が終わって、最後のEI、RETが実行されて、メインルーチンに復帰した途端に、また次の割り込みが発生することになります。
予測としては、メインルーチンは全く実行されないけれど、割り込み処理は毎回完全に完了した直後に次の割込み処理が行われるために、スタックは異常に消費されたりはしない、ということが考えられます。
さて、結果はどうなったでしょうか?
●T0とINTRD信号です
上(CH1)がINT信号(ずっとアクティブ)をT0でゲートしたあとの出力です(実質的にT0と同じ)。
下(CH2)はINT信号が受け付けられたあとの、INTRD信号です。
INTRDが出される直前のT0と次のT0の間が少し長いことがわかります。
ここがRST命令が実行されているところです。
このあと、PUSH、INR、POP、EI、RETと実行されて、メインプログラムに戻った直後のT0でまた割込みが発生して、INTRDが出されている様子がわかります。
●上の写真の時間軸を拡大したものです
●テストプログラムを実行中の写真です
非常に短い間隔(約30μsec)で連続して割込みが発生して、各レジスタをインクリメントしているため、全点灯しているようにしか見えません。
しかし、Aレジスタは00000001を表示していて、メインプログラムが最初の1回INR Aを実行しただけであることがわかります。
上の列の、ALUレジスタ”A”、レジスタ”B”は消灯したままです。
RST7が実行されてしまうような誤動作は、今回発生していないことがわかります。
この状態は連続4時間テストしても変化しませんでした。
どうやら、誤動作は防ぐことができたようです。
2009.6.10upload
前へ
次へ
ホームページトップへ戻る