當(dāng)前位置:首頁(yè) > 嵌入式 > 嵌入式教程
[導(dǎo)讀]八位微控制器的代碼優(yōu)化技巧

本文將介紹一些優(yōu)化技術(shù),幫助設(shè)計(jì)人員節(jié)約多達(dá) 10% 的代碼空間,從而讓容量有限的程序存儲(chǔ)器支持更多新特性和補(bǔ)丁。

良好的操作方法

許多程序員在 32 位處理器上學(xué)習(xí)編寫(xiě)軟件,如 Intel 的 Pentium 處理器或某種 ARM 平臺(tái)。不過(guò),嵌入式領(lǐng)域的軟件編寫(xiě)需要不同的思路。在 32 位 CPU 上,存儲(chǔ)比特位的最佳方法通常是使用 32 位變量。對(duì) 8 位處理器而言,最好的辦法就是采用單字節(jié)。像增強(qiáng)型 8051s 等某些處理器可能提供特殊的 1 位變量。

嵌入式處理器通常會(huì)超出標(biāo)準(zhǔn)的哈佛架構(gòu)將存儲(chǔ)器分散到不同的存儲(chǔ)器空間中,有的相互重疊,有的又是相互分離。例如,8051 中常見(jiàn)的存儲(chǔ)器空間包括 CODE、XDATA、DATA、IDATA、BIT 以及寄存器等。當(dāng)要決定在何處存放變量時(shí),了解每個(gè)存儲(chǔ)器空間的優(yōu)缺點(diǎn)顯得非常重要,特別是在各個(gè)存儲(chǔ)空間的容量都有限時(shí)更是如此。例如,IDATA 空間可能只能運(yùn)行 256 個(gè)字節(jié),不過(guò)它為間接存取進(jìn)行了優(yōu)化。雖然 DATA 空間也只能運(yùn)行 256 個(gè)字節(jié),但它包括了 位可尋址空間和寄存器。盡管 CODE 和 XDATA 只能通過(guò)慢速間接存取機(jī)制進(jìn)行訪問(wèn),但它們的尋址空間卻高達(dá) 64K。

許多 8 位 CPU 的編譯器包含了很多優(yōu)化程序,不過(guò),這些優(yōu)化程序都有其局限性。如果可以,應(yīng)該盡可能簡(jiǎn)化表達(dá)。例如下面這段代碼:

X = a * CONSTANT1;

X *= CONSTANT2;

通常要比下述代碼多占空間:

X = a * CONSTANT1* CONSTANT2;

因?yàn)榫幾g器能將兩個(gè)常量合并為一個(gè)。

優(yōu)化——三思而后行

經(jīng)驗(yàn)豐富的木匠都知道做事應(yīng)該事先作好計(jì)劃,三思而后行。嵌入式固件工程師也應(yīng)該遵循這一原則。所有嵌入式編譯器都提供了一個(gè)可給出有用信息映射文件。如圖 1 所示,該映射文件提供了本文所用代碼示例的有用信息。圖中所示的庫(kù) (LIB_CODE) 使用的空間超過(guò)了 1K,而且啟動(dòng)代碼 (c51startup) 使用的代碼超過(guò)了 140 字節(jié)。

進(jìn)行優(yōu)化的另一原因是可以節(jié)約時(shí)間。在優(yōu)化之前,衡量程序的性能尤為重要。顯而易見(jiàn),如果源文件過(guò)大,肯定會(huì)占用大量的存儲(chǔ)器空間,但我們很難測(cè)定代碼的哪些關(guān)鍵部分在消耗寶貴的 MIPS。在此過(guò)程中,我們可將程序概要分析 (Profiling) 作為一個(gè)重要的工具來(lái)加以利用。

我們可利用未使用的單一輸出引腳來(lái)進(jìn)行程序概要分析,不過(guò)輸出引腳越多,分析也就越容易。我們可創(chuàng)建一個(gè)宏來(lái)設(shè)置程序概要分析輸出,如下所示,再將宏放在每個(gè)例程的起點(diǎn)和終點(diǎn)處。

 

了解支付情況

[!--empirenews.page--]

在上述的映射文件中,我們了解到庫(kù)占用了 1K 的寶貴存儲(chǔ)器空間。深入查看映射文件,通過(guò) Excel 進(jìn)行分析后得到了如圖 2 所示的結(jié)果。我們從圖中移出較小的庫(kù)函數(shù)部分。盡管這些函數(shù)名稱比較晦澀,不過(guò)我們可以對(duì)照庫(kù)參考資料逐一了解其含義。首先,ULDIV 是指無(wú)符號(hào)數(shù)的長(zhǎng)除法 (long division),而圖中第二個(gè)則是指長(zhǎng)乘法 (long multiplication)。

.map 文件的交叉參考表明我們很幸運(yùn):上述函數(shù)只用于一個(gè)文件中。.lst 文件顯示了長(zhǎng)除法函數(shù)的兩種使用情況以及長(zhǎng)乘法函數(shù)的一種使用情況 

glNandDevCapacity = CYAN_NAND_DEV_NUMPAGES_BLOCK * CYAN_NAND_UBLKS_PER_ZONE * (uint32_t)glNandNumZones;

在該特定案例中,我們知道 zone 的數(shù)量是一個(gè)二進(jìn)制數(shù),而另兩個(gè)值為常量。因此,我們可用重復(fù) 8 次的左移位 (left shift) 操作替代長(zhǎng)乘法:

{

char zoneCtr = glNandNumZones;

glNandDevCapacity = CYAN_NAND_DEV_NUMPAGES_BLOCK * CYAN_NAND_UBLKS_PER_ZONE;

while (zoneCtr)

{

glNandDevCapacity <<= 1;

zoneCtr >>= 1;

}

}

盡管這個(gè)例程相當(dāng)大,但它仍能減少庫(kù)的使用并減小代碼的整體大小。

掌握比編輯器更多的信息

成熟的 8 位編譯器包括代碼編寫(xiě)良好、經(jīng)過(guò)優(yōu)化的庫(kù)函數(shù)。不過(guò),這些函數(shù)須考慮到通過(guò)對(duì)數(shù)據(jù)的了解可自行處理的一些不常見(jiàn)情況。映射文件中顯示的最大庫(kù)函數(shù)就是這樣一個(gè)很好的例子。調(diào)用兩次 ULDIV 例程,以獲得輸入值除以常量后得到的除數(shù)和余數(shù): 

zn = (adj_lba / CYAN_NAND_UBLKS_PER_ZONE);

glNandRelativeBlkAddr = (adj_lba % CYAN_NAND_UBLKS_PER_ZONE);

由于我們?cè)陬A(yù)期值方面比編譯器了解的更多,因此我們可以讓編譯器不使用龐大的長(zhǎng)除法函數(shù),而采用較小的 16 位版本來(lái)替代。

{

xdata unsigned char lastNibble = adj_lba & 0xf;

adj_lba >>= 4;

zn = ((uint16_t)adj_lba / (uint8_t)CYAN_NAND_UBLKS_PER_ZONE/16));

glNandRelativeBlkAddr = ((uint16_t)adj_lba % (uint8_t) (CYAN_NAND_UBLKS_PER_ZONE/16));

glNandRelativeBlkAddr = (glNandRelativeBlkAddr << 4) + lastNibble;

}

激進(jìn)的的程序優(yōu)化者甚至可能實(shí)現(xiàn)他們自己的二進(jìn)制長(zhǎng)除法例程。[!--empirenews.page--]

全局變量更好用

將參數(shù)傳遞給函數(shù)是一個(gè)很好的代碼經(jīng)驗(yàn)。在 C 程序中,編譯器可絕對(duì)確保調(diào)用的子程序不會(huì)修改參數(shù)。編譯器可處理存儲(chǔ)器管理的問(wèn)題。不過(guò),這將占用難以承受的大量時(shí)間和空間。試考慮下面這段代碼:

Main()

{

Int effectiveGlobal;

Foo(effectiveGlobal)

}

由于變量在 main() 中已經(jīng)聲明,因此該變量與真正的全局變量之間的真正差別是命名空間 (namespace)。但是,每次調(diào)用 foo() 時(shí),編譯器都必須在新的位置存儲(chǔ) effectiveGlobal。聲明真正的全局變量有助于降低因調(diào)用而造成的代碼和數(shù)據(jù)開(kāi)銷。

向編譯器提供盡可能多的信息

8051 可提供 64K 的地址空間 XDATA、256 字節(jié)的堆棧與間接尋址空間 IDATA 以及 256 字節(jié)的直接尋址空間 DATA 等多個(gè)存儲(chǔ)器空間。在大多數(shù)情況下,代碼編寫(xiě)人員都知道指針指向了哪個(gè)存儲(chǔ)器空間。如果用戶指定了存儲(chǔ)器空間,編譯器就無(wú)需包含對(duì)例程中的所有三類存儲(chǔ)器進(jìn)行尋址的代碼,只需使用一個(gè)即可。由于指針無(wú)需包含數(shù)據(jù)空間信息,因此有助于節(jié)約數(shù)據(jù)空間。

在我的 8051 編譯器中,上述變量可通過(guò)包含 OPTR 字符串的庫(kù)例程進(jìn)行存取。在列表和庫(kù)文件中搜索對(duì)OPTR的引用可以發(fā)現(xiàn)長(zhǎng)變量被多次使用,而且由于在代碼中假定了指針的大小,其中某些長(zhǎng)變量還會(huì)導(dǎo)致一些問(wèn)題。

在變量聲明中使用 const 關(guān)鍵詞可以實(shí)現(xiàn)兩方面的優(yōu)化:第一,編譯器不必再存儲(chǔ)變量的初始值;第二,編譯器能在編譯時(shí)間而非執(zhí)行時(shí)間執(zhí)行一些數(shù) 學(xué) 運(yùn) 算。查看示例程序的編譯輸出,以確定對(duì) const與 #define 的處理是否真的一樣。以下是我對(duì)代碼的測(cè)試:

 

經(jīng)過(guò)測(cè)試,得到以下輸出,表明它并不清楚 const 變量的值。

匯編語(yǔ)言

不少嵌入式固件工程師信誓旦旦的表示他們始終能比編譯器做得更好,不僅如此,他們還認(rèn)為應(yīng)該使用匯編語(yǔ)言重新編寫(xiě)所有代碼。然而事實(shí)上,現(xiàn)代編譯器提供的許多特性已經(jīng)能趕上人腦的水平了。

變量共享:一些 8 位處理器尚無(wú)有效的機(jī)制來(lái)存取堆棧上的變量。一般的解決方案是創(chuàng)建調(diào)用樹(shù),并在相互不進(jìn)行調(diào)用的函數(shù)間共享變量。在匯編程序中要想保持這種結(jié)構(gòu)相當(dāng)困難,且容易出錯(cuò)。

可靠性:任何從事專業(yè)軟件或固件開(kāi)發(fā)工作的人員都能讀懂 C 語(yǔ)言程序。如果您需要將代碼交給其它開(kāi)發(fā)人員處理,他們無(wú)需掌握那些為發(fā)揮匯編語(yǔ)言的最大效率而需要的所有技巧便可立即開(kāi)始修改代碼。

可移植性:C 語(yǔ)言最初的開(kāi)發(fā)目的之一就是要提供一種非常抽象,以便可以在多種處理器上應(yīng)用的語(yǔ)言。這一目標(biāo)至今仍然非常重要。

代碼共享:許多 8 位編譯器都能在鏈接時(shí)間之后進(jìn)行優(yōu)化,這使得編譯器不僅能執(zhí)行許多人工能完成的優(yōu)化,而且還能完成一些人工所不能完成的優(yōu)化。例如,現(xiàn)在許多編譯器都能搜索不同函數(shù) 中 共 有的代碼字符串,并將其合并為一個(gè)新的函數(shù)。而人類是不可能記住每個(gè)編譯周期中執(zhí)行此函數(shù)所需要的全部細(xì)節(jié)的。

匯編語(yǔ)言現(xiàn)在仍占有一席之地。不過(guò),在使用匯編語(yǔ)言之前應(yīng)首先考慮上述所有因素。

結(jié)論

在撰寫(xiě)本文的過(guò)程中,我將成熟程序的大小從 0x6000 多字節(jié)縮減到了 0x5f2b 字節(jié),節(jié)約了 200 多字節(jié)。該程序過(guò)去曾是多次試圖優(yōu)化程序大小的目標(biāo)。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉