您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 其它行业文档 > n4_ARM程序设计
1嵌入式系统原理与应用第四讲ARM程序设计22内容提要ARM汇编语言程序设计汇编语言源程序格式与伪指令ARM程序开发工具嵌入式C语言程序设计原则与技巧嵌入式程序开发流程3ARM汇编程序设计由于高级编程语言隐藏了CPU执行指令的许多细节,因此在只关心系统所具有功能的系统中,采用高级语言编写程序更为合适。但是,CPU执行指令的细节差异会反应在系统的非功能特性上,例如系统程序的规模和运行速度。因此,掌握汇编语言程序设计对于嵌入式系统的设计者来说是非常必要的。4ARM汇编语言程序设计简单程序设计分支程序设计循环程序设计子程序设计5简单程序设计1顺序程序设计例1用ARM指令实现的C赋值语句:x=(a+b)-c可以用r0表示a、r1表示b、r2表示c和r3表示x,用r4作为间接寻址寄存器。在进行算术运算之前,代码必须先把a、b、c的值装入到寄存器,运算结束后,还要把x的值存回存储器中。6这段代码执行下面这些必须的步骤:ADRr4,a;读取变量a的地址LDRr0,[r4];读a的内容到r0ADRr4,b;读取变量b的地址LDRrl,[r4];读b内容到r1ADDr3,r0,rl;a+b的结果保存在r3ADRr4,c;读取变量c的地址LDRr2,[r4];读c的内容到r2SUBr3,r3,r2;(a+b)-c结果保存到r3ADRr4,x;读x的地址STRr3,[r4];保存变量x7例2用ARM指令实现的C赋值语句z=(a2)|(b&15)可以使用r0表示a和z,r1表示b,r4表示地址进行编码,代码如下:ADRr4,a;读取变量a的地址到r4LDRr0,[r4];读a的内容到r0MOVr0,r0,LSL#2;实现a2操作,结果保存在r0ADRr4,b;读取变量b的地址到r4LDRrl,[r4];读b的内容到r1ANDr1,r1,#15;实现b&15操作,结果保存在r1中ORRrl,r0,rl;计算z的结果ADRr4,z;读取变量z的地址到r4STRrl,[r4];保存变量z82分支程序设计例3-3在ARM中实现下面if语句:if(ab)y=c+d:elsey=c-d;实现上述指令的第一种方法比较传统并且和其他微处理器相似。下列指令使用条件分支和无条件数据操作:9ADRr4,a;读取变量a的地址到r4LDRr0,[r4];读a的内容到r0ADRr4,b;读取变量b的地址到r4LDRrl,[r4];读b的内容到r1CMPr0,rl;比较a,bBGEfblock;如果a=b,跳转到fblock子程序执行ADRr4,c;读取变量c的地址到r4LDRr0,[r4];读c的内容到r0ADRr4,d;读取变量d的地址到r4LDRrl,[r4];读取d的内容到r110ADDr0,r0,rl;计算a+b,结果保存在r0ADRr4,y;读取变量y的地址STRr0,[r4];结果保存在y中Bafter;程序跳转到after子块fblock:ADRr4,c;读取变量c的地址LDRr0,[r4];读c的内容到r0ADRr4,d;读取变量d的地址到r4LDRrl,[r4];读变量d的内容到r1SUBr0,r0,rl;计算a–b结果保存在r0ADRr4,y;读取变量x的地址STRr0,[r4];结果保存在x中after:…11ADDr0,r0,rl;计算a+b,结果保存在r0Bafter;程序跳转到after子块fblock:ADRr4,c;读取变量c的地址LDRr0,[r4];读c的内容到r0ADRr4,d;读取变量d的地址到r4LDRrl,[r4];读变量d的内容到r1SUBr0,r0,rl;计算a–b结果保存在r0after:…ADRr4,y;读取变量x的地址STRr0,[r4];结果保存在x中12ADRr4,a;读取变量a的地址到r4LDRr0,[r4];读a的内容到r0ADRr4,b;读取变量b的地址到r4LDRrl,[r4];读b的内容到r1CMPr0,rl;比较a,bBGEfblock;如果a=b,跳转到fblock子程序执行ADRr4,c;读取变量c的地址到r4LDRr0,[r4];读c的内容到r0ADRr4,d;读取变量d的地址到r4LDRrl,[r4];读取d的内容到r1出现2次13ADRr4,a;读取变量a的地址到r4LDRr0,[r4];读a的内容到r0ADRr4,b;读取变量b的地址到r4LDRrl,[r4];读b的内容到r1ADRr4,c;读取变量c的地址到r4LDRr3,[r4];读c的内容到r0ADRr4,d;读取变量d的地址到r4LDRr5,[r4];读取d的内容到r1CMPr0,rl;比较a,bBGEfblock;如果a=b,跳转到fblock子程序执行14CMPr0,rl;比较a,bBGEfblock;如果a=b,跳转到fblock子程序执行ADDr0,r3,r5;计算a+b,结果保存在r0Bafter;程序跳转到after子块fblock:SUBr0,r3,r5;计算a–b结果保存在r0after:…ADRr4,y;读取变量x的地址STRr0,[r4];结果保存在x中15CMPr0,rl;比较a,bADDLTr0,r3,r5;计算a+b,结果保存在r0SUBGEr0,r3,r5;计算a–b结果保存在r0ADRr4,y;读取变量x的地址STRr0,[r4];结果保存在x中16例4在ARM中实现C的switch语句C中的switch语句采用下列形式:switch(test){case0:...break;case1:...break;}上述语句也可以像if语句那样编码,首先测试test=A,然后测试test=B,依此类推.用基址加偏移量寻址并建立分支表的方法执行起来会更有效地实现:17ADRr2,test;读取变量test的地址LDRr0,[r2];读test的内容到r0ADRr1,switchtab;读取switchtab的地址到r1LDRpc,[r1,r0,LSL#2]switchtab:.wordcase0.wordcasel…case0:…@codeforcase0casel:…@codeforcase118这种实现方法使用test值作为一个表的偏移量,其中该表保存了实现各种情况的代码段的地址。每一个case都由存放在存储器某处的一段代码实现。分支表从名为switchtab的单元开始。.word语句是在该处装入一个32位地址到存储器的一种方法,因此分支表包含了对应于各个case的代码段起点的地址。这段代码的核心就是LDR指令,它把多种功能集中在一个简单的指令里:它将r0的值左移两位,把偏移量转化为字地址。它用基址加偏移量寻址的方法把左移了的test的值(存放在r0中)加到保存在r1中的表的基址中。它将该指令计算出的新地址置为程序计数器(r15)的值193循环程序设计循环能用条件分支自然地实现,因为循环总是对存在数组中的值进行操作,循环也是对基址加偏移量寻址模式的另一种用法较好的说明。例5用ARM指令实现FIR过滤器FIR滤波器是简单的对积求和:∑cixi1≤i≤nxi假定为周期性采集的数据样本,ci是滤波器系数。这个计算总是按如下方式进行:20每次一个新的采样到来都要重新计算一次FIR滤波器的输出。△方框表示存储刚刚到来的采样产生xi时延元素。延迟的采样分别单独与c相乘,然后求和得到滤波的输出ΔΔΔΔΣfc1c2c3c4x1x2x3x421FIR过滤器的C语言代码如下:for(i=0,f=0;in;i++)f=f+c[i]*x[i];可以根据基址加偏移量寻址法对数组c和x进行编址。将每个数组的第零元素的地址,装入一个寄存器,存放i的寄存器则用作偏移量。22MOVr0,#0;使用r0作为计数器i,置初值为0MOVr8,#0;使用r8作为字节偏移量,置初值为0ADRr2,n;读取n的地址到r2LDRr1,[r2];读n的值到r1MOVr2,#0;使用r2作为f,置初值为0ADRr3,c;读取c的地址到r3作为c[i]数;组的首地址ADRr5,x;读取x的地址到r5,作为x[i];数组的首地址23loop:LDRr4,[r3,r8];读取c[i]的值到r4LDRr6,[r5,r8];读取x[i]的值到r6MULr6,r4,r6;计算c[i]*s[i],结果保存到r6ADDr2,r2,r6;求和送给f;修改循环计数器和数组下标ADDr8,r8,#4;偏移量增加32位ADDr0,r0,#1;i++;测试推出循环条件CMPr0,rlBLTLoop;ifiN,继续循环looploopend…24不论该代码是用C语言还是用汇编语言编写,我们都要注意代码中的数值精确度。32位乘法得到64位的结果。ARM的MUL指令把结果的低32位保存到目的寄存器中。只要结果不超过32位,就能得到所需结果。如果输出值超过32位,我们就要重新设计代码来计算高分辨率的值。30ARM源程序文件使用简单的文本编辑器或者其他的编程开发环境进行编辑.文件类型扩展名汇编语言文件.sC语言源文件.cC++源文件.cpp引入文件.INC头文件.h3131内容提要ARM汇编语言程序设计汇编语言源程序格式与伪指令ARM程序开发工具嵌入式C语言程序设计原则与技巧嵌入式程序开发流程32汇编语言源程序格式两种常见的ARM编译开发环境ADS编译环境下的伪操作和宏指令GNU编译环境下的伪操作和宏指令33两种常见的ARM编译开发环境ADS/SDTIDE开发环境:它由ARM公司开发,使用了CodeWarrior公司的编译器;集成了GNU开发工具的IDE开发环境:它由GNU的汇编器as、交叉编译器gcc、和链接器ld等组成。34汇编语言程序的结构汇编源程序示例第一部分(test0源程序)CODE32;32位的ARM指令段AREAcodesec,CODE,READONLY;代码段,名称codesec,属性为;只读mainPROC;函数mainSTMFDsp!,{lr};保存必要的寄存器和返回地址;到数据栈ADRr0,strhello;取标签strhello代表的地址值BL_printf;调用C运行时库的_printf函数;打印“Helloworld!”字符串BLwelcomefun;调用子函数welcomfunLDMFDsp!,{pc};恢复寄存器值strhello;strhello代表本地字符串的地址DCBHelloworld!\n\0;定义一段字节空间ENDP;函数main结束ARM的汇编语言程序一般由几个段组成,每个段均由AREA伪操作定义。段可以分为多种,如代码段、数据段、通用段,每个段又有不同的属性,象代码段的默认属性为READONLY,数据段的默认属性为READWRITE。本程序定义了两个段,第一个段为代码段codesec;第二个段为数据段constdatasec35汇编语言程序的结构汇编源程序示例第二部分welcomefun;子函数welcomfunSTMFDsp!,{lr};保存必要的寄存器和返回地;址到数据栈ADRr0,adrstrarm;取adrstrarm的地址放到寄存器r0中LDRr0,[r0,#0];将strarm的值放到r0中BL_printf;调用C运行时库的_printf函数打印;“WelcomtoARMworld!”字符串LDMFDsp!,{pc};恢复寄存器值adrstrarm;adrstrarm标签DCDstrarm;保存strarm的地址AREAconstdatasec,DATA,READONLY,ALIGN=0;数据段,名称为constdatasec,属性;为只读本程序定义了两个段,第一个段为代码段codesec第二个段为数据段constdatasec36汇编语言程序的结构汇编源程序示例第三部分strarmDCBWelcometoARMworld!\n\0;存放“WelcometoARM;world!”字符串EXPORTmain;导出main函数供外部调用;引入三个C运行时
本文标题:n4_ARM程序设计
链接地址:https://www.777doc.com/doc-3155838 .html