<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > 嵌入式軟件開(kāi)發(fā)之: 基于A(yíng)RM處理器的嵌入式系統設計

嵌入式軟件開(kāi)發(fā)之: 基于A(yíng)RM處理器的嵌入式系統設計

作者: 時(shí)間:2014-10-18 來(lái)源:網(wǎng)絡(luò ) 收藏

  本章主要介紹應用程序的設計方法。本章中的一些實(shí)例程序是以公司的2.2為開(kāi)發(fā)平臺。由于目前應用環(huán)境相差非常大,這里主要是通過(guò)這些實(shí)例程序來(lái)更直接地介紹應用系統的開(kāi)發(fā)方法,具體的代碼因具體的嵌入式環(huán)境不同而有所差異。

本文引用地址:http://dyxdggzs.com/article/264071.htm

  13.1 基于處理器的嵌入式系統設計

  系列處理器是RISC(Reducded Instruction Set Computing)處理器。很多基于A(yíng)RM的高效代碼的程序設計策略都源于RISC處理器。和很多RISC處理器一樣,ARM系列處理器的內存訪(fǎng)問(wèn)也要求數據對齊,即存取“字(Word)”數據時(shí)要求四字節對齊,地址的bits[1:0]=0b00;存取“半字(Halfwords)”時(shí)要求兩字節對齊,地址的bit[0]=0b0;存取“字節(Byte)”數據時(shí)要求該數據按其自然尺寸邊界(Natural Size Boundary)定位。

  ARM編譯程序通常將全局變量對齊到自然尺寸邊界上,以便通過(guò)使用 LDR和STR指令有效地存取這些變量。

  這種內存訪(fǎng)問(wèn)方式與多數CISC(Complex Instruction Set Computing)體系結構不同,在CISC體系結構下,指令直接存取未對齊的數據。因而,當需要將代碼從CISC體系結構向 ARM處理器移植時(shí),內存訪(fǎng)問(wèn)的地址對齊問(wèn)題必須予以注意。在RISC體系結構下,存取未對齊數據無(wú)論在代碼尺寸或是程序執行效率上,都將付出非常大的代價(jià)。

  注意在A(yíng)RM11處理器上,新增加了支持非內存對齊數據訪(fǎng)問(wèn)的硬件,此結構在本章中不作討論。

  下面將從4個(gè)方面詳細討論在A(yíng)RM體系結構下的程序設計:

  · 未對齊指針;

  · 結構體中的未對齊字段;

  · 用于半字存取的Load指令;

  · 移植代碼并檢測非對齊存取。

  13.1.1 未對齊的數據指針

  C和C++編程標準規定,指向某一數據類(lèi)型的指針,必須和該類(lèi)型的數據地址對齊方式一致,所以ARM編譯器期望程序中的C指針指向存儲器中字對齊地址,因為這可使編譯器生成更高效的代碼。

  比如,如果定義一個(gè)指向int數據類(lèi)型的指針,用該指針讀取一個(gè)字,ARM 編譯器將使用LDR指令來(lái)完成此操作。如果讀取的地址為4的倍數(即在一個(gè)字的邊界)即能正確讀取。但是,如果該地址不是4的倍數,那么,一條LDR指令返回一個(gè)循環(huán)移位結果,而不是執行真正的未對齊字載入。循環(huán)移位結果取決于該地址相對于字的邊界的偏移量和系統所使用的端序(Endianness)。例如,如果代碼要求從指針指向的地址0x8006載入數據,即要載入0x8006、0x8007、0x8008和0x8009 4個(gè)字節的內容。但是,在A(yíng)RM處理器上,這個(gè)存取操作載入了0x8004、0x8005、0x8006和0x8007字節的內容。這就是在未對齊的地址上使用指針存取所得到的循環(huán)移位結果。

  因而,如果想將指針定義到一個(gè)指定地址(該地址為非自然邊界對齊),那么在定義該指針時(shí),必須使用__packed限定符來(lái)定義指針:

  例如:

  __packed int *pi; // 指針指向一個(gè)非字對其內存地址

  使用了__packed限定符限定之后,ARM編譯器將產(chǎn)生字節存取命令(LDRB或STRB指令)來(lái)存取內存,這樣就不必考慮指針對齊問(wèn)題。所生成的代碼是字節存取的一個(gè)序列,或者取決于編譯選項、跟變量對齊相關(guān)的移位和屏蔽。但這會(huì )導致系統性能和代碼密度的損失。

  值得注意的是,不能使用__packed限定的指針來(lái)存取存儲器映射的外圍寄存器,因為ARM編譯程序可使用多個(gè)存儲器存取來(lái)獲取數據。因而,可以對實(shí)際存取地址附近的位置進(jìn)行存取,而這些附近的位置可能對應于其他外部寄存器。當使用了位字段(Bitfield)時(shí),ARM程序將訪(fǎng)問(wèn)整個(gè)結構體,而非指定字段。

  13.1.2 結構體中未對齊字段

  與全局變量位于其自然尺寸邊界相同,結構體(Structure)中的域字段(Filed)也如此。也就是說(shuō)編譯程序經(jīng)常要在字段間插入填充字節(Padding)來(lái)確保域字段對齊。當編譯程序插入填充字節時(shí),編譯器將產(chǎn)生以下警告信息。

  #1301-D: padding inserted in struct mystruct

  可以使用-remark編譯選項使編譯器產(chǎn)生備份信息,或使用-diag_warning選項選擇編譯器產(chǎn)生的備份信息。

  如果不希望編譯器產(chǎn)生填充字節,可以使用__packed限定符來(lái)創(chuàng )建字段之間沒(méi)有填充字節的結構,且這些結構需要非對齊存取。

  如果ARM編譯器能夠確定所訪(fǎng)問(wèn)結構體的對齊方式,那么它就可以自動(dòng)識別所存取結構體中的字段的對齊方式。在這些情況下,編譯程序盡可能地采用更有效的對齊字或半字存取方式。否則,編譯器將使用多個(gè)對齊存儲器存取(LDR、STR、LDM和STM)與固定移位和屏蔽相結合來(lái)存取存儲器中的字節。

  對非對齊元素的存取是通過(guò)內聯(lián)還是通過(guò)調用一個(gè)函數來(lái)完成,由編譯程序-Ospace(默認,調用一個(gè)函數)和-Otime(執行非對齊存取內聯(lián))選項來(lái)控制。

  例如:

  創(chuàng )建一個(gè)名為foo.c源文件。

  __packed struct mystruct {

  int aligned_i;

  short aligned_s;

  int unaligned_i;

  };

  struct mystruct S1;

  int foo (int a, short b)

  {

  S1.aligned_i=a;

  S1.aligned_s=b;

  return S1.unaligned_i;

  }

  使用armcc -c -Otime foo.c編譯。所生成的代碼為:

  MOV r2,r0

  LDR r0,|L1.84|

  MOV r12,r2,LSR #8

  STRB r2,[r0,#0]

  STRB r12,[r0,#1]

  MOV r12,r2,LSR #16

  STRB r12,[r0,#2]

  MOV r12,r2,LSR #24

  STRB r12,[r0,#3]

  MOV r12,r1,LSR #8

  STRB r1,[r0,#4]

  STRB r12,[r0,#5]

  ADD r0,r0,#6

  BIC r3,r0,#3

  AND r0,r0,#3

  LDMIA r3,{r3,r12}

  MOV r0,r0,LSL #3

  MOV r3,r3,LSR r0

  RSB r0,r0,#0x20

  ORR r0,r3,r12,LSL r0

  BX lr

  其中,“|L1.84|”為結構體mystruct在內存中的地址。

  從上例可以看出,所有對結構體域成員的訪(fǎng)問(wèn)都是通過(guò)字節訪(fǎng)問(wèn)實(shí)現的,所以這種不對齊內存訪(fǎng)問(wèn)無(wú)論從代碼占用的存儲器空間,還是代碼的執行時(shí)間上都要付出一定的代價(jià)。

  然而,開(kāi)發(fā)者可以給編譯器提供更多的信息,使其知道結構體內哪個(gè)字段是對齊的,哪個(gè)字段不是。為此,必須將未對齊字段聲明為_(kāi)_packed,并從struct本身除去__packed屬性。通過(guò)這種方法可以保證對struct中自然對齊成員的快速訪(fǎng)問(wèn)。而且,哪個(gè)字段是未對齊的也更清楚,但這樣就增加了訪(fǎng)問(wèn)struct結構的難度,當用戶(hù)從結構中增加或刪除字段時(shí)需要特別小心。

  修改上例中結構體的定義,來(lái)減少訪(fǎng)問(wèn)結構體的開(kāi)銷(xiāo)。具體代碼如下所示。

  struct mystruct {

  int aligned_i;

  short aligned_s;

  __packed int unaligned_i;

  };

  struct mystruct S1;

  對修改后的程序進(jìn)行編譯,產(chǎn)生的匯編代碼如下所示。

  MOV r2,r0

  LDR r0,|L1.32|

  STR r2,[r0,#0]

  STRH r1,[r0,#4]

  LDMIB r0,{r3,r12}

  MOV r0,r3,LSR #16

  ORR r0,r0,r12,LSL #16

  BX lr

  從編譯后的匯編代碼不難看出,對結構體內符號自然邊界對齊的域,編譯器直接使用相應的Load/Store指令進(jìn)行訪(fǎng)問(wèn),而只有那些非自然邊界對齊的域,編譯器才進(jìn)行附加處理。這樣,從時(shí)間和空間兩方面減小了程序的開(kāi)銷(xiāo)。

  同一原理也適應于聯(lián)合體結構(unions)。使用在存儲器中未對齊的聯(lián)合組件的__packed屬性。

  13.1.3 用于半字存取的非對齊 LDR指令

  一些特殊情況下,ARM編譯程序可以生成非對齊LDR指令。特別是編譯程序從存儲器中載入半字時(shí)將使用該方法。這是因為,通過(guò)使用相應地址,所需的半字可以載入到寄存器的高半段(bits[31:16]),然后通過(guò)移位,將有效數據移到寄存器的低半段(bits[15:0])。這樣做的目的是通過(guò)減少內存訪(fǎng)問(wèn)次數來(lái)減少程序的執行時(shí)間。通過(guò)上面的方法,程序只需要一次存儲器的訪(fǎng)問(wèn),而使用LDRB指令做同樣的操作需要兩次存儲器的存取,而且還要為將這兩個(gè)字節合并在一起添加特殊的代碼。在A(yíng)RM體系結構v3和其早期版本中,通常使用該方法進(jìn)行所有的半字載入。但在A(yíng)RMv4及其以后版本中,出現了專(zhuān)門(mén)的半字載入指令,這種方法逐漸被取代。但是,非對齊LDR指令仍可能會(huì )出現,比如在一個(gè)充填結構中存取一個(gè)非對齊short域類(lèi)型。

  注意在RVCT中已經(jīng)不再支持ARMv3架構。

  13.1.4 移植代碼并檢測非對齊內存訪(fǎng)問(wèn)

  在非RISC體系結構的處理器上執行的代碼中,可能會(huì )存在使用指針訪(fǎng)問(wèn)非自然邊界對齊的數據類(lèi)型。這種操作,在A(yíng)RM體系結構中是不允許的。這就給代碼的移植帶來(lái)很大困難。用戶(hù)必須識別并更改此類(lèi)內存訪(fǎng)問(wèn)代碼才能使其在RISC體系結構的處理器上正確執行。

  識別非對齊存取可能會(huì )很困難,因為使用非對齊地址進(jìn)行的載入或存儲操作會(huì )產(chǎn)生不正確的動(dòng)作。追蹤到底是哪部分的C源程序造成了這個(gè)問(wèn)題是很困難的。

  具有完整存儲器管理單元(MMUs)的ARM處理器,例如ARM920TTM,支持內存對齊檢測功能,用戶(hù)可以通過(guò)設置MMU使處理器檢測每一次的內存訪(fǎng)問(wèn)以確保其被正確地對齊。如果出現非對齊內存訪(fǎng)問(wèn),MMU將產(chǎn)生數據中斷。這樣就給追蹤出錯代碼帶來(lái)了很大的方便。

  對于一些簡(jiǎn)單的沒(méi)有MMU的內核,如ARM7TDMI,最好的方法是在A(yíng)SIC(Application Specific Integrated Circuit)/ASSP(Application Specific Standard Product)內部實(shí)現對齊檢測??梢栽黾訉?zhuān)門(mén)的ARM內核擴展硬件,由其監控每次數據的訪(fǎng)問(wèn)的內存大小和存取地址總線(xiàn)的最低有效位。在非對齊存取的情況下,可以通過(guò)配置ASIC/ASSP產(chǎn)生中斷信號(ABORT)。ARM公司建議在需要運行移植代碼設備中包含這樣的ASIC/ASSP邏輯。

  如果在設計系統時(shí),將系統設計成為當出現非對齊的內存訪(fǎng)問(wèn)時(shí)產(chǎn)生異常,則必須安裝數據中斷異常處理程序(Data Abort Handler)。出現非對齊存取時(shí),程序進(jìn)入數據中斷處理程序,并由此識別位于返回地址(在LR中保存的地址)減8(r14-8)的出錯數據存取指令。

  一旦出現數據中斷異常,必須通過(guò)改變C源程序來(lái)修復非對齊的數據訪(fǎng)問(wèn)。使用下列指令可有條件地完成修復:

  #ifdef __arm

  #define PACKED __packed

  #else

  #define PACKED

  #endif

  :

  PACKED int *pi;

  :

  由于代碼大小和性能上的開(kāi)銷(xiāo),最好盡可能少采用存取非對齊數據。

  ARM編譯器支持--pointer_alignment和--min_array_alignment與內存對齊相關(guān)的編譯選項,詳見(jiàn)ARM相關(guān)文檔。

linux操作系統文章專(zhuān)題:linux操作系統詳解(linux不再難懂)

c++相關(guān)文章:c++教程


存儲器相關(guān)文章:存儲器原理




關(guān)鍵詞: 嵌入式 ARM Realview

評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>