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

●SHLD、LHLD、XTHLのテストプログラムです

今回はSHLD、LHLD、XTHLの各命令のテストプログラムです。
いずれもHLレジスタとメモリとの間でデータを交換する命令です。

前回テストしたSTA、LDAはAレジスタの値をメモリにSTORE、メモリからLOADする命令でした。
SHLD、LHLDはHLの値をメモリにSTORE、メモリからLOADします。
STA、LDAはSTORE、LOADするメモリアドレスを直接指定しました。SHLD、LHLDも、それと同様にメモリアドレスを直接指定します。
SHLD、LHLD命令についての詳しい説明は[第104回]にあります。

XTHLはちょっと難しい命令です。
スタックのトップにある2バイトのデータとHLの値とを交換します。
XTHL命令は[第100回]で説明していますので、詳しくはそちらを参照してください。

0000 310000   LXI SP,0000
0003 010000   LXI B,0000
0006 110000   LXI D,0000
0009 3E00     MVI A,00
000B C5       PUSH B   (4)
000C E3       XTHL      (8)
000D 23       INX H     (4)or(6)
000E 225000   SHLD 0050 (10)
0011 210000   LXI H,0000 (4)
0014 2A5000   LHLD 0050 (10)
0017 E3       XTHL      (8)
0018 C1       POP B     (4)
0019 1C       INR E      (4)
001A C20B00   JNZ 000B  (6)or(4)
001D 14       INR D      (4)
001E C20B00   JNZ 000B  (6)or(4)
0021 3C       INR A      (4)
0022 C30B00   JMP 000B  (6)

今回はちょっとわかりにくいプログラムです。
SHLD、LHLDとXTHLの動作を確認しようとしたら、このような複雑なプログラムになってしまいました。

BCレジスタとDEレジスタには初期値0000を入れます。
Aレジスタにも00を入れます。

PUSH B、POP Bは、XTHLの動作を確認するために使っています。
PUSH B命令の実行によって、スタックのトップにはBCレジスタの値が置かれます。
その次のアドレスにXTHL命令がありますが、必ずしもこのようにPUSH命令とペアで使わなければならない、ということではありません。
XTHLは任意の時点で使うことができます。

XTHLを実行すると、そのときにスタックトップにある2バイトのデータと、HLレジスタの値とが交換されます。
XTHL命令によって、スタックトップのデータ(実はBCレジスタの値と同じ)がHLレジスタに入り、代わりにHLレジスタの値がスタックに置かれます。
BCレジスタは変化しませんが、動作としては、BCとHLの値を交換したに近い動作になります。
ですから、HLの値は、実はBCの値と同じになっています。

そのHLの値を次のINX Hで+1します。
そしてSHLDとLHLDのテストのために、まずSHLD命令で、メモリの0050にHLの値をSTOREします。

次のLXI H,0000は、STOREした値をそのままHLに戻したのでは、本当にそのように動作したかどうか確認できないので、STORE後に一旦HLをクリアするための目的で使っています。
本当は、わざわざここまでしなくても、ステップ動作で、SHLD、LHLDが正しく機能していることは確認済みなのですけれど、まあ、ちょいとした、お遊び、です。

その後に、LHLD命令で、メモリの0050から、ふただび値をHLレジスタに読み込みます。
そしてもう一度、XTHLを実行して、スタックトップのデータ(保存してあった、もともとのHLのデータ)と、現在のHLレジスタの値とを交換します。

ここまでの動作で、スタックトップの値(実はBCレジスタの値)が+1されたことになります。
そして最後に、POP Bで、スタックトップの値をBCレジスタに戻します。
結局、HLレジスタの値は変わることなく、BCレジスタの値だけが+1されたことになります。

勿論、BCレジスタの値を+1するだけなら、こんな面倒なことをしなくても、
INX B
だけで済んでしまいます。
このプログラムは、XTHLのテストが目的ですから、そういう面倒なことを、わざとしています。

実行時間を時計で計って、計算結果と比較できるように、以上の動作を1回実行するごとに、Eレジスタを+1します。
Eレジスタを+1した結果が00でなければ、000Bに戻って繰り返します。
結果が00のときは、Dレジスタを+1します。

Dレジスタを+1した結果が00でなければ000Bに戻って繰り返します。
Dレジスタを+1した結果が00のときは、Aレジスタを+1してから、000Bに戻って繰り返します。

●INX命令の実行時間

INX命令は[第159回]で、テストプログラムを作ってテストしましたが、実行時間については、計算はしませんでした。
INX命令の詳しい説明は[第95回]にあります。

INX命令は16ビットのレジスタを、+1(インクリメント)するのに、8ビットのカウンタを利用して、下位8ビットと上位8ビットの2回に分けて計算を行います。
まず下位8ビットを+1して、その結果、上位8ビットへの繰り上がりが発生しなければ、そこで計算を打ち切ります。
そのため、繰り上がりがあるときとないときとで、実行時間が異なってきます。

繰り上がりがないときは8クロック(4μs)で、繰り上がりがあるときは12クロック(6μs)です。
このことは、DCX命令でも同じです。
DCXのときは、上位桁からの繰り下がりがないときは8クロック(4μs)で、繰り下がりがあるときは12クロック(6μs)です。

なお8080では、繰り上がり(繰り下がり)の有無にかかわらず、INX、DCXの実行クロック数は5クロックです。

●その他の命令の実行時間

プログラムの実行時間を計算するのに必要な、各命令の実行時間は、それぞれの命令の後ろに( )で示しました。
単位はμsです。

PUSH、POP命令の実行時間は、[第157回]で説明しました。
INR r命令の実行時間は、[第148回]で説明しました。
JNZ命令の実行時間についても、同じく[第148回]で説明しました。

命令の実行時間はタイミングチャートから知ることができます。
XTHL命令のタイミングチャートは、[第100回]にあります。
タイミングチャートから、XTHLの実行クロック数は16クロックです。

「つくるCPU」のCPUクロックは2MHzなので、1クロックは0.5μsになります。
ですからXTHL命令の実行時間は、16×0.5=8μsになります。
なお、8080では、XTHLのクロック数は18クロックです。

SHLD、LHLD命令のタイミングチャートは[第104回]にあります。
タイミングチャートからSHLD、LHLDの実行クロック数は20クロックです。
ですから、実行時間は10μsになります。
なお、8080では、SHLD、LHLDのクロック数は16クロックです。

●テストプログラムの実行時間

必ず繰り返し実行されるのは、000B〜001Cです。
そこで、この範囲の命令が1回実行されるのに必要な時間をまず求めてみます。

000DのINX Hと、001AのJNZ 000Bには実行時間が2つあります。
INX Hは、実行した結果、下位8ビットが00になるときだけ6μsで、それ以外のときは4μsです。
JNZ 000Bは、Zフラグが立っているときだけ(つまりその前に実行されるINR Eの実行の結果、Eが00になったときだけ)4μsで、それ以外のときは、6μsです。

プログラムは、B、C、D、E、Aに00を初期セットするところからスタートします。
H、Lには何がはいっているかわかりませんが、000B〜001Cの中では、B、Cの値がH、Lに入ることになりますから、H、Lも最初は00からスタートすることになります。

INX HとINR Eは同じように、00からスタートして+1ずつインクリメントされていきますから、Lレジスタが00になるタイミングとEレジスタが00になるタイミングは同じになります。
ということは、000DのINX Hと、001AのJNZ 000Bの2つの命令の実行時間の合計は、常に10μsということになります。

その10μsに残りの命令の実行時間を加算すると、合計は62μsになります。
つまり、000B〜001Cが1回実行されて、HLレジスタ(実はBCレジスタ)とEレジスタが+1されるのに必要な実行時間は62μsということです。
そして、Eレジスタが00からはじまって、また00になるまで、256カウントするたびに、Dレジスタが+1されます。

そこで今度は、Dレジスタが+1されるのにかかる時間を計算してみます。
Eレジスタが256カウントするのにかかる時間は、
62×256=15872μsです。
その15872μsに、INR Dとその次のJNZ 000Bの実行時間を加算すると、
15872+4+6=15882μsになります。
これがDレジスタが+1されるのにかかる時間です。

同様にして、Aレジスタが+1されるのにかかる時間を計算します。
Dレジスタが256カウントするたびに、Aレジスタが+1されるのですから、
15882×256−2+4+6=4065800μsになります。
最後の4+6はINR Aとその次のJMP 000Bの実行時間です。
その前の−2は、Dレジスタが256カウントする間に、1回だけ結果が00になって、JNZ命令の条件が不成立になるので、残りの255回の実行時間6μsより2μs短くなることによる差を引いているものです。

さて、このテストプログラムを実行している様子を、例によってLEDの表示で確認することにします。
すると、目視できるレジスタはD(およびB)とAレジスタのみということになります。
Eレジスタは速すぎて見えません。Dレジスタも下位のほうのビットはちょっとむつかしいでしょうね。

Aレジスタが+1されるのにかかる時間が、約4秒ですから、Aレジスタが256カウントして一巡するのにかかる時間は、
4.0658×256=1040.8448秒です。
ですから、17分20秒でAレジスタが一巡することになります。

次回はストップウォッチを横に置いて、テストプログラムを実行しているところの写真をお見せすることにいたします。
実は、そこでの検証でも、Aレジスタが一巡する時間、17分20秒が引用されることになります。
2009.2.13upload

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