<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 硬件堆棧和軟件堆棧在AVR中的理解

          硬件堆棧和軟件堆棧在AVR中的理解

          作者: 時(shí)間:2016-11-23 來源:網(wǎng)絡(luò) 收藏
          首先是從理論上的東西。。網(wǎng)上轉(zhuǎn)載來的,后面是看AVR代碼時(shí)得出的一些東西。

          硬件堆棧:或許也可以稱作系統(tǒng)堆棧,是位于片內(nèi)RAM區(qū)。有人說,只要能使用PUSH,POP指令的單片機(jī),都可以說含有硬件堆棧。這樣的說法我個(gè)人覺得不是很全面。通過指令進(jìn)行壓棧和出棧操作只是系統(tǒng)堆棧中的一種操做。系統(tǒng)堆棧還可以被隱含調(diào)用。例如,當(dāng)調(diào)用子程序時(shí),系統(tǒng)會(huì)主動(dòng)把返回地址壓入堆棧,并不需要用戶通過指令操作。通常,棧底設(shè)在內(nèi)存的高端,也就是把內(nèi)存的最高一段空間劃作棧區(qū)。這些都是向下生長(zhǎng)棧。棧指針可能是專用的寄存器,也可能借用一通用寄存器。也有單片機(jī)是在數(shù)據(jù)區(qū)里劃一塊作棧區(qū),可能是向上生長(zhǎng),也可能是向下生長(zhǎng)。

          本文引用地址:http://www.ex-cimer.com/article/201611/320152.htm

          硬件堆棧:是通過寄存器SPH,SPL做為索引指針的地址,是調(diào)用了CALL,RCALL等函數(shù)調(diào)用指令后硬件自動(dòng)填充的堆棧!

          軟件堆棧:是編譯器為了處理一些參數(shù)傳遞而做的堆棧,會(huì)由編譯器自動(dòng)產(chǎn)生和處理,可以通過相應(yīng)的編譯選項(xiàng)對(duì)其進(jìn)行編輯。

          簡(jiǎn)單一點(diǎn)說,硬件堆棧主要做為地址堆棧用,而軟件堆棧主要會(huì)被分配成數(shù)據(jù)堆棧!

          ---摘自《AVR單片機(jī)C語(yǔ)言開發(fā)入門指導(dǎo)》-P169---
          ICCAVR使用兩個(gè)堆棧:一個(gè)用于子程序調(diào)用和中斷操作的硬件堆棧,一個(gè)用于傳遞參數(shù)、臨時(shí)變量和局部變量的軟件堆棧??梢允褂枚褩z測(cè)函數(shù)檢測(cè)兩個(gè)堆棧是否溢出。

          如果沒有硬堆棧,你可以選定一個(gè)寄存器作堆棧指針,通過軟件實(shí)現(xiàn)堆棧操作。移植μC/OS-II也不一定要硬堆棧。ARM 就很難說它的堆棧是軟的還是硬的。32位的ARM指令中沒有PUSH、POP指令。ARM習(xí)慣上用R13作堆棧指針(SP),但用別的寄存器作堆棧指針也未常不可。ARM習(xí)慣上用LDM/STM(多寄存器加載/存儲(chǔ)指令)來操作堆棧,壓多少,按什么順序都能選擇。應(yīng)該說ARM是軟硬結(jié)合的堆棧。

          C代碼(AVR-GCC編譯,優(yōu)化等級(jí)-00):

          #include <avr/io.h>

          int add(int a,int b)
          {
          int c;
          c=a+b;
          return c;
          }

          int main(void)
          {
          int a=2,b=3,c=0;

          c=add(a,b);
          //c=sub(a,b);
          }
          匯編代碼:

          (省略一些boot代碼)

          。。。。。。。

          00000054 <__ctors_end>:
          54: 11 24 eor r1, r1
          56: 1f be out 0x3f, r1 ; 63
          58: cf e5 ldi r28, 0x5F ; 95 //此處Y指針和SP都指到了SRAM最高端
          5a: d4 e0 ldi r29, 0x04 ; 4
          5c: de bf out 0x3e, r29 ; 62
          5e: cd bf out 0x3d, r28 ; 61

          。。。

          0000008e :
          #include

          int add(int a,int b)
          {
          8e: cf 93 push r28
          90: df 93 push r29 //保存了Y指針,此時(shí)SP已經(jīng)-2,這里再減2
          92: cd b7 in r28, 0x3d ; 61 //重新定位Y指針跟SP一樣。
          94: de b7 in r29, 0x3e ; 62
          96: 26 97 sbiw r28, 0x06 ; 6 //減掉6,即向下開了6字節(jié)的區(qū)域,存放3變量
          98: 0f b6 in r0, 0x3f ; 63
          9a: f8 94 cli
          9c: de bf out 0x3e, r29 ; 62
          9e: 0f be out 0x3f, r0 ; 63
          a0: cd bf out 0x3d, r28 ; 61
          a2: 9a 83 std Y+2, r25 ; 0x02
          a4: 89 83 std Y+1, r24 ; 0x01
          a6: 7c 83 std Y+4, r23 ; 0x04
          a8: 6b 83 std Y+3, r22 ; 0x03
          int c;
          c=a+b;
          aa: 29 81 ldd r18, Y+1 ; 0x01
          ac: 3a 81 ldd r19, Y+2 ; 0x02
          ae: 8b 81 ldd r24, Y+3 ; 0x03
          b0: 9c 81 ldd r25, Y+4 ; 0x04
          b2: 82 0f add r24, r18
          b4: 93 1f adc r25, r19
          b6: 9e 83 std Y+6, r25 ; 0x06
          b8: 8d 83 std Y+5, r24 ; 0x05
          return c;
          ba: 8d 81 ldd r24, Y+5 ; 0x05
          bc: 9e 81 ldd r25, Y+6 ; 0x06
          be: 26 96 adiw r28, 0x06 ; 6 //加了6個(gè)字節(jié)空間,Y指針恢復(fù)到減6之前
          c0: 0f b6 in r0, 0x3f ; 63
          c2: f8 94 cli
          c4: de bf out 0x3e, r29 ; 62
          c6: 0f be out 0x3f, r0 ; 63
          c8: cd bf out 0x3d, r28 ; 61
          ca: df 91 pop r29
          cc: cf 91 pop r28
          ce: 08 95 ret //彈出堆棧中2個(gè)字節(jié)

          000000d0

          :
          }

          int main(void)
          {
          d0: c9 e5 ldi r28, 0x59 ; 89 //這4句給SP和Y指針重新賦值了,很明顯的在SP的
          d2: d4 e0 ldi r29, 0x04 ; 4 //上面還有6個(gè)字節(jié)(SRAM最大到045E),這6個(gè)字節(jié)
          d4: de bf out 0x3e, r29 ; 62 //被存放了a,b,c三個(gè)變量(可以與上面理論對(duì)應(yīng))
          d6: cd bf out 0x3d, r28 ; 61 //通過Y指針來保存了這三個(gè)變量到這個(gè)區(qū)域
          int a=2,b=3,c=0;
          d8: 82 e0 ldi r24, 0x02 ; 2
          da: 90 e0 ldi r25, 0x00 ; 0
          dc: 9a 83 std Y+2, r25 ; 0x02
          de: 89 83 std Y+1, r24 ; 0x01
          e0: 83 e0 ldi r24, 0x03 ; 3
          e2: 90 e0 ldi r25, 0x00 ; 0
          e4: 9c 83 std Y+4, r25 ; 0x04
          e6: 8b 83 std Y+3, r24 ; 0x03
          e8: 1e 82 std Y+6, r1 ; 0x06
          ea: 1d 82 std Y+5, r1 ; 0x05

          c=add(a,b);
          ec: 6b 81 ldd r22, Y+3 ; 0x03
          ee: 7c 81 ldd r23, Y+4 ; 0x04
          f0: 89 81 ldd r24, Y+1 ; 0x01
          f2: 9a 81 ldd r25, Y+2 ; 0x02
          f4: 0e 94 47 00 call 0x8e //使用call時(shí)自動(dòng)將PC+2的地址壓到堆棧
          f8: 9e 83 std Y+6, r25 ; 0x06
          fa: 8d 83 std Y+5, r24 ; 0x05
          //c=sub(a,b);
          }
          fc: 80 e0 ldi r24, 0x00 ; 0
          fe: 90 e0 ldi r25, 0x00 ; 0
          100: 0c 94 82 00 jmp 0x104 <_exit>

          00000104 <_exit>:
          104: ff cf rjmp .-2 ; 0x104 <_exit>

          r28和r29一起組成SP指針,Y指針可以作為間接尋址,很明顯的剛開始的時(shí)候Y指針和SP都在045F這里,后來在高處開了6個(gè)字節(jié)的空間來存放臨時(shí)變量,所以Y指針成了這個(gè)軟件堆棧的棧頂,在這個(gè)過程中都是使用Y和SP的配合來實(shí)現(xiàn)變量和數(shù)據(jù)的改變,以及恢復(fù),硬件堆棧和軟件堆棧在這里已經(jīng)不怎么區(qū)分了。。。不清楚流程可以畫個(gè)圖來加深理解,好了,看了那么久,總算有點(diǎn)感覺了。。



          關(guān)鍵詞: 硬件堆棧軟件堆棧AV

          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();