日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

任务切换的基础:模拟任务切换时寄存器的保存与恢复

發布時間:2025/4/5 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 任务切换的基础:模拟任务切换时寄存器的保存与恢复 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 1 任務切換的基礎:模擬任務切換時寄存器的保存與恢復

1 任務切換的基礎:模擬任務切換時寄存器的保存與恢復

需求說明:使用PendSVC觸發異常,在異常處理函數中,保存R4-R11寄存器到緩沖區,再恢復R4-R11寄存器,以模擬任務切換時的寄存器保存與恢復。

文件組織結構如下圖:

main.c:

#define NVIC_INT_CTRL 0xE000ED04 // 中斷控制及狀態寄存器 #define NVIC_PENDSVSET 0x10000000 // 觸發軟件中斷的值 #define NVIC_SYSPRI2 0xE000ED22 // 系統優先級寄存器 #define NVIC_PENDSV_PRI 0x000000FF // 配置優先級#define MEM32(addr) *(volatile unsigned long *)(addr) #define MEM8(addr) *(volatile unsigned char *)(addr)void triggerPendSVC (void) {MEM8(NVIC_SYSPRI2) = NVIC_PENDSV_PRI; // 向NVIC_SYSPRI2寫NVIC_PENDSV_PRI,設置其為最低優先級MEM32(NVIC_INT_CTRL) = NVIC_PENDSVSET; // 向NVIC_INT_CTRL寫NVIC_PENDSVSET,用于PendSV }typedef struct _BlockType_t {unsigned long * stackPtr; }BlockType_t;BlockType_t * blockPtr;void delay (int count) {while (--count > 0); }int flag;unsigned long stackBuffer[1024]; BlockType_t block;int main () {block.stackPtr = &stackBuffer[1024];blockPtr = █for (;;) {flag = 0;delay(100);flag = 1;delay(100);triggerPendSVC();}return 0; }

switch.c:

__asm void PendSV_Handler () {// blockPtr在main.c中定義,定義為:BlockType_t * blockPtr。// 在匯編代碼中,如要引用C中的符號,必 須先用IMPORT導入。有些類似于在C語言中的externIMPORT blockPtr// 加載寄存器存儲地址// LDR R0, =blockPtr ; 將blockPtr變量的地址加載到R0中// LDR R0, [R0] ; 再從該地址加載32位數據值,也就是將blockPtr的值加載到R0中。在main()中,我們已經設置:// BlockType_t block;// block.stackPtr = &stackBuffer[1024];// blockPtr = █// 所以,此時R0的值將會是block結構的起始地址。// LDR R0, [R0] ; 再次加載32位數據,顯示此次就是從block結構開始處加載32位值,根據block結構的定義:// typedef struct _BlockType_t {// unsigned long * stackPtr;// }BlockType_t// 顯然,此時R0的值就是stackPtr的值,也就是&stackBuffer[1024];LDR R0, =blockPtrLDR R0, [R0]LDR R0, [R0]// 保存寄存器// 此時R0的值就是&stackBuffer[1024]。然后,將R4, R5, .. R11寫入到stackBuff緩沖區中,順序不重要,你只需知道其與下面LDMIA的加載次序正好相反即可。寫入前,以R0中地址為基準,每寫入一個寄存器前,先對地址減去4,然后再寫入寄存器值。完成所有寫入之后,將最后的地址覆蓋到R0寄存器中STMDB R0!, {R4-R11}// 將最后的地址寫入到blockPtr中// LDR R1, =blockPtr ; 將blockPtr變量的地址加載到R1中// LDR R1, [R1] ; 再從該地址加載32位數據值,也就是將blockPtr的值加載到R1中。在main()中,我們已經設置:// BlockType_t block;// block.stackPtr = &stackBuffer[1024];// blockPtr = █// 所以,此時R1的值將會是block結構的起始地址。// STR R0, [R1] ; 將前面執行STM執行后,R0的值也就是最后寫入的地址寫入R1中地址指向的位置。// typedef struct _BlockType_t {// unsigned long * stackPtr;// }BlockType_t// 顯然,此時R1的值就是block結構的地址,也就是向將R0的值寫入到stackPtr。最終實現將最后的寫stackBuff的 地址保存到block.stackPtrLDR R1, =blockPtrLDR R1, [R1]STR R0, [R1]// 修改部分寄存器,用于測試// 測試代碼。用于檢查前面的保存(STMDB),以及后面的恢復(LDMIA)是否正確。如果保存和恢復正確,那么執行LDMIA后,R4,R5的值應為恢復之前的值。// 如果需要,可在此添加對其它寄存器的修改測試代碼。ADD R4, R4, #1ADD R5, R5, #1// 恢復寄存器// 與STMDB正好相反,從R0地址對應的存儲單元中讀取多個32位的單元,恢復到R4~R11寄存器。// 注意到,此時,R0為之前向存儲單元寫R4~R11的最后單元的地址,所以此時可以正確恢復。// 具體執行時,首先從當前地址對應的單元處加載數據恢復到寄存器,再將地址+4,如此反復,直到所有寄存器恢復完畢。LDMIA R0!, {R4-R11}// 異常返回// 異常返回指令,不同于從函數調用。此時LR的值不是函數的返回地址,而是一串特定的值,如0xFFFF_FFFxBX LR }

參考資料:

  • 【李述銅】從0到1自己動手寫嵌入式操作系統
  • 總結

    以上是生活随笔為你收集整理的任务切换的基础:模拟任务切换时寄存器的保存与恢复的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。