BitBand
今回、ライブラリの使い方は置いといて、ARM Cortex-MのBitBandという機能について見てみます。
BitBandについては、こちらでわかりやすく説明されています。要約すると、RAMやレジスタを複数箇所で触っている場合、1ビット操作をしたいときに、普通はディスパッチ禁止区間を作って、リード、変更、ライトを行うところを、これらの処理を1命令でアトミックに実行できる機能で、Coretex-Mの特徴機能だそうです。
hw_types.h では、下記のように、BitBand エイリアス領域にアクセスするマクロが定義されています。BitBand エイリアス領域は、1MByteの領域に対して、1bit毎に1アドレス(32bit)を割り当てているので、空間上32Mbyte存在します。stellarisのSRAM 0x20000000~ は、0x22000000 から 0x223FFFFF までが、BitBand エイリアス空間ということになりますが、もちろん、実際は32KByte RAMの領域しかありません。
#define HWREG(x) \ (*((volatile unsigned long *)(x))) #define HWREGBITW(x, b) \ HWREG(((unsigned long)(x) & 0xF0000000) | 0x02000000 | \ (((unsigned long)(x) & 0x000FFFFF) << 5) | ((b) << 2))
下のようなサンプルコードを書いてみました。
g_ulValue は SRAM 上の変数です。
テスト1では、マクロを使って1ビット書き込みをしています。
テスト2では、g_ulValue に設定した値を、マクロを使って1ビットずつ読みんでみます。
テスト3では、マクロを使わず、g_ulValue のアドレスである、0x20004000 に対するBitBand エイリアスアドレスに直接、値を設定しています。
#include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "driverlib/gpio.h" #include "driverlib/pin_map.h" #include "driverlib/sysctl.h" #include "utils/uartstdio.h" static volatile unsigned long *g_ulValue = 0x20004000; // RAM上の適当な場所 int main(void) { int i; unsigned long *alias; SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); // Init UART SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); UARTStdioInit(0); // test 1. // BitBand による 1 ビット書き込み *g_ulValue = 0; HWREGBITW(g_ulValue, 10) = 1; UARTprintf("0x%08x\n", *g_ulValue); // test 2. // BitBand による 1 ビット読み込み *g_ulValue = 0x4; for (i = 0; i < 32; i++) { UARTprintf("%d", HWREGBITW(g_ulValue, 31 - i)); } UARTprintf("b\n"); // test 3. // 直接 g_ulValue の 16 ビット目の BitBand エイリアスアドレスに書き込み *g_ulValue = 0; alias = 0x22080040; // 0x22000000 + 0x4000 * 32 + 16 * 4 *alias = 1; UARTprintf("0x%08x\n", *g_ulValue); while(1){} }
結果は期待通りです。
0x00000400 00000000000000000000000000000100b 0x00010000
テスト3の 45 行目のアセンブリを見ても、エイリアスアドレス 0x22080040 へのSTRだけになっています。
44 alias = 0x22080040; // 0x22000000 + 0x4000 * 32 + 16 * 4 0000073e: 480E LDR R0, $C$CON5 00000740: 9001 STR R0, [SP, #0x4] 45 *alias = 1; 00000742: 9801 LDR R0, [SP, #0x4] 00000744: 2101 MOV R1, #0x1 00000746: 6001 STR R1, [R0]