ARM处理器的未定义指令异常处理过程分析

您所在的位置:网站首页 mrc指令错误 ARM处理器的未定义指令异常处理过程分析

ARM处理器的未定义指令异常处理过程分析

2023-10-07 09:17| 来源: 网络整理| 查看: 265

在前面的两篇文章中已经介绍了ARM处理器的工作模式和ARM异常中断处理流程。这篇文章我们通过代码来详细介绍ARM处理器未定义指令的异常中断处理;当发生未定义指令异常中断时,CPU进入未定义指令模式。可以通过读取CPSR寄存器的值来判定是否真的进入了未定义指令模式。

开发板:tiny4412;

工具链版本:gcc version 4.5.1 (ctng-1.8.1-FA)

主要设置以下几个文件:

start.S文件,详细内容如下:

.text .global _start _start: b reset /* vector 0x46000000 reset*/ ldr pc, _undefined_instruction /* vector 0x46000004 Undefined instruction*/ /* 我们将程序重定义到0x46000000地址.并在后面设置CP15协处理器将异常向量表地址设置为0x46000000 * 所以,发生复位异常时,程序跳转到0x46000000地址开始执行.发生未定义指令异常时,跳转到0x46000004 * 开始执行. */ _undefined_instruction: .word undefined_instruction /* 如果发生未定义指令异常,则程序跳转到这里执行 */ undefined_instruction: /* 注意:程序走到这里,说明已经发生了未定义指令异常; * CPU已经完成了以下工作: * 1.lr_und寄存器保存有被中断模式中的下一条即将执行的指令的地址; * 2.SPSR_und保存有被中断模式的CPSR寄存器的值; * 3.CPSR中的M4-M0被设置为11011, 进入到und模式; * 4.跳到0x46000004的地址处开始处理异常. */ /* 由于处理异常调用了C函数.所以,设置异常模式下使用的栈:sp_undef */ ldr sp, =0x48000000 /* 将在其它模式下可能使用的寄存器r0-r12入栈保存,并将lr中的值也入栈 */ stmdb sp!, {r0-r12, lr} /* 处理异常 * R0和R1来传输参数 */ mrs r0, cpsr ldr r1, =undef_string /* 跳转到C函数中执行,打印CPSR中的值和字符串 */ bl printException /* 返回现场;从栈中将r0-r12原来的值取回;并将原来lr中的值保存pc中;^符合表示将SPSR中的值返回到CPSR中. */ ldmia sp!, {r0-r12, pc}^ undef_string: //定义一个字符串 .string "Undefined Instruction Exception!" .align 4 //这里一定要4个字节对齐 /* 复位异常入口 */ reset: /* 重新设置异常向量表的地址 */ ldr r0,=0x46000000 mcr p15,0,r0,c12,c0,0 // Vector Base Address Register ldr sp, =0x02027400 //调用C函数之前必须设置栈,栈用于保存运行环境,给局部变量分配空间; //参考ROM手册P14,我们把栈指向BL2的最上方; //即:0x02020000(iROM基地址)+5K(iROM代码用)+8K(BL1用)+16K(BL2用) /* 首先,初始化时钟 */ bl system_clock_init /* 初始化内存控制器,使LPDDR可以使用.然后就可以将程序重定位到LPDRR中执行 */ bl mem_ctrl_asm_init //重定位整个代码到0x4200_0000地址处;这个地址位于LPDDR里面 adr r0, _start //将_start标号(程序的开始地址)位于iRAM里的实际地址保存到R0寄存器中;也是开始拷贝程序的地址 ldr r1, =_start //获取链接地址;也就是想将程序运行的地址;将拷贝的程序从这个地址开始保存 ldr r2, =bss_start //将链接地址中的bss_start标识地址保存到R1寄存器中;也是拷贝程序结束的地址;R1-R2的大小也就是要 //重定位代码的大小 cmp r1, r2 //比较两个地址是否相等,如果相等在直接去清除bss段即可; beq clear_bss //跳转到清零bss处 reload_loop: ldr r3, [r0], #4 //将R0数字表示地址处的数据加载到R3寄存器中;并将R0+4 str r3, [r1], #4 //将R3中的数据保存到R1寄存器数字表示的地址中,并将R1+4 cmp r1, r2 bne reload_loop //循环拷贝 clear_bss: //将bss段清零 ldr r0, =bss_start //将bss段的开始地址保存到R0寄存器 ldr r1, =bss_end //将bss段的结束地址保存到R1寄存器 mov r2, #0x0 //将0数字保存到R2寄存器中 cmp r0, r1 beq run_main clear_loop: str r2, [r0], #4 //将0保存到R0寄存器地址,并将R0+4 cmp r0, r1 bne clear_loop //如果不相等则表示没有清零完成 run_main: /* 跳转到LPDDR中执行 */ ldr pc, =lpddr lpddr: /* 初始化串口 */ bl uart0_init /* 打印调试信息 */ bl printHello /* 专门设置一个未定义指令;执行到这条指令时会跳转到未定义指令异常向量地址处指令 */ .word 0xdeadc0de /* 点亮LED灯 */ ldr sp, =0x45000000 //重新设置栈 mov r0, pc ldr pc, =main //跳转到C函数中执行 halt_loop: //死循环 b halt_loop

此文件开始开机运行的第一个文件,里面已经做了详细的注释这里就不再做详细的介绍。

clock_init_tiny4412.S文件主要用来设置时钟,内容如下:

//初始化时钟要使用的宏: #define ELFIN_CLOCK_BASE 0x10030000 #define CLK_SRC_DMC_OFFSET 0x10200 #define CLK_SRC_CPU_OFFSET 0x14200 #define CLK_DIV_DMC0_OFFSET 0x10500 #define CLK_DIV_DMC1_OFFSET 0x10504 #define CLK_SRC_TOP0_OFFSET 0x0C210 #define CLK_SRC_TOP1_OFFSET 0x0C214 #define CLK_DIV_TOP_OFFSET 0x0C510 #define CLK_SRC_LEFTBUS_OFFSET 0x04200 #define CLK_DIV_LEFTBUS_OFFSET 0x04500 #define CLK_SRC_RIGHTBUS_OFFSET 0x08200 #define CLK_DIV_RIGHTBUS_OFFSET 0x08500 #define APLL_LOCK_OFFSET 0x14000 #define MPLL_LOCK_OFFSET 0x14008 #define EPLL_LOCK_OFFSET 0x0C010 #define VPLL_LOCK_OFFSET 0x0C020 #define CLK_DIV_CPU0_OFFSET 0x14500 #define CLK_DIV_CPU1_OFFSET 0x14504 #define APLL_CON1_OFFSET 0x14104 #define APLL_CON0_OFFSET 0x14100 #define MPLL_CON0_OFFSET 0x10108 #define MPLL_CON1_OFFSET 0x1010C #define EPLL_CON2_OFFSET 0x0C118 #define EPLL_CON1_OFFSET 0x0C114 #define EPLL_CON0_OFFSET 0x0C110 #define VPLL_CON2_OFFSET 0x0C128 #define VPLL_CON1_OFFSET 0x0C124 #define VPLL_CON0_OFFSET 0x0C120 //使用到的值定义 /* CLK_DIV_DMC0 */ #define CORE_TIMERS_RATIO 0x0 #define COPY2_RATIO 0x0 #define DMCP_RATIO 0x1 #define DMCD_RATIO 0x1 #define DMC_RATIO 0x1 #define DPHY_RATIO 0x1 #define ACP_PCLK_RATIO 0x1 #define ACP_RATIO 0x3 #define CLK_DIV_DMC0_VAL ((CORE_TIMERS_RATIO


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3