版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、第4章 ARM編程技術(shù)硅谷芯微 技術(shù)奉獻(xiàn)threeway.cc. ARM處置器支持兩種言語(yǔ)進(jìn)展設(shè)計(jì),一種是匯編言語(yǔ)ARM/Thumb,另一種是高級(jí)言語(yǔ)如C/C+言語(yǔ)。匯編言語(yǔ)的機(jī)器代碼生效果率很高,但可讀性卻不強(qiáng),復(fù)雜的程序很難讀懂;而高級(jí)言語(yǔ)在大多數(shù)情況下其機(jī)器代碼生效果率較差,但可讀性和可移植性卻比匯編言語(yǔ)強(qiáng)很多,而且還可以嵌入?yún)R編來(lái)處理高效性的代碼編寫(xiě)問(wèn)題。本章的內(nèi)容主要有: 匯編言語(yǔ)編程技術(shù); C言語(yǔ)編程技術(shù); 匯編言語(yǔ)與C/C+言語(yǔ)的混合編程。.第4章 目錄1. 匯編言語(yǔ) 2. C言語(yǔ)程序設(shè)計(jì)3. 匯編言語(yǔ)與C/C+言語(yǔ)的混合編程4. ARM編程實(shí)戰(zhàn)5. 課后練習(xí) .4.1 匯編言語(yǔ)
2、 運(yùn)用匯編言語(yǔ)編寫(xiě)程序,它的特點(diǎn)是程序執(zhí)行速度快,程序代碼生成量少,但匯編言語(yǔ)是一種不易學(xué)習(xí)的編程言語(yǔ),并且可讀性較差,這種言語(yǔ)屬于低級(jí)言語(yǔ)。每一種匯編言語(yǔ)對(duì)應(yīng)每一款芯片,運(yùn)用這種言語(yǔ)需求對(duì)硬件有深化的了解。在通常情況下,可以運(yùn)用匯編言語(yǔ)編寫(xiě)驅(qū)動(dòng)程序、需求嚴(yán)厲計(jì)算執(zhí)行時(shí)間的程序以及需求加速執(zhí)行的程序。 .4.1.1 ARM匯編程序的格式1 先引見(jiàn)一個(gè)例子來(lái)闡明ARM匯編程序的格式。例1 計(jì)算20+8,結(jié)果放入R0存放器。 .4.1.1 ARM匯編程序的格式2 例1中定義了兩個(gè)段:數(shù)據(jù)段Buf和代碼段Example。數(shù)據(jù)段中定義了字節(jié)單元Count,其中Count用來(lái)保管一個(gè)被加數(shù);代碼段中包含
3、了一切源程序代碼,程序中首先讀取Count字節(jié)單元的內(nèi)容,然后與立刻數(shù)8相加,計(jì)算結(jié)果保管到R0中。 由例1可見(jiàn),ARM匯編言語(yǔ)的源程序是分段的,由假設(shè)干個(gè)段組成一個(gè)源程序。源程序的普通格式為: .4.1.1 ARM匯編程序的格式3 每一個(gè)段都有一個(gè)名字,并且段名是獨(dú)一的。每個(gè)段以符號(hào)AREA作為段的開(kāi)場(chǎng),以碰到下一個(gè)符號(hào)AREA作為該段的終了。段都有本人的屬性,如是代碼段CODE還是數(shù)據(jù)段DATA,是只讀READONLY還是可讀寫(xiě)READWRITE?這些屬性可以在attr欄中設(shè)定。留意:符號(hào)AREA和END都不能頂格寫(xiě),只需標(biāo)號(hào)可以而且必需頂格寫(xiě)。 .4.1.1.1 ARM匯編程序的書(shū)寫(xiě)格式
4、1 ARM匯編源程序是由假設(shè)干段組成的,而一個(gè)段又是由假設(shè)干個(gè)語(yǔ)句行組成。語(yǔ)句就是完成一個(gè)動(dòng)作的闡明。源程序中的語(yǔ)句可以分為以下兩種類型: 指令性語(yǔ)句:匯編程序會(huì)把指令性語(yǔ)句翻譯成機(jī)器代碼,然后利用這些機(jī)器代碼命令處置器執(zhí)行某些操作。如由MOV、ADD等指令構(gòu)造的語(yǔ)句。 指示性語(yǔ)句:匯編程序并不把它們翻譯成機(jī)器代碼,只是用來(lái)指示、引導(dǎo)匯編程序在匯編時(shí)進(jìn)展一些操作。如由ENTRY、AREA等指令構(gòu)造的語(yǔ)句,我們也稱這些指令為偽指令。從例1可知,語(yǔ)句行的根本格式如下:.4.1.1.1 ARM匯編程序的書(shū)寫(xiě)格式2 在一條語(yǔ)句中, 號(hào)中的內(nèi)容是可選的。在書(shū)寫(xiě)ARM匯編程序時(shí),需求留意以下3點(diǎn): 標(biāo)號(hào)必
5、需在一行的頂格書(shū)寫(xiě),其后面不要加“:,對(duì)于變量的設(shè)置、常量的定義,其標(biāo)識(shí)符必需在一行的頂格書(shū)寫(xiě);而一切指令均不能頂格書(shū)寫(xiě)。 匯編器對(duì)標(biāo)識(shí)符大小寫(xiě)敏感,書(shū)寫(xiě)標(biāo)號(hào)及指令時(shí)字母大小寫(xiě)要一致。在ARM匯編程序時(shí),一個(gè)ARM指令、偽指令、存放器名可以全部為大寫(xiě)字母,也可以全部為小寫(xiě)字母,但不要大小寫(xiě)混合運(yùn)用。 注釋運(yùn)用“;。注釋內(nèi)容由“;開(kāi)場(chǎng)到此行終了,注釋可以在一行的頂格書(shū)寫(xiě)。例2 某一段錯(cuò)誤的匯編言語(yǔ)程序。.4.1.1.1 ARM匯編程序的書(shū)寫(xiě)格式3例2 某一段錯(cuò)誤的匯編言語(yǔ)程序。.4.1.1.2 語(yǔ)句行的符號(hào)1 任何一個(gè)匯編源程序都是由符號(hào)組成的。符號(hào)分為兩大類:指令助記符和用戶定義符。指令助記符
6、包括ARM指令、偽指令等,這些符號(hào)都是預(yù)先定義好的,且具備公用的目的和功能;用戶定義符是由用戶在編寫(xiě)匯編程序時(shí)自行定義的,只在本程序中有意義,不具備通用性。本節(jié)所講的符號(hào)特指用戶定義符,符號(hào)的命名需留意以下規(guī)那么: 符號(hào)由大小寫(xiě)字母、數(shù)字以及下劃線組成。 符號(hào)不能以數(shù)字開(kāi)頭部分標(biāo)號(hào)除外。 符號(hào)區(qū)分大小寫(xiě),且一切字符都是有意義的。 符號(hào)在其作用域范圍內(nèi)必需是獨(dú)一的。 符號(hào)不能與系統(tǒng)內(nèi)部或系統(tǒng)預(yù)定義的符號(hào)同名。 符號(hào)不要以指令助記符、偽指令同名。符號(hào)可以代表地址、數(shù)值、變量。當(dāng)符號(hào)代表地址時(shí)又稱為標(biāo)號(hào),符號(hào)代表某個(gè)特定數(shù)值時(shí)又稱為符號(hào)常量,.4.1.1.2 語(yǔ)句行的符號(hào)2符號(hào)代表變量時(shí)又稱為變量名
7、。所以符號(hào)有3個(gè)用途:標(biāo)號(hào)、符號(hào)常量、變量名。1標(biāo)號(hào): 標(biāo)號(hào)代表一個(gè)地址,段內(nèi)標(biāo)號(hào)的地址在匯編時(shí)確定,而段外標(biāo)號(hào)的地址值在鏈接時(shí)確定。根據(jù)標(biāo)號(hào)的生成方式可以分為以下3種: 基于PC的標(biāo)號(hào):該標(biāo)號(hào)是位于目的指令前的標(biāo)號(hào)或程序中的數(shù)據(jù)定義偽指令前的標(biāo)號(hào)。這種標(biāo)號(hào)在匯編時(shí)將被處置成PC值加上或減去一個(gè)數(shù)字常量。它常用于表示跳轉(zhuǎn)指令的目的地址,或者代碼段中所嵌入的少量數(shù)據(jù)。 基于存放器的標(biāo)號(hào):該標(biāo)號(hào)通常用MAP和FILED偽指令定義,也可以用于EQU偽指令定義。這種標(biāo)號(hào)在匯編時(shí)被處置成存放器的值加上或減去一個(gè)數(shù)字常量。它常用于訪問(wèn)位于數(shù)據(jù)段中的數(shù)據(jù)。.4.1.1.2 語(yǔ)句行的符號(hào)3 絕對(duì)地址:絕對(duì)地址
8、是一個(gè)32位的數(shù)字量,可尋址的范圍為0232-1,可以直接尋址整個(gè)內(nèi)存空間。例3 標(biāo)號(hào)舉例。.4.1.1.2 語(yǔ)句行的符號(hào)42符號(hào)常量: 在程序運(yùn)轉(zhuǎn)過(guò)程中,其值不能被改動(dòng)的量稱為常量。常量區(qū)分為3種不同的類型: 數(shù)字常量:數(shù)字常量表示某個(gè)特定的數(shù)字,如0、5、-19、0 xF8都是數(shù)字常量。同一個(gè)數(shù)字常量可以有十進(jìn)制數(shù)、十六進(jìn)制數(shù)等多種表達(dá)方式。 字符常量:字符常量由一對(duì)單引號(hào)及中間字符串表示,規(guī)范C言語(yǔ)中的本義符也是也可運(yùn)用。假設(shè)需求包含雙引號(hào)或“$,必需運(yùn)用“或“$替代。如H是一個(gè)字符常量,“Hello World是一個(gè)字符串常量。 布爾常量:布爾常量由括號(hào)和邏輯值TRUE、FALSE表示
9、。邏輯真為T(mén)RUE,邏輯假為FALSE。 為了程序書(shū)寫(xiě)的方便,可以用一個(gè)標(biāo)識(shí)符來(lái)代表一個(gè)常量,稱這個(gè)標(biāo)識(shí)符為符號(hào)常量,即標(biāo)識(shí)符方式的常量。.4.1.1.2 語(yǔ)句行的符號(hào)5例4 用EQU偽指令定義數(shù)字符號(hào)常量。 例子中定義了兩個(gè)數(shù)字符號(hào)常量:T_bit和PLLCON。所以程序中用到這兩個(gè)符號(hào)常量時(shí),在程序鏈接時(shí)就會(huì)被相應(yīng)的值0 x20、0 xE01FC080所替代。 .4.1.1.2 語(yǔ)句行的符號(hào)63變量名: 變量是指存放在存儲(chǔ)單元的操作數(shù),并且它的值可以改動(dòng)。變量名代表了一個(gè)變量,當(dāng)程序中要用到變量時(shí),只需求援用對(duì)應(yīng)的變量名。 實(shí)踐上,變量名是一個(gè)符號(hào)地址,當(dāng)程序編譯鏈接時(shí),系統(tǒng)會(huì)給每一個(gè)變量
10、名分配一個(gè)內(nèi)存地址。在程序中從變量中取值,實(shí)踐上是經(jīng)過(guò)變量名找到相應(yīng)的內(nèi)存地址,從其存儲(chǔ)單元中讀取數(shù)據(jù)。 按照變量的作用范圍可分為全局變量和部分變量;按照變量的數(shù)值類型可分為數(shù)字變量、字符變量和邏輯變量。根據(jù)兩種類型的組合,變量共具有6種類型:全局?jǐn)?shù)字變量、全局邏輯變量、全局字符串變量、部分?jǐn)?shù)字變量、部分邏輯變量、部分字符串變量。詳細(xì)對(duì)這些類型的變量如何聲明、賦初值,將在4.1.2小節(jié)符號(hào)定義偽指令中詳細(xì)引見(jiàn)。.4.1.2 偽指令語(yǔ)句1 匯編言語(yǔ)程序由機(jī)器指令、偽指令和宏指令組成。偽指令不像機(jī)器指令那樣在處置器運(yùn)轉(zhuǎn)期間由機(jī)器執(zhí)行,而是在對(duì)源程序進(jìn)展匯編期間由匯編工具處置的操作,它們可以完成如符
11、號(hào)定義、數(shù)據(jù)定義、分配存儲(chǔ)區(qū)、指示程序開(kāi)場(chǎng)終了等功能。本小節(jié)只闡明一些常用的偽指令。另外,還有一些偽指令可查看相關(guān)手冊(cè)。 在前面的ARM指令集章節(jié)中,曾經(jīng)接觸了幾條常用的ARM偽指令,如ADR、ADRL、LDR、NOP等。把它們和指令集一同引見(jiàn)是由于它們?cè)趨R編時(shí)會(huì)被適宜的機(jī)器指令替代,實(shí)現(xiàn)真正機(jī)器指令操作。偽指令大約可分為以下6種類型: ARM偽指令,如ADR、LDR、NOP等,本節(jié)不再反復(fù)引見(jiàn)。 符號(hào)定義偽指令。 段及段屬性定義偽指令。 .4.1.2 偽指令語(yǔ)句2 數(shù)據(jù)定義偽指令。 匯編控制偽指令。 雜項(xiàng)偽指令。.4.1.2.1 符號(hào)定義偽指令1 符號(hào)定義偽指令用于定義ARM匯編程序的常量、
12、標(biāo)號(hào)和變量,對(duì)變量進(jìn)展賦值等操作。符號(hào)定義偽指令包括EQU偽指令、變量聲明偽指令、變量賦值偽指令。變量的聲明與賦值偽指令如表4.1所示。表4.1 變量聲明與賦值偽指令.4.1.2.1 符號(hào)定義偽指令21EQU: EQU用于將程序中的數(shù)字常量、標(biāo)號(hào)、基于存放器的值賦予一個(gè)等效的稱號(hào),這一點(diǎn)類似于C言語(yǔ)中的#define,可用“*替代EQU。指令格式如下: 其中,name為要定義的常量的稱號(hào);expr可以為數(shù)字常量、程序中的標(biāo)號(hào)、32位地址常量、存放器的地址值等;type指示expr的數(shù)據(jù)類型,是可選項(xiàng)。例5 EQU偽指令的運(yùn)用。.4.1.2.1 符號(hào)定義偽指令32變量聲明偽指令: 變量聲明偽指令
13、包括全局變量聲明偽指令和部分變量聲明偽指令。全局變量聲明偽指令包括GBLA、GBLL、GBLS,部分變量聲明偽指令包括LCLA、LCLL、LCLS。全局變量多用于程序體中,而部分變量用于宏定義體中。其中: GBLA、LCLA偽指令用于聲明一個(gè)數(shù)字變量,并將其初始化為0。 GBLL、LCLL偽指令用于聲明一個(gè)邏輯變量,并將其初始化為FALSE。 GBLS、LCLS偽指令用于聲明一個(gè)字符串變量,并將其初始化為空字符串。偽指令格式如下:.4.1.2.1 符號(hào)定義偽指令4 其中,GB/LCLA/L/S為變量聲明偽指令,可以為6個(gè)變量聲明偽指令GBLA、GBLL、GBLS、LCLA、LCLL、LCLS中
14、的任一個(gè)。variable是定義的變量名,其數(shù)據(jù)類型和作用范圍由變量聲明偽指令來(lái)確定,但變量名在其作用內(nèi)必需獨(dú)一。例6 運(yùn)用全局變量。例7 宏構(gòu)造中運(yùn)用部分變量。.4.1.2.1 符號(hào)定義偽指令53變量賦值偽指令: 變量賦值偽指令用于對(duì)已定義的全局變量或部分變量賦值,共有3條變量賦值偽指令:SETA、SETL、SETS。SETA偽指令用于給一個(gè)全局或部分的算術(shù)變量賦值。SETL偽指令用于給一個(gè)全局或部分的邏輯變量賦值。SETS偽指令用于給一個(gè)全局或部分的字符變量賦值。指令格式如下: 其中Variable_a、Variable_l、Variable_s就是前面全局變量或部分變量所定義的變量名。e
15、xpr_a為賦值的常數(shù);expr_l為邏輯值,即TRUE或FALSE;expr_s為賦值的字符串。.4.1.2.1 符號(hào)定義偽指令6例8 給字符串變量賦值。.4.1.2.2 段及段屬性定義偽指令1 由前面分析得知,匯編言語(yǔ)的源程序是分段的,并且每個(gè)段都有本人的屬性,下面講述段定義和段屬性定義偽指令。該類指令引見(jiàn)如下: AREA:定義一個(gè)段開(kāi)場(chǎng)。 END:整個(gè)文件終了。 ALIGN:定義邊境對(duì)齊方式。 ENTRY:定義程序入口。 CODE16:指明本段為16位Thumb代碼。 CODE32:指明本段為32位ARM代碼。例9 代碼段的例子。 .4.1.2.2 段及段屬性定義偽指令2 例9中AREA
16、偽指令定義了一個(gè)段,段名為Hello,段屬性是只讀的代碼段。 ENTRY偽指令用于指定程序的入口點(diǎn)。一個(gè)程序可以包含多個(gè)源文件至少要有一個(gè)ENTRY,可以有多個(gè)ENTRY,但一個(gè)源文件中最多只需一個(gè)ENTRY。 CODE32偽指令指示匯編編譯器后面的指令為32位的ARM指令。ARM9處置器支持兩種指令集:Thumb指令集和ARM指令集。其中CODE16偽指令指示匯編編譯器后面的指令為16位的Thumb指令,CODE32偽指令指示匯編編譯器后面的指令為32位的ARM指令。CODE16和CODE32偽指令只是指示匯編編譯器后面的指令的類型,偽指令本身并不進(jìn)展程序形狀切換。要用BX指令操作才干進(jìn)展切
17、換。 最后一條語(yǔ)句END偽指令用于通知編譯器曾經(jīng)到了源程序的結(jié)尾。每一個(gè)匯編文件均要運(yùn)用一個(gè)END偽指令指示根源程序終了。 .4.1.2.2 段及段屬性定義偽指令3下面引見(jiàn)略微復(fù)雜的AREA偽指令和ALIGN偽指令。1AREA偽指令: AREA偽指令用于定義一個(gè)代碼段或數(shù)據(jù)段。ARM匯編程序設(shè)計(jì)采用分段式設(shè)計(jì),一個(gè)ARM源程序至少需求一個(gè)代碼段,而大的程序可以包含多個(gè)代碼段及數(shù)據(jù)段。偽指令格式如下: 其中sectionname為所定義的代碼段或數(shù)據(jù)段的稱號(hào)。假設(shè)該稱號(hào)是以數(shù)據(jù)開(kāi)頭的,那么該稱號(hào)必需用“|括起來(lái)。attr為該代碼段或數(shù)據(jù)段的屬性。 在AREA偽指令中,各屬性之間用逗號(hào)隔開(kāi),以下為
18、段屬性及相關(guān)闡明: .4.1.2.2 段及段屬性定義偽指令4 ALIGN=expr。默許的情況下,代碼段和數(shù)據(jù)段是4字節(jié)對(duì)齊的,expr可以取031的數(shù)值,相應(yīng)的對(duì)齊方式為2expr字節(jié)對(duì)齊。對(duì)于代碼段,expr不能為0或1。 ASSOC=section。指定與本段相關(guān)的ELF段。任何時(shí)候鏈接section段也必需包括sectionname段。 CODE為定義代碼段。屬性默以為READONLY。 DATA為定義數(shù)據(jù)段。屬性默以為READWRITE。 COMMON定義一個(gè)通用段。該段不包含任何用戶代碼和數(shù)據(jù)。鏈接器將其初始化為0。各源文件中同名的COMMON段共用同樣的內(nèi)存單元,鏈接器為其分配適
19、宜的尺寸。 NOINIT指定本數(shù)據(jù)段僅僅保管了內(nèi)存單元,而沒(méi)有將各個(gè)初始值寫(xiě)入內(nèi)存單元,或者將內(nèi)存單元值初始化為0。 .4.1.2.2 段及段屬性定義偽指令5 READONLY指定本段為只讀,代碼段的默許屬性為READONLY。 READWRITE指定本段為可讀可寫(xiě),數(shù)據(jù)段的默許屬性為READWRITE。 運(yùn)用AREA偽指令將程序分為多個(gè)ELF格式的段,段稱號(hào)可以一樣,這時(shí)同名的段被放在同一個(gè)ELF段中。例10 聲明了代碼段Example1,只讀,并且4字節(jié)對(duì)齊。 .4.1.2.2 段及段屬性定義偽指令62ALIGN偽指令: ALIGN偽指令可經(jīng)過(guò)添加填充字節(jié)的方式,使當(dāng)前位置滿足一定的對(duì)齊方
20、式。偽指令格式如下: 其中,表達(dá)式的值用于指定對(duì)齊方式。能夠的取值為2的冪,如1、2、4、8、16等,不能為0。假設(shè)偽指令中沒(méi)有指定表達(dá)式,那么編譯器會(huì)將當(dāng)前位置對(duì)齊到下一個(gè)字的位置。偏移量也為一個(gè)數(shù)字表達(dá)式,假設(shè)運(yùn)用該字段,那么當(dāng)前位置的對(duì)齊方式為:2的表達(dá)式次方+偏移量。 ALIGN=expr:對(duì)齊方式為2expr,如expr=3,那么對(duì)齊方式為8字節(jié)對(duì)齊。表達(dá)式的取值范圍為031。.4.1.2.3 數(shù)據(jù)定義偽指令1 數(shù)據(jù)定義偽指令用于數(shù)據(jù)表定義、文字池定義、數(shù)據(jù)空間分配等,同時(shí)也可完成已分配存儲(chǔ)單元的初始化。該類偽指令有許多,這里只詳細(xì)引見(jiàn)如下常用的偽指令,感興趣的可參考相關(guān)手冊(cè)。 聲明
21、一個(gè)文字池:LTORG。 定義一個(gè)構(gòu)造化的內(nèi)存表的首地址:MAP。 定義構(gòu)造化內(nèi)存表中的一個(gè)數(shù)據(jù)域:FIELD。 分配一塊內(nèi)存空間,并用0初始化:SPACE。 分配一段字節(jié)的內(nèi)存單元,并用指定的數(shù)據(jù)初始化:DCB。 分配一段半字的內(nèi)存單元,并用指定的數(shù)據(jù)初始化:DCW。 分配一段字的內(nèi)存單元,并用指定的數(shù)據(jù)初始化:DCD。 分配一段雙字的內(nèi)存單元,并用指定的數(shù)據(jù)初始化:DCQ。.4.1.2.3 數(shù)據(jù)定義偽指令21LTORG: LTORG用于聲明一個(gè)文字池,在運(yùn)用LDR偽指令時(shí),要在適當(dāng)?shù)牡刂穮⑴cLTORG聲明文字池,這樣就會(huì)把要加載的數(shù)據(jù)保管到文字池內(nèi),再用ARM的加載指令讀出數(shù)據(jù)假設(shè)沒(méi)有運(yùn)用
22、LTORG聲明文字池,那么匯編器會(huì)在程序末尾自動(dòng)聲明。偽指令格式如下:例11 文字池舉例。.4.1.2.3 數(shù)據(jù)定義偽指令3 LTORG偽指令常放在無(wú)條件跳轉(zhuǎn)指令之后,或者子程序前往指令之后,這樣處置器就不會(huì)錯(cuò)誤地將文字池中的數(shù)據(jù)當(dāng)作指令來(lái)執(zhí)行。.4.1.2.3 數(shù)據(jù)定義偽指令42MAP: MAP偽指令用于定義一個(gè)構(gòu)造化的內(nèi)存表的首地址。此時(shí)內(nèi)存表的位置計(jì)數(shù)器VAR設(shè)置為該地址值。VAR為匯編器的內(nèi)置變量。MAP也可用“替代。偽指令格式如下: 其中,expr為程序中的標(biāo)號(hào)或數(shù)字表達(dá)式。base_register基址存放器為可選項(xiàng),當(dāng)base_register選項(xiàng)不存在時(shí),expr的值即為內(nèi)存表
23、的首地址,當(dāng)該選項(xiàng)存在時(shí),內(nèi)存表的首地址為expr的值與base_register的和。.4.1.2.3 數(shù)據(jù)定義偽指令5例12 MAP指令。 MAP偽指令通常與FIELD偽指令配合運(yùn)用來(lái)定義構(gòu)造化的內(nèi)存表。但MAP、FIELD偽指令僅僅是定義數(shù)據(jù)構(gòu)造,它們并不初始化內(nèi)存單元的內(nèi)容。MAP偽指令中的base_register存放器的值對(duì)于其后一切的FIELD偽指令定義的數(shù)據(jù)域是默許運(yùn)用的,直到遇到新的包含base_register項(xiàng)的MAP偽指令。 .4.1.2.3 數(shù)據(jù)定義偽指令63FIELD: FIELD偽指令用于定義一個(gè)構(gòu)造化內(nèi)存表中的數(shù)據(jù)域。FIELD也可用“#替代。偽指令格式如下:
24、其中l(wèi)abel為數(shù)據(jù)域標(biāo)號(hào),expr表示本數(shù)據(jù)域在內(nèi)存表中所占的字節(jié)數(shù)。FIELD偽指令常與MAP偽指令配合運(yùn)用來(lái)定義構(gòu)造化的內(nèi)存表。MAP偽指令定義內(nèi)存表的首地址,F(xiàn)IELD偽指令定義內(nèi)存表中的各個(gè)數(shù)據(jù)域,并可以為每個(gè)數(shù)據(jù)域指定一個(gè)標(biāo)號(hào)供其他的指令援用。例13 MAP和FIELD偽指令的運(yùn)用。.4.1.2.3 數(shù)據(jù)定義偽指令7例13 MAP和FIELD偽指令的運(yùn)用。.4.1.2.3 數(shù)據(jù)定義偽指令84SPACE: SPACE用于分配一塊內(nèi)存單元,并用0初始化。%與SPACE同義。偽指令格式如下: 其中,label為內(nèi)存塊起始地址標(biāo)號(hào),expr為所要分配的內(nèi)存字節(jié)數(shù)。例14 為Buf變量懇求空
25、間。.4.1.2.3 數(shù)據(jù)定義偽指令95DCB、DCW、DCD、DCQ: 這4條偽指令都是用于分配一段內(nèi)存單元,并對(duì)該內(nèi)存單元初始化。獨(dú)一的區(qū)別是它們分配內(nèi)存單元的大小不同。這一類偽指令的格式是: 其中標(biāo)號(hào)label字段是可有可無(wú)的,它表示分配的內(nèi)存起始地址,作用與指令語(yǔ)句前的標(biāo)號(hào)一樣。Operand為操作數(shù),即內(nèi)存單元的初始化數(shù)據(jù)。 助記符Mnemonic字段闡明所用偽指令的助記符,常用的有以下幾種: DCB分配一段字節(jié)的內(nèi)存單元,其后的每個(gè)操作數(shù)都占有一個(gè)字節(jié),操作數(shù)可以為-128255的數(shù)值或字符串。 .4.1.2.3 數(shù)據(jù)定義偽指令10 DCW分配一段半字的內(nèi)存單元,其后的每個(gè)操作數(shù)都
26、占有兩個(gè)字節(jié),操作數(shù)是16位二進(jìn)制數(shù),取值范圍為-3276865535。 DCD分配一段字的內(nèi)存單元,其后的每個(gè)操作數(shù)都占有4個(gè)字節(jié),操作數(shù)可以是32位的數(shù)字表達(dá)式,也可以是程序中的標(biāo)號(hào)由于程序中的標(biāo)號(hào)代表地址,也是32位二進(jìn)制數(shù)值。 DCQ分配一段雙字的內(nèi)存單元,其后的每個(gè)操作數(shù)都占有8個(gè)字節(jié)。例15 分配內(nèi)存單元舉例操作數(shù)可以是常數(shù),或者是表達(dá)式。.4.1.2.3 數(shù)據(jù)定義偽指令11 匯編程序在匯編期間對(duì)存儲(chǔ)器進(jìn)展內(nèi)存分配,分配結(jié)果如圖4.1所示,其中Addr代表一個(gè)隨機(jī)分配的內(nèi)存地址。圖4.1中保管的數(shù)據(jù)都用十六進(jìn)制表示,其中DCB偽指令定義的每個(gè)數(shù)據(jù)占用一個(gè)字節(jié)空間,DCW偽指令定義的
27、每個(gè)數(shù)據(jù)占用兩個(gè)字節(jié)空間,DCD偽指令定義的每個(gè)數(shù)據(jù)占用4個(gè)字節(jié)空間。.4.1.2.3 數(shù)據(jù)定義偽指令12圖4.1 例15內(nèi)存分配表示圖 .4.1.2.3 數(shù)據(jù)定義偽指令13例16 分配內(nèi)存單元舉例操作數(shù)也可以是字符串。 例16的內(nèi)存分配結(jié)果如圖4.2所示,用了10個(gè)字節(jié)空間保管這個(gè)字符串,標(biāo)號(hào)MESSAGE指向該內(nèi)存塊的第一個(gè)地址。 .4.1.2.3 數(shù)據(jù)定義偽指令14圖4.2 例16內(nèi)存分配表示圖 .4.1.2.3 數(shù)據(jù)定義偽指令15例17 向量中斷表操作數(shù)還可以是程序中的標(biāo)號(hào)。.4.1.2.4 匯編控制偽指令1 匯編控制偽指令用于條件匯編、宏定義、反復(fù)匯編控制等。該類偽指令如下: 宏定義
28、:MACRO和MEND。 條件匯編控制:IF,ELSE和ENDIF。 反復(fù)匯編:WHILE和WEND。.4.1.2.4 匯編控制偽指令21宏定義偽指令MACRO和MEND: 宏定義偽指令包括MACRO、MEND、MEXIT。MACRO定義一個(gè)宏語(yǔ)句段的開(kāi)場(chǎng),MEND定義宏語(yǔ)句段的終了,MEXIT可以實(shí)現(xiàn)從宏程序段的跳出。用MACRO及MEND定義的一段代碼稱為宏定義體。在程序中就可以經(jīng)過(guò)宏指令多次調(diào)用該代碼段。指令格式如下:.4.1.2.4 匯編控制偽指令3宏定義指令格式闡明如下: 標(biāo)號(hào):是可選項(xiàng)。當(dāng)宏定義被展開(kāi)時(shí),可被交換成相應(yīng)的符號(hào),通常為一個(gè)標(biāo)號(hào),在一個(gè)符號(hào)前運(yùn)用$表示被匯編時(shí)將運(yùn)用相應(yīng)
29、的值替代$后的符號(hào)。 宏名:所定義的宏的稱號(hào)。宏調(diào)用是經(jīng)過(guò)調(diào)用宏的稱號(hào)來(lái)實(shí)現(xiàn)的。 參數(shù):宏指令的參數(shù)。當(dāng)宏指令被展開(kāi)時(shí)將被交換成相應(yīng)的值,類似于函數(shù)的方式參數(shù)。參數(shù)是可選項(xiàng),可以有多個(gè)。 宏是一段功能完好的程序,可以實(shí)現(xiàn)一個(gè)特定的功能,在運(yùn)用中可以把它視為一個(gè)子程序。在其他程序中可以調(diào)用宏來(lái)完成某個(gè)功能。調(diào)用宏是經(jīng)過(guò)調(diào)用宏的稱號(hào)來(lái)實(shí)現(xiàn)的。在源程序被編譯時(shí),匯編器將宏調(diào)用展開(kāi)。用宏定義中的指令序列交換程序中宏名的調(diào)用,并將實(shí)踐參數(shù)的值傳送給宏定義中的參數(shù)。.4.1.2.4 匯編控制偽指令4 宏與子程序的區(qū)別,在于調(diào)用宏時(shí)編譯程序會(huì)在調(diào)用途插入宏的程序段,有多少次調(diào)用就會(huì)插入多少宏的程序段;而調(diào)用
30、子程序不添加新的程序段。調(diào)用宏的益處是不占用傳送參數(shù)的存放器,不用維護(hù)現(xiàn)場(chǎng),但假設(shè)多次調(diào)用宏,那么無(wú)形中添加了代碼量。例18 宏運(yùn)用舉例。.4.1.2.4 匯編控制偽指令5 上例定義了MAX宏,宏語(yǔ)句段的功能是完成將兩個(gè)參數(shù)date和time保管到起始地址為0 x1000的內(nèi)存單元中。倒數(shù)第二條語(yǔ)句是宏調(diào)用語(yǔ)句,編譯后該條語(yǔ)句會(huì)展開(kāi)。整個(gè)語(yǔ)句段編譯后的程序如下:.4.1.2.4 匯編控制偽指令62條件匯編控制偽指令I(lǐng)F、ELSE和ENDIF: IF,ELSE和ENDIF偽指令可以根據(jù)條件把一段代碼包括在匯編程序內(nèi)或?qū)⑵渑懦诔绦蛑狻?與IF同義,|與ELSE同義,與ENDIF同義。偽指令格式
31、如下: 其中,logical_expr為用于控制的邏輯表達(dá)式。假設(shè)條件成立,那么代碼段1落在匯編源程序中有效。假設(shè)條件不成立,代碼段1無(wú)效,同時(shí)假設(shè)運(yùn)用ELSE偽指令,代碼段2有效。.4.1.2.4 匯編控制偽指令7例19 條件匯編控制舉例。留意:IF,ELSE和ENDIF偽指令是可以嵌套運(yùn)用的。 .4.1.2.4 匯編控制偽指令83反復(fù)匯編偽指令WHILE和WEND: WHILE和WEND偽指令用于根據(jù)條件反復(fù)匯編一樣的或幾乎一樣的一段源程序。偽指令格式如下: 其中,logical_expr為用于控制的邏輯表達(dá)式。假設(shè)條件成立,那么代碼段在匯編程序中有效,并不斷反復(fù)這段代碼直到條件不成立。例
32、20 反復(fù)匯編舉例。.4.1.2.4 匯編控制偽指令9例20 反復(fù)匯編舉例。留意:WHILE和WEND偽指令是可以嵌套運(yùn)用的。 .4.1.2.5 雜項(xiàng)偽指令1雜項(xiàng)偽指令引見(jiàn)如下: 導(dǎo)出偽指令:EXPORT、GLOBAL。 導(dǎo)入偽指令:IMPORT、EXTERN。 文件包含偽指令:GET、INCLUDE。 一個(gè)程序可以由多個(gè)匯編源文件組成,多個(gè)文件間會(huì)相互援用符號(hào)變量或標(biāo)號(hào)。當(dāng)在一個(gè)源文件中定義的一個(gè)符號(hào)希望其他文件援用時(shí),那么必需用導(dǎo)出偽指令定義這個(gè)符號(hào);假設(shè)這個(gè)文件援用了外部定義的符號(hào),那么必需用導(dǎo)入偽指令定義這個(gè)符號(hào)。.4.1.2.5 雜項(xiàng)偽指令21導(dǎo)出偽指令EXPORT和GLOBAL:
33、EXPORT聲明一個(gè)符號(hào)可以被其他文件運(yùn)用,相當(dāng)于聲明一個(gè)全局標(biāo)號(hào),可以被其他文件援用。GLOBAL與EXPORT一樣。偽指令格式如下: 其中,標(biāo)號(hào)為要聲明的符號(hào)稱號(hào)。, WEAK為可選項(xiàng),聲明其他文件有同名的標(biāo)號(hào)時(shí),那么該同名標(biāo)號(hào)優(yōu)先于該標(biāo)號(hào)被援用。例21 定義全局標(biāo)號(hào)InitStack和Vectors。.4.1.2.5 雜項(xiàng)偽指令3例21 定義全局標(biāo)號(hào)InitStack和Vectors。.4.1.2.5 雜項(xiàng)偽指令42導(dǎo)入偽指令I(lǐng)MPORT和EXTERN: IMPORT通知編譯器這個(gè)標(biāo)號(hào)要在當(dāng)前源文件中運(yùn)用,但標(biāo)號(hào)是在其他的源文件中定義的。不論當(dāng)前源文件能否運(yùn)用過(guò)該標(biāo)號(hào),這個(gè)標(biāo)號(hào)都會(huì)參與到
34、當(dāng)前源文件的符號(hào)表中。EXTERN和IMPORT同義,都是聲明一個(gè)外部符號(hào)。偽指令格式如下: 其中,標(biāo)號(hào)為要聲明的符號(hào)稱號(hào)。, WEAK為可選項(xiàng),表示假設(shè)一切的源文件都沒(méi)有找到這個(gè)標(biāo)號(hào)的定義,編譯器也不會(huì)提示錯(cuò)誤信息。 .4.1.2.5 雜項(xiàng)偽指令5 運(yùn)用IMPORT或EXTERN聲明外部標(biāo)號(hào)時(shí),假設(shè)鏈接器在鏈接處置時(shí)不能解釋該符號(hào),而偽指令中沒(méi)有WEAK選項(xiàng),那么鏈接器會(huì)報(bào)告錯(cuò)誤;如偽指令中有WEAK選項(xiàng),那么鏈接器不會(huì)報(bào)告錯(cuò)誤,而是進(jìn)展下面的操作: 假設(shè)該符號(hào)被B或者BL指令援用,那么該符號(hào)被設(shè)置成下一條指令的地址,該B或BL指令相當(dāng)于一條NOP指令。 其他情況下該符號(hào)被設(shè)置為0。例22
35、導(dǎo)入標(biāo)號(hào)InitStack和Vectors。.4.1.2.5 雜項(xiàng)偽指令63文件包含偽指令GET和INCLUDE: GET偽指令將一個(gè)源文件包含到當(dāng)前的源文件中,并將被包含的源文件在當(dāng)前位置展開(kāi)進(jìn)展匯編處置。INCLUDE與之同義。偽指令格式如下: 我們通常這樣運(yùn)用這個(gè)偽指令:在某源文件中定義一些宏指令用MAP和FIELD定義構(gòu)造化的數(shù)據(jù)類型,用EQU定義常量的符號(hào)稱號(hào),然后用GET/INCLUDE將這個(gè)源文件包含到其他的源文件中。這樣的源文件類似于C言語(yǔ)中的頭文件,GET/INCLUDE不能用于包含目的文件,包含目的文件那么需求運(yùn)用INCBIN偽指令。例23 包含inc文件。.4.1.3 匯
36、編言語(yǔ)程序設(shè)計(jì)及舉例 程序有順序、分支、循環(huán)和子程序4種構(gòu)造方式。順序程序構(gòu)造是指完全按順序逐條執(zhí)行的指令序列,這在程序段中是大量存在的,但作為完好的程序那么很少見(jiàn)。本小節(jié)將引見(jiàn)順序、分支、循環(huán)和子程序這4種構(gòu)造。.4.1.3.1 順序程序設(shè)計(jì)1 最簡(jiǎn)單的程序是沒(méi)有分支、沒(méi)有循環(huán)的順序運(yùn)轉(zhuǎn)程序。下面以一個(gè)算術(shù)運(yùn)算程序進(jìn)展闡明和引見(jiàn)。 例24 經(jīng)過(guò)查表操作實(shí)現(xiàn)數(shù)組中的第1項(xiàng)數(shù)據(jù)和第5項(xiàng)數(shù)據(jù)相加,結(jié)果保管到數(shù)組中。程序中首先讀取數(shù)組的第1項(xiàng)數(shù)據(jù),然后讀取第5項(xiàng)數(shù)據(jù),之后將結(jié)果相加,最后保管結(jié)果,整個(gè)流程是順序執(zhí)行的,如圖4.3所示。圖4.3 程序流程圖.4.1.3.1 順序程序設(shè)計(jì)2程序清單4.1
37、 例24的程序.4.1.3.2 分支程序設(shè)計(jì)1 在一個(gè)實(shí)踐的程序中,程序一直是順序執(zhí)行的情況并不多見(jiàn),通常都會(huì)有各種分支。在ARM匯編程序中,條件后綴能實(shí)現(xiàn)程序分支。例25 編寫(xiě)匯編程序?qū)崿F(xiàn)C言語(yǔ)if else分支程序。C言語(yǔ)程序如下分支流程圖如圖4.4所示:圖4.4 分支流程圖.4.1.3.2 分支程序設(shè)計(jì)2圖4.4 分支流程圖 設(shè)R0保管變量x的值,R1保管變量y的值,R2保管變量z的值x、y、z均為無(wú)符號(hào)整數(shù),對(duì)應(yīng)實(shí)現(xiàn)的匯編程序見(jiàn)程序清單4.2。程序清單4.2 例25的匯編程序.4.1.3.2 分支程序設(shè)計(jì)3程序清單4.2 例25的匯編程序 B和BL指令可以實(shí)現(xiàn)分支,程序清單4.3展現(xiàn)了
38、B指令實(shí)現(xiàn)匯編程序中常用的散轉(zhuǎn)算法。程序清單4.3 B指令實(shí)現(xiàn)散轉(zhuǎn)功能.4.1.3.2 分支程序設(shè)計(jì)4程序清單4.3 B指令實(shí)現(xiàn)散轉(zhuǎn)功能.4.1.3.3 循環(huán)程序設(shè)計(jì)1 在程序中,往往要求某一段程序反復(fù)執(zhí)行多次,這時(shí)就可以利用循環(huán)程序構(gòu)造。一個(gè)循環(huán)構(gòu)造由以下兩部分組成。 循環(huán)體:就是要求反復(fù)執(zhí)行的程序段部分。 循環(huán)終了條件:在循環(huán)程序中必需給出循環(huán)終了條件,否那么程序就會(huì)進(jìn)入死循環(huán)。常見(jiàn)的循環(huán)有計(jì)數(shù)循環(huán)和條件循環(huán)。計(jì)數(shù)循環(huán)是當(dāng)循環(huán)了一定次數(shù)后就終了循環(huán);條件循環(huán)是當(dāng)循環(huán)條件為假時(shí)就終了循環(huán)。 在C言語(yǔ)中,for和while語(yǔ)句可以實(shí)現(xiàn)這兩種循環(huán)。下面引見(jiàn)如何用匯編言語(yǔ)實(shí)現(xiàn)這兩種循環(huán)。例26 編
39、寫(xiě)匯編程序?qū)崿F(xiàn)計(jì)數(shù)循環(huán)。計(jì)數(shù)循環(huán)用C言語(yǔ)表達(dá)如下:.4.1.3.3 循環(huán)程序設(shè)計(jì)2設(shè)R0為x,R2為ii、x均為無(wú)符號(hào)整數(shù),匯編言語(yǔ)程序段如下:例27 編寫(xiě)匯編程序?qū)崿F(xiàn)條件循環(huán)。條件循環(huán)用C言語(yǔ)表達(dá)如下:.4.1.3.3 循環(huán)程序設(shè)計(jì)3設(shè)x為R0,y為R1x、y均為無(wú)符號(hào)整數(shù),匯編言語(yǔ)程序段如下: 例28 編寫(xiě)循環(huán)語(yǔ)句實(shí)現(xiàn)數(shù)據(jù)塊復(fù)制。.4.1.3.3 循環(huán)程序設(shè)計(jì)4例28 編寫(xiě)循環(huán)語(yǔ)句實(shí)現(xiàn)數(shù)據(jù)塊復(fù)制。.4.1.3.4 子程序設(shè)計(jì)1 在一個(gè)程序的不同部分往往要用到類似的程序段,這些程序段的功能和構(gòu)造方式都一樣,只是某些變量的賦值不同,此時(shí)就可以把這些程序段寫(xiě)成子程序方式,以便需求時(shí)可以調(diào)用它。
40、調(diào)用程序在調(diào)用子程序時(shí),經(jīng)常需求傳送一些參數(shù)給子程序;子程序運(yùn)轉(zhuǎn)完后也經(jīng)常要回送結(jié)果給調(diào)用程序。這種調(diào)用程序和子程序之間的信息傳送稱為參數(shù)傳送。參數(shù)傳送可以有以下兩種方法: 當(dāng)參數(shù)比較少時(shí),可以經(jīng)過(guò)存放器傳送參數(shù)。 當(dāng)參數(shù)比較多時(shí),可以經(jīng)過(guò)內(nèi)存塊或堆棧傳送參數(shù)。 子程序的正確執(zhí)行是由子程序的正確調(diào)用及正確前往保證的。這就要求調(diào)用程序在調(diào)入子程序時(shí)必需保管正確的前往地址,即當(dāng)前PC值由于ARM流水線特性.4.1.3.4 子程序設(shè)計(jì)2,能夠要減去一個(gè)偏移量。PC值可以保管在公用的鏈接存放器R14中,也可以保管到堆棧中。根據(jù)這兩種情況,可以在子程序中采用如下的前往語(yǔ)句: 運(yùn)用堆棧來(lái)恢復(fù)處置器的形狀時(shí)
41、,留意STMFD與LDMFD要配合運(yùn)用。 普通來(lái)講,在ARM匯編言語(yǔ)程序中,子程序的調(diào)用是經(jīng)過(guò)BL指令來(lái)實(shí)現(xiàn)的。該指令在執(zhí)行時(shí)完成如下操作:將子程序的前往地址存放在鏈接存放器LR中針對(duì)流水線特性,曾經(jīng)減去偏移量了,同時(shí)將程序計(jì)數(shù)器PC指向子程序的入口點(diǎn),當(dāng)子程序執(zhí)行終了需求前往調(diào)用途時(shí),只需求將存放在LR中的前往地址重新拷貝給程序計(jì)數(shù)器PC即可。 .4.1.3.4 子程序設(shè)計(jì)3 下面看一段C代碼。程序?qū)崿F(xiàn)比較兩個(gè)數(shù),取出其最大值。實(shí)現(xiàn)求最大值功能的C言語(yǔ)代碼見(jiàn)程序清單4.4的MAX函數(shù),對(duì)應(yīng)的匯編代碼見(jiàn)程序清單4.5的MAX標(biāo)號(hào)。在程序清單4.5中,子程序和調(diào)用主程序之間經(jīng)過(guò)存放器R0、R1、
42、R2傳送參數(shù)。程序清單4.4 MAX函數(shù)和調(diào)用主程序.4.1.3.4 子程序設(shè)計(jì)4程序清單4.5 MAX匯編子程序和調(diào)用主程序.4.2 C言語(yǔ)程序設(shè)計(jì) C/C+言語(yǔ)是一種高級(jí)言語(yǔ),運(yùn)用它可以快速地編寫(xiě)運(yùn)用程序。用C/C+言語(yǔ)編寫(xiě)的程序,一條語(yǔ)句可以替代多條匯編言語(yǔ)語(yǔ)句。運(yùn)用高級(jí)言語(yǔ)進(jìn)展程序設(shè)計(jì)有以下優(yōu)點(diǎn): 有豐富的程序庫(kù)支持。 程序容易編寫(xiě),具有構(gòu)造化特點(diǎn)。 程序可讀性強(qiáng),容易修正。 便于調(diào)試和維護(hù)。 可移植性好。 對(duì)于大中型工程來(lái)說(shuō),用C/C+言語(yǔ)編寫(xiě)軟件其開(kāi)發(fā)周期和開(kāi)發(fā)本錢通常要小于匯編言語(yǔ)。所以在做工程時(shí),普通會(huì)提倡用C/C+言語(yǔ)編寫(xiě)代碼。但C言語(yǔ)程序設(shè)計(jì)的思想與方法不是本節(jié)重點(diǎn),本節(jié)只
43、討論以下3方面的內(nèi)容:. 運(yùn)用Semihosting效力建立C言語(yǔ)調(diào)試環(huán)境。 移植ADS1.2中的C言語(yǔ)函數(shù)庫(kù)。 C程序編寫(xiě)規(guī)范。 如對(duì)ADS1.2集成開(kāi)發(fā)環(huán)境不太熟習(xí),請(qǐng)參閱相關(guān)章節(jié)做輔助閱讀。.4.2.1 運(yùn)用Semihosting的效力1 在C程序設(shè)計(jì)中,經(jīng)常要用到C規(guī)范庫(kù)中提供的一些輸入/輸出函數(shù),如printf()、scanf()、putchar()、getchar()等函數(shù)。這些I/O函數(shù)能顯示程序運(yùn)轉(zhuǎn)結(jié)果,接納按鍵輸入,極大方便了程序的運(yùn)轉(zhuǎn)與調(diào)試。在ADS1.2環(huán)境中,利用Semihosting效力功能,可以很方便地調(diào)用ADS1.2中的C言語(yǔ)函數(shù)庫(kù),包括根本的輸入/輸出函數(shù)。 在
44、ADS的C言語(yǔ)函數(shù)庫(kù)中,某些ANSIC的功能是由主機(jī)的調(diào)試環(huán)境來(lái)提供的,這套機(jī)制有一個(gè)專門(mén)術(shù)語(yǔ)叫Semihosting。例如,Semihosting技術(shù)能將運(yùn)用程序中的I/O懇求經(jīng)過(guò)一定的通道傳送入主機(jī)的調(diào)試環(huán)境,由主機(jī)的調(diào)試環(huán)境來(lái)實(shí)現(xiàn)數(shù)據(jù)的輸入/輸出。 .4.2.1 運(yùn)用Semihosting的效力2 Semihosting的效力功能是經(jīng)過(guò)一組軟件中斷SWI指令來(lái)實(shí)現(xiàn)的。當(dāng)一個(gè)Semihosting軟中斷被執(zhí)行時(shí),調(diào)試系統(tǒng)先識(shí)別這個(gè)SWI懇求,然后掛起正在運(yùn)轉(zhuǎn)的程序,調(diào)用Semihosting的效力,完成后再恢復(fù)原來(lái)的程序執(zhí)行。因此,主機(jī)執(zhí)行的義務(wù)對(duì)于程序來(lái)說(shuō)是透明的。 下面引見(jiàn)一個(gè)運(yùn)用Se
45、mihosting的C言語(yǔ)程序例如,并對(duì)Semihosting進(jìn)展簡(jiǎn)單的分析。 .4.2.1.1 C言語(yǔ)程序例如1 1啟動(dòng)ADS1.2,運(yùn)用ARM Executable Image工程模板建立一個(gè)工程Semihosting。2建立源文件UseLib.c,編寫(xiě)實(shí)驗(yàn)程序,如圖4.5所示,然后添加到工程Semihosting中。圖4.5 建立源文件UseLib.c .4.2.1.1 C言語(yǔ)程序例如2 圖4.5 建立源文件UseLib.c .4.2.1.1 C言語(yǔ)程序例如3 3編譯鏈接工程,選擇ProjectDebug命令,啟動(dòng)AXD進(jìn)展仿真調(diào)試。4在AXD調(diào)試環(huán)境中選擇OptionConfigure
46、 Target命令,彈出Choose Target對(duì)話框,如圖4.6所示,選擇ARMUL仿真環(huán)境。圖4.6 選擇ARMUL仿真環(huán)境.4.2.1.1 C言語(yǔ)程序例如4 5選擇FileLoad Image命令,找到Semihosting工程中的映像文件Semihosting. axf,把映像文件加載到AXD環(huán)境中,加載后如圖4.7所示。圖4.7 把映像文件加載到AXD環(huán)境中.4.2.1.1 C言語(yǔ)程序例如5 圖4.7 把映像文件加載到AXD環(huán)境中.4.2.1.1 C言語(yǔ)程序例如6 6按F5鍵運(yùn)轉(zhuǎn),程序會(huì)在main()函數(shù)斷點(diǎn)處停頓,如圖4.8所示。圖4.8 按F5鍵運(yùn)轉(zhuǎn).4.2.1.1 C言語(yǔ)程序
47、例如7 7繼續(xù)運(yùn)轉(zhuǎn),輸出第一條語(yǔ)句的結(jié)果,如圖4.9所示。圖4.9 輸出第一條語(yǔ)句的結(jié)果8輸入一個(gè)大寫(xiě)字符H,輸出結(jié)果如圖4.10所示。圖4.10 輸出結(jié)果.4.2.1.1 C言語(yǔ)程序例如8 9繼續(xù)運(yùn)轉(zhuǎn),最后程序終了,程序指針停留在“SWI 0 x123456語(yǔ)句處,如圖4.11所示。圖4.11 程序指針停在“SWI 0 x123456語(yǔ)句處.4.2.1.2 機(jī)器代碼分析1 圖4.12和圖4.13分別是映像文件反匯編后的部分匯編代碼,程序指針首先從_main函數(shù)處執(zhí)行,執(zhí)行一段程序后再執(zhí)行main函數(shù),其中main函數(shù)才是用戶本人編輯的程序。圖4.12 _main函數(shù).4.2.1.2 機(jī)器代碼
48、分析2 圖4.13 main函數(shù) 在程序中運(yùn)用庫(kù)函數(shù),必需先建立一個(gè)庫(kù)函數(shù)可以執(zhí)行的環(huán)境。從反匯編代碼中,可以看出程序在執(zhí)行main函數(shù)前執(zhí)行了一長(zhǎng)串的程序,這些程序是ADS編譯器自動(dòng)給用戶程序加上去的。.4.2.1.2 機(jī)器代碼分析3 ADS編譯器在編譯C言語(yǔ)程序時(shí),假設(shè)程序中運(yùn)用了main函數(shù),那么編譯器將自動(dòng)添加額外代碼,完成初始化堆棧和C庫(kù)等任務(wù)。生成的映像文件執(zhí)行如下的任務(wù)流程。1將執(zhí)行文件中的RO段和RW段從加載域地址load address復(fù)制到執(zhí)行域地址execution address。2初始化ZI區(qū)域,用0來(lái)初始化變量。3跳轉(zhuǎn)到_rt_entry,執(zhí)行如下4個(gè)調(diào)用: 調(diào)用_
49、rt_stackheap_init,建立程序的堆和棧。 調(diào)用_rt_lib_init,初始化程序用到的C庫(kù),并為main傳送參數(shù)。 調(diào)用main,即用戶程序的入口。 調(diào)用exit,退出Semihosting。.4.2.1.2 機(jī)器代碼分析4 總結(jié)以上流程,ADS初始化過(guò)程如圖4.14所示。總體上,初始化過(guò)程可以分為兩部分來(lái)看: _main擔(dān)任設(shè)置運(yùn)轉(zhuǎn)映像存儲(chǔ)器映射,_rt_entry擔(dān)任庫(kù)函數(shù)的初始化。 _main完成代碼和數(shù)據(jù)的復(fù)制,并把ZI數(shù)據(jù)區(qū)清零。這一步只需當(dāng)代碼和數(shù)據(jù)區(qū)在存儲(chǔ)和運(yùn)轉(zhuǎn)時(shí)處于不同的存儲(chǔ)器位置時(shí)才有意義。接著_main跳進(jìn)_rt_entry,進(jìn)展STACK棧和HEAP堆等的
50、初始化。最后_rt_entry跳進(jìn)運(yùn)用程序的入口main()。當(dāng)運(yùn)用程序執(zhí)行完時(shí),_rt_entry又將控制權(quán)交還給調(diào)試器。圖4.14 ADS初始化過(guò)程.4.2.1.2 機(jī)器代碼分析5 圖4.14 ADS初始化過(guò)程.4.2.1.2 機(jī)器代碼分析6 函數(shù)main()在ADS中有特殊的意義。當(dāng)一個(gè)程序工程工程中存在main()時(shí),鏈接器會(huì)把_main和_rt_entry中的初始化代碼鏈接進(jìn)來(lái);假設(shè)沒(méi)有main()函數(shù),初始化過(guò)程就不會(huì)被鏈接,結(jié)果就會(huì)導(dǎo)致一些規(guī)范的C庫(kù)函數(shù)無(wú)效。.4.2.2 移植ADS1.2中的C言語(yǔ)函數(shù)庫(kù) 1 1Semihost調(diào)用C言語(yǔ)函數(shù)庫(kù)的機(jī)制: 開(kāi)發(fā)一個(gè)嵌入式運(yùn)用軟件時(shí),
51、ADS用戶能夠并不完全清楚目的硬件的一些參數(shù)目的。如有關(guān)外設(shè)、存儲(chǔ)器地址分布,甚至處置器類型等一些細(xì)節(jié),都還沒(méi)有最終確定。為了在一切這些細(xì)節(jié)全部就緒前就能進(jìn)展軟件開(kāi)發(fā),ADS工具有一套程序構(gòu)建和調(diào)試的默許設(shè)置,使得用戶能在Semihost效力的支持下完成軟件的調(diào)試與開(kāi)發(fā)。 在Semihost效力的支持下,開(kāi)發(fā)人員可以很透明地調(diào)用C言語(yǔ)函數(shù)庫(kù)中的一切函數(shù)。從概念上來(lái)講,C言語(yǔ)函數(shù)可以被分成兩部分,一是ANSIC言語(yǔ)規(guī)范本身的一部分,一是只受某一特定ANSIC層次支持的函數(shù),如圖4.15所示。其中,一些ANSIC的功能是由主機(jī)調(diào)試環(huán)境調(diào)用驅(qū)動(dòng)程序級(jí)的函數(shù)完成的。例如,ADS的庫(kù)函數(shù).4.2.2 移
52、植ADS1.2中的C言語(yǔ)函數(shù)庫(kù) 2 printf()把輸出信息輸出到調(diào)試器的控制臺(tái)窗口,這個(gè)功能經(jīng)過(guò)調(diào)用_sys_write()實(shí)現(xiàn)。_sys_write()執(zhí)行了一個(gè)把字符串輸出到主機(jī)控制臺(tái)的Semihosting軟中斷效力程序。 圖4.15 C言語(yǔ)庫(kù)函數(shù)構(gòu)造.4.2.2 移植ADS1.2中的C言語(yǔ)函數(shù)庫(kù) 3 假設(shè)用戶在程序編譯時(shí)沒(méi)有指定映像的存儲(chǔ)器映射分布,ADS將為生成的目的代碼和數(shù)據(jù)分配一個(gè)默許的存儲(chǔ)器映射圖,如圖4.16所示。 圖4.16 存儲(chǔ)器映射.4.2.2 移植ADS1.2中的C言語(yǔ)函數(shù)庫(kù) 4 目的映像被鏈接至地址0 x8000,存儲(chǔ)和執(zhí)行區(qū)域都位于該地址開(kāi)場(chǎng)的空間。RO只讀部
53、分放在前面,接著是RW讀寫(xiě)部分,最后是ZI零初始化部分。 在ZI部分之上緊跟著HEAP,所以HEAP確實(shí)切地址要在鏈接時(shí)才干確定。 STACK的基地址是在運(yùn)用程序啟動(dòng)時(shí)由一個(gè)Semihosting操作調(diào)用_rt_stackheap_init函數(shù)提供。.4.2.2 移植ADS1.2中的C言語(yǔ)函數(shù)庫(kù) 5 2根據(jù)目的環(huán)境移植C庫(kù)函數(shù): 默許形狀下C庫(kù)函數(shù)利用Semihosting機(jī)制來(lái)實(shí)現(xiàn)設(shè)備驅(qū)動(dòng)的功能。但一個(gè)真正的嵌入式系統(tǒng)要運(yùn)用到詳細(xì)的外設(shè)或硬件獨(dú)立于主機(jī)環(huán)境運(yùn)轉(zhuǎn)。 規(guī)范庫(kù)中包含了部分依賴于ARM Semihosted執(zhí)行環(huán)境的函數(shù),需求重新實(shí)現(xiàn)這部分函數(shù)。假設(shè)在程序中定義這些函數(shù),那么編譯器就
54、會(huì)運(yùn)用新定義的函數(shù),這個(gè)過(guò)程叫做重定向C言語(yǔ)庫(kù)函數(shù),如圖4.17所示。普通情況下,只需求重新定義很少的幾個(gè)函數(shù)就可以運(yùn)用C庫(kù)。圖4.17 重定向C言語(yǔ)庫(kù)函數(shù).4.2.2 移植ADS1.2中的C言語(yǔ)函數(shù)庫(kù) 6 圖4.17 重定向C言語(yǔ)庫(kù)函數(shù).4.2.2 移植ADS1.2中的C言語(yǔ)函數(shù)庫(kù) 7 舉例來(lái)說(shuō),規(guī)范I/O庫(kù)中最常用的是printf系列函數(shù),包括_printf()、printf()、_fprintf()、fprintf、_vprintf()和vprintf()。一切這些函數(shù)非透明地運(yùn)用_FILE,并且僅依賴于fputc()和ferror()兩個(gè)函數(shù)。只需定義了本人的_FILE版本和fputc
55、()、ferror()函數(shù),外加定義一個(gè)具有FILE類型的_stdout變量,就可以不作任何修正地運(yùn)用printf系列、fwrite()、fputc()和puts函數(shù)了。 假設(shè)用戶有一個(gè)I/O設(shè)備如UART。本來(lái)庫(kù)函數(shù)fputc()是把字符輸出到調(diào)試器控制窗口中去的,但用戶把輸出設(shè)備改成UART端口,這樣一來(lái),一切基于fputc()函數(shù)的printf()系列函數(shù)輸出都被重定向到UART端口上。下面是實(shí)現(xiàn)fputc()重定向的例子: .4.2.2 移植ADS1.2中的C言語(yǔ)函數(shù)庫(kù) 8 下面是實(shí)現(xiàn)fputc()重定向的例子: 這個(gè)例子簡(jiǎn)單地將輸入字符重新定向到另一個(gè)函數(shù)sendchar(),sen
56、dchar()假定是一個(gè)另外定義的串口輸出函數(shù)。在這里,fputc()就好象目的硬件和規(guī)范C庫(kù)函數(shù)之間的一個(gè)籠統(tǒng)層。 .4.2.3 編程規(guī)范1 嵌入式系統(tǒng)的開(kāi)發(fā)是一項(xiàng)艱巨復(fù)雜的工程,涉及很多方面的知識(shí),系統(tǒng)的開(kāi)發(fā)必需注重團(tuán)隊(duì)協(xié)作。所謂“沒(méi)有規(guī)范,不成方圓,系統(tǒng)開(kāi)發(fā)前必需建立一個(gè)編程規(guī)約,且該規(guī)約應(yīng)貫穿整個(gè)開(kāi)發(fā)一直。采用一致的規(guī)約能提高程序的可了解性,提高勞動(dòng)消費(fèi)率,并使開(kāi)發(fā)軟件便于維護(hù)。 用C言語(yǔ)或其他言語(yǔ)編寫(xiě)程序的風(fēng)格有很多種。慣用的、好的書(shū)寫(xiě)風(fēng)格都具有如下的效果: 易看懂,干凈整齊,可了解性好,可維護(hù)性好。 具備良好的兼容性,可移植性好。 無(wú)論采用什么樣的編程風(fēng)格,必需在整個(gè)開(kāi)發(fā)過(guò)程中采用
57、一直如一的格式。對(duì)于一項(xiàng)大工程的整個(gè)團(tuán)隊(duì),建議運(yùn)用一致的編程風(fēng)格,可以少發(fā)生一些程序維護(hù)中令人頭疼的事情,降低維護(hù)本錢;采用一致的書(shū)寫(xiě)方法,有助于防止代碼的反復(fù)編寫(xiě)。這里展現(xiàn)的C言語(yǔ)程序.4.2.3 編程規(guī)范2 的編程風(fēng)格,主要強(qiáng)調(diào)如何使源碼便于閱讀與維護(hù)。 為了加強(qiáng)程序的可了解性、可維護(hù)性,可以從4個(gè)方面去思索:恰當(dāng)完備的注釋、一致合理的命名規(guī)那么、美觀良好的編輯風(fēng)格和組織有序的文件構(gòu)造。.4.2.3.1 恰當(dāng)完備的注釋1 恰當(dāng)完備的注釋有利于加強(qiáng)對(duì)程序文件或代碼的了解,但是不規(guī)范、胡亂的注釋反而妨礙人們對(duì)程序的了解。怎樣的注釋才是有效的注釋呢,這樣的注釋至少要遵照以下規(guī)那么: 注釋該當(dāng)準(zhǔn)確
58、。注釋的位置應(yīng)與被描畫(huà)的代碼相鄰,并盡量防止在注釋中運(yùn)用縮寫(xiě),不要讓人對(duì)代碼產(chǎn)生誤解;錯(cuò)誤的注釋不但無(wú)益反而有害,修正代碼的同時(shí)修正相應(yīng)的注釋,以保證注釋與代碼一致。 注釋該當(dāng)簡(jiǎn)明扼要。重要復(fù)雜的代碼段或代碼行一定要有注釋,注釋要簡(jiǎn)明扼要。沒(méi)有用的注釋要?jiǎng)h除。假設(shè)代碼本來(lái)就是清楚的,那么不用加注釋。否那么多此一舉,令人膩煩。 注釋不可喧賓奪主。注釋是對(duì)代碼的“提示,但是過(guò)多的、花哨的注釋會(huì)讓人眼花繚亂,反而妨礙了了解。.4.2.3.1 恰當(dāng)完備的注釋2 注釋主要出如今文件頭和程序代碼中。文件頭的注釋用于版本、版權(quán)聲明;程序代碼中的注釋用于函數(shù)接口闡明、重要的段落提示和重要的代碼行提示,如例29
59、所示。 普通來(lái)講,C/C+言語(yǔ)的注釋符有兩種,分別為“/*/和“/。通常情況下,程序塊的注釋采用“/*/,行注釋那么采用“/。例29 注釋范例。.4.2.3.1 恰當(dāng)完備的注釋3 例29 注釋范例。.4.2.3.2 一致合理的命名規(guī)那么1 比較著名的命名規(guī)那么當(dāng)推Microsoft公司的“匈牙利法,該命名規(guī)那么的主要思想是“在變量和函數(shù)名中參與前綴以增進(jìn)人們對(duì)程序的了解。例如,一切的字符變量均以ch為前綴,假設(shè)是指針變量那么追加前綴p。假設(shè)一個(gè)變量由ppch開(kāi)頭,那么闡明它是指向字符指針的指針。 “匈牙利法最大的缺陷是繁瑣,如下定義:倘假設(shè)采用“匈牙利命名規(guī)那么,那么該當(dāng)寫(xiě)成: 如此繁瑣的程序
60、會(huì)讓絕大多數(shù)程序員無(wú)法忍受。 .4.2.3.2 一致合理的命名規(guī)那么2 據(jù)調(diào)查,沒(méi)有一種命名規(guī)那么可以讓一切的程序員贊同,程序設(shè)計(jì)教科書(shū)普通都不指定命名規(guī)那么。命名規(guī)那么對(duì)軟件產(chǎn)品而言并不是“成敗悠關(guān)的事,我們不要花太多精神試圖發(fā)明世界上最好的命名規(guī)那么,而該當(dāng)制定一種令大多數(shù)工程成員稱心的命名規(guī)那么,并在工程中貫徹實(shí)施。不論采取什么樣的命名規(guī)那么,至少要遵照以下3條規(guī)那么。1命名直觀明了: 標(biāo)識(shí)符該當(dāng)直觀且可以拼讀,可望文知義,不用進(jìn)展“解碼。標(biāo)識(shí)符最好采用英文單詞或其組合,便于記憶和閱讀。標(biāo)識(shí)符通常采用“大小寫(xiě)混排的方式,如AddView。切忌運(yùn)用漢語(yǔ)拼音來(lái)命名。程序中的英文單詞普通不會(huì)太
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 北師大版數(shù)學(xué)試卷
- 二零二五版奶茶店員工培訓(xùn)與職業(yè)發(fā)展規(guī)劃合同2篇
- 15 珍惜水資源 說(shuō)課稿-2024-2025學(xué)年科學(xué)三年級(jí)上冊(cè)蘇教版
- 基于賽博風(fēng)格的粵劇人物形象設(shè)計(jì)研究
- 群文閱讀視域下初中語(yǔ)文古詩(shī)詞閱讀教學(xué)研究
- 大理州小學(xué)數(shù)學(xué)試卷
- 德州市城市道路景觀評(píng)價(jià)與優(yōu)化模式分析
- 財(cái)產(chǎn)性人格權(quán)損害賠償問(wèn)題研究
- 二零二五年度倉(cāng)儲(chǔ)設(shè)施租賃與智能化物業(yè)管理合同3篇
- 5走進(jìn)科學(xué)家 說(shuō)課稿-2024-2025學(xué)年道德與法治三年級(jí)上冊(cè)統(tǒng)編版
- 湖北省石首楚源“源網(wǎng)荷儲(chǔ)”一體化項(xiàng)目可研報(bào)告
- 醫(yī)療健康大數(shù)據(jù)平臺(tái)使用手冊(cè)
- 碳排放管理員 (碳排放核查員) 理論知識(shí)考核要素細(xì)目表四級(jí)
- 撂荒地整改協(xié)議書(shū)范本
- 診所負(fù)責(zé)人免責(zé)合同范本
- 經(jīng)顱磁刺激增強(qiáng)定神狀態(tài)的研究
- 2024患者十大安全目標(biāo)
- 會(huì)陰切開(kāi)傷口裂開(kāi)的護(hù)理查房
- 實(shí)驗(yàn)報(bào)告·測(cè)定雞蛋殼中碳酸鈣的質(zhì)量分?jǐn)?shù)
- 部編版小學(xué)語(yǔ)文五年級(jí)下冊(cè)集體備課教材分析主講
- 電氣設(shè)備建筑安裝施工圖集
評(píng)論
0/150
提交評(píng)論