|
Keil Software — C51 Compiler User’s Guide 341 C附錄C. 編寫優(yōu)化的代碼 本文列舉了一些針對(duì)8051單片機(jī)及其C51編譯器的可以提高軟件效能的方法(如:生成更小的 代碼,獲得更快的運(yùn)行速度等)。在大多數(shù)情況下,這些方法都可以起到很好的作用。存儲(chǔ)器模式 /Memory Model 減少代碼尺寸和提高運(yùn)行速度的最有效的方式是將編譯器的存儲(chǔ)器模式設(shè)定為小模 式。該模式下,編譯器可以生成最小的代碼。 使用小模式的關(guān)鍵字是 SMALL。 在小模式下,所有的變量(除非是顯式地進(jìn)行了存儲(chǔ)位置申 明),都存放在8051芯片的內(nèi)部存儲(chǔ)器中。而8051對(duì)內(nèi)部存儲(chǔ)器的訪問速度是最快的(典型情況下 為1或2個(gè)時(shí)鐘周期),并且產(chǎn)生的訪問這些變量的代碼也是最少的,指令是最短的。請(qǐng)參看下面的 循環(huán)代碼: for (i = 0; i < 100; i++) { do_nothing (); } 在不同的編譯模式下(小模式和巨模式),將生成不同的目標(biāo)代碼。 stmt level source 1 #pragma small 2 3 void do_nothing (void); 4 5 6 void func (void) 7 { 8 1 unsigned char i; 9 1 10 1 for (i = 0; i < 100; i++) 11 1 { 12 2 do_nothing (); 13 2 } 14 1 } ; FUNCTION func (BEGIN) ; SOURCE LINE #10 0000 E4 CLR A 0001 F500 R MOV i,A 0003 ?C0001: 0003 E500 R MOV A,i 0005 C3 CLR C 0006 9464 SUBB A,#064H 0008 5007 JNC ?C0004 ; SOURCE LINE #12 000A 120000 E LCALL do_nothing ; SOURCE LINE #13 000D 0500 R INC i 000F 80F2 SJMP ?C0001 ; SOURCE LINE #14 0011 ?C0004: 0011 22 RET ; FUNCTION func (END) 在小模式下,變量I被放置在內(nèi)部數(shù)據(jù)存儲(chǔ)器中。訪問變量I的指令,如:
MOV A,i 和 INC I 只需要2字節(jié)。每條指令運(yùn)行只需要1個(gè)時(shí)鐘周期。整個(gè)代碼長(zhǎng)度只有17字節(jié)。 下面是同樣的代碼在巨模式下的編譯結(jié)果: ; FUNCTION func (BEGIN) ; SOURCE LINE #10 0000 E4 CLR A 0001 900000 R MOV DPTR,#i 0004 F0 MOVX @DPTR,A 0005 ?C0001: 0005 900000 R MOV DPTR,#i 0008 E0 MOVX A,@DPTR 0009 C3 CLR C 000A 9464 SUBB A,#064H 000C 500B JNC ?C0004 ; SOURCE LINE #12 000E 120000 E LCALL do_nothing ; SOURCE LINE #13 0011 900000 R MOV DPTR,#i 0014 E0 MOVX A,@DPTR 0015 04 INC A 0016 F0 MOVX @DPTR,A 0017 80EC SJMP ?C0001 ; SOURCE LINE #14 0019 ?C0004: 0019 22 RET ; FUNCTION func (END) 在巨模式下,變量i被放置在外部數(shù)據(jù)存儲(chǔ)器中。為訪問變量I,編譯器必須首先加載數(shù)據(jù)指針 指向正確的地址(參見偏移0001h到0004h)。這2條指令就需要4個(gè)時(shí)鐘周期。使變量i 增量的操 作需要6 字節(jié)的存儲(chǔ)空間及7個(gè)時(shí)鐘周期?偟拇a大小達(dá)到25 字節(jié)。變量定位原則是將需要頻繁 訪問的數(shù)據(jù)對(duì)象放置在8051的內(nèi)部數(shù)據(jù)存儲(chǔ)器中。硬件訪問內(nèi)部數(shù)據(jù)存儲(chǔ)器要比訪問外部數(shù)據(jù)存儲(chǔ) 器有效的多。內(nèi)部數(shù)據(jù)存儲(chǔ)器由寄存器組、位變量區(qū)域、堆棧和其它用戶自定義變量共享?梢允 用關(guān)鍵字data來指定。 由于受存儲(chǔ)容量的限制(內(nèi)部數(shù)據(jù)存儲(chǔ)器為128字節(jié),最多256字節(jié))。 在整個(gè)軟件中使用的 所有該類型變量都將占據(jù)這個(gè)區(qū)域,并且總的尺寸不能超過相應(yīng)芯片的物理限制。在某些情況下, 就不得不將一些數(shù)據(jù)對(duì)象放置到外部數(shù)據(jù)存儲(chǔ)器中。有2種辦法可以進(jìn)行該操作。
一是:改變存儲(chǔ)模式,讓編譯器來自動(dòng)完成該操作。這是最簡(jiǎn)單的方法,但需要產(chǎn)生更多的代碼并 降低運(yùn)行速度。 二是:手工將需要放置在外部數(shù)據(jù)存儲(chǔ)器中的數(shù)據(jù)對(duì)象使用關(guān)鍵字xdata進(jìn)行申明。這種方式不會(huì) 產(chǎn)生額外的代碼。
變量尺寸 8051系列是8位的CPU。使用8位的數(shù)據(jù)類型將比使用其它類型的數(shù)據(jù)要有效的多(如:char 和unsigned char就比使用int或long類型有效)。所以,在任何情況下應(yīng)該首先使用最短的數(shù) 據(jù)類型。 C51編譯器直接支持所有的字節(jié)操作指令。除非特別指明,否則字節(jié)類型不會(huì)被轉(zhuǎn)換成整數(shù)類 型來操作。參見INTPROMOTE關(guān)鍵字。 例如:兩個(gè)字節(jié)類型的數(shù)據(jù)乘操作,將直接使用8051的單指令MUL AB。而如果使用其它類型的數(shù) 據(jù),則會(huì)導(dǎo)致對(duì)編譯器庫函數(shù)的調(diào)用。
無符號(hào)類型Unsigned 8051系列的處理器并不直接支持浮點(diǎn)數(shù)的運(yùn)算。因此,編譯器必須對(duì)浮點(diǎn)數(shù)運(yùn)算產(chǎn)生額外的 代碼。因此,任何時(shí)候都必須首先考慮使用無符號(hào)數(shù)據(jù)類型。
局部變量 在遇到循環(huán)或其它臨時(shí)計(jì)算操作時(shí),應(yīng)盡可能地使用局部變量。作為編譯器優(yōu)化處理過程的一 部分,臨時(shí)變量將被編譯器盡可能地放置在寄存器中。而寄存器訪問是最快速的。在具體程序中, 可以申明為unsigned char和unsigned int變量類型。
其它原因 通常最影響程序代碼質(zhì)量的原因并不是編譯器生成代碼的效率,而是軟件本身為解決其目標(biāo)問 題而使用的算法類型。采用更有效的算法,通常比其它方式來達(dá)到減少代碼尺寸和提高運(yùn)行速度的 目的更為有效。例如:heap排序算法總是比bubble算法更有效。
參考鏈接:http://www.picavr.com/news/2009-11/1719.htm |