ARM(32bit)用GCCと64bitINTと8バイト境界とFAULT

CoreSourcery G++ 4.5.1 (GCC 4.3.2ベース)で、64bit int値を使うとどんなコードが出るのか見てみた。CPUはSTM32(Cortex-M3)。

; volatile uint64_t a,b;

	push	{r4, r5, r6, lr}
	ldr	r6, .L5+8

; a = 0;
	movs	r0, #0
	movs	r1, #0
	strd	r0, [r6]

; a++;
	movs	r0, #1
	ldrd	r2, [r6]
	movs	r1, #0
	adds	r2, r2, r0
	adc	r3, r3, r1
	strd	r2, [r6]

; a = a + 2;
	movs	r4, #2
	ldrd	r2, [r6]
	movs	r5, #0
	adds	r2, r2, r4
	adc	r3, r3, r5
	strd	r2, [r6]

こんなふうにLDRD/STRD命令を使って、割とコンパクトなコードになってるし、なにより、ロード/ストアが atomic だ(だよね・・・? →後述。アトミックじゃなかった)。
(某社オリジナルコア32bitCPU用のGCCでは、64bit値使ったら、いちいちライブラリをコールしてやがったので、不安になって、チェックしたのです…)

しかし、LDRD/STRD命令は、8バイト境界でないところに使ってしまうと、ARMコアがFAULTするので注意が必要だ。

Cortex-M3(ARM v7-Mアーキテクチャ)は、奇数アドレスからの16bit/32bitデータアクセスが出来る(サイクルは余計にかかるが。なお、ARM7は出来ない)ので、油断していた・・・すこし、ハマった・・・。

注:アンアラインドデータアクセスは単一ロード/ストア命令(LDR/STR)でしか利用できない。コンパイラによっては単純なポインタアクセスでLDM/STM命令を使ってくれたりしてFAULTするので(KEIL…)、この機構に期待しない方が安全だ・・・。

・・・Cortex-M3でも、LDRD/STRD命令は、アトミックってことでいいんだろうか?

マニュアルには、LDM/STMは割り込み中断・再開できるのでレイテンシが改善してると書いてあるけど、LDRD/STRDは割り込まれないんだろうか?
・・・マニュアルに書いてあるのはLDM/STM, PUSH/POPについてだけだから、LDRD/STRDは大丈夫なんじゃないかと思うんだけど・・・。

→うーんでも http://www.yokogawa-digital.com/arm/support/faq/index.php?VER-B-09 に 「ARM v7M 及び v7EM のコアに於いて、LDRD/STRD 命令はシングルコピーの最小単位(atomic)ではありません」[SDCOMP-14812]って書かれててるなあ…アトミックじゃないのかなあ。

→Cortex-M3 テクニカルマニュアルの ETMの項に、 ETMCANCEL ポートの説明として、
現在実行されているオペコードがキャンセルされました。割り込みされたオペコードは、この実行コンテキストに復帰したときに再始動または続行されます。これには、次のオペコードが含まれます。
LDR/STR
LDRD/STRD
LDM/STM
U/SMULL
MLA
U/SDIV
MSR
CPSID
とあるな…。じゃあ、LDRD/STRDもアトミックじゃないのか…。がっかり。

コメント

タイトルとURLをコピーしました