×
单片机 > 单片机程序设计 > 详情

ARM4412中SWI中断

发布时间:2020-09-01 发布时间:
|

在ARM中的流水线分为:取值,译码,执行,仿存,回写。这五步详细如下:

而主要发生异常情况主要集中在译码以及执行阶段。此次的SWI(软中断)和上次的UND中断都出现在译码阶段,而其他5种中断都发生在执行阶段。


在异常向量表中可以看见对应异常的模式以及SWI异常的描述如图,详细参考ARM架构手册第54以及58页

如下代码,当发生SWI中断异常

1

2

3

4

5

6

7

8

9

10

11

2 int (*printf)(char *, ...) = 0xc3e114d8;

 3

 4 int main()

 5 {

 6     __asm__ __volatile__(

 7         "swi #88n"

 8     );

 9

10     printf("welcome backn");

11 }

12

此时,对应地异常向量表。ARM就会到0x00000008这个地址去取指令来处理软异常,和处理UND异常一样,实现跳转模式,处理异常(在这里,我们打印“hello swi”).然后再跳转回来。我们把这处理的指令存到SOURCE地址中,由MEMCOPY函数拷贝到0X60000008地址。然后触发异常,最后打印一句话,如果能打印“welcome back”则代表测试成功。


 1 

  2 int (*printf)(char *, ...) = 0xc3e114d8;

  3 

  4 void init_ttb(unsigned long *addr);

  5 void enable_mmu(void);

  6 unsigned long swi_init();

  7 void memcopy(unsigned long* dest,unsigned long* source,int len);

  8 

  9 int main()

 10 {

 11     //发生异常时会进入异常模式跳转到0000 0004地址处理异常事件   

 12     unsigned long source_addr=swi_init();

 13     //异常事件处理函数

 14     printf("swi_souce addr is %xn",source_addr);

 15     //将异常处理地址的值放到0x60000004

 16     memcopy(0x60000008,source_addr,0x100);

 17 

 18     enable_mmu();

 19     //内存映射将0x00000004映射到0x6000000004    

 20     __asm__ __volatile__(

 21         "swi #88n"

 22      );

 23     printf("welcome back! n");

 24 

 25 

 26 }

 27 

 28 void memcopy(unsigned long* dest,unsigned long* source,int len)

 29 {

 30     int i=0;;

 31     for(i=0;i

 32         dest[i]=source[i];

 33 }

 34 

 35 unsigned long  swi_init()

 36 {

 37     unsigned long source;

 38     __asm__ __volatile__(

 39          "ldr %0, =swi_startn"

 40          : "=r" (source)

 41      );

 42 

 43 

 44     return source;

 45 

 46 }

 47 __asm__(

 48      "swi_start:n"

 49 

 50 

 51     //跳转要分三部:

 52     //1:将PC保存到新模式下的lr中;

 53     //2:将CPSR保存在SPSR中

 54     //3:初始化SP

 55     //前两步由硬件完成,而第三部需要手动完成

 56      "mov sp, #0x66000000n"//初始化SP

 57      "stmfd sp!, {r0-r12, lr}n"//初始化sp,入栈保护寄存器 

 58 

 59     //打印一句话 

 60      "ldr r0, =stringn"

 61      "ldr r2, shown"

 62      "blx r2n"

 63 

 64     //跳回来分两部

 65     //1:将CPSR保存在SPSR中

 66     //2:将PC保存到新模式下的lr中;

 67      "mov sp, #0x66000000n"//

 68      "ldmea sp, {r0-r12, pc}^n"// 

 69 

 70 

 71      "loop:n"

 72      "b loopn"

 73 

 74 

 75      "show:n"

 76      ".word 0xc3e114d8n"

 77 

 78      "string:n"

 79      ".asciz "hello SWI\n" n"

 80      ".align 2n"

 81         );

 82 

 83 void init_ttb(unsigned long *addr)

 84 {

 85     unsigned long va = 0;//定义虚拟地址

 86     unsigned long pa = 0;//定义物理地址

 87 

 88     //40000000-------80000000   ====  40000000------80000000

 89     for(va=0x40000000; va<=0x80000000; va+=0x100000){

 90         pa = va;

 91         addr[va >> 20] = pa | 2;

 92         //|2的目的是将0-2位置为10此时将是小页模式4K

 93     }

 94 

 95     //00000000-------10000000   ====  60000000------70000000

 96     for(va=0x00000000; va<=0x10000000; va+=0x100000){

 97         pa = va+0x60000000;

 98         addr[va >> 20] = pa | 2;

 99     }

100 

101     //10000000-------14000000   ====  10000000------14000000

102     for(va=0x10000000; va<=0x14000000; va+=0x100000){

103         pa = va;

104         addr[va >> 20] = pa | 2;

105     }

106 

107     //30000000-------40000000   ====  50000000------60000000

108     for(va=0x30000000; va<0x40000000; va+=0x100000){

109         pa = va + 0x20000000;

110         addr[va >> 20] = pa | 2;

111     }

112 }

113 

114 void enable_mmu(void)

115 

116 {

117     unsigned long addr = 0x70000000;

118     init_ttb(addr);

119     //step:初始化页表

120 

121     unsigned long mmu = 1 | (1 << 1) | (1 << 8);

122     //将MMU的第0,1,8位置1

123     __asm__ __volatile__(

124         "mov r0, #3n"

125         "MCR p15, 0, r0, c3, c0, 0n"//manager

126         "MCR p15, 0, %0, c2, c0, 0n"//addr  

127         "MCR p15, 0, %1, c1, c0, 0n"// enable mmu

128         :

129         : "r" (addr), "r" (mmu)

130         : "r0"

131     );

132     printf("MMU is enable!n");

133 }


vim Makefile:

  1 

  2 all:

  3     arm-none-linux-gnueabi-gcc -c mmu.c -o mmu.o

  4     arm-none-linux-gnueabi-ld -Ttext=0x41000000 mmu.o  -o mmu 

  5     arm-none-linux-gnueabi-objcopy  -Ielf32-littlearm -Obinary  mmu mmu.bin

  6 


make

在minicom中dnw 41000000,

在终端中下载dnw 到板子,go 41000000

可以思考一下:怎么将SWI立即数打印出来?

关键字:ARM4412  SWI中断  流水线 


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
AVR熔丝位操作时的要点和需要注意的相关事项