韦东山嵌入式第一期学习笔记DAY_13——14_4_und异常模式程序(解决了老师代码中不能触发und中断的大坑,深入理解了代码重定位)

作者:GWD 时间:2019.7.15

一、课程内容:
摘要:本节课程主要讲解了und(未知指令)中断过,并编写了一个程序当遇到未执行指令的时候串口打印一个字符串。深入思考了代码重定位。
注意:这节课老师讲的代码有个大坑
在这里插入图片描述
用老师给的代码时候去掉print1函数就无法输出异常信息,原因是老师给的deadc0de代码时有条件指令,前面的print1函数正好满足了条件从而被编译器识别为正常指令了。解决办法是将0xdeadc0de改为0xeeadc0de。
二、学习要点:
1、问:为什么把und_addr赋值给pc之后就可以在SDRAM中运行了?
在这里插入图片描述
答:因为异常模式是在重定位之后执行的,此时PC指针已近被指定在SDRAM范围内了,所以此时在SDRAM中执行了。
2、问:.word do_und与直接写do_und有什么区别?
在这里插入图片描述
答:编译器一般会把do_und放在.S文件中的末尾处,若start.S文件大小超过4K后在nand运行时,编译器找不到do_und标号(标号是给人看的,对于编译器是个地址);有的同学会有疑问,不是重定义了么?为何还需要在nand中查找标号呢?是因为,und中断标号的0x04地址不是由PC决定的,这是由硬件决定的,所以在中断触发时会回到nor/nand中寻找跳转指令,程序员需要做的是,把跳转指令利用PC指针再次跳转到SDRAM中。
在这里插入图片描述
3、问:重定位的实质?
答:首先从0地址说起,“0”地址可以有很多个,譬如从nor启动时nor的“0”地址就是nor的第一个单元格子,从nand启动的“0”就是片内4K RAM中的第一个格子。这就是在代码重定位之后就要用pc进行绝对地址的操作了,bl、b这样的相对地址跳转指令范围并不能满足要求,那么怎么才能确定程序执行的真正地址呢——PC指针,当PC指向0x30000000到0x34000000时就是指向的SDRAM。
4、问:由本节课的程序中.word和.string学习如何在汇编中定义变量?
答:
在这里插入图片描述
三、代码:
Start.C

.text
.global _start

_start:
	b reset
	ldr pc , und_addr

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
	
	/*重定位data段*/
	bl copy2sdram
	
	/*清除bss段*/
	bl clean_bss
	ldr pc, =sdram
	
sdram:	
	bl uart0_init
	//bl print1
und_code:
    //.word 0xdeadc0de	
	.word 0xeeadc0de	 
	ldr pc,=main

halt:
	b halt
	


printException.c

#include "uart.h"

void printException(unsigned int cpsr,char *str)
{
	puts("Exception! cpsr = ");
	printHex(cpsr);
	puts(" ");
	puts(str);
	puts("\n\r");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值