微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > GNU ARM汇编--(五)中断汇编之嵌套中断处理

GNU ARM汇编--(五)中断汇编之嵌套中断处理

时间:11-26 来源:互联网 点击:

代码中可以看到,从R0到PC都在栈中有备份,这里我们叫栈帧.记得《深入理解计算机系统》一书在讲x86汇编的函数调用时也是栈帧的概念.这点上中断嵌套和函数调用有相似之处.有了这个栈帧,利用压栈出栈操作就一切ok了.

刚看这个代码,对有个地方有疑问,就是觉得中断开早了:

BIC r1,r1,#I_Bit ; 8 :
MSR CPSR_c,r1 ; 8 : enable int
STMDB r13!,{r4-r7} ; 9 : save r4-r7 SVC
STR r2,[r13,#FRAME_PSR] ; 9 : save PSR
STR r8,[r13,#FRAME_R12] ; 9 : save r12
STR r9,[r13,#FRAME_PC] ; 9 : save pc
STR r14,[r13,#FRAME_LR] ; 9 : save lr

觉得开中断的代码应该放在后面,这样才能保证svc mode下的stack frame不会被破坏.但在草稿纸上画一下irq和svc下的stack图,就发现堆栈操作并没有问题.可以假设刚开中断立马就有新的中断了,r4-r7 r8 r9都有在STMIA r13,{r4-r11} 中保存到svc的stack中,LDMIA r0,{r4-r9} 和STMDB r13!,{r4-r7} 保证了最初的r0-r3在栈中,而LDMIA r0,{r4-r9}和STR r8,[r13,#FRAME_R12] 以及STR r9,[r13,#FRAME_PC] 保证了R12和PC,保证正确返回.(这里的r9装的是r14_irq,所以pc就是r14_irq,这样就保证了从中断服务例程中返回).至于STR r14,[r13,#FRAME_LR]中的r14是r14_svc,将其压入svc的stack中,中断例程用bl就不会出现错误了,在最后LDMIA r13!,{r14,pc}^ 中r14得到恢复.而r2保存的是spsr,也就是svc模式的状态,一直不变,不用担心会被覆盖.

最后,再看了一遍图,觉得r10和r11的帧可以省去,因为r4-r9是用来存atpcs的r0-r3,r12,r14,而r10和r11用不到.貌似可以省点空间和时间,具体的待会实验一下.

下面给出实际的嵌套中断处理,利用r10来保存INTOFFSET的值,根据该值来判定是什么中断,从而做不同的处理.具体的效果是:代码会做流水灯的动作,Key1代表INT1,中断处理动作是4个灯全全亮然后全灭,Key4代表代表INT0,中断处理动作是第一个灯和第三个灯亮,然后第二个灯和第四个灯亮.

[cpp]view plaincopy

  1. /*
  2. simpleinterruption
  3. copyleft@dndxhej@gmail.com
  4. */
  5. .equMaskmd,0x1f@processormodemask
  6. .equSVC32md,0x13@SVCmode
  7. .equI_Bit,0x80@IRQbit
  8. .equFRAME_R0,0x00
  9. .equFRAME_R1,FRAME_R0+4
  10. .equFRAME_R2,FRAME_R1+4
  11. .equFRAME_R3,FRAME_R2+4
  12. .equFRAME_R4,FRAME_R3+4
  13. .equFRAME_R5,FRAME_R4+4
  14. .equFRAME_R6,FRAME_R5+4
  15. .equFRAME_R7,FRAME_R6+4
  16. .equFRAME_R8,FRAME_R7+4
  17. .equFRAME_R9,FRAME_R8+4
  18. .equFRAME_R10,FRAME_R9+4
  19. .equFRAME_R11,FRAME_R10+4
  20. .equFRAME_R12,FRAME_R11+4
  21. .equFRAME_PSR,FRAME_R12+4
  22. .equFRAME_LR,FRAME_PSR+4
  23. .equFRAME_PC,FRAME_LR+4
  24. .equFRAME_SIZE,FRAME_PC+4
  25. .equNOINT,0xc0
  26. .equWTCON,0x53000000
  27. .equGPBCON,0x56000010@led
  28. .equGPBDAT,0x56000014@led
  29. .equGPBUP,0x56000018@led
  30. .equGPFCON,0x56000050@interruptconfig
  31. .equEINTMASK,0x560000a4
  32. .equEXTINT0,0x56000088
  33. .equEXTINT1,0x5600008c
  34. .equEXTINT2,0x56000090
  35. .equINTMSK,0x4A000008
  36. .equEINTPEND,0x560000a8
  37. .equINTSUBMSK,0X4A00001C
  38. .equSRCPND,0X4A000000
  39. .equINTPND,0X4A000010
  40. .equINTOFFSET,0x4A000014
  41. .global_start
  42. _start:breset
  43. ldrpc,_undefined_instruction
  44. ldrpc,_software_interrupt
  45. ldrpc,_prefetch_abort
  46. ldrpc,_data_abort
  47. ldrpc,_not_used
  48. @birq
  49. ldrpc,_irq
  50. ldrpc,_fiq
  51. _undefined_instruction:.wordundefined_instruction
  52. _software_interrupt:.wordsoftware_interrupt
  53. _prefetch_abort:.wordprefetch_abort
  54. _data_abort:.worddata_abort
  55. _not_used:.wordnot_used
  56. _irq:.wordirq
  57. _fiq:.wordfiq
  58. .balignl16,0xdeadbeef
  59. reset:
  60. ldrr3,=WTCON
  61. movr4,#0x0
  62. strr4,[r3]@disablewatchdog
  63. ldrr0,=GPBCON
  64. ldrr1,=0x15400
  65. strr1,[r0]
  66. ldrr2,=GPBDAT
  67. ldrr1,=0x160
  68. strr1,[r2]
  69. bldelay
  70. msrcpsr_c,#0xd2@进入中断模式
  71. ldrsp,=0xc00@中断模式的栈指针定义
  72. msrcpsr_c,#0xd3@进入svc模式
  73. ldrsp,=0xfff@设置svc模式的栈指针
  74. @--------------------------------------------
  75. ldrr0,=GPBUP
  76. ldrr1,=0x03f0
  77. strr1,[r0]
  78. ldrr0,=GPFCON
  79. ldrr1,=0x2ea@0x2
  80. strr1,[r0]
  81. ldrr0,=EXTINT0
  82. @ldrr1,=0x8f888@0x0@0x8f888@~(7|(7<4)|(7<8)|(7<16))
  83. ldrr1,=0xafaaa
  84. strr1,[r0]
  85. ldrr0,=EINTPEND
  86. ldrr1,=0xf0@0b10000
  87. strr1,[r0]
  88. ldrr0,=EINTMASK
  89. ldrr1,=0x00@0b00000
  90. strr1,[r0]
  91. ldrr0,=SRCPND
  92. ldrr1,=0xff@0x1@0b11111
  93. strr1,[r0]
  94. ldrr0,=INTPND
  95. ldrr1,=0xff@0x1@0b11111
  96. strr1,[r0]
  97. ldrr0,=INTMSK
  98. ldrr1,=0xffffff00@0b00000
  99. strr1,[r0]
  100. MRSr1,cpsr
  101. BI

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top