韦东山ARM第一期作业(五)异常和中断


01 - 作业所在路径

  ARM裸机1期加强版\源码文档图片\文档图片\第014课_异常与中断

02 - 作业描述

2.1 - 作业1

  014_und_exception_014_004/001有一个BUG,把以下字符串多加一个字符,看看程序还能否运行。

und_string:
	.string "undefined instruction exception"

  尝试分析反汇编,找到原因(实在找不到的话,下一节视频有讲)

2.2 - 作业2

  014_und_exception_014_004/002有一个BUG,把start.S"bl print1"去掉,看看未定义指令异常会不会发生,如果能自己解决这个BUG,那么绝对学到家了。我用了整整一个上午才发现原因(哈,我先不说原因,后面的视频也没有讲)。这BUG是一个同学发现的,原因是我找出来的。

2.3 - 作业3

  实际上LINUX系统中app调用的open, read等函数就是通过执行swi命令触发异常,在异常处理函数中实现文件的打开、读写功能。
   我们可以实现类似的功能,写一个led_ctrl汇编函数:
  a. 它可以接收1个参数
  b. 它会在栈中保存参数
  c. 它调用swi #val,这个val来自所接收的参数
  d. 恢复参数、返回
    修改swi异常处理函数,
  a. 根据val来点灯、灭灯
    修改main函数,调用 led_ctrl(0),led_ctrl(1)

2.4 - 作业4

  对于按键S2,使用快中断支持它。
  a. 编写FIQ的中断处理函数,实现保存环境、恢复环境的功能
  b. 编写按键的中断处理函数,实现点灯、灭灯功能
  c. 修改中断控制器,把S2对应的INTMOD设置为FIQ

2.5 - 作业5

  最后一个程序用到了函数指针、注册中断等概念。这对C语言的要求越来越高。main函数中用到这3个初始化函数,
  led_init();
  interrupt_init();
  key_eint_init();
  把它们放在一个函数指针数组里,用一个for循环逐个调用

03 - 作业解答

3.1 - 作业1解答

014_und_exception_014_004/001有一个BUG,把以下字符串多加一个字符,看看程序还能否运行。
und_string:
.string “undefined instruction exception”
尝试分析反汇编,找到原因

  不能正常运行,查看反汇编码,当字符串为undefined instruction的时候,und_string段及后段汇编A为:

   30000020 <und_string>:
	30000020:	65646e75 	strvsb	r6, [r4, #-3701]!
	30000024:	656e6966 	strvsb	r6, [lr, #-2406]!
	30000028:	736e6920 	cmnvc	lr, #524288	; 0x80000
	3000002c:	63757274 	cmnvs	r5, #1073741831	; 0x40000007
	30000030:	6e6f6974 	mcrvs	9, 3, r6, cr15, cr4, {3}
		...
	30000035 <reset>:

  当字符串为undefined instruction exception的时候,und_string段及后段汇编B为:

	30000020 <und_string>:
	30000020:	65646e75 	strvsb	r6, [r4, #-3701]!
	30000024:	656e6966 	strvsb	r6, [lr, #-2406]!
	30000028:	6e692064 	cdpvs	0, 6, cr2, cr9, cr4, {3}
	3000002c:	75727473 	ldrvcb	r7, [r2, #-1139]!
	30000030:	6f697463 	swivs	0x00697463
	30000034:	7865206e 	stmvcda	r5!, {r1, r2, r3, r5, r6, sp}^
	30000038:	74706563 	ldrvcbt	r6, [r0], #-1379
	3000003c:	006e6f69 	rsbeq	r6, lr, r9, ror #30
	30000040 <reset>:

  明显,汇编A中,由于字符串的长度问题(22字节),导致汇编指令无法自动按4字节对齐,于是reset段的首地址不是4字节对齐,导致调用出错。而汇编B中,字符串长度刚刚好是32字节,汇编指令能够按照4字节自动对齐,reset段首地址就是4字节对齐,因此没有问题

3.2 - 作业2解答

014_und_exception_014_004/002有一个BUG,把start.S中"bl print1"去掉,看看未定义指令异常会不会发生,如果能自己解决这个BUG。

  参看ARM指令集手册,发现ARM的所有指令都可以是条件执行,指令格式如下

  cond的含义如下
  原来的命令:
  .word 0xdeadc0de  /* 未定义指令 */

  这个指令中高4位bit[31:28]=1101,对应图中黄色块,只有当Z set, or N set and V clear, or N clear and V set (Z == 1 or N != V)的时候才会被执行,而上面的bl uart0_init改变了状态位,使得条件不成立,没有执行这个指令,于是没有undefine异常发生
  根据手册,修改bit[31:28] = 1110,对应图中红色块,就是无条件执行语句,undefine异常就可以发生

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

3.3 - 作业3解答

实际上LINUX系统中app调用的open, read等函数就是通过执行swi命令触发异常,在异常处理函数中实现文件的打开、读写功能。
我们可以实现类似的功能,写一个 led_ctrl 汇编函数:
a. 它可以接收1个参数
b. 它会在栈中保存参数
c. 它调用swi #val,这个val来自所接收的参数
d. 恢复参数、返回
修改swi异常处理函数,
a. 根据val来点灯、灭灯
修改main函数,调用 led_ctrl(0),led_ctrl(1)

  需要编写汇编的函数,可以反编译先看看有一个int函数参数的汇编程序是怎样的,然后参考它的写法,小白测试后,发现有一个int参数的C函数对应的汇编大概是这样的:

funtion:
	mov	ip, sp						/* IP=SP;保存SP */
	stmdb	sp!, {fp, ip, lr, pc}	/* 先对SP减4,再对fp,ip,lr,pc压栈 */
	sub	fp, ip, #4					/* fp=ip-4;此时fp指向栈里面的“fp” */
	sub	sp, sp, #4					/* 开辟一个int内存 */
	str	r0, [fp, #-16]				/* 参数压栈,-16是跳过ip/lr/pc,到第4个位置 */
	ldr	r3, [fp, #-16]				/* 取出刚刚压入的参数 */
	
	/* r3存放着参数,然后进行具体操作  */
	
	ldmia	sp, {r3,fp, sp, pc}	

  有了参考,led_ctrl就好写了,不过还是不熟悉汇编,功能是实现了,不知道有没有bug,代码如下

.global led_ctrl
led_ctrl:
	mov	ip, sp						/* IP=SP;保存SP */
	stmdb	sp!, {fp, ip, lr, pc}	/* 先对SP减4,再对fp,ip,lr,pc压栈 */
	sub	fp, ip, #4					/* fp=ip-4;此时fp指向栈里面的“fp” */
	sub	sp, sp, #4					/* 开辟一个int内存 */
	str	r0, [fp, #-16]				/* 参数压栈,-16是跳过ip/lr/pc,到第4个位置 */
	ldr	r3, [fp, #-16]				/* 取出刚刚压入的参数 */
	cmp r3, #0						/* r3和0比较 */
	beq swi_zero					/* 如果相等,触发swi中断,传参0 */
swi_one:
	swi 0x1
	b ctrl_flag
swi_zero:
	swi 0x0
ctrl_flag:
	ldmia	sp, {r3,fp, sp, pc}		

  然后在Start.S汇编do_swi中添加bl led_set

……					
mrs r0,cpsr						/* 传参1 */
	ldr r1,=swi_string			/* 传参2 */
	bl print_exception			/* 处理异常 */
	mov r0, r4					/* 传参 */
	bl led_set
……

  在led.c中添加led_set()函数如下

void led_set(unsigned int *p_swi)
{
	unsigned int val = *p_swi & ~0xff000000;
	if(val == 0)
		GPFDAT &= ~(GP_ONE_ROTATE<<GPF4_DATA);
	else
		GPFDAT |= GP_ONE_ROTATE<<GPF4_DATA;
}

  先取出swi呼叫号数,然后根据号数去开关LED(GP_ONE_ROTATE和GPF4_DATA是自己写的宏,和老师写的数值一样)
  最后就可以在main()函数中调用led_ctrl(1)打开LED,led_ctrl(0)关闭LED

3.4 - 作业4解答

对于按键S2,使用快中断支持它。
a. 编写FIQ的中断处理函数,实现保存环境、恢复环境的功能
b. 编写按键的中断处理函数,实现点灯、灭灯功能
c. 修改中断控制器,把S2对应的INTMOD设置为FIQ

  先开启FIQ,然后设置按键,再添加do_fiq和handle_fiq即可
  修改Start.S

	bic r0,r0,#(1<<6)			/* 对FIQ清0,开启CPU中断总开关 */

  修改interrupt_init()函数,S2为FIQ

	INTMOD = 0x01;				//设置按键s2为FIQ模式

  Start.S中添加do_fiq

do_fiq:
	/*
	 * 1.lr_fiq保存了被中断模式中下一条即将被执行的指令的地址
	 * 2.SPSR_fiq保存有被中断模式下的CPSR程序状态
	 * 3.CPSR中的模式被设置为10001,进入fiq模式
	 * 4.跳到0x1C的地方执行程序do_fiq
	 */
			
	ldr sp, =0x33c00000			/* sp_fiq未设置,先设置栈 */
	sub lr, lr, #4				/* 根据手册,返回地址lr需要减4 */
	stmdb sp!, {r0-r12,lr}		/* 保存现场 异常处理中可能修改r0~r12以及返回地址lr先保存*/
	mrs r0, cpsr				/* 传参1 */
	ldr r1, =fiq_string			/* 传参2 */
	bl handle_fiq				/* 处理异常 */
	ldmia sp!, {r0-r12,pc}^		/* 恢复现场 ^会把spsr恢复到cpsr*/
fiq_string:
	.string "fiq instruction exception"
.align 4						/* 为了让后面的程序4字节对齐 */

  key.c中添加handle_fiq()

/**
  * @brief  发送按键中断后的服务函数,用于区分中断源并执行对应函数
  * @param  cpsr:保存现场时的备份寄存器
  * @param  str:待打印的字符串
  * @retval None
  */
void handle_fiq(unsigned int cpsr, char* str)
{
	unsigned int val = GPFDAT;
	//需要读SRCPND。因为FIQ下,INTOFFSET和INTPND不会被影响
	int bit = SRCPND;

	//1.信息输出
	puts("[FALSE] Exception instruction!\n\r");
	puts("CPSR=");
	printHex(cpsr);
	puts(" ");
	puts(str);
	puts("\n\r");

	//2.FIQ只有一个中断源
	//处理中断, 清中断源EINTPEND
	if (val & (1<<0)) /* s2 --> gpf6 */
	{
		/* 松开 */
		GPFDAT |= (1<<6);
	}
	else
	{
		/* 按下 */
		GPFDAT &= ~(1<<6);
	}

	//3.清位,INTPND不会被FQI影响,从源头开始清
	SRCPND = (1<<(bit-1));
}

3.5 - 作业5解答

最后一个程序用到了函数指针、注册中断等概念。这对C语言的要求越来越高。main函数中用到这3个初始化函数,
led_init();
interrupt_init();
key_eint_init();
把它们放在一个函数指针数组里,用一个for循环逐个调用

  在main函数上方声明类型,定义初始化数组

typedef void(*init_func)(void);
irq_func init_array[32];
unsigned char num_init = 0;

  然后main函数中使用

int i;
init_array[num_init++] = key_eint_init;
init_array[num_init++] = leds_init;
init_array[num_init++] = timer0_init;
for(i = 0; i<num_init; i++)
	init_array[i]();

猜你喜欢

转载自blog.csdn.net/Hxj_CSDN/article/details/85779840