UCOS學習筆記——堆棧

堆棧

Cortex-M3堆棧操作

Cortex-M3使用的是“向下生長的滿棧”模型。堆棧指針SP指向最後一個被壓入堆棧的32位數值。在下一-次壓棧時,SP先自減4,再存入新的數值,如圖2.3.1所示。在這裏插入圖片描述
POP操作剛好相反:先從SP指針處讀出,上一次被壓入的值,再把SP指針自增4。如圖2.3.2所示。
在這裏插入圖片描述
在進入ISR時,CM3會自動把一些寄存器壓棧,這裏使用的是進入ISR之前使用的SP指針(MSP或者是PSP)。離開ISR後,只要ISR沒有更改過CONTROL[1],就依然使用先前的SP指針來執行出棧操作。

雙堆棧機制

我們已經知道了CM3的堆棧是分爲兩個:主堆棧和進程堆棧, CONTROL[1]決定如何選擇。當CONTROL[1]=0時,只使用MSP, 此時用戶程序和異常handler 共享同一個堆棧。這也是復位後的缺省使用方式,如圖2.3.3所示。
在這裏插入圖片描述
當CONTROL[1]=1時,線程模式將不再使用PSP,而改用MSP(handler模式永遠使用MSP)。此時,進入異常時的自動壓棧使用的是進程堆棧,進入異常handler後才自動改爲MSP,退出異常時切換同psp,並日從講程堆棧十彈出數據,如圖2.3.4所示:
在這裏插入圖片描述
在特權級下,可以指定具體的堆棧指針,而不受當前使用堆棧的限制,示例代碼如下:

MRS  RO,MSP ; 讀取主堆棧指針到RO
MSR MSP,RO ; 寫入RO的值到主堆棧中
MRS RO,PSP ;讀取進程堆棧指針到RO
MSR RO ;寫入RO的值到進程堆棧中

通過讀取PSP的值,OS就能夠獲取用戶應用程序使用的堆棧,進一一步地就知道了在發生異常時,被壓入寄存器的內容,而且還可以把其它寄存器進一步壓棧的書寫形式)。OS還可以修改PSP,用於實現多任務中的任務上下文切換。

Stack frames

在進入異常服務程序的時候會將一些數據壓入堆棧中,這些數據所佔用的數據塊被稱爲Stack frames,由於M3沒有FPU所以其Stack frames總是8個字(一個字32bit)如圖2.3.5所示。
在這裏插入圖片描述
在符合AAPCS的應用程序中,對於響應異常時的堆棧操作是要進行雙字對齊的在M3處理器中如果堆棧指針SP未雙字對齊的話,那麼就會在堆棧中自動的增加一個填充位使其雙字對齊。雙字對齊是一一個可選項,欲使能此特性,需要把NVIC配置控制寄存器的STKALIGN置位,如下面彙編代碼所演示:

LDR RO,=0xE0O0ED1 4; R0=NVIC CCR的基址
LDR R1,[R0]
ORR.W R1,R1, #0x200;設置STKALIGN位
STR R1,[R0];更新NVIC CCR

如果用C語言:

#define NVIC_ CCR ((volatile unsigned long *)(0xE000ED14))
*NVIC_ CCR= *NVIC_ CCR | 0x200; //設置 STKALIGN位

xPSP寄存器的bit9 被用來指示SP是否需要對齊,bit9 如果爲1的話就需要雙字對齊,如果爲0的話就不需要雙字對齊,未使用FPU時採用雙字對齊的Stack frame如圖2.3.6所示。
我們可以看到這裏只是將xPSR、PC、LR、R12、R0-R3這8個寄存器自動入棧,其餘的8個寄存器R4-R11就需要我們自己手動入棧了,入棧順序不能亂了。
Alt
我們可以看出還有R4-R11這些寄存器沒有做處理,那麼我們就要手動對這些寄存器做入棧和出棧處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章