2011-07-19 50 views
5

在CMSIS定義爲GCC你可以找到這樣的事情:數據內存屏障(DMB)的CMSIS庫的Cortex-M3S

static __INLINE void __DMB(void) { __ASM volatile ("dmb"); } 

我的問題是:內存屏障有什麼用,如果它沒有在clobber列表中聲明「內存」?

這是core_cm3.h中的錯誤,還是有一個原因,爲什麼gcc應該沒有任何額外的幫助正確行爲?

+1

好問題。請注意,Linux使用'memory' clobber:http://lxr.free-electrons.com/source/arch/arm/include/asm/system.h?v=2.6.39#L135 – ninjalj

+1

@ninjalj:感謝鏈接。 (沒有出現在Google上) – jpc

回答

5

我用gcc 4.5.2(用LTO構建)做了一些測試。如果我編譯此代碼:

static inline void __DMB(void) { asm volatile ("dmb"); } 
static inline void __DMB2(void) { asm volatile ("dmb" ::: "memory"); } 

char x; 

char test1 (void) 
{ 
    x = 15; 
    return x; 
} 

char test2 (void) 
{ 
    x = 15; 
    __DMB(); 
    return x; 
} 

char test3 (void) 
{ 
    x = 15; 
    __DMB2(); 
    return x; 
} 

使用arm-none-eabi-gcc -Os -mcpu=cortex-m3 -mthumb -c dmb.c,然後從arm-none-eabi-objdump -d dmb.o我得到這個:

00000000 <test1>: 
    0: 4b01  ldr r3, [pc, #4] ; (8 <test1+0x8>) 
    2: 200f  movs r0, #15 
    4: 7018  strb r0, [r3, #0] 
    6: 4770  bx lr 
    8: 00000000 .word 0x00000000 

0000000c <test2>: 
    c: 4b02  ldr r3, [pc, #8] ; (18 <test2+0xc>) 
    e: 200f  movs r0, #15 
    10: 7018  strb r0, [r3, #0] 
    12: f3bf 8f5f dmb sy 
    16: 4770  bx lr 
    18: 00000000 .word 0x00000000 

0000001c <test3>: 
    1c: 4b03  ldr r3, [pc, #12] ; (2c <test3+0x10>) 
    1e: 220f  movs r2, #15 
    20: 701a  strb r2, [r3, #0] 
    22: f3bf 8f5f dmb sy 
    26: 7818  ldrb r0, [r3, #0] 
    28: 4770  bx lr 
    2a: bf00  nop 
    2c: 00000000 .word 0x00000000 

顯而易見的是,__DBM()只插入dmb指令,它需要DMB2()實際強制編譯器刷新緩存在寄存器中的值。

我想我發現了一個CMSIS錯誤。

2

恕我直言,CMSIS版本是正確的。

注射沒有撞列表中的內存屏障指令實現它到底是什麼應該做的:

如果「X」變量前面寫了緩衝則承諾。例如,如果您要將「x」地址傳遞爲DMA地址,或者您要設置MPU,這非常有用。

它對返回「x」沒有影響(即使您省略了內存障礙,您的程序也保證是正確的)。

另一方面,通過在clobber列表中插入內存,您在以前的示例(DMA,MPU ..)等情況下沒有任何效果。

後一種情況唯一的區別是,如果你有例如一個ISR在「strb」之後修改「x」的值,那麼返回的值就是由ISR修改的值,因爲clobber導致編譯器從內存中讀取以再次註冊。 但是,如果你想獲得這個東西,那麼你應該使用「易變」的變量。

換句話說:爲了保證與其他可能訪問RAM存儲器的硬件​​資源的一致性,屏障強制高速緩衝存儲器與存儲器提交相同,而斷開存儲器會導致編譯器停止,假定存儲器沒有改變並在本地寄存器中再次讀取,這是另一種具有不同目的的內容(無論內存更改是否仍在高速緩存中或已在RAM上提交都沒有關係,因爲最終的加載操作在兩種情況下均可保證無障礙地工作)。

+1

但編譯器是否可以自由地對周圍的指令進行重新排序,以便在執行屏障時寫入「x」根本不會觸發緩存?我想要內存clobber,以便編譯器被迫提交變量(可能緩存)內存,然後強制高速緩存刷新。 – jpc