[PP0906] 10. コールとリターン

今回はサブルーチンを呼出すための仕組みを追加します。サブルーチンというのは、決まった仕事をするための小さなプログラムのことで、C 言語の関数に相当します。というより、C 言語の関数も、一種のサブルーチンとして実現されています。

命令 ニーモニック 命令長 意味
17 CALL 2 サブルーチンを呼出す
18 RET 1 サブルーチンから呼出し元に戻る

それではいつものように、CALL と RET 命令を使ったプログラムを作ってみましょう。

int program[] =
{
  LXI, 0x10000,
  MOVSX,

  LI, 123,
  OUT,
  CALL, 0x100,
  LI, 456,
  OUT,
  -1,
};
 
int sub1[] =
{
  LI, 789,
  OUT,
  RET
};

08. ジャンプで紹介したように、呼出し先のプログラムは別の配列に収めています。この配列 sub1 がサブルーチンに相当します。これを、main 関数のはじめで、

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

として、メモリにロードするようにしてください。実行結果は次のようになることを想定しています。

0x0000007b(123)
0x00000315(789)
0x000001c8(456)

それでは、命令を追加していきたいと思います。

case CALL:
  eaddr = memory[pc];
  pc = pc + 1;
  sp = sp - 1;
  memory[sp] = pc;
  pc = eaddr;
  break;
case RET:
  pc = memory[sp];
  sp = sp + 1;
  break;

CALL 命令では、まず始めに、オペランドである 2 ワード目を読み込んで実効アドレスとし、PC を 1 進めています。この時点で、PC は次の命令のアドレスを保持しているはずです。そして、その PC の値をスタックに退避しています。最後に、実行アドレスを PC に代入することで、サブルーチンにジャンプしています。

RET 命令では、スタックから戻り先アドレス(CALL 命令の次の命令を指しているはず)を取り出し、そのアドレスにジャンプしています。ここで、CALL と RET、あるいは PUSH と POP がうまく対応していないと、つじつまが合わなくなってしまうので要注意です。

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

http://www.kijineko.co.jp/trackback/525