![第2章3-ARM汇编程序设计课件_第1页](http://file4.renrendoc.com/view/0097f8898aebd93124ef5a8ef79d55b4/0097f8898aebd93124ef5a8ef79d55b41.gif)
![第2章3-ARM汇编程序设计课件_第2页](http://file4.renrendoc.com/view/0097f8898aebd93124ef5a8ef79d55b4/0097f8898aebd93124ef5a8ef79d55b42.gif)
![第2章3-ARM汇编程序设计课件_第3页](http://file4.renrendoc.com/view/0097f8898aebd93124ef5a8ef79d55b4/0097f8898aebd93124ef5a8ef79d55b43.gif)
![第2章3-ARM汇编程序设计课件_第4页](http://file4.renrendoc.com/view/0097f8898aebd93124ef5a8ef79d55b4/0097f8898aebd93124ef5a8ef79d55b44.gif)
![第2章3-ARM汇编程序设计课件_第5页](http://file4.renrendoc.com/view/0097f8898aebd93124ef5a8ef79d55b4/0097f8898aebd93124ef5a8ef79d55b45.gif)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第二章_3ARM汇编程序设计在ARM嵌入式系统中,一般用C语言等高级语言对各个应用接口模块功能的实现进行程序设计,但在某些地方用汇编语言更方便、简单。在一些关键部分,例如用来初始化电路以及用来为软件(高级语言编写)做运行前准备的启动代码必须用汇编语言编写。汇编语言的代码效率很高,一般用于对硬件的直接控制。编程步骤
1分析问题
2确定算法3确定数据分配的存储单元
4画程序流程图
5编写程序ARM源程序文件
文件类型扩展名汇编语言源文件.sC语言源文件.cC++源文件.cpp引入文件.INC头文件.h本章提要324汇编语言程序设计实例嵌入式C语言程序设计技巧汇编语言与C语言混合编程技术1GNU汇编语言源程序格式GNU汇编程序基本格式使用伪操作.equ定义了几个变量并为其赋值。用伪操作.global声明一个全局变量_strat,在下面就可以看出,_strat一般用于标识程序代码的开始,即程序的入口点。.text伪操作表示以下为代码段,将被编译到代码段或者代码子段。.end伪操作汇编编译器源文件的结束。每一个汇编模块必须包含一个.end伪操作,指示本模块的结束。
二、ARM编译环境下汇编语句.global_start.equx,30.equy,40.text_start:movsp,#0x00000800movr0,#xmovr1,#yaddr2,r0,r1strr2,[sp]stop:bstop.end GNU环境下汇编语句与编译说明
GNU环境下ARM汇编语言程序设计主要是面对在ARM平台上进行嵌入式LINUX的开发。GNU标准中提供了支持ARM汇编语言的汇编器as(arm-elf-as)、交叉编译器gccld(arm-elf-gcc)和链接器ld(arm-elf-ld)。GNU环境下ARM汇编语言语句格式如下:[标签:]指令/伪操作/伪指令操作数[@语句的注释]GNU环境下ARM汇编程序编译基本语法(1)预处理GNU汇编器as的内部预处理包括:移除多余的间隔符代码中的所有注释,并将字符常量转换为数字值。它不作宏处理和文件包含处理,但这些事情可以交由gcc编译器去做,文件包含可以用.include伪指令来实现。(2)注释GNUARMAssembly可识别的注释方式有:C风格多行注释符/*...*/或GNU单行注释符“@”或“#”。(3)符号与C语言基本一致,符号名由字母、数字以及'_'、和'.'组成,大小写敏感。段与重定位链接器ld用于把多个目标文件合并为一个可执行文件。汇编器as生成的目标文件都假定从地址0开始,ld为其指定最终的地址。链接器ld把目标文件中的每个section都作为一个整体,为其分配运行的地址符号说明(1)labellable后面要带冒号‘:’
例如:_start:breset_handler。(2)给符号赋值三种方式:=.set.equ(3)符号名由数字、字母或“.”,“_”组成,不可以数字开头,大小写敏感。汇编器预定义的寄存器名称本章提要324汇编语言程序设计实例嵌入式C语言程序设计技巧汇编语言与C语言混合编程技术1汇编语言源程序格式ARM汇编语言程序设计实例解析
数据块复制
两数中大者减小者直到零累加队列中所有数利用跳转表实现程序跳转整数除法
例1先对内存地址0x3000开始的100个字内存单元填入0x10000001~0x10000064字数据,然后将每个字单元进行64位累加结果保存于[R9:R8]。(R9中存放高32位)_start:
MOV R0,#0X3000 @初始化寄存器
MOV R1,#0X10000001 MOV R2,#100loop_1: @第一次循环赋值
STR R1,[R0],#4 ADD R1,R1,#1 SUBS R2,R2,#1 BNE loop_1
MOV R0,#0X3000 MOV R2,#100 MOV R9,#0 MOV R8,#0 loop_2: @第二次循环累加
LDR R1,[R0],#4 ADDS R8,R1,R8@R8=R8+R1,进位影响标志位
ADC R9,R9,#0@R9=R9+C,C为进位
SUBS R2,R2,#1 BNE loop_2用ARM指令编写程序,将两数中的大数减小数直至减到结果为0为止。例2程序如下:.text_start:MOV r0,#9MOV r1,#15CMP r0,r1 ;r0-r1即两数比较
SUBLT r1,r1,r0 ;r1>r0,则r1=r1–r0SUBGT r0,r0,r1 ;r0>r1,则r0=r0–r1BNE start ;r0≠r1,则转start继续stopB stopEND写一段ARM汇编程序:循环累加队列中的所有元素,直到碰上零值元素,结果放在r4。源程序末尾处声明队列:Myarray DCD0x11 DCD0x22 DCD0r0指向队列头:
ADRr0,myarray
使用命令LDRr1,[r0],#4来装载,累加至r4之中,循环直到r1为0,用死循环来停止。例3源程序如下:AREAtotal,CODEENTRY MOV r4,#0 ;设置初始值
ADR r0,arrayloop LDR r1,[r0],#4 ;基址指针r0自动增加
ADD r4,r4,r1 CMP r1,#0
BNE loop ;r1为0时中断循环stop
B stop ;死循环ArrayDCD 0x11 ;声明队列
DCD 0x22
DCD 0END利用跳转表实现程序跳转。在程序中常需要根据一定的参数选择执行不同的子程序。本例跳转表中存放的是各子函数的地址,选择不同的子程序的参数是该子程序在跳转表中的偏移量。在本例中,R3寄存器中存放的是跳转表的基地址,即存放子程序的入口地址的跳转表的首地址。
R0寄存器的值用于选择不同的子程序:当R0为0时,选择的是子程序DoAdd;当R0为1时,选择的是子程序DoSub。例4在ADS编译环境下,程序如下:AREAJump,CODE,READONLY ;设置本段程序的名称及属性NUMEQU2 ;跳转表中的子程序个数ENTRY ;程序执行的入口点StartMOVR0,#0 ;设置参数,R0中为需调用哪个子程序
MOVR1,#3 ;R1为子程序要用的参数
MOVR2,#2 ;R2为子程序要用的参数
BLFunc
;调用子程序Func,进行算术运算stopMOVR0,#0x18 ;软中断参数设置
LDRR1,=0x20026 ;软中断参数设置
SWI0x123456 ;将CPU的控制权交给调试器FuncCMPR0,#NUM ;判断R0是否在有效范围之内
MOVHSPC,LR ;如果超出范围则程序返回ADRR3,JTable
;读取跳转表的基地址
LDRPC,[R3,R0,LSL#2] ;根据R0的值跳转到相应的子程序JtableDCDDoAdd
;当R0为0时上面的代码将跳转到DoAddDCDDoSub
;当R0为1时上面的代码将跳转到DoSubDoAdd
ADDR0,R1,R2 ;子程序DoAdd执行加法操作
MOVPC,LR ;子程序返回DoSub
SUBR0,R1,R2 ;子程序DoAdd执行减法操作
MOVPC,LR ;子程序返回
END ;结束汇编例5实现整数除法,整数用补码表示。先将被除数和除数高位对齐,如果够减上商1,并减去除数;否则上商0。然后右移除数1位,重复上述操作。.global_start .macromCLZRd,Rs @求一个数的前导0个数
MOV \Rd,#0 @在某些ARM中,可使用指令CLZ代替__mCLZ_L1: TST \Rs,#0x80000000 ADDEQ \Rd,\Rd,#1 MOVEQ \Rs,\Rs,ROR#31 @左移一位 BEQ __mCLZ_L1 MOV \Rs,\Rs,LSR\Rd.endm
.macro mUNSIGN Rd,Rs @将一个数无符号化
TST \Rs,#0x80000000 @将无符号的整数放到Rs中
EORNE \Rd,\Rd,#1 @将符号部分放到Rd中
MVNNE \Rs,\Rs ADDNE \Rs,\Rs,#1.endm.text_start: LDR R0,=-123456 @被除数
LDR R1,=523 @除数Div: MOV R6,#0 @结果的符号位
mUNSIGN R6,R0 @无符号化
mUNSIGN R6,R1 MOV R5,#0 @商
CMP R0,R1 @如果被除数小于除数
BLT Division_L2 @直接商0 mCLZ R3,R1 @判断除数位数,确定移位情况
SUB R3,R3,#1 MOV R1,R1,LSLR3Division_L1: MOV R5,R5,LSL#1 CMP R0,R1 @判断是否够减
SUBGT R0,R0,R1 @如果够减,做减法,上商1 ORRGT R5,R5,#1 SUBS R3,R3,#1 MOVCS R1,R1,LSR#1 BCS Division_L1Division_L2: TST R6,#1 @处理结果的符号
MVNNE R5,R5 ADDNE R5,R5,#1Division_F: MOV R1,R0 MOV R0,R5例6用Thumb指令实现内存数据区块拷贝操作。.global _start.equ NUM, 18 @设置要复拷贝的字数.text_start: .arm MOV SP,#0x9000 ADR R0,Thumb_start+1 BX R0 .thumb Thumb_start: LDR R0,=Src@R0=源数据区指针
LDR R1,=Dst@R1=目标数据区指针MOV R2,#NUM LSR R3,R2,#2 @获得块拷贝的次数
BEQ Copy_Words PUSH {R4-R7}@保存将要使用的寄存器R4-R7
Copy_4Word: @进行块拷贝,每次拷贝4个字 LDMIA R0!,{R4-R7} STMIA R1!,{R4-R7} SUB R3,#1 BNE Copy_4Word POP {R4-R7} @恢复寄存器R4-R7 Thumb_start: @将剩余的数据区以字为单位拷贝Copy_Words: MOV R3,#3 AND R2,R3 @获得剩余的数据的字数
BEQ Stop Copy_Word: LDMIA R0!,{R3} STMIA R1!,{R3} SUB R2,#1 BNE Copy_Word Stop: B Stop.ltorgSrc: .long 1,2,3,4,5,6,7,8,9,0xA,0xB,0xC,0xD,0xE,0xF,0x10,0x11,0x12Dst: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.end @文件结束
本章提要324汇编语言程序设计嵌入式C语言程序设计技巧汇编语言与C语言混合编程技术1汇编语言源程序格式4.3嵌入式C语言程序设计技巧变量定义参数传递循环条件以空间换时间数学方法解决问题使用位操作嵌入汇编一、变量定义
在变量声明的时候,最好把所有相同类型的变量放在一起定义,这样可以优化存储器布局。由下例可以看出:对于局部变量类型的定义,使用short或char来定义变量并不是总能节省存储空间。有时使用32位int或unsinged
int局部变量更有效率一些,如下图所示:变量定义中,为了精简程序,程序员总是竭力避免使用冗余变量。但有时使用冗余变量可以减少存储器访问的次数这可以提高系统性能。
二、参数传递
为了使单独编译的C语言程序和汇编程序能够互相调用,定义了统一的函数过程调用标准ATPCS。ATPCS定义了寄存器组中的{R0~R3}作为参数传递和结果返回寄存器,如果参数数目超过四个,则使用堆栈进行传递。
内部寄存器的访问速度是远远大于存储器的,所以要尽量使参数传递在寄存器里面进行,即应尽量把函数的参数控制在四个以下。三、循环条件
计数循环是程序中十分常用的流程控制结构,一般有以下两种形式:for(loop=1;loop<=limit;loop++)
for(loop=limit;loop!=0;loop--)这两种循环形式在逻辑上并没有效率差异,但是映射到具体的体系结构中时,就产生了很大的不同,如下图所示。
四、以空间换时间
计算机程序中最大的矛盾是空间和时间的矛盾,从这个角度出发逆向思维来考虑程序的效率问题,比如若系统的实时性要求很高,内存还有剩余,则我们就有可以用以空间换时间的方法来提高程序执行的效率。
五、数学方法解决问题
数学是计算机之母,计算机的发展是以数学为依据和基础的,所以在编写程序的时候,适当地采用一些数学方法会对程序的执行效率有数量级的提高,如下例所示:
方法1:inti,,j;For(i=1;i<=100;i=++){j+=i;}方法2:inti;i=(100*(1+100))/2六、使用位操作
一般的位操作是用来控制硬件的,或者做数据变换使用,但是,灵活的位操作可以减少除法和取模的运算有效地提高程序运行的效率,如下例所示:
方法1:intI,J;I=257/8;J=456%32;方法2:intI,J;I=257>>3;J=456-(456>>4<<4);七、嵌入汇编
汇编语言是效率最高的计算机语言,但是它地可读性较差,因此在C语言编程中为了获得程序的高效率,我们可以采用变通的方法--嵌入汇编、混合编程。
本章提要324汇编语言上机过程嵌入式C语言程序设计技巧汇编语言与C语言混合编程技术1汇编语言源程序格式汇编语言与C语言混合编程技术ARM体系结构支持ARM的汇编语言与C与C++的混合编程.一般的在一个完整的程序设计的中,除了初始化部分用汇编语言完成外,其大部分的编程任务一般都用C或C++完成。ATPCS介绍内嵌汇编C和ARM汇编程序间相互调用一、ATPCS介绍
ATPCS(ARM-ThumbProduceCallStandard)是ARM程序和Thumb程序中子程序调用的基本规则,目的是为了使单独编译的C语言程序和汇编程序之间能够相互调用。这些基本规则包括子程序调用过程中寄存器的使用规则、数据栈的使用规则和参数的传递规则。
1.寄存器的使用规则子程序间通过寄存器R0~R3来传递参数,这时,寄存器R0~R3可以记作A1~A4。
在子程序中,使用寄存器R4~R11来保存局部变量。这时,寄存器
R4~R11可以记作V1~V8。在Thumb程序中,通常只能使用寄存器R4~R7来保存局部变量。寄存器R12用作子程序间的scratch寄存器(用于保存SP,在函数返回时使用该寄存器出栈),记作ip。
寄存器R13用作数据栈指针,记作sp。
寄存器R14称为链接寄存器,记作lr。
寄存器R15是程序计数器,记作pc。
寄存器别名特殊名使用规则R0a1
参数/结果/scratch寄存器1R1a2
参数/结果/scratch寄存器2R2a3
参数/结果/scratch寄存器3R3a4
参数/结果/scratch寄存器4R4v1
ARM状态局部变量寄存器1R5v2
ARM状态局部变量寄存器2R6v3
ARM状态局部变量寄存器3R7v4wrARM状态局部变量寄存器4Thumb状态工作寄存器R8v5
ARM状态局部变量寄存器5R9v6sbARM状态局部变量寄存器6,在支持RWPI的ATPCS中为静态基址寄存器R10v7slARM状态局部变量寄存器7,在支持数据栈检查的ATPCS中为数据栈限制指针R11v8fpARM状态局部变量寄存器8/帧指针R12
ip子程序内部调用的scratch寄存器R13
sp数据栈指针R14
lr连接寄存器R15
pc程序计数器2.数据栈的使用规则根据堆栈指针指向位置的不同和增长方向的不同可以分为以下4种数据栈:
FD(FullDescending)满递减
ED(EmptyDescending)空递减
FA(FullAscending)满递增
EA(EmptyAscending)空递增
ATPCS规定数据栈为FD(满递减)类型,并且对数据栈的操作是8字节对齐的。
3.参数的传递规则参数个数固定的子程序参数传递规则:第一个整数参数,通过寄存器R0~R3来传递。其他参数通过数据栈传递。参数个数可变的子程序参数传递规则:当参数不超过4个时,可以使用寄存器R0~R3来传递参数;当参数超过4个时,还可以使用数据栈来传递参数子程序结果返回规则:
结果为一个32位的整数时,可以通过寄存器R0返回;结果为一个64位整数时,可以通过寄存器R0和R1返回,依次类推。二、内嵌汇编
在C程序中嵌入汇编程序可以实现一些高级语言没有的功能,并可以提高执行效率。armcc和armcpp内嵌汇编器支持完整的ARM指令集;tcc和tcpp用于Thumb指集。内嵌的汇编指令包括大部分的ARM指令和Thumb指令,但是不能直接引用C的变量定义,数据交换必须通过ATPCS进行。嵌入式汇编在形式上表现为独立定义的函数体。1.内嵌汇编指令的语法格式
__asm(“指令[;指令]”);ARMC汇编器使用关键字“__asm"。如果有多条汇编指令需要嵌入,可以用“{}”将它们归为一条语句。如:__asm{指令[;指令]…[指令]}需要特别注意的是__asm是两个下划线。2.内嵌的汇编指令的特点
操作数可以是寄存器、常量或C表达式。它们可以是char、short或者int类型,而且是作为无符号数进行操作。内嵌的汇编指令中使用物理寄存器有一些限制。常量前的符号“#”可以省略只有指令B可以使用C程序中的标号,指令BL不能使用C程序中的标号。不支持汇编语言中用于内存分配的伪操作。指令中如果包含常量操作数,该指令可能会被汇编器展开成几条指令。3.内嵌汇编器与armasm汇编器的区别
内嵌汇编器不支持通过“·”指示符或PC获取当前指令地址;
不支持LDRRn,=expression伪指令,而使用MOVRn,
expression指令向寄存器赋值;
不支持标号表达式;不支持ADR和ADRL伪指令;不支持BX和BLX指令;不可以向PC赋值;使用0x前缀替代“&”表示十六进制数。
4.内嵌汇编注意事项
必须小心使用物理寄存器,如R0~R3,LR和PC。
不要使用寄存器寻址变量。
使用内嵌汇编时,编译器自己会保存和恢复它可能用到的寄存器,用户无须保存和恢复寄存器。
LDM和STM指令的寄存器列表只允许物理寄存器。
汇编语言用“,”作为操作数分隔符
三、C和ARM汇编程序间相互调用
在C和ARM汇编程序之间相互调用必须遵守ATPCS(ARM-ThumbProcedureCallStandard)规则。C和汇编之间的相互调用可以从以下这三方面来介绍:汇编程序对C全局变量的访问在C语言程序中调用汇编程序在汇编程序中调用C语言程序1.汇编程序访问全局C变量
汇编程序可以通过地址间接访问在C语言程序中声明的全局变量。通过使用IMPORT关键词引人全局变量,并利用LDR和STR指令根据全局变量的地址可以访问它们。对于不同类型的变量,需要采用不同选项的LDR和STR指令,如下所示:
unsignedchar LDRB/STRBunsignedshort LDRH/STRHunsignedint LDR/STRchar LDRSB/STRSBshort LDRSH/STRSHAREAglobals,CODE,READONLYEXPORTasmsubroutine;IMPORTglobvar
;asmsubroutineLDRR1,=globvar;从文字池读globvar的地;址,并将其保存到R1LDRR0,[R1] ;再将其值读入到寄存器R0中ADDR0,R0,#2STRR0,[R1];修改后再将寄存器R0的值;赋予变量globvarMOVPC,LREND2.在C语言程序中调用汇编程序
为了保证程序调用时参数的正确传递,汇编程序的设计要遵守ATPCS。在汇编程序中需要使用EXPORT伪操作来声明,使得本程序可以被其它程序调用。同时,在C程序调用该汇编程序之前需要在C语言程序中使用extern关键词来声明该汇编程序。C源程序:#include<stdio.h>externvoidstrcopy(char*d,constchar*s)
;用extern声明一个函数为外部函数,可以被其他文件中的函数调用。intmain(){constchar*srcstr=“Firststring
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- +第三单元章节综合学练习题 统编版高中语文必修上册
- 2024标准合法借款合同样式
- 2024年幼儿园国庆节主题活动实施方案
- DB1505T 20-2024 医疗保障定点医药机构协议管理规范
- 第11课+応援+导学案 高中日人教版初中日语第一册
- 2024年注册监理工程师《合同管理》热身练习题
- 2024音像制品复制加工合同
- 河南省平顶山市42中学2025届初三第一次诊断考试英语试题理试题含答案
- 2024土地抵押个人借贷合同
- 2024“画廊-艺术家”代理合同的样本纲要
- 《第2课 感知智能生活》参考课件6
- 康复领域的3D打印技术应用
- 《认识周长》(教学设计)人教版三年级上册数学
- 新生儿小肠坏死性结肠炎及护理课件
- 飞机租赁服务合同
- 以爱为桨乘梦远航 育人方略
- 湖南省长沙市雅礼教育集团2023-2024学年七年级下学期期末语文试题
- 小学大课间体育活动开展现状调查与研究 论文
- 专升本合同协议模板
- G -B- 17378.2-2007 海洋监测规范 第2部分 数据处理与分析质量控制-副本(正式版)
- 患者发生误吸的应急预案
评论
0/150
提交评论