s3c2440裸机-异常中断(二. und未定义指令异常)

发布时间:2023-08-09  

1._und(未定义指令异常)介绍

我们之前分析过5种异常,那么如何进入未定义指令异常,当然是cpu读取指令发生异常,出现了指令解析异常。
我们先来看下当cpu解析到什么样的指令才会触发未定义指令异常呢?

从上面的arm指令格式中可知,只要指令码属于划线的格式,就属于未定义指令异常。

2.汇编向c函数传参

我们知道汇编给C语言函数传参是通过r0,r1,...通过堆栈的方式去传递的参数,比如r0=1, r1=2;那么在被调用的c函数中argv0就是r0, argv1就是r1...,那么我们如果通过汇编给C函数传递字符串呢?

我们可以通过这样声明und_string为一个字符串:

und_string:

.string "undefined instruction exception"

然后用ldr r1, =und_string,这样r1中就保存了und_string的地址。

这样调用我们的c函数就可以把und_string传入进去。


3._und异常程序示例

我们现在定义一条未定义指令伪代码:


.text

.global _start


_start:

b reset  /* vector 0 : reset */ 

b do_und /* vector 4 : und (看中断向量表)*/

reset:

/*看门狗

时钟

sdram

设置SP

重定位*/

...

bl print1


und_code:

.word 0xdeadc0de; /*定义一条未定义指令*/

/*故意以一个数据的方式引入一条未定义指令,当cpu执行到这里,读取0xdeadc0de指令码的时候,

发现无法识别这条指令,就发生未定义指令异常,就跳转到0x4的中断向量去执行*/

bl print2

...

我们现在为了方便调试理解:我们在未定义指令异常前后加上打印print1, print2,如果出现未定义指令异常后,就会跳到0x4的地方去读取指令,print2也就没法执行。


当跳转到0x4的中断向量后,发现此处是一条跳转指令"bl do_und", 我们再到未定义指令异常的服务程序do_und中打印出und_string这个字符串的内容。


现在开始写指令异常的服务程序do_und,实现如下:


do_und:

/* sp_und未设置, 先设置它 (由于之前一直处于管理模式,现在处在und状态)*/

ldr sp, =0x34000000


/* 保存现场 */

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

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

stmdb sp!, {r0-r12, lr}  /*先减后存*/ /* 把栈中的值备份到r0-r12*/

/* 处理und异常 */

mrs r0, cpsr

ldr r1, =und_string /*保存und_string地址*/

bl printException

/* 恢复现场 */

ldmia sp!, {r0-r12, pc}^  /*(ldmia先读后加),把备份的值恢复到栈中,让pc=lr就可以恢复到异常前的指令地址。^会把spsr的值恢复到cpsr里 */

下面来分析一下这个未定义指令异常服务程序:(其实代码的注释已经讲的很详细了)


1.进入未定义指令异常服务do_und之前硬件自动完成的事情如下:


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

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

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

4. 跳到0x4的地方执行程序 (bl do_und)

2.进入指令异常服务程序do_und后,我们需要保存现场,处理und异常,恢复现场,注意:由于发生了cpu模式切换,如果要用到栈,那么先要设置对应模式的栈。由于栈的地址是向下生长的,这里我就用sdram的末位地址作为栈指针,把sp_und=0x34000000。


3.在und异常服务程序中有可能会用到栈, 所以先保存现场,通过stmdb sp!, {r0-r12, lr}语句把栈中的值备份到r0-r12和lr,然后恢复现场的时候通过ldmia sp!, {r0-r12, pc}^,详见上面的注释。


4.我们看到保存现场后,我们把cpsr的值放到r0, 把und_string放到r1, 然后用bl printException调用c函数,这样我们的c函数printException就能收到汇编传过来的参数,一个是cpsr模式(r0),一个是und_string汇编传过来的字符串(r1)。我们用C函数实现printException:


void printException(unsigned int cpsr, char *str)

{

puts("Exception! cpsr = ");

printHex(cpsr);

puts(" ");

puts(str);

puts("nr");

}

测试结果如下:

打印出print1中的字符串‘abc’后,紧接着打印printException函数中的结果,cpsr=0x600000db,那么对应的M[4:0]=11011, 对应下图为und模式。然后从und异常返回,恢复原来的模式继续执行。

4.上述代码改进:

1.保证指令4字节对齐

我们将上面的代码的und_string字符串修改一下:

...und_string:
	.string "undef instruction"reset:
	/* 关闭看门狗 */
	/* 时钟 */...AVRASM复制全屏

编译烧录再次运行,发现没有任何打印输出,这是为什么呢?我明明只是把und_string字符串改了一下呀。

查看反汇编:

我们发现reset的地址是0x30000032,竟然不是4字节对齐的,我们知道arm指令集是以4字节为基本单位的,那么这里没有对齐,肯定无法解析指令。那么我们手工改进代码如下:


...

und_string:

.string "undef instruction"

.align 4

reset:

/* 关闭看门狗 */

/* 时钟 */

...

我们再来看看反汇编,发现reset的地址是30000040,是以4字节对齐的,再次烧录运行,发现能够正常输出print1, 能够进入未定义指令异常。

2.中断向量表进入异常向量用绝对跳转

如果我们程序非常大,中断向量入口代码的地址可能会大于sram的容量4k,比如do_und和do_swi,那么这个时候就需要用绝对跳转。

    .text

.global _start

_start:

    b reset  /* vector 0 : reset */ 

    b do_und /* vector 4 : und (看中断向量表)*/

将上面的相对跳转换成如下代码:


 .text

.global _start


_start:

b reset  

ldr pc, und_addr 

    ldr pc, swi_addr

    ...

    ... 

und_addr:

.word do_und

swi_addr:

    .word do_swi

这样我们的do_und, do_swi就可放在4k之外的地方。


3.重定位完程序后马上跳转到sdram上执行

我们现在不断增加的程序代码量,那么有可能在 'ldr pc, =main' 这条指令执行之前程序就已经超过4k。那么我们当从nand启动的时候,还没执行到ldr pc, =main这句来,就无法取指令执行了。 所以我们干脆重定位完代码后就直接跳转到sdram上去执行,代码裁剪如下:


...

reset:

/*

看门狗

时钟

set SP

sdram_init

重定位

                    */

ldr pc, =sdram sdram:

            ...

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


halt:

b halt

我们再来分析下整个程序执行过程:

1.一上电,cpu从0地址执行,执行b reset(进行初始化硬件)

2.重定位程序

3.跳转到sdram去继续执行

4.执行到 deadc0de,发生未定义指令异常

5.跳转到异常向量表的0x4地址去执行

6.跳转到sdram上执行异常处理函数(do_und)

7.异常返回,继续执行

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

相关文章

    我们在产品方案确定的时候,我们会不断的比较不同的方案,不同的模块,最终确定自己的产品设计。 今天,我们就以无际单片机编程给学员的第二个项目“WIFI防盗报警网关”为例,给大家比较透彻的解析一下硬件设计的过程。 第一步:根据......
    人机交互。保安中心可以通过监控管理软件实时监测各种系统状态,可以对报警系统进行双向控制,还可以与公安局报警中心联网并自动报警,构成多级联网报警系统。 家庭报警系统的硬件设计主要由报警主机、前端......
    故障原因 ①接线错误; ②电磁干扰; ③机械振动导致的编码器硬件损坏; ④现场环境导致的污染; 02 故障排除 ①检查接线并排除错误; ②检查屏蔽是否到位,检查布线是否合理并解决,必要......
    选型需要综合考虑上述关键参数以及其他诸如电源类型和电气接口等因素。当我们了解了这些参数后,就能够选择最适合我们应用的编码器,以提高设备运行效率和准确性。 常见故障 1、编码器本身故障:是指编码器本身元器件出现故障,导致......
    、银行和工厂等。 电话自动报警的主要功能为: 用户根据需要把自己的手机号码、办公室电话或报警监控中心的电话预存入报警主机。报警主机不断地对所监控的设备( 门禁、烟雾探测器、窗磁、摄像头等) 状况......
    制卡上电时默认使能信号关闭;将此状态保存,确保控制卡再次上电时即为此状态。 在伺服电机上:设置控制方式;设置使能由外部控制;编码器信号输出的齿轮比;设置控制信号与电机转速的比例关系。一般来说,建议......
    数据的测试,以KPA Studio软件作为EtherCAT端的虚拟主站,转动编码器时,在KPA上在线检测MK5 5002编码器模块采集到的数据。 在进行通信测试前,首先要对MK5-5002-T000编码器模块进行硬件......
    安森美推出电感型位置传感器,可替代光学编码器;凭借其专利技术,onsemi(安森美) 将感应式位置传感带入了高速、高精度领域。安森美在2022 Electronica上展示了 onsemi 的新......
    安森美推出电感型位置传感器,可替代光学编码器;凭借其专利技术,onsemi(安森美) 将感应式位置传感带入了高速、高精度领域。安森美在2022 Electronica上展示了 onsemi 的新......
    电机、轮子、陀螺仪、加速度计、电池等。通过设计的电路板进行连接,组成一个完整的系统。 三、硬件设计 根据上述需求,我进行了电路图设计 四、软件设计 4.1电机驱动编写 4.1.1电机引脚说明 编码......

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>