[PP0906] 08. ジャンプ

これまで作ってきた命令では、プログラムは上から下へ向かって順番に実行することしかできませんでした。しかし、実際のプログラムでは、途中で別の場所へ行ったり来たりすることが少なくありません。通常、それらは条件判断を行って、条件に合うかどうかで別の場所にジャンプするかどうかを決めますが、今回はその準備段階として無条件にジャンプする命令を追加することにしましょう。

命令 ニーモニック 命令長 意味
12 JMP 2 ジャンプ

それでは、JMP 命令を使った簡単なプログラムを作ってみましょう。

int program[] =
{
  JMP, 5,
  LI, 123,
  OUT,
  LI, 321,
  OUT,
  -1,
};

このプログラムでは、5 番地にジャンプしています。5 番地というのは、配列の 6 番目の要素(配列の要素は 0 番目から始まるので)にあたりますので、LI, 321 の LI 命令の位置になります。したがって、最初の LI, 123 と OUT は実行されずに、LI, 321 と OUT だけが実行されることになります。

では、JMP 命令を実際に追加することにしましょう。

case JMP:
  eaddr = memory[pc];
  pc = pc + 1;
  pc = eaddr;
  break;

PC を 1 進めたあと、すぐに PC に実行アドレスを代入していますので、PC を 1 進めなくても同じなのですが、フェッチの後は PC を 1 進めるという原則を貫くために、あえてこのように書いています。このコードを見れば、ジャンプというのは、PC に値を設定する操作に他ならないことが分かるかと思います。

ところで、JMP 命令ではオペランドにジャンプ先のアドレスを指定することになるわけですが、実際にジャンプしたい箇所のアドレスを調べるのは骨が折れます。しかも、途中の命令を少し追加・削除しただけで、アドレスがずれてしまいます。本格的なアセンブラであれば、ジャンプ先にラベルを書いて、そのラベルを使ってアドレスを指定することができるようになっています。しかし、我々にはそんな便利なツールはありません。

そこで、多少なりともアドレスの指定が楽になる方法を考えてみましょう。例えば、先ほどのプログラムでジャンプ先のコードだけを別の配列にしてみます。

int sub1[] =
{
  LI, 321,
  OUT,
  -1,
};

そして、これを main 関数の最初で、

memcpy(&memory[0x100], sub1, sizeof sub1);

のようにして 0x100 番地に転送してやれば、このプログラムの開始アドレスを 0x100 に強制することができるようになります。ただし、配列 program が大きくなると、0x100 番地以降が重なってしまいますので、その場合は 0x200 にするなど、適当にアドレスを変更してください。

この記事のトラックバックURL:

http://www.kijineko.co.jp/trackback/523
このエントリーを含むはてなブックマーク