版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1第五章基于ARM的嵌入式程序設(shè)計(jì)5.1ARM匯編語言的偽操作、宏指令與偽指令5.2ARM匯編語言程序設(shè)計(jì)5.3
嵌入式C語言程序設(shè)計(jì)基礎(chǔ)5.4
嵌入式C語言程序設(shè)計(jì)實(shí)例5.5嵌入式C語言程序設(shè)計(jì)技巧5.6C與匯編語言混合編程25.1ARM匯編語言的偽操作、宏指令與偽指令5.1.1兩種常見的ARM編譯開發(fā)環(huán)境5.1.2ADS編譯環(huán)境下的偽操作和宏指令5.1.3GNU編譯環(huán)境下的偽操作和宏指令5.1.4ARM匯編語言的偽指令
35.1.1兩種常見的ARM編譯開發(fā)環(huán)境ADS/SDTIDE開發(fā)環(huán)境:它由ARM公司開發(fā),使用了CodeWarrior公司的編譯器;集成了GNU開發(fā)工具的IDE開發(fā)環(huán)境::它由GNU的匯編器as、交叉編譯器gcc、和鏈接器ld等組成。4GNU計(jì)劃:譯為“革奴計(jì)劃”,是由理查德·斯托曼在1983年9月27日公開發(fā)起的。它的目標(biāo)是創(chuàng)建一套完全自由的操作系統(tǒng)。理查德·斯托曼最早是在net.unix新聞組上公布該消息,并附帶一份《GNU宣言》解釋為何發(fā)起該計(jì)劃的文章,其中一個(gè)理由就是要“重現(xiàn)當(dāng)年軟件界合作互助的團(tuán)結(jié)精神”。GNU:“GNU'sNotUnix”的縮寫,發(fā)音為“Guh-NOO”(/?gnu?/
)。宗旨:自由軟件計(jì)劃5偽操作:ARM匯編語言程序里的特殊指令助記符,主要作用是完成匯編程序各種準(zhǔn)備工作,在源程序進(jìn)行編譯時(shí)由匯編程序處理,而不是在計(jì)算機(jī)運(yùn)行期間由機(jī)器執(zhí)行。宏指令:是一段獨(dú)立的代碼,可插在源程序中,它通過偽操作來定義。通過實(shí)際指令替代宏體實(shí)現(xiàn)相關(guān)的一段代碼。偽指令:ARM匯編語言里的特殊指令助記符,不在處理器運(yùn)行期間由機(jī)器執(zhí)行。它們?cè)诰幾g時(shí)將被合適的機(jī)器指令替代。65.1.2ADS編譯環(huán)境下的偽操作和宏指令
ADS編譯環(huán)境下的偽操作可分為以下幾類:符號(hào)定義(SymbolDefinition)偽操作數(shù)據(jù)定義(DataDefinition)偽操作匯編控制(AssemblyControl)偽操作信息報(bào)告(Reporting)偽操作其他(Miscellaneous)偽操作
7符號(hào)定義偽操作偽操作語法格式作用GBLAGBLAVariable聲明一個(gè)全局的算術(shù)變量,并將其初始化成0。GBLLGBLLVariable聲明一個(gè)全局的邏輯變量,并將其初始化成{FALSE}。GBLSGBLSVariable聲明一個(gè)全局的字符串變量,并將其初始化成空串“”。LCLALCLAVariable聲明一個(gè)局部的算術(shù)變量,并將其初始化成0。LCLLLCLLVariable聲明一個(gè)局部的邏輯變量,并將其初始化成{FALSE}。LCLSLCLSVariable聲明一個(gè)局部的串變量,并將其初始化成空串“”。SETAVariableSETAexpr給一個(gè)全局或局部算術(shù)變量賦值。SETLVariableSETLexpr給一個(gè)全局或局部邏輯變量賦值。SETSVariableSETSexpr給一個(gè)全局或局部字符串變量賦值。RLISTnameRLIST{listofregisters}為一個(gè)通用寄存器列表定義名稱。CNnameCNexpr為一個(gè)協(xié)處理器的寄存器定義名稱。CPnameCPexpr為一個(gè)協(xié)處理器定義名稱。DN/SNnameDN/SNexprDN/SN為一個(gè)雙精度/單精度的VFP寄存器定義名稱。FNnameFNexpr為一個(gè)FPA浮點(diǎn)寄存器定義名稱。8數(shù)據(jù)定義偽操作
偽操作語法格式作用LTORGLTORG聲明一個(gè)數(shù)據(jù)緩沖池(也稱為文字池)的開始。MAPMAPexpr{,base-register}定義一個(gè)結(jié)構(gòu)化的內(nèi)存表(StorageMap)的首地址。FIELD{label}FIELDexpr定義一個(gè)結(jié)構(gòu)化內(nèi)存表中的數(shù)據(jù)域。SPACE{label}SPACEexpr分配一塊連續(xù)內(nèi)存單元,并用0初始化。DCB{label}DCBexpr{,expr}分配一段字節(jié)內(nèi)存單元,并用expr初始化。DCD/DCDU{label}DCDexpr{,expr}…分配一段字內(nèi)存單元。DCDO{label}DCDOexpr{,expr}…分配一段字對(duì)齊的字內(nèi)存單元。DCFD/DCFDU{label}DCFD{U}fpliteral{,fpliteral}…為雙精度的浮點(diǎn)數(shù)分配字對(duì)齊的內(nèi)存單元。DCFS/DCFSU{label}DCFS{U}fpliteral{,fpliteral}…為單精度的浮點(diǎn)數(shù)分配字對(duì)齊的內(nèi)存單元。DCI{label}DCIexpr{,expr}…在ARM代碼中分配一段字對(duì)齊的內(nèi)存單元;在Thumb代碼中,分配一段半字對(duì)齊的半字內(nèi)存單元。DCQ/DCQU{label}DCQ{U}{﹣}literal{,{﹣}literal}…分配一段以雙字(8個(gè)字節(jié))為單位的內(nèi)存DCW/DCWU{label}DCW{U}expr{,expr}…DCW用于分配一段半字對(duì)齊的半字內(nèi)存單元。9匯編控制偽操作偽操作語法格式作用IF,ELSE及ENDIFIFlogicalexpression…{ELSE…}ENDIF能夠根據(jù)條件把一段源代碼包括在匯編語言程序內(nèi)或者將其排除在程序之外。WHILE及WENDWHILElogicalexpression…WEND能夠根據(jù)條件重復(fù)匯編相同的一段源代碼。MACRO、MEND及MEXITMACRO{$label}macroname{$parameter{,$parameter}…}… ;宏代碼MENDMACRO標(biāo)識(shí)宏定義的開始,MEND標(biāo)識(shí)宏定義的結(jié)束。MERIT用于從宏中跳轉(zhuǎn)出去。用MACRO和MEND定義的一段代碼,稱為宏定義體。通過宏名稱來調(diào)用宏。10信息報(bào)告?zhèn)尾僮?/p>
偽操作語法格式作用ASSERTASSERTlogicalexpression對(duì)匯編程序的第二遍掃描中,如果其中ASSERT中條件不成立,ASSERT偽操作將報(bào)告該錯(cuò)誤信息。INFOINFOnumeric-expression,string-expression在匯編處理過程的第一遍掃描或者第二遍掃描時(shí)INFO偽操作報(bào)告診斷信息。OPTOPTn通過OPT偽操作可以在源程序中設(shè)置列表選項(xiàng)。TTLTTLtitle在列表文件的每一頁的開頭插入一個(gè)標(biāo)題。SUBTSUBTsubtitle在列表文件的每一頁的開頭插入一個(gè)子標(biāo)題。11其他偽操作偽操作語法格式作用CODE16CODE16告訴匯編編譯器后面的指令序列為16位的Thumb指令CODE32CODE32告訴匯編編譯器后面的指令序列為32位的ARM指令。EQUnameEQUexpr{,type}為數(shù)字常量、基于寄存器的值和程序中的標(biāo)號(hào)(基于PC的值)定義一個(gè)字符名稱。AREAAREAsectionname{,attr}{,attr}…定義一個(gè)代碼段或者數(shù)據(jù)段。ENTRYENTRY指定程序的入口點(diǎn)。ENDEND告訴編譯器已經(jīng)到了源程序結(jié)尾。ALIGNALIGN{expr{,offset}}通過添加補(bǔ)丁字節(jié)使當(dāng)前位置滿足一定的對(duì)齊方式。EXPORT/GLOBALEXPORTsymbol{[WEAK]}聲明一個(gè)符號(hào)可以被其他文件引用,相當(dāng)于聲明了一個(gè)全局變量。IMPORTIMPORTsymbol{[WEAK]}告訴編譯器當(dāng)前的符號(hào)不是在本源文件中定義的,而是在其他源文件中定義的,在本源文件中可能引用該符號(hào)。EXTERNEXTERNsymbol{〔WEAK〕}告訴編譯器當(dāng)前的符號(hào)不是在本源文件中定義的,而是在其他源文件中定義的,在本源文件中可能引用該符號(hào)。GET/INCLUDEGETfilename
將一個(gè)源文件包含到當(dāng)前源文件中,并將被包含的文件在其當(dāng)前位置進(jìn)行匯編處理。INCBININCBINfilename將一個(gè)文件包含到當(dāng)前源文件中,被包含的文件不進(jìn)行匯編處理。KEEPKEEP{symbol}告訴編譯器將局部符號(hào)包含在目標(biāo)文件的符號(hào)表中。NOFPNOFP禁止源程序中包含浮點(diǎn)運(yùn)算指令。REQUIREREQUIRElable指定段之間的相互依賴關(guān)系。RNnameRNexpr為一個(gè)特定的寄存器定義名稱。ROUT{name}ROUT定義局部變量的有效范圍。125.1.3GNU編譯環(huán)境下的偽操作和宏指令
GNU編譯環(huán)境下的偽操作可分為以下幾類:常量編譯控制偽操作匯編程序代碼控制偽操作宏及條件編譯控制偽操作其他偽操作13常量編譯控制偽操作
偽操作語法格式作用.byte.byteexpr{,expr}…分配一段字節(jié)內(nèi)存單元,并用expr初始化。.hword/.short.hwordexpr{,expr}…分配一段半字內(nèi)存單元,并用expr初始化。.ascii.asciiexpr{,expr}…定義字符串expr(非零結(jié)束符)。.asciz/.string.ascizexpr{,expr}…定義字符串expr(以/0為結(jié)束符)。.float/.single.floatexpr{,expr}…定義一個(gè)32bitIEEE浮點(diǎn)數(shù)expr。.double.doubleexpr{,expr}…定義64bitIEEE浮點(diǎn)數(shù)expr。word/.long/.int.wordexpr{,expr}…分配一段字內(nèi)存單元,并用expr初始化。.fill.fillrepeat{,size}{,value}分配一段字節(jié)內(nèi)存單元,用size長度value填充repeat次。.zero.zerosize分配一段字節(jié)內(nèi)存單元,并用0填充內(nèi)存。.space/.skip.spacesize{,value}分配一段內(nèi)存單元,用value將內(nèi)存單元初始化。14匯編程序代碼控制偽操作偽操作語法格式作用.section.sectionexpr定義域中包含的段。.text.text{subsection}將操作符開始的代碼編譯到代碼段或代碼段子段。.data.data{subsection}將操作符開始的數(shù)據(jù)編譯到數(shù)據(jù)段或數(shù)據(jù)段子段。.bss.bss{subsection}將變量存放到.bss段或.bss段的子段。.code16/.thumb.code16.thumb表明當(dāng)前匯編指令的指令集選擇Thumb指令集。.code32/.arm.code32.arm表明當(dāng)前匯編指令的指令集選擇ARM指令集。.end.end標(biāo)記匯編文件的結(jié)束行,即標(biāo)號(hào)后的代碼不作處理。.include.include“filename”將一個(gè)源文件包含到當(dāng)前源文件中。.align/.balign.align{alignment}{,fill}{,max}通過添加填充字節(jié)使當(dāng)前位置滿足一定的對(duì)齊方式。15宏及條件編譯控制偽操作
偽操作語法格式作用.macro、.exitm及.endm.macroacroname{parameter{,
parameter}…}….endm.macro偽操作標(biāo)識(shí)宏定義的開始,.endm標(biāo)識(shí)宏定義的結(jié)束。用.macro及.endm定義一段代碼,稱為宏定義體。.exitm偽操作用于提前退出宏。.ifdef,.else及.endif.ifdefcondition….else….endif當(dāng)滿足某條件時(shí)對(duì)一組語句進(jìn)行編譯,而當(dāng)條件不滿足時(shí)則編譯另一組語句。其中else可以缺省。16其他偽操作偽操作語法格式作用.eject.eject在匯編符號(hào)列表文件中插入一分頁符。.list.list產(chǎn)生匯編列表(從.list到.nolist)。.nolist.nolist表示匯編列表結(jié)束處。.title.title“heading”使用“heading”作為標(biāo)題。.sbttl.sbttl“heading”使用“heading”作為子標(biāo)題。.ltorg.ltorg在當(dāng)前段的當(dāng)前地址(字對(duì)齊)產(chǎn)生一個(gè)文字池。.req.reqname,expr為一個(gè)特定的寄存器定義名稱。.err.err使編譯時(shí)產(chǎn)生錯(cuò)誤報(bào)告。.print.printstring打印信息到標(biāo)準(zhǔn)輸出。.fail.failexpr編譯匯編文件時(shí)產(chǎn)生警告。175.1.4ARM匯編語言的偽指令
偽指令語法格式作用ADRADR{cond}
register,expr將基于PC或基于寄存器的地址值讀取到寄存器中。小范圍的地址讀取。ADRLADRL{cond}register,expr將基于PC或基于寄存器的地址值讀取到寄存器中。中等范圍的地址讀取。LDRLDR{cond}register,=[expr|label-expr]將一個(gè)32位的立即數(shù)或者一個(gè)地址值讀取到寄存器中。大范圍的地址讀取。NOPNOP在匯編時(shí)將被替換成ARM中的空操作。185.2ARM匯編語言程序設(shè)計(jì)5.2.1ARM匯編中的文件格式5.2.2ARM匯編語言語句格式5.2.3ARM匯編語言編程的重點(diǎn)5.2.4ARM匯編程序?qū)嵗?95.2.1ARM匯編中的文件格式
ARM源程序文件(可簡稱為源文件)可以由任意一種文本編輯器來編寫程序代碼,它一般為文本格式。在ARM程序設(shè)計(jì)中,常用的源文件可簡單分為以下幾種:源程序文件文件名說
明匯編程序文件*.S用ARM匯編語言編寫的ARM程序或Thumb程序。C程序文件*.C用C語言編寫的程序代碼。頭文件*.H為了簡化源程序,把程序中常用到的常量命名、宏定義、數(shù)據(jù)結(jié)構(gòu)定義等等單獨(dú)放在一個(gè)文件中,一般稱為頭文件。205.2.2ARM匯編語言語句格式
ARM匯編語言語句格式如下所示:{symbol}{instruction|directive|pseudo-instruction}{;comment}
其中:instruction為指令。directive為偽操作。pseudo-instruction為偽指令。symbol為符號(hào)。comment為語句的注釋。
21ARM匯編語言中的符號(hào)符號(hào):可以代表地址、變量和數(shù)字常量。符號(hào)的命名規(guī)則:符號(hào)由大小寫字母、數(shù)字以及下劃線組成局部標(biāo)號(hào)以數(shù)字開頭,其他符號(hào)都不能以數(shù)字開頭符號(hào)是區(qū)分大小寫的符號(hào)在其作用范圍內(nèi)必須唯一程序中的符號(hào)不能與系統(tǒng)內(nèi)部變量或者系統(tǒng)預(yù)定義的符號(hào)同名程序中的符號(hào)通常不要與指令助記符或者偽操作同名22變量: 3種變量:數(shù)字變量、邏輯變量、串變量數(shù)字常量:
3種表示方式:
十進(jìn)制數(shù),如:43、6、112等
十六進(jìn)制數(shù),如:0x3425、0xEF、0x1等
n進(jìn)制數(shù),用n_XXX表示
n為2~9,XXX為具體數(shù) 如:2_01001101、8_432623
標(biāo)號(hào):
表示程序中的指令或地址的符號(hào),3種:基于PC的標(biāo)號(hào)基于寄存器的標(biāo)號(hào)絕對(duì)地址局部標(biāo)號(hào):主要用于局部范圍代碼。由一個(gè)0~99數(shù)字和符號(hào)組成定義的格式:N{routname}
其中:N為0~99數(shù)字,routname為符號(hào)引用的格式:%{F|B}{A|T}N{routname}
其中:%表示引用操作、F指示編譯器只先向前搜索、B指示編譯器只向后搜索、A指示編譯器搜索宏的所有嵌套層次、T指示編譯器搜索宏的當(dāng)前層次24ARM匯編語言中的表達(dá)式優(yōu)先級(jí):括號(hào)內(nèi)的表達(dá)式優(yōu)先級(jí)最高各種操作符有一定的優(yōu)先級(jí)相鄰的單目操作符的執(zhí)行順序?yàn)橛捎业阶螅瑔文坎僮鞣麅?yōu)先級(jí)高于其他操作符優(yōu)先級(jí)相同的雙目操作符執(zhí)行順序?yàn)橛勺蟮接?5字符串表達(dá)式相關(guān)操作符LEN:返回字符串的長度
:LEN:A A為字符串變量 例: GBLSSTR STRSETS“AAA” :LEN:STR ;LEN=3CHR:將0~255之間的整數(shù)作為含一個(gè)ASCII字符的串
:CHR: A A為某一字符的ASCII值26字符串表達(dá)式相關(guān)操作符STR:將一個(gè)數(shù)字量或者邏輯表達(dá)式轉(zhuǎn)換成串。對(duì)于32為的數(shù)字量,STR將其轉(zhuǎn)換成8個(gè)十六進(jìn)制數(shù)組成的串;對(duì)于邏輯表達(dá)式,STR將其轉(zhuǎn)換成字符串T或F。
:STR: A A為數(shù)字量或邏輯表達(dá)式 例:
GLBA A1 SETA A115 :STR: A1 ;將A1轉(zhuǎn)換為”0000000F”27字符串表達(dá)式相關(guān)操作符LEFT:返回一個(gè)字符串最左端一定長度的子串。
A :LEFT: B A為源字符串;B為數(shù)字量,表示返回字符個(gè)數(shù) 例:
GBLS STR1 GBLS STR2 SETS STR1 “AAAABBBB” SETS STR2 STR1 :LEFT: 3
結(jié)果:STR2為”AAA”28字符串表達(dá)式相關(guān)操作符RIGHT:返回一個(gè)字符串最右端一定長度的子串
A :RIGHT: B A為源字符串;B為數(shù)字量,表示返回的字符個(gè)數(shù) 例:
GBLS STR1 GBLS STR2 SETS STR1 “AAABBB” SETS STR2 STR1 :RIGHT: 3
結(jié)果:STR2為”BBB”29字符串表達(dá)式相關(guān)操作符CC:連接2個(gè)字符串
A :CC: B A為第一個(gè)源字符串;B為第二個(gè)源字符串 例:
GBLS STR1 GBLS STR2 STR1 SETS “AAACCC” STR2 SETS “BBB” :CC: (STR1 :LEFT: 3)
結(jié)果:STR2為”BBBAAA”30數(shù)字表達(dá)式相關(guān)操作符NOT:按位取反
:NOT: A
A為32位的數(shù)字量+、-、×、/及MOD:算術(shù)操作符
A+B A、B的和
A-B A、B的差
A×B A、B的積
A/B A除以B的商
A:MOD:B A除以B的余數(shù)31數(shù)字表達(dá)式相關(guān)操作符ROL、ROR、SHL、SHR:循環(huán)移位操作
A:ROL:B 將整數(shù)A循環(huán)左移B位
A:ROR:B 將整數(shù)A循環(huán)右移B位
A:SHL:B 將整數(shù)A左移B位,空位補(bǔ)0 A:SHR:B 將整數(shù)A右移B位,空位補(bǔ)0AND、OR、EOR:按位邏輯操作符
A:AND:B 將數(shù)字表達(dá)式A和B按位作邏輯“與”操作
A:OR:B 將數(shù)字表達(dá)式A和B按位作邏輯“或”操作
A:EOR:B 將數(shù)字表達(dá)式A和B按位作邏輯“異或”操作32邏輯表達(dá)式關(guān)系操作符:
A=B A等于B A>B A大于B A>=B A大于或等于B A<B A小于B A/=BA<>B A不等于B邏輯操作符:
:LNOT:A A的值取反
A:LAND:B A和B的邏輯“與”
A:LOR:B A和B的邏輯“或”
A:LEOR:B A和B的邏輯“異或”33ARM匯編語言程序格式ARM匯編語言是以段(section)為單位來組織源文件的。段是相對(duì)獨(dú)立的、具有特定名稱的、不可分割的指令或者數(shù)據(jù)序列。段又可以分為代碼段和數(shù)據(jù)段,代碼段存放執(zhí)行代碼,數(shù)據(jù)段存放代碼運(yùn)行時(shí)需要用到的數(shù)據(jù)。一個(gè)ARM源程序至少需要一個(gè)代碼段,大的程序可以包含多個(gè)代碼段和數(shù)據(jù)段。
34舉例說明ARM匯編語言源程序的基本結(jié)構(gòu)
AREAEXAMPLE,CODE,READONLYENTRYstartMOVR0,#10MOVR1,#3ADDR0,R0,R1END本程序的程序體部分實(shí)現(xiàn)了一個(gè)簡單的加法運(yùn)算。
355.2.3ARM匯編語言編程的重點(diǎn)ARM數(shù)據(jù)處理操作設(shè)置條件碼匯編語言子程序調(diào)用及返回跳轉(zhuǎn)表思想ARM與Thumb之間的狀態(tài)轉(zhuǎn)換及函數(shù)的互相調(diào)用36ARM數(shù)據(jù)處理操作ARM中數(shù)據(jù)的處理有以下三種形式:簡單的寄存器操作立即數(shù)操作寄存器移位操作其中32位立即數(shù)在32位指令中的編碼以及ARM特有的寄存器移位操作是數(shù)據(jù)處理方面的難點(diǎn)。37設(shè)置條件碼ARM的任何數(shù)據(jù)處理指令都能通過增加“S”操作碼來設(shè)置條件碼(N,Z,C和V)。
條件執(zhí)行
ARM指令集不同尋常的特征是每條指令(除了某些v5T指令)都可以是條件執(zhí)行的。
條件轉(zhuǎn)移
在程序中可以通過條件碼的使用讓微處理器決定是否進(jìn)行轉(zhuǎn)移,還可用來控制循環(huán)的退出。
38匯編語言子程序調(diào)用及返回
子程序的調(diào)用在ARM匯編語言中,子程序調(diào)用是通過BL指令來完成的。BL指令的語法格式如下:BLsubname其中,subname是被調(diào)用的子程序的名稱。子程序的返回在返回調(diào)用子程序時(shí),轉(zhuǎn)移鏈接指令保存到LR寄存器(R14)中的值需要拷貝回程序寄存器PC(R15)。
39跳轉(zhuǎn)表思想在程序設(shè)計(jì)中,有時(shí)為使程序完成一定的功能,需要調(diào)用一系列子程序中的一個(gè),而決定究竟調(diào)用哪一個(gè)由程序的計(jì)算值確定。跳轉(zhuǎn)表是解決該問題的有效方案。跳轉(zhuǎn)表是利用程序計(jì)數(shù)器PC在通用寄存器文件中的可見性來實(shí)現(xiàn)的,如下例所示:
40ARM與Thumb間的狀態(tài)轉(zhuǎn)換
狀態(tài)切換的實(shí)現(xiàn)
ARM/Thumb之間的狀態(tài)切換是通過一條專用的轉(zhuǎn)移交換指令BX來實(shí)現(xiàn)的。BX利用Rn寄存器中目的地址值的最后一位來判斷跳轉(zhuǎn)后的狀態(tài)。當(dāng)最后一位為0時(shí),表示轉(zhuǎn)移到ARM狀態(tài);當(dāng)最后一位為1時(shí),表示轉(zhuǎn)移到Thumb狀態(tài),如下圖所示。
41ARM與Thumb間的函數(shù)的相互調(diào)用ARM/Thumb之間的函數(shù)調(diào)用
在同一狀態(tài)下的子程序調(diào)用,通常只需要一條指令實(shí)現(xiàn)調(diào)用:
BLfunction實(shí)現(xiàn)返回也只需要從LR恢復(fù)PC即可:
MOVPC,LR在不同狀態(tài)下的子程序調(diào)用中,就需要進(jìn)行狀態(tài)之間的切換,需要考慮到以下幾點(diǎn):需要由BX來切換狀態(tài),因?yàn)锽L不能完成狀態(tài)切換。需要在BX之前先保存好LR,BX不能自動(dòng)保存返回地址到LR。需要用“BXLR”來返回,不能使用“MOVPC,LR”,返回時(shí)要仔細(xì)考慮保存在LR中最低位的內(nèi)容是否正確。425.2.4ARM匯編程序?qū)嵗?/p>
簡單的ARM指令程序數(shù)據(jù)塊復(fù)制
利用跳轉(zhuǎn)表實(shí)現(xiàn)程序跳轉(zhuǎn)
435.3嵌入式C語言程序設(shè)計(jì)基礎(chǔ)5.3.1C語言“預(yù)處理偽指令”在嵌入式程序 設(shè)計(jì)中的應(yīng)用5.3.2嵌入式程序設(shè)計(jì)中的函數(shù)及函數(shù)庫5.3.3嵌入式程序設(shè)計(jì)中常用的C語言語句5.3.4嵌入式程序設(shè)計(jì)中C語言的變量、數(shù) 組、結(jié)構(gòu)、聯(lián)合
445.3.1C語言“預(yù)處理偽指令”在嵌入式程序設(shè)計(jì)中的應(yīng)用
“預(yù)處理命令”可以改進(jìn)程序設(shè)計(jì)的環(huán)境,提高編程效率,一般以#號(hào)打頭,可分為以下三種:文件包含宏定義條件編譯45文件包含文件包含偽指令可將頭文件包含到程序中,頭文件中定義的內(nèi)容包括符號(hào)常量、復(fù)合變量原型、用戶定義的變量類型原型和函數(shù)的原型說明等。編譯器編譯預(yù)處理時(shí)用文件包含的正文內(nèi)容替換到實(shí)際程序中。文件包含偽指令的格式#include<頭文件名.h>;標(biāo)準(zhǔn)頭文件#include“頭文件名.h”
;自定義頭文件#include宏標(biāo)識(shí)符46宏定義宏定義偽指令分為:簡單宏、參數(shù)宏、條件宏、預(yù)定義宏及宏釋放。
簡單宏:#define宏標(biāo)識(shí)符宏體參數(shù)宏:#define宏標(biāo)識(shí)符(形式參數(shù)表)
宏體條件宏定義:
#ifdef 宏標(biāo)識(shí)符 #ifndef宏標(biāo)識(shí)符
#undef 宏標(biāo)識(shí)符 #define 宏標(biāo)識(shí)符宏體
#define 宏標(biāo)識(shí)符宏體 #else #else #undef 宏標(biāo)識(shí)符
#define 宏標(biāo)識(shí)符宏體 #define 宏標(biāo)識(shí)符宏體
#endif #endif47條件編譯條件編譯偽指令是寫給編譯器的,指示編譯器在滿足某一條件時(shí)僅編譯源文件中與之相應(yīng)的部分。其格式如右框中所示:
#if(條件表達(dá)式1)…#elif(條件表達(dá)式2)…#elif(條件表達(dá)式n)…#else…#endif485.3.2嵌入式程序設(shè)計(jì)中的函數(shù)及函數(shù)庫
函數(shù)是C語言程序設(shè)計(jì)的核心。一個(gè)較大的C語言程序一般是由一個(gè)主函數(shù)和若干個(gè)子函數(shù)組成,每個(gè)函數(shù)完成一個(gè)特定的功能。函數(shù)之間也可以相互調(diào)用。函數(shù)的格式:
定義性說明格式:[存儲(chǔ)類說明符]類型說明符[修飾符]標(biāo)識(shí)符(參數(shù)表){函數(shù)體}
原型說明格式:extern類型說明符[修飾符]標(biāo)識(shí)符(參數(shù)表){函數(shù)體}
49嵌入式程序設(shè)計(jì)中的函數(shù)及函數(shù)庫函數(shù)庫是為了減少編程工作量,將一些常用的功能的函數(shù)放在函數(shù)庫中供公共使用.它包括C的標(biāo)準(zhǔn)庫函數(shù),也包括一些用戶自己編寫非標(biāo)準(zhǔn)庫。例如,
44blib.h
是根據(jù)基于S3C44B0X處理器的開發(fā)板及其功能模塊編寫的一個(gè)C語言函數(shù)庫。它不屬于C語言的標(biāo)準(zhǔn)庫。505.3.3嵌入式程序設(shè)計(jì)中常用的C語言語句
C語言語句格式為:
[標(biāo)號(hào):]語句[;]
C語言語句很多,常用到的有以下幾種:條件語句
swith語句循環(huán)語句
515.3.4嵌入式程序設(shè)計(jì)中C語言的變量、數(shù)組、結(jié)構(gòu)、聯(lián)合
變量
[存儲(chǔ)類型]類型說明符[修飾符]標(biāo)識(shí)符[=初值][,標(biāo)識(shí)符[=初值]]…;數(shù)組一維數(shù)組:類型說明符標(biāo)識(shí)符[常量表達(dá)式][={初值,初值,…}];char標(biāo)識(shí)符[]=“字符串”;二維數(shù)組:類型說明符標(biāo)識(shí)符[m][n][={{初值表},{初值表}…}];指針數(shù)組和數(shù)組指針類型說明符*標(biāo)識(shí)符[常量表達(dá)式][={地址,地址,…}];類型說明符(*標(biāo)識(shí)符)[][=數(shù)組標(biāo)識(shí)符];
52嵌入式程序設(shè)計(jì)中C語言的變量、數(shù)組、結(jié)構(gòu)、聯(lián)合結(jié)構(gòu)說明
[存儲(chǔ)類說明符]struct[結(jié)構(gòu)原型名]{類型說明標(biāo)識(shí)符[,標(biāo)識(shí)符…];類型說明標(biāo)識(shí)符[,標(biāo)識(shí)符…];
…}標(biāo)識(shí)符[={初值表}[,標(biāo)識(shí)符[={初值表}]…];
53嵌入式程序設(shè)計(jì)中C語言的變量、數(shù)組、結(jié)構(gòu)、聯(lián)合聯(lián)合說明
[存儲(chǔ)類說明符]union[聯(lián)合原型名]{類型說明符標(biāo)識(shí)符[,標(biāo)識(shí)符…];類型說明符標(biāo)識(shí)符[,標(biāo)識(shí)符…];
…
}標(biāo)識(shí)符
={初值表}[,標(biāo)識(shí)符[={初值表}]…];
545.4嵌入式C語言程序設(shè)計(jì)實(shí)例*5.4.1S3VCE40開發(fā)板測(cè)試程序?qū)嵗?.4.2嵌入式C語言程序編寫的簡單構(gòu)架*5.4.3Flash測(cè)試代碼介紹555.4.2嵌入式C語言程序編寫的簡單構(gòu)架#include預(yù)編譯指令
一個(gè)C語言代碼,一般要用#include編譯指令將所需要的頭文件加到該程序中,這是很有必要的,尤其是對(duì)編寫較大的程序代碼時(shí)。隨后是定義一些外部變量,并對(duì)程序中的函數(shù)進(jìn)行聲明。主函數(shù)main()的編寫;在每一個(gè)C語言代碼中,一定要有一個(gè)main()函數(shù),在該函數(shù)中完成該程序文件所要完成的各個(gè)功能,一般是通過調(diào)用各個(gè)子函數(shù)來完成。當(dāng)然,它也可以調(diào)用其他文件中的函數(shù)。完成相應(yīng)功能的各個(gè)功能函數(shù)的編寫。各個(gè)函數(shù)之間可以相互調(diào)用。
565.5嵌入式C語言程序設(shè)計(jì)技巧5.5.1變量定義5.5.2參數(shù)傳遞5.5.3循環(huán)條件575.5.1變量定義
在變量聲明的時(shí)候,最好把所有相同類型的變量放在一起定義,這樣可以優(yōu)化存儲(chǔ)器布局。由下例可以看出:對(duì)于局部變量類型的定義,使用short或char來定義變量并不是總能節(jié)省存儲(chǔ)空間。有時(shí)使用32位int或unsingedint局部變量更有效率一些,如下圖所示:變量定義中,為了精簡程序,程序員總是竭力避免使用冗余變量。但有時(shí)使用冗余變量可以減少存儲(chǔ)器訪問的次數(shù)這可以提高系統(tǒng)性能。
585.5.2參數(shù)傳遞
為了使單獨(dú)編譯的C語言程序和匯編程序能夠互相調(diào)用,定義了統(tǒng)一的函數(shù)過程調(diào)用標(biāo)準(zhǔn)ATPCS。ATPCS定義了寄存器組中的{R0~R3}作為參數(shù)傳遞和結(jié)果返回寄存器,如果參數(shù)數(shù)目超過四個(gè),則使用堆棧進(jìn)行傳遞。內(nèi)部寄存器的訪問速度是遠(yuǎn)遠(yuǎn)大于存儲(chǔ)器的,所以要盡量使參數(shù)傳遞在寄存器里面進(jìn)行,即應(yīng)盡量把函數(shù)的參數(shù)控制在四個(gè)以下。595.5.3循環(huán)條件
計(jì)數(shù)循環(huán)是程序中十分常用的流程控制結(jié)構(gòu),一般有以下兩種形式:for(loop=1;loop<=limit;loop++)
for(loop=limit;loop!=0;loop--)這兩種循環(huán)形式在邏輯上并沒有效率差異,但是映射到具體的體系結(jié)構(gòu)中時(shí),就產(chǎn)生了很大的不同,如下圖所示。
605.6C與匯編語言混合編程5.6.1ATPCS介紹
寄存器的使用 數(shù)據(jù)棧的使用 參數(shù)的傳遞5.6.2內(nèi)嵌匯編5.6.3C和ARM匯編程序間相互調(diào)用615.6.1ATPCS介紹
ATPCS(ARM-ThumbProduceCallStandard)是ARM程序和Thumb程序中子程序調(diào)用的基本規(guī)則,目的是為了使單獨(dú)編譯的C語言程序和匯編程序之間能夠相互調(diào)用。這些基本規(guī)則包括子程序調(diào)用過程中寄存器的使用規(guī)則、數(shù)據(jù)棧的使用規(guī)則和參數(shù)的傳遞規(guī)則。
62寄存器的使用規(guī)則子程序間通過寄存器R0~R3來傳遞參數(shù),這時(shí),寄存器R0~R3可記作A1~A4。被調(diào)用的子程序在返回前無需恢復(fù)寄存器R0~R3的內(nèi)容在子程序中,使用寄存器R4~R11來保存局部變量,這時(shí),寄存器R4~R11可記作V1~V8。如果在子程序中使用到了寄存器V1~V8中的某些寄存器,則子程序進(jìn)入時(shí)必須保存這些寄存器的值,在返回前必須恢復(fù)這些寄存器的值;在Thumb中,只使用R4~R7。寄存器R12用作程序間的scratch寄存器(用于保存SP,在函數(shù)返回時(shí)使用該寄存器出棧),記作IP。63寄存器的使用規(guī)則寄存器R13用作數(shù)據(jù)棧指針,記作SP。在子程序中R13不能用作其他用途。寄存器SP在進(jìn)入子程序時(shí)的值和退出子程序的值必須相等寄存器R14稱為鏈接寄存器,記作LR。它用于保存程序的返回地址。如果在子程序中保存了返回地址,則寄存器R14可用作其他用途寄存器R15是程序計(jì)數(shù)器,記作PC。它不能用作其他用途。64寄存器別名特殊名使用規(guī)則R0a1
參數(shù)/結(jié)果/scratch寄存器1R1a2
參數(shù)/結(jié)果/scratch寄存器2R2a3
參數(shù)/結(jié)果/scratch寄存器3R3a4
參數(shù)/結(jié)果/scratch寄存器4R4v1
ARM狀態(tài)局部變量寄存器1R5v2
ARM狀態(tài)局部變量寄存器2R6v3
ARM狀態(tài)局部變量寄存器3R7v4wrARM狀態(tài)局部變量寄存器4Thumb狀態(tài)工作寄存器R8v5
ARM狀態(tài)局部變量寄存器5R9v6sbARM狀態(tài)局部變量寄存器6,在支持RWPI的ATPCS中為靜態(tài)基址寄存器R10v7slARM狀態(tài)局部變量寄存器7,在支持?jǐn)?shù)據(jù)棧檢查的ATPCS中為數(shù)據(jù)棧限制指針R11v8fpARM狀態(tài)局部變量寄存器8/幀指針R12
ip子程序內(nèi)部調(diào)用的scratch寄存器R13
sp數(shù)據(jù)棧指針R14
lr連接寄存器R15
pc程序計(jì)數(shù)器65數(shù)據(jù)棧的使用規(guī)則根據(jù)堆棧指針指向位置的不同和增長方向的不同可以分為以下4種數(shù)據(jù)棧:
FD(FullDescending)
滿遞減
ED(EmptyDescending)空遞減
FA(FullAscending)
滿遞增
EA(EmptyAscending)
空遞增ATPCS規(guī)定數(shù)據(jù)棧為FD(滿遞減)類型,并且對(duì)數(shù)據(jù)棧的操作是8字節(jié)對(duì)齊的。
66參數(shù)的傳遞規(guī)則參數(shù)個(gè)數(shù)固定的子程序參數(shù)傳遞規(guī)則:第一個(gè)整數(shù)參數(shù),通過寄存器R0~R3來傳遞。其他參數(shù)通過數(shù)據(jù)棧傳遞。
參數(shù)個(gè)數(shù)可變的子程序參數(shù)傳遞規(guī)則:當(dāng)參數(shù)不超過4個(gè)時(shí),可以使用寄存器R0~R3來傳遞參數(shù);當(dāng)參數(shù)超過4個(gè)時(shí),還可以使用數(shù)據(jù)棧來傳遞參數(shù)子程序結(jié)果返回規(guī)則
結(jié)果為一個(gè)32位的整數(shù)時(shí),可以通過寄存器R0返回;結(jié)果為一個(gè)64位整數(shù)時(shí),可以通過寄存器R0和R1返回,依次類推。675.6.2內(nèi)嵌匯編
在C程序中嵌入?yún)R編程序可以實(shí)現(xiàn)一些高級(jí)語言沒有的功能,并可以提高執(zhí)行效率。armcc和armcpp內(nèi)嵌匯編器支持完整的ARM指令集;tcc和tcpp用于Thumb指集。內(nèi)嵌的匯編指令包括大部分的ARM指令和Thumb指令,但是不能直接引用C的變量定義,數(shù)據(jù)交換必須通過ATPCS進(jìn)行。嵌入式匯編在形式上表現(xiàn)為獨(dú)立定義的函數(shù)體。68內(nèi)嵌匯編指令的語法格式
__asm(“指令[;指令]”);
ARMC匯編器使用關(guān)鍵字“__asm”。如果有多條匯編指令需要嵌入,可以用“{}”將它們歸為一條語句。如:__asm{指令[;指令]…[指令]}需要特別注意的是__asm是兩個(gè)下劃線。
69內(nèi)嵌的匯編指令的特點(diǎn)
操作數(shù)可以是寄存器、常量或C表達(dá)式。它們可以是char、short或者int類型,而且是作為無符號(hào)數(shù)進(jìn)行操作。內(nèi)嵌的匯編指令中使用物理寄存器有一些限制。常量前的符號(hào)“#”可以省略只有指令B可以使用C程序中的標(biāo)號(hào),指令BL不能使用C程序中的標(biāo)號(hào)。
不支持匯編語言中用于內(nèi)存分配的偽操作。指令中如果包含常量操作數(shù)。則該指令可能會(huì)被匯編器展開成幾條指令
70內(nèi)嵌匯編器與armasm匯編器的區(qū)別
內(nèi)嵌匯編器不支持通過“·”指示符或PC獲取當(dāng)前指令地址;
不支持LDRRn,=expression偽指令,而使用MOVRn,
expression指令向寄存器賦值;
不支持標(biāo)號(hào)表達(dá)式;不支持ADR和ADRL偽指令;不支持BX和BLX指令;不可以向PC賦值;使用0x前綴替代“&”表示十六進(jìn)制數(shù)。
71內(nèi)嵌匯編注意事項(xiàng)
必須小心使用物理寄存器,如R0~R3,LR和PC。
__arm __arm{ {MOVR0,x MOVvar,xADDy,R0,x/y ADDy,var,x/y} }72不要使用寄存器尋址變量。
intbac_f(intx) { __arm { ADDR0,R0,#1 } returnx } intbac_f(intx) { __arm { ADDx,x,#1 } returnx }intf(intx){ __asm { STMFDSP!,{R0} ADDR0,x,#1 EORx,R0,x LDMFDSP!,{R0} } returnx;}73編譯器自動(dòng)保存和恢復(fù)用到的
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 甘孜職業(yè)學(xué)院《理解當(dāng)代中國英語讀寫》2023-2024學(xué)年第一學(xué)期期末試卷
- 甘肅政法大學(xué)《制藥工藝學(xué)》2023-2024學(xué)年第一學(xué)期期末試卷
- 《赤壁賦公開課》課件
- 《疫的概念與功能》課件
- 三年級(jí)數(shù)學(xué)上冊(cè)六采摘節(jié)-混合運(yùn)算乘加減混合運(yùn)算說課稿青島版六三制
- 三年級(jí)科學(xué)上冊(cè)第1單元水3水結(jié)冰了教案1教科版
- 安全亮眼看世界課件
- 《汽車實(shí)習(xí)報(bào)告》課件
- 2021年衛(wèi)生系統(tǒng)招聘(預(yù)防醫(yī)學(xué))考試題庫
- 洗腦培訓(xùn)課件
- 職工心理健康知識(shí)手冊(cè)
- 11396-國家開放大學(xué)2023年春期末統(tǒng)一考試《藥事管理與法規(guī)(本)》答案
- 工程量自動(dòng)計(jì)算表格新
- 天津市四校2022-2023學(xué)年高二上學(xué)期期末聯(lián)考數(shù)學(xué)試題(原卷版)
- 新時(shí)期學(xué)校德育工作的思路與方法
- 全國優(yōu)質(zhì)課一等獎(jiǎng)人教部編版小學(xué)四年級(jí)下冊(cè)道德與法治《說話要算數(shù)》公開課課件(內(nèi)嵌視頻)
- 四年級(jí)上冊(cè)道德與法治全冊(cè)知識(shí)點(diǎn)匯總
- 分布式計(jì)算安全與隱私保護(hù)
- 客情關(guān)系的有效維護(hù)
- 《班主任工作》教學(xué)大綱
- 新版出口報(bào)關(guān)單模板
評(píng)論
0/150
提交評(píng)論