パイプライン処理(時間的並列処理)
パイプライン処理とは、一つの操作を複数の部分操作に分解し、それぞれが独立に、かつ同時に処理できるユニットを用意し、並行して動作させる並列処理のことを言います。
例えば命令をメモリから読み出して、演算を行って、演算結果を記憶装置(メモリまたはレジスタ)に格納するまでの一連の作業を次のような分担のユニットに分けます。
- 命令を読み出すユニット(フェッチ)
- 命令コードを解読・翻訳するユニット(デコード)
- 演算を実行するユニット(演算)
- 演算結果を記憶装置に格納するユニット(格納)
各々のユニットは他のユニットとは完全に独立して自分の仕事を行います。通常は1クロックで仕事を終えて、次のユニットに処理結果を送ります。他のユニットが何をどう処理していようがお構いなく、自分の仕事だけをひたすら1サイクルで行います。
上記の場合「1」~「4」の4段階でひとつの命令の処理が終わるので、4段パイプラインと呼びます。実際は1命令に4サイクル必要ですが、各々のユニットが並列処理を行い、「4」の処理は1サイクルごとに結果を出しますので、見かけ上1サイクルで1命令の処理が終るようになります。
メリットとデメリットを挙げると次のようになります。
- メリット
- 同種の操作が連続的に行われる場合に好適(RISC向き)
- ハードウェアが小さくなる
- デメリット
- 簡単な操作には逆効果
- 並列度を極端に高くすることができない(パイプライン障害が起きると効率が落ちる)
Cortex-M3のパイプライン処理
Cortex-M3は3段パイプライン処理です。3段とは「フェッチ」「デコード」「演算(格納含)」です。下図にCortex-M3のパイプラインシーケンスの図を示します。
- ステップ1:Flashから命令をフェッチ(F)
- ステップ2:命令をデコード(解読・翻訳)(D)
- ステップ3:演算して、結果の書き込み(E)
0x8FECのAND命令から0x8FF0のEOR命令までは、何の障害もなくパイプライン処理が行われ、1サイクルごとに演算結果が出てきますので、1命令1サイクルになります。
しかし、0x8000のBX r5命令のような条件分岐命令があると、演算結果によって、0x8002のSUB命令を続けて演算するのか、0x8FECのAND命令に分岐するのが決まるため、BX r5命令の結果を待たなければなりません。そのためパイプライン処理が中断します。この様にパイプライン処理が中断することをパイプライン障害と呼びます。分岐命令以外でも、リード・アフタ・ライトと言って「ある命令の結果が次の命令のオペランドとして使われる場合」でもパイプライン障害が起きます。
Cortex-M3では、この様なパイプライン障害が発生しても、被害を最小限に抑えるために、前もって分岐先を計算しておく機能を持っています。その機能を分岐投機と呼んでいます。下の例は2サイクルのロスになっています。
こちらも是非
“もっと見る” Cortex-M編
SysTick、電力管理
SysTick機能を有効にするには、SysTick制御およびステータスレジスタを使用します。このレジスタのENABLEビットを1にすると、カウンタは動作をはじめます。つまり、カウンタにリロード値がロードされてから、カウントダウンが開始されます。
メモリマップ
Cortex-M3のメモリマップには、一般的なマイコンのメモリマップと若干異なる特徴があります。一般的なマイコンでは、メモリ領域を変更できるものもあります。しかし、Cortex-M3のメモリマップは定義されたメモリマップになっており、アドレス領域のマッピングは固定です。
ベクタテーブル
Cortex-M3のベクタテーブルは0番地から始まります。一般的なマイコンは、ベクタテーブルの最小アドレス部(0番地)にはリセットベクタが割り当てられていますが、Cortex-M3ではメインスタック(SP_main)の初期値が割り当てられています。