ARM的工作模式分为下面几种:
共有七种工作模式,他们分别为:
1.System & User模式
2.Fiq快速中断模式
3.SVC管理模式
4.abt终止模式
5.irq普通中断模式
6.und未定义指令模式
其中:
1.黑三角表示该模式下所特有的寄存器
2.R13:链接寄存器LR
3.R14:栈指针寄存器SP
4.R15:程序指令计数器PC
ARM模式之间切换过程:
1.ARM一上电,CPU就处于了SVC模式
2.当发生了中断,CPU将进入IRQ模式,R13,R14会切换到IRQ模式下的R13,R14,然后跳到0x18出取执行(0x18地址是ARM规定好的,该地址就是中断入口地址)
3.当碰到了一条机器码CPU不认识,CPU将进入undefined模式,R13,R14切换到undefined模式下的R13,R14,最后跳转到0x4地址去执行(0x4也是ARM规定好的)
4.当执行了swi #val,CPU将进入SVC模式,R13,R14也就切换到SVC模式下的R13,R14,最后跳转到0x8去执行
5.当切换到另一种模式时,会将当前的cpsr保存到另一种模式下的spsr中。
总结:
当发生了swi #val
硬件上:
1.CPU进入SVC模式
2.当前的CPSR状态被保存到SVC模式下的SPSR中
3.R13,R14切换到SVC模式下的R13,R14
4.把当前下一条指令的地址存放到SVC模式下的R14(lr)中
5.跳转到 0x8地址执行
软件上:
1.在地址0x8地方,放一条跳转指令
2.保存现场
3.处理异常
4.恢复现场
测试程序如下:
.globl _start _start: /* 0 地址 */ b reset /* 复位时,cpu跳到0地址 */ ldr pc, =undefined_instruction /* cpu遇到不能识别的指令时 */ ldr pc, _vector_swi /* 当执行swi指令时, 进入SVC模 式 */ @ldr pc, _prefetch_abort /* 预取中止异常 */ @ldr pc, _data_abort /* 数据访问异常 */ @ldr pc, _not_used /* 没用到 */ @ldr pc, _irq /* 中断异常 */ @ldr pc, _fiq /* 快中断异常 */ _vector_swi: .word vector_swi vector_swi: /* 1. 保存现场 */ ldr sp, =0x56000000 /* sp,r13, r13_svc */ stmdb sp!, {r0-r12, lr} /* lr就是swi的下一条指令地址 */ /* 2. 处理异常 */ mrs r0, cpsr ldr r1, =swi_str bl print_cpsr /* 3. 恢复现场 */ ldmia sp!, {r0-r12, pc}^ /* ^表示把spsr恢复到cpsr */ swi_str: .word 0x00697773 /* swi */ undefined_instruction: /* 1. 保存现场 */ ldr sp, =0x55000000 stmdb sp!, {r0-r12, lr} /* 2. 处理异常 */ mrs r0, cpsr ldr r1, =und_str bl print_cpsr /* 3. 恢复现场 */ ldmia sp!, {r0-r12, pc}^ /* ^表示把spsr恢复到cpsr */ und_str: .word 0x00646e75 /* und */ usr_str: .word 0x00727375 /* usr */ reset: /* 硬件相关的设置 */ /* Peri port setup */ ldr r0, =0x70000000 orr r0, r0, #0x13 mcr p15,0,r0,c15,c2,4 @ 256M(0x70000000-0x7fffffff) /* 关看门狗 */ /* 往WTCON(0x7E004000)写0 */ ldr r0, =0x7E004000 mov r1, #0 str r1, [r0] /* 设置时钟 */ bl clock_init /* 设置栈 */ ldr sp, =8*1024 bl ddr_init bl init_uart /* 把程序的代码段、数据段复制到它的链接地址去 */ ldr r0, =_start /* _start的链接地址 0x51000000 */ adr r1, _start /* 获得_start指令当前所在的地址 : 0*/ ldr r2, =bss_start /* bss段的起始链接地址 */ sub r2, r2, r0 cmp r0,r1 beq clean_bss bl nand_read cmp r0, #0 bne halt /* 清BSS */ /* 把BSS段对应的内存清零 */ clean_bss: ldr r0, =bss_start ldr r1, =bss_end mov r3, #0 cmp r0, r1 ldreq pc, =on_ddr clean_loop: str r3, [r0], #4 cmp r0, r1 bne clean_loop ldr pc, =on_ddr on_ddr: mrs r0, cpsr bic r0,r0,#0x1f orr r0,r0,#0x10 msr cpsr,r0 /* 进入user mode */ ldr sp, =0x57000000 //设置用户模式下的sp ldr r1, =usr_str bl print_cpsr swi 0 /* * cpu进入svc模式 * 把之前的cpsr保存到spsr_svc * 切换到r13_svc, r14_svc * 把swi的下一条指令存到r14(lr)_svc * 跳到地址8 */ bl hello undef: .word 0xff000000 /* * cpu进入Undefined模式 * 把之前的cpsr保存到spsr_und * 切换到r13_und, r14_und * 把下一条指令存到r14(lr)_und * 跳到地址4 */ swi_ret: bl main halt: b halt