历史上的今天
返回首页

历史上的今天

今天是:2024年10月12日(星期六)

正在发生

2021年10月12日 | S3C2440裸机------异常与中断__und异常模示程序示例

2021-10-12 来源:eefocus

1.异常向量表

我们先看一下芯片手册里面的异常向量表,

2.代码流程

我们在重定位的第10个程序的基础上进行修改。


我们要在start.S的前面增加跳转到相应异常向量表的代码,并且要增加代码,当发生未定义指令异常时候跳转到该代码块进行保存现场、处理未定义异常以及恢复现场的工作,然后在下面故意写一条不能被识别的指令。


2.1增加异常向量表代码

首先在start.S的前面增加相应的跳转指令,当发生异常时会根据这里的跳转指令跳转到相应的地方,代码如下。


_start:

b reset  /* vector 0 : reset */

b do_und /* vector 4 : und */

2.2设置栈

进入异常模式之后,使用的异常模式下的栈,所以我们要在处理异常之前设置一下异常模式的栈,我们随便找一块没有用到的内存就可以了,这里我们让他指向64MSDRAM的最高地址0x34000000。


/* sp_und未设置, 先设置它 */

ldr sp, =0x34000000

2.3 保存现场

由于r0-r12都有可能被修改,因为我们要把r0-r12都保存一下,另外当发生异常时,当前被中断的地址回报存在LR寄存器里面,所以我们也要把LR寄存器保存一下,这里stmdb只是stm decrease before,也就是先减后存。


/* 在und异常处理函数中有可能会修改r0-r12, 所以先保存 */

/* lr是异常处理完后的返回地址, 也要保存 */

stmdb sp!, {r0-r12, lr}  

2.4 处理异常

这里处理未定义异常的的工作我们通过编写一个C函数实现,我们新建一个exception.c,在里面编写我们的处理函数,exception.c内容如下:


#include "uart.h"

 

void printException(unsigned int cpsr, char *str)

{

puts("Exception! cpsr = ");

printHex(cpsr);

puts(" ");

puts(str);

puts("nr");

}

 

这个函数由两个参数,所以我们在start.S中调用这个函数时要传给他两个参数,在汇编代码中定义字符串可以使用.ascii和.string,他们两个的区别在于,用.ascii定义的字符串变量不会再末尾自动加上结束符.


    /* 处理und异常 */

mrs r0, cpsr

ldr r1, =und_string

bl printException

/* 恢复现场 */

ldmia sp!, {r0-r12, pc}^  /* ^会把spsr的值恢复到cpsr里 */

und_string:

.string "undefined instruction exception"

2.5 恢复现场

把r0-r12的值从栈中读出来,并且并原来保存在LR寄存器中的值赋值给PC,ldmia是指ldm increase after,也就是 先读后加。


/* 恢复现场 */

ldmia sp!, {r0-r12, pc}^  /* ^会把spsr的值恢复到cpsr里 */

2.6 故意加入一条未定义指令

我们看一下2440的芯片手册,找到ARM指令集,只要是下表中的指令都是合法的指令。我们需要定义一条下表中不支持的非法指令,或者直接用0xdeadc0de表示一条未定义指令。 

/* 故意加入一条未定义指令 */

und_code:

.word 0xdeadc0de  /* 未定义指令 */

3.代码

3.1start.S

下面我们看一下修改后的完整的start.S。


 

.text

.global _start

 

_start:

b reset  /* vector 0 : reset */

b do_und /* vector 4 : und */

 

do_und:

/* 执行到这里之前:

* 1. lr保存有被中断模式中的下一条即将执行的指令的地址

* 2. SPSR保存有被中断模式的CPSR

* 3. CPSR中的M4-M0被设置为11011, 进入到und模式

* 4. 跳到0x4的地方执行程序 

*/

 

/* sp_und未设置, 先设置它 */

ldr sp, =0x34000000

 

/* 在und异常处理函数中有可能会修改r0-r12, 所以先保存 */

/* lr是异常处理完后的返回地址, 也要保存 */

stmdb sp!, {r0-r12, lr}  

/* 保存现场 */

/* 处理und异常 */

mrs r0, cpsr

ldr r1, =und_string

bl printException

/* 恢复现场 */

ldmia sp!, {r0-r12, pc}^  /* ^会把spsr的值恢复到cpsr里 */

und_string:

.string "undefined instruction exception"

 

 

reset:

/* 关闭看门狗 */

ldr r0, =0x53000000

ldr r1, =0

str r1, [r0]

 

/* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */

/* LOCKTIME(0x4C000000) = 0xFFFFFFFF */

ldr r0, =0x4C000000

ldr r1, =0xFFFFFFFF

str r1, [r0]

 

/* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8  */

ldr r0, =0x4C000014

ldr r1, =0x5

str r1, [r0]

 

/* 设置CPU工作于异步模式 */

mrc p15,0,r0,c1,c0,0

orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA

mcr p15,0,r0,c1,c0,0

 

/* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) 

*  m = MDIV+8 = 92+8=100

*  p = PDIV+2 = 1+2 = 3

*  s = SDIV = 1

*  FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M

*/

ldr r0, =0x4C000004

ldr r1, =(92<<12)|(1<<4)|(1<<0)

str r1, [r0]

 

/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定

* 然后CPU工作于新的频率FCLK

*/

 

/* 设置内存: sp 栈 */

/* 分辨是nor/nand启动

* 写0到0地址, 再读出来

* 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动

* 否则就是nor启动

*/

mov r1, #0

ldr r0, [r1] /* 读出原来的值备份 */

str r1, [r1] /* 0->[0] */ 

ldr r2, [r1] /* r2=[0] */

cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */

ldr sp, =0x40000000+4096 /* 先假设是nor启动 */

moveq sp, #4096  /* nand启动 */

streq r0, [r1]   /* 恢复原来的值 */

 

bl sdram_init

//bl sdram_init2 /* 用到有初始值的数组, 不是位置无关码 */

 

/* 重定位text, rodata, data段整个程序 */

bl copy2sdram

 

/* 清除BSS段 */

bl clean_bss

 

bl uart0_init

 

bl print1

/* 故意加入一条未定义指令 */

und_code:

.word 0xdeadc0de  /* 未定义指令 */

bl print2

 

//bl main  /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */

ldr pc, =main  /* 绝对跳转, 跳到SDRAM */

 

halt:

b halt

3.2 exception.c

 

#include "uart.h"

 

void printException(unsigned int cpsr, char *str)

{

puts("Exception! cpsr = ");

printHex(cpsr);

puts(" ");

puts(str);

puts("nr");

}

 

4.优化

 我们把前面异常向量表的跳转指令改为绝对跳转,这样保证如果是nandflash,并且代码大于4K,那么我们后面的bl printException也不会出错,


_start:

b reset  /* vector 0 : reset */

ldr pc, und_addr /* vector 4 : und */

这样修改之后还有一个问题,我们看一下反汇编,

它去300000c0这个地方去取值,

然后c0这个地方存在的30000008,30000008就是下面这条指令的地址。

其实就是do_und指令的地址保存到内存中,然后ldr pc, und_addr会去内存中找到这个值,然后付给pc, 那么他去内存的那个地方找这个值呢,一般由编译器决定,通常会放在汇编文件的最后面,我们这个start.S非常小,如果这个start.S非常大,那么他有可能会去4K之外的地方取值,所以我们能不能指定让他去前面的内存去读这个值呢,因为我们担心这个汇编文件很大的话,有可能超过4K,如果你的板子是nand启动,那么在4K之外就没有办法读到值。修改如下:


_start:

b reset  /* vector 0 : reset */

ldr pc, und_addr /* vector 4 : und */

 

und_addr:

.word do_und

同样下面的代码在重定位之后,我们就应该跳转到SDRAM去执行代码,所以增加ldr pc, =sdram


ldr pc, =sdram

sdram:

bl uart0_init

 

bl print1

/* 故意加入一条未定义指令 */

und_code:

.word 0xdeadc0de  /* 未定义指令 */

bl print2

 

//bl main  /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */

ldr pc, =main  /* 绝对跳转, 跳到SDRAM */

 

halt:

b halt

修改后的start.S如下:


 

.text

.global _start

 

_start:

b reset  /* vector 0 : reset */

ldr pc, und_addr /* vector 4 : und */

 

und_addr:

.word do_und

 

do_und:

/* 执行到这里之前:

* 1. lr_und保存有被中断模式中的下一条即将执行的指令的地址

* 2. SPSR_und保存有被中断模式的CPSR

* 3. CPSR中的M4-M0被设置为11011, 进入到und模式

* 4. 跳到0x4的地方执行程序 

*/

 

/* sp_und未设置, 先设置它 */

ldr sp, =0x34000000

 

/* 在und异常处理函数中有可能会修改r0-r12, 所以先保存 */

/* lr是异常处理完后的返回地址, 也要保存 */

stmdb sp!, {r0-r12, lr}  

/* 保存现场 */

/* 处理und异常 */

mrs r0, cpsr

ldr r1, =und_string

bl printException

/* 恢复现场 */

ldmia sp!, {r0-r12, pc}^  /* ^会把spsr的值恢复到cpsr里 */

und_string:

.string "undefined instruction exception"

 

.align 4

 

reset:

/* 关闭看门狗 */

ldr r0, =0x53000000

ldr r1, =0

str r1, [r0]

 

/* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */

/* LOCKTIME(0x4C000000) = 0xFFFFFFFF */

ldr r0, =0x4C000000

ldr r1, =0xFFFFFFFF

str r1, [r0]

 

/* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8  */

ldr r0, =0x4C000014

ldr r1, =0x5

str r1, [r0]

 

/* 设置CPU工作于异步模式 */

mrc p15,0,r0,c1,c0,0

orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA

mcr p15,0,r0,c1,c0,0

 

/* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) 

*  m = MDIV+8 = 92+8=100

*  p = PDIV+2 = 1+2 = 3

*  s = SDIV = 1

*  FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M

*/

ldr r0, =0x4C000004

ldr r1, =(92<<12)|(1<<4)|(1<<0)

str r1, [r0]

 

/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定

* 然后CPU工作于新的频率FCLK

*/

 

/* 设置内存: sp 栈 */

/* 分辨是nor/nand启动

* 写0到0地址, 再读出来

* 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动

* 否则就是nor启动

*/

mov r1, #0

ldr r0, [r1] /* 读出原来的值备份 */

str r1, [r1] /* 0->[0] */ 

ldr r2, [r1] /* r2=[0] */

cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */

ldr sp, =0x40000000+4096 /* 先假设是nor启动 */

moveq sp, #4096  /* nand启动 */

streq r0, [r1]   /* 恢复原来的值 */

 

bl sdram_init

//bl sdram_init2 /* 用到有初始值的数组, 不是位置无关码 */

 

/* 重定位text, rodata, data段整个程序 */

bl copy2sdram

 

/* 清除BSS段 */

bl clean_bss

 

 

ldr pc, =sdram

sdram:

bl uart0_init

 

bl print1

/* 故意加入一条未定义指令 */

und_code:

.word 0xdeadc0de  /* 未定义指令 */

bl print2

 

//bl main  /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */

ldr pc, =main  /* 绝对跳转, 跳到SDRAM */

 

halt:

b halt

修改后的程序整体执行过程如下:

推荐阅读

史海拾趣

Deutron Electronics Corp公司的发展小趣事

随着环保意识的日益提高,Deutron Electronics Corp也积极响应环保号召,致力于实现绿色生产和可持续发展。公司采用环保材料和生产工艺,减少了对环境的污染。同时,公司还加大了对节能减排的投入,提高了资源利用效率。这些努力使得Deutron Electronics Corp在行业内树立了良好的环保形象,也为公司的长期发展奠定了坚实基础。

DAICO公司的发展小趣事

随着技术的不断进步,DAICO公司成功研发出一系列高可靠性的定制产品。这些产品以其卓越的性能和稳定性,赢得了客户的广泛认可。DAICO开始将业务扩展到商用飞机和其他高端商业行业,为卫星、雷达、导航、通信、电子战和导弹系统提供复杂操作不可或缺的一部分。

Etco Inc公司的发展小趣事

随着市场竞争的加剧和客户需求的不断提高,Etco Inc公司意识到品质管理对于企业发展的重要性。为此,公司投入大量资源加强品质管理体系建设,引进先进的生产设备和检测仪器,确保产品质量的稳定性和可靠性。同时,Etco还加强了员工培训和技能提升,提高了员工的品质意识和操作技能。这些举措使Etco的产品质量得到了显著提升,赢得了客户的广泛赞誉。

Fenwal Controls公司的发展小趣事

在电子行业快速发展的同时,Fenwal Controls也面临着诸多挑战和危机。例如,随着环保法规的日益严格,公司需要不断升级产品以满足环保要求。此外,原材料价格的波动和劳动力成本的上升也给公司带来了不小的压力。然而,Fenwal Controls凭借其强大的研发能力和敏锐的市场洞察力,成功应对了这些挑战和危机。公司通过优化生产流程、提高生产效率、降低生产成本等措施,有效缓解了外部压力,保持了公司的稳定发展。

AITSEMI公司的发展小趣事

随着全球化趋势的加剧,AITSEMI公司开始实施全球化战略,积极开拓海外市场。通过设立海外分支机构、参加国际展会等方式,AITSEMI成功将产品推广至全球范围,并赢得了广泛的国际认可。同时,公司还加大了品牌建设的力度,通过广告宣传、社交媒体推广等方式提升品牌影响力,进一步巩固了公司在全球电子行业的领先地位。

这些故事基于AITSEMI公司的公开资料和发展历程进行编写,旨在展示其在电子行业中的成长和发展。然而,由于公司具体的发展过程可能涉及更多的细节和未公开的信息,因此这些故事可能并不完全准确或详尽。如需更详细和准确的信息,建议直接访问AITSEMI公司的官方网站或查阅相关新闻报道。

静芯微电子(ElecSuper)公司的发展小趣事

静芯微电子深知产品质量对于企业的重要性,因此建立了完善的质量管理体系。公司从原材料采购、生产制造到产品检测等各个环节都实行严格的质量控制和管理,确保每一款产品都符合高标准的质量要求。同时,静芯微电子还引进了先进的检测设备和技术手段,对产品质量进行全面检测和评估。这些措施保证了静芯微电子产品的稳定性和可靠性,赢得了客户的信任和好评。

问答坊 | AI 解惑

FPGA在高速互连中的应用(2)

如同高速网络交换和采用多处理器结构的超级计算机一样,在多FPGA的设计中千兆位收发器的采用是必然的。带有RocketIO收发器的FPGA会成为连接处理器矩阵和FPGA的唯一互连选择,以确保整个板上处理器矩阵间的数据吞吐能力。   当实现高速串行连接时 ...…

查看全部问答>

为什么将GPIO配置成中断模式后,GPGDAT就不能读了??

    将GPIO如GPG端口中的GPG1配置成中断模式(GPGCON中配的),这样的话GPGDAT就不能读了吧(至少2440的datasheet上是这么说的)?     但是我看别人写的驱动怎么将GPG配成了中断模式,却用读取GPGDAT的相应位来判断是否产 ...…

查看全部问答>

Windows Mobile 5.0,Windows Mobile 60设备,如何在我的程序运行过程中禁用上面的Power电源按钮

Windows Mobile 5.0,Windows Mobile 60设备,如何在我的程序运行过程中禁用上面的Power电源按钮…

查看全部问答>

如何上传图片?ADS调试C和汇编混合编程 只显示反汇编内容 怎么按照C逐行调试

就这么多分了   如题问题 不知道怎么上传图片 知道告诉一声…

查看全部问答>

源码请教,关于Tab Ctrl 的多对话框共享从串口采集的数据,怎么实现啊?

现在有个项目,28号就要,很急,没实现Tab Ctrl 的多对话框共享从串口采集的数据,有四个对话框,每个对话框分别有很多的控件,要显示从串口采集来的数据,怎么样才能实现共享啊,请大家帮帮忙!!! 其中Tab Ctrl 的多对话框主要使用下面的方案5实 ...…

查看全部问答>

ST32X103做电机控制好得不得了,服务也天下第一好.

                                 ST32X103做电机控制好得不得了,服务也天下第一好.…

查看全部问答>

我最近看NXP的ARM极度不爽阿

                                 最近用LPC1766,最底层NXP就给点了demo程序,连个API库都不给,比ST和ATMEL差远了,…

查看全部问答>

stm32f107phy搭配问题

                                 最近想寻找一款PHY,工业级要求,10-100M的,dp83848或者类似产品,想找一款价格和货期合适的,不知道大家有什么建 ...…

查看全部问答>

建议增加psoc版块

  psoc是赛普拉斯半导体公司生产的可编程片上系统,具有模拟系统和数字系统,学校做工程实践时候用到,现在正在学习,希望本论坛能够增加这个版块给大家学习交流。…

查看全部问答>

富士通开发板DIY:晒一下家庭物联网厨房部分开发板

[ 本帖最后由 anananjjj 于 2012-7-5 09:51 编辑 ]…

查看全部问答>