新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 硬件堆棧和軟件堆棧在AVR中的理解

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

        作者: 時間:2016-11-23 來源:網絡 收藏
        首先是從理論上的東西。。網上轉載來的,后面是看AVR代碼時得出的一些東西。

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

        本文引用地址:http://www.104case.com/article/201611/320152.htm

        硬件堆棧:是通過寄存器SPH,SPL做為索引指針的地址,是調用了CALL,RCALL等函數調用指令后硬件自動填充的堆棧!

        軟件堆棧:是編譯器為了處理一些參數傳遞而做的堆棧,會由編譯器自動產生和處理,可以通過相應的編譯選項對其進行編輯。

        簡單一點說,硬件堆棧主要做為地址堆棧用,而軟件堆棧主要會被分配成數據堆棧!

        ---摘自《AVR單片機C語言開發入門指導》-P169---
        ICCAVR使用兩個堆棧:一個用于子程序調用和中斷操作的硬件堆棧,一個用于傳遞參數、臨時變量和局部變量的軟件堆棧。可以使用堆棧檢測函數檢測兩個堆棧是否溢出。

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

        C代碼(AVR-GCC編譯,優化等級-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指針,此時SP已經-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字節的區域,存放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個字節空間,Y指針恢復到減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個字節

        000000d0

        :
        }

        int main(void)
        {
        d0: c9 e5 ldi r28, 0x59 ; 89 //這4句給SP和Y指針重新賦值了,很明顯的在SP的
        d2: d4 e0 ldi r29, 0x04 ; 4 //上面還有6個字節(SRAM最大到045E),這6個字節
        d4: de bf out 0x3e, r29 ; 62 //被存放了a,b,c三個變量(可以與上面理論對應)
        d6: cd bf out 0x3d, r28 ; 61 //通過Y指針來保存了這三個變量到這個區域
        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時自動將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指針可以作為間接尋址,很明顯的剛開始的時候Y指針和SP都在045F這里,后來在高處開了6個字節的空間來存放臨時變量,所以Y指針成了這個軟件堆棧的棧頂,在這個過程中都是使用Y和SP的配合來實現變量和數據的改變,以及恢復,硬件堆棧和軟件堆棧在這里已經不怎么區分了。。。不清楚流程可以畫個圖來加深理解,好了,看了那么久,總算有點感覺了。。



        評論


        技術專區

        關閉
        主站蜘蛛池模板: 马龙县| 南丰县| 宜宾市| 嘉义市| 罗江县| 故城县| 宁海县| 扶风县| 玉门市| 舟山市| 福安市| 大悟县| 花垣县| 新乡县| 红原县| 武穴市| 湘乡市| 无为县| 定襄县| 北京市| 宁波市| 英超| 天峻县| 遂平县| 广丰县| 托克逊县| 伊通| 云和县| 萨嘎县| 永新县| 聂拉木县| 凌海市| 玉树县| 巴彦淖尔市| 寿宁县| 鄄城县| 庆城县| 陇南市| 镇康县| 麟游县| 华宁县|