ARM的异常(S3C2440)

先厘清概念
异常:异常就是在程序运行过程中(USER mode),出现了一些异常情况,而中断是异常的一种情况。
中断:中断是一种异常。

异常发生了会进入相应的模式。

ARM体系的CPU有7种工作模式:

  • User(用户模式) : ARM处理器正常的程序执行状态
  • FIQ(快速中断模式) : 当一个高优先级(fast) 中断产生时将会进入这种模式
  • IRQ(中断模式) : 通常的中断产生时将会进入这种模式
  • Svc(管理模式) : 当复位或软中断指令执行时将会进入这种模式
  • Abt(中止模式) : 当数据或指令预取中止时将会进入这种模式
  • Und(未定义指令模式) : 当执行未定义指令时会进入这种模式
  • Sys(系统模式) : 使用和User模式相同寄存器集的特权模式,运行具有特权的操作系统任务

再看一下ARM在各模式下的寄存器
在这里插入图片描述
ARM一共有37个32位寄存器。其中31个通用寄存器和6个状态寄存器。
图中带三角的寄存器在物理上是不同的寄存器。例如,R8_fiq和R8就属于不同的物理寄存器。
再重点看一下程序状态寄存器:
在这里插入图片描述

ARM对异常(中断)处理过程
1 初始化:
a 设置中断源,让它可以产生中断
b 设置中断控制器(可以屏蔽某个中断,优先级)
c 设置CPU总开关,(使能中断)

2 执行其他程序:正常程序

3 产生中断:按下按键—>中断控制器—>CPU

4 cpu每执行完一条指令都会检查有无中断/异常产生

5 发现有中断/异常产生,开始处理。对于不同的异常,跳去不同的地址执行程序。这地址上,只是一条跳转指令,跳去执行某个函数(地址),这个就是异常向量。如下就是异常向量表。
(3-5都是硬件强制做的)
在这里插入图片描述

6 这些函数做什么事情?
软件做的:
a 保存现场(各种寄存器)
b 处理异常(中断):
分辨中断源
再调用不同的处理函数
c 恢复现场

发生异常时,我们的CPU会做什么事情?

1 把下一条指令的地址保存在LR寄存器里(某种异常模式的LR等于被中断的下一条指令的地址)
它有可能是PC + 4有可能是PC + 8,到底是那种取决于不同的情况

2 把CPSR保存在SPSR里面(某一种异常模式下SPSR里面的值等于CPSR)
3 修改CPSR的模式为进入异常模式(修改CPSR的M4 ~ M0进入异常模式)
4 跳到向量表

退出异常怎么做?
1 让LR减去某个值,让后赋值给PC(PC = 某个异常LR寄存器减去 offset)
减去什么值呢?
也就是我们怎么返回去继续执行原来的程序,根据下面这个表来取值
在这里插入图片描述
如果发生的是SWI可以把 R14_svc复制给PC
如果发生的是IRQ可以把R14_irq的值减去4赋值给PC
2 把CPSR的值恢复(CPSR 值等于 某一个一场模式下的SPSR)
3 清中断(如果是中断的话,对于其他异常不用设置)
S3C2440的数据手册中也有相关描述:
在这里插入图片描述

编程
根据上面的分析,我们编程就是做3个任务:
1 保存现场(保存被中断模式的寄存器)
就比如说我们的程序正在系统模式/用户模式下运行,当你发生中断时,需要把R0 ~ R14这些寄存器全部保存下来,让后处理异常,最后恢复这些寄存器
但如果是快中断,那么我就不需要保存 系统/用户模式下的R8 ~ R12这几个寄存器,在FIQ模式下有自己专属的R8 ~ R12寄存器,省略保存寄存器的时间,加快处理速度
但是在Linux中并不会使用FIQ模式

2 处理异常

3 恢复现场

uboot是裸板程序的集大成者,看看uboot中对异常是怎么编程的。
以下是uboot的start.S的部分程序。

 /*code: 28 -- 72*/
    #include <config.h>
    #include <version.h>
    
    
    /*
     *************************************************************************
     *
     * Jump vector table as in table 3.1 in [1]
     *
     *************************************************************************
     */
    #define GSTATUS2   (0x560000B4)
    #define GSTATUS3   (0x560000B8)
    #define GSTATUS4   (0x560000BC)
    
    #define REFRESH(0x48000024)
    #define MISCCR (0x56000080)
    
    #define LOCKTIME	0x4C000000	/* R/W, PLL lock time count register */
    #define MPLLCON		0x4C000004	/* R/W, MPLL configuration register */
    #define UPLLCON		0x4C000008	/* R/W, UPLL configuration register */
    #define CLKCON		0x4C00000C	/* R/W, Clock generator control reg. */
    #define CLKSLOW		0x4C000010	/* R/W, Slow clock control register */
    #define CLKDIVN		0x4C000014	/* R/W, Clock divider control */
    
    /******下面这些就是异常向量表*****/
    .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

分析:从0地址开始,根据异常向量表中的地址,放了一条跳转指令,发生异常之后,程序调到异常向量表的对应地址执行程序,然后跳转到相应处理函数中。
通常这些都是放在start.S的开始部分,异常处理函数放在程序后面。
例:_undefined_instruction: .word undefined_instruction
undefined_instruction是异常处理函数的标号,_undefined_instruction是异常处理函数对应的地址值,而ldr pc, _undefined_instruction是把这个地址值给PC。

注1:异常处理程序一般放在汇编的最后。
注2:重定位完成后,最好立即跳到SDRAM执行。

发生异常时,程序的具体执行流程:
在这里插入图片描述

下面是包含了未定义异常和定时器中断异常的start.S。具体的函数处理过程由c语言实现。


.text
.global _start

_start: 
	b reset
	ldr	pc, und_addr		/* 遇到未定义指令,进入未定义模式 */
	ldr	pc, _software_interrupt
   	ldr	pc, _prefetch_abort
    ldr	pc, _data_abort
    ldr	pc, _not_used
    ldr	pc, irq_addr
    ldr	pc, _fiq

und_addr:
	.word undefined_instruction
	
_software_interrupt:
_prefetch_abort:
_data_abort:
_not_used:


irq_addr:
	.word irq_code
_fiq:
	
.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
	

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

	/* 清除BSS段 */
	bl clean_bss
	
	/* 复位之后, cpu处于svc模式
	 * 现在, 切换到usr模式
	 */
	mrs r0, cpsr         /* 读出cpsr */
	bic r0, r0, #0xf     /* 修改M4-M0为0b10000, 进入usr模式 */
	bic r0, r0, #(1<<7)  /* 清除I位, 使能中断 */
	msr cpsr, r0
	
	/* 设置usr模式下的栈 */
	ldr sp, =0x33f00000
	
	ldr pc, =sdram		/* 重定位已完成,跳转到SDRAM执行 */
sdram:

	
	//bl main  /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */
	ldr pc, =main  /* 绝对跳转, 跳到SDRAM */

halt:
	b halt


.align 4	
undefined_instruction:
	ldr sp, =0x34000000
	
	/* 保护现场 */
	stmdb sp!, {r0-r12,lr}
	/* 处理异常 */
	
	/* 恢复现场 */
	ldmia sp!, {r0-r12,pc}^	

.align 4
irq_code:
	ldr sp, =0x33d00000
	
	/* 保护现场 */
	sub lr, lr, #4
	stmdb sp!, {r0-r12,lr}
	/* 处理异常 */
	bl timer_isr
	/* 恢复现场 */
	ldmia sp!, {r0-r12,pc}^	

参考:http://wiki.100ask.org/第014课_异常与中断#.E7.AC.AC001.E8.8A.82_.E6.A6.82.E5.BF.B5.E5.BC.95.E5.85.A5.E4.B8.8E.E5.A4.84.E7.90.86.E6.B5.81.E7.A8.8B

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值