[嵌入式]Cortex-A8處理器程式設計(下)

丫就是熊個貓貓發表於2016-12-19

第3章 Cortex-A8處理器程式設計

3.6  指令系統

ARM偽指令不屬於ARM指令集中的指令,是為了程式設計方便而定義的。偽指令可以像其它ARM指令一樣使用,但在編譯時這些指令將被等效的ARM指令代替。ARM偽指令有四條,分別為ADR偽指令、ADRL偽指令、LDR偽指令、NOP偽指令。

ARM偽指令——小範圍的地址讀取

ADR偽指令將基於PC相對偏移的地址值或基於暫存器相對偏移的地址值讀取到暫存器中。在彙編編譯器編譯源程式時,ADR偽指令被編譯器替換成一條合適的指令。通常,編譯器用一條ADD指令或SUB指令來實現該ADR偽指令的功能,若不能用一條指令實現,則產生錯誤,編譯失敗。

 

地址表示式expr的取指範圍:

當地址值不是字對齊時,其取值範圍為-255~255;

當地址值是字對齊時,其取值範圍為-1020~1020;

當地址值是16位元組對齊時,其取值範圍將更大。

應用示例(源程式):

  ...

    ADR     R0,Delay    

    ...

Delay

    MOV     R0,r14

    ...

使用偽指令將程式標號Delay的地址存入R0

ARM偽指令——中等範圍的地址讀取

ADRL偽指令將基於PC相對偏移的地址值或基於暫存器相對偏移的地址值讀取到暫存器中,比ADR偽指令可以讀取更大範圍的地址 。在彙編編譯器編譯源程式時,ADRL偽指令被編譯器替換成兩條合適的指令。若不能用兩條指令實現,則產生錯誤,編譯失敗。

 

地址表示式expr的取指範圍:

當地址值不是字對齊時,其取址範圍為-64K~64K;

當地址值是字對齊時,其取址範圍為-256K~256K;

當地址值是16位元組對齊時,其取址範圍將更大。

應用示例(源程式):

...

    ADRL    R0,Delay    

    ...

Delay

    MOV     R0,r14

    ...

使用偽指令將程式標號Delay的地址存入R0

ARM偽指令——大範圍的地址讀取

LDR偽指令用於載入32位的立即數或一個地址值到指定暫存器。在彙編編譯源程式時,LDR偽指令被編譯器替換成一條合適的指令。若載入的常數未超出MOV或MVN的範圍,則使用MOV或MVN指令代替該LDR偽指令,否則彙編器將常量放入文字池,並使用一條程式相對偏移的LDR指令從文字池讀出常量。

 

應用示例(源程式):

   ...

    LDR     R1,=InitStack

    ...

InitStack    

    MOV     R0, LR

    ...

使用偽指令將程式標號InitStack的地址存入R1

注意:

1.從指令位置到文字池的偏移量必須小於4KB;

2.與ARM指令的LDR相比,偽指令的LDR的引數有“=”號。

ARM偽指令——空操作偽指令

NOP偽指令在彙編時將會被代替成ARM中的空操作,比如可能是“MOV  R0,R0”指令等。NOP可用於延時操作。

 

應用示例(延時子程式):

    Delay

    NOP;空操作

    NOP

    NOP

    SUBS    R1,R1,#1  ;迴圈次數減一

    BNE     Delay      ;如果迴圈沒有結束,跳轉Delay繼續

    MOV     PC,LR       ;子程式返回

3.7 ARM彙編程式規範

     在只關心繫統所具有功能的設計中,採用高階程式語言編寫程式更合適,由於其隱藏了CPU執行指令的許多細節。但是,CPU執行指令的細節差異會反應在系統的非功能特性上,例如系統程式的規模和執行速度。因此,掌握組合語言程式設計對於嵌入式系統的設計者來說是非常必要的。

ARM彙編程式中每一行的通用格式為:

{標號} {指令|指示符|偽指令} {;註解}

     在ARM組合語言源程式中,除了標號和註釋外,指令、偽指令和指示符都必須有前導空格,而不能頂格書寫。如果每一行的程式碼太長,可以使用字元“\”將其分行書寫,並允許有空行。指令助記符、指示符和暫存器名既可以用大寫字母,也可以用小寫字母,但不能混用。註釋從“;”開始,到該行結束為止。

 

標號

標號代表一個地址,段內標號的地址值在彙編時確定,段外標號的地址值在連結時確定。在此要區別程式相對定址和暫存器相對定址。在程式段中,標號代表其所在位置與段首地址的偏移量,根據程式計數器PC和偏移量計算地址稱為程式相對定址。在映像中定義的標號代表標號到映像首地址的偏移量,映像的首地址通常被賦予一個暫存器,根據該暫存器值與偏移量計算地址稱為暫存器相對定址。

指示符

 

 

 

 

 

預定義變數

ARM彙編器對ARM的暫存器進行了預定義,所有的暫存器和協處理器名都是大小寫敏感的。預定義的暫存器如下:

·R0~R15或r0~r15;

·a1~a4(引數、結果或臨時暫存器,與r0~r3同義);

·v1~v8(變數暫存器,與r4~r11同義);

·sb和SB(靜態基址暫存器,與r9同義);

·sl和SL(堆疊限制暫存器,與r10同義);

·fp和FP(幀指標,與r11同義);

·ip和IP(過程呼叫中間臨時暫存器,與r12同義);

·sp和SP(堆疊指標,與r13同義);

·lr和LR(連結暫存器,與r14同義);

·pc和PC(程式計數器,與r15同義);

·cpsr和CPSR(程式狀態暫存器);

·spsr和SPSR(程式狀態暫存器);

·f0~f7和F0~F7(FPA暫存器);

·s0~s31和S0~S31(VFP單精度暫存器);

·d0~d15和D0~D15(VFP雙精度暫存器);

·p0~p15(協處理器0~15);

·c0~c15(協處理器暫存器0~15)。

內建變數

ARM彙編器所定義的內建變數如表所示。值得注意的是內建變數的設定不能用SETA、SETL或SETS等指示符來設定,只能用表示式或條件來設定。例如:

IF  {ARCHITECTURE} = “4T”

 

 

子程式呼叫規則

ARM9處理器的子程式呼叫指令有別於Intel X86的子程式呼叫指令CALL,此小節再對這一特點進行歸納。另外,本小節還將介紹C或C++語言編寫的程式與組合語言編寫的程式之間相互呼叫的規則。

彙編子程式呼叫

程式設計時,通常會把完成某個特定功能的一段程式程式碼編寫成子程式,在需要的地方進行呼叫。ARM彙編程式中,使用下面語句呼叫子程式。

    BL  next

    其中,next為子程式中的第一條指令程式碼的標號。

    任何一個子程式進入前,處理器需要儲存主程式中的現場,即需要儲存當前工作暫存器(注意:當採用了子程式巢狀呼叫時,應該儲存LR暫存器)。彙編指令BL的功能是將BL指令的下一條指令地址放到LR暫存器中,作為返回地址。並將子程式的第一條指令地址賦予PC暫存器,實現程式轉移,即進入子程式執行。子程式執行完後,通過把LR暫存器值賦予PC暫存器,實現返回。

C、C++語言程式中內嵌彙編

C、C++語言編寫的程式要比組合語言編寫的程式易讀性、移植性好,因此,在嵌入式系統開發時,編寫系統程式大多還是採用C、C++語言。但是在某些場合有時需要採用彙編指令編寫程式,以實現一些高階語言沒有的功能,並提高執行效率。ARM彙編工具支援在C、C++語言程式中嵌入彙編編寫的程式段,其語法格式如下:

    __asm{“指令[;指令]”}

 

彙編程式序例項--系統載入程式

掌握組合語言程式設計對於嵌入式系統的設計者來說是非常必要的。大多數嵌入式系統加電後執行的第一段程式(在此稱為系統載入程式,有時也稱啟動程式碼),往往是採用組合語言編寫的。

    系統載入程式是依賴於具體硬體環境的,除了依賴於CPU的體系結構外,還依賴於具體的板級硬體配置。

·關看門狗定時器,關中斷。

·有時需要設定系統CPU的速度和時脈頻率。

·設定好堆疊。系統堆疊初始化取決於使用者使用哪些異常,以及系統需要處理哪些錯誤型別。

  一般情況下,管理模式堆疊必須設定;若使用了IRQ中斷,則IRQ中斷堆疊必須設定。

·如果系統應用程式是執行在使用者模式下,可在系統載入程式中將系統改為使用者模式並初始

  化使用者堆疊指標。

·若系統使用了DRAM或其他外設,需要設定相關暫存器,以確定其重新整理頻率、匯流排寬度

  等資訊。

·初始化所需的儲存器空間。將系統需要讀寫的資料和變數從ROM拷貝到RAM裡;要求快

  速響應的程式,如中斷程式,也需要在RAM中執行;對Flash的擦除和寫入操作也一定

  要在RAM裡執行。

·跳轉到C程式的入口點。

系統上電或復位後,首先執行的是“b reset”指令,系統跳轉到標號為reset處接著執行,在完成了關中斷、使能管理模式、初始化各模式的堆疊等功能後,執行指令“b main”跳轉到C語言的主函式處執行。

 

相關文章