PIC講習/ジャンプ

概要

本章では、ジャンプと呼ばれる機能を解説します。
メモリ上のアドレスが変化していくので、時間軸で区切って順に考えましょう。

重要語

ラベル

プログラムメモリ上のアドレスを示す定数

ジャンプ

プログラムカウンタを変更すること

サブルーチン

プログラム中で呼び出す副命令列

スタック

プログラムカウンタの値を一時退避するメモリ

必要語

命令

コンピュータへの指令の最小単位

プログラムカウンタ

次に実行する命令のアドレス

ラベル

定数のうち、特にプログラムメモリ上のアドレスを示すものを、ラベルといいます。
本や辞書の重要な箇所に付箋を貼るのに似ています。

特殊変数PWC

特殊変数PWCは、次に翻訳される命令が書き込まれるアドレスを示します。
プログラムの先頭で0であり、コンパイラが命令を1つ翻訳して書き込んだ後、1増えます。
なお、これはコンパイル時のみの概念ですが、実行時のプログラムカウンタと等しい値になります。

ラベルの定義

ラベルは定数なので、COLを使って定義します。
ただし、2つめの引数にPWCを指定するか、定数の名前だけ指定します。
後者の場合、.は命令と引数の間の1つだけでよいです。
COL構文は、2つめの引数が省略されたとき、PWCとみなすようになっています。
ラベルであることがわかりやすいですし、書くのも楽なので、省略するとよいです。
ラベルの例
COL.LABEL1     #2つめの引数省略
COL.LABEL2.PWC #こちらでもよい

COL.LABEL3     #LABEL3は次のNOP命令のアドレスを示す
  NOP          #ラベルの後はインデントを付けるとわかりやすい

ジャンプ

プログラムカウンタは、命令を実行するごとに1増えます。
しかし、プログラムメモリは有限なので、すぐに端についてしまいます。
プログラムでは、繰り返しや分岐が重要ですが、1方向に1ずつしか進めないのでは、どちらも実現できません。
これらに対応するための、実行中にプログラムカウンタを変更できる機能が、ジャンプです。

GOT命令

具体的には、GOT命令がジャンプの機能を持ちます。
引数は1つで、プログラムカウンタに書き込む値を指定します。
しかし、ジャンプ先の命令のアドレスを手動で調べるのは、非常に大変で信頼性も低いです。
そこで、先ほどのラベルを使えば、コンパイラが自動でやってくれます。
ジャンプの例
GOT.SKIP
  #ここに書いた命令は飛ばされる
COL.SKIP

COL.LOOP
  #ここに書いた命令を繰り返す
  GOT.LOOP

サブルーチン

PICのプログラムメモリは限られています。
効率的にプログラムを書くには、同じ命令列を何度も書くのは避けたいです。
そこで、サブルーチンと呼ばれる命令列を書き、必要な個所からジャンプする、という方法があります。
サブルーチンにジャンプすることを、サブルーチンを呼び出すcall a subroutine、ということがあります。
Lチカのプログラムでは、一定時間待つ命令列を、サブルーチンにしていました。

CAL/RET命令

ところで、サブルーチンを実行した後は、どこに戻ればよいのでしょうか。
複数個所から呼び出されるサブルーチンであれば、単純にGOT命令を使うわけにもいきません。
呼び出し元のアドレスを保存してからジャンプする必要があります。
これを行うのが、CAL命令です。
現在のプログラムカウンタを後述のスタックに保存した後、ジャンプします。
サブルーチン終了時には、RET命令で戻りreturn from a subroutineます。
RETのジャンプ先は、スタックに保存されているアドレスなので、引数はありません。

スタック

スタックとはメモリの一つで、プログラムカウンタを保存できます。
ただし、サブルーチンからさらにサブルーチンを呼び出す状況なども考えられます。
そのため、16F1827では、16段の領域があり、16重までの多重呼び出しが可能です。
しかし、安全のため、8重以上になるような状況は避けましょう。
なお、スタックは最後に保存された値から順に取り出される構造になっています。
サブルーチンの例
CAL.SRA   #サブルーチンSRAを呼び出す

COL.SRA   #サブルーチンSRAはここから
  NOP     #ここにサブルーチンの内容おい
  CAL.SRB #別のサブルーチンを呼び出してもよい
  RET     #サブルーチンSRAはここで終わり

COL.SRB   #サブルーチンSRBはここから
  NOP
  RET     #ここまで