第4章ARM处理器指令概述.ppt
第4章ARM处理器指令概述,本章重点,常用ARM指令 ARM汇编程序编程实例 汇编与C语言混合编程 ADS集成开发环境,本章内容,4.1 ARM 微处理器的指令的分类与格式 4.2 ARM 指令的寻址方式 4.3 常用ARM指令 4.4 汇编语言的程序结构及在ADS环境下调试 4.5 汇编语言与 C/C+的混合编程,4.1 ARM 微处理器的指令的分类与格式,ARM微处理器的指令集是加载/存储型的,也即指令集仅能处理寄存器中的数据,而且处理结果都要放回寄存器中,而对系统存储器的访问则需要通过专门的加载/存储指令来完成。ARM微处理器的指令集可以分为跳转指令、数据处理指令、程序状态寄存器(PSR)处理指令、加载/存储指令、协处理器指令和异常产生指令六大类。,4.2 ARM 指令的寻址方式,所谓寻址方式就是处理器根据指令中给出的地址信息来寻找物理地址的方式。目前ARM指令系统支持如下几种常见的寻址方式。4.2.1 立即寻址立即寻址也叫立即数寻址,这是一种特殊的寻址方式,操作数本身就在指令中给出,只要取出指令也就取到了操作数。这个操作数被称为立即数,对应的寻址方式也就叫做立即寻址。例如以下指令:ADD R0,R0,1;R0R01 ADD R0,R0,0 x3f;R0R00 x3f 在以上两条指令中,第二个源操作数即为立即数,要求以“”为前缀,对于以十六进制表示的立即数,还要求在“”后加上“0 x”或“&”。,4.2 ARM 指令的寻址方式,4.2.2 寄存器寻址 寄存器寻址就是利用寄存器中的数值作为操作数,这种寻址方式是各类微处理器经常采用的一种方式,也是一种执行效率较高的寻址方式。以下指令:ADD R0,R1,R2;R0R1R2该指令的执行效果是将寄存器R1和R2的内容相加,其结果存放在寄存器R0中。4.2.3 寄存器间接寻址 寄存器间接寻址就是以寄存器中的值作为操作数的地址,而操作数本身存放在存储器中。例如以下指令:ADD R0,R1,R2;R0R1R2 LDR R0,R1;R0R1 STR R0,R1;R1R0在第一条指令中,以寄存器 R2 的值作为操作数的地址,在存储器中取得一个操作数后与 R1 相加,结果存入寄存器 R0 中。第二条指令将以 R1 的值为地址的存储器中的数据传送到 R0 中。第三条指令将 R0 的值传送到以 R1 的值为地址的存储器中。,4.2 ARM 指令的寻址方式,4.2.4 基址变址寻址 基址变址寻址就是将寄存器(该寄存器一般称作基址寄存器)的内容与指令中给出的地址偏移量相加,从而得到一个操作数的有效地址。变址寻址方式常用于访问某基地址附近的地址单元。采用变址寻址方式的指令常见有以下几种形式,如下所示:LDR R0,R1,#4;R0R14 LDR R0,R1,#4!;R0R14、R1R14 LDR R0,R1,#4;R0R1、R1R14 LDR R0,R1,R2;R0R1R2 在第一条指令中,将寄存器 R1 的内容加上 4 形成操作数的有效地址,从而取得操作数存入寄存器 R0 中。在第二条指令中,将寄存器 R1 的内容加上 4 形成操作数的有效地址,从而取得操作数存入寄存器 R0 中,然后,R1 的内容自增 4 个字节。在第三条指令中,以寄存器 R1 的内容作为操作数的有效地址,从而取得操作数存入寄存器 R0中,然后,R1 的内容自增 4 个字节。在第四条指令中,将寄存器 R1 的内容加上寄存器 R2 的内容形成操作数的有效地址,从而取得操作数存入寄存器 R0 中。,4.2 ARM 指令的寻址方式,4.2.5 多寄存器寻址 采用多寄存器寻址方式,一条指令可以完成多个寄存器值的传送。这种寻址方式可以用一条指令完成传送最多 16 个通用寄存器的值。以下指令:LDMIA R0,R1,R2,R3,R4;R1R0;R2R04;R3R08;R4R012该指令的后缀 IA 表示在每次执行完加载/存储操作后,R0 按字长度增加,因此,指令可将连续存储单元的值传送到 R1R4。4.2.6 相对寻址 与基址变址寻址方式相类似,相对寻址以程序计数器 PC 的当前值为基地址,指令中的地址标号作为偏移量,将两者相加之后得到操作数的有效地址。以下程序段完成子程序的调用和返回,跳转指令 BL 采用了相对寻址方式:BL NEXT;跳转到子程序 NEXT 处执行 NEXT MOV PC,LR;从子程序返回,4.2 ARM 指令的寻址方式,4.2.7 堆栈寻址 堆栈是一种数据结构,按先进后出(First In Last Out,FILO)的方式工作,使用一个称作堆栈指针的专用寄存器指示当前的操作位置,堆栈指针总是指向栈顶。当堆栈指针指向最后压入堆栈的数据时,称为满堆栈(Full Stack),而当堆栈指针指向下一个将要放入数据的空位置时,称为空堆栈(Empty Stack)。同时,根据堆栈的生成方式,又可以分为递增堆栈(Ascending Stack)和递减堆栈(Decending Stack),当堆栈由低地址向高地址生成时,称为递增堆栈,当堆栈由高地址向低地址生成时,称为递减堆栈。这样就有四种类型的堆栈工作方式,ARM 微处理器支持这四种类型的堆栈工作方式,即:满递增堆栈:堆栈指针指向最后压入的数据,且由低地址向高地址生成。满递减堆栈:堆栈指针指向最后压入的数据,且由高地址向低地址生成。空递增堆栈:堆栈指针指向下一个将要放入数据的空位置,且由低地址向高地址生成。空递减堆栈:堆栈指针指向下一个将要放入数据的空位置,且由高地址向低地址生成。,4.3 常用ARM指令,4.3.1 内存访问指令 1.基本指令 LDR:存储器memory中数据传送到寄存器register STR:寄存器register中数据传送到存储器memory例如:ldrr0,r1;r1作为指针,该指针指向的数存入r0strr0,r1,#4;r1+4作为指针,r0的值存入该地址strr0,r1,#4!;同上,并且r1=r1+4ldrr1,=0 x08100000;立即数0 x08100000存到r1ldrr1,r2,#4;r2+4作为指针,指向的值存入r1,并且r2=r2+4,4.3 常用ARM指令,4.3.1 内存访问指令 2.多字节存取指令 多字节存取指令常应用于堆栈操作。LDM:存储器memory中数据传送到多个寄存器STM:多个寄存器中的数据传送到存储器memory例如:sub lr,lr,#4;lr4是异常处理完后应该返回的地方stmfdsp!,r0-r12,lr;保存r0r12和lr寄存器的值到堆栈并更新堆栈指针。ldmfdsp!,r0-r12,pc;从堆栈中恢复r0r12,返回地址赋给pc指针,使程序返回到异常发生前所执行的地方,标记用来使CPU退出异常模式,进入普通状态。,4.3 常用ARM指令,4.3.2 算术运算指令基本指令:ADD:加SUB:减例如:add r0,r1,r2;r0=r1+r2adds r0,r1,#0 x80;r0=r1+0 x80,并设置状态寄存器subs r0,r1,#2000;r0=r1 2000,并设置状态寄存器,4.3 常用ARM指令,4.3.3 逻辑运算指令 基本指令:AND:与ORR:或EOR:异或BIC:位清0例如:ands r0,r1,#0 xff00;r0=r1 and 0 xff00,并设置状态寄存器orr r0,r1,r2;r0=r1 and r2bics r0,r1,#0 xff00;r0=r1 and!(0 xff00)ands r0,r1,#0 xffff00ff;错误,4.3 常用ARM指令,4.3.4 MOV指令 mov指令:例如:mov r0,#8;r0=8mov r0,r1;r0=r1mov不同于LDR、STR指令,该指令可以在寄存器间赋值。4.3.5比较指令 基本指令:CMP:比较两个操作数,并设置状态寄存器例如:cmp r0,r1;计算r0-r1,并设置状态寄存器,判断r0是否大于、小于或等于r1cmp r0,#0;,4.3 常用ARM指令,4.3.6 跳转指令 基本指令:B:跳转BL:跳转并将下一指令的地址存入lr寄存器例如:loop1bloop1;跳到地址loop1处blsub1;将下一指令地址写入lr,并跳至sub1sub1mov pc,lr;从sub1中返回,4.3 常用ARM指令,4.3.7 条件执行指令 条件:状态寄存器中某一或某几个比特的值代表条件,对应不同的条件后缀cond。例如:cmp r0,r1;比较r0和r1blgt sub1;如果r0r1,跳转到sub1,否则不操作;一段循环代码ldr r2,=8;r2=8loop;这里可以进行一些循环内的操作subsr2,r2,#1;r2=r2 1,并设置状态位bneloop;如果r2不等于0,则继续循环;movr0,#1;r0=1cmpr2,#8;比较r2和8movltr0,#2;如果r28,r0=2,4.4 汇编语言的程序结构及在ADS环境下调试,在 ARM(Thumb)汇编语言程序中,以程序段为单位组织代码。段是相对独立的指令或数据序列,具有特定的名称。段可以分为代码段和数据段,代码段的内容为执行代码,数据段存放代码运行时需要用到的数据。一个汇编程序至少应该有一个代码段,当程序较长时,可以分割为多个代码段和数据段,多个段在程序编译链接时最终形成一个可执行的映象文件。441 汇编语言程序结构以下是一个汇编语言源程序的基本结构。AREA Init,CODE,READONLYENTRYEND;汇编语言源程序的基本结构,分号为注释AREA EX2,CODE,READONLY;AREA指令定义一个名为EX2程序段,属性为只读,4.4 汇编语言的程序结构及在ADS环境下调试,例4-1 定义一个代码段arm,其属性为只读,首先分别给3个变量赋值,给x、y赋两个值,给stack_top赋一个地址,程序代码如下,请阅读程序写出最后r0的值及调试程序及地址0 x1000上的内容,程序名为test1.s。AREA arm,CODE,READONLY x EQU 45y EQU 64stack_top EQU 0 x1000ENTRYMOV sp,#stack_topMOV r0,#xSTR r0,spMOV r0,#yLDR r1,spADD r0,r0,r1STR r0,spStopB StopEND,4.4 汇编语言的程序结构及在ADS环境下调试,442 汇编语言编辑、运行与调试 1、运行 ADS1.2 集成开发环境,点击 File|New,在 New 对话框中,选择 Project中的ARM Executable Image 选项,在 Project name 栏中输入项目的名称,按“确定”保存项目。,4.4 汇编语言的程序结构及在ADS环境下调试,2、在新建的工程中,选择Debug 版本,如图4-2,使用Edit|Debug Settings 菜单对Debug版本进行参数设置。,4.4 汇编语言的程序结构及在ADS环境下调试,3、在如图4-3 中,点击Debug Setting 按钮,弹出4-4 图,选中Target Setting 项,在Post-linker 栏中选中ARM fromELF 项。按OK 确定。这是为生成可执行的代码的初始开关。,4.4 汇编语言的程序结构及在ADS环境下调试,4.4 汇编语言的程序结构及在ADS环境下调试,4、在如图4-5 中,点击ARM Assembler,在Architecture or Processer 栏中选ARM9TDMI。这是要编译的CPU 核。,4.4 汇编语言的程序结构及在ADS环境下调试,5、在如图4-6 中,点击ARM C Compliler,在Architecture or Processer 栏中选ARM9TDMI。这是要编译的CPU 核。,4.4 汇编语言的程序结构及在ADS环境下调试,6、在如图4-7 中,点击ARM linker,在output 栏中设定程序的代码段地址,以及数据使用的地址。图中的RO Base 栏中填写程序代码存放的起始地址,RW Base 栏中填写程序数据存放的起始地址。该地址是属于SDRAM 的地址。,4.4 汇编语言的程序结构及在ADS环境下调试,在options 栏中,如图4-8,Image entry point 要填写程序代码的入口地址,其他保持不变,如果是在SDRAM 中运行,则可在0 x0c0000000 x0cffffff 中选值,这是16MSDRAM 的地址,但是这里用的是起始地址,所以必须把你的程序空间给留出来,并且还要留出足够的程序使用的数据空间,而且还必须是4字节对齐的地址(ARM 状态)。通常入口点Image entry point 为0 xc100000,ro_base 也为0 xc100000。,4.4 汇编语言的程序结构及在ADS环境下调试,在Layout 栏中,如图4-9,在Place at beginning of image 框内,需要填写项目的入口程序的目标文件名,如,整个工程项目的入口程序是44binit.s,那么应在Object/Symbol 处填写其目标文件名44binit.o,在Section 处填写程序入口的起始段标号。它的作用是通知编译器,整个项目的开始运行,是从该段开始的。,4.4 汇编语言的程序结构及在ADS环境下调试,7、在如图4-10 中,即在Debug Setting 对话框中点击左栏的ARM fromELF 项,在Output file name 栏中设置输出文件名*.bin,前缀名可以自己取,在Output format 栏中选择Plain binary,这是设置要下载到flash 中的二进制文件。图4-10 中使用的是test.bin.。,4.4 汇编语言的程序结构及在ADS环境下调试,8、装载文件test1.s,在如图4-11所示工程test1.mcp中File的空白处点击右键,选择菜单项Add Files,导入文件test1.s,并作图4-12的选项。,4.4 汇编语言的程序结构及在ADS环境下调试,9、在ADS1.2 集成开发环境(CodeWarrior for ARM Developer Suite)选择菜单Project|Debug。10、如果是模拟调试,选择AXD中菜单OptionsConfigure Target选择ARMUL,如图-11所示。,4.4 汇编语言的程序结构及在ADS环境下调试,11、程序调试(1)查看/修改存储器内容在AXD窗口中,点击Processor Views|Memory,可以在Memory start address输入存储器的起始地址,查看存储器某地址上的内容,双击某一数据,可以修改此存储单元的内容。(2)在命令行窗口执行AXD命令 在AXD窗口中,点击System Views|Command Line Interface,在提示符下可以输入命令进行调试。(3)监视变量变化在AXD窗口中,点击Processor Views|Watch,用鼠标选中某变量,单击鼠标右键,在弹出的菜单中选中Add to watch,此变量显示在watch窗口中。,4.4 汇编语言的程序结构及在ADS环境下调试,(4)设置断点 将光标定位在要设置断点的某语句处,按F9键。调试的结果如图4-12所示,图中显示了断点、Watch中寄存器的值、存储器从起始地址0 x1000开始的存储内容。,4.5 汇编语言与 C/C+的混合编程,在应用系统的程序设计中,若所有的编程任务均用汇编语言来完成,其工作量是可想而知的,同时,不利于系统升级或应用软件移植,事实上,ARM 体系结构支持 C/C+以及与汇编语言的混合编程,在一个完整的程序设计的中,除了初始化部分用汇编语言完成以外,其主要的编程任务一般都用C/C+完成。汇编语言与C/C+的混合编程通常有以下几种方式:1 在C/C+代码中嵌入汇编指令。2在汇编程序和C/C+的程序之间进行变量的互访。3汇编程序、C/C+程序间的相互调用。,4.5 汇编语言与 C/C+的混合编程,在以上的几种混合编程技术中,必须遵守一定的调用规则,如物理寄存器的使用、参数的传递等,这对于初学者来说,无疑显得过于烦琐。在实际的编程应用中,使用较多的方式是:程序的初始化部分用汇编语言完成,然后用C/C+完成主要的编程任务,程序在执行时首先完成初始化过程,然后跳转到C/C+程序代码中,汇编程序和C/C+程序之间一般没有参数的传递,也没有频繁的相互调用,因此,整个程序的结构显得相对简单,容易理解。.C程序调用汇编程序 1C程序嵌入汇编指令汇编指令以语句块形式嵌入在C程序的函数中,其使用格式为:_asm 汇编语句 汇编指令以函数形式嵌入在C程序的函数中,其使用格式为:_asm int 函数名(形式参数表)汇编代码,4.5 汇编语言与 C/C+的混合编程,(1)汇编指令以语句块形式嵌入在C程序中例如:在C程序中嵌入汇编语句的例子。#includeint add(int i,int j)int sum;_asm ADD sum,i,j return sum;int main()int x,y;scanf(%d%d,请建立一个工程,调试上述程序。,4.5 汇编语言与 C/C+的混合编程,(2)在C程序中调用以函数形式构成的汇编指令 C程序调用汇编程序时,汇编程序的书写也要遵循ATPCS规则,以保证程序调用时参数正确传递。在C程序中调用汇编子程序的方法为:首先在汇编程序中使用EXPORT伪指令声明被调用的子程序,表示该子程序将在其他文件中被调用;然后在C程序中使用extern关键字声明要调用的汇编子程序为外部函数。例如:在一个汇编源文件中定义了如下求和函数。EXPORT add;声明add子程序将被外部函数调用add;求和子程序addADD r0,r0,r1MOV pc,lr在一个C程序的main()函数中对add汇编子程序进行了调用:extern int add(int x,int y);/声明add为外部函数void main()int a=1,b=2,c;c=add(a,b);/调用add子程序当main()函数调用add汇编子程序时,变量a、b的值会给了r0和r1,返回结果由r0带回,并赋值给变量c。函数调用结束后,变量c的值变成3。,4.5 汇编语言与 C/C+的混合编程,例如:1、建立文件add.s,代码如下:EXPORT addAREA add,CODE,READONLYENTRYADD r0,r0,r1MOV pc,lrEND2、C程序代码为:#includeextern int add(int x,int y);int main()int x,y;scanf(%d%d,4.5 汇编语言与 C/C+的混合编程,3、程序调试方法(1)首先建立一个工程test(2)按照图-所示建立源程序main.c与add.s,请注意选中”Add to Project”,并分别输入源程序与汇编源程序。,4.5 汇编语言与 C/C+的混合编程,(3)在图-中设置inker中utput的ase地址设为x400000,。,4.5 汇编语言与 C/C+的混合编程,(4)设置程序开始执行的地址,如图-所示。,4.5 汇编语言与 C/C+的混合编程,(5)如图-所示,设置程序从main.o开始执行。,4.5 汇编语言与 C/C+的混合编程,(6)执行菜单rocject下的make命令,编译程序。(7)执行程序run,如图-所示。,4.5 汇编语言与 C/C+的混合编程,4.5.2 汇编程序调用C程序 从汇编程序调用程序,格式较为简单。其格式为:BL C函数名 例题1、新建一个工程项目test3.mcp2、新建一个init.s文件,这个程序是该项目文件的入口程序,程序代码为:AREA asm,CODE,READONLYIMPORT addENTRYLDR r0,=0 x1LDRr1,=0 x20LDR r2,=0 x2BLadd;result saved in r0B.END,4.5 汇编语言与 C/C+的混合编程,3、新建一个main.c程序,程序代码为:int add(int a,int b,int c)int sum=0,i;for(i=a;i=b;i=i+c)sum=sum+i;return sum;4、在ADS1.2 集成开发环境(CodeWarrior for ARM Developer Suite)选择微处理器、ase地址、程序执行的首地址、程序开始执行的函数Init.o等环境参数。5、选择菜单Project|Make后,点击Project|Debug,转入AXD环境。6、在AXD环境中,点击Ecxute|Go,然后进行单步调试。7、调试过程中把变量r0、r1、r2、i、sum添加到Watch窗口,观察这些变量的变化情况。,