历史上的今天
返回首页

历史上的今天

今天是:2025年03月08日(星期六)

2020年03月08日 | ARM处理器的未定义指令异常处理过程分析

2020-03-08 来源:eefocus

在前面的两篇文章中已经介绍了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 << 28) | (COPY2_RATIO << 24) | (DMCP_RATIO << 20) | (DMCD_RATIO << 16)

| (DMC_RATIO << 12) | (DPHY_RATIO << 8) | (ACP_PCLK_RATIO << 4) | (ACP_RATIO))

 

#define CLK_DIV_DMC1_VAL 0x07071713

 

/* CLK_SRC_TOP0 */

#define MUX_ONENAND_SEL 0x0 /* 0 = DOUT133, 1 = DOUT166 */

#define MUX_ACLK_133_SEL 0x0 /* 0 = SCLKMPLL, 1 = SCLKAPLL */

#define MUX_ACLK_160_SEL 0x0

#define MUX_ACLK_100_SEL 0x0

#define MUX_ACLK_200_SEL 0x0

#define MUX_VPLL_SEL 0x1

#define MUX_EPLL_SEL 0x1

 

#define CLK_SRC_TOP0_VAL ((MUX_ONENAND_SEL << 28)|(MUX_ACLK_133_SEL << 24)|(MUX_ACLK_160_SEL << 20)

| (MUX_ACLK_100_SEL << 16)|(MUX_ACLK_200_SEL << 12)|(MUX_VPLL_SEL << 8)

| (MUX_EPLL_SEL << 4))

 

#define CLK_SRC_TOP1_VAL (0x01111000)

 

/* CLK_DIV_TOP */

#define ACLK_400_MCUISP_RATIO 0x1

#define ACLK_266_GPS_RATIO 0x2

#define ONENAND_RATIO 0x1

#define ACLK_133_RATIO 0x5

#define ACLK_160_RATIO 0x4

#define ACLK_100_RATIO 0x7

#define ACLK_200_RATIO 0x4

 

#define CLK_DIV_TOP_VAL ((ACLK_400_MCUISP_RATIO << 24)|(ACLK_266_GPS_RATIO << 20)|(ONENAND_RATIO << 16)

| (ACLK_133_RATIO << 12)|(ACLK_160_RATIO << 8)|(ACLK_100_RATIO << 4)

| (ACLK_200_RATIO))

 

/* CLK_SRC_LEFTBUS */

#define CLK_SRC_LEFTBUS_VAL (0x10)

 

/* CLK_DIV_LEFRBUS */

#define GPL_RATIO 0x1

#define GDL_RATIO 0x3

#define CLK_DIV_LEFRBUS_VAL ((GPL_RATIO << 4) | (GDL_RATIO))

 

/* CLK_SRC_RIGHTBUS */

#define CLK_SRC_RIGHTBUS_VAL (0x10)

 

/* CLK_DIV_RIGHTBUS */

#define GPR_RATIO 0x1

#define GDR_RATIO 0x3

#define CLK_DIV_RIGHTBUS_VAL ((GPR_RATIO << 4) | (GDR_RATIO))

 

#define APLL_MDIV 0xAF

#define APLL_PDIV 0x3

#define APLL_SDIV 0x0

 

#define APLL_RATIO 0x2

#define CORE_RATIO 0x0

#define CORE2_RATIO 0x0

#define COREM0_RATIO 0x3

#define COREM1_RATIO 0x7

#define PERIPH_RATIO 0x7

#define ATB_RATIO 0x6

#define PCLK_DBG_RATIO 0x1

 

/* CLK_DIV_CPU1 */

#define CORES_RATIO 0x5

#define HPM_RATIO 0x0

#define COPY_RATIO 0x6

 

#define MPLL_MDIV 0x64

#define MPLL_PDIV 0x3

#define MPLL_SDIV 0x0

 

#define EPLL_MDIV 0x40

#define EPLL_PDIV 0x2

#define EPLL_SDIV 0x3

 

#define VPLL_MDIV 0x48

#define VPLL_PDIV 0x2

#define VPLL_SDIV 0x3

 

/* APLL_LOCK */

#define APLL_LOCK_VAL (APLL_PDIV * 270)

 

/* MPLL_LOCK */

#define MPLL_LOCK_VAL (MPLL_PDIV * 270)

 

/* EPLL_LOCK */

#define EPLL_LOCK_VAL (EPLL_PDIV * 3000)

 

/* VPLL_LOCK */

#define VPLL_LOCK_VAL (VPLL_PDIV * 3000)

 

#define CLK_DIV_CPU0_VAL ((CORE2_RATIO << 28)|(APLL_RATIO << 24)|(PCLK_DBG_RATIO << 20)|(ATB_RATIO << 16)

                            |(PERIPH_RATIO <<12)|(COREM1_RATIO << 8)|(COREM0_RATIO << 4)|(CORE_RATIO))

 

#define CLK_DIV_CPU1_VAL ((CORES_RATIO << 8)|(HPM_RATIO << 4)|(COPY_RATIO))

 

#define APLL_CON1_VAL (0x00803800)

 

/* Set PLL */

#define set_pll(mdiv, pdiv, sdiv) (1<<31 | mdiv<<16 | pdiv<<8 | sdiv)

#define APLL_CON0_VAL set_pll(APLL_MDIV,APLL_PDIV,APLL_SDIV)

 

/* MPLL_CON1 */

#define MPLL_CON1_VAL (0x00803800)

#define MPLL_CON0_VAL set_pll(MPLL_MDIV,MPLL_PDIV,MPLL_SDIV)

 

#define EPLL_CON2_VAL 0x00000080

#define EPLL_CON1_VAL 0x66010000

 

#define EPLL_CON0_VAL set_pll(EPLL_MDIV,EPLL_PDIV,EPLL_SDIV)

#define VPLL_CON2_VAL 0x00000080

#define VPLL_CON1_VAL 0x66010000

 

#define VPLL_CON0_VAL set_pll(VPLL_MDIV,VPLL_PDIV,VPLL_SDIV)

 

/*

 * system_clock_init: Initialize core clock and bus clock. 初始化系统时钟

 * void system_clock_init(void)  时钟初始化,参考uboot中设置的

*/

 

.globl system_clock_init

system_clock_init:

push {lr}

 

    //往(CLK_SRC_CPU)0x10044200寄存器写入0;

ldr r0, =ELFIN_CLOCK_BASE         @0x1003_0000

ldr r1, =0x0

ldr r2, =CLK_SRC_CPU_OFFSET         @0x14200

str r1, [r0, r2]

 

/* 休息 ?us */

mov r1, #0x10000

1: subs r1, r1, #1

bne 1b

 

    //设置CLK_DIV_DMC0(0x10040500)寄存器

ldr r1, =CLK_DIV_DMC0_VAL

ldr r2, =CLK_DIV_DMC0_OFFSET

str r1, [r0, r2]

 

    //设置CLK_DIV_DMC1(0x10040504)寄存器

ldr r1, =CLK_DIV_DMC1_VAL

ldr r2, =CLK_DIV_DMC1_OFFSET

str r1, [r0, r2]

 

    

    //设置CLK_SRC_TOP0(0x1003C210)寄存器

ldr r1, =CLK_SRC_TOP0_VAL

ldr r2, =CLK_SRC_TOP0_OFFSET

str r1, [r0, r2]

//设置CLK_SRC_TOP1(0x1003C214)寄存器

ldr r1, =CLK_SRC_TOP1_VAL

ldr r2, =CLK_SRC_TOP1_OFFSET

str r1, [r0, r2]

 

/* 休息 ?us */

mov r1, #0x10000

3: subs r1, r1, #1

bne 3b

 

    //设置CLK_DIV_TOP(0x1003C510)寄存器

ldr r1, =CLK_DIV_TOP_VAL

ldr r2, =CLK_DIV_TOP_OFFSET

str r1, [r0, r2]

 

    //设置 CLK_SRC_LEFTBUS(0x10034200)寄存器

ldr r1, =CLK_SRC_LEFTBUS_VAL

ldr r2, =CLK_SRC_LEFTBUS_OFFSET

str r1, [r0, r2]

 

/* 休息 ?us */

mov r1, #0x10000

4: subs r1, r1, #1

bne 4b

 

    //设置CLK_DIV_LEFTBUS(0x10034500)寄存器

ldr r1, =CLK_DIV_LEFRBUS_VAL

ldr r2, =CLK_DIV_LEFTBUS_OFFSET

str r1, [r0, r2]

 

    //设置CLK_SRC_RIGHTBUS(0x10038200)寄存器

ldr r1, =CLK_SRC_RIGHTBUS_VAL

ldr r2, =CLK_SRC_RIGHTBUS_OFFSET

str r1, [r0, r2]

 

/* 休息 ?us */

mov r1, #0x10000

5: subs r1, r1, #1

bne 5b

 

    //设置CLK_DIV_RIGHTBUS(0x10038500)寄存器

ldr r1, =CLK_DIV_RIGHTBUS_VAL

ldr r2, =CLK_DIV_RIGHTBUS_OFFSET

str r1, [r0, r2]

 

    //设置APLL_LOCK(0x10044000)寄存器

ldr r1, =APLL_LOCK_VAL

ldr r2, =APLL_LOCK_OFFSET

str r1, [r0, r2]

 

    //设置MPLL_LOCK(0x10044004)寄存器

ldr r1, =MPLL_LOCK_VAL

ldr r2, =MPLL_LOCK_OFFSET

str r1, [r0, r2]

    //设置EPLL_LOCK(0x1003C010)寄存器

ldr r1, =EPLL_LOCK_VAL

ldr r2, =EPLL_LOCK_OFFSET

str r1, [r0, r2]

 

    //设置VPLL_LOCK(0x1003C020)寄存器

ldr r1, =VPLL_LOCK_VAL

ldr r2, =VPLL_LOCK_OFFSET

str r1, [r0, r2]

 

    //设置CLK_DIV_CPU0(0x10044500)寄存器

ldr r1, =CLK_DIV_CPU0_VAL

ldr r2, =CLK_DIV_CPU0_OFFSET

str r1, [r0, r2]

 

推荐阅读

史海拾趣

Dow-Key Microwave Corporation公司的发展小趣事

随着技术的不断进步和市场需求的增长,Dow-Key Microwave开始寻求技术突破和市场拓展。公司投入大量研发资金,加强与高校和研究机构的合作,成功开发出一系列高性能、高可靠性的射频微波开关产品。这些产品广泛应用于通信、航空、军事等领域,赢得了客户的广泛赞誉。同时,公司还积极拓展国际市场,产品出口到多个国家和地区,进一步提升了公司的知名度和影响力。

BREL International Components公司的发展小趣事

品质是BREL International Components公司发展的基石。公司从原材料采购到生产流程控制,再到产品检测,都严格遵循国际质量标准。BREL还建立了完善的品质管理体系,通过定期的质量检查和持续改进,确保每一件产品都达到客户的要求。正是这种对品质的执着追求,让BREL的产品在市场上赢得了良好的口碑,品牌价值不断提升。

EUCHNER公司的发展小趣事

EUCHNER公司的历史可追溯到1940年,由艾米·安士能先生创立的工程事务所。艾米·安士能先生是一位热衷于机械运动和系统工程领域的创新者。在1952年,他成功发明了世界上第一个组合行程开关,这一创新技术为公司的未来发展奠定了坚实的基础。1953年,EUCHNER公司正式成立,开始专注于机电控制产品的研究与开发。

Dfx公司的发展小趣事

某消费电子公司在生产过程中经常遇到质量问题,导致产品退货率居高不下。为了解决这个问题,该公司引入了DFX的设计理念,对产品设计、生产和测试等环节进行了全面优化。通过改进生产工艺、优化材料选择和加强质量控制等手段,该公司成功提高了产品的质量和可靠性,降低了退货率,赢得了消费者的信任。

Forge Europa Ltd公司的发展小趣事

在快速发展的过程中,Forge Europa Ltd公司始终注重品牌与文化的塑造。公司秉承“创新、品质、服务”的企业精神,致力于为客户提供优质的产品和服务。同时,公司还注重员工的培养和发展,建立了完善的培训体系和激励机制,激发了员工的创造力和工作热情。通过这些努力,Forge Europa不仅塑造了一个具有行业影响力的品牌形象,还形成了独特的企业文化,为企业的长远发展奠定了坚实的基础。

Aeroflex Metelics / Hi-Rel Components公司的发展小趣事

随着技术实力的不断增强,Forge Europa Ltd公司开始将目光投向国际市场。公司积极参与国际展会,与全球客户建立联系,并通过优化供应链管理,确保产品能够迅速响应国际市场需求。在欧洲市场,Forge Europa凭借其高品质的产品和专业的服务,迅速赢得了众多知名客户的青睐。同时,公司还不断拓展北美、亚洲等新兴市场,逐步建立起覆盖全球的销售网络。

问答坊 | AI 解惑

可否将论坛精华以邮件形式发给每个注册ID

如题! 不用登陆网站 亦可知晓天下 有些坛友上网不便只能查邮件…

查看全部问答>

verilog设计经验总结

本贴转自网络,不知原创于何处,粘贴于此:http://hi.baidu.com/icc%5Ffuzhou/blog/item/8c73b731e8ac821feac4afd5.html 其中有很多都是我在实际的fpga设计中用到的,比起书本来的实在,现在分享给大家: 先记下来: 1、不使用初始化语句; 2、 ...…

查看全部问答>

sim300与mirco2440串口如何连接??

我有一个sim300模块与mirco2440串口连接后测试没反应,请问sim300与mirco 2440串口能直接相连吗??做过的高手请指点下!!!!…

查看全部问答>

新手提问 symbol mc3000 开发问题

91program老师,各位老师 最近刚刚接触Wince的开发,还不知道如何下手。 我想在symbol mc3000 上开发一个小软件,非常非常简单的软件。 如上图, 1.点击Button1读取一个txt文件,将文本导入到下面的listbox中 2.在tex1中输入文本,然后回车 ...…

查看全部问答>

请教SIM300如何通过AT指令进行GPRS和上网?

SIM300给了一个可以收发短信、打电话的、拨号的软件,可是我还是拨不上号,现在打算用AT指令拨号, 请问用AT指令应该怎样拨号呢? 顺便问一下,有没有人用过SIM300给的这个软件,我用这个软件接收到的短信显示全是乱码,请问有谁知道怎么回事呢?…

查看全部问答>

各位大侠帮帮忙

我的电脑没有串口应该怎么接到DP51单片机仿真实验仪??…

查看全部问答>

M16AD转换产生PWM波实际调试问题

我手上有个用M16AD转换,然后产生PWM,已通过proteus仿真,但就是在开发板上运行不能独到AD转换的值,求解,一下使我的程序: /ICC-AVR application builder : 2011-10-8 下午 04:03:21// Target : M16// Crystal: 7.3728Mhz #include <iom16v. ...…

查看全部问答>

关于SPI长时间通讯的问题

最近在做一个SPI通讯的实验,SPI边发边收且循环执行,刚开始程序运行正常,但是运行几个小时后程序就卡在while(!SPIS_SPRF)那里跳不出来了,至今找不到问题。求高人指点啊,小弟谢谢了。 /******************************************************* ...…

查看全部问答>

【视频】飞思卡尔机电一体化机器人FSLBOT介绍

飞思卡尔机电一体化机器人FSLBOT是一个拥有4个自由度的两足行走机器人,是在机器人机械结构的基础上,配合3轴加速度传感器、PWM控制的RC伺服电机,触摸板等,由带有MCF52258 32位Coldfire处理器的塔式机电一体化板控制机器人的动作。 它其实是一个 ...…

查看全部问答>

急急急!音频功放声音最大时喇叭有吱吱的声音?

       找大侠帮帮忙,设计的音频功放声音最大时有时有吱吱的声音!其他歌曲没有,现在找到一首:蔡琴-把悲伤留给自己 就有吱吱的声音       欢迎大家来讨论!! …

查看全部问答>