《嵌入式系統(tǒng)原理及應(yīng)用》課件第3章_第1頁
《嵌入式系統(tǒng)原理及應(yīng)用》課件第3章_第2頁
《嵌入式系統(tǒng)原理及應(yīng)用》課件第3章_第3頁
《嵌入式系統(tǒng)原理及應(yīng)用》課件第3章_第4頁
《嵌入式系統(tǒng)原理及應(yīng)用》課件第3章_第5頁
已閱讀5頁,還剩177頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

第3章ARM指令系統(tǒng)3.1

ARM指令概述3.2

ARM指令集3.3Thumb

及Thumb-2指令集3.4ARM匯編語言程序設(shè)計(jì)

3.5ARMC語言程序設(shè)計(jì)習(xí)題

3.1

ARM指令概述

ARM處理器既支持32位的ARM指令集,也支持16位的Thumb指令集,從ARMv6開始,新的ARM處理器支持16/32位的Thumb2指令集,ARMv7M僅支持Thumb2指令集,ARMCortex-A8處理器核支持ARM、Thumb2、ThumbEE、Jazelle、DSP指令集。

3.1.1ARM指令特點(diǎn)

ARM指令有如下特點(diǎn):(1)指令長度固定。ARM具有32位ARM指令集和16位Thumb指令集,程序的啟動(dòng)都是從ARM指令集開始,包括所有異常中斷都是自動(dòng)轉(zhuǎn)化為ARM狀態(tài)。ARM指令集效率高,但是代碼密度低;而Thumb指令集具有較高的代碼密度,卻仍然保持ARM的大多數(shù)性能上的優(yōu)勢,它是ARM指令集的子集。

(2)所有的ARM指令都可以條件執(zhí)行,可以通過添加適當(dāng)?shù)臈l件碼“cond”后綴來達(dá)到條件執(zhí)行的目的,從而提高代碼密度,實(shí)現(xiàn)高效的邏輯操作(節(jié)省跳轉(zhuǎn)和條件語句),提高代碼效率。而Thumb指令僅有一條指令具備條件執(zhí)行功能。

(3)新版本增加指令,并保持指令向后兼容,如16/32位的Thumb2指令集、VFP浮點(diǎn)數(shù)運(yùn)算,指令集可以通過協(xié)處理器擴(kuò)展。

(4)大量使用寄存器,大多數(shù)據(jù)操作都在寄存器中完成,指令執(zhí)行速度更快。

(5)尋址方式靈活簡單,執(zhí)行效率高。

(6)LoadStore結(jié)構(gòu)。在RISC中,所有的計(jì)算都要求在寄存器中完成。而寄存器和內(nèi)存的通信則由單獨(dú)的Load/Store指令來完成。

3.1.2ARM指令格式與條件碼

ARM指令是三地址指令格式,如圖3-1所示,指令的基本格式如下:

其中,<>號內(nèi)的項(xiàng)是必須的,{}號內(nèi)的項(xiàng)是可選的。圖3-1ARM指令集的指令格式

各項(xiàng)的說明如下:

(1)opcped:指令操作碼、助記符,如ADD、LDR等。

(2)cond:指令的條件碼,如表3-1所示,條件碼共有16種,占用指令編碼的最高四位[31:28]。

所有的ARM指令都可以條件執(zhí)行,而Thumb指令只有B(跳轉(zhuǎn))指令具有條件執(zhí)行功能。如果指令不標(biāo)明條件代碼,將默認(rèn)為無條件(AL)執(zhí)行。

例3-1用戶可以測試某個(gè)寄存器的值,滿足條件時(shí)才可以執(zhí)行某些指令。

例3-2巧妙地使用條件碼,可寫出非常簡練的代碼。

(3)S:決定指令的操作是否影響CPSR的值。

默認(rèn)情況下,數(shù)據(jù)處理指令不影響程序狀態(tài)寄存器的條件碼標(biāo)志位,但可以選擇通過添加“S”來影響標(biāo)志位。CMP不需要增加“S”就可改變相應(yīng)的標(biāo)志位。

例3-3“S”位的使用。

LOOP

(4)Rd:目標(biāo)寄存器編碼,Rd可為任意通用寄存器,寄存器之間用“,”分隔。

(5)Rn:包含第一個(gè)操作數(shù)的寄存器編碼,Rn可為任意通用寄存器。

(6)operand2:第2操作數(shù),可為8位立即數(shù)、寄存器及寄存器移位方式。

靈活地使用第2個(gè)操作數(shù)“operand2”能夠提高代碼效率。它有三種形式:

①#immed-8r——常數(shù)表達(dá)式。

該常數(shù)必須對應(yīng)8位位圖,當(dāng)小于等于255(0xFF)時(shí),正常使用;當(dāng)大于255時(shí),必須是一個(gè)8位(小于等于8位有效數(shù)字)的常數(shù)通過循環(huán)右移偶數(shù)位得到。

例3-4邏輯與運(yùn)算。ANDR1,R2,#0x04800000;其中此處的立即數(shù)是由0x12循環(huán)右移10位得到的,如圖3-2所示。圖3-2第2操作數(shù)的常數(shù)形式

例3-5ADDR3,R7,#1020;#1020為#immed-8r型的第2操作數(shù)。

分析:1020=0x3FC=0x000003FC,1020是0xFF循環(huán)右移30位后生成的32位立即數(shù),因此合法。

例3-6判斷如下立即數(shù)是否合法。

②Rm——寄存器方式。

在寄存器方式下,操作數(shù)即為寄存器的數(shù)值。例如:

SUMR1,R1,R2;R1-R2→R1

③Rm,shift——寄存器移位方式。

將寄存器的移位結(jié)果作為操作數(shù)(移位操作不消耗額外的時(shí)間),但Rm值保持不變,移位方法如表3-2與圖3-3所示,其中1≤n≤32。圖3-3寄存器移位方式

例3-7寄存器移位方式。

例3-8可以借助左右移實(shí)現(xiàn)操作數(shù)對2n乘除運(yùn)算,左移3次相當(dāng)于乘以8,右移3次相當(dāng)于除以8,加上加減運(yùn)算,從而實(shí)現(xiàn)任意函數(shù),如Y=AX+B等。

3.1.3ARM指令的尋址方式

尋址方式就是處理器根據(jù)指令中給出的源操作數(shù)地址碼字段來實(shí)現(xiàn)尋找真實(shí)操作數(shù)地址(或物理地址)的方式。例如B現(xiàn)在21號樓201教室,A要找到B必須先找到教室再找到人,即為間接尋址方式。ARM處理器具有9種基本尋址方式,下面將分別介紹。

1)立即尋址

指令中的操作碼字段后面的地址碼部分即是操作數(shù)本身,也就是說,數(shù)據(jù)就包含在指令當(dāng)中,取出指令也就取出了可以立即使用的操作數(shù),立即數(shù)要以“#”號為前綴,十六進(jìn)制數(shù)值時(shí)以“0x”表示,不加0x時(shí)表示十進(jìn)制數(shù)。立即尋址指令舉例如下:

2)寄存器尋址

操作數(shù)的值在寄存器中,指令中的地址碼字段指出的是寄存器編號,指令執(zhí)行時(shí)直接取出寄存器值來操作。寄存器尋址指令舉例如下:

3)寄存器移位尋址

寄存器移位尋址是ARM指令集特有的尋址方式。當(dāng)?shù)?個(gè)操作數(shù)是寄存器移位方式時(shí),第2個(gè)寄存器操作數(shù)在與第1個(gè)操作數(shù)結(jié)合之前,選擇進(jìn)行移位操作。

4)寄存器間接尋址

指令中的地址碼給出的是一個(gè)通用寄存器的編號,所需的操作數(shù)保存在寄存器指定地址的存儲單元中,即寄存器為操作數(shù)的地址指針。

例如,現(xiàn)須到12201教室找XXX同學(xué)借書,其中12201教室為間接地址,XXX同學(xué)為具體操作數(shù),如果發(fā)現(xiàn)XXX同學(xué)不在12201而在12205教室,需要加一個(gè)偏移量#4,最終找到XXX同學(xué)。

5)基址尋址

基址尋址是將基址寄存器的內(nèi)容與指令中給出的偏移量(<4KB)相加/減,形成操作數(shù)的有效地址?;穼ぶ酚糜谠L問基址附近的存儲單元,常用于查表、數(shù)組操作、功能部件寄存器訪問等。寄存器間接尋址可認(rèn)為是偏移量為0的基址加偏移尋址。

6)多寄存器尋址多寄存器尋址一次可傳送幾個(gè)寄存器值,允許一條指令傳送16個(gè)寄存器的任何子集或所有寄存器。多寄存器尋址指令舉例如下:

此處需要注意,使用多寄存器尋址指令時(shí),寄存器子集的順序是按由小到大的順序排列的,連續(xù)的寄存器可用“”連接,否則用“,”分隔書寫。

7)堆棧尋址

堆棧是一種存儲部件,即數(shù)據(jù)的寫入跟讀出不需要提供地址,而是根據(jù)寫入的順序決定讀出的順序。形象地來說,棧就是一條流水線,而流水線中加工的就是方法的主要程序,在分配棧時(shí),由于程序是自上而下順序執(zhí)行,就將程序指令一條一條壓入棧中,就像流水線一樣。而堆上站著的就是工作人員,他們加工流水線中的商品,由程序員分配何時(shí)加工、如何加工。

堆棧的操作順序?yàn)椤昂筮M(jìn)先出”。堆棧尋址是隱含的,它使用一個(gè)專門的寄存器(堆棧指針)指向一塊存儲區(qū)域(堆棧),指針?biāo)赶虻拇鎯卧词嵌褩5臈m敗?/p>

存儲器堆??煞譃閮煞N:

(1)向上生長:向高地址方向生長,稱為遞增堆棧。

(2)向下生長:向低地址方向生長,稱為遞減堆棧。堆棧指針指向最后壓入的堆棧的有效數(shù)據(jù)項(xiàng),稱為滿堆棧;堆棧指針指向下一個(gè)待壓入數(shù)據(jù)的空位置,稱為空堆棧。

所以可以組合出四種類型的堆棧方式:

(1)滿遞增:堆棧向上增長,堆棧指針指向內(nèi)含有效數(shù)據(jù)項(xiàng)的最高地址。指令如LDMFA、STMFA等。

(2)空遞增:堆棧向上增長,堆棧指針指向堆棧上的第一個(gè)空位置。指令如LDMEA、STMEA等。

(3)滿遞減:堆棧向下增長,堆棧指針指向內(nèi)含有效數(shù)據(jù)項(xiàng)的最低地址。指令如LDMFD、STMFD等。

(4)空遞減:堆棧向下增長,堆棧指針指向堆棧下的第一個(gè)空位置。指令如LDMED、STMED等。

例3-10使用堆棧指令進(jìn)行堆棧操作。

例3-11通過ADS集成開發(fā)環(huán)境的AXD調(diào)試器窗口,可以觀察到多寄存器指令執(zhí)行后各內(nèi)存地址存儲字?jǐn)?shù)據(jù)的結(jié)果,如圖3-4所示。圖3-4多寄存器指令的執(zhí)行順序

8)塊拷貝尋址

塊拷貝尋址又稱多寄存器傳送指令,用于將一塊數(shù)據(jù)(最多16個(gè)通用寄存器的值)從存儲器的某一位置拷貝到另一位置。ARM支持堆棧和塊復(fù)制兩種不同的數(shù)據(jù)塊操作機(jī)制,兩者使用相同的指令,如表3-3所示。

例3-12多寄存器傳送指令。

9)相對尋址

相對尋址是基址尋址的一種變通。由程序計(jì)數(shù)器PC提供基準(zhǔn)地址,指令中的地址碼字段作為偏移量,兩者相加后得到的地址即為操作數(shù)的有效地址。

3.2

ARM指令集

3.2.1數(shù)據(jù)處理指令

數(shù)據(jù)處理指令編碼格式如圖3-5所示,數(shù)據(jù)處理指令可分為四類:數(shù)據(jù)傳送指令、算術(shù)邏輯運(yùn)算指令、比較指令和乘法指令。

數(shù)據(jù)處理指令只能對寄存器的內(nèi)容進(jìn)行操作,而不能對內(nèi)存中的數(shù)據(jù)進(jìn)行操作。所有ARM數(shù)據(jù)處理指令均可選擇使用S后綴,以使指令影響狀態(tài)標(biāo)志。比較指令CMP、CMN、TST和TEQ不需要后綴S,它們會直接影響狀態(tài)標(biāo)志。常用數(shù)據(jù)處理指令如表3-4所示。

圖3-5ARM數(shù)據(jù)處理指令編碼

3.2.2存儲器訪問指令

ARM處理器是典型的RISC處理器,對存儲器的訪問只能使用加載和存儲指令實(shí)現(xiàn)。常用存儲器訪問指令如表3-5所示。

(1)單寄存器存取指令。LDR/STR指令尋址非常靈活,它由兩部分組成,其中一部分為一個(gè)基址寄存器,可以為任一個(gè)通用寄存器;另一部分為一個(gè)地址偏移量。LDR/STR指令用于對內(nèi)存變量的訪問、內(nèi)存緩沖區(qū)數(shù)據(jù)的訪問、查表、外圍部件的控制操作等。若使用LDR指令加載數(shù)據(jù)到PC寄存器,則實(shí)現(xiàn)程序跳轉(zhuǎn)功能,這樣也就實(shí)現(xiàn)了程序散轉(zhuǎn)。

例3-16加載/存儲指令的使用。

例3-17下列程序?qū)崿F(xiàn)將一個(gè)數(shù)從內(nèi)存某地址中取出一個(gè)字,然后將該數(shù)進(jìn)行了處理,結(jié)果放回內(nèi)存中該數(shù)的相鄰的下一字地址中。

(2)多寄存器加載/存儲指令可以實(shí)現(xiàn)在一組寄存器和一塊連續(xù)的內(nèi)存單元之間傳輸數(shù)據(jù)。允許一條指令傳送16個(gè)寄存器的任何子集或所有寄存器。它們主要用于現(xiàn)場保護(hù)、數(shù)據(jù)復(fù)制、常數(shù)傳遞等。

使用LDM指令用于將由基址寄存器所指示的一片連續(xù)存儲器讀到寄存器列表所指示的多個(gè)寄存器中,該指令的常用用途是將多個(gè)寄存器的內(nèi)容出棧。

使用STM指令用于將寄存器列表所指示的多個(gè)寄存器的數(shù)據(jù)存儲到由基址寄存器所指示的一片連續(xù)存儲器中,該指令的常用用途是將多個(gè)寄存器的內(nèi)容入棧。

(3)SWP指令可實(shí)現(xiàn)寄存器和內(nèi)存交換數(shù)據(jù),用于實(shí)現(xiàn)信號量操作。

指令格式為:SWPRd,Rm,[Rn]

SWP指令用于將一個(gè)內(nèi)存單元(該單元地址放在寄存器Rn中)的內(nèi)容讀取到一個(gè)寄存器Rd中,同時(shí)將另一個(gè)寄存器Rm的內(nèi)容寫入到該內(nèi)存單元中。

3.2.3分支指令

在ARM中,有兩種方法可以實(shí)現(xiàn)程序跳轉(zhuǎn):

(1)直接向PC寄存器(R15)賦值實(shí)現(xiàn)跳轉(zhuǎn),可以實(shí)現(xiàn)4GB地址空間中的長跳轉(zhuǎn)。如:

(2)使用分支指令直接跳轉(zhuǎn),跳轉(zhuǎn)指令可以實(shí)現(xiàn)從當(dāng)前指令向前或向后的32MB地址空間的跳轉(zhuǎn),如表3-6所示。

3.2.4協(xié)處理器指令

ARM微處理器最多可支持16個(gè)協(xié)處理器,用于各種協(xié)處理操作、硬件協(xié)處理器支持與否完全由生產(chǎn)商定義,是否支持協(xié)處理器或支持哪個(gè)協(xié)處理器與ARM版本無關(guān)。生產(chǎn)商可以選擇實(shí)現(xiàn)部分協(xié)處理器指令或完全不支持協(xié)處理器。在程序執(zhí)行的過程中,每個(gè)協(xié)處理器只執(zhí)行針對自身的協(xié)處理指令,忽略ARM處理器和其他協(xié)處理器的指令。當(dāng)一個(gè)協(xié)處理器硬件不能執(zhí)行屬于它的協(xié)處理器指令時(shí),將產(chǎn)生未定義指令異常中斷。

ARM處理器包括兩個(gè)內(nèi)部協(xié)處理器:CP14,用于調(diào)試控制;CP15,用于內(nèi)存系統(tǒng)控制和測試控制。ARM的協(xié)處理器指令主要用于ARM處理器初始化、ARM協(xié)處理器的數(shù)據(jù)處理操作、在ARM處理器的寄存器和協(xié)處理器的寄存器之間傳送數(shù)據(jù)和在ARM協(xié)處理器的寄存器和存儲器之間傳送數(shù)據(jù)。

ARM協(xié)處理器指令包括以下5條。

(1)CDP(協(xié)處理器數(shù)操作指令)。

CDP指令的格式為:CDP{條件}協(xié)處理器編碼,協(xié)處理器操作碼1,目的寄存器,源寄存器1,源寄存器2,協(xié)處理器操作碼2

CDP指令用于ARM處理器通知ARM協(xié)處理器執(zhí)行特定的操作,若協(xié)處理器不能成功完成特定的操作,則產(chǎn)生未定義指令異常中斷。其中協(xié)處理器操作碼1和協(xié)處理器操作碼2為協(xié)處理器將要執(zhí)行的操作,目的寄存器和源寄存器均為協(xié)處理器的寄存器,指令不涉及RM處理器的寄存器和存儲器。

指令示例:

CDPP3,2,C12,C10,C3,4;該指令完成協(xié)處理器P3的初始化,操作碼為2,可選操作碼為4

(2)LDC(協(xié)處理器數(shù)據(jù)加載指令)。

LDC指令的格式為:

LDC{條件}{L}協(xié)處理器編碼,目的寄存器,[源寄存器]

LDC指令用于將源寄存器所指向的存儲器中的字?jǐn)?shù)據(jù)傳送到目的寄存器中,若協(xié)處理器不能成功完成傳送操作,則產(chǎn)生未定義指令異常中斷。其中,{L}選項(xiàng)表示指令為長讀取操作,例如傳輸雙精度數(shù)據(jù)時(shí)需要采用長讀取操作,即可使用此后綴。此條指令類似LDR指令。

指令示例:LDCP3,C4,[R0,#4];將寄存器R0+4所指向的存儲器中的字?jǐn)?shù)據(jù)傳送到協(xié)處理器P3的C寄存器中

(3)STC(協(xié)處理器數(shù)據(jù)存儲指令)。

STC指令的格式為:

STC{條件}{L}協(xié)處理器編碼,源寄存器,[目的寄存器]

STC指令用于將源寄存器中的字?jǐn)?shù)據(jù)傳送到目的寄存器所指向的存儲器中,若協(xié)處理器不能成功完成傳送操作,則產(chǎn)生未定義指令異常中斷。此條指令類似STR指令。指令示例:STCP3,C4,[R0];將協(xié)處理器P3的C4寄存器中的字?jǐn)?shù)據(jù)傳送到寄存器R0所指向的存儲器中

(4)MCR(ARM處理器寄存器到協(xié)處理器寄存器的數(shù)據(jù)傳送指令)。

MCR指令的格式為:

MCR{條件}協(xié)處理器編碼,協(xié)處理器操作碼1,源寄存器,目的寄存器1,目的寄存器2,協(xié)處理器操作碼2MCR指令用于將ARM處理器寄存器中的數(shù)據(jù)傳送到協(xié)處理器寄存器中,若協(xié)處理器不能成功完成操作,則產(chǎn)生未定義指令異常中斷。其中協(xié)處理器操作碼1和協(xié)處理器操作碼2為協(xié)處理器將要執(zhí)行的操作,源寄存器為ARM處理器的寄存器,目的寄存器1和目的寄存器2均為協(xié)處理器的寄存器。

指令示例:

MCRP3,3,R0,C4,C5,6;該指令將寄存器R0中的數(shù)據(jù)傳送到協(xié)處理器P3的寄存器C4和C5中

(5)MRC(協(xié)處理器寄存器到ARM處理器寄存器的數(shù)據(jù)傳送指令)。

MRC指令的格式為:

MRC{條件}協(xié)處理器編碼,協(xié)處理器操作碼1,目的寄存器,源寄存器1,源寄存器2,協(xié)處理器操作碼2MRC指令用于將協(xié)處理器寄存器中的數(shù)據(jù)傳送到ARM處理器寄存器中,若協(xié)處理器不能成功完成操作,則產(chǎn)生未定義指令異常中斷。其中協(xié)處理器操作碼1和協(xié)處理器操作碼2為協(xié)處理器將要執(zhí)行的操作,目的寄存器為ARM處理器的寄存器,源寄存器1和源寄存器2均為協(xié)處理器的寄存器。

指令示例:

MRCP3,3,R0,C4,C5,6;該指令將協(xié)處理器P3的寄存器中的數(shù)據(jù)傳送到ARM處理器寄存器中

3.2.5程序狀態(tài)寄存器訪問指令

ARM指令集提供了兩條指令,可直接控制程序狀態(tài)寄存器。在ARM處理器中,只有MRS和MRS指令可以對狀態(tài)寄存器CPSR和SPSR進(jìn)行讀操作。通過讀CPSR可以了解當(dāng)前處理器的工作狀態(tài)。讀SPSR寄存器可以了解到進(jìn)入異常前的處理器狀態(tài)。該指令不影響條件碼。

3.2.6雜項(xiàng)指令

1.SWI(軟件中斷指令)軟件中斷是軟件實(shí)現(xiàn)的中斷,也就是程序運(yùn)行時(shí)其他程序?qū)λ闹袛?。軟件中斷與硬件中斷的區(qū)別:

(1)軟件中斷發(fā)生的時(shí)間是由程序控制的,而硬件中斷發(fā)生的時(shí)間是隨機(jī)的。

(2)軟件中斷是由程序調(diào)用引發(fā)的,而硬件中斷是由外設(shè)引發(fā)的。

SWI指令用于產(chǎn)生軟件中斷異常,使得CPU模式變換到管理模式,并且將CPSR保存到管理模式的SPSR-svc中,然后程序跳轉(zhuǎn)到SWI異常入口。不影響條件碼標(biāo)志。

該指令主要用于用戶程序調(diào)用操作系統(tǒng)的系統(tǒng)服務(wù),操作系統(tǒng)在SWI異常處理程序中進(jìn)行相應(yīng)的系統(tǒng)服務(wù)。

指令格式為:

使用SWI指令時(shí),通常使用以下兩種方法進(jìn)行參數(shù)傳遞。

(1)指令中的24位的立即數(shù)指定了用戶請求的類型,中斷服務(wù)程序的參數(shù)通過寄存器傳遞。

(2)指令中的24位立即數(shù)忽略,用戶請求的服務(wù)類型由寄存器R0的值決定,參數(shù)通過其他寄存器傳遞。

2.BKPT(斷點(diǎn)中斷指令)

此指令用于產(chǎn)生軟件斷點(diǎn)中斷,它使處理器停止執(zhí)行正常指令而進(jìn)入相應(yīng)的調(diào)試程序。指令格式為:

3.CLZ指令(計(jì)算前導(dǎo)零數(shù)目)

ARMv5T及以上版本的微處理器支持CLZ指令,即Rm中的前導(dǎo)0的個(gè)數(shù)進(jìn)行計(jì)數(shù),結(jié)果放到Rd中,如果未在源寄存器中設(shè)置任何位,則該結(jié)果值為32,如果設(shè)置了位31,則結(jié)果為0。

指令格式為:

4.飽和指令

1)QADD、QSUB、QDADD和QDSUB指令

語法格式為:op{cond}{Rd},Rm,Rn

該指令可用于v5T-E

及v6或更高版本的ARM體系中。如果發(fā)生飽和,則這些飽和指令會設(shè)置Q標(biāo)志位。若要讀取Q標(biāo)記的狀態(tài),需要使用MRS指令。

其中op為下列四個(gè)指令之一:

(1)QADD指令可將Rm和Rn中的值相加。

(2)QSUB指令可從Rm中的值中減去Rn中的值。

(3)QDADD指令可計(jì)算SAT(Rm+SAT(Rn

*2))。

(4)QDSUB指令可計(jì)算SAT(Rm-SAT(Rn

*2))。

進(jìn)行加倍和加法運(yùn)算均有可能出現(xiàn)飽和。如果加倍運(yùn)算發(fā)生飽和,而加法運(yùn)算沒有出現(xiàn)飽和,則將設(shè)置Q標(biāo)記,但最終結(jié)果是不飽和的。這些指令會將所有值視為有符號整數(shù)的二進(jìn)制補(bǔ)碼。

2)SSAT和USAT

有符號飽和到任何位位置和無符號飽和到任何位位置,可選擇在飽和前進(jìn)行移位。語法格式為:

3.3Thumb

及Thumb-2指令集

Thumb指令集可以看做是ARM指令壓縮形式的子集,它是為減小代碼量而提出,具有16bit的代碼密度。Thumb指令體系并不完整,只支持通用功能,必要時(shí)仍需要使用ARM指令,如進(jìn)入異常時(shí)。其指令的格式和使用方式和ARM指令集類似,而且使用并不頻繁。Thumb指令集中操作數(shù)仍然是32位,指令地址也為32位,只是指令編碼為16位。

3.3.1Thumb指令集

1.Thumb指令集與ARM指令集的區(qū)別

Thumb指令集與ARM指令集相比,具有以下特點(diǎn):

(1)在編寫Thumb指令時(shí),先要使用偽指令CODE16聲明;編寫ARM指令時(shí),則可使用CODE32偽指令聲明。

(2)Thumb指令集沒有協(xié)處理器指令、信號量(SWP)指令、訪問CPSR或SPSR的指令以及乘加指令和64位乘法指令等,且指令的第二操作數(shù)受到限制。

(3)大多數(shù)的Thumb數(shù)據(jù)處理指令采用2地址或2個(gè)操作數(shù)格式。

(4)除了跳轉(zhuǎn)指令B有條件執(zhí)行功能之外,其他指令均為無條件執(zhí)行,而且分支指令的跳轉(zhuǎn)范圍有更多限制,B條件跳轉(zhuǎn)限制在[-252,258]B偏移范圍內(nèi),無條件跳轉(zhuǎn)限制為±2KB偏移范圍內(nèi),BL、BX等跳轉(zhuǎn)限制在±4MB偏移范圍內(nèi),而ARM為±32MB偏移。

個(gè)操作數(shù)寄存器中,而不是放入第3個(gè)寄存器中;訪問寄存器R8~R15受到一定的限制,除MOV、ADD指令訪問R8~R15外,其他數(shù)據(jù)處理指令只能訪問R0~R7寄存器,訪問寄存器R8~R15的Thumb數(shù)據(jù)處理指令不能更新CPSR中的ALU狀態(tài)位。

(6)Thumb狀態(tài)下,單寄存器加載和存儲指令只能訪問寄存器R0~R7。

(7LDM、STM

,指令可以將任何范圍為R0~R7的寄存器子集加載或存儲。

(8)PUSH、POP指令使用R13作為基址堆棧操作。例如:

由于Thumb指令的長度為16位,即只用ARM指令一半的位數(shù)來實(shí)現(xiàn)同樣的功能,所以要實(shí)現(xiàn)特定的程序功能,所需的Thumb指令的條數(shù)較ARM指令多。

在一般的情況下,Thumb指令與ARM指令的時(shí)間效率和空間效率關(guān)系為:

(1)Thumb代碼所需的存儲空間約為ARM代碼的60%~70%。

(2)Thumb代碼使用的指令數(shù)比ARM代碼多約30%~40%。

(3)若使用32位的存儲器,ARM代碼比Thumb代碼快約40%。

(4)若使用16位的存儲器,Thumb代碼比ARM代碼快約40%~50%。

(5)與ARM代碼相比較,使用Thumb代碼,存儲器的功耗會降低約30%。

2.ARMThumb交互工作

1)交互工作的必要性為一個(gè)Thumb兼容的ARM處理器編寫代碼時(shí),ARM指令的程序和Thumb指令的程序各有自己的優(yōu)勢,對于8位和16位的存儲系統(tǒng)來說,Thumb指令可以提供更好的代碼密度和性能,對于32位的存儲系統(tǒng)來說,ARM指令則占有速度和性能上的優(yōu)勢。

例如:(1)速度。

(2)功能。

(3)異常處理。(4)單獨(dú)的Thumb程序。

2)交互工作的切換指令A(yù)RM和Thumb間的交互工作必須滿足以下兩點(diǎn):

(1)通過BX指令切換處理器的狀態(tài)。

注意:當(dāng)不需要狀態(tài)切換時(shí)也可以使用BX作為分支指令,尤其是當(dāng)B和BL指令不能使用的情況下,因?yàn)锽XX指令可以尋址32位的存儲空間,而B和BL指令則有如下限制:

①ARM狀態(tài)下,B

和BL指令的尋址空間為32MB。

②Thumb狀態(tài)下,無條件B和BL指令的尋址空間為4MB。

③Thumb狀態(tài)下,有條件B指令的尋址空間為-128~+127個(gè)指令。

(2)通過偽指令CODE32和CODE16指示匯編器根據(jù)處理器的狀態(tài)生成合適的代碼。

ARM指令的程序頭主要完成如下兩步操作:

①通過ADR指令裝載分支地址,并且設(shè)置地址最低位為1。

②通過BX指令完成分支跳轉(zhuǎn)并切換到Thumb狀態(tài)。

3.3.2Thumb-2指令集

Thumb-2是Thumb指令集的一項(xiàng)主要增強(qiáng)功能,并且由ARMv6T2和ARMv7M體系結(jié)構(gòu)定義。它以現(xiàn)有的ARM技術(shù)為基礎(chǔ),目標(biāo)是提供低功耗、高性能的最優(yōu)設(shè)計(jì)。Thumb-2提供了幾乎與ARM指令集完全一樣的功能。它兼有16位和32位指令,并可檢索與ARM類似的性能,但其代碼密度與Thumb代碼類似。

新的Thumb-2技術(shù)可以帶來很多好處:

(1)可以實(shí)現(xiàn)ARM指令的所有功能。

(2)增加了12條新指令,可以改進(jìn)代碼性能和代碼密度之間的平衡。

(3)相對ARM代碼,Thumb2代碼密度縮小了31%,代碼性能達(dá)到了純ARM代碼性能的98%。

(4)與現(xiàn)有的Thumb指令集相比,Thumb2代碼密度更高,代碼大小平均降低5%,性能提高了38%。

(5)為了提高處理壓縮數(shù)據(jù)結(jié)構(gòu)的效率,新的ARM架構(gòu)為Thumb-2指令集和ARM指令集增加了一些新的指令來實(shí)現(xiàn)比特位的插入和抽取。這樣,開發(fā)者進(jìn)行比特位的插入和抽取所需的指令數(shù)目就可以明顯減少,使用壓縮的數(shù)據(jù)結(jié)構(gòu)也會更加方便,而代碼對存儲器的需求也會降低。

3.4ARM匯編語言程序設(shè)計(jì)匯編語言比機(jī)器語言易于讀寫、易于調(diào)試和修改,同時(shí)也具有機(jī)器語言執(zhí)行速度快、占內(nèi)存空間少等優(yōu)點(diǎn);但在編寫復(fù)雜程序時(shí)具有明顯的局限性,匯編語言依賴于具體的機(jī)型,不能通用,也不能在不同機(jī)型之間移植。使用匯編語言編寫的程序,機(jī)器不能直接識別,要由一種程序?qū)R編語言翻譯成機(jī)器語言,這種起翻譯作用的程序叫匯編程序(也叫匯編器)。匯編程序是系統(tǒng)軟件中語言處理系統(tǒng)軟件。

目前常用的ARM匯編程序的編譯環(huán)境有兩種:

(1)ADS/SDT、RealView

MDK

等ARM公司推出的開發(fā)工具。

(2)GNUARM開發(fā)工具。GNU是GNU’sNotunix的遞歸縮寫。GNU格式ARM匯編語言程序主要是面對在ARM平臺上移植嵌入式Linux

操作系統(tǒng)。

3.4.1ARM匯編偽指令

人們設(shè)計(jì)了一些專門用于指導(dǎo)匯編器進(jìn)行匯編工作的指令,由于這些指令不形成機(jī)器碼指令,它們只是在匯編器進(jìn)行匯編工作的過程中起作用,所以被叫做偽指令。偽指令具有以下特點(diǎn):

(1)偽指令在程序中通常起到程序定位、指令代碼定義、對程序段做標(biāo)注等作用。

(2)偽指令只在匯編期間產(chǎn)生作用,由編譯器進(jìn)行解釋。

(3)偽指令除部分語句可申請存儲空間外,不產(chǎn)生任何目標(biāo)代碼。

1.ARM處理器支持的偽指令

ARM處理器支持的偽指令有ADR、ADRL、LDR和NOP。偽指令不是真正的指令,它在匯編編譯器對源程序進(jìn)行匯編處理時(shí)被替換成對應(yīng)的ARM或者Thumb指令。

(1)ADR:小范圍的地址讀取偽指令。

(2)ADRL:中等范圍的地址讀取偽指令。

(3)LDR:將一個(gè)32位的常數(shù)或者一個(gè)地址值讀取到寄存器中。

(4)NOP:空操作。

匯編時(shí)被替換成ARM中的空操作,相當(dāng)于MOVRd,Rd。

2.指示符

ARM匯編器所支持的指示符包括符號定義指示符、數(shù)據(jù)定義指示符、匯編控制指示符、信息報(bào)告指示符及其他指示符。

1)符號定義指示符

符號定義指示符用于定義ARM匯編程序中的變量、對變量進(jìn)行賦值以及定義寄存器名稱。具體包括以下指示符:

(1)GBLA,GBLL及GBL:聲明全局變量。

(2)LCLA,LCLL及LCLS:聲明局部變量。

(3)SET,SETL及SETS:給變量賦值。

(4)RLIST:通用寄存器列表定義名稱。

(5)CN:協(xié)處理器的寄存器定義名稱。

(6)CP:協(xié)處理器定義名稱。

(7)DN及SN:VFP的寄存器定義名稱。

(8)FN:FPA的浮點(diǎn)寄存器定義名稱。

2)數(shù)據(jù)定義指示符

數(shù)據(jù)定義指示符包括以下的指示符:

(1)LTORG:聲明一個(gè)數(shù)據(jù)緩沖池或者文字池的開始。通常ARM匯編器把數(shù)據(jù)緩沖池放在代碼段的最后面,即下一個(gè)代碼段開始之前,或者END指示符之前。

例3-27LTORG使用舉例。

(2)MAP:定義數(shù)據(jù)結(jié)構(gòu)的起始地址,MAP可以用“^”代替。如:

(3)FIELD:定義數(shù)據(jù)結(jié)構(gòu)中的字段,說明一個(gè)數(shù)據(jù)項(xiàng)所需要的內(nèi)存空間,并且為這個(gè)數(shù)據(jù)項(xiàng)提供一個(gè)標(biāo)號,F(xiàn)IELD也可用“#”代替。

(4)SPZCE:分配一塊內(nèi)存單元,并初始化為0,SPACE也可用“%”代替。

(5)DCB:分配一段字節(jié)的內(nèi)存單元,并用指定的數(shù)據(jù)初始化。

(6)DCD及DCDU:分配一段字的內(nèi)存單元,并用指定的數(shù)據(jù)初始化,DCD可用“&”代替。用DCDU分配的字存儲單元并不嚴(yán)格字對齊。如:

(7)DCDO:分配一段字的內(nèi)存單元,并將單元的內(nèi)容初始化成該單元相對于靜態(tài)基值寄存器的偏移量。

(8)DCFD及DCFDU:分配一段雙字的內(nèi)存單元,并用雙精度的浮點(diǎn)數(shù)據(jù)初始化。

(9)DCFS及DCFSU:分配一段字的內(nèi)存單元,并用單精度的浮點(diǎn)數(shù)據(jù)初始化。如:

(10)DCI:分配一段字節(jié)的內(nèi)存單元,用指定的數(shù)據(jù)初始化,指定內(nèi)存單元中存放的是代碼,而不是數(shù)據(jù)。

(11)DCQ及DCQU:分配一段雙字的內(nèi)存單元,并用64位的整數(shù)數(shù)據(jù)初始化。

(12)DCW及DCWU:分配一段半字的內(nèi)存單元,并用指定的數(shù)據(jù)初始化。如:

(13)DATA:在代碼段中使用數(shù)據(jù)?,F(xiàn)已不再使用,僅用于保持向前兼容。

3)匯編控制指示符

匯編控制指示符包括下面的指示符:

(1)IF、ELSE及ENDIF:匯編或者不匯編一段源代碼。

(2)WHILE及WEND:條件重復(fù)匯編相同的一段源代碼。

(3)MACRO及MEND:標(biāo)識宏定義開始與結(jié)束,宏中的所有標(biāo)號必須在前面冠以符號“$”。

(4)MEXIT:用于從宏定義中跳轉(zhuǎn)出去。例如:

4)信息報(bào)告指示符

信息報(bào)告指示符包括下列指示符:

(1)ASSERT:在匯編編譯器對匯編程序的第二遍掃描中,如果ASSERTION條件不成立,ASSERT偽指令將報(bào)告該錯(cuò)誤信息。

(2)INFO:支持匯編編譯器對匯編程序的第一遍或第二遍掃描時(shí)報(bào)告診斷信息。

(3)OPT:在源程序中設(shè)置列表選項(xiàng)。

(4)TTL及SUBT:在列表文件中的每一頁的開頭插入一個(gè)標(biāo)題和子標(biāo)題。

5)其他指示符

這些雜類的指示符包括:

(1)ALIGN定義對齊方式偽指令。如:

(2)AREA用于定義一個(gè)代碼段或者數(shù)據(jù)段。如:

(3)CODE16及CODE32用來表明其后的指令為16位Thumb指令/32位ARM指令。

(4)END用于通知編譯器匯編工作到此結(jié)束,不再往下匯編了。

(5)ENTRY用于指定匯編程序的入口點(diǎn)。

(6)EQU用于為程序中的常量、標(biāo)號等定義一個(gè)等效的字符名字,其作用類似于C語言中的#define,EQU也可用“?”代替。如:

(7)EXPORT或GLOBA用于外部可引用符號聲明。

(8)EXTERN:與IMPORT偽指令的功能基本相同,但如果當(dāng)前源文件中的程序?qū)嶋H并未使用該指令,則該符號不會加入到當(dāng)前源文件的符號表中。

(9)GET或INCLUDE用于將一個(gè)源文件包含到當(dāng)前的源文件中,并將被包含的源文件在當(dāng)前位置進(jìn)行匯編。如:

(10)IMPORT:當(dāng)在一個(gè)源文件中需要使用另外一個(gè)源文件的外部可引用符號時(shí),在被引用的符號前面必須使用偽指令I(lǐng)MPORT對其進(jìn)行聲明。如:

(11)INCBIN用于將一個(gè)目標(biāo)文件或數(shù)據(jù)文件包含到當(dāng)前的源文件中,被包含的文件不做任何變動(dòng)地存放在當(dāng)前文件中,編譯器從其后開始繼續(xù)處理。如:

(12)KEEP用于保留符號表中的局部符號。

(13)NOFP用于禁止源程序中包含浮點(diǎn)運(yùn)算指令。

(14)REQUIRE用于指定段之間的相互依賴關(guān)系,當(dāng)進(jìn)行連接處理時(shí)包含了有REQUIRElable

指示符的源文件,則定義lable的源文件也將被包含。

(15)REQUIRE8及PRESERVE8:在定義堆棧時(shí)用到,這兩個(gè)指令告訴編譯器保證8字節(jié)對齊。實(shí)際操作時(shí),REQUIRE8和PRESERVE8并不完成8字節(jié)對齊的操作,而只是更改編譯器中的編譯屬性,真正的對齊由ALIGN完成。

(16)RN用于給一個(gè)寄存器定義一個(gè)別名,以提高程序的可讀性。如:

(17)ROUT用于給一個(gè)局部變量定義作用范圍。在程序中未使用該偽指令時(shí),局部變量的作用范圍為所在的AREA;而使用ROUT后,局部變量的作用范圍為當(dāng)前ROUT和下一個(gè)ROUT之間。如:

3.4.2匯編語言程序舉例分析

1.匯編程序的設(shè)計(jì)過程

匯編程序的設(shè)計(jì)過程可分為以下幾個(gè)步驟:

(1)分析問題:已知條件、要解決的問題、功能/性能要求、輸入輸出信號要求等。

(2)建立數(shù)學(xué)模型:把系統(tǒng)任務(wù)分解為便于描述的模塊或過程,即數(shù)學(xué)化、公式化、模塊化,便于計(jì)算機(jī)處理。

(3)確定算法:對數(shù)學(xué)模型的求解或工程處理方法進(jìn)行優(yōu)化,逐步總結(jié)出便于功能實(shí)現(xiàn)的簡單、高效、精度高、代碼量小、編程容易的處理方案。

(4)畫程序流程圖:用箭頭、框圖、菱形圖等表示程序結(jié)構(gòu),可以首先從圖上檢驗(yàn)算法的正確性,減少出錯(cuò)的可能,使得動(dòng)手編寫程序時(shí)的思路更加清晰。

(5)內(nèi)存空間分配:分配存儲空間和工作單元是指存儲空間的分段和數(shù)據(jù)定義。另外,由于寄存器的數(shù)量有限,編寫程序時(shí)經(jīng)常會感到寄存器不夠用。因此,對于字節(jié)數(shù)據(jù),要盡量使用8位寄存器。而采用適當(dāng)?shù)膶ぶ贩绞?,也會達(dá)到節(jié)省寄存器的目的。

(6)編制程序與靜態(tài)檢查:程序結(jié)構(gòu)層次簡單、清楚、易懂。為了提高編程能力,對于初學(xué)者,一是要多閱讀現(xiàn)有的程序,以學(xué)習(xí)別人的編程經(jīng)驗(yàn);而更為重要的是,必須多親自動(dòng)手編寫,不要怕失敗,只有通過無數(shù)次失敗,才能從中積累自己的編程經(jīng)驗(yàn)。

(7)上機(jī)調(diào)試程序:ARM源程序的調(diào)試可以在ARM開發(fā)板上直接進(jìn)行,也可在PC機(jī)上通過軟件仿真環(huán)境實(shí)現(xiàn)。通過匯編的源程序,只能說明它里面不存在語法錯(cuò)誤。但是它是否能達(dá)到算法所要求的預(yù)期效果,還必須經(jīng)過上機(jī)調(diào)試,用一些實(shí)驗(yàn)數(shù)據(jù)來測試,才能夠真正地得出結(jié)論。

2.匯編語句格式規(guī)范

匯編語句格式遵循以下規(guī)范:

(1)ARM匯編中,所有標(biāo)號必須在一行的頂格書寫。

(2)所有指令均不能頂格書寫。

(3)ARM匯編器對標(biāo)識符大小寫敏感(即區(qū)分大小寫字母),書寫標(biāo)號及指令時(shí)字母大小寫要一致。

(4)在ARM匯編程序中,ARM指令、偽指令、寄存器名可以全部為大寫字母,也可以全部為小寫字母,但不要大小寫混合使用。

(5)源程序中,語句之間可以插入空行,以使得源代碼的可讀性更好。

(6)如果單行代碼太長,可以使用字符“\”將其分行?!埃堋焙蟛荒苡腥魏巫址?,包括空格和制表符等。

(7)對于變量的設(shè)置、常量的定義,其標(biāo)識符必須在一行的頂格書寫。

檢查上面程序,可以檢出:

第一行:AREA指示符不允許從行的最左邊開始書寫。

第二行:標(biāo)號DOB沒有頂格書寫。

第三行:指令助記符不允許頂格書寫。

第四行:指令中大小寫混合。第五行:無法跳轉(zhuǎn)到LOOP標(biāo)號,大小寫不一致。

3.匯編程序結(jié)構(gòu)

要設(shè)計(jì)出高質(zhì)量的匯編程序就要熟練掌握匯編指令的應(yīng)用、匯編程序的設(shè)計(jì)過程,并能靈活地運(yùn)用順序、條件、循環(huán)和子程序四種程序結(jié)構(gòu)以及模塊化的設(shè)計(jì)思想。

常見的程序結(jié)構(gòu),是上述四種結(jié)構(gòu)的混合體。順序程序結(jié)構(gòu)就是指完全按順序逐條執(zhí)行的指令序列,在程序設(shè)計(jì)過程中,順序結(jié)構(gòu)大量存在,但一個(gè)完整的程序只是逐條去執(zhí)行指令,這非常少見。

3.5ARMC語言程序設(shè)計(jì)

3.5.1嵌入式C語言程序設(shè)計(jì)規(guī)范

1)文件包含偽指令|

2)宏定義偽指令

習(xí)慣上總是全部用大寫字母來定義宏,這樣易于把程序的宏標(biāo)識符和一般變量標(biāo)識符區(qū)別開來。如果想要改變數(shù)組的大小,只需要更改宏定義并重新編譯程序即可。

3)條件宏

先測試是否定義過某宏標(biāo)識符,然后決定如何處理,這樣做是為了避免重復(fù)定義。例如:

4)條件編譯偽指令|

這樣,編譯時(shí),編譯器僅對#if()...#endif之間滿足某一條件表達(dá)式的源文件部分進(jìn)行編譯。例如:

5)使用寄存器變量

當(dāng)一個(gè)變量頻繁被讀寫時(shí),需要反復(fù)訪問內(nèi)存,從而花費(fèi)大量的存取時(shí)間。為此,C語言提供了一種變量,即寄存器變量。這種變量存放在CPU的寄存器中,使用時(shí),不需要訪問內(nèi)存,而直接從寄存器中讀寫,從而提高效率。寄存器變量的說明符是register。對于循環(huán)次數(shù)較多的循環(huán)控制變量及循環(huán)體內(nèi)反復(fù)使用的變量均可定義為寄存器變量,而循環(huán)計(jì)數(shù)是應(yīng)用寄存器變量的最好候選者。

例如:

6)活用位操作使用C語言的位操作可以減少除法和取模的運(yùn)算。在計(jì)算機(jī)程序中數(shù)據(jù)的位是可以操作的最小數(shù)據(jù)單位,理論上可以用“位運(yùn)算”來完成所有的運(yùn)算和操作,因而,靈活的位操作可以有效地提高程序運(yùn)行的效率。例如:

C語言位運(yùn)算除了可以提高運(yùn)算效率外,在嵌入式系統(tǒng)的編程中,它的另一個(gè)最典型的應(yīng)用,而且正在被十分廣泛地使用著的是位間的與(&)、或(|)、非(~)操作,這與嵌入式系統(tǒng)的編程特點(diǎn)有很大關(guān)系。例如:

7)數(shù)據(jù)指針

在嵌入式系統(tǒng)的編程中,常常要求在特定的內(nèi)存單元讀寫內(nèi)容,匯編有對應(yīng)的MOV指令,而除C/C++以外的其他編程語言基本沒有直接訪問絕對地址的能力。在嵌入式系統(tǒng)的實(shí)際調(diào)試中,多借助C語言指針?biāo)哂械膶^對地址單元內(nèi)容的讀寫能力。

以指針直接操作內(nèi)存多發(fā)生在以下幾種情況:

(1)某I/O芯片被定位在CPU的存儲空間而非I/O空間,而且寄存器對應(yīng)于某特定地址。

(2)兩個(gè)CPU之間以雙端口RAM通信,CPU需要在雙端口RAM的特定單元書寫內(nèi)容以在對方CPU產(chǎn)生中斷。

(3)讀取在ROM或Flash的特定單元所燒錄的漢字和英文字模。例如:

8)關(guān)鍵字volatile

C/C++作為系統(tǒng)級語言,它們與硬件的聯(lián)系是很緊密的。volatile的意思是“易變的”,這個(gè)關(guān)鍵字最早就是針對那些“異?!钡膬?nèi)存操作而準(zhǔn)備的。它的效果是讓編譯器不要對這個(gè)變量的讀寫操作做任何優(yōu)化,每次讀的時(shí)候都直接去該變量的內(nèi)存地址中去讀,每次寫的時(shí)候都直接寫到該變量的內(nèi)存地址中去,即不做任何緩存優(yōu)化。

volatile的用途有以下幾點(diǎn):

(1)中斷服務(wù)程序中修改的供其他程序檢測的變量需要加volatile。

(2)多任務(wù)環(huán)境下各任務(wù)間共享的標(biāo)志應(yīng)該加volatile。

(3)存儲器映射的硬件寄存器通常也要加voliate,因?yàn)槊看螌λ淖x寫都可能有不同意義。

如果對此外部設(shè)備進(jìn)行初始化的過程像上面代碼一樣順序的對其賦值,顯然優(yōu)化過程并不能達(dá)到目的。反之如果不是對此端口反復(fù)寫操作,而是反復(fù)讀操作,其結(jié)果是一樣的,編譯器在優(yōu)化后,也許代碼對此地址的讀操作只做了一次。然而從代碼角度看是沒有任何問題的。這時(shí)候就該使用volatile通知編譯器這個(gè)變量是一個(gè)不穩(wěn)定的,在遇到此變量時(shí)候不要優(yōu)化。所以應(yīng)該修改為

9)函數(shù)定義

函數(shù)的定義:hudelay為函數(shù)名稱,void為函數(shù)返回值的數(shù)據(jù)類型←voidhudelay→括號中為參數(shù)傳遞的類型

函數(shù)的結(jié)構(gòu)可分為:

(1)子函數(shù)在主程序之前的,先定義子函數(shù),主函數(shù)中直接調(diào)用子函數(shù)。

(2)子函數(shù)在主程序之后的,在主函數(shù)之前要先聲明子函數(shù),然后在主函數(shù)中直接調(diào)用子函數(shù),在主程序之后定義子函數(shù)。

(3)中斷函數(shù)采用--irq關(guān)鍵詞(雙下劃線),比如定義定時(shí)器1的中斷函數(shù)為:void--irqTimel--IRS(void)

(4)可重入函數(shù):出現(xiàn)在多進(jìn)程訪問同一公共資源時(shí),在編寫函數(shù)時(shí)使用局部變量,即變量保存在CPU的寄存器或者堆棧中。

3.5.2C語言與匯編語言混合編程

實(shí)際應(yīng)用時(shí),關(guān)鍵底層的初始化及驅(qū)動(dòng)使用匯編語言,而大部分的應(yīng)用程序使用C語言,如采用匯編語言不僅工作量大、也不利于系統(tǒng)升級和應(yīng)用軟件移植,因此實(shí)際嵌入式系統(tǒng)的應(yīng)用程序是匯編語言與C語言相結(jié)合的混合編程。事實(shí)上,ARM體系結(jié)構(gòu)支持匯編語言的程序設(shè)計(jì)和C/C++語言的程序設(shè)計(jì),以及兩者的混合編程。

1.ATPCS規(guī)則

為了使單獨(dú)編譯的C語言程序和匯編程序之間能夠相互調(diào)用,必須為子程序之間的調(diào)用規(guī)定一定的規(guī)則,ATPCS(ARMThumbProcdeureCallStandard,ARMThumb過程調(diào)用標(biāo)準(zhǔn))就是ARM程序和Thumb程序中子程序調(diào)用的基本規(guī)則。如果讀者使用的是ADS1.2編譯器,那么ATPCS.pdf文檔就在X:/PorgrmamPreogramFiles/ARM/ADSv1-2/PDF/specs目錄里面。X:/指的是ADS1.2編譯器所在的安裝盤。

ATPCS中的各寄存器在ARM編譯器和匯編器中都是預(yù)定義的,寄存器的使用規(guī)則如表3-7所示。

基本ATPCS規(guī)定了在子程序調(diào)用時(shí)的一些基本規(guī)則,包括下面三方面的內(nèi)容。

1)寄存器的使用規(guī)則

寄存器的使用必須滿足以下規(guī)則:

(1)子程序間通過寄存器R0~R3來傳遞參數(shù)。被調(diào)用的子程序在返回前無須恢復(fù)寄存器R0~R3的內(nèi)容。

(2)在子程序中,使用寄存器R4~R11來保存局部變量。這時(shí),寄存器R4~R11可以記為v1~v8。如果在子程序中使用了寄存器v1~v8中的某些寄存器,則子程序進(jìn)入時(shí)必須保存這些寄存器的值,在返回前必須恢復(fù)這些寄存器的值。在Thumb程序中,通常只能使用寄存器R4~R7來保存局部變量。

(3)R9、R10和R11還有一個(gè)特殊作用,分別記為:靜態(tài)基址寄存器SB、數(shù)據(jù)棧限制指針SL和楨指針FP。

(4)寄存器R12用作過程調(diào)用中間臨時(shí)寄存器IP。寄存器R13用作堆棧指針SP。在子程序中寄存器R13不能用作其他用途。寄存器SP在進(jìn)入子程序時(shí)的值和退出子程序的值必須相等。

(5)寄存器R14稱為鏈接寄存器LR,它用于保存子程序的返回地址。如果在子程序中保存了返回地址,寄存器R14則可以用作其他用途。

(6)寄存器R15為程序計(jì)數(shù)器PC,不能用作其他用途。

(7)只有寄存器R0~R7、SP、LR和PC可以在Thumb狀態(tài)下使用,其中R7常作為Thumb狀態(tài)的工作寄存器,記為WR。

2)數(shù)據(jù)棧的使用規(guī)則

ATPCS規(guī)定數(shù)據(jù)棧為FD類型,并對數(shù)據(jù)棧的操作是8字節(jié)對齊的,下面是一個(gè)數(shù)據(jù)棧的組成。

(1)數(shù)據(jù)棧棧指針是指向最后一個(gè)寫入棧的數(shù)據(jù)的內(nèi)存地址。

(2)數(shù)據(jù)棧的基地址是指數(shù)據(jù)棧的最高地址。由于ATPCS中的數(shù)據(jù)棧是FD類型的,實(shí)際上數(shù)據(jù)棧中最早入棧數(shù)據(jù)占據(jù)的內(nèi)存單元是基地址的下一個(gè)內(nèi)存單元。

(3)數(shù)據(jù)棧界限是指數(shù)據(jù)棧中可以使用的最低的內(nèi)存單元地址。

(4)已占用的數(shù)據(jù)棧是指數(shù)據(jù)棧的基地址和數(shù)據(jù)棧棧指針之間的區(qū)域,其中包括數(shù)據(jù)棧棧指針對應(yīng)的內(nèi)存單元。

(5)數(shù)據(jù)棧中的數(shù)據(jù)幀是指在數(shù)據(jù)棧中,為子程序分配的用來保存寄存器和局部變量的區(qū)域。

據(jù)的傳送速度。用ADS編譯器產(chǎn)生的目標(biāo)文件中,外部接口的數(shù)據(jù)棧都是8字節(jié)對齊的,并且編譯器將告訴連接器:本目標(biāo)文件中的數(shù)據(jù)棧是8字節(jié)對齊的。而對于匯編程序來說,如果目標(biāo)文件中包含了外部調(diào)用,則必須滿足以下條件:

(1)外部接口的數(shù)據(jù)棧一定是8位對齊的,也就是要保證在進(jìn)入該匯編代碼后,直到

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論