新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > ARM 匯編若干問題(一般中斷問題與軟中斷SWI分析)

ARM 匯編若干問題(一般中斷問題與軟中斷SWI分析)

作者: 時間:2016-11-11 來源:網絡 收藏
一般中斷問題分析
ARM CPU 在上電啟動之后會自動進入SVC模式,也是ARM上電后的默認工作模式,如果發(fā)生了中斷,ARM會自動切換到外部中斷模式(IRQ為例),如果是FIQ那么就切換到FIQ模式下面進行處理。
在每一個模式下面都有一組可以訪問的寄存器,SVC和IRQ模式下的R0~R12是共用的,這就涉及到寄存器Rx內容的保存:壓棧,恢復:出棧操作。在IRQ處理中用到了哪些Rx就要進行相應的保護與恢復,否則當處理退出IRQ時就會出錯誤。
發(fā)生中斷時候,ARM是要首先完成當前正在執(zhí)行的指令,然后再進行為IRQ的必要處理。具體的內容如下:
將當前CPSR,保存到IRQ模式下的的SPSR_irq,進行備份。
把PC-4所指向的地址放到LR。LR = PC-4。為中斷返回是有個退出點。
強制PC= 0X00000018,指向IRQ的中斷向量的地址,通常地址0X00000018放置一條跳命令,跳轉到IRQ的中斷服務函數(shù)的入口地址。B HANDLERIRQ.
補充一點:ARM的正在執(zhí)行的指令地址x,和取指令的地址PC,地址y,之間是差x=y-8.
難點:中斷服務函數(shù)退出地址的計算
PC-8 --------------->|正在執(zhí)行的指令的地址|0x120 如果此時發(fā)生中斷了
PC-4 --------------->|真正的中斷返回點地址|0x124
PC ---------------->|取指令的地址 |0x128
通過上述分析可以得出:真正的中斷返回點地址是0X124,真正應該存入LR的地址是0X124.但是實際情況是:0X128 ?????
分析:ARM 總是執(zhí)行完當前的指令才會處理其他事情,問題就出在這里,當ARM執(zhí)行完當前的指令的時候PC已經更新了,如下
PC = PC+4;PC = 0X128+4 = 0X12C,存放到LR=PC-4; LR = 0X12C-4=0X128;這個0X128不是真正的中斷函數(shù)的返回點。真正的函數(shù)返回點是0X124.怎么辦????
在給PC恢復數(shù)值是進行這樣的處理下:LR = LR-4,PC=LR. ==>SUBS PC,LR,#4. 并且自動恢復CPSR=SPSR_irq
SWI軟中斷問題分析
軟中斷和一般的中斷處理流程有不同的地方:CPU在執(zhí)行指令時候,遇見一般的中斷,先要執(zhí)行完當前的指令,更新PC,然后把LR=PC-4.SPSR_irq=CPSR.CPSR=XXX.進入IRQ中斷處理過程。真正的斷點返回地址是:LR-4。在返回時需要進行地址的調整。 ==>SUBS PC,LR,#4.并且自動恢復CPSR=SPSR_irq。
swi軟中斷還是很特別的玩意,軟中斷發(fā)生的時候,CPU切換到SVC工作模式,PC的數(shù)值不進行更新,即:不是等到把當前的指令執(zhí)行完畢之后在執(zhí)行其他的處理。而是立刻處理。CPU立即把軟中斷的返回地址寫入LR中。LR=PC-4,這是真正的返回地址,PC的數(shù)據(jù)不更新。?。。。?。SWI中斷返回地址不需要調整就是正確的地址。
然后就是軟中斷編號的計算,方法:發(fā)生軟中斷時那條指令地址里面數(shù)據(jù)的低24位放的就是軟中斷標號,從中取出來放到R0里面,R0是函數(shù)的第一個參數(shù),也是存放函數(shù)返回結果的地方。
HandlerSWI
STMFD SP!,{R0-R3,R12,LR},LR存放的是swi真正的軟中斷要返回的中斷地址點。
LDR R0,[LR,#-4];找到到底在哪一條指令時發(fā)生了軟中斷,很明顯:就是LR真正斷點返回地址的上面一條地址。LR-4或者PC-8。找個這個指令的地址,取出其中的內容。軟中斷的編號就是存放在發(fā)生軟中斷那條指令地址的低24位數(shù)據(jù)里面。
BIC R0,R0,#0xFF000000,低24位是軟中斷號
BL my_swi_handler;
LDMFD SP! ,{R0-R3,R12,PC}^,其中^表示CPSR=SPSR_svc.只能手動恢復。
使用方法
extern void my_swi_handler(unsigned int num);
__swi(0x1)led_one(void);
__swi(0x2)led_two(void);
main()
{
led_one();
delay(100ms);
led_two();
}
void my_swi_handler(unsigned int num)
{
case 0x1:{ do_some_thing}break;
case 0x2:{do_another_thing}break;
default: break;
}


評論


技術專區(qū)

關閉