第2章3_ARM汇编程序设计_第1页
第2章3_ARM汇编程序设计_第2页
第2章3_ARM汇编程序设计_第3页
第2章3_ARM汇编程序设计_第4页
第2章3_ARM汇编程序设计_第5页
已阅读5页,还剩58页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第二章_3 ARM汇编程序设计n在ARM嵌入式系统中,一般用C语言等高级语言对各个应用接口模块功能的实现进行程序设计,但在某些地方用汇编语言更方便、简单。n在一些关键部分,例如用来初始化电路以及用来为软件(高级语言编写)做运行前准备的启动代码必须用汇编语言编写。n汇编语言的代码效率很高,一般用于对硬件的直接控制。编程步骤 1 分析问题 2 确定算法 3 确定数据分配的存储单元 4 画程序流程图 5 编写程序ARM源程序文件 文件类型扩展名汇编语言源文件.sC语言源文件.cC+源文件.cpp引入文件.INC头文件.h本章提要本章提要汇编语言程序设计实例汇编语言程序设计实例嵌入式嵌入式C C语言程

2、序设计技巧语言程序设计技巧汇编语言与汇编语言与C C语言混合编程技术语言混合编程技术GNUGNU汇编语言源程序格式汇编语言源程序格式GNU汇编程序基本格式n 使用伪操作.equ定义了几个变量并为其赋值。n 用伪操作.global声明一个全局变量_strat,在下面就可以看出, _strat一般用于标识程序代码的开始,即程序的入口点。n .text伪操作表示以下为代码段,将被编译到代码段或者代码子段。n .end伪操作汇编编译器源文件的结束。每一个汇编模块必须包含一个.end伪操作,指示本模块的结束。 二、二、ARMARM编译环境下汇编语句编译环境下汇编语句n.global _startn.eq

3、u x,30n.equ y,40n.textn_start:nmov sp,#0 x00000800nmov r0,#xnmov r1,#ynadd r2,r0,r1nstr r2,spnstop:nb stopn.endGNU环境下汇编语句与编译说明环境下汇编语句与编译说明 GNU环境下ARM汇编语言程序设计主要是面对在ARM平台上进行嵌入式LINUX的开发。 GNU标准中提供了支持ARM汇编语言的汇编器as(arm-elf-as)、交叉编译器gcc ld(arm-elf-gcc)和链接器ld(arm-elf-ld)。 GNU环境下ARM汇编语言语句格式如下: 标签:标签: 指令指令/ /伪

4、操作伪操作/ /伪指令伪指令 操作数操作数 语句的注释语句的注释 GNUGNU环境下环境下ARMARM汇编程序编译汇编程序编译基本语法基本语法(1) 预处理 GNU汇编器as的内部预处理包括:移除多余的间隔符代码中的所有注释,并将字符常量转换为数字值。它不作宏处理和文件包含处理,但这些事情可以交由gcc编译器去做,文件包含可以用.include伪指令来实现。(2) 注释GNU ARM Assembly可识别的注释方式有:C风格多行注释符/* . */或GNU单行注释符“”或“#”。(3) 符号与C语言基本一致,符号名由字母、数字以及_、和.组成,大小写敏感。段与重定位段与重定位链接器ld用于把

5、多个目标文件合并为一个可执行文件。汇编器as生成的目标文件都假定从地址0开始,ld为其指定最终的地址。链接器ld把目标文件中的每个section都作为一个整体,为其分配运行的地址 符号说明符号说明(1)label lable后面要带冒号: 例如:_start: b reset_handler。(2)给符号赋值三种方式:= .set .equ(3)符号名由数字、字母或“.”,“_”组成,不可以数字开头,大小写敏感。汇编器预定义的寄存器名称汇编器预定义的寄存器名称 本章提要本章提要汇编语言程序设计实例汇编语言程序设计实例嵌入式嵌入式C C语言程序设计技巧语言程序设计技巧汇编语言与汇编语言与C C语

6、言混合编程技术语言混合编程技术汇编语言源程序格式汇编语言源程序格式ARMARM汇编语言程序设计实例解析汇编语言程序设计实例解析 u数据块复制 u两数中大者减小者直到零u累加队列中所有数累加队列中所有数u利用跳转表实现程序跳转u整数除法 例 1n先对内存地址0 x3000开始的100个字内存单元填入0 x100000010 x10000064字数据,然后将每个字单元进行64位累加结果保存于R9:R8。(R9中存放高32位)n_start:nMOVR0 , #0X3000初始化寄存器nMOVR1 , #0X10000001nMOVR2 , #100nloop_1:第一次循环赋值nSTRR1 , R

7、0,#4nADDR1 , R1,#1nSUBSR2 , R2,#1nBNEloop_1nMOVR0 , #0X3000nMOVR2 , #100nMOVR9 , #0nMOVR8 , #0nloop_2:第二次循环累加nLDRR1 , R0,#4nADDSR8 , R1,R8 R8=R8+R1,进位影响标志位nADCR9 , R9 , #0 R9=R9+C,C为进位nSUBSR2 , R2 , #1nBNEloop_2用ARM指令编写程序,将两数中的大数减小数直至减到结果为0为止。例 2程序如下:.text_start: MOVr0, #9 MOVr1, #15 CMPr0, r1;r0 -r

8、1即两数比较 SUBLTr1, r1, r0;r1 r0,则r1=r1 r0 SUBGTr0, r0, r1;r0 r1,则r0=r0 r1 BNEstart ;r0 r1,则转start继续stop B stopEND写一段 ARM汇编程序:循环累加队列中的所有元素,直到碰上零值元素,结果放在r4。源程序末尾处声明队列: Myarray DCD 0 x11 DCD 0 x22 DCD 0r0 指向队列头: ADR r0, myarray 使用命令 LDR r1, r0, #4来装载,累加至 r4之中,循环直到r1为0,用死循环来停止。例 3源程序如下:AREA total, CODEENTR

9、Y MOV r4, #0 ;设置初始值 ADRr0, arrayloop LDRr1,r0, #4 ;基址指针 r0自动增加 ADDr4, r4, r1 CMPr1, #0 BNEloop ;r1为0时中断循环stop B stop ;死循环Array DCD 0 x11 ;声明队列 DCD 0 x22 DCD 0END利用跳转表实现程序跳转。 在程序中常需要根据一定的参数选择执行不同的子程序。本例跳转表中存放的是各子函数的地址,选择不同的子程序的参数是该子程序在跳转表中的偏移量。在本例中,R3寄存器中存放的是跳转表的基地址,即存放子程序的入口地址的跳转表的首地址。 R0寄存器的值用于选择不同

10、的子程序:当R0为0时,选择的是子程序DoAdd;当R0为1时,选择的是子程序DoSub。例 4在ADS编译环境下,程序如下:AREA Jump,CODE,READONLY ;设置本段程序的名称及属性NUM EQU 2 ;跳转表中的子程序个数ENTRY ;程序执行的入口点Start MOV R0, #0;设置参数,R0中为需调用哪个子程序 MOV R1, #3; R1为子程序要用的参数 MOV R2, #2 ; R2为子程序要用的参数 BL Func ;调用子程序Func,进行算术运算stop MOV R0, #0 x18 ;软中断参数设置 LDR R1, =0 x20026 ;软中断参数设置

11、 SWI 0 x123456 ;将CPU的控制权交给调试器Func CMP R0,#NUM ;判断R0是否在有效范围之内 MOVHS PC,LR ;如果超出范围则程序返回 ADR R3,JTable ;读取跳转表的基地址 LDR PC,R3,R0,LSL #2;根据R0的值跳转到相应的子程序Jtable DCD DoAdd ;当R0为0时上面的代码将跳转到DoAdd DCD DoSub ;当R0为1时上面的代码将跳转到DoSubDoAdd ADD R0,R1,R2 ;子程序DoAdd执行加法操作 MOV PC,LR ;子程序返回DoSub SUB R0,R1,R2;子程序DoAdd执行减法操作

12、 MOV PC,LR ;子程序返回 END ;结束汇编例 5n实现整数除法,整数用补码表示。先将被除数和除数高位对齐,如果够减上商1,并减去除数;否则上商0。然后右移除数1位,重复上述操作。n.global _startn.macro mCLZ Rd, Rs 求一个数的前导0个数nMOVRd, #0 在某些ARM中,可使用指令CLZ代替n_mCLZ_L1:nTSTRs, #0 x80000000nADDEQ Rd, Rd, #1nMOVEQRs, Rs, ROR #31 左移一位nBEQ_mCLZ_L1nMOVRs, Rs, LSR Rdn.endm n.macro mUNSIGN Rd, R

13、s 将一个数无符号化nTST Rs, #0 x80000000 将无符号的整数放到Rs中nEORNE Rd, Rd, #1 将符号部分放到Rd中nMVNNE Rs, RsnADDNE Rs, Rs, #1n.endmn.textn_start:nLDRR0, =-123456 被除数nLDRR1, =523 除数nDiv:nMOVR6, #0 结果的符号位nmUNSIGNR6, R0 无符号化nmUNSIGNR6, R1nMOVR5, #0 商nCMPR0, R1 如果被除数小于除数nBLTDivision_L2 直接商0nmCLZR3, R1 判断除数位数,确定移位情况nSUBR3, R3,

14、 #1nMOVR1, R1, LSL R3nDivision_L1:nMOVR5, R5, LSL #1nCMPR0, R1 判断是否够减nSUBGTR0, R0, R1 如果够减,做减法,上商1nORRGTR5, R5, #1nSUBSR3, R3, #1nMOVCSR1, R1, LSR #1nBCS Division_L1nDivision_L2:nTSTR6, #1 处理结果的符号nMVNNER5, R5nADDNER5, R5, #1nDivision_F:nMOVR1, R0nMOVR0, R5例 6n用Thumb指令实现内存数据区块拷贝操作。n .global_startn.eq

15、uNUM,18设置要复拷贝的字数n.textn_start:n.armnMOVSP, #0 x9000nADRR0, Thumb_start + 1nBXR0 n.thumbnThumb_start:nLDRR0, =Src R0 = 源数据区指针nLDRR1, =Dst R1 = 目标数据区指针n MOVR2, #NUMnLSRR3, R2, #2获得块拷贝的次数nBEQCopy_WordsnPUSHR4-R7 保存将要使用的寄存器R4-R7nCopy_4Word:进行块拷贝,每次拷贝4个字nLDMIAR0!, R4-R7nSTMIAR1!, R4-R7nSUBR3, #1nBNECopy_

16、4WordnPOPR4-R7恢复寄存器R4-R7nThumb_start:将剩余的数据区以字为单位拷贝nCopy_Words:nMOVR3, #3nANDR2, R3 获得剩余的数据的字数nBEQStopnCopy_Word:nLDMIAR0!, R3nSTMIAR1!, R3nSUBR2, #1nBNECopy_WordnStop:nBStopn.ltorgnSrc:n.long1,2,3,4,5,6,7,8,9,0 xA,0 xB,0 xC,0 xD,0 xE,0 xF,0 x10,0 x11,0 x12nDst:n.long0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,

17、0,0,0,0n.end文件结束本章提要本章提要汇编语言程序设计汇编语言程序设计嵌入式嵌入式C C语言程序设计技巧语言程序设计技巧汇编语言与汇编语言与C C语言混合编程技术语言混合编程技术汇编语言源程序格式汇编语言源程序格式4.3 嵌入式C语言程序设计技巧变量定义变量定义参数传递参数传递循环条件循环条件以空间换时间以空间换时间数学方法解决问题数学方法解决问题使用位操作使用位操作嵌入汇编嵌入汇编一、变量定义 在变量声明的时候,最好把所有相同类型的变量放在一起定义,这样可以优化存储器布局。由下例可以看出: 对于局部变量类型的定义,使用short或char来定义变量并不是总能节省存储空间。有时使用3

18、2位int或unsinged int局部变量更有效率一些,如下图所示:变量定义中,为了精简程序,程序员总是竭力避免使用冗余变量。但有时使用冗余变量可以减少存储器访问的次数这可以提高系统性能。 二、参数传递 为了使单独编译的C语言程序和汇编程序能够互相调用,定义了统一的函数过程调用标准ATPCS。ATPCS定义了寄存器组中的R0R3作为参数传递和结果返回寄存器,如果参数数目超过四个,则使用堆栈进行传递。 内部寄存器的访问速度是远远大于存储器的,所以要尽量使参数传递在寄存器里面进行,即应尽量把函数的参数控制在四个以下。 三、循环条件 计数循环是程序中十分常用的流程控制结构,一般有以下两种形式: f

19、or for (loop=1loop=1;loop=limitloop=limit;loop+loop+) for for (looploop= =limitlimit;looploop!=!=0 0;looploop-)这两种循环形式在逻辑上并没有效率差异,但是映射到具体的体系结构中时,就产生了很大的不同,如下图所示。 四、以空间换时间 计算机程序中最大的矛盾是空间和时间的矛盾,从这个角度出发逆向思维来考虑程序的效率问题,比如若系统的实时性要求很高,内存还有剩余,则我们就有可以用以空间换时间的方法来提高程序执行的效率。 五、数学方法解决问题 数学是计算机之母,计算机的发展是以数学为依据和基础

20、的,所以在编写程序的时候,适当地采用一些数学方法会对程序的执行效率有数量级的提高,如下例所示: 六、使用位操作 一般的位操作是用来控制硬件的,或者做数据变换使用,但是,灵活的位操作可以减少除法和取模的运算有效地提高程序运行的效率,如下例所示: 七、嵌入汇编 汇编语言是效率最高的计算机语言,但是它地可读性较差,因此在C语言编程中为了获得程序的高效率,我们可以采用变通的方法-嵌入汇编、混合编程。 本章提要本章提要汇编语言上机过程汇编语言上机过程嵌入式嵌入式C C语言程序设计技巧语言程序设计技巧汇编语言与汇编语言与C C语言混合编程技术语言混合编程技术汇编语言源程序格式汇编语言源程序格式汇编语言与C

21、语言混合编程技术nARM体系结构支持ARM的汇编语言与C与C+的混合编程.一般的在一个完整的程序设计的中,除了初始化部分用汇编语言完成外,其大部分的编程任务一般都用C或C+完成。一、ATPCS介绍 ATPCS(ARM-Thumb Produce Call Standard)是ARM程序和Thumb程序中子程序调用的基本规则,目的是为了使单独编译的C语言程序和汇编程序之间能够相互调用。这些基本规则包括子程序调用过程中寄存器的使用规则数据栈的使用规则参数的传递规则 1. 寄存器的使用规则子程序间通过寄存器R0R3来传递参数,这时,寄存器R0R3可以记作A1A4。 在子程序中,使用寄存器R4R11来

22、保存局部变量。这时,寄存器 R4R11可以记作V1V8。在Thumb程序中,通常只能使用寄存器R4R7来保存局部变量 。寄存器R12用作子程序间的scratch寄存器(用于保存SP,在函数返回时使用该寄存器出栈),记作ip。 寄存器R13用作数据栈指针,记作sp。 寄存器R14称为链接寄存器,记作lr。 寄存器R15是程序计数器,记作pc。 寄存器别名特殊名使用规则R0a1参数/结果scratch寄存器1R1a2参数/结果scratch寄存器2R2a3参数/结果scratch寄存器3R3a4参数/结果scratch寄存器4R4v1ARM状态局部变量寄存器1R5v2ARM状态局部变量寄存器2R6

23、v3ARM状态局部变量寄存器3R7v4wrARM状态局部变量寄存器4Thumb状态工作寄存器R8v5ARM状态局部变量寄存器5R9v6sbARM状态局部变量寄存器6,在支持RWPI的ATPCS中为静态基址寄存器R10v7slARM状态局部变量寄存器7,在支持数据栈检查的ATPCS中为数据栈限制指针R11v8fpARM状态局部变量寄存器8/帧指针R12ip子程序内部调用的scratch寄存器R13sp数据栈指针R14lr连接寄存器R15pc程序计数器2. 数据栈的使用规则n 根据堆栈指针指向位置的不同 和增长方向的不同可以分为以下4种数据栈 : FD (Full Descending) 满递减

24、ED (Empty Descending) 空递减 FA (Full Ascending) 满递增 EA (Empty Ascending) 空递增 ATPCS规定数据栈为FD(满递减)类型,并且对数据栈的操作是8字节对齐的。 3. 参数的传递规则参数个数固定的子程序参数传递规则: 第一个整数参数,通过寄存器R0R3来传递。其他参数通过数据栈传递。 参数个数可变的子程序参数传递规则: 当参数不超过4个时,可以使用寄存器R0R3来传递参数;当参数超过4个时,还可以使用数据栈来传递参数 子程序结果返回规则: 结果为一个32位的整数时,可以通过寄存器R0返回;结果为一个64位整数时,可以通过寄存器R

25、0和R1返回,依次类推。 二、内嵌汇编 在C程序中嵌入汇编程序可以实现一些高级语言没有的功能,并可以提高执行效率。armcc和armcpp内嵌汇编器支持完整的ARM指令集;tcc和tcpp用于Thumb指集。 内嵌的汇编指令包括大部分的ARM指令和Thumb指令,但是不能直接引用C的变量定义,数据交换必须通过ATPCS进行。嵌入式汇编在形式上表现为独立定义的函数体。 1. 内嵌汇编指令的语法格式 n_asm(“指令;指令”); ARM C汇编器使用关键字“_ asm。如果有多条汇编指令需要嵌入,可以用“”将它们归为一条语句。如:_ asm 指令;指令 指令 n需要特别注意的是_asm是两个下划

26、线。 2. 内嵌的汇编指令的特点 操作数可以是寄存器、常量或C表达式。它们可以是char、short或者int类型,而且是作为无符号数进行操作 。内嵌的汇编指令中使用物理寄存器有一些限制。常量前的符号“#”可以省略 只有指令B可以使用C程序中的标号,指令BL不能使用C程序中的标号。 不支持汇编语言中用于内存分配的伪操作。指令中如果包含常量操作数,该指令可能会被汇编器展开成几条指令。 3. 内嵌汇编器与armasm汇编器的区别 内嵌汇编器不支持通过“”指示符或PC获取当前指令地址; 不支持LDR Rn,= expression伪指令,而使用MOV Rn, expression指令向寄存器赋值;

27、不支持标号表达式;不支持ADR和ADRL伪指令; 不支持BX和BLX指令; 不可以向PC赋值; 使用0 x前缀替代“”表示十六进制数。 4. 内嵌汇编注意事项 必须小心使用物理寄存器,如R0R3,LR和PC。 不要使用寄存器寻址变量。 使用内嵌汇编时,编译器自己会保存和恢复它可能用到的寄存器,用户无须保存和恢复寄存器。 LDM和STM指令的寄存器列表只允许物理寄存器。 汇编语言用“,”作为操作数分隔符 三、C和ARM汇编程序间相互调用 在C和ARM汇编程序之间相互调用必须遵守ATPCS(ARM-Thumb Procedure Call Standard)规则。C和汇编之间的相互调用可以从以下这

28、三方面来介绍:汇编程序对C全局变量的访问在C语言程序中调用汇编程序在汇编程序中调用C语言程序1. 汇编程序访问全局C变量 n 汇编程序可以通过地址间接访问在C语言程序中声明的全局变量。通过使用IMPORT关键词引人全局变量,并利用LDR和STR指令根据全局变量的地址可以访问它们。n 对于不同类型的变量,需要采用不同选项的LDR和STR指令,如下所示: unsigned char LDRB/STRBunsigned short LDRH/STRHunsigned intLDR/STRchar LDRSB/STRSBshort LDRSH/STRSH nAREA globals,CODE,READ

29、ONLYnEXPORT asmsubroutine;nIMPORT globvarnasmsubroutinenLDR R1,=globvar ;从文字池读globvar的地n ;址,并将其保存到R1nLDR R0,R1 ;再将其值读入到寄存器R0中nADD R0,R0,#2nSTR R0,R1 ;修改后再将寄存器R0的值n ;赋予变量globvarnMOV PC,LRnEND2. 在C语言程序中调用汇编程序n 为了保证程序调用时参数的正确传递,汇编程序的设计要遵守ATPCS。在汇编程序中需要使用EXPORT伪操作来声明,使得本程序可以被其它程序调用。同时,在C程序调用该汇编程序之前需要在C语言程序中使用extern关键词来声明该汇编程序。 nC源程序源程序:n# include ne

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论