[PP0906] 09. スタック操作

プログラムを実行する上で、非常に重要なデータ構造がスタックです。多くのプロセッサでは、スタックを利用するためのハードウェア的な仕組みが設けられています。スタックは、レジスタの値を一時的に退避したり、サブルーチンを呼出すときに戻り先のアドレスを退避する目的に使われます。

命令 ニーモニック 命令長 意味
13 PUSH 1 アキュムレータをスタックに積む
14 POP 1 スタックから値を取り出し、アキュムレータに格納する
15 PUSHX 1 インデックスレジスタをスタックに積む
16 POPX 1 スタックから値を取り出し、インデックスレジスタに格納する

それでは、スタック操作を行うための簡単なプログラムを書いてみましょう。今回は PUSHX と POPX の使用例は割愛し、PUSH と POP だけを使っています。PUSHX と POPX については、動作確認も兼ねて、各自でプログラムを作ってみてください。

int program[] =
{
  LXI, 0x10000,
  MOVSX,
 
  LI, 123,
  LXI, 456,
  PUSH,
  MOVAX,
  OUT,
  POP,
  OUT,
  -1
};

上のプログラムで、最初の二つの命令(LXI,0x10000 と MOVSX)は、SP の初期化のためのものです。PP0906 では、PC 以外のレジスタは起動時の値が不定になります。SP も例外ではありません。したがって、SP を初期化する必要があるわけです。しかし、SP に直接即値をロードする命令はありませんので、いったんインデックスレジスタを介して初期値を設定することになります。

次に、アキュムレータとインデックスレジスタのそれぞれに即値をロードし、インデックスレジスタ → アキュムレータの順に値を出力しようとしています。インデックスレジスタの値を直接出力する命令はありませんので、アキュムレータを介さなければならないわけですが、それではアキュムレータの値を破壊してしまいます。そこで、PUSH 命令を使って、いったんアキュムレータの値をスタックに退避しています。

それから、インデックスレジスタの値をアキュムレータに転送し、出力しています。次に、アキュムレータの元の値をスタックから取り出し、出力しています。

スタックは、通常上位のアドレスから下位のアドレスへ向かって使用されます。そのため、SP の初期値は、配列 memory の要素数であり、最大のアドレス + 1 の値である 0x10000 を使用しています。スタックに値を積むときは、まず SP を 1 減じてから、その値をアドレスとして、メモリにレジスタの値を書き込みます。逆に、スタックから値を取り出すときは、その時点の SP の値をアドレスとして、メモリから値を読み取り、その後に SP に 1 を加えることになります。

これを踏まえた上で、各命令を作ると次のようになります。

case PUSH:
  sp = sp - 1;
  memory[sp] = a;
  break;
case POP:
  a = memory[sp];
  sp = sp + 1;
  break;
case PUSHX:
  sp = sp - 1;
  memory[sp] = x;
  break;
case POPX:
  x = memory[sp];
  sp = sp + 1;
  break;

スタック操作は、これから現れる PP0906 の他の命令でも使用します。上のコードは、他の要素がからまない最もシンプルなものですので、スタックでつまづいた場合は、いったんここに戻って再確認するとよいでしょう。

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

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