前編では、プログラムがアドレス空間の中に置かれ、その場所はベクタテーブルの中で示されていることを学びました。後編の今回は、プログラムの実行と、割り込みの際にどのようなことがCPU内で起きているかを解説します。

プログラムの進行をナビする―プログラムカウンタ

一般にプログラムとは、コンピュータが行う処理を順序立てて記述した命令の集まりを呼びます。マイコンではプログラムは、前編で解説したアドレス空間(メモリ空間)の中に置き、CPUが命令を実行(処理)します。仮に、アドレス空間中の一つの番地に一つの命令が収められているとすれば、ある番地の命令の実行(例「値をCPU内にセットする」)が行われ、続いて次の番地の命令が実行され、また次の命令が、と連続することでプログラムが実行されます。

では、実行する命令の順番を、どのようにCPUは判断しているのでしょうか……。マイコンでは、プログラムの実行とともに「プログラムカウンタ(PC)」が更新されます。プログラムカウンタとは、CPU内にあるアドレス(番地)を収める場所で、そのCPUが次に実行する命令が置かれている番地が書かれています。ある番地の命令を実行した後、次はどこの番地にある命令を実行したらよいのか、その答えを示しているのがプログラムカウンタです。

通常、プログラムは連続した番地に置かれ、CPUは各々の番地に収められた命令を順番に実行していきます。図1にプログラムカウンタのイメージを示しました。現在、(1)1000h番地にある命令が実行されているとします。(2)1000h番地の命令の実行が終わった時には、プログラムカウンタの値は自動的に値が一つ増加して連続する次の1001h番地を示し、続いて、(3)CPUは1001h番地の命令を実行します。

図1.プログラムカウンタ

図1.プログラムカウンタ

それでは、CPUが最初に命令を実行するときはどうなるのでしょう。マイコンの電源投入時やリセットされた時は、前編で説明したベクタテーブルのリセットに収められた値(プログラムの先頭番地)がプログラムカウンタに移され、その番地の命令が実行されます(前編の図2を参照)。

⇒アドレス空間やベクタテーブルは、本シリーズの第5回「プログラミング(前編)」で解説しています。

プログラムの進行ルートを変える―分岐命令

プログラムを記述していると、ある命令の処理の後に「(連続した)次の番地」ではない番地に置かれた命令を実行させなければならないことがあります。そのような時は、プログラムカウンタの値を書き換えます。このために使う命令を「分岐命令」と呼びます。

図2に、分岐命令のイメージを示しました。この例では、(1)1000h番地に置かれた分岐命令には、(2)プログラムカウンタの値を次に実行すべき番地(1100h)に書き換える命令が書かれています。つまり、CPUは1000h番地の命令(分岐命令)の次には、連続する次の1001h番地の命令を実行することなく、(3)1100h番地の命令を実行することになります。

図2.分岐命令

図2.分岐命令

そのほか、分岐命令では、「現在のプログラムカウンタの値から前に(番地の大きい方へ)/後ろに(番地の小さな方へ)何番地進む」といった方法でプログラムカウンタの値を設定することも可能です。

情報の一時置き場―スタック

プログラムの実行時、演算中などには、CPUの中にあるデータの記憶場所(CPU内部レジスタ)だけでは足りなくなり、メインメモリの中に一時的に情報を置くことがあります。そのような情報の一時置き場を「スタック」と呼び、「次に(一時的に)情報を置く番地」を収めているのが「スタックポインタ(SP)」です。最初にスタックの場所を設定すれば、スタックポインタは自動的に更新され常に「次に(一時的に)情報を置く番地」を指してくれます。

⇒CPU内部レジスタなど、マイコンの構成は「マイコン入門(1)」で解説しています。

「この情報をスタックに置く(「積む」と表現することもあります)」という命令が実行されると、指定された情報が、スタックポインタが指している番地に書き込まれ、スタックポインタの値は、新しい番地(一般には一つ小さな番地)に更新されます。この様子を図3に示します。(1)CPUが、スタックポインタが指す番地へ情報を置くと、(2)スタックポインタの値が更新され、(3)次に情報を置く番地を指します。

図3.スタックに情報を置く

図3.スタックに情報を置く

スタックに置いた情報をCPUに戻すときも、スタックポインタが使われます。図4に情報を戻す様子を示します。(1)スタックポインタの値を(一つ大きい番地に)更新し、(2)一時的にスタックに置いた情報をCPUに戻す。その時、スタックポイントは(3)次に書き込める番地(先ほどCPUに情報を戻して空いた場所)を指している。

図4.スタックから情報を戻す

図4.スタックから情報を戻す

 

スタックに情報を置くことは、無限にできるわけではありません。RAMと呼ばれる書き替え可能なメモリの範囲だけがスタックとして利用できるからです。もしも情報を置き過ぎて、スタックがRAMの領域からはみ出してしまうと、プログラムは正常に動きません。

※スタックに情報を置く、スタックに置いた情報をCPUに戻す手順はCPUによって異なります。

割り込み処理を理解しよう

さて、今回は本シリーズ「マイコン活用 基礎編 周辺機能を学ぼう」の最終回です。いままで解説した内容をひとつに束ねて、マイコンの動作(処理)を理解しましょう。

例として、割り込みが起きたときの処理を考えます(図5)。割り込み処理とは、あるプログラムを実行中に、何らかのきっかけ(割り込み)により、全く別のプログラムを開始することでした。周辺機能の一つである独立ウォッチドッグタイマ(WDT、ウォッチドッグとは、番犬の意味です)からの割り込みを例に考えましょう。独立ウォッチドックタイマは、プログラムが正常に動作していれば何もしませんが、プログラムが暴走して必要な手順の処理を行っていないと割り込みを発生させます。暴走したプログラムを終了させシステムを安定的に停止させる処理は、割り込みにより開始されたプログラムで行います。割り込み処理の流れは、本シリーズの第4回「割り込み」の図2を参照して下さい。
⇒割込みの仕組みや処理の流れは、本シリーズの第4回「割り込み」で解説しています。
⇒ウォッチドックタイマについては、本シリーズの第2回「タイマ」で解説しています。

図5.割り込み処理の流れ

図5.割り込み処理の流れ

  1. まず、割り込みが発生すると、実行中のプログラムを退避させなければなりません。
  2. 割り込み処理の「退避」の際には、スタックポインタが指している番地(スタック)に情報を置きます。割り込み処理時にスタックに置かれる情報は、その時実行している元のプログラム(割り込まれたプログラム)のプログラムカウンタの値、つまり、元のプログラムをどこまで実行していたかという情報(番地)です。そのほかにも、CPUの内部状態を表す情報や一時的に記憶していた値もスタックに置かれます。
  3. CPU内部の情報がスタックに置かれ「明け渡し」の準備(退避)が完了すると、割り込みプログラムが実行されます。割り込みプログラムは、実行中のプログラムとは別のものでアドレス空間の中でも別の場所に置かれているので、プログラムカウンタの値は元のプログラムと全く異なります。割り込みプログラムの開始場所は、ベクタテーブルに書かれています。どのような割り込みがあったかによって、ベクタテーブル中のどの項に書かれた開始番地が使われるかが決まります。例えば、ノンマスカブル割り込み(NMI、禁止できない割り込み)が起きたのであれば、NMIの項に書かれた番地から処理が始まります(本シリーズ第5回「プログラミング前編」の図2と図3を参照)。

    ⇒ベクタテーブルを使った処理の流れは、本シリーズの第5回「プログラミング(前編) 」で解説しています。

  4. こうして、ベクタテーブルのNMIの項にある値(番地)がプログラムカウンタに移され、そこから実行が始まります。そのほかにも、例えば数値を0で割ろうとしてエラーが出たときや、メモリが無い場所をアクセスしようとしたときにも、CPUが自ら割り込みを起こしベクタテーブルから処理を開始する番地を読み出します。この例では、プログラムの暴走を検知した独立ウォッチドックタイマによる割り込み処理のため、割り込みプログラムはシステムの停止処理に進みます。
  5. 通常の周期的な割り込みの場合は、割り込み処理が終わると、退避する時にスタックに置いた「元のプログラム実行時の情報」をCPUに戻します。最後にプログラムカウンタの値を戻して、割り込みから戻るための処理である「復帰」が完了します。

割り込みプログラムを始めるときは、外部からの信号やCPU自身が発する命令で退避を開始します。復帰の際は「割り込みからの復帰命令」という命令を使います。プログラマが、「どの情報をどんな順序でスタックに置いたか?」と管理する必要はありません。命令一つで、復帰処理がなされます。

前回のプログラミング前編とあわせて、プログラムの実行という観点で、CPUの中で何が起きているかを解説してきました。アドレス空間にプログラムが置かれること、ベクタテーブルに開始番地が収められること、スタックという情報の一時置き場があること……など、組み込みプログラミングを行うときは、このような内部の動作を考えながら記述します。細かな部分までプログラムで指示でき、そのマイコンの力を引き出すことができれば、プログラミングがより楽しくなります。

全6回で解説してきた本シリーズ(マイコン活用 基礎編 「周辺機能」を学ぼう)は今回で最終回です。どの回も、本当に基本的なことを解説しただけですが、その分、予備知識がなくても理解できるように努めました。ぜひ、何度も読み返して、しっかりと理解して下さい!

「周辺機能」を学ぼう

  1. GPIO
  2. タイマ
  3. シリアル通信
  4. 割り込み
  5. プログラミング(前編)
  6. プログラミング(後編)