1. 程式人生 > 實用技巧 >SWI軟中斷

SWI軟中斷

  1 .text
  2 .global _start
  3 
  4 _start:
  5     b reset          /* vector 0 : reset */
  6     ldr pc, und_addr /* vector 4 : und */
  7     ldr pc, swi_addr /* vector 8 : swi */
  8 
  9 und_addr:
 10     .word do_und
 11 
 12 swi_addr:
 13     .word do_swi
 14 
 15 do_und:
 16     /* 執行到這裡之前:
 17      * 1
. lr_und儲存有被中斷模式中的下一條即將執行的指令的地址 18 * 2. SPSR_und儲存有被中斷模式的CPSR 19 * 3. CPSR中的M4-M0被設定為11011, 進入到und模式 20 * 4. 跳到0x4的地方執行程式 21 */ 22 23 /* sp_und未設定, 先設定它 */ 24 ldr sp, =0x34000000 25 26 /* 在und異常處理函式中有可能會修改r0-r12, 所以先儲存 */ 27 /* lr是異常處理完後的返回地址, 也要儲存 */ 28 stmdb sp!, {r0-r12, lr}
29 30 /* 儲存現場 */ 31 /* 處理und異常 */ 32 mrs r0, cpsr 33 ldr r1, =und_string 34 bl printException 35 36 /* 恢復現場 */ 37 ldmia sp!, {r0-r12, pc}^ /* ^會把spsr的值恢復到cpsr裡 */ 38 39 und_string: 40 .string "undefined instruction exception" 41 42 .align 4 43 44
do_swi: 45 /* 執行到這裡之前: 46 * 1. lr_svc儲存有被中斷模式中的下一條即將執行的指令的地址 47 * 2. SPSR_svc儲存有被中斷模式的CPSR 48 * 3. CPSR中的M4-M0被設定為10011, 進入到svc模式 49 * 4. 跳到0x08的地方執行程式 50 */ 51 52 /* sp_svc未設定, 先設定它 */ 53 ldr sp, =0x33e00000 54 55 /* 儲存現場 */ 56 /* 在swi異常處理函式中有可能會修改r0-r12, 所以先儲存 */ 57 /* lr是異常處理完後的返回地址, 也要儲存 */ 58 stmdb sp!, {r0-r12, lr} 59 60 mov r4, lr 61 62 /* 處理swi異常 */ 63 mrs r0, cpsr 64 ldr r1, =swi_string 65 bl printException 66 67 sub r0, r4, #4 /* 此時r0中存放的只是地址,地址指向swi 0x123 */ 68 bl printSWIVal 69 70 /* 恢復現場 */ 71 ldmia sp!, {r0-r12, pc}^ /* ^會把spsr的值恢復到cpsr裡 */ 72 73 swi_string: 74 .string "swi exception" 75 76 .align 4 77 78 reset: 79 /* 關閉看門狗 */ 80 ldr r0, =0x53000000 81 ldr r1, =0 82 str r1, [r0] 83 84 /* 設定MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */ 85 /* LOCKTIME(0x4C000000) = 0xFFFFFFFF */ 86 ldr r0, =0x4C000000 87 ldr r1, =0xFFFFFFFF 88 str r1, [r0] 89 90 /* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8 */ 91 ldr r0, =0x4C000014 92 ldr r1, =0x5 93 str r1, [r0] 94 95 /* 設定CPU工作於非同步模式 */ 96 mrc p15,0,r0,c1,c0,0 97 orr r0,r0,#0xc0000000 //R1_nF:OR:R1_iA 98 mcr p15,0,r0,c1,c0,0 99 100 /* 設定MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) 101 * m = MDIV+8 = 92+8=100 102 * p = PDIV+2 = 1+2 = 3 103 * s = SDIV = 1 104 * FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M 105 */ 106 ldr r0, =0x4C000004 107 ldr r1, =(92<<12)|(1<<4)|(1<<0) 108 str r1, [r0] 109 110 /* 一旦設定PLL, 就會鎖定lock time直到PLL輸出穩定 111 * 然後CPU工作於新的頻率FCLK 112 */ 113 114 115 116 /* 設定記憶體: sp 棧 */ 117 /* 分辨是nor/nand啟動 118 * 寫0到0地址, 再讀出來 119 * 如果得到0, 表示0地址上的內容被修改了, 它對應ram, 這就是nand啟動 120 * 否則就是nor啟動 121 */ 122 mov r1, #0 123 ldr r0, [r1] /* 讀出原來的值備份 */ 124 str r1, [r1] /* 0->[0] */ 125 ldr r2, [r1] /* r2=[0] */ 126 cmp r1, r2 /* r1==r2? 如果相等表示是NAND啟動 */ 127 ldr sp, =0x40000000+4096 /* 先假設是nor啟動 */ 128 moveq sp, #4096 /* nand啟動 */ 129 streq r0, [r1] /* 恢復原來的值 */ 130 131 bl sdram_init 132 //bl sdram_init2 /* 用到有初始值的陣列, 不是位置無關碼 */ 133 134 /* 重定位text, rodata, data段整個程式 */ 135 bl copy2sdram 136 137 /* 清除BSS段 */ 138 bl clean_bss 139 140 /* 復位之後, cpu處於svc模式 141 * 現在, 切換到usr模式 142 */ 143 mrs r0, cpsr /* 讀出cpsr */ 144 bic r0, r0, #0xf /* 修改M4-M0為0b10000, 進入usr模式 */ 145 msr cpsr, r0 146 147 /* 設定 sp_usr */ 148 ldr sp, =0x33f00000 149 150 ldr pc, =sdram 151 sdram: 152 bl uart0_init 153 154 bl print1 155 /* 故意加入一條未定義指令 */ 156 und_code: 157 .word 0xdeadc0de /* 未定義指令 */ 158 bl print2 159 160 swi 0x123 /* 執行此命令, 觸發SWI異常, 進入0x8執行 */ 161 162 //bl main /* 使用BL命令相對跳轉, 程式仍然在NOR/sram執行 */ 163 ldr pc, =main /* 絕對跳轉, 跳到SDRAM */ 164 165 halt: 166 b halt

注意第67行,其中r0中存放的只是地址,地址指向第160,所有r0中存放的不是0x123

因此,對於下面的兩個函式:

向printHex函式傳入的是整型數,實則傳入的是r0的地址

此時打印出來的數值 (printHex)是r0的地址,

如果,printHex函式傳入的參量是 指標的話,輸出的就是r0地址中的數值

觀察下面的反彙編程式碼:

此時就可以輸出正確的結果: