ARM的七种异常类型.pdf
ARM7支持六种操作模式:(1) 用户模式(usr):正常的程序执行状态(2) FIQ模式(fiq): 支持数据传送或通道处理(3) IRQ模式(irq): 用于通用的中断处理(4) 管理模式(svc):用于操作系统的保护模式(5) 异常模式(abt):数据或者指令预取异常时进入(6) 无定义模式(und):当无定义指令被执行时进入(7)软件控制, 外部中断, 异常处理都可以改变操作模式。 大部分的应用程序在用户模式下执行。其他模式,比如管理模式,在中断、异常服务、或者访问被保护资源时进入。ARM 的中央寄存器集是16 个用户寄存器R0 R15。 这些寄存器均是32 位宽度, R0 R12没有其他特殊功能,寄存器R13 R15在CPU中有特殊功能。R13被用作栈指针(stackpointer,SP)。R14被称为链接寄存器(link register, LR),当调用一个函数时返回地址被自动保存到链接寄存器,在函数返回时有效。这使得快速进入和返回“叶”函数(不调用其他函数的函数)成为可能。 如果函数是分支的一部分 (即该函数将调用另一个函数) , 链接寄存器必须入栈 (R13) 。R15 是程序计数器(program counter, PC)。有趣的是,许多指令也可以在R13 R15中执行,就像它们是标准的用户寄存器。ARM 中断的问题ARM 的七种异常类型1 复位异常2 数据访问中止异常3 快速中断请求异常4 一般中断请求5 预取指令异常6 软件中断异常7 未定义异常问题:1 为什么除了进入复位异常模式外,在别的异常处理模式中都允许 FIQ 中断?2 数据访问中止异常的优先级 大于 FIQ 异常,为什么在数据访问异常处理模式中,还允许 FIQ 中断?这样不就成了:在高优先级异常处理中允许低优先级的中断发生?即使这样,因为 FIQ 中断的优先级 将下一条指令的地址存入 LR2 复制 CPSR 到 SPSR3 根据异常类型,设置 CPSR 的运行模式位和相应的中断位4 强制 PC 从相应的异常向量地址取下一条指令执行,跳转到相应的异常处理程序处B:异常处理完毕之后,ARM 微处理器会执行以下几步操作1 将连接寄存器 LR 的值减去相应的偏移量后送到 PC 中。2 将 SPSR 复制回 CPSR 中。3 若在进入异常处理时设置了中断禁止位,要在此清除。4 可以认为应用程序总是从复位异常处理程序开始执行的,因此复位异常处理程序不需要返回。问题 1:在 B中,为什么还要清除中断禁止位?我是这样理解的:进入异常时, 先保存了 CPSR 到相应的 SPSR, 返回的时候, 直接复制 SPSR到 CPSR 不就使得和中断前的 CPSR 一样吗?为什么还要清除相应的中断位?问题 2:B点怎么理解?麻烦大家给讲讲。1: 如果 CPSR 的 I 位为 0,ARM 处理器会再次响应中断,所以清除 I 位是必须的2: 其实是说,一旦发生复位,处理就立即转向复位向量.其实复位还有其它操作,B4 的说法不是很准确的armarm 开发经验笔记开发经验笔记IT /malonely 发表于 2007-09-20, 15:57前一段时间做了 arm 的一些开发 ,主要是编写了 arm 的启动软件和移植了uCOS-II到 arm7。 我做事情喜欢深入简出 ,及从最简单 ,最原理的方面先做一个框架 ,然后在这个框架里面进行补充。 我还是一个很喜欢和别人讨论的人,希望有人可以给我提出意见和建议。我的这个心得很初级 ,都是一些基本的东西。现在拿出来和大家分享 ,希望在我毕业之前能给大家留一些纪念。_由于这些东西发 paper 实在是没有价值 ,但是我感觉可以作为arm 开发的入门。由于我的水平和经验有限 ,错误也是难免的。 但是如果不拿出来和大家分享 , 就算有错误我也发现不了 ,是么?呵呵。我现试试发连载的第一篇,看看有多少价值 ,如果大家觉得有价值 ,我会继续连载的。前言这个文档是我学习 ARM 编程的总结和心得。阅读这个文档的人应当首先阅读ADS1.2 的帮助文档及相关内容。这个文档不会对编译器及连接器做出详细的说明, 在需要的时候会指出具体内容在相关资料的章节。同时阅读这个文档的人需要了解ARM 指令集和一些 ARM 汇编的基本内容以及C 和 C+的相关编程内容。同时还需要了解 ARM 的流水线结构及一些基本的编程知识。同时为了方便查阅英文文档,所有的相关术语都使用英文原文第一章第一章STARTUPSTARTUP1 1 ARMARM 的启动的启动一般的嵌入式系统在主程序执行之前都需要执行一些初始化的过程以创造嵌入式程序运行的 环境,尤其是一些高级的嵌入式系统 ,由于核心芯片使用内存映射、 内存保护等机制以及编程使用高级语言C,C+甚至 JAVA 语言,都需要先创建一个适合程序运行的硬件环境 ,然后初始化或者配置或者剪裁run-timelibrary,这些工作都必须在主程序运行前完成 ,所以一个 startup 程序或者程序组对于一个嵌入式系统来说是非常重要的。要编写 startup 程序,需要对编译器、链接器和汇编器的细节有一定的了解,同时对 ARM 芯片硬件本身的地址分配以及memory mapping 机制也需要有一些了解。2 2 ARMARM 程序的工作过程程序的工作过程首先由各种 source file 经过编译产生 object 文件,然后 object 文件经过链接生成 Image 文件,然后通过 ICE 的方法,根据描述文件的指定下载到目标板上的固态存储器指定地址当中 ,比如 flash,EEPROM,ROM 等等。在程序执行之前 ,根据某些描述文件,将需要读写数据的部分读出放入动态存储器比如RAM 当中,然后程序从 ROM 开始执行。或者有时为了提高程序的运行速度 ,也可以将所有的程序 (有一些 root 的部分除外,以后会提及 )通过一个描述文件放入指定的RAM 当中,然后程序从 RAM 开始执行,但是这样会耗费大量的动态存储器 ,所以大部分程序会取折中的方法,将需要快速运行的部分和要读写的部分放入RAM 中(一般读固态存储器的过程和动态存储器的过程是 一样的,但是写就不同了 ,所以读写的部分一定要放到RAM 中),而只读的部分和对速度要求不是那么高的部分放入固态存储器。同时ARM 结构的异常向量表规定放在地址为 0 x00000000 开始的地址空间上 ,而一般的 CPU 为了提高异常相应速度 ,会将这个向量段 remap 到其他的 RAM 当中,所以在描述文件当中必须精确指定异常向量跳转程序的地址到remap 的地方。在 application 程序执行前 ,还需要由一些文件描述 application 程序执行 的环境。比如系统工作时钟 ,总线频率。现在一般嵌入式编程语言为 C,C+等。如果在使用它们的时候使用的runtime-library, 那么在程序执 行前还需要为这些库函数初始化heap。然后 ARM 可能工作在不同的模式 ,还需要为不同的工作模式设置stack。这样,描述链接地址的文件 ,以及在 application 运行前所有的初始化程序就是startup 程序组3 3 STARTUPSTARTUP 分类分类这样,将 startup 程序所完成的功能分类。一类是链接地址描述,一类是各种初始化的程序。根据不同的应用 ,描述文件和初始化程序的内容以及结构和复杂程度都会不同。但是基本上 ,它们都必须实现以下功能。3.1 描述文件实现功能描述文件可以是链接命令行上简单的几个字符,也可以是一个非常复杂的文件 ,但是它必须完成如下功能:指定程序下载的地址指定程序执行的地址3.2 初始化程序实现的功能初始化程序根据不同的应用 ,其结构和复杂度也不同 ,但是它必须完成如下基本功能:异常向量初始化内存环境初始化其他硬件环境初始化4 4描述文件描述文件要编写描述文件 ,必须知道 ARM Image 文件的组成及 ARM Image 文件执行的机理。4.1 ARM Image 的结构一个 ARM Image structure 由 linker 在以下几个方面定义:组成它的 regions 和 output sections当 Image 下载的时候这些 regions 和 sections在内存中的位置当 Image 执行时这些 regions 和 sections 在内存中的位置4.1.1 ARM Image 的组成一个 ARM Image 被保存在可执行文件当中 ,它的层次结构可以包括Image,regions,output sections 和 input sections 。一个 Image 由一个或多个 regions 组成,每个 region 包括一个或多个 output sections每个 output section 由一个或多个 input sections 组成 Input sections 是一个 object file 中的 code 和 data 信息。Image 的结构如下图:NOTE Input section,outputsection 和 region 的定义见 ADS_LinkerGuide3-3 页。同时 Input section 有几种属性 ,分别为 readonly,read-write,zero-initialized。分别称为 RO,RW 和 ZI。属性来源于 AREA 后的 attr 属性。比 如 CODE 是 RO,DATA 是 RW,NOINT 默认为 ZI,即用 0 值初始化 ,但是可以选择不进行 0 值初始化。 ZI 属性仅仅来源于 SPACE, DCB, DCD, DCDU, DCQ, DCQU, DCW, 或者 DCWU。 由以上定义 ,ZI 属性的包含于 RW 属性,它是有初始值的 RW数据。又例如在 C 语言中,代码为 RO,静态变量和全局变量是RW,ZI 的。4.1.2 Image 的 Load view 和 executionview在 下载的时候 Image regions 被放置在 memory map 当中,而在执行 Image 前,或许你需要将一些 regions 放置在它们执行时的地址上 ,并建立起 ZI regions 。 例如,你初始化的 RW 数据需要从它在下载时的在ROM 中的地址处移动到执行时RAM 的地址处。NOTE Load view 和 executionview 的详细定义见 ADS_LinkerGuide3-4以上的描述包括二个内容 ,一是要指定各个 section 在 load view 和 executionview 时的地址即 memory map,二是要在执行前根据这些地址进行section 的初始化。4.1.3 制定 Memory map制 定 memory map 的方法基本上有二种 ,一是在 link 时使用命令行选项 ,并在程序执行前利用 linker pre-definesymbol 使用汇编语言制定 section 的段初始化 ,二是使用 scatter file。 以上二种方法依应用程序的复杂度而定,一针对简单的情况 ,二针对复杂的情况。4.1.1.1 利用 linker pre-definesymbol 使用汇编程序这是简单的方法 ,针对简单的 memory map。在 link 时使用选项 -ro, -rw, 等等指定 memory map 的地址。详细说明参看 ADS_LinkerGuide 中命令行选项说明。 然后利用汇编使用 pre-definesymbol, 来进行各种段的定位。 Linker pre-define 定义如下:由前面对 ZI 的说明,Image$RW$Limit= Image$ZI$Limit 。这些都是 linker 预先定义的外部变量 ,在使用的时候可以用IMPORT 引入。下面给出一个例子。假 设 linker 选项为: -ro-base0 x40000000-rw-base0 x40003000 。程序和只读变量 (const 变量)大小为 0 x84,这样 RO section 的大小为 0 x84 bytes。Data 的大小为 0 x04 bytes,并且 data 被初始化 ,则 RW section 的大小为 0 x04,ZI section 的大小为 0 x04。这样程序在 load view,地址是这样的:0 x40000000 开始到地址 0 x40000080, 是 RO section 部分(程序从 0 x40000000 开始),Image$RO$Limit= 0 x40000084.0 x40000084 地址开始到地址 0 x40000084, 是 RW section 部分。在 executionview,由 linker 的选项,各个 section 的地址是这样的:RO section 的地址不变。RW section 的起始地酚 蔽?x40003000, 则 Image$RW$Base= 0 x40003000。因为全部的 0 x04 bytes data 被初始化 ,所以 Image$RW$Limit= Image$ZI$Limt = 0 x40003004 。现在要做的就是将 RW section 移到以 0 x40003000 开始的地方 ,并且创造一个 ZIsection 。一个更通用的做法是:首 先比较 Image$RO$Limit 和 mage$RW$Base, 如果相等 ,说明 executionview 下 RW section 的地址和 load view 下 RW section 的地址相同 ,这样,不需要移动 RW section; 如果不等 ,说明需要移动 RW section 到它在 executionview 中的地方。然后将 Image$ZI$Base 地址到 Image$ZI$Limt 地址的内容清零。示例代码如下:;读入 linker pre-definesymbolsIMPORT Image$RO$LimitIMPORT Image$RW$BaseIMPORT Image$ZI$BaseIMPORT Image$ZI$Limit; . 一些其他的代码或伪指令;R0 读入 section load addressLDR R0,= Image$RO$Limit;R1 读入 section executionaddressLDR R1,= Image$RW$Base;R2 读入 executionsection 后的紧跟的 word addressLDR R2,= Image$ZI$Base;检查 RW section 的地址在 load view 和 executionview 下;是否相等 ,如果相等 ,就不移动 RW section, 直接建立;ZI scetionCMP R0,R1BEQ do_zi_init;否则就 copy RW section 到 executionview 下指定的地址BL copy; .; .;copy 是一个用于 copy 的子函数 ,它把从 R0 中的地址开始的;sectioncopy 到 R1 中的地址开始的 section, 这个 section 的;上限地址后紧跟的 word address 保存在 R2 中copyCMP R1,R2LDRCC R3,R0,#4STRCC R3,R1,#4BCC copyMOV PC,LR; .; .;do_zi_int 子函数是为创建 ZI section 做一些准备工作do_zi_int;将 ZI section 开始的地址装入 R1LDR R1,= Image$ZI$Base;将 ZI section 结束后紧跟的 word address 装入 R2LDR R2,= Image$ZI$Limit;将 ZI section 需要的初始化量装入R3MOV R3,#0BL zi_int; .; .;zi_int 子函数用于建立并初始化ZI section,ZIsection 的;开始地址储存在 R1,ZI section 结束后紧跟的 word address;地址储存在 R2zi_intCMP R1,R2STRCC R3,R1,#4BCC zi_intMOV PC,LR; .; .这个方法针对比较简单的应用 ,如果需要进行一个比较复杂的memory map,如下图,那么这个方法就不适用了。为了解决复杂memory map 的问题需要用到 scatter load 机制。标签: arm发信人: duremi (快乐点), 信区: Modern_Elec标题: ARM7 常见问题 1:数据异常 (ZZ)发信站: 逸仙时空 Yat-sen Channel (Fri Apr 7 10:11:49 2006), 站内信件ARM7 常见问题 1:数据异常 作者 呜哇啦 日期 2006-3-30 13:45:00其实很多人刚开始都会觉得数据异常很讨厌, 到后来真正了解之后,才发现这个东西真不错,能有效的帮助我们查找到问题所在。如果没有这个东西,很多问题是很难被发现的。一般会出现此现象的原因: 1.堆栈的指针不合理(C 编译器无法侦测到。),随着 SP 的延伸,可能会到临界地区,发生不正确的物理地址的访问。 2.在 C 中使用 volatile 的物理地址访问, 有可能出现非法的数据区域访问。 3.特别是在工业控制等场合 (掉电重起后, 数据要求不更改, 做到数据保护) ,系统启动过程中,屏蔽掉_main 的初始化变量功能,很多公共变量(如定义成 unsigned shortx=0 x8888,或指向某些结构的指针).在启动后没有初始化代码为其做初始化。所以容易产生随机地址访问,出现data abort。此情况下,最好在用户程序一开始就做好全局变量的初始化工作。解决方案:应有一些 ARM 汇编基础,在进入数据异常的时候,通过查找 LR 地址,ADS下使用 setpc 跳到 LR 内的地址(keil 下,则是 show code atAddress),此处的代码(可能是一个小小范围,因为流水线的问题)就是引起错误的指令。查看此代码对哪些变量进行了访问(如果有堆栈操作,则设置断点,程序执行到此处后。查看 SP 指针是否合法)- o o o o o o True love is powerful. o o o o o o 来源:逸仙时空 Yat-sen Channel FROM:202.116.78.152ARM S3C4510BARM S3C4510B 系统中的异常中断技术系统中的异常中断技术 ( (图图) )作者:作者:中国海洋大学 钟石磊 孙克怡 曹伟 程凯日期:日期:2004-9-1来源:来源:本网字符大小:【大】中】 【小】【摘摘要要:介绍 ARM S3C4510B 系统的异常中断机制,包括异常中断的分类,响应与返回;中断处理程序的安装与调用;SWI,IRQ 中断的实例与关键代码。关键词关键词:ARM;S3C4510;异常中断;SWI;IRQ;中断向量表引言引言-随着人们对于电子产品的要求越来越高, 以 80C51 系列为代表的 8 位处理器系统开始面临越来越多的局限和挑战,人们对于高性能芯片和嵌入式功能的呼声也越来越高。16/32 位的处理器系统得到了前所未有的关注和重视。32 位 ARM 体系系列处理器便是其中的代表。S3C4510B 处理器是基于 ARM7 体系 16/32 位 RISC 处理器,内部集成了 8KB 的 CACHE/SDRAM,内嵌 EARTHNET 控制器,拥有 7 种处理器模式和内部多线程和外部多处理器的处理器结构。 在嵌入式系统中具有重要意义的异常中断技术在 S3C4510B 系统中也体现了 ARM 体系独有的一些的特点。本文根据 S3C4510B 系统的特点,分析了该系统中七种异常中断的功能及特点。并给出了SWI异常中断(外部中断)和 IRQ 异常中断(软件中断)的应用实例代码。1 S3C4510B1 S3C4510B 系统中的异常中断系统中的异常中断1.1 S3C4510B 系统异常中断的特点-S3C4510B 系统中控制程序执行流程的方式通常有三种,一是正常程序执行过程,即根据指令类型增加程序计数器 PC 使程序顺序执行;二是通过跳转的方式来控制程序的执行,可以利用跳转的命令执行跳转操作,也可以通过直接修改程序计数器来达到跳转的目的;三是异常中断的方式,可以根据软件的执行情况,外部设备的异常请求等实现内部、外部异常的处理,系统功能的调用和程序进程的控制等功能。-S3C4510B 系统的异常中断具有以下几个特点。首先,作为 ARM 体系 RTOS(实时操作系统)组成部分,程序中的异常中断必须按照 ARM 体系的要求进行处理器模式的转换。其次,如果对系统的优化有需求时,可以进行 32 位的 ARM 处理指令和 16 位的 THUMB 指令的转换。另外,S3C4510B 处理器正常运行时,保存的返回地址是通过将 PC 存入 LR 寄存器完成的,由于中断产生时的计数器 PC 的值有时已经更新,如产生了外部中断和快速中断等;有时可能尚未更新,如软件中断和未定义指令中止等,故必须根据实际情况对返回地址进行软件修正之后才能正确返回。最后还要注意,ARM 体系支持 c 语言和汇编语言程序的相互之间的调用,并有 ATPCS规则进行协调,所以异常中断处理程序必需按照 ATPCS 规则进行寄存器处理。1.2 S3C4510B 系统中的异常中断的类型-S3C4510B 拥有七种不同的异常中断类型,分别适应于不同的中断需要。根据 ARM 系列处理器的特点,各种异常中断对应于 ARM 系列的不同工作模式。其种类和对应关系如表 1 所示。-其中,复位中断是优先级最高的中断。在复位引脚有效的前提下,系统加电或系统复位时都会引起复位中断。数据访问中止是在数据访问指令的目标地址不存在或者该地址不允许当前指令访问的情况下产生的。指令预取中止中断是处理器或系统协处理器认为当前指令未定义,当系统预取该指令时,本中断执行。未定义中止在处理器或系统协处理器认为当前指令未定义时产生, 故而可以根据该异常中断机制仿真浮点向量运算。快速中断和外部中断都是在对应的中断请求引脚有效,且状态寄存器中的相应中断禁止标志位清零时产生。其中的外部中断还可以用来进行各系统进程的切换;软中断由用户定义,在程序运行时由 SWI 指令调用,可用于用户模式下的程序调用特权模式指令。在 RTOS 系统中可以通过该中断机制实现系统功能调用。1.3 S3C4510B 系统对异常中断的响应-S3C4510B 系统对异常中断的响应流程如下:-(1) 保存处理器当前状态寄存器 CPSR 的值、中断屏蔽以及各条件标志位到将要执行的异常中断的 SPSR中。-(2) 设置当前程序状态寄存器 CPSR 的值。其中包括:设置CPSR 相应位的值使处理器进入特定的处理器模式;按要求屏蔽中断,通常应该屏蔽 IRQ 中断,在 FIQ 中断时屏蔽 FIQ 中断。-(3) 设置 Lr 寄存器。将中断相应模式的Lr 寄存器的值设置为异常中断的返回地址。-(4) 处理程序计数器 PC。将 PC 值设为相应的中断向量的地址,从而实现跳转以执行中断程序。-当处理器执行完以上流程之后, 处理器已经自中断向量进入异常中断的处理状态。 异常中断处理完毕之后,在异常中断程序的末端,处理器进入异常中断的返回状态,其流程如下:-(1) 恢复状态寄存器。将保存在中断模式中的 SPSR 值赋给当前的状态寄存器。-(2) 将返回地址复制到程序计数器。 这样程序将返回到异常中断产生的下一条指令或出现问题的指令处执行。整个响应与返回的过程如图 1 所示。需要注意的是,对于不同的异常中断,其返回地址的计算方法也是不同的。IRQ 和 FIQ 异常中断产生时,程序计数器 PC 已经更新,而 SWI 中断和未定义指令中断是由当前指令自身产生的,程序计数器 PC 尚未更新,所以要计算出下一条指令的地址来执行返回操作;指令预取中止异常中断和数据访问异常中断要求返回到出现异常的执行现场,重新执行操作。2 S3C4510B2 S3C4510B 系统中的异常中断处理程序的安装系统中的异常中断处理程序的安装S3C4510B 系统通过异常向量表安装异常中断处理程序,即将异常向量表指向异常中断处理程序的入口,实现面向异常中断的跳转。这里需要介绍一下 S3C4510B 系统的中断向量表。在 S3C4510B 系统中,无论在地址重映射之前还是之后,异常中断向量表的入口地址为固定的(见表 1)。当系统运行到满足异常中断条件而产生异常中断时,系统将自动跳入相应的异常中断向量表中。而在异常向量表中保存的,正是利用跳转指令或 ldr 指令指向该中断的异常中断处理程序的指令程序,这样就实现了异常中断处理程序的安装。以 SWI软中断为例,异常中断安装的基本顺序如图 2 所示,其中异常中断向量的地址是固定的,其他地址为假设的。2.1 利用跳转指令实现异常中断的安装将 BL 指令放置到中断向量表的特定位置,跳转目标地址为中断处理程序的首地址,便可直接实现异常中断的安装。其优点是 BL 指令可以直接保存地址,缺点是 BL 的跳转范围只有 32MB 的地址空间,如 blSWI_Handler。2.2 利用 ldr 指令实现异常中断的安装利用 ldr 直接向程序计数器 PC 中赋值也可以实现中断处理程序的安装。先要将异常中断处理程序首地址的绝对地址放在邻近的一个存储单元中,然后用 ldr 命令将该内存单元中的地址读取到 PC 中。其优点是可调用程序的范围不受限制,如: ;ldr pc,SWI_ADDR;SWI_ADDR dcd SWI_Handler以上两种安装方法各有优缺点,需要根据实际情况来选择。3 S3C4510B3 S3C4510B 系统中系统中 SWISWI 异常中断实例异常中断实例S3C4510B 中的 SWI 指令可以用来实现 RTOS 中的系统功能调用。它由用户模式下当前执行的指令引发,通过一个 24 位的立即数来指代 SWI 需要调用的系统功能,调用执行的过程在特权模式中进行。3.1 SWI 异常中断的处理程序通常我们把 SWI 的中断处理程序分为两级,分别完成立即数的读取和功能调用的执行。其指令代码如下:stmfd sp!,r0-r12,lr;保护现场,保存寄存器的值ldr r0,lr,#-4;lr 寄存器保存指令bic r0,r0,#0XFF000000 ;读取指令中的 24 位立即数cmp R0,#MaxOfSWI;判断立即数是否有效ldrls pc,pc,r0,lsl #2b OutOfSWIRange ;超出范围JumpListofSWIdcd SWIPro_0dcd SWIPro_1;其他所有的软中断入口SWIPro_0;进入 SWI 对应立即数 0 的中断处理程序;对应立即数 0 的中断处理程序b EndOfSWISWIPro0;进入 SWI 对应立即数 1 的中断处理程序;对应立即数 1 的中断处理程序b EndOfSWI;其他的 SWI 处理程序EndOfSWIldmfd sp!,r0-r12,pc;恢复各寄存器3.2 SWI 异常中断的调用与返回对于 SWI 异常中断的调用要根据中断现场所处的处理器模式进行调用。 通常用户模式下调用 SWI 功能只需将处理器所需要的参数存放于寄存器中,然后调用相应功能号的系统功能。 Mov r0,#80;假设参数为#80 swi0X1;SWI 中断立即数 1由于 SWI 中断功能调用在特权模式下执行,故而当在特权模式下调用 SWI 功能时,必须对当前模式下的SPSR 和寄存器 LR 进行保存。stmfdsp!,r0r12,lr;保存寄存器movr1,spmov r0, spsr_svcstmfdsp!,r0 ;保存 SPSR;读取立即数,调用 SWI 中断处理程序ldmfdsp!,r0 ;恢复 SPSRmsr spsr_svc, r0ldmdf sp!,r0-r12,lr ;恢复其他寄存器4 S3C4510B4 S3C4510B 系统中的系统中的 IRQIRQ 异常中断实例异常中断实例4.1 IRQ 异常中断的产生S3C4510B 处理器系统常用于进行外部异常的响应和操作系统进程的控制。 CPSR 寄存器的 I 控制位置 0 时,处理器在指令边界查询是否有 IRQ 请求,系统的外部中断管理器或者外设通过使能处理器的 IRQ 输入管脚产生 IRQ 异常中断。4.2 IRQ 异常中断的处理程序IRQ 异常中断产生后,根据中断向量的指令跳入相应的中断处理程序。系统的外围中断管理硬件会将所用的 IRQ 中断请求按照优先级进行排列,把最高优先级的 IRQ 中断的信息放入寄存器中。通常的 IRQ 中断处理程序也需要保存返回地址、寄存器,而且需要屏蔽 IRQ 中断,以保证优先级较高的中断完全处理。sub lr,lr,#4stmfd sp!,lr;保存返回地址mrs r14,spsr_irqstmfd sp!,r12,r14;保存 r12,spsrmov r12,#IntBase;读取中断管理接口的基址ldr r12,r12,#IntLevel;计算当前中断的物理地址mrs r14,cpsrbic r14,r14,#0X80;清零 IRQ 中断禁止位msr cpsr_irq,r14;开 IRQ 中断ldr pc, pc,r12,lsr #2;跳转到相应的中断处理程序dcd PirQ0Handlerdcd PirQ1Handlerdcd PirQnHandler;优先级为 n 的中断处理程序地址PirQ0Handlerstmfd sp!,r0-r11;优先级为 1 的中断处理程序ldmfd sp!,r0-r11msr spsr_irq,r14;恢复 r12 和 spsrldmfd sp!,pc ;中段返回dcd PirQnHandler;中断优先级为 N 的中断处理程序4.3 IRQ 异常中断在进程控制中的应用S3C4510B 处理器系统中的进程之间的切换也是通过 IRQ 来完成的。操作系统中的每一个进程都由进程控制块 PCB 来表示,PCB 中包含了进程相关的信息。比如,当某一进程进行到一定的程度时,利用IRQ 中断将当前进程中断,保存需要保存的寄存器的值之后,切换到另一进程中执行。5 5 结束语结束语S3C4510B 的异常中断机制较为复杂,但也正是因为其复杂的机制,使我们在开发的过程中有了更灵活的选择。用好了异常中断,不仅可以实现系统的实时响应,而且对于提高系统效率和提升整体性能方面都有着很大的帮助。希望本文能够对 S3C4510B 系统的开发者有所帮助。参考文献1 杜春雷.ARM 体系结构与编程. 北京:清华大学出版社2 马忠梅,马广云等.ARM 嵌入式处理器结构与应用基础. 北京:北京航空航天大学出版社,2002.63 S3c4510b Data Sheet. SAMSUNG.1999.34 ARM Limited. Developer suit(Version 1.1), Assembler Guide.ARM DUI 0068A,2000浅谈浅谈 ARMARM 启动代码分析启动代码分析理解启动代码(ADS)所谓启动代码,就是处理器在启动的时候执行的一段代码,主要任务是初始化处理器模式,设置堆栈,初始化变量等等.由于以上的操作均与处理器体系结构和系统配置密切相关,所以一般由汇编来编写.具体到 S64,启动代码分成两部分,一是与 ARM7TDMI 内核相关的部分,包括处理器各异常向量的配置,各处理器模式的堆栈设置,如有必要,复制向量到 RAM,以便 remap 之后处理器正确处理异常,初始化数据(包括 RW 与 ZI),最后跳转到 Main.二是与处理器外部设备相关的部分,这和厂商的联系比较大.虽然都采用了 ARM7TDMI 的内核,但是不同的厂家整合了不同的片上外设,需要不同的初始化,其中比较重要的是初始化 WDT,初始化各子系统时钟,有必要的话,进行 remap.这一部分与一般控制器的初始化类似,因此,本文不作重点描述.在进行分析之前,请确认如下相关概念:S64 片上 FLASH 起始于 0 x100000,共 64kB,片上 RAM 起始于 0 x200000,共 16kB.S64 复位之后,程序会从 0 开始执行,此时 FLASH 被映射到 0 地址,因此,S64可以取得指令并执行.显然,此时还是驻留在 0 x100000 地址.如果使用 remap命令,将会把 RAM 映射到 0 地址,同样的这时 0 地址的内容也只是 RAM 的镜像.S64 的 FLASH 可以保证在最差情况时以 30MHz 进行单周期访问,而 RAM可以保证在最大速度时的单周期访问.OK,以下开始分析启动代码.一,处理器异常S64 将异常向量至于 0 地址开始的几个直接,这些是必需要处理的.由于复位向量位于 0,也需要一条跳转指令.具体代码如下:RESETBSYSINIT; ResetBUDFHANDLER; UNDEFINEDBSWIHANDLER; SWIBPABTHANDLER; PREFETCH ABORTBDABTHANDLER; DATA ABORTB .; RESERVEDBVECTORED_IRQ_HANDLERB .; ADD FIQ CODE HERE UDFHANDLERB . SWIHANDLERB . PABTHANDLERB . DABTHANDLERB .请注意,B 指令经汇编后会替换为当前 PC 值加上一个修正值(+/-),所以这条指令是代码位置无关的,也就是不管这条指令是在0地址还是在0 x100000执行,都能跳转到指定的位置,而LDR PC,=将向PC直接装载一个标号的值,请注意,标号在编译过后将被替换为一个与 RO 相对应的值,也就是说,这样的指令无论在哪里执行,都只会跳转到一个指定的位置.下面举一个具体的例子来说明两者的区别:假定有如下程序:RESETBINIT或者 LDRPC,=INITINIT其中RESET为起始时的代码,也就是这条代码的偏移为0,设INIT的偏移量为 offset.如果将这段程序按照 RO=0 x1000000 编译, 那么 B INIT 可理解为 ADD PC, PC, #offset,而 LDRPC,=INIT 可被理解为 MOVPC,#(RO+offset) .显然当系统复位时,程序从 0 开始运行,而 0 地址有FLASH的副本,执行BINIT将把PC指向位于0地址处的镜像代码位置,也即INIT;如果执行 LDRPC,=INIT 将会将 PC 直接指向位于 FLASH 中的原始代码.因此以上两者都能正确运行.下面将 RO 设置为 0 x200000,编译后生成代码,还是得烧写到 FLASH 中,也就是还是 0 x100000,系统复位后从 0 地址执行,还是 FLASH 的副本,此时执行BINIT,将跳到副本中的 INIT 位置执行,此处有对应的代码;但是如果执行 LDRPC,=INIT,将向 PC 加载0 x200000+offset,这将使得PC跳到RAM中,而此时由于代码没有复制,RAM中的指定位置并没有代码,程序无法运行.二,处理器模式ARM的处理器可工作于多种模式,不同模式有不同的堆栈 ,以下设置各模式及其堆栈.预定义一些参数:MODUSREQU0 x10MODSYSEQU0 x1FMODSVCEQU0 x13MODABTEQU0 x17MODUDFEQU0 x1BMODIRQEQU0 x12MODFIQEQU0 x11IRQBITEQU0 x80FIQBITEQU0 x40RAMENDEQU0 x00204000 ; S64 : 16KB RAMVECTSIZE EQU0 x100;UsrStkSzEQU8; size of USR stackSysStkSzEQU12