2017-02-11 62 views
3

在ARM處理器(HT32F1655),寄存器的特定部分需要字訪問。從用戶手冊:力GCC與詞語訪問結構

請注意,AHB總線中的所有外設寄存器都只支持字訪問。

但是GCC正在產生一些ldrb(負載字節)和strb(存儲字節)在填充結構的說明。該結構是這個樣子:

typedef union { 
    struct { 
     uint32_t CKOUTSRC : 3; //!< CKOUT Clock Source Selection 
     uint32_t    : 5; 
     uint32_t PLLSRC  : 1; //!< PLL Clock Source Selection 
     uint32_t    : 2; 
     uint32_t CKREFPRE : 5; //!< CK_REF Clock Prescaler Selection 
     uint32_t    : 4; 
     uint32_t URPRE  : 2; //!< USART Clock Prescaler Selection 
     uint32_t USBPRE  : 2; //!< USB Clock Prescaler Selection 
     uint32_t    : 5; 
     uint32_t LPMOD  : 3; //!< Lower Power Mode Status 
    } __attribute__((packed)) __attribute__ ((aligned(4))); 
    uint32_t word; 
} reg; 

用法示例:

(*(volatile uint32_t*)0x40088000)->CKOUTSRC = 1; 

生成類似的東西:

ldrb r2, [r1] 
orr r2, r2, #1 
strb r2, [r1] 

當我需要:

ldr r2, [r1] 
orr r2, r2, #1 
str r2, [r1] 

有什麼強制gcc只有g的方法嵌入指令可以訪問整個單詞嗎?某些選項(-mno-unaligned-access)讓GCC生成字訪問,但只有當一個字節是不是4字對齊。

有一個-mslow-bytes應該做正確的事情,但它似乎選項臂無 - EABI - 海合會不存在。

理想的情況下,會有辦法迫使這個僅在受影響的結構。

請,沒有「不使用位域」的答案。我知道這些缺點,但我有能力在這裏控制使用的編譯器,所以我不擔心可移植性。

+0

將「打包位圖覆蓋到設備寄存器上」的代碼會使此更好更清晰。 – chux

+0

只需決定一組好的函數來提供所需的訪問權限,並在需要時使用內聯彙編編寫代碼。 –

+0

@DavidSchwartz這些寄存器映射的數量不是很重要。映射的結構很好地工作,除了這個問題之外,所以我認爲值得花一點點努力試圖在轉向不同的解決方案之前完成這項工作。 – Shade

回答

5

你要尋找的是GCC的-fstrict-volatile-bitfields選項:

如果訪問volatile位域(或其他結構域,儘管編譯器通常尊敬那些類型反正)應該使用這個選項應該使用一個字段類型的寬度的單個訪問,如果可能,對齊到自然對齊。例如,具有內存映射外設寄存器的目標可能要求所有這些訪問都是16位寬;用該標誌可以聲明所有外圍位字段作爲無符號短(假設短於這些目標是16位)來強制GCC使用16位訪問來代替,也許更有效的32位訪問。

如果禁用此選項,編譯器將使用最高效的指令。在前面的例子中,這可能是一個32位的加載指令,即使訪問不包含該位字段的存儲器映射寄存器無關的一個被更新任何部分,或字節。

在一些情況下,當打包屬性應用於一個結構領域,如,它可能無法用單個讀訪問字段或寫入被正確地對目標機器對齊。在這種情況下,GCC退回到生成多個訪問,而不是在運行時會錯誤或截斷結果的代碼。

注意:由於C/C++ 11內存模型的限制,寫訪問不允許觸摸非位字段成員。因此建議將字段類型的所有位定義爲位字段成員。

此選項的默認值由目標處理器的應用程序二進制接口確定。

與使用volatile關鍵字一起。請參閱:https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html

-1

這也正是volatile關鍵字是專爲。

+1

問題是gcc正在WORD-addressable-only內存上生成BYTE訪問指令。 – Shade

+0

'volatile'關鍵字用於告訴編譯器某些內存可能在外部被修改,這使得某些優化成爲不可能。 – Chaos

+0

@Chaos不僅僅如此。 – o11c