版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、2.5 ARM程序设计基础2.5 ARM程序设计基础 在嵌入式系统程序设计中,大量使用了C语言进行编程。在有些程序中,使用汇编语言进行编程则更加方便、简单,甚至是不可替代的,例如初始化硬件的代码、启动代码等。 2.5 ARM程序设计基础 2.5.1 ARM汇编语句格式 2.5.2 ARM汇编程序格式 2.5.3 汇编语言编程实例 2.5.4 汇编语言与C语言的混合编程 ARM源程序文件 文件类型扩展名汇编语言文件.sC语言源文件.cC+源文件.cpp引入文件.INC头文件.h使用简单的文本编辑器或者其他的编程开发环境进行编辑. ARM汇编语言语句格式ARM 汇编语言程序中符号的定义规则:符号区
2、分大小写,同名的大、小写符号会被编译器认为是两个不同的符号。符号由大小写字母、数字以及下划线组成。 符号在其作用范围内必须唯一。 自定义的符号名不能与系统的保留字相同。 符号名不应与指令或伪操作同名。 ARM汇编语言语句格式程序中的变量和常量 变量;变量有数字变量、逻辑变量和串变量3种类型 数字常量;使用EQU伪操作来定义数字常量。 标号;标号代表一个地址,段内标号的地址在汇编时确定,而段外标号的地址在连接时确定。 ARM汇编语言程序格式 在 ARM ( Thumb )汇编语言程序中,以段为单位组织源文件的。段是相对独立的指令或数据序列,具有特定的名称。段可以分为代码段和数据段,代码段的内容为
3、执行码,数据段存放代码运行时需要用到的数据。多个段在程序编译链接时最终形成一个可执行的映象文件。 ARM汇编语言程序格式 可执行映象文件通常由以下几部分构成: 一个或多个代码段,代码段的属性为只读。 0个或多个包含初始化数据的数据段,数据段的属性为可读写。 0个或多个不包含初始化数据的数据段,这些数据段被初始化为0,数据段的属性为可读写。 汇编语言源程序格式1 汇编语言程序的结构汇编源程序示例AREA Sort,CODE,READONLYENTRYstart MOV r4,#0 LDR r6,=src ADD r6,r6,#lenouter LDR r1,=src 汇编源程序示例inner L
4、DR r2,r1 LDR r3,r1,#4 CMP r2,r3 STRGT r3,r1 STRGT r2,r1,#4 ADD r1,r1,#4 CMP r1,r6 BLT inner ADD r4,r4,#4 CMP r4,#len SUBLE r6,r6,#4 BLE outer 汇编源程序示例stop MOV r0,#0 x18 LDR r1,=0 x20026 SWI 0 x123456 AREA Array,DATA,READWRITEsrc DCD 2,4,10,8,14,1,20len EQU 7*4 ENDARM的汇编语言程序一般由几个段组成,每个段均由AREA伪操作定义。段可以
5、分为多种,如代码段、数据段、通用段,每个段又有不同的属性,象代码段的默认属性为READONLY,数据段的默认属性为READWRITE。本程序定义了两个段,第一个段为代码段codesec;第二个段为数据段constdatasec。 汇编语言的行构成格式:标签 指令/伪操作 操作数 ;语句的注释所有的标签必须在一行的开头顶格写,前面不能留空格,后面也不能跟C语言中的标签一样加上“:”; ARM汇编器对标识符的大小写敏感,书写标号及指令时字母的大小写要一致;注释使用“;”符号,注释的内容从“;”开始到该行的结尾结束。例:Labeladd add r0,r0,r1Str1SETS“This is a
6、string.”;给字符串Str1赋值 汇编语言的行构成标签:标签是一个符号,可以代表指令的地址、变量、数据的地址和常数。一般以字母开头,由字母、数字、下划线组成。标签不能采用关键字。指令/伪操作指令/伪操作是指令的助记符或者定义符,它告诉ARM的处理器应该执行什么样的操作或者告诉汇编程序伪指令语句的伪操作功能。汇编语言的常量数字常量:十进制数,如1、2、123十六进制数,如 0 x123,0 xabc字符常量:由单引号及中间的字符组成,包括C语言中的转义字符,如a,n字符串常量:由一对双引号及中间的字符串表示,中间也可以使用C语言中的转义字符,比如:“abcdef0 xarn”逻辑常量:TR
7、UE,FALSE,注意带大括号 ARM汇编语言程序格式代码段示例:汇编语言源程序的基本结构: AREA Init , CODE , READONLY ENTRY Start LDR R0 , =0 x3FF5000 LDR R1 , 0 xFF STR R1 , R0 LDR R0 , =0 x3FF5008 LDR R1 , 0 x01 STR R1 , R0 END ARM汇编语言程序格式 ARM体系中通常有以下3种方式控制程序的执行流程: 在正常执行过程中,每执行一条ARM指令,程序计数器(PC)的值加4个字节;每执行一条Thumb指令,程序计数器寄存器(PC)加2个字节。整个过程是按顺
8、序执行。跳转指令,程序可以跳转到特定的地址标号处执行,或者跳转到特定的子程序处执行。 当异常中断发生时,系统执行完当前指令后,将跳转到相应的异常中断处理程序处执行。 ARM汇编程序设计顺序结构程序顺序结构是按照逻辑操作顺序,从某一条指令开始逐条顺序执行,直至某一条指令为止。 AREA EXAMPLE,CODE,READONLYENTRY;程序入口Start ;程序开始MOV R0,#10;将立即数10放入寄存器R0MOV R1,#3;将立即数3放入寄存器R1ADD R0,R0,R1;将R1和R0相加,结果放入R0END;程序结束 ARM汇编程序设计选择分支结构程序单分支结构程序 ARM汇编程序
9、设计选择分支结构程序 多分支结构 ARM汇编语言中的子程序调用 在 ARM 汇编语言程序中,子程序的调用一般是通过 BL 指令来实现的。在程序中,使用指令: BL 子程序名 该指令在执行时完成如下操作:将子程序的返回地址存放在连接寄存器 LR 中,同时将程序计器PC 指向子程序的入口点,当子程序执行完毕需要返回调用处时,只需要将存放在 LR 中的返回地址重新拷贝给程序计数器 PC即可。在调用子程序的同时,也可以完成参数的传递和从子程序回运算的结果,通常可以使用寄存器 R0 R3 完成。 ARM汇编语言中的子程序调用BL 指令调用子程序的汇编语言源程序的基本结构: AREA Init , COD
10、E , READONLY ENTRY Start LDR R0 , =0 x3FF5000 LDR R1 , 0 xFF STR R1 , R0 LDR R0 , =0 x3FF5008 LDR R1 , 0 x01 STR R1 , R0 BL PRINT_TEXT PRINT_TEXT MOV PC,LR END 简单汇编实例 简单汇编实例1、求两个数的最大值,并将最大值放与R0寄存器AREA MAX,CODE,READONLYENTRYSTARTMOV R1,#0 x16M0V R2,#0 x17CMP R1,R2 MOVMI R0,R2MOVPL R0,R1END 简单汇编实例2、循环
11、实现数的递减,即每次减1。最终结果为0时退出循环。AREA MAX,CODE,READONLYENTRYSTARTMOV R0,#10LOOPSUBS R0,R0,#1BNE LOOPEND 简单汇编实例2 简单汇编实例3 、修改下列C程序段代码为ARM汇编程序段代码。void gcd( int a, int b)while(a!=b)if (ab)a=a-b;elseb=b-a; 简单汇编实例4 、修改下列C程序段代码为ARM汇编程序段代码。AREA MAX,CODE,READONLYENTRYSTARTCMP R0,R1BEQ ENDBLT LessSUB R0,R0,R1BAL ENDL
12、essSUB R1,R1,R0END.4 汇编语言与C/C+的混合编程 在C或C+代码中实现汇编语言的方法有内联汇编和内嵌汇编两种,使用它们可以在C/C+程序中实现C/C+语言不能完成的一些工作。嵌入式C语言程序设计基础C语言“预处理伪指令”在嵌入式程序设计中的应用嵌入式程序设计中的函数及函数库嵌入式程序设计中常用的C语言语句嵌入式程序设计中C语言的变量、数组、结构、联合 C语言“预处理伪指令”在嵌入式程序设计中的应用 “预处理命令”可以改进程序设计的环境,提高编程效率,一般以#号打头 ,可分为以下三种 :文件包含宏定义条件编译文件包含文件包含伪指令可将头文件包含到程序中,头文件中定义的内容包
13、括符号常量、复合变量原型、用户定义的变量类型原型和函数的原型说明等。编译器编译预处理时用文件包含的正文内容替换到实际程序中。文件包含伪指令的格式:#include ;标准头文件#include“头文件名.h” ;自定义头文件#include 宏标识符宏定义宏定义伪指令分为:简单宏、参数宏、条件宏、预定义宏及宏释放。 简单宏:# define 宏标识符 宏体 参数宏:# define 宏标识符(形式参数表) 宏体条件宏定义:#ifdef宏标识符#ifndef 宏标识符#undef宏标识符#define宏标识符 宏体#define宏标识符 宏体#else#else#undef宏标识符#define
14、宏标识符 宏体#define宏标识符 宏体#endif#endif条件编译条件编译伪指令是写给编译器的,指示编译器在满足某一条件时仅编译源文件中与之相应的部分。其格式如右框中所示: #if(条件表达式1)#elif(条件表达式2)#elif(条件表达式n)#else#endif嵌入式C语言程序编写的简单构架 #include预编译指令 C语言代码,一般要用#include编译指令将所需要的头文件加到该程序中,这是很有必要的,尤其是对编写较大的程序代码时。随后是定义一些外部变量,并对程序中的函数进行声明。 主函数main()的编写; 在每一个C语言代码中,一定要有一个main()函数,在该函数中
15、完成该程序文件所要完成的各个功能,一般是通过调用各个子函数来完成。也可以调用其他文件中的函数。 完成相应功能的各个功能函数的编写。 各个函数之间可以相互调用。 嵌入式程序设计中常用的C语言语句C语言语句格式为: 标号: 语句; C语言语句很多,常用到的有以下几种:条件语句 swith语句循环语句 嵌入式C语言程序设计技巧变量定义参数传递 循环条件 变量定义 在变量声明的时候,最好把所有相同类型的变量放在一起定义,这样可以优化存储器布局。例: 对于局部变量类型的定义,使用short或char来定义变量并不是总能节省存储空间。有时使用32位int或unsinged int局部变量更有效率一些,如图
16、所示:变量定义中,为了精简程序,程序员总是竭力避免使用冗余变量。但有时使用冗余变量可以减少存储器访问的次数这可以提高系统性能。 参数传递 为了使单独编译的C语言程序和汇编程序能够互相调用,定义了统一的函数过程调用标准ATPCS。 ATPCS定义了寄存器组中的R0R3作为参数传递和结果返回寄存器,如果参数数目超过四个,则使用堆栈进行传递。 内部寄存器的访问速度是远远大于存储器的,所以要尽量使参数传递在寄存器里面进行,即应尽量把函数的参数控制在四个以下。 循环条件 计数循环是程序中十分常用的流程控制结构,一般有以下两种形式:for (loop=1;loop=limit;loop+) for (lo
17、op=limit;loop!=0;loop-)这两种循环形式在逻辑上并没有效率差异,但是映射到具体的体系结构中时,就产生了很大的不同,如下图所示: C与汇编语言混合编程ATPCS介绍内嵌汇编C和ARM汇编程序间相互调用ATPCS介绍 ATPCS(ARM-Thumb Procedure Call Standard)是ARM程序和Thumb程序中子程序调用的基本规则,目的是为了使单独编译的C语言程序和汇编程序之间能够相互调用。这些基本规则包括子程序调用过程中寄存器的使用规则、数据栈的使用规则和参数的传递规则。 寄存器的使用规则寄存器别名特殊名使用规则R0a1参数/结果scratch寄存器1R1a2
18、参数/结果scratch寄存器2R2a3参数/结果scratch寄存器3R3a4参数/结果scratch寄存器4R4v1ARM状态局部变量寄存器1R5v2ARM状态局部变量寄存器2R6v3ARM状态局部变量寄存器3R7v4wrARM状态局部变量寄存器4Thumb状态工作寄存器R8v5ARM状态局部变量寄存器5R9v6sbARM状态局部变量寄存器6,在支持RWPI的ATPCS中为静态基址寄存器R10v7slARM状态局部变量寄存器7,在支持数据栈检查的ATPCS中为数据栈限制指针R11v8fpARM状态局部变量寄存器8/帧指针R12ip子程序内部调用的scratch寄存器R13sp数据栈指针R1
19、4lr连接寄存器R15pc程序计数器ATPCS规则寄存器的使用规则子程序之间通过寄存器r0r3来传递参数,当参数个数多于4个时,使用堆栈来传递参数。此时r0r3可记作A1A4。在子程序中,使用寄存器r4r11保存局部变量。因此当进行子程序调用时要注意对这些寄存器的保存和恢复。此时r4r11可记作V1V8。寄存器r12用于保存堆栈指针SP,当子程序返回时使用该寄存器出栈,记作IP。寄存器r13用作堆栈指针,记作SP。寄存器r14称为链接寄存器,记作LR。该寄存器用于保存子程序的返回地址。寄存器r15称为程序计数器,记作PC。数据栈的使用规则根据堆栈指针指向位置的不同 和增长方向的不同可以分为以下
20、4种数据栈 : FD (Full Descending) 满递减 ED (Empty Descending)空递减 FA (Full Ascending) 满递增 EA (Empty Ascending) 空递增ATPCS规定数据栈为FD(满递减)类型,并且对数据栈的操作是8字节对齐的。 参数的传递规则参数个数固定的子程序参数传递规则: 第一个整数参数,通过寄存器R0R3来传递。其他参数通过数据栈传递。 参数个数可变的子程序参数传递规则: 当参数不超过4个时,可以使用寄存器R0R3来传递参数;当参数超过4个时,还可以使用数据栈来传递参数 子程序结果返回规则 结果为一个32位的整数时,可以通过寄
21、存器R0返回;结果为一个64位整数时,可以通过寄存器R0和R1返回,依次类推。 C和ARM汇编程序间相互调用 在C和ARM汇编程序之间相互调用必须遵守ATPCS(ARM-Thumb Procedure Call Standard)规则。C和汇编之间的相互调用可以从以下这三方面来介绍:汇编程序对C全局变量的访问在C语言程序中调用汇编程序在汇编程序中调用C语言程序汇编程序访问全局C变量 汇编程序可以通过地址间接访问在C语言程序中声明的全局变量。通过使用IMPORT关键词引入全局变量,并利用LDR和STR指令根据全局变量的地址可以访问它们。对于不同类型的变量,需要采用不同选项的LDR和STR指令,如
22、下所示: unsigned charLDRB/STRBunsigned shortLDRH/STRHunsigned intLDR/STRchar LDRSB/STRSBshort LDRSH/STRSH 子程序-访问C 程序的全局变量AREA globals,CODE,READONLYENTRYEXPORT asmsubroutimeIMPORT glovbvar ;声明外部变量glovbvarLDR R1,=glovbvar ;装载变量地址LDR R0,R1 ;读出数据ADD R0,R0,#1 ;加1 操作STR R0,R1 ;保存变量值MOV PC,LREND在C语言程序中调用汇编程序
23、为了保证程序调用时参数的正确传递,汇编程序的设计要遵守ATPCS。在汇编程序中需要使用EXPORT伪操作来声明,使得本程序可以被其它程序调用。同时,在C程序调用该汇编程序之前需要在C语言程序中使用extern关键词来声明该汇编程序。 例如在一个汇编源文件中定义了如下求和函数: EXPORT add ;声明add子程序将被外部函数调用 add ;求和子程序add ADD r0,r0,r1 MOV pc,lr 在一个C程序的main()函数中对add汇编子程序进行了调用: extern int add (int x,int y); /声明add为外部函数 void main() int a=1,b
24、=2,c; c=add(a,b); /调用add子程序 当main()函数调用add汇编子程序时,变量a、b的值会给了r0和r1,返回结果由r0带回,并赋值给变量c。函数调用结束后,变量c的值变成3。在汇编程序中调用C语言程序为了保证程序调用时参数的正确传递,汇编程序的设计要遵守ATPCS。在汇编程序调用C程序之前需要在汇编语言程序中使用IMPORT伪操作来声明C程序。在汇编程序中通过BL指令来调用子程序。 例如在一个C源文件中定义了如下求和函数:int add(int x,int y)return(x+y);调用add()函数的汇编程序结构如下:IMPORT add ;声明要调用的C函数MO
25、V r0,1MOV r1,2BL add ;调用C函数add当进行函数调用时,使用r0和r1实现参数传递,返回结果由r0带回。函数调用结束后,r0的值变成3。内嵌汇编 在C程序中嵌入汇编程序可以实现一些高级语言没有的功能,并可以提高执行效率。armcc和armcpp内嵌汇编器支持完整的ARM指令集;tcc和tcpp用于Thumb指集。 内嵌的汇编指令包括大部分的ARM指令和Thumb指令,但是不能直接引用C的变量定义,数据交换必须通过ATPCS进行。嵌入式汇编在形式上表现为独立定义的函数体。 内嵌汇编指令的语法格式 _asm(“指令;指令”);ARM C汇编器使用关键字“_asm。如果有多条汇
26、编指令需要嵌入,可以用“”将它们归为一条语句。如:_asm指令;指令指令需要特别注意的是_asm是两个下划线。 内嵌的汇编指令的特点 操作数可以是寄存器、常量或C表达式。它们可以是char、short或者int类型,而且是作为无符号数进行操作 。内嵌的汇编指令中使用物理寄存器有一些限制。常量前的符号“#”可以省略 只有指令B可以使用C程序中的标号,指令BL不能使用C程序中的标号。 不支持汇编语言中用于内存分配的伪操作。指令中如果包含常量操作数,该指令可能会被汇编器展开成几条指令。 内嵌汇编器与armasm汇编器的区别 内嵌汇编器不支持通过“”指示符或PC获取当前指令地址; 不支持LDR Rn,
27、= expression伪指令,而使用MOV Rn, expression指令向寄存器赋值; 不支持标号表达式;不支持ADR和ADRL伪指令; 不支持BX和BLX指令; 不可以向PC赋值; 使用0 x前缀替代“”表示十六进制数。 内嵌汇编注意事项 必须小心使用物理寄存器,如R0R3,LR和PC。 不要使用寄存器寻址变量。 使用内嵌汇编时,编译器自己会保存和恢复它可能用到的寄存器,用户无须保存和恢复寄存器。 LDM和STM指令的寄存器列表只允许物理寄存器。 汇编语言用“,”作为操作数分隔符 嵌入汇编程序举例使能IRQ 中断:_inline void enable_IRQ(void)int tmp
28、_asm /嵌入汇编代码MRS tmp,CPSR /读取CPSR 的值BIC tmp,tmp,#0 x80 /将IRQ 中断禁止位I 清零,即允许IRQ 中断MSR CPSR_c,tmp /设置CPSR 的值,“_c”表示控制域即7:0位嵌入汇编程序举例禁止IRQ 中断:_inline void disable_IRQ(void)int tmp;_asmMRS tmp,CPSRORR tmp,tmp,#0 x80MSR CPSR_c,tmp 本节描述如何在C+代码中使用C头文件。从C+调用C头文件之前,C头文件必须包含在externC命令中。本节包含以下两部分内容: (1)在C+中使用系统的C
29、头文件; (2)在C+中使用自定义的C头文件。3. C+中使用C头文件 要包括标准的系统 C 头文件,如 stdio.h,不必进行任何特殊操作,由编译器自动包含标准 C 头文件。 1在C+中使用系统C头文件 要包含自己的C头文件,用户必须将#include命令包在extern C语句中。 2在C+中使用自定义的C头文件 汇编程序、C程序及C+程序相互调用时,要特别注意遵守相应的AAPCS。下面一些例子具体说明了在这些混合调用中应注意遵守的AAPCS规则。3. 混合编程调用举例ARM汇编程序设计/c程序g()返回5个整数的和int g(int a, int b, int c, int d, int e)return a + b + c + d + e;汇编程序调用c程序g()计算5个整数i, 2*i, 3*i, 4*i, 5*i的和EXPORT fAREA f, CODE, READONLYIMPORT g ;使用伪操作数IMPORT声明c程序g()STR lr, sp,#-4! ;保存返回地址ADD r1, r0, r0 ;假设进入程序f时,r0中的值为i,r1值设为2*iADD r2, r1, r0 ;r2的值设为3*iADD r3,
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 民营医院院感专项培训考核试题附答案
- 2026年药品上市后风险管理考试试题及答案
- 学校消防应急疏散演练实施方案评估报告
- 地质灾害应急预案
- 地质钻探野外安全防护技师理论考试题
- 2026儿童家具安全标准升级对行业影响深度解读
- 2026低温鲜榨果汁保质技术与冷链物流分析报告
- 2026乳品加工副产品高值化利用添加剂技术开发现状报告
- 2026乐器制造专用木材供需格局演变报告
- 2026中国高端乳制品消费行为与品牌竞争策略分析报告
- 2025年公司主要负责人安全培训考试试题及答案(有一套)
- 2026事业单位笔试-福建-福建康复医学与技术(医疗招聘)历年参考题库含答案详解
- 2026年初级经济师经济基础真题试卷及答案解析
- 文学概论讲义
- 河南警察学院引进高层次人才考核办法(试行)
- 医院审方中心工作制度
- 2026年中铝集团校园招聘笔试
- 雨课堂学堂在线学堂云《Age of Sustainable Development(SDG Academy)》单元测试考核答案
- 心衰病的中医护理常规
- 重卡充电站施工总承包合同
- SJG 46 – 2023《建设工程安全文明施工标准》
评论
0/150
提交评论