ARMは記述した順番に命令実行されない
===============================
ARMマイコンでは、命令実行を効率化する為にCPU内部ハードウェアレベルで、命令実行の入れ替えを行っている。
従って、命令を記述した順番に命令実行やデータアクセスが必ずしも実行されない。特に、IOレジスタ操作などで実行順番が重要な場合には注意が必要。
尚、このような効率化はARMマイコンに限らず最近の高性能CPUでは当たり前に使われている技術。
バリア命令
---------
ARMにはこのような事象に対処する為に、下記の命令を備えている。
### データメモリバリア(DMB)命令
- データメモリバリア命令よりも前に存在するすべてのメモリアクセスが、先にアクセス完了する事を保障する。
- メモリアクセスに関連しない、命令を実行する事は可能。
### データ同期バリア(DSB)命令
- データ同期バリア命令よりも前に存在するすべてのメモリアクセスが完了するまで、以後の命令を実行しないように、プロセッサを待機状態にする。
- データ同期バリア命令が完了するまで、それ以降の命令が実行を完了したり割り込みマスクを変更する事はない。
- 全てのキャッシュ、分岐予測およびTLBメンテナンス処理が完了する。
### 命令同期バリア(ISB)命令
- 命令同期バリア命令はパイプラインをフラッシュし、命令キャッシュ(またはメモリ)から再フェッチする。
記述例
-----
下記、ルネサスのサンプルプログラムから抜粋。
/*******************************************************************************
* Outline : initializing Cortex-M3 settings
* Function Name: init_cm3
* Description : Initialize Cortex-M3 settings of RZ/T1.
Copy the Cortex-M3 code
* Arguments : none
* Return Value : none
*******************************************************************************/
void init_cm3( void )
{
volatile unsigned char *p_org;
volatile unsigned int psize;
unsigned char *p;
/* Copy the Cortex-M3 program code */
p =(unsigned char *)( 0x04000000+0x0 );// M3 RAM start address for Cortex-R4
p_org = __section_begin("CM3_SECTION");
psize = __section_size("CM3_SECTION");
memcpy(p, (char *)p_org, psize);
asm("dsb"); // Ensuring data-changing
/* Release the Software reset 2 (Cortex-M3) */
R_RST_WriteEnable();
asm("isb"); // Ensuring instruction-changing
SYSTEM.SWRR2.LONG = 0x00000000; // Release Software reset 2
asm("isb");
R_RST_WriteDisable();
}
- EWARMでは、`__DSB()` `__ISB()` などのようにコンパイラ組み込み関数を利用しても記述できる。(`#include `が必要)
補足
----
- I/Oデータアクセス順番を確保する為に、`DSB`命令などを使わずに、該当レジスタのダミーリードで記述してある例もある。(多少、命令の処理速度が速くなる為と思われる)
参考
----
1. [[wpjp>メモリバリア]]
2. [[http://i-saint.hatenablog.com/entry/20101005/1286208402|マルチスレッドとメモリ同期]]
3. [[https://k-onishi.hatenablog.jp/entry/2019/03/10/000311|Linux Kernel ~ 同期機構 ~]]
4. [[https://srad.jp/~Yoh2/journal/544783/|ロード/ストア命令の追い越し例]]