本項では「2.2 動作確認用プログラムLED1の説明」で説明した動作確認用プログラムLED1をArm製Cortex-M33で実行し、CPUが条件成立により分岐する動作を確認します。前項までと同じく、マイコン開発ボードのSTマイクロエレクトロニクス製NUCLEO-H503RBと統合開発環境のSTマイクロエレクトロニクス製STM32CubeIDEを使います。
確認する動作
- 演算結果によりフラグが変化する
- 条件分岐命令はフラグの値が条件に、合っていると分岐を行い、合っていないと何もしないで次の命令に進む
「1.3.2.3 フラグ」に書いたように、CPUは減算命令や比較命令のような演算命令を実行すると演算結果に応じてフラグの値を変化させます。
そして条件分岐命令はフラグの値が条件に合っているとプログラムカウンター(PC)の値が分岐先の命令の先頭アドレスに書き換えられて分岐を行います。一方、フラグの値が条件に合っていないと何もしないで、プログラムカウンター(PC)の値に条件分岐命令の命令長が加算されて次の命令に進みます。
この確認で実行する演算命令と条件分岐命令はLD2の点灯と消灯の間隔を作る500ms遅延サブルーチンの中の「カウンタ値1減算」する演算命令と「カウンタ値≠0」ならカウンタ1減算に戻る条件分岐命令です。下図のフローチャートでは太い矢印で指している命令です。このフローチャートでは条件分岐命令の条件を一般的な「カウンタ値≠0」と記述していますが、これをフラグの値で記述すると「Z==0」になります。(「1.3.2.3 フラグ」参照)以降では条件分岐命令の条件を「Z==0」と記述します。

ここで500ms遅延サブルーチンの説明をしておきます。このサブルーチンの機能は、呼ばれてから500ms後にサブルーチンから復帰して元のプログラムに戻るというものです。そのための動作は、まずカウンタに繰り返し回数の5,333,333を設定し、カウンタ値を1減算する命令をカウンタ値が0になるまで繰り返します。この繰り返しにかかる時間で500msの遅延を作っていて、繰り返し1回に93.75nsかかる計算になります。CPUのクロック周波数は32MHzなので周期は31.25nsです。ですから繰り返し1回に3クロックかかる計算になります。なお繰り返し回数は試行錯誤して決めました。
確認の手順
1)CPUにリセットをかけた後プログラムを停止した状態にします。
リセットはツールバーの
Reset the chip and restart debug sessionアイコンをクリックします。
2)500ms遅延サブルーチンの中の「カウンタ値1減算」する演算命令の前でプログラムの実行が停止するようにブレークポイントを設定します。
まず、ウィンドウの中央部に表示されているプログラムのソースファイル:LED1.sの上で84行が見えるように縦スクロールします。この行が「カウンタ値1減算」する演算命令です。次に、行番号の「84」をダブルクリックします。行番号の84の前にブレークポイントが設定されたことを示す
のアイコンが表示されます。
メニューで Window → Show View → Breakpoints をクリックしてBreakpointsビューを表示すると、ここでもLED1.sの84行にブレークポイントが設定されたことがわかります。

3)プログラムを実行してブレークポイントで停止した状態にし、「カウンタ値1減算」する演算命令の先頭アドレスを確認します。
プログラムの実行はツールバーの
Resume アイコンをクリックします。
ウィンドウの中央部に表示されているLED1.sを見るとブレークポイントを設定した84行に矢印が付いてハイライト表示されています。「カウンタ値1減算」する演算命令の前でプログラムの実行が停止したことがわかります。
Registersビューでpcの値を見ると0x0800 0080です。これが「カウンタ値1減算」する演算命令の先頭アドレスです。

4)「Z==0」なら「カウンタ1減算」に戻る条件分岐命令の先頭アドレスと命令長、分岐先アドレスを確認します。
ウィンドウ中央部でLED1.listのタブをクリックしてファイルが見えるようにします。3)で確認したプログラムカウンター(PC)の値:0x0800 0080が命令の先頭アドレスになっている機械語の行を探すと119行で、この行の命令が「カウンタ値1減算」する演算命令です。この命令の次の機械語の行を探すと122行で、この行の命令が「Z==0」なら「カウンタ1減算」に戻る条件分岐命令です。
122行の条件分岐命令の先頭アドレスは0x0800 0082です。
機械語の命令は0xD1FDで、命令長は2Byte(16bit)です。
分岐先アドレスはこの行の逆アセンブル結果を見るとわかり、0x0800 0080です。ですから条件(Z==0)が成立すれば119行の「カウンタ値1減算」する演算命令に分岐します。
ちなみに、逆アセンブル結果の最初にある「bne」がZ==0を条件とする条件分岐命令を意味し[1]、次の「.n」は命令長2Byteの命令を意味します[2]。

5)「カウンタ値1減算」する前のカウンタ値を確認します。
LED1プログラムでは500ms遅延サブルーチンのカウンタに汎用レジスタのR0を使っています。Registersビューでr0の値を見ると0x0051 6155です。この値を10進数にすると5,333,333で、「カウンタ値1減算」の繰り返し回数です。
6)「カウンタ値1減算」する前のゼロフラグ(Z)の値を確認します。
Registersビューでxpsrの値を見ると0x0100 0000です。値の表示は上位の0が省略されるので桁数に注意してみてください。xPSRレジスタのbit[30]がゼロフラグ(Z)なので[3]、ゼロフラグ(Z)の値は0です。これが「カウンタ値1減算」する前の値です。ただし、この値はリセットからこれまでに実行した命令の結果であり、今回の確認に直接関係はありません。
7)「カウンタ値1減算」する演算命令を実行して、カウンタ値とゼロフラグ(Z)の値を確認します。
ツールバーの
Step Intoアイコンをクリックして1命令実行します。
Registersビューでr0の値は0x0051 6154です。5)で確認した値から1減りました。
同じくRegistersビューでxpsrの値は0x2100 0000です。xPSRレジスタのbit[30]がゼロフラグ(Z)なのでゼロフラグ(Z)の値は0です。次に実行する条件分岐命令の条件はZ==0なので条件は成立します。
8)「Z==0」なら「カウンタ1減算」に戻る条件分岐命令を実行して、プログラムカウンター(PC)の値を確認します。
ツールバーの
Step Intoアイコンをクリックして1命令実行します。
Registersビューでpcの値は0x0800 0080です。4)で確認した分岐先のアドレスに変わりました。Z==0の条件が成立して、分岐先の「カウンタ値1減算」する演算命令の先頭アドレスに書き換えられていることがわかります。
ウィンドウの中央部に表示されているプログラムのソースファイル:LED1.sの上では84行に矢印が付いてハイライト表示されています。ここでも「カウンタ値1減算」する演算命令に分岐したことがわかります。

9)「カウンタ値1減算」する演算命令の2回目の実行を行い、カウンタ値とゼロフラグ(Z)の値を確認します。
ツールバーの
Step Intoアイコンをクリックして1命令実行します。
Registersビューでr0の値は0x0051 6153で、7)で確認した値から1減りました。
同じくRegistersビューでxpsrの値は0x2100 0000です。xPSRレジスタのbit[30]がゼロフラグ(Z)なのでゼロフラグ(Z)の値は0で、7)で確認した値と同じです。
10)「Z==0」なら「カウンタ1減算」に戻る条件分岐命令の2回目の実行を行い、プログラムカウンター(PC)の値を確認します。
ツールバーの
Step Intoアイコンをクリックして1命令実行します。
Registersビューでpcの値は0x0800 0080と、8)で確認した値と同じで分岐先のアドレスに変わっています。今回もZ==0の条件が成立して、分岐先の命令の先頭アドレスに書き換えられました。
11)条件分岐命令の次の命令の前でプログラムの実行を停止するようにブレークポイントの設定を変更します。
まず、ウィンドウの中央部に表示されているプログラムのソースファイル:LED1.sの上で行番号「88」をダブルクリックします。行番号の88の前にブレークポイントが設定されたことを示す
のアイコンが表示されます。この行が条件分岐命令の次の命令で、分岐しなかった場合に実行します。
次に、Breakpointsビューに表示されている84行に設定したブレークポイントの先頭についているチェックをクリックして外し無効にします。88行に設定したブレークポイントにだけチェックが付いて有効な状態です。

12)プログラムを実行してブレークポイントで停止した状態にし、条件分岐命令の次の命令の前でプログラムが停止したときのプログラムカウンター(PC)とカウンタ値、ゼロフラグ(Z)の値を確認します。
プログラムの実行はツールバーの
Resume アイコンをクリックします。
Registersビューでpcの値は0x0800 0084です。このプログラムカウンター(PC)の値は、4)で確認した条件分岐命令の先頭アドレス:0x0800 0082に命令長:2(単位Byte)を加えた値です。条件分岐命令が分岐しなかったことがわかります。
ウィンドウの中央部に表示されているLED1.sを見るとブレークポイントを設定した88行に矢印が付いてハイライト表示されています。ここでも条件分岐命令が分岐しなくて次の命令の前でプログラムの実行が停止したことがわかります。
Registersビューでr0の値は0x0000 0000で、カウント値が0になっています。
同じくRegistersビューでxpsrの値は0x6100 0000です。xPSRレジスタのbit[30]がゼロフラグ(Z)なのでゼロフラグ(Z)の値は1です。9)の確認結果から変化しました。
「カウンタ値1減算」する演算命令を繰り返した結果、カウント値:R0レジスタが0に、ゼロフラグ(Z)は1になり、条件分岐命令の条件:Z==0が成立しないので分岐しないで次の命令に進んだと考えられます。

13)ブレークポイントを削除して、プログラムを実行します。
設定していたブレークポイントの削除は、Breakpointsビューで
Remove All Breakpointsアイコンをクリックします。
プログラムの実行はツールバーの
Resume アイコンをクリックします。マイコン開発ボード:NUCLEO-H503RBのLD2が点滅します。
ここまででプログラムLED1を使った動作の確認を終わります。デバッガーを終了するにはツールバーの
Terminateアイコンをクリックしてください。

以上で、CPUが条件成立により分岐する動作の確認は終わりです。
演算結果によりフラグが変化することがわかりました。
また、条件分岐命令はフラグの値が条件に、合っていると分岐を行い、合っていないと何もしないで次の命令に進むことがわかりました。
| 項目 | カウンタ値1減算 実行前 |
カウンタ値1減算 1回目実行後 |
カウンタ値1減算 2回目実行後 |
条件分岐命令の 次の命令の前で 停止時 |
|---|---|---|---|---|
| カウンター値(R0) | 0X0051 6155 | 0X0051 6154 | 0X0051 6153 | 0x0000 0000 |
| ゼロフラグ(Z)の値 | 0 | 0 | 0 | 1 |
| カウンタ1減算後の 条件分岐命令の動作 |
- | 分岐した | 分岐した | 分岐しなかった |
[1] Arm Limited.Arm® Cortex®-M33 Devices Generic User Guide.Issue 0100-06.1 August 2024,3.11.2 B, BL, BX, and BLX.p.166-168,3.3.7.2 Condition code suffixes.p.94-95.
[2] Arm Limited.Arm® Cortex®-M33 Devices Generic User Guide.Issue 0100-06.1 August 2024,3.3.8 Instruction width selection.p.95.
[3] Arm Limited.Arm® Cortex®-M33 Devices Generic User Guide.Issue 0100-06.1 August 2024,2.1.3.6 Combined Program Status Register.p.24-25.
メカトロ制御向け CPUの構造と動作
2.7 条件成立により分岐する動作 ← 現在のページ