新聞中心

EEPW首頁 > 嵌入式系統(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ū)。這些都是向下生長棧。棧指針可能是專用的寄存器,也可能借用一通用寄存器。也有單片機(jī)是在數(shù)據(jù)區(qū)里劃一塊作棧區(qū),可能是向上生長,也可能是向下生長。

本文引用地址:http://butianyuan.cn/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)行編輯。

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

---摘自《AVR單片機(jī)C語言開發(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)閉