標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第163回]
●SPHL、PCHLのテストプログラムです
ここのところ、プログラムの説明が続いています。
ハードウェア回路ではなくて、アセンブラプログラム教室みたいな様子ですね。
[第156回]で、いくつかの命令回路をまとめて実装してしまいましたので、こんな調子になっていますけれど、あと一息です。
今回のSPHL、PCHL命令で、[第156回]でまとめて実装した部分の説明はひとまず完了です。
今回はSPHL、PCHL命令のテストプログラムです。
前回、前々回に説明したXTHL命令はなかなかに難しい命令でしたが、今回のSPHLもなんだかよくわからない命令です。
いずれもふだん余り使うことの無い命令です。
通常の制御プログラムなどではまず必要はありません。
もう少し複雑な、システム的なモニタプログラムなどでは、こういう命令があると重宝します。
SPHL命令については、[第93回]で説明しています。
動作そのものはXTHLよりも単純で、HLレジスタの値をSP(スタックポインタ)に移す、というただそれだけの動作です。
HLレジスタの値は変わりません。
SP(スタックポインタ)に値を設定する命令としては、LXI SPがありました。
LXI SP命令は、サブルーチンを使うテストプログラムの先頭で必ず使ってきましたから、もうすっかりおなじみになってしまったと思います。
LXI SP命令は、メモリアドレスを直接指定する命令です。プログラムにアドレス値を直接書き込んでしまいますから、実行中にその値を変えることはできません。
SPHL命令は、HLレジスタに入っている値をSPに入れますから、プログラムの実行中に、SPに自由に値を設定することができます。
ということは、スタックの位置をプログラムの実行中に自由に変更することができる、ということです。
そ、そんなことをしたら、プログラムがめちゃめちゃになって、暴走してしまうのでは…?
ですから、一般的ではありません。上級者向きです。
あとで紹介するテストプログラムで、その実際をお見せします。
なお、SP(スタックポインタ)を操作できる命令は、LXI SPと、このSPHLのほかには、INX SP、DCX SPがあります。
SPHL命令はHLの値をSPに移す命令ですが、逆にSPからHLに値を移す命令はありません。
しかし、実はそのための機能は別の命令に用意されています。
まだ説明はしていない命令ですが、DAD(double add)を使うことで、HLにSPの値を入れることができます(この機能については、いずれDAD命令の説明のところでお話しすることにいたします)。
今回のテストプログラムでテストする、もうひとつの命令はPCHLです。
SPHLはHLレジスタの値をSP(スタックポインタ)に移す命令ですが、PCHLはHLレジスタの値をPC(プログラムカウンタ)に移す命令です。
PCHL命令についても、[第93回]で説明しています。
PC(プログラムカウンタ)を操作できる命令は、このPCHL命令だけです。
プログラムの実行中に、PC(プログラムカウンタ)の値を任意に設定することができます。
そ、そんなことをしたら、それこそプログラムが暴走してしまう…!
確かに。不用意に使えば、そうなります。これも上級者向きです。
PCHLは、なかなかにユニークな命令で、プログラムの行き先を、プログラムの実行中に変更することが可能になります。
もちろんプログラムの行き先を変更するには、CMP(compare、比較)命令と条件JMP命令を組み合わせれば可能になりますが、それを少ないバイト数でシステマチックにやってのける、というのがこの命令のウリです。
メモリが安価になった今日、このような命令の存在価値は減少してしまいましたが、それでもプログラムが大きくなって限られたスペースに入りきらない、というような場面では、真価を発揮します。
とはいえ、Cコンパイラ全盛の今日では、アセンブラそのものがいまや賞味期限切れになりつつあるようなのですけれど…。
テストプログラムです。
0000 3E00 MVI A,00
0002 47 MOV B,A
0003 4F MOV C,A
0004 57 MOV D,A
0005 5F MOV E,A
0006 210001 LXI H,0100
0009 F9 SPHL (4)
000A E9 PCHL (4)
00FE 00 DB 00
00FF 00 DB 00
0100 3B DCX SP (4)or(6)
0101 3B DCX SP (4)or(6)
0102 F1 POP PSW (4)
0103 3C INR A (4)
0104 F5 PUSH PSW (4)
0105 C20901 JNZ 0109 (6)or(4)
0108 03 INX B (4)or(6)
0109 24 INR H (4)
010A E5 PUSH H (4)
010B 210900 LXI H,0009 (4)
010E E3 XTHL (8)
010F C9 RET (4)
01FE 00 DB 00
01FF 00 DB 00
0200 3B DCX SP (4)or(6)
0201 3B DCX SP (4)or(6)
0202 F1 POP PSW (4)
0203 3C INR A (4)
0204 F5 PUSH PSW (4)
0205 C20902 JNZ 0209 (6)or(4)
0208 13 INX D (4)or(6)
0209 25 DCR H (4)
020A C30A01 JMP 010A (6)
今回は、何がなんだかさっぱりわからない、一見すると、間違ってるじゃないか!というプログラムです。
010FにRETがありますが、どこにもCALLがありません。
010AにPUSH Hはあるけれど、それと対になりそうなPOP命令はどこにもありません。
こんなんで、ほんとにいいの?
でも、ちゃんと動きます。
このプログラムを実行すると、BCレジスタとDEレジスタがカウントアップしていきます。
BCレジスタとDEレジスタの下位にAレジスタがあって一番下位でのカウントをします。
つまり、B、C、AとD、E、Aという2組の24ビットカウンタがあって、それぞれが交互に+1(インクリメント)されていきます。
このとき最下位のAレジスタは共通ではなくて、見かけ上はAレジスタが別々に2個存在するかのように動作します。
いったいどうなっているのでしょうか?
その答えは、次回までの宿題といたしましょう。
それまでに、よーく考えてみてください。
いやぁ。こういうプログラムを書くと、いかにもアセンブラだなぁ、という感じになりますねぇ。
あ。こんな複雑なプログラムを書かなくても、カウントアップのプログラムはいくらでも書けるはず、なんてことは、言いっこなし、にしましょうね。
簡単に済ませてしまったら、PCHLもSPHLも出番がありませんから。
このプログラムは単なるテストプログラムですから、実につまらないことをさせているだけですし、わざと複雑にしているところもありますけれど、実は、普段は滅多にお目にかかれない、ウラワザ的なことをやっています。
そのあたりのところもじっくりと味わっていただきたいと思って、用意しましたのですよ(ぜひ、ご賞味あれ)。
なお、DBというのはアセンブラの擬似命令です。
擬似命令とは、CPUにはない命令なのですが、アセンブラを機械語に翻訳する過程で必要になる特殊な機能を実現するために、用意された手続きのことです。
DBはdefine byte、のことで、1バイトのコードをそのままその位置(メモリアドレス)に置く、という働きをします。
もうひとつ。
このプログラムはRAMの上でしか、動きません。
ROMで動作させるためには、スタックとプログラムを分離する必要があります(その意味、わかりますでしょうか?)。
あ。もうひとつ。
プログラムの先頭で、MOV命令を使っていますが、ここはLXI B,0000、LXI D,0000でも構いません。
一般にアセンブラ(機械語も同じ)では、レジスタを00でクリアするときには、バイト数の節約から、このような書き方をします。
ついでに、もうひとつ。
先頭のMVI A,00も、今のところは、こう書くより仕方がないので、こうしていますが、ここは、本当はXOR命令を使って、
XOR A
と書くのが一般的です。こうすると、1バイト節約できます。
XOR命令はレジスタクリアの代わりに最も良く用いられます(キャリーフラグもクリアされるなどフラグにも影響することに注意)。
MVI A,00
と書くよりも、
XOR A
と書いたほうが、なんとなく、かっこよく見えたりしませんか?
2009.2.15upload
2009.2.16一部追記、訂正(昨日は眠い目をこすりながら書いていましたので、とんでもない大ポカをやってしまいました。SPとPCの説明が一部入れ替わっていました。今朝読み返していて気がつきましたので大急ぎで訂正しました)
前へ
次へ
ホームページトップへ戻る