ARM学习笔记资料

  • 格式:doc
  • 大小:292.50 KB
  • 文档页数:20

ARM学习笔记本课程的主要学习内容1. 基础部分●ARM处理器的基础知识●ARM指令系统●伪操作和伪指令●基于汇编语言的程序设计●ARM存储系统●异常中断处理2.应用部分●基于ARM处理器的C程序设计●DMA过程的实现●利用定时部件实现定时●对I/O端口编程第二章ARM处理器的基础知识2.1 ARM处理器模式2.2 ARM寄存器介绍2.3 ARM存储系统2.4 ARM体系的异常中断2.1 ARM处理器模式1. 处理器模式的分类(1)用户模式(User, user)(2)快速中断模式(FIQ, fiq) ---用于高速数据传输和通道处理(3)外部中断模式(IRQ, irq) ----用于通常的中断处理(4)管理模式(Supervisor, svc)-----供操作系统使用的一种保护模式(5)数据访问中止模式(Abort, abt) ---用于虚拟存储及存储保护(6)未定义指令中止模式(Undefine, und)-----用于支持通过软件仿真硬件的协处理器(7)系统模式(System, sys)-----用于特权级的操作系统任务除了用户模式之外的其它6种模式称为特权模式(Previleged mode).在这些模式下,程序可以访问所有的系统资源.也可以任意地进行处理器模式的切换.其中,除了系统模式以外,其它5种特权模式又称为异常模式.2. 处理器模式的切换(1)处理器模式可以通过软件控制进行切换.也可以通过异常中断的方式进行切换.(2)大多数的应用程序运行在用户模式下.这时,应用程序不能够访问一些受操作系统保护的系统资源.(3)应用程序不能直接进行处理器模式的切换.当需要进行处理器模式切换时,应用程序可以通过异常中,在异常中断的处理过程中实现处理器模式的切换.(4)当应用程序发生异常中断时,处理器进入相应的处理器模式.每一种处理器模式都有一组寄存器,供相应的异常中断程序使用.这样可以保证在进入相应的处理器模式时,用户模式下的寄存器不被破坏.(5)系统模式不是通过异常中断进入的,它和用户模式具有完全一样的寄存器.但系统模式属于特权模式,可以访问所有的系统资源,也可以直接进行处理器模式切换.它主要供操作系统使用.2.2 ARM寄存器介绍ARM处理器共有37个寄存器.其中包括:31个通用寄存器,包括程序计数器(PC)在内.这些寄存器都是32位寄存器.6个状态寄存器.这些寄存器都是32位寄存器.但目前只使用了其中的14位.通用寄存器可分为3类:●未备份寄存器,包括R0-R7●备份寄存器,包括R8-R14●程序计数器PC,即R15●程序状态寄存器CPSR对于备份寄存器R13和R14来说,每个寄存器对应6个不同的物理寄存器.●寄存器R13在ARM中经常用作堆栈指针.现场保护。

●寄存器R14又被称为连接寄存器(LR).主要有两个作用:保存子程序的返回地址保存异常中断程序的返回地址。

当通过BL或BLX指令调用子程序时,R14被设置成该子程序的返回地址。

在子程序中,当把R14的值复制到PC时,就实现了子程序的返回。

MOV PC LR或者BL LR.●程序计数器R15被称为PC.它的值为当前指令的地址值加8个字节.一条ARM指令固定占有4个字节的存储空间.所以PC总是指向当前指令的下两条指令.并且ARM 指令是字对齐的,所以PC的第0位和第1位总是0.●程序状态寄存器CPSRCPSR可以在任何处理器模式下被访问.每一种处理器模式下都有一个专用的物理寄存器,称为备份程序状态寄存器(SPSR).当特定的异常中断发生时,这个寄存器用于存放当前程序状态寄存器的内容.在异常中断程序退出时,可以用SPSR的内容来恢复CPSR.由于用户模式和系统模式不是异常中断模式,所以它们没有SPSR.CPSR是一个32位的寄存器2.3 ARM存储系统●ARM存储系统中1个字单元包含4个字节单元.●ARM存储系统中引入了半字的概念,1个半字单元包含2个字节单元.●小端存储格式----高位地址保存高位数据大端存储格式----高位地址保存低位数据●ARM存储系统的默认存储格式是小端存储格式2.4 ARM体系的异常中断●保存被中断程序:SPSR_mode ←CPSRR14_mode ←return address●恢复被中断程序:CPSR ←SPSR_modePC ←R14_modeCPSR是指用户模式的程序状态寄存器SPSR_mode是指即将进入的异常模式的备份程序状态寄存器R14_mode是指即将进入的异常模式的连接寄存器return_address是指异常中断处理程序的返回地址第三章寻址方式3.1 ARM指令的基本特点3.2 数据处理指令的操作数寻址方式3.3 Load/Store指令的操作数寻址方式3.1 ARM指令的基本特点●一条ARM指令的字长为固定的32位,需要4个字节的存储空间.一条典型的ARM指令的语法格式如下所示:<OPCODE> {<COND>} {S} <Rd>, <Rn>, <Shifter_operand><OPCODE>: 指令的助记符,如ADD,MOV等等.{<COND>}: 指令的执行条件.{S}: 决定指令的运行是否影响CPSR值<Rd>: 表示目标寄存器<Rn>: 表示包含第一个操作数的寄存器<shifter_operand>: 表示第二个操作数2.2 数据处理指令的操作数寻址方式<shifter_operand>通常具有以下3种格式(1)立即数方式ADD R0, R0, #2 ;R0←R0+21.如十六进制数在0x00到0xFF之间,则它一定是合法的1.若十六进制数>0XFF则将十六进制的数转化成十进制2.如果这个十进制数能够被4整除则这个十六进制的立即数和合法的,否则是非法的3例如:0x101=257/4=64.25 非法0x104=260/4=65 合法(2)寄存器方式ADD R0, R0, R1 ;R0←R0+R1(3)寄存器移位方式移位方式有以下的几种形式●ASR 算术右移最高有效位右移,同时用自身填入,最低位移C可以实现带符号数的除2运算例:ADD R0, R1, R2, ASR #1;R0←R1+R2/2●LSL 逻辑左移最低位补0,最高位移入C实现无符号数的乘2运算例:ADD R0, R1, R2, LSL #2 ;R0←R1+R2*4●LSR 逻辑右移最高位补0,最低位移入C实现无符号数的除2运算例:MOV R3, #2ADD R0, R1, R2, LSR R3 ;R0←R1+R2/4●ROR循环右移例: MOV R0, R0, ROR #8将R0循环右移8位●RRX 扩展的循环右移例: MOV R0, R0, RRXC←R0[0]R0[31]←C原来的值RRX操作只能右移1位2.3 Load/Store指令的操作数寻址方式●Load指令用于从内存中读取数据到寄存器中.指令的助记符为LDR.●Store指令用于将寄存器中的数据保存到内存中.指令的助记符为STR.●批量的Load/Store指令可以实现一组寄存器和一块连续的内存单元之间传输数据.各类型的Load/Store指令的寻址方式由两部分组成.一部分为一个基址寄存器,另一部分为一个地址偏移量.基址寄存器可以是任一个通用寄存器,地址偏移量有以下三种格式.(1)立即数(2)寄存器(3)寄存器及一个移位常数在寻址方式中,地址的计算方法有3种(1)偏移量方法(2)事先更新方法在这种方法中,基址寄存器中的值和地址偏移量作加减运算,生成操作数的地址.指令执行后,这个生成的操作数地址被写入基址寄存器.(3)事后更新方法在这种方法中,指令将基址寄存器的值作为操作数的地址执行内存访问.基址寄存器中的值和地址偏移量做加减运算,生成操作数的地址.指令执行后,这个生成的操作数地址被写入基址寄存器.(1)基本的Load/Store指令[<Rn>, #+/-<offset_12>]<Rn>为地址寄存器<offset_12>为12位的地址偏移量例: LDR R0, [R1, #4] ;R0←[R1+4]LDR R0, [R1, #-4] ;R0←[R1-4][<Rn>, #+/-<Rm>]例: LDR R0, [R1, R2] ;R0←[R1+R2]LDR R0, [R1, -R2] ;R0←[R1-R2][<Rn>, #+/-<Rm>, <shift> #<shift_imm>]<Rm>为寄存器中的数值经过移位或循环移位后生成的地址偏移量<shift>为移位运算符<shift_imm>为移位或循环移位的位数例: LDR R0, [R1, R2, LSL #2] ;R0←[R1+R2*4][<Rn>, #+/-<offset_12>]!<Rn>为基址寄存器<offset_12>为12位的地址偏移量!表示采用了事先更新方法.在这种方法中基址寄存器中的值和地址偏移量作加减运算,生成操作数的地址.指令执行后,这个生成的操作数地址被写入基址寄存器.例: LDR R0, [R1, #4] ;R0←[R1+4]LDR R0, [R1, #4]! ;R0←[R1+4], R1←R1+4[<Rn>, #+/-<Rm>]!例: LDR R0, [R1, R2] ;R0←[R1+R2]LDR R0, [R1, R2]! ;R0←[R1+R2], R1←R1+R2[<Rn>, #+/-<Rm>, <shift> #<shift_imm>]!<Rn>为地址寄存器<Rm>为寄存器中的数值经过移位或循环移位后生成的地址偏移量<shift>为移位运算符<shift_imm>为移位或循环移位的位数例: LDR R0, [R1, R2, LSL #2] ;R0←[R1+R2*4]LDR R0, [R1, R2, LSL #2]! ;R0←←R1+R2*4[<Rn>], #+/-<offset_12><Rn>为地址寄存器<offset_12>为12位的地址偏移量这种寻址方式采用了事后更新方法.在这种方法中,指令将基址寄存器的值作为操作数的地址执行内存访问.基址寄存器中的值和地址偏移量做加减运算,生成操作数的地址.指令执行后,这个生成的操作数地址被写入基址寄存器.例: LDR R0, [R1, #4] ;R0← [R1+4]LDR R0, [R1, #4]! ;R0← [R1+4], R1←R1+4LDR R0, [R1], #4 ;R0← [R1], R1←R1+4[<Rn>], #+/-<Rm>例: LDR R0, [R1, R2] ;R0← [R1+R2]LDR R0, [R1, R2]! ;R0← [R1+R2], R1←R1+R2LDR R0, [R1], R2 ;R0← [R1], R1←R1+R2[<Rn>], #+/-<Rm>, <shift> #<shift_imm>例: LDR R0, [R1, R2, LSL #2] ;R0← [R1+R2*4]LDR R0, [R1, R2, LSL #2]! ;R0←LDR R0, [R1], R2, LSL #2 ;R0← [R1], R1← R1+R2*4(2)批量的Load/Store指令一条批量的Load/Store指令可以实现在一组寄存器和一块连续的内存单元之间传输数据.其语法格式如下LDM {<Cond>}<addressing_mode> <Rn>{!}, <registers>{^}STM {<Cond>}<addressing_mode> <Rn>{!}, <registers>{^}其中,指令中寄存器和内存单元的对应关系满足这样的规则:编号低的寄存器对应于内存中低地址单元,编号高的寄存器对应于内存中高地址单元.<Rn>中存放连续的内存单元中的最低地址值.例:STMFD R13!, {R0-R12, R14};STMDB ←STMFD;R0← [R13-4*14];R1← [R13-4*13];…;R14← [R13-4],R14通常保存返回地址;R13←R13-4*14LDMFD R13!, {R0-R12, PC};R0← [R13];R1← [R13+4];…;PC← [R13+4*13],即PC←R14,子程序返回或中断返回;R13←R13+4*14;R13为堆栈指针,该指令将堆栈中数据装载到寄存器中.;LDMIA ←LDMFD第四章ARM指令集4.1 ARM指令集概述4.2 跳转指令4.3 数据处理指令4.5 内存访问指令4.4 状态寄存器访问指令4.6 异常中断产生指令4.7 Thumb指令集简介4.8 基本的ARM指令功能段ARM指令可以分为6类,即跳转指令,数据处理指令,程序状态寄存器指令,内存访问指令,协处理器指令和异常中断指令.4.2 跳转指令在ARM中有两种方式实现程序的跳转,一种是跳转指令;另一种是直接向PC寄存器(R15)中写入目标地址值.通过直接向PC寄存器中写入目标地址值可以实现在4GB的地址空间中任意跳转.ARM的跳转指令可以从当前指令向前或向后的32MB的地址空间跳转.ARM的跳转指令有以下的4种B跳转指令执行B指令可以跳转到指令中所指定的目标地址.并且B指令仅执行跳转操作.例:B Label ;程序跳转到标号Label处执行BEQ Label ;若Z=1,程序跳转到标号Label处执行BL带返回和跳转的指令BL指令可以跳转到指令中的目标地址,同时将PC(R15)寄存器的值减4后保存在LR(R14)寄存器中.BL指令用于实现子程序调用例:BL func1 ;调用子程序func1…MOV PC, LR ;子程序返回BLX带返回和状态切换的跳转指令(略去)BX带状态切换的跳转指令(略去)4.3 数据处理指令(1)MOV 数据传送指令实现程序跳转MOV PC, LR ;R15←R14实现从异常中断中返回MOVS PC, LR ;R15←R14;CPSR←SPSR_mode(2)ADD 加法指令(3)ADC 带进位加法指令ADC和ADD指令的联合使用可以实现两个64位操作数的相加.假设R0和R1存放一个64位操作数,其中R0保存低位数据;R2和R3存放另一个64位操作数,其中R2存放低位数据.实现这两个操作数相加的指令为ADDS R4, R0, R2 ;影响CPSRADC R5, R1, R3 ;不影响CPSR(4)SUB 减法指令注意:在SUBS指令中,如果发生了借位操作,CSPR寄存器中的C标志位设置为0;如果没有发生借位,CPSR寄存器中的借位标志设置为1.这与ADDS指令正好相反.这主要是为了适应SBC等指令的需要(5)SBC 带借位减法指令SBC和SUB指令的联合使用可以实现两个64位操作数的相减.SUBS R4, R0, R2 ;影响CPSRSBC R5, R1, R3 ;不影响CPSR(6)MUL 乘法指令(8)AND 逻辑与操作指令(10)BIC 位清除指令BIC指令将<shifter_operand>表示的数值的反码与寄存器<Rn>的值进行按位相与操作.并把结果保存到目标寄存器<Rd>中.BIC R0, R0, #%1011 ;将R0中第0位,第1位,第3位清0,其它位不变.%表示后面的数据采用二进制(11)EOR 逻辑异或操作指令(9)ORR 逻辑或操作指令(7)CMP 比较指令(12)TST 位测试指令4.4 状态寄存器访问指令ARM中有两条指令用于在程序状态寄存器和通用寄存器之间传送数据.程序状态寄存器指令包括以下两条MRS程序状态寄存器到通用寄存器的传送指令MSR通用寄存器到程序状态寄存器的传送指令例:下面的指令段将当前的处理器模式切换到管理模式MRS R0, CPSR ;读取CPSRBIC R0, R0, #0x1F ;修改,去除当前的处理器模式ORR R0, R0, #0x13 ;修改,设置管理模式MSR CPSR_c, R0 ;写回,仅仅修改CPSR中的控制位域4.5 内存访问指令(Load/Store指令)(1)LDRB指令LDRB指令用于从内存中将一个8位的字节数据读取到指令中的目标寄存器中,并将寄存器的高24位清零.指令的语法格式LDR {<cond>}B <Rd>, <addressing_mode>LDRB R0, [R2, #3] ; 将内存单元(R2+3)中的字节数据读取到R0中,R0的高24位清零(2)STRB指令STRB指令将一个8位的字节数据写入到指令中指定的内存单元,该字节数据为指令中存放操作数的寄存器的低8位.指令的语法格式STR {<cond>}B <Rd>, <addressing_mode>STRB R0, [R2, #3] ;将R0中的低8位数据保存到内存单元(R2+3)中.4.6 异常中断产生指令(1)SWI软件中断指令4.7 基本的ARM指令功能段4.7.1 基本的指令功能段条件判断语句下面的程序段实现了在满足一定条件下的加法运算CMP R0, #0 ;判断R0是否等于0CMPNE R1, #1 ;如果R0不等于0,判断R1是否等于1ADDEQ R2, R3, R4 ;R0=0或R1=1时,R2=R3+R4循环语句下面的代码段实现了程序的循环执行MOV R0 , #loopcount;初始化循环次数loop…SUBS R0, R0, #1 ;循环计数器减1,同时设置条件标志位BNE loop ;如果循环计数器不为0,跳转到loop处继续执行;如果循环计数器为0,则结束循环.…简单的数据块复制下面的代码段实现简单的数据块复制.程序一次将48个字数据从R12作为首地址的一段连续的内存单元复制到R13作为首地址的一段连续的内存单元.代码执行前R12为源数据区首地址,R13为目标数据区首地址,R14为源数据区末地址.loopLDMIA R12!, {R0-R11} ;从源数据区读取48个字STMIA R13!, {R0-R11} ;将48个字保存到目标数据区CMP R12, R14 ;是否到达源数据结尾BLO loop ;没有到达则继续复制链表操作下面的代码段在链表中搜索与某一数据相等的元素.链表的每个元素包括两个字,第1个字包含1个字节的数据;第2个字是指向下一个链表元素的指针.当这个指针为0时表示链表结束.代码执行前R0指向链表的头元素,R1中存放要搜索的数据;代码执行后R0指向第1个匹配的元素,或者当没有匹配元素时,R0为0.llsearchCMP R0, 0 ;R0指针是否指向链表尾部LDRNEB R2, [R0] ;读取当前链表元素中的字节数据CMPNE R1, R2 ;判断当前元素是否为需要搜索的数据LDRNE R0, [R0, #4] ;如果不是,指针R0指向下一个元素BNE llsearch ;如果下一个元素存在,跳转到llsearch处执行MOV PC, LR ;搜索完成,程序返回简单的串比较下面的代码段实现比较两个串的大小.代码执行前,R0指向第1个串,R1指向第2个串.代码执行后R0中保存比较结果,如果两个串相同,R0为0;如果第1个串大于第2个串,R0>0;如果第1个串小于第2个串,R0<0.strcmpLDRB R2, [R0], #1 ;从第1个串读取字节数据到R2中LDRB R3, [R1], #1 ;从第2个串读取字节数据到R3中CMP R2, #0 ;判断第1个串是否已经搜索完了CMPNE R3, #0 ;判断第2个串是否已经搜索完了BEQ return ;如果任一个串搜索完了,跳转到returnCMP R2, R3 ;如果两个串均未搜索完,比较两个串中的对应元素BEQ strcmp ;如果两个元素相等,继续比较后面的元素returnSUB R0, R2, R3 ;判断两个串的大小关系MOV PC, LR ;程序返回多路跳转下面的代码段通过函数地址表实现多路跳转.其中,maxindex为跳转的最大索引号,R0跳转的索引号.CMP R0, #maxindex ;判断索引号是否超过了最大索引号LDRLO PC, [PC, R0, LSL #2] ;如果没有超过,跳转到相应的程序处B IndexOutOfRange ;如果超过,跳转到错误程序处理处DCD Handler0 ;子程序0的地址DCD Handler1 ;子程序1的地址DCD Handler2 ;子程序2的地址…4.7.2 与系统相关的指令功能段SWI中断处理程序示例SWI指令使处理器切换到管理模式,在管理模式下请求特定的系统服务(这些系统服务通常由操作系统提供).当SWI指令执行时通常完成下面的操作指令的下一条指令的地址;将返回地址赋给管理模式中的R14寄存器SPSR_svc=CPSR ;保存当前CPSRCPSR[4:0]=0b10011 ;使处理器切换到管理模式CPSR[5]=0 ;使程序进入ARM状态CPSR[7]=1 ;禁止正常的中断响应if high vectors configured then ;程序跳转到相应的中断向量处PC=0xFFFF0008 ;使用高端向量elsePC=0x00000008 ;使用正常向量下面的代码段是SWI中断处理程序的基本框架.SWI中断向量存放在内存单元0x00000008处.通常在该地址处放一条跳转指令.其目标地址为下面代码段的首地址.在下面的代码段中,程序保存了相关的寄存器,接着提取SWI指令中的立即数,以确定SWI指令中的立即数,以确定SWI指令请求的具体服务.对于ARM状态和Thumb状态分别得到24位和8位立即数.根据得到的立即数程序跳转到相应的代码处执行.在下面的代码段中,仅仅保存了寄存器R0-R3,R12和LR(R14).如果实际代码还用到了其它的寄存器,可以修改代码中的寄存器列表,也可以在各个具体的服务程序中保存各自用到的寄存器.SWIHandlerSTMFD sp!, {r0-r3, r12, lr} ;保存相关的寄存器MRS r0, spsr ;将SPSR内容传送到R0中TST r0, #0x20 ;判断程序状态是否为ARM状态LDRNE r0, [lr, # -2] ; 如果是Thumb状态,提取指令中的8位立即数BICNE r0, r0, #0xff00LDREQ r0, [lr, # -4] ; 如果是ARM状态,提取指令中的24位立即数BICEQ r0, r0, #0xff000000CMP r0, #MaxSWI ;判断请求的服务的序号是否超过合法的范围LDRLS pc, [pc, r0, LSL #2] ;如果没有超出合法范围,跳转到相应的服务程序执行B SWIOutOfRange ;如果超出了合法范围,跳转到错误处理程序.Switable ;下面是各服务程序的地址表DCD do_swi_0;立即数为0时,对应的服务程序的入口地址DCD do_swi_1 ;立即数为1时,对应的服务程序的入口地址…do_swi_0 ;服务程序do_swi_0的代码…LDM sp!, {r0-r3, r12, pc}^do_swi_1 ;服务程序do_swi_1的代码…(2)IRQ中断处理程序示例在ARM中,外部中断管理器或外设通过使能ARM处理器中的IRQ输入引脚产生IRQ异常中断.CSPR寄存器中的I 控制位设置为1时禁止ARM处理器响应IRQ中断请求,CPSR 寄存器中的I控制位设置为0时ARM处理器在指令边界处检查是否有IRQ中断请求.ARM处理器响应IRQ中断请求时,完成以下工作R14_irq←PC ;保存当前PC值SPSR_irq=CPSR ;保存CPSRCPSR[4:0]=0b100010 ;将处理器模式切换到IRQ模式CPSR[5]=0 ;进入ARM状态CPSR[7]=1 ;禁止常规中断if high vectors configured then ;跳转到IRQ异常中断的中断向量PC=0xFFFF0018 ;使用高端向量elsePC=0x00000018 ;使用正常向量下面的代码段是IRQ中断处理程序的基本框架.通常,IRQ中断向量存放在内存单元0x00000018处.通常在该地址处放一条跳转指令,其目标地址为下面代码段的首地址.外围中断管理硬件将所有的IRQ异常中断请求按优先级排队,并把优先级最高的IRQ异常中断的相关信息保存到寄存器中.IRQ中断处理程序读取这些信息,并跳转到相应的代码处执行.;保存工作寄存器,返回地址和当前程序现场SUB r14, r14, #4 ;调整R14值,使其指向发生IRQ中断的指令的下一条指令STMFD r13!, {r12, r14} ;保存返回地址和相关的寄存器,r13为栈指针.MRS r12, SPSR ;保存SPSRSTMFD r13!, {r12}MOV r12, #IntBase ;读取中断控制器的基地址LDR r12, [r12, #IntLevel] ;读取优先级最高的中断号MRS r14, CPSR ;读取CPSRBIC r14, r14, #0x80 ;清除中断禁止位MSR CPSR_c, r14 ;将R14的值写入CPSR LDR PC, [PC, r12, LSL #2];跳转到当前IRQ对应的中断处理程序NOP ;插入该指令是为了实现正确跳转DCD Priority0Handler ; Priority0Handler的地址DCD Priority1Handler ; Priority1Handler的地址…Priority0Handler ; Priority0Handler的程序体STMFD r13!, {r0-r11} ;保存工作寄存器组…MRS r12, CPSR ; 修改CPSR的相关位,禁止响应中断ORR r12, r12, #0x80MSR CPSR_c, r12LDMFD r13!, {r0-r12} ;恢复工作寄存器组和SPSR MSR SPSR_cxsf, r12LDMFD r13!, {r12, PC}^ ; 恢复所有寄存器组并返回Priority1Handler ; Priority1Handler的程序体…(3)进程切换进程是操作系统中任务调度的基本单位.每个进程由一个控制块PCB来表示.进程间切换就是通过某种方式保存当前进程的PCB,加载新进程的PCB到处理器中.这里介绍的仅仅是一个简单的演示性的例子,通过下面的约定使这个例子简单并且清晰一些.这里讨论的是用户模式下的进程间的切换.切换过程是通过IRQ中断处理程序完成的.比如在进程1执行到特定时机时,希望切换到进程2.这时系统产生IRQ中断,首先执行常规的中断处理操作,然后判断是返回被中断的进程1,还是切换到新的进程2执行.这里仅仅讨论用户模式下进程间的切换.如果在特权模式下发生了IRQ中断,中断处理程序一定要回到被中断的进程.这里假设IRQ中断处理程序仅仅保存寄存器R0-R3,R12和R14;使用R13作为栈指针;栈的类型为FD型.在中断处理程序中始终禁止中断,也不进行处理器模式的切换.这里假设进程控制块格式为从低地址到高地址依次为下列寄存器:CPSR,返回地址,R0-R14.下面分三部分介绍进程切换的过程在进入IRQ中断处理程序时,首先计算返回地址,并保存相关的寄存器.SUB r14, r14, #4;使r14指向发生中断的指令的下一条指令STMFD R13!, {R0-R3, R12, R14};保存R0-R3,R12和R14如果IRQ中断处理程序返回到被中断的进程,则执行下面的指令.该指令从数据栈中恢复寄存器R0-R3及R12的值,将返回地址传送到PC中,并将SPSR_irq值复制到CPSR中.LDMFD R13!, {R0-R3, R12, PC}^如果IRQ切换到新的进程,则要保存被中断的进程的PCB,然后加载新进程的PCB到处理器中.;保存被中断的进程的PCB,该PCB存放在R0所指向的连续的内存单元MRS R12, SPSR ;读取被中断的进程的CPSRSTR R12, [R0], #8 ;将其保存到R0指向的内存单元,并更新R0值;R0=R0+8LDMFD R13!, {R2, R3} ;读取被中断进程的R0和R1STMIA R0!, {R2, R3} ;将其保存到R0指向的内存单元,并更新R0的值LDMFD R13!, {R2, R3, R12, R14} ;读取栈中的其它数据STR R14, [R0, #-12] ;将返回地址值R14保存在PCB中的第2个字单元,即CPSR之后STMIA R0, {R2-R14}^ ;保存其它所有的寄存器;将新进程的PCB中的内容加载到处理器中,其中R1指向新进程的PCBLDMIA R1!, {R12, R14} ;恢复CPSR及R14MSR SPSR_fxsc, R12LDMIA R1, {R0-R14}^ ;恢复R0-R14NOP ;因为在用户模式下的LDM指令后不能立即操作备份寄存器,故插入本指令.MOVS PC, R14 ; 切换到新进程执第五章伪操作5.1 伪操作概述5.2 符号定义伪操作5.3 数据定义伪操作5.4 伪指令5.5 用于程序说明的伪操作5.6 程序设计实例5.1 伪操作概述ARM汇编语言源程序中语句由指令和伪操作组成.指令在程序运行期间由机器执行.而伪操作是在编译期间由汇编程序进行处理.伪操作的作用主要有:符号定义,数据定义,汇编控制,框架描述,信息报告等.5.2 符号定义伪操作●GBLA, GBLL和GBLSGBLA Var1 ;声明一个全局算术变量并将其初始化为0GBLL Var2 ;声明一个全局逻辑变量并将其初始化为{FALSE}GBLS Var3 ;声明一个全局字符串变量并将其初始化为空串●LCLA, LCLL和LCLSLCLA Var1 ;声明一个局部算术变量并将其初始化为0LCLL Var2 ;声明一个局部逻辑变量并将其初始化为{FALSE}LCLS Var3 ;声明一个局部字符串变量并将其初始化为空串●SETA, SETL及SETSSETA给一个算术变量赋值GBLA Var1Var1 SETA 0xffSETL给一个逻辑变量赋值GBLL Var2Var2 SETL {TRUE} SETS给一个字符串变量赋值GBLS Var3Var3 SETS “ABC”●RLISTRLIST为一个通用寄存器列表定义名称.其语法格式为name RLIST {list_of_rigisters}其中:name是寄存器列表的名称{list_of_rigisters}为通用寄存器列表lst1 RLIST {R0-R6} ;将寄存器列表名称定义为lst15.3 数据定义伪操作●SPACESPACE指令用于分配一块内存单元,并将内存单元初始化为0语法格式为{Label} SPACE exprData1 SPACE 280 ;分配280字节的内存单元并将内存单元初始化为0●DCBDCB用于分配一段字节内存单元.语法格式为{Label} DCB exprStr1 DCB “ABC”,0 ;为字符串分配内存空间字符串以0为结束标志●DCDDCD用于分配一段字内存单元.语法格式为{Label} DCD exprData1 DCD 1, 2, 5 ;分配了3个字单元,其值为1 ,2和55.4 伪指令ADRADR指令将标号相对于PC的偏移量加载到寄存器中语法格式为ADR{cond} register, exprADR指令在编译过程中会被转化为一条机器指令label M OV R1, #10ADR R3, label ;编译为SUB R3, PC, #0x0CADRLADRL指令将标号相对于PC的偏移量加载到寄存器中,ADRL指令被汇编为两条数据处理指令,因而允许更大的地址偏移量.语法格式为ADRL{cond} register, exprstart MOV R0, #10ADRL R4, start+60000ADRL指令被汇编为下面两条指令ADD R4, PC, #0xE800 ;0xE800=59392ADD R4, R4, #0x254 ;0x254=596LDRLDR指令将标号相对于PC的偏移量加载到寄存器中.如果加载到寄存器中的数据不超过MOV指令可以操作的范围,则被汇编成MOV指令;如果超出,则加载基于PC寄存器的地址偏移量.语法格式为LDR{cond} register, expr✧LDR R1, =0xFF0汇编后将得到MOV R1, 0xFF0 ;MOV指令的操作数最大为0xFFF✧LDR R1, =ADDR1汇编后得到LDR R1, [PC, OFFSET_TO_LPOOL]…LPOOL DCD ADDR15.5 用于程序说明的伪操作◆CODE16及CODE32CODE16说明后面的指令序列为16位的Thumb指令CODE32说明后面的指令序列为32位的ARM指令在下面的例子中,程序先在ARM状态下执行,然后通过BX指令切换到Thumb状态,并跳转到相应的Thumb指令处执行.在Thumb程序入口处用CODE16标识下面的指令为Thumb 指令AREA ChangeState, CODE, READONL Y。