久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

專注電子技術學習與研究
當前位置:單片機教程網 >> MCU設計實例 >> 瀏覽文章

keilc51中如何看堆棧的分配情況

作者:佚名   來源:本站原創   點擊數:  更新時間:2012年10月11日   【字體:

  Keil C是非常優秀的C51編譯器,可能是最好的C51編譯器,提供各種優化模式,對變量的優化和地址安排做得非常好。這是用C語言寫代碼的好處之一,如果用匯編寫,得費一大番功夫給各個變量安排內存物理地址,還得時刻記住哪些地址的內存單元是已經分配了,新增加的變量就不能占用那些已經分配了的單元,以免產生內存交疊沖突和溢出。我一直非常信賴Keil C51的編譯結果,在我的印象里,它對內存的分配是完美的,只要代碼用它編譯時沒有報告任何warning和error,代碼運行時不可能內存沖突或溢出的現象。

但,今天發生的事情證明我錯了。

  手頭上有個產品的代碼,代碼量很大。程序跑起來的效果不大好,因此打算把代碼優化一下。代碼量越大,通常可優化的地方也越多。對8051來說,訪問芯片內部的data區(0~7FH)內存速度是最快的,直接訪問,一條指令就能讀寫,而idata區(80H~FFH)雖然還是內存區,但由于地址分配上跟特殊寄存器SFR重合,只能間接地址訪問,兩條指令才能讀寫,速度稍慢點,而外存xdata區(0~7FFFH)必須使用DPTR指針才能訪問,速度是最慢的。很明顯,優化的原則就是盡量把頻繁讀寫的變量優先安排在data區,然后是idata區,最后才是xdata區。

   
 


 


  8051在物理上有4個存儲器空間

   片內ROM和片外ROM。片內RAM和片外RAM。

   片外程序存儲器ROM地址空間為64kB,片外數據存儲器RAM也有64kB的尋址區,在地址上是與ROM重迭的。

   8051單片機通過不同信號來選通ROM或RAM。當從外部ROM中取指令時,采用選通信號PSEN,而從外部RAM中讀寫數據時

   則采用讀RD和寫WR信號或來選通,因此不會因地址重迭而發生混亂。

片內數據存儲器RAM

     片內RAM有256個字節,其中00H~7FH地址空間是直接尋址區,該區域內從00H~1FH地址為工作寄存器區,

安排了4組工作寄存器,每組都為R0~R7,在某一時刻,CPU只能使用其中任意一組工作寄存器,由程序狀態字

PSW中RS0和RS1的狀態決定。

片內RAM的20H~2FH地址單元為位尋址區,其中每個字節的每一位都規定了位地址。每個地址單元除了可進行字

節操作之外,還可進行位操作。

片內RAM的80H~FFH地址空間是特殊功能寄存器SFR區,對于51子系列在該區域內安排了21個特殊功能寄存器,對于52子系列

則在該區域內安排了26個特殊功能寄器,同時擴展了128個字節的間接尋址片內RAM,地址也為80~FFH,與SFR區地址重迭.

 

當我做完變量手工優化工作后,把編譯模式設為SMALL,這樣C51編譯器會自動把那些我沒手工指定存放區的變量優先安排進data區,如果超出有效地址范圍,它會報錯,因此我大可以放心。按下rebuild all按鈕后,編譯器提示:

Program Size: data=236.2 xdata=19321 code=43372

"ipphone_main" - 0 Error(s), 0Warning(s).

編譯器提示的data區包括了idata在內,按以往的經驗來看,data區有256個byte,程序才使用了236.2個,還剩下19個,沒有溢出,而xdata有32k,現在才使用了19k,遠沒有溢出,編譯結果一切很正常。

把代碼燒錄進芯片跑起來后,結果出人意料,從現象來看,上電約1秒后就自動重啟,重啟后過1秒又重啟,非常有規律的重啟。

我沒有懷疑是編譯器的原因,當時第一念頭是懷疑是看門狗,代碼里上電后就打開了看門狗,可能某些子程序代碼執行時間過長,看門狗復位了,于是在有懷疑的地方插入了喂狗代碼,重新編譯后再測試,依然自動重啟。于是干脆就把看門狗的代碼注釋了,不使用看門狗,以為這回沒問題了吧,結果出人意料,還是重啟。

我仔細想了一下,能造成8051的重啟的原因不多,一是看門狗引起的重啟,這點可以排除;二是某些8051支持重啟指令,我手頭上用的這款雖然支持,但我沒用過那指令,這點也可以排除;三是8051被強干擾,把取指寄存器PC的內容改變了,改成0,于是就重啟了,這點也可以排除,因為如果現場有強干擾,沒優化前也會重啟才對。

由于沒想出來是什么原因,于是開始折騰,把優化的變量一個個恢復成未恢復優化的狀態,每恢復一步就重新測試一次。終于在恢復一個16字節的數組時發現程序正常了,仔細看了一下,那數組定義在xdata區的時候程序就完全正常,而定義在idata區的時候程序就復位了,雖然奇怪的是,定義在idata區時,編譯器并沒有報告內存溢出。跟蹤匯編指令也沒發現異常,無論定義在idata還是xdata,編譯器為該數組分配的地址證明確實都是有效地址,確實沒有溢出,編譯器的安排還是正確。

雖然還沒找到根源,但問題既然是出現在內存上,我于是決定查看當那個數組指定為idata類型時的內存分配。Keil C51在編譯時會輸出一個M51文件,該文件包含了大量的內存分配信息,非常詳細,包括哪個變量被編譯器分配到哪個內存地址,占用多少個字節,哪些變量是局部變量,可以重復利用……這個M51文件里都有詳細的列表。

從列表里的變量分配地址一路看下來,都沒錯,邊看還邊驚嘆編譯器對變量的分配安排非常精確,但看到最后一個堆棧指針的安排時,終于發現問題所在了,它是這樣安排的:


  TYPE        BASE       LENGTH      RELOCATION      SEGMENT NAME
  ----------------------------------------------------------------------------------------------
  IDATA       0080H     0034H          UNIT                      _IDATA_GROUP_
  IDATA       00B4H     0022H          UNIT                      ?ID?IPPHONE_MAIN
  IDATA       00D6H     001FH          UNIT                      ?ID?DNS_NICRCV?IPPHONE_DNS
  IDATA       00F5H      0004H          UNIT                      ?ID?DISP
  IDATA       00F9H      0001H          UNIT                      ?STACK

這上面標有STACK的段就是堆棧分配,上面的數據表明,SP堆棧指針安排在F9H這個地址,堆棧空間是1個字節!表面看沒有溢出,但我的程序里使用了中斷服務,進入中斷服務時,至少需要8個字節的堆棧空間(保存R0~R7寄存器)來進行保護現場,8051使用的是遞增壓棧的設計,堆棧指針往往被安排在內存空間的后面可用部分,每壓棧一個字節,SP指針往上加1,進中斷服務時,至少壓棧8個字節,F9H+8,超出了FFH,堆棧指針不能超過FFH,也就是說堆棧溢出了!原來這就是導致程序不斷重啟的原因,不是變量內存溢出,而是堆棧溢出!

而當我把那個數組指定為xdata類型后,由于該數組不再占用idata區,于是IDATA一下子多了16個字節的可用空間,重新編譯后的M51這樣安排:

  IDATA      0080H      0024H           UNIT                      _IDATA_GROUP_
  IDATA      00A4H      0022H           UNIT                      ?ID?IPPHONE_MAIN
  IDATA      00C6H      001FH           UNIT                      ?ID?DNS_NICRCV?IPPHONE_DNS
  IDATA      00E5H      0004H           UNIT                      ?ID?DISP
  IDATA      00E9H      0001H           UNIT                      ?STACK

從這組數據來看,SP指針安排到在E9H這個地址,堆棧空間有FFH-E9H+1=23個字節,對于程序來說已經夠用,因此程序運行正常。

多次調整變量類型的編譯結果表明,C51對于堆?臻g需求大小不作計算,任何代碼都只是按堆?臻g只有1個字節需求來分配(在我眼里看來這明顯是胡來,稍復雜點的子程序調用都不可能只要1個字節就能完成現場保護),由于堆棧只能分配在data區和idata區,因此當一個程序為了優化而data區占用太多時,雖然編譯器能編譯成功,但往往SP堆棧指針被分配在data區的最后面,很容易造成堆棧空間不夠而溢出。為保險起見,最好保證編譯后的SP值安排在F0H之前,那樣至少有16個字節的堆?臻g,才能最大限度保證程序不會跑飛。

看樣子不能太相信Keil C51,以后編譯完后,還得查看一下M51才能確保程序的質量,不知道這個算不算Keil C51的bug。

 

關閉窗口

相關文章

主站蜘蛛池模板: 免费网站国产 | 亚洲二区视频 | 中文字幕二区 | 亚洲精品一区二区三区蜜桃久 | 亚洲福利在线观看 | 在线免费观看日本视频 | 亚洲女人的天堂 | 免费午夜剧场 | 亚洲天堂av在线 | 国产成人艳妇aa视频在线 | 三区在线观看 | 综合色播| 欧美精品久久久久 | 高清久久久 | 中文字幕不卡在线88 | 亚洲一区二区视频 | 日本一区视频在线观看 | 久久久青草婷婷精品综合日韩 | 国产精品免费一区二区三区四区 | 欧美精品在线视频 | 成人免费视频网站在线看 | 亚洲欧美另类在线观看 | 亚洲一区二区精品视频 | 婷婷国产一区二区三区 | 国产一区二| 三级特黄特色视频 | 国产精品视频一二三区 | 国产探花 | 午夜精品一区二区三区在线视频 | 日韩欧美中文字幕在线观看 | 日日日色 | 久久精品国产a三级三级三级 | 亚洲一区二区三区四区五区中文 | 在线国产小视频 | 亚洲一区自拍 | 国产精品久久久久久一区二区三区 | 日本三级电影免费 | 免费av毛片 | 亚洲最大的成人网 | 一二三区在线 | 国产激情91久久精品导航 |