ライトバッファ
ライトバッファとは
一般的に、プロセッサコアクロックに対してバスクロックは低速で、プロセッサコアがメモリに書き込みが完了するまで待機すると、実行速度が低下します。この問題を解消するため、プロセッサコアとバスインターフェースユニット間にライトバッファ(FIFOメモリ)を設け、プロセッサコアの実行速度低下を抑えます。プロセッサコアは、コアクロック速度でライトバッファに書き込めるので、バスインターフェースユニットへの書き込み待機は発生しません。ライトバッファに空きがない場合は、空きができるまでプロセッサコアは待機状態になります。
ライトバッファを制御するDMB(データメモリバリア)命令とDSB(データ同期バリア)命令、パイプラインをフラッシュ(破棄)するISB(命令同期バリア)命令の3種類をバリア命令と言います。
ライトバッファの段数は、テクニカルリファレンスマニュアルを参照ください。尚、Cortex-A9の場合はデータ結合機能を持つ4つの64ビットスロットです。
ライトバッファ制御の必要性
Armプロセッサはメモリタイプとアクセスオーダ(第10回参照)に従ってメモリアクセスを行います。デバイスメモリに配置されているペリフェラルとノーマルメモリに配置されているメモリ間でアクセス順序を守る場合、DMB命令またはDSB命令によるライトバッファの制御が必要です。さらに、キャッシュの制御(Clean(クリーン)/Invalidate(無効))を合わせた検討が必要です。
あわせて読みたい
No | メモリタイプ | キャッシュ | ライトバッファ |
---|---|---|---|
1 | ノーマルメモリ | ◯ | ◯ |
2 | デバイスメモリ | × | ◯ |
3 | ストロングリオーダメモリ | × | × |
バリア命令
バリア命令の動作
アセンブリ言語でのバリア命令
動作制限は非推奨のため設定を省略します。
No | 命令名称 | アセンブリ命令 |
---|---|---|
1 | データ同期バリア | DSB |
2 | データメモリバリア | DMB |
3 | 命令同期バリア | ISB |
C/C++言語でのバリア命令
Armコンパイラは、「Arm C Language Extensions 2.0」で、C/C++言語から使用できる、3種類のバリア命令が定義されています。accs(引数)の動作制限は非推奨のため、デフォルト値の15を設定します。
No | 命令名称 | 関数名称 |
---|---|---|
1 | データ同期バリア | void __dsb(unsigned int accs) |
2 | データメモリバリア | void __dmb(unsigned int accs) |
3 | 命令同期バリア | void __isb(unsigned int accs) |
DMB命令の動作
DMB命令以前に存在するすべてのメモリアクセスが、先にアクセス完了することを保障します。メモリアクセス命令以外の「ADD r0,r1,r2」命令は実行します。
DSB命令の動作
DSB命令以前に存在するすべてのメモリアクセスが完了するまで、以後の命令を実行しないように、プロセッサを待機状態にします。メモリアクセス命令と「ADD r0,r1,r2」命令も実行しません。
ISB命令の動作
Armプロセッサのパイプラインがフラッシュ(破棄)されることを保障します。パイプラインステージの命令が破棄され、命令はメモリシステムから再度フェッチされます。
スタンバイモードとバリア命令を使用した場合の事例
ペリフェラルからの割り込みにより、スタンバイモードから復帰し処理を継続する場合について解説します。ペリフェラルアクセス後に、WFI(*1)組み込み関数を使用しプロセッサをスタンバイモードにする場合、DSB組み込み関数を使用します。
(*1)プロセッサがWFI命令を実行した場合、実行を保留します。詳しくは「Armアーキテクチャリファレンスマニュアル Armv7-AおよびArmv7-Rエディション」を参照ください。
動作説明
STATUSレジスタは0x40000000番地にメモリマップされたレジスタで、0x00000003を書き込むことにより、入力クロックでCOUNTレジスタを減算し、0x0で割り込みが発生します。COUNTレジスタは0x40000004番地にメモリマップされたレジスタで、割り込みが発生するまでの時間を設定します。STATUS/COUNTレジスタは「デバイス」に配置しています。
プログラム解説
- 割り込みを発生するために、STATUS/COUNTレジスタに設定値を書き込みます。
- STATUS/COUNTレジスタの書き込みは、ライトバッファに書き込みが終了した時点で次の命令を実行します。
- WFI組み込み関数の実行で、Armプロセッサコアがスタンバイモードに入るので、ライトバッファの内容がSTATUS/COUNTレジスタに書き込まれている保障はありません。
- 「ノーマルメモリ」と「デバイスメモリ」のアクセス順序は保障されませんので、DSB組み込み関数で書き込み完了まで待機します。
【プログラム例】
#define STATUS (*(volatile unsigned long *)0x40000000) // ステータスレジスタ #define COUNT (*(volatile unsigned long *)0x40000004) // カウンタレジスタ COUNT = 10000; // 一定時間プロセッサの動作を停止 STATUS = 0x00000003; // 動作と割り込み許可 __wfi(); // プロセッサコアをスタンバイへ
【修正プログラム例】
#define STATUS (*(volatile unsigned long *)0x1C010000) // ステータスレジスタ #define COUNT (*(volatile unsigned long *)0x1C010004) // カウンタレジスタ COUNT = 10000; // 一定時間プロセッサの動作を停止 STATUS = 0x00000003; // 動作と割り込み許可 __dsb(15); // すべてのメモリアクセスを完了 __wfi(); // プロセッサコアをスタンバイへ
こちらも是非
“もっと見る” Cortex-A編
初期化処理
リセット例外からmain()関数を呼び出すまでの初期化は、ユーザが作成する部分とArmコンパイラが実行する部分に分けることができます。コードのコピーや初期化変数/未初期化変数の初期化は、リンカのメモリ配置設定を処理系ライブラリが実行します。
PMU(パフォーマンス監視ユニット)
PMUに関連するレジスタは、ユーザモードでのアクセスは禁止されていますので、PMUSERENR(ユーザイネーブルレジスタ)を特権モードでユーザモードアクセス許可を設定します。PMUSERENRについては、 後述の該当項目を参照ください。
TrustZone(セキュリティ拡張機能)
TrustZoneはCortex-Aシリーズの拡張機能で、大規模OSやアプリケーションが動作するノーマルワールドとセキュリティ関連が動作するセキュアワールドを導入しています。TrustZoneでは、ノーマルワールドメモリ空間とセキュアワールドメモリ空間の分離が可能です。