历史上的今天
今天是:2024年09月03日(星期二)
2021年09月03日 | 【S3C2440】第14课、异常与中断之学习笔记
2021-09-03 来源:eefocus
1、异常向量表
/******下面这些就是异常向量表*****/
.globl _start
_start: b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq
手册异常向量表定义

2、程序
.text
.global _start
_start:
b reset /*vector 0 一上电复位,是从0地址开始执行,跳到reset*/
b do_und /*vector 4 如果发生未定义指令异常,硬件就会在自动跳转0x04地址未定义指令异常处,执行do_und*/
/*假设一上电从0地址开始执行,reset,做一系列初始化之后
*故意加入一条未定义指令
*/
do_und:
/* 执行到这里之前:
* 1. lr_und保存有被中断模式中的下一条即将执行的指令的地址
* 2. SPSR_und保存有被中断模式的CPSR
* 3. CPSR中的M4-M0被设置为11011, 进入到und模式
* 4. 跳到0x4的地方执行程序
*/
/*需要从新设置sp栈,指向某一块没有使用的地址*/
/* sp_und未设置, 先设置它 */
ldr sp,=0x34000000 /*指向SDRAM的一块内存上*/
/* 在und异常处理函数中有可能会修改r0-r12, 所以先保存 */
/* 发生异常时,当前被中断的地址会保存在lr寄存器中 先减后存*/
/* lr是异常处理完后的返回地址, 也要保存 */
stmdb sp!,{r0-r12,lr} /*先减后存*/
/* 1、保存现场 */
/* 2、处理und异常 */
mrs r0,cpsr
ldr r1,=und_string
bl printException
/* 3、恢复现场 */
ldmia sp!,{r0-r12,pc}^ /* ^ 会把und_spsr的值恢复到cpsr里 */
und_string:
.string "undefined instruction exception"
如何定义字符串,可以百度搜索 arm-linux-gcc 汇编 定义字符串
官方的说明文档
http://web.mit.edu/gnu/doc/html/as_7.html
.string "str" /*汇编代码定义字符串*/
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] /* 恢复原来的值 */
/*初始化SDRAM*/
bl sdram_init
/*初始化UART0*/
bl uart0_init
/*重定位text rodata data段整个程序*/
bl copy2sdram
/*清除BSS段*/
bl clean_bss
bl print1
und_code:
.word 0xff123456 /*未定义指令*/
bl print2
//bl main /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */
ldr pc, =main /* 绝对跳转, 跳到SDRAM */
halt:
b halt
如何处理这个异常呢?
直接print打印一句话,新建一个exception.c文件
#include "uart.h"
void printException(unsigned int cpsr, char *str) //cpsr打印相应的寄存器,str打印一个字符串
{
puts("Exception! cpsr = ");\打印cpsr
printHex(cpsr);//输出cpsr的值
puts(" ");//输出空格
puts(str);//输出str值
puts("nr");//回车,换行
}
我们打开之前编译过的程序的反汇编文件
里面一定包含了保存恢复
30000084 30000084: e1a0c00d mov ip, sp 30000088: e92dd800 stmdb sp!, {fp, ip, lr, pc} //保存 d是减 b是存 3000008c: e24cb004 sub fp, ip, #4 ; 0x4 30000090: e24dd004 sub sp, sp, #4 ; 0x4 30000094: e50b0010 str r0, [fp, #-16] 30000098: e51b3010 ldr r3, [fp, #-16] 3000009c: e2433001 sub r3, r3, #1 ; 0x1 300000a0: e50b3010 str r3, [fp, #-16] 300000a4: e51b3010 ldr r3, [fp, #-16] 300000a8: e3730001 cmn r3, #1 ; 0x1 300000ac: 0a000000 beq 300000b4 300000b0: eafffff8 b 30000098 300000b4: e89da808 ldmia sp, {r3, fp, sp, pc}//恢复,先读后加 上传编译 修改makefile添加文件 objs := start.o led.o main.o uart.o init.o exception.o all:$(objs) arm-none-linux-gnueabi-ld -T sdram.lds $^ -o main.elf arm-none-linux-gnueabi-objcopy -O binary -S main.elf main.bin arm-none-linux-gnueabi-objdump -D main.elf > main.dis %.o:%.c arm-none-linux-gnueabi-gcc -g -nostdlib -c -o $@ $< %.o:%.S arm-none-linux-gnueabi-gcc -g -nostdlib -c -o $@ $< clean: rm *.bin *.o *.elf *.dis 编译成功烧写 没有输出我们想要的字符串 很多同学想学会如何调试程序 这里我们演示 sdram: bl print1 //添加print1 /* 故意加入一条未定义指令 */ und_code: .word 0xdeadc0de /* 未定义指令 */ bl print2 //添加print2,实现这两个函数,来打印 //bl main /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */ ldr pc, =main /* 绝对跳转, 跳到SDRAM */ halt: b halt 实现print1 print2这两个打印函数,在uart.c这个文件里 void print1(void) { puts("abcnr"); } void print2(void) { puts("123nr"); } 上传代码烧写,发现print1、print2并未执行成功 发现在start.S并未初始化 uart0_init(),删除main.c中的uart0_init()初始化函数 ldr pc, =sdram sdram: bl uart0_init /*串口初始化代码添加*/ bl print1 /* 故意加入一条未定义指令 */ und_code: .word 0xff123456 /* 未定义指令 */ bl print2 //bl main /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */ ldr pc, =main /* 绝对跳转, 跳到SDRAM */ halt: b halt 加上uart0_init,再次编译烧写 程序正常运行,print1 print2全部打印,表明未定义指令并未运行,难道这个地址是一个已经定义的地址 打开2440芯片手册,找到ARM指令集 发现竟然是SWI指令,CPU可以识别出来,他不是一条未定义指令 我们得找到一条CPU不能识别的指令,定义为0x03000000 ldr pc, =sdram sdram: bl uart0_init bl print1 /* 故意加入一条未定义指令 */ und_code: .word 0x03000000 /* 未定义指令 */ bl print2 //bl main /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */ ldr pc, =main /* 绝对跳转, 跳到SDRAM */ halt: b halt 编译烧写执行 打印了未定义指令异常CPSR地址,打印了字符串,最后执行main函数 .word 0xdeadcode /* 也是一条未定义指令 只要指令地址对不上上表就是未定义指令*/ 我们查看下cpsr是否处于未定义模式 bit[4:0]表示CPU模式 11011,果然处于und模式 我们看看这个程序做了什么事情 .text .global _start /*一上电复位,从0地址开始执行 跳到 reset: 做了一系列初始化 当执行到0xdeadc0de这条指令时候,CPU根本就不知道这条指令什么意思 und_code: .word 0xdeadc0de /* 未定义指令 */ bl print2 让后就发生未定义指令异常,他会把下一条指令的地址保存到异常模式的LR寄存器 /* 执行到这里之前已经发生了很多事情 * 1. lr_und保存有被中断模式中的下一条即将执行的指令的地址 * 2. SPSR_und保存有被中断模式的CPSR * 3. CPSR中的M4-M0被设置为11011, 进入到und模式 * 4. 跳到0x4的地方执行程序 * * 设置栈 sp是指und的地址 * sp_und未设置, 先设置它 * /* 在und异常处理函数中有可能会修改r0-r12, 所以先保存 */ * lr是异常处理完后的返回地址, 也要保存 */ * 保存现场 */ * 处理und异常 */ * 恢复sp * cpu就会切换到之前的模式 */ */ .text .global _start _start: b reset /* vector 0 : reset */ b do_und /* 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里 */ 
史海拾趣
|
一、引言 过去工业控制计算机系统的软件功能都靠软件人员编程实现。工作量大,软件通用性差,且易产生错误。随着工业控制要求的不断提高,专门用于工业控制的组态软件应运而生,它是一套功能齐全的组态生成工具软件,通用性强,而 ...… 查看全部问答> |
|
_irqHandler PROC 1. STMFD sp!,{r0-r4,r12,lr} 2. mov r4,#0x80000000 //中断控制寄存器首地址(假设的) 3. ldr r0,[r4,#0] ...… 查看全部问答> |
|
请问: wince中的文件夹有没有后缀名? 我想把一个名为NandFlash的文件夹,放到桌面快捷方式, 我在WINCE500\\PLATFORM\\SMDK2440\\FILES创建了一个NandFlash.LNK文件,里面写上22#\\windows\\NandFlash 我又在Project.bib 里面加上 NandFlash ...… 查看全部问答> |
|
首先我的程序在某些主板上是可以正常工作的(具体型号我也搞不懂),设置的是从设备,内部只有从设备状态机。没有接入奇偶检验,仲裁和热插拔。 问题是在一些主板上发现设置为从设备时无法找到设备,设置为主设备可以找到,但是通过软件读取配置信 ...… 查看全部问答> |
|
今天听单片机老师讲课讲中断,说分了好几种,被他弄得一头雾水,还是没明白他说的中断都有什么,怎么配置,查了查2553手册,愣是没找到讲解终端的地方,球大神指点123!不胜感激。… 查看全部问答> |




