| | / S−OS講座・第6回「Z80:JRとDJNZ」 \ ・光陰矢のごとし!恐るべきは時の流れ哉  約1年ぶりのごぶさたでしたが,みなさん寒いなかいかがお過ごしでしょうか.前 回は,分岐命令のJPについてやりましたので,今回はそれの続きとして, JR命令 DJNZ命令 について学習します. (こんなペースで進んで,本当に会員の役に立っているのだろうか?) ・JRといっても○○旅客鉄道ではない? コンピュータがマシン語を実行するとき,今から実行する命令が格納されているア ドレスは, PCレジスタ に記憶されていることは,前回お話ししました.JP命令は,このPCレジスタの内 容を書き換えることによって,コンピュータに別のアドレスからのプログラムを実行 させることができる,すなわちジャンプできるのでした.JR命令も,JP命令同様 指定のアドレスにジャンプする働きがあります.次のプログラムをご覧ください. 【プログラム】押したキーのコードを16進表示する. ラベル ニモニック コメント -------+-------+----------------+----------------------------------------- _PRTHX EQU 1FC1H ; Aレジの内容を16進表示するサブルーチン _FLGET EQU 2021H ; Aレジに1文字入力するサブルーチン ORG 8000H ; 8000Hより始めよ LOOP: CALL _FLGET ; A←キーコード CALL _PRTHX ; Aの内容を16進表示 JR LOOP ; LOOPへ戻る 「JR LOOP」はLOOP番地へジャンプすることを示していますので,ソー スリストを見た限り,JP命令と全く同じにみえます.それでは,どこが違うのか? アセンブルしてオブジェクトを見てみましょう. A>A . OBJECT CODE END 8007 ←注目! A>D8000 :8000=CD 21 20 CD C1 1F 18 F8 .. .. ... 前回のプログラムとよく見比べてください.プログラムの長さが1バイト短かくな ~~~~~~~~~~~~~~ っているのにお気付きでしょうか? それでは一体どこが短かくなったのでしょうか.  ″JP LOOP″のマシン語は,C3 00 80  ″JR LOOP″のマシン語は,18 F8 ですから,JR命令のほうは飛び先番地を1バイトで指定していることが分かります (JR命令のオペコードは 18H).  ではどうして,LOOP番地へのジャンプが″F8″になるのでしょうか? ・相対アドレスのカラクリ Z80はじめ,多くのCPUでは, ____ | ↓ | 命令の読み込み(フェッチ) | ↓ | 命令の解読  (デコード) | ↓ | 命令の実行と,それに伴なうメモリの読み書き | |  ̄ ̄ ̄ ̄ というサイクルでプログラムが実行されてゆきます.そしてPCレジスタは命令フェ ッチが終了した時点で,つぎの命令の先頭アドレスへ移動しています.したがって先 ほどのプログラムでは,″JR LOOP″の読み込みが終わって実行するときには PCの値はその次の命令のアドレス(8008H)になっていることを頭に入れてお いてください.  そろそろ種あかしをしましょう.JR命令では,飛び先のアドレスは 現在のPCから数えてなんぼ で指定します.ここで注意しなければならないのは,「現在のPCレジスタの内容」 がどこになるかです.さっき述べたように,JR命令を実行する時点でPCは JR命令の次の命令の先頭 を指し示していますので,例えば次の図で"3E"へジャンプしたいときは,"3E"は PCレジスタの指し示している位置より数えて3バイト目ですから,ee = 03 となり ます. +0 +1 +2 +3 +4 バイト目 18 ee ?? ?? ?? 3E 01 ... | ↑ ee = 03  ̄ ̄ ̄ ̄ ̄ ̄ ↑PC 逆に後ろにジャンプ(バック)する場合には,指定する数値は1つ前が FF,2つ前 が FE,...のようになります(これを2の補数表現という).ちょうどラジカセのテ ープカウンタの表示が,巻き戻しをかけると 000 → 999 → 998 → ……となるのと 同じです(これは10の補数表現).数値の表現方法については,機会があればくわ しく解説したいと思っています. -7 -6 -5 -4 -3 -2 -1 +0 バイト目 3E 01 ?? ?? ?? 18 ee ?? ... ↑ | ↑ ee = -7 = F9  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ PC (ただし今述べた事はオブジェクトレベルの話で,アセンブラを使うときはJPも JRも飛び先の指定はラベル名を書くだけでよろしい.あとはアセンブラが良きに計 らってくれます) またJR命令で指定できるのは1バイトですから,ジャンプできるアドレスの範囲は PCレジスタの場所から−128〜+127バイトの範囲のみとなります.これ以上 遠くへ飛ばすことはできません.また,JR命令のほうがJP命令より若干時間がか かります.都合の悪いときはJP命令を使用してください. ・リロケータブルということ  前回JP命令の説明で JP nn = LD PC,nn であると書きましたが,同じような書きかたをすれば, JR e  = ADD PC,e と書けそうですね.そうやって考えると,マシン語いうのは,「データ転送」と「演 算」だけで全ての処理を行なっていることが分ってきます.  JP命令に条件分岐命令があったように,JRにも演算結果によってジャンプした りしなかったりするものがあります.ただし,その種類はJPの場合より少なくて, 4種類です. JR Z,e ……演算結果が零のとき ジャンプ. JR NZ,e …… 〃 零でないとき 〃 JR C,e ……演算で桁あふれが生じたとき 〃 JR NC,e …… 〃 生じなかったとき 〃  もう1つJR命令には,プログラムが短かくなるほかに,「オブジェクトをそのま ま別のアドレスへ移動しても,そのまま動く」という大きなメリットがあります.た とえば,前回のプログラムをそのまま7000番地へ持っていけば確実に暴走します が,先ほどのプログラムでは全く問題はありません. JPの場合 JRの場合 ___ 7000 CD 常| ↓ .... .. に| 7000 CD 7006 C3 -8| .... .. 7007 00 番| 7006 18 7007 80 地| 7007 F8 ↓ !| | 8000番地に行って暴走.  ̄ ̄ ̄ JR命令のこのような働きを再配置可能(リロケータブル)と言い,特に短かいプ ログラムをいくつもつなげて使用する場合に威力を発揮します. ・繰返しに便利な,DJNZ  Z80で繰返しのプログラムを記述するときは,前述のJPやJRの条件分岐を使 用すれば事足りるのですが,Bレジスタを組合せて使用すると,簡潔にループ処理が 記述できる命令があります.それが, DJNZ命令 です.次のプログラムを見てみましょう. 【プログラム】8010H番地〜のメモリに,50H,4FH,4EH...と,80バイト格納する. ラベル ニモニック コメント -------+-------+----------------+------------------------------------------- DATAS EQU 8010H ; データ領域の先頭アドレス ORG 8000H ; 8000Hより始めよ LD HL,DATAS ; HL←データ領域の先頭アドレス LD B,80 ; B←80 LOOP: LD (HL),B ; (HLが指すメモリ)←B INC HL ; HL←HL+1 DJNZ LOOP RET ; おわり  これも前回解説したプログラムに似ています.どこが違うかと言うと, 1)Aレジスタ → Bレジスタになっている 2)「DEC A」がない 3)「JP NZ,LOOP」が「DJNZ LOOP」になっている とりあえず,アセンブルしてみましょう. A>A OBJECT CODE END 8009 ← 2バイト節約! 実行してみると,プログラムが短かくなっているだけで,前回のプログラムと同じ働 きをすることがわかります. A>J8000 A>D8000 :8000 21 10 80 06 50 70 23 10 :8008 FC C9 .. .. :8010 50 4F 4E 4D 4C 4B 4A 49 :8018 48 47 46 45 44 43 42 41 : : :8058 08 07 06 05 04 03 02 01 :8060 .. .. これでおわかりいただけたと思いますが,DJNZ命令は「Bレジスタを−1して B>0ならばLOOPへジャンプ」という働きがあるわけです.  BASICのGOTOとFOR〜NEXTのように,繰返し専用命令を使うことは ループ構造であることをプログラム中で明示できるというメリットがあります(ただ マシン語の場合「DJNZを使ったループ構造でないプログラム」も書けるので,人 の作ったプログラムを読むときには注意しよう). ※次回は「スタック操作」と「サブルーチン」について解説する予定です.お楽しみ に! (EOF)