中断体系结构
来源:互联网 发布:海关数据免费 福步 编辑:程序博客网 时间:2024/06/01 07:24
ARM体系的CPU的7种工作模式:
1.用户模式(usr):ARM处理器正常的运行状态。
2.中断模式(irq):用于通用的中断处理。
3.快速中断模式(fiq):用于高速数据传输或通道处理。
4.管理模式(svc):操作系统使用的保护模式。
5.系统模式(sys):运行具有特权的操作系统任务。
6.数据访问终止模式(abt):当数据或者指令预取终止时进入该模 式。可用于虚拟存储和数据保护。
7.未定义指令终止模式(und):当未定义的指令执行时进入该模式。可用于支持硬件协处理的软件仿真。
除了用户模式,其他模式可称为特权模式。大多数程序运行于用户模式,进入特权模式是为了处理中断、异常、或者访问被保护的系统资源。
所以当有中断发生时,CPU须由用户模式进入到中断模式。那么CPU怎么进入中断模式呢?这就需要了解不同模式下的寄存器的使用喽。
另外,ARM体系的CPU有以下两种工作状态。
*ARM状态:此时处理器执行32位的字对齐的ARM指令
*Thumb状态:此时处理器执行16位的、半字节对齐的Thumb指令
实际上,CPU一上电就处于ARM状态。
ARM920T有31个通用的32为寄存器和6个程序状态寄存器。当进入不同的模式时就使用该模式下的寄存器。
部分寄存器在不同的模式下有自己的副本,当进入某工作模式时,该工作模式下的副本寄存器将被使用。由图中可以看到FIQ(快速中断模式)的副本寄存器最多,这就使得进入快速中断模式时需要保存的寄存器状态也就最少,倘若r1-r8不做修改的话几乎不需要保存。这应该也是它被称为快速中断的原因。
在这些寄存器中,r13称为栈指针寄存器;r14称为程序连接寄存器;r15称为程序计数器。
关于r14和r15,当执行BL指令时,r14得到r15的备份。指令执行完后,再将r14的值赋给r15.当发生中断或者异常时,不同模式下的r14得到r15的备份,异常处理完后再赋给r15
每种工作模式除R0~R15共16个寄存器外,还有第17个寄存器CPSR,即“当前程序状态寄存器”CPSR中一些位被用于标识各种状态,一些位被用于标识当前处于什么工作模式
CPSR中各位意义如下,如图
(1)T位:置位时,CPU处于Thumb状态;否则处于ARM状态
(2)中断禁止位:I位和F位属于中断禁止位。它们被置位时,IRQ中断、FIQ中断分别被禁止。
(3)工作模式位:表明CPU当前处于什么工作模式。可以编写这些位,使CPU进入指定的工作模式。
除CPSR外,还有快速中断模式、中断模式、管理模式、数据访问终止模式和未定义指令中止模式等5种工作模式和一个寄存器——SPSR,即“程序状态保存寄存器”。当切换进入这些工作模式时,在SPSR中保存前一个工作模式的CPSR值,这样,当返回前一个工作模式时,可以将SPSR的值恢复到CPSR。
综上所述,当一个异常发生时,将切换进入相应的工作模式,这时ARM920T CPU核将自动完成如下事情。
(1)在异常工作模式的连接寄存器R14中保存前一个工作模式的下一条,即将执行的指令的地址。对于ARM状态,这个值是当前PC值加4或者加8.
(2)将CPSR的值复制到异常模式的SPSR。
(3)将CPSR的工作模式位设为这个异常中断的对应的工作模式。
(4)令PC值等于这个异常模式在异常向量表中的地址,即跳转去执行异常向量表中的相应指令。
相反地,从异常工作模式退回到之前的工作模式时,需要通过软件完成如下事情。
(1)前面进入异常工作模式时,连接寄存器中保存了前一份工作模式的一个指令地址,将它减去一个适当的值(参考表9.1)后赋给PC寄存器
(2)将SPSR的值复制回CPSR。
CPU运行过程中,如何知道各类外设发生了某些不预期的事件,比如串口接收到了新数据、USB接口中插入了设备、按下了某个按键等。主要有以下两个方法。(1)查询方式:程序循环地查询各设备的状态并做出相应反应。它实现简单,常用在单一的系统中,比如在一个温控系统中可以使用查询方式不断地检测温度的变化。缺点是占用CPU资源过高,不适用于多任务系统。(2)中断方式:当某件事件发生时,硬件会设置某个寄存器;CPU在每执行完一个指令时,通过硬件查看这个寄存器,如果发现所关注的事情发生了,则中断当前程序流程,跳转到一个固定的地址处理这事件,最后返回继续执行被中断的程序。它的实现相对复杂,但是效率很高,是常用的方法。参考图9.3,不论何种CPU,中断的处理过程是相似的。(1)中断控制器汇集各类外设发出的中断信号,然后告诉CPU。(2)CPU保存当前程序的运行环境(各个寄存器等),调用中断服务程序ISR来处理这些中断。(3)在ISR中通过读取中断控制器、外设的相关寄存器来识别这是哪个中断,并进行相应的处理。(4)清除中断:通过读写控制器和外设的相关寄存器来实现。(5)最后恢复被中断程序的运行环境(即上面保存的相关寄存器等),继续执行。
对于不同CPU而言,中断的处理知识细节的不同。S3C2410/S3C2440的中断控制器结构如图9.4,从中可以看出中断的处理细节。
SUBSRCPND和SRCPND寄存器表明有哪些中断被触发了,正在等待处理;SUBMASK(INTSUBMASK寄存器)和MASK(INTMASK寄存器)用于屏蔽某些中断。
(1)“Request sources(without sub-register)”中的中断源被触发之后,SRCPND寄存器中相应位被置1,如果此中断没有被INTMSK寄存器屏蔽或者快速中断FIQ的话,它将被进一步处理。
(2)对于“Request source(with sub-register)”中的中断源被触发之后,SUBSRCPND寄存器中的相应位也被置1,之后的处理过程和上面一样
沿着9.4的箭头走:在SRCPND寄存器中,被触发的中断的相应位被置1,等待处理。
(1)如果被触发的中断有快速中断FIQ——MODE(INTMOD寄存器)中为1的位对应的中断是FIQ,则CPU进入快速中断模式(FIQ M ode)进行处理。
(2)对于一般中断IRQ,可能同时有几个中断被触发,未被INTMSK寄存器屏蔽的中断经过比较后,选出优先级最高的中断,此中断在INTPND寄存器中的相应位置被置1,然后CPU进入中断模式
综上所述,使用中断的步骤
(1)设置好中断模式和快速中断模式下的栈
(2)准备好中断处理函数
1.异常向量
2.中断服务程序ISR
3.清除中断
(3)进入、退出中断模式或者快速中断模式时,需要保存、恢复被中断程序的运行环境
1.对于IRQ,进入和退出的代码如下
sub lr, lr, #4 @ 计算返回地址 stmdb sp!, { r0-r12,lr } @ 保存使用到的寄存器 ...... @处理中断 ldmia sp!, { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr
2.对于FIQ,进入和退出的代码如下
sub lr, lr, #4 @ 计算返回地址 stmdb sp!, { r0-r7,lr } @ 保存使用到的寄存器 ...... @处理快速中断 ldmia sp!, { r0-r7,pc }^ @ 快速中断返回, ^表示将spsr的值复制到cpsr
还需要设置GPIO的中断模式开发板上,K1~K2四个按键所接的CPU引脚可以设成外部中断功能。本程序的main函数是一个不做任何事的无限循环,程序的中断完全靠中断的驱动:当按下某个按键时,CPU调用其中断服务程序来点亮对应的LED本程序有四个源文件:head.S init.c interrupt.c main.c
head,S程序:
@******************************************************************************@ File:head.S@ 功能:初始化,设置中断模式、管理模式的栈,设置好中断处理函数@****************************************************************************** .extern main.text .global _start _start:@****************************************************************************** @ 中断向量,本程序中,除Reset和HandleIRQ外,其它异常都没有使用@****************************************************************************** b Reset@ 0x04: 未定义指令中止模式的向量地址HandleUndef: b HandleUndef @ 0x08: 管理模式的向量地址,通过SWI指令进入此模式HandleSWI: b HandleSWI@ 0x0c: 指令预取终止导致的异常的向量地址HandlePrefetchAbort: b HandlePrefetchAbort@ 0x10: 数据访问终止导致的异常的向量地址HandleDataAbort: b HandleDataAbort@ 0x14: 保留HandleNotUsed: b HandleNotUsed@ 0x18: 中断模式的向量地址 b HandleIRQ@ 0x1c: 快中断模式的向量地址HandleFIQ: b HandleFIQReset: ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈 bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启 msr cpsr_c, #0xd2 @ 进入中断模式 ldr sp, =3072 @ 设置中断模式栈指针 msr cpsr_c, #0xd3 @ 进入管理模式 ldr sp, =4096 @ 设置管理模式栈指针, @ 其实复位之后,CPU就处于管理模式, @ 前面的“ldr sp, =4096”完成同样的功能,此句可省略 bl init_led @ 初始化LED的GPIO管脚 bl init_irq @ 调用中断初始化函数,在init.c中 msr cpsr_c, #0x5f @ 设置I-bit=0,开IRQ中断 ldr lr, =halt_loop @ 设置返回地址 ldr pc, =main @ 调用main函数halt_loop: b halt_loopHandleIRQ: sub lr, lr, #4 @ 计算返回地址 stmdb sp!, { r0-r12,lr } @ 保存使用到的寄存器 @ 注意,此时的sp是中断模式的sp @ 初始值是上面设置的3072 ldr lr, =int_return @ 设置调用ISR即EINT_Handle函数后的返回地址 ldr pc, =EINT_Handle @ 调用中断服务函数,在interrupt.c中int_return: ldmia sp!, { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr
init.c程序:
/* * init.c: 进行一些初始化 */ #include "s3c24xx.h"/* * LED1,LED2,LED4对应GPF4、GPF5、GPF6 */#define GPF4_out (1<<(4*2))#define GPF5_out (1<<(5*2))#define GPF6_out (1<<(6*2))#define GPF4_msk (3<<(4*2))#define GPF5_msk (3<<(5*2))#define GPF6_msk (3<<(6*2))/* * S2,S3,S4对应GPF0、GPF2、GPG3 */#define GPF0_eint (0x2<<(0*2))#define GPF2_eint (0x2<<(2*2))#define GPG3_eint (0x2<<(3*2))#define GPF0_msk (3<<(0*2))#define GPF2_msk (3<<(2*2))#define GPG3_msk (3<<(3*2))/* * 关闭WATCHDOG,否则CPU会不断重启 */void disable_watch_dog(void){ WTCON = 0; // 关闭WATCHDOG很简单,往这个寄存器写0即可}void init_led(void){ // LED1,LED2,LED4对应的3根引脚设为输出 GPFCON &= ~(GPF4_msk | GPF5_msk | GPF6_msk); GPFCON |= GPF4_out | GPF5_out | GPF6_out;}/* * 初始化GPIO引脚为外部中断 * GPIO引脚用作外部中断时,默认为低电平触发、IRQ方式(不用设置INTMOD) */ void init_irq( ){ // S2,S3对应的2根引脚设为中断引脚 EINT0,ENT2 GPFCON &= ~(GPF0_msk | GPF2_msk); GPFCON |= GPF0_eint | GPF2_eint; // S4对应的引脚设为中断引脚EINT11 GPGCON &= ~GPG3_msk; GPGCON |= GPG3_eint; // 对于EINT11,需要在EINTMASK寄存器中使能它 EINTMASK &= ~(1<<11); /* * 设定优先级: * ARB_SEL0 = 00b, ARB_MODE0 = 0: REQ1 > REQ3,即EINT0 > EINT2 * 仲裁器1、6无需设置 * 最终: * EINT0 > EINT2 > EINT11即K2 > K3 > K4 */ PRIORITY = (PRIORITY & ((~0x01) | (0x3<<7))) | (0x0 << 7) ; // EINT0、EINT2、EINT8_23使能 INTMSK &= (~(1<<0)) & (~(1<<2)) & (~(1<<5));}
interrupt.c程序:
#include "s3c24xx.h"void EINT_Handle(){ unsigned long oft = INTOFFSET; unsigned long val; switch( oft ) { // S2被按下 case 0: { GPFDAT |= (0x7<<4); // 所有LED熄灭 GPFDAT &= ~(1<<4); // LED1点亮 break; } // S3被按下 case 2: { GPFDAT |= (0x7<<4); // 所有LED熄灭 GPFDAT &= ~(1<<5); // LED2点亮 break; } // K4被按下 case 5: { GPFDAT |= (0x7<<4); // 所有LED熄灭 GPFDAT &= ~(1<<6); // LED4点亮 break; } default: break; } //清中断 if( oft == 5 ) EINTPEND = (1<<11); // EINT8_23合用IRQ5 SRCPND = 1<<oft; INTPND = 1<<oft;}
main.c程序:
int main(){ while(1); return 0;}
makefile:
objs := head.o init.o interrupt.o main.oint.bin: $(objs) arm-linux-ld -Ttext 0x00000000 -o int_elf $^ arm-linux-objcopy -O binary -S int_elf $@ arm-linux-objdump -D -m arm int_elf > int.dis%.o:%.c arm-linux-gcc -Wall -O2 -c -o $@ $<%.o:%.S arm-linux-gcc -Wall -O2 -c -o $@ $<clean: rm -f int.bin int_elf int.dis *.o
S3C24XX.h:
/* WOTCH DOG register */#define WTCON (*(volatile unsigned long *)0x53000000)/* SDRAM regisers */#define MEM_CTL_BASE 0x48000000#define SDRAM_BASE 0x30000000/* NAND Flash registers */#define NFCONF (*(volatile unsigned int *)0x4e000000)#define NFCMD (*(volatile unsigned char *)0x4e000004)#define NFADDR (*(volatile unsigned char *)0x4e000008)#define NFDATA (*(volatile unsigned char *)0x4e00000c)#define NFSTAT (*(volatile unsigned char *)0x4e000010)/*GPIO registers*/#define GPBCON (*(volatile unsigned long *)0x56000010)#define GPBDAT (*(volatile unsigned long *)0x56000014)#define GPFCON (*(volatile unsigned long *)0x56000050)#define GPFDAT (*(volatile unsigned long *)0x56000054)#define GPFUP (*(volatile unsigned long *)0x56000058)#define GPGCON (*(volatile unsigned long *)0x56000060)#define GPGDAT (*(volatile unsigned long *)0x56000064)#define GPGUP (*(volatile unsigned long *)0x56000068)#define GPHCON (*(volatile unsigned long *)0x56000070)#define GPHDAT (*(volatile unsigned long *)0x56000074)#define GPHUP (*(volatile unsigned long *)0x56000078)/*UART registers*/#define ULCON0 (*(volatile unsigned long *)0x50000000)#define UCON0 (*(volatile unsigned long *)0x50000004)#define UFCON0 (*(volatile unsigned long *)0x50000008)#define UMCON0 (*(volatile unsigned long *)0x5000000c)#define UTRSTAT0 (*(volatile unsigned long *)0x50000010)#define UTXH0 (*(volatile unsigned char *)0x50000020)#define URXH0 (*(volatile unsigned char *)0x50000024)#define UBRDIV0 (*(volatile unsigned long *)0x50000028)/*interrupt registes*/#define SRCPND (*(volatile unsigned long *)0x4A000000)#define INTMOD (*(volatile unsigned long *)0x4A000004)#define INTMSK (*(volatile unsigned long *)0x4A000008)#define PRIORITY (*(volatile unsigned long *)0x4A00000c)#define INTPND (*(volatile unsigned long *)0x4A000010)#define INTOFFSET (*(volatile unsigned long *)0x4A000014)#define SUBSRCPND (*(volatile unsigned long *)0x4A000018)#define INTSUBMSK (*(volatile unsigned long *)0x4A00001c)/*external interrupt registers*/#define EINTMASK (*(volatile unsigned long *)0x560000a4)#define EINTPEND (*(volatile unsigned long *)0x560000a8)
- 中断体系结构
- 中断体系结构
- 中断体系结构
- S3C2440中断体系结构
- Linux中断处理体系结构
- WinCE中断体系结构
- WinCE中断体系结构
- WinCE中断体系结构
- WinCE中断体系结构
- Linux中断处理体系结构
- linux中断处理体系结构
- linux中断处理体系结构
- Linux中断处理体系结构
- 中断处理体系结构
- ARM920T中断体系结构
- **arm的中断体系结构
- arm中断体系结构
- ARM9的中断体系结构
- 关于1024,我有个疑问
- 短信开发接口案例介绍-手机短信开发1
- 央视专访:坚果激光电视 未来新趋势
- YouTube Go上线,离线观看和蓝牙共享一个都不能少
- 人大代表团视察腾讯 马化腾详解反诈骗“腾讯模式”
- 中断体系结构
- mybatis中的时间比较
- 猜数游戏--C语言描述
- 7-1 整数分解为若干项之和(20 分)
- 谷歌发布神经机器翻译,翻译质量接近笔译人员
- 预告:从Note 7燃烧事故探究锂电安全问题 | 硬创公开课
- 小整合大动力,马斯克又要在能源行业上创新了
- 微信买单来了,微信将如何降低支付的技术门槛?
- 访问者模式