k-ogawa2025’s ブログ

メカトロ制御回路設計に関する情報発信ブログ

1.8 スタック

本項ではメカトロ制御に使うCPUのスタックについて記載しています。

一般にスタックはLIFO(Last In First Out)構造を持つバッファーのことですが、ここで取り上げるのはLIFO構造のバッファーでCPUに例外事象が発生したときにレジスタの値を一時的に退避する用途のスタックです。例外事象については「1.9 例外」を見てください。また、ここで取り上げるスタックはプログラムからレジスタの値を一時的に退避する用途にも使います。

CPUはスタック全体を内蔵しているのではなく、レジスタの値を退避する記憶場所にはMCU内蔵のSRAMなどのCPUの外部にあるメモリーを割り当てる必要があります。CPUが持っているのは制御レジスタのスタックポインター(SP)です。スタックポインター(SP)はスタックとして割り当てられたメモリーのどこまでを使っているか示します。

ここでは、下記の3つについて書きます。


1.8.1 スタックへのレジスタ退避

例外事象が発生した時にCPUがレジスタの値をスタックに退避する動作を下記に書きます。前提条件として、例外事象が発生するとCPUはフラグと割り込み制御が一緒になったレジスタ(以下ではステータスレジスタと称します)とプログラムカウンターの2つのレジスタの値をスタックに退避するとします。このCPUのレジスタは32bit幅とします。

まず、初期状態です。スタックとしてCPU外部にあるメモリーのm 番地からn Byteの領域を使います。スタックポインター(SP)の初期値はスタック領域の最上位アドレスに1を加えた値にするので、この場合は (m+n) をスタックポインター(SP)にリセット後の初期設定で設定します。初期値がこの値になるのは、スタックにレジスタの値を退避するときはスタック領域の最上位アドレスからアドレスの小さいほうへ順番に使っていくからです。

例外事象が発生するとCPUは最初にステータスレジスタの値をスタックに退避します。32bit幅のレジスタの値をメモリーに書き込むには4Byteの領域が必要になるので、初期状態のスタックポインター(SP)の値から4減算した (m+n−4) を新しいスタックポインター(SP)の値にし、その値のアドレスにステータスレジスタの値を書き込みます。

CPUは次にプログラムカウンターの値をスタックに退避します。スタックポインター(SP)の値をさらに4減算した (m+n−8) を新しいスタックポインター(SP)の値にし、その値のアドレスにプログラムカウンターの値を書き込みます。

上記に書いたスタックポインター(SP)の値の変化を下図に示します。

図 1.8-1 レジスタ退避時のスタックとスタックポインター(SP)

1.8.2 スタックからのレジスタ復帰

次に例外事象による処理が終わり元のプログラムに戻るときにCPUが行うスタックからレジスタに値を復帰する動作を下記に書きます。前述の様に例外事象が発生したときにCPUはフラグと割り込み制御が一緒になったステータスレジスタとプログラムカウンターの値をスタックに退避しています。

復帰前は「図 1.8-1 スタックへのデータ退避」の右側の「プログラムカウンター退避後」と同じ状態で、スタックポインター(SP)の値は (m+n−8) です。

まず、CPUはスタックからプログラムカウンターの値を復帰します。メモリーのスタックポインター(SP)が示す (m+n−8) 番地から値を読み出してプログラムカウンターに格納します。そして、スタックポインター(SP)の値に4加算した (m+n−4) を新しいスタックポインター(SP)の値にします。

次にCPUはスタックからステータスレジスタの値を復帰します。メモリーのスタックポインター(SP)が示す (m+n−4) 番地から値を読み出してステータスレジスタに格納します。そして、スタックポインター(SP)の値に4加算した (m+n) を新しいスタックポインター(SP)の値にします。

スタックに退避した2つのレジスタの値を復帰するとスタックポインター(SP)の値はレジスタを退避する前の値、すなわち「図 1.8-1 スタックへのデータ退避」の左側の「初期状態」と同じ値の (m+n) に戻りました。

上記に書いたスタックポインター(SP)の値の変化を下図に示します。

図 1.8-2 レジスタ復帰時のスタックとスタックポインター(SP)

1.8.3 スタックの仕組みのまとめ

スタックの仕組みについてまとめると下記になります。

  • スタックポインター(SP)はスタックとして割り当てたメモリーのどこまでを使っているか示す。
    モリーのスタックとして割り当てた領域の最上位アドレスからスタックポインター(SP)の値のアドレスまでを使っています。
  • リセット後の初期設定でスタックポインター(SP)にスタック領域の最上位アドレスに1を加えた値を設定する。
    この状態ではスタックは空なことを示します。
  • スタックにレジスタの値を退避するときはスタックポインター(SP)の値を4減算し、メモリーのその値の番地にレジスタの値を書き込む。
  • スタックからレジスタに値を復帰するときはメモリーのスタックポインター(SP)の値のアドレスから読み出してレジスタに格納する。そのあとにスタックポインター(SP)の値を4加算する。
    スタックに退避したレジスタの値を復帰するとスタックポインタ(SP)の値はレジスタを退避する前の値に戻ります。

このスタックにレジスタの値を退避するときと復帰するときの動作は例外事象が起きた時だけでなく、プログラムでレジスタの値を退避するとき(PUSH命令など)と復帰するとき(POP命令など)も同じです。スタックポインタ(SP)の減算とメモリーへの書き込み、またはメモリーの読み出しとスタックポインタ(SP)の加算がセットで行われます。

このように一時的なレジスタの値の退避にスタックを使うと、退避している間はメモリーの領域を使いますが復帰すると使っていた領域を空けるのでこの後に他のレジスタの値を退避することに使用できるようになります。すなわち必要な期間だけメモリーの領域を使うので少ないメモリー領域で済ますことができます。

例として用いるCPUのスタックポインター(SP)については「1.3.2.2 スタックポインター(SP)」を見てください。

メカトロ制御向け CPUの構造と動作