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

下载本文档

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

文档简介

1、ARM处理器开发详解处理器开发详解第第4章章 ARM汇编语言程序设计汇编语言程序设计2 由于高级编程语言隐藏了由于高级编程语言隐藏了CPUCPU执行指令的许多细节,因执行指令的许多细节,因此在只关心系统所具有功能的系统中,采用高级语言编写此在只关心系统所具有功能的系统中,采用高级语言编写程序更为合适。程序更为合适。 但是,但是,CPUCPU执行指令的细节差异会反应在系统的非功能执行指令的细节差异会反应在系统的非功能特性上,例如系统程序的规模和运行速度。因此,掌握汇特性上,例如系统程序的规模和运行速度。因此,掌握汇编语言程序设计对于嵌入式系统的设计者来说是非常必要编语言程序设计对于嵌入式系统的设

2、计者来说是非常必要的。的。3 3 4.1 ARM汇编器支持的伪操作汇编器支持的伪操作4.2 ARM汇编器支持的伪指令汇编器支持的伪指令4.3 ARM 汇编语言的语句格式汇编语言的语句格式4.4 ARM 汇编语言的程序结构汇编语言的程序结构4.5 汇编语言与汇编语言与C语言的混合编程语言的混合编程本章课程:本章课程:4 4 4.1.1 伪操作概述伪操作概述 伪操作伪操作(Directive)是是ARM汇编语言程序里的一汇编语言程序里的一些特殊的些特殊的指令助记符指令助记符,其作用主要是为完成汇编程其作用主要是为完成汇编程序做各种准备工作序做各种准备工作,对源程序运行汇编程序处理对源程序运行汇编程

3、序处理,而而不是在计算机运行期间由处理器执行。不是在计算机运行期间由处理器执行。 伪操作仅在汇编过程中起作用,一旦汇编结伪操作仅在汇编过程中起作用,一旦汇编结束,伪操作的使命就完成。束,伪操作的使命就完成。 4.1 ARM汇编器支持的伪操作汇编器支持的伪操作5伪操作主要有:伪操作主要有:u符号定义伪操作符号定义伪操作u数据定义伪操作数据定义伪操作u汇编控制伪操作汇编控制伪操作u杂项伪操作杂项伪操作6 6 4.1.2 符号定义伪操作符号定义伪操作 符号定义伪操作用于符号定义伪操作用于定义定义ARM汇编程序中的变量、对汇编程序中的变量、对变量赋值及定义寄存器的别名变量赋值及定义寄存器的别名等操作。

4、等操作。 常见的符号定义伪操作有如下几种:常见的符号定义伪操作有如下几种:(1)用于定义)用于定义全局变量全局变量的的GBLA、GBLL和和GBLS。(2)用于定义)用于定义局部变量局部变量的的LCLA、LCLL和和LCLS。(3)用于)用于对变量赋值对变量赋值的的SETA、SETL和和SETS。(4)为)为通用寄存器列表定义名称的通用寄存器列表定义名称的RLIST。7 7 1全局变量全局变量定义伪操作定义伪操作GBLA、GBLL和和GBLS(1)语法格式)语法格式GBLA、GBLL和和GBLS伪操作用于定义一个伪操作用于定义一个ARM程序中的全局程序中的全局变量并将其初始化。变量并将其初始化

5、。 GBLA伪操作用于定义一个全局的伪操作用于定义一个全局的数字变量并初始化为数字变量并初始化为0 GBLL伪操作用于定义一个全局的伪操作用于定义一个全局的逻辑变量并初始化为逻辑变量并初始化为F GBLS伪操作用于定义一个全局的伪操作用于定义一个全局的字符串变量并初始化为空字符串变量并初始化为空语法格式如下:语法格式如下: 取值为取值为GBLA、GBLL、GBLS三者中的之一三者中的之一 定义的全局变量名,在其作用范围内必须唯一。定义的全局变量名,在其作用范围内必须唯一。8 8 (2)示例)示例 使用伪操作声明全局变量。使用伪操作声明全局变量。 GBLA Test1;定义一个全局的数字变量,变

6、量名为定义一个全局的数字变量,变量名为 ;Test1 Test1 SETA 0 xaa;将该变量赋值为将该变量赋值为0 xaa GBLL Test2;定义一个全局的逻辑变量,变量名为定义一个全局的逻辑变量,变量名为 ;Test2 Test2 SETL TRUE;将该变量赋值为真将该变量赋值为真 GBLS Test3;定义一个全局的字符串变量,变量名定义一个全局的字符串变量,变量名 ;为为Test3 Test3 SETS Testing ;将该变量赋值为将该变量赋值为“Testing”9 9 2局部变量局部变量定义伪操作定义伪操作LCLA、LCLL和和LCLS(1)语法格式)语法格式LCLA、L

7、CLL和和LCLS伪指令用于定义一个伪指令用于定义一个ARM程序中的局程序中的局部变量并将其初始化。部变量并将其初始化。 LCLA伪操作用于定义一个伪操作用于定义一个局部的数字变量并初始化为局部的数字变量并初始化为0 LCLL伪操作用于定义一个伪操作用于定义一个局部的逻辑变量并初始化为局部的逻辑变量并初始化为F LCLS伪操作用于定义一个伪操作用于定义一个局部的字符串变量并初始化为空局部的字符串变量并初始化为空语法格式如下:语法格式如下: 取值为取值为LCLA、LCLL、LCLS三者中的之一。三者中的之一。 定义的局部变量名,在其作用范围内必须唯一。定义的局部变量名,在其作用范围内必须唯一。1

8、010 (2)示例)示例 使用伪操作声明局部变量。使用伪操作声明局部变量。 LCLA Test4;声明一个局部的数字变量,变量名为声明一个局部的数字变量,变量名为 ;Test4 Test4 SETA 0 xaa;将该变量赋值为将该变量赋值为0 xaa 下面的例子定义一个宏,显示了局部变量的作用范围。下面的例子定义一个宏,显示了局部变量的作用范围。 MACRO;声明一个宏声明一个宏$label message $a;宏原型宏原型 LCLS err;声明局部字符串变量声明局部字符串变量$label INFO 0,err:CC:STR:$a MEND;宏结束,局部变量不再起作用宏结束,局部变量不再起

9、作用1111 3变量赋值变量赋值伪操作伪操作SETA、SETL和和SETS(1)语法格式)语法格式伪指令伪指令SETA、SETL和和SETS用于给一个已经定义的全局变用于给一个已经定义的全局变量或局部变量赋值。量或局部变量赋值。 SETA伪操作用于给一个伪操作用于给一个数学变量赋值数学变量赋值。 SETL伪操作用于给一个伪操作用于给一个逻辑变量赋值。逻辑变量赋值。 SETS伪操作用于给一个伪操作用于给一个字符串变量赋值字符串变量赋值。语法格式如下:语法格式如下:Variable expr Variable 变量名为已经定义过的全局变量或局部变量。变量名为已经定义过的全局变量或局部变量。 取值为

10、取值为SETA、SETL、SETS三者中的之一。三者中的之一。 expr 数学、逻辑或字符串表达式,也就是将要赋予变量数学、逻辑或字符串表达式,也就是将要赋予变量的值。的值。1212 (2)示例)示例 为预先定义的变量赋值。为预先定义的变量赋值。 LCLA Test3;声明一个局部的数字变量,变量名为声明一个局部的数字变量,变量名为 ;Test3 Test3 SETA 0 xaa;将该变量赋值为将该变量赋值为0 xaa 使用变量赋值伪操作,定义一些程序相关内容。使用变量赋值伪操作,定义一些程序相关内容。 GBLA versionNumber VersionNumber SETA 21 GBLL

11、 Debug DebugSETL TRUE GBLSversionString VersionString SETS version 1.0 提示:在向变量赋值前必须先声明变量。提示:在向变量赋值前必须先声明变量。1313 4.1.3 数据定义(数据定义(Data Definition)伪操作)伪操作数据定义伪操作一般用于数据定义伪操作一般用于:为特定的数据分配存储单元为特定的数据分配存储单元;可完成已分配存储单元的初始化可完成已分配存储单元的初始化。主要包括:主要包括:(1)LTORG (1)LTORG 声明一个文字池。声明一个文字池。(2)MAP (2)MAP 定义一个结构化的内存表的首地

12、址。定义一个结构化的内存表的首地址。(3)FIELD (3)FIELD 定义结构化内存表中的一个数据域。定义结构化内存表中的一个数据域。(4)SPACE (4)SPACE 分配一块内存单元,并初始化为分配一块内存单元,并初始化为0 0。(5)(5)DCBDCB 分配一段字节的内存单元并用指定的数据初始化。分配一段字节的内存单元并用指定的数据初始化。14 当程序中使用当程序中使用LDR之类的指令时,数据缓冲池的使用之类的指令时,数据缓冲池的使用可能越界。为防止越界发生,可使用可能越界。为防止越界发生,可使用LTONG伪操作定义伪操作定义数据缓冲池。通常大的代码段可以使用多个数据缓冲池。数据缓冲池

13、。通常大的代码段可以使用多个数据缓冲池。ARM汇编编译器一般把数据缓冲池放在代码段的最后面,汇编编译器一般把数据缓冲池放在代码段的最后面,即下一代码段开始之前,或者即下一代码段开始之前,或者END伪操作之前。伪操作之前。 LTORG指示符要求汇编器立即安排一个数据缓指示符要求汇编器立即安排一个数据缓冲池(文字池)冲池(文字池) 。1.LTORG指示符指示符15AREA EXP_1, CODE, READONLYAREA EXP_1, CODE, READONLYSTARTSTART BL BL FUNC1 FUNC1FUNC1FUNC1;CODE;CODE LDR R1,=0 x800 LDR

14、 R1,=0 x800 ; ; 将将0 x8000 x800加载到加载到R1R1;CODE;CODE MOV PC, LR MOV PC, LR; ; 子程序结束子程序结束 LTORGLTORG; ; 定义数据缓冲池定义数据缓冲池DATADATASPACE 40 SPACE 40 ; ; 从当前位置开始分配从当前位置开始分配4040字节字节ENDEND; 0 x800; 0 x800的值被编译器暂时放在了的值被编译器暂时放在了data0-3data0-3字字 ; ;段中。段中。LTORG指示符例子指示符例子16 ADS编译器使用编译器使用MAP和和FIELD两个指示符描述两个指示符描述数据结构

15、。数据结构。MAP定义了数据结构的起始地址;定义了数据结构的起始地址;FIELD用来定义数据结构中的字段。说明一个数据项用来定义数据结构中的字段。说明一个数据项所需要的内存空间,并且为这个数据项提供一个标所需要的内存空间,并且为这个数据项提供一个标号号。2. MAP和和FIELD指示符指示符17startofdataEQU0 x0100 MAP startofdataint_aFIELD 4int_bFIELD 4str_one FIELD 64k_array FIELD 128bit_maskFIELD 4MAP和和FIELD指示符例子指示符例子 本例中数据结构的起始位置映射到固定(绝对)地

16、址本例中数据结构的起始位置映射到固定(绝对)地址0 x0100,然后为各个字段分配空间。也可以用,然后为各个字段分配空间。也可以用LDR和和STR之类的指令对结构体中的字段进行操作。例如使用下面的语之类的指令对结构体中的字段进行操作。例如使用下面的语句:句:LDRR4, int_a18分配一片连续的字节存储单元并初始化为指定字分配一片连续的字节存储单元并初始化为指定字符串符串 DCB伪操作用于分配一片连续的字节存储单伪操作用于分配一片连续的字节存储单元并用伪指令中指定的表达式初始化。元并用伪指令中指定的表达式初始化。3.DCB 与与C中的字符串不同,中的字符串不同,ARM汇编中的字符串不以汇编

17、中的字符串不以null结尾,下面指令以结尾,下面指令以ARM汇编形成一个汇编形成一个C语言风格的语言风格的字符串。字符串。Str DCB This is a test! C_string DCB C_string,019 数据定义指示符数据定义指示符LTORG指示汇编器汇编当前文字池指示汇编器汇编当前文字池 或或MAP置存储映射的起点到一个特定的地址置存储映射的起点到一个特定的地址# 或或FIELD描述指示符所定义的存储映射中的空间描述指示符所定义的存储映射中的空间% 或或SPACE定义一块值为定义一块值为0的存储器区域的存储器区域= 或或DCB分配一个或多个字节分配一个或多个字节&

18、或或DCD分配一个或多个字,从分配一个或多个字,从4字节边界开始字节边界开始DCDU分配一个或多个字,但不一定从分配一个或多个字,但不一定从4字节边界开始字节边界开始DCDO分配以字边界开始的存储区域,并指定初始值为到静态分配以字边界开始的存储区域,并指定初始值为到静态基址寄存器的偏移基址寄存器的偏移DCFD分配给双精度浮点数一段以字边界开始的内存区域分配给双精度浮点数一段以字边界开始的内存区域DCFDU分配给双精度浮点数一段以任意边界开始的内存区域分配给双精度浮点数一段以任意边界开始的内存区域DCFS分配给单精度浮点数一段以字边界开始的内存区域分配给单精度浮点数一段以字边界开始的内存区域DC

19、FSU分配给单精度浮点数一段以任意边界开始的内存区域分配给单精度浮点数一段以任意边界开始的内存区域DCI分配以字边界开始的存储区域,并指定初始值。标记此分配以字边界开始的存储区域,并指定初始值。标记此地址存储的是代码而不是数据地址存储的是代码而不是数据DCQ分配给双精度浮点数一段以分配给双精度浮点数一段以4字节边界开始的内存区域字节边界开始的内存区域DCQU分配给双精度浮点数一段以任意边界开始的内存区域分配给双精度浮点数一段以任意边界开始的内存区域DCW分配给一个或多个半字以半字边界开始的内存区域分配给一个或多个半字以半字边界开始的内存区域DCWU分配给一个或多个半字以任意边界开始的内存区域分

20、配给一个或多个半字以任意边界开始的内存区域DATA标识一个标号是代码段中数据的标号,该符号后是标识一个标号是代码段中数据的标号,该符号后是DCB或或DCD2020 4.1.4 汇编控制伪操作汇编控制伪操作 汇编控制伪操作汇编控制伪操作用于控制汇编程序的执行流程,汇编控用于控制汇编程序的执行流程,汇编控制伪操作用于条件汇编、宏定义和重复汇编控制等制伪操作用于条件汇编、宏定义和重复汇编控制等,该类伪该类伪操作如下所述操作如下所述:(1)(1)IFIF、ELSEELSE和和ENDIFENDIF (2)(2) MACRO MACRO和和MENDMEND (3) (3) WHILEWHILE和和WEND

21、WEND IFIF、ELSEELSE和和ENDIFENDIF伪操作能够根据条件伪操作能够根据条件, ,把一段代码包括在汇编把一段代码包括在汇编程序内或将其排除在程序之外。程序内或将其排除在程序之外。 IFIF、ELSEELSE和和ENDIFENDIF是可以嵌套是可以嵌套使用的。使用的。MACROMACRO和和MENDMEND伪操作用于宏定义。伪操作用于宏定义。 MACROMACRO标识宏定义的开始标识宏定义的开始, , MENDMEND标识宏定义的结束。标识宏定义的结束。WHILEWHILE和和WENDWEND伪操作用于根据条件重复汇编相同的或几乎相同伪操作用于根据条件重复汇编相同的或几乎相同

22、的一段源程序。的一段源程序。 WHILEWHILE和和WENDWEND伪操作是可以嵌套使用的。伪操作是可以嵌套使用的。21 GBLL Test GBLL Test ;声明一个全局的逻辑变量;声明一个全局的逻辑变量Test Test IFIF Test = TRUE Test = TRUE 指令序列指令序列 1 1 ELSEELSE 指令序列指令序列 2 2 ENDIFENDIF 下面的例子用下面的例子用countcount来控制循环体执行次数。来控制循环体执行次数。Count SETA 1 Count SETA 1 WHILE count5 WHILE count b) a = a - b;

23、else b = b - a; return a;5757【程序程序2】充分利用了充分利用了ARM指令条件执行指令条件执行的特点,仅使用了的特点,仅使用了4条指令就完条指令就完成了全部算法。这对提供程序的代码密度和执行速度十分有帮助。成了全部算法。这对提供程序的代码密度和执行速度十分有帮助。事实上,事实上,分支指令十分影响处理器的速度。每次执行分支指令,处理分支指令十分影响处理器的速度。每次执行分支指令,处理器都会排空流水线,重新装载指令。器都会排空流水线,重新装载指令。用用ARM汇编语言重写来重写这个例子,如下所示。汇编语言重写来重写这个例子,如下所示。【程序程序1】gcd CMP r0,

24、r1 BEQ END BLT less SUB r0, r0, r1 B gcdless SUB r1, r1, r0 B gcdEND【程序程序2】gcd CMP r0, r1 SUBGT r0, r0, r1 SUBLT r1, r1, r0 BNE gcd58【例例3 3】统计一个字符串的长度。统计一个字符串的长度。( (统计以回车符为结束符的字符串长度统计以回车符为结束符的字符串长度) ) CR EQU 0 x0D CR EQU 0 x0D AREA Program AREA Program,CODECODE,READONLY READONLY ENTRY ENTRY Main Mai

25、n LDR R0,=String LDR R0,=String EOR R1,R1EOR R1,R1,R1 R1 Loop Loop LDRB R2LDRB R2,R0R0,#1 #1 CMP R2CMP R2,#CR #CR BEQ BEQ Done Done ADD R1ADD R1,R1R1,#1 #1 B Loop B Loop Done Done LDR ROLDR RO,=Number =Number STRB R1STRB R1,R0 R0 Here Here B Here B Here AREA Data1 AREA Data1,DATA DATA String String

26、DCB “Hello,China”DCB “Hello,China”,CR CR ALIGN ALIGN Number Number DCB 0 DCB 0 END END 这是按直到型循环写的程序。取出一个字符后先判断是否为回车符,再决这是按直到型循环写的程序。取出一个字符后先判断是否为回车符,再决定是否长度加定是否长度加l l。59【例例3 3】统计一个字符串的长度。统计一个字符串的长度。( (统计以回车符为结束符的字符串长度统计以回车符为结束符的字符串长度) ) CR EQU 0 x0D CR EQU 0 x0D AREA Program AREA Program,CODECODE,RE

27、ADONLY READONLY ENTRY ENTRY Main Main LDR R0,=String LDR R0,=String ;字符串首地址存入;字符串首地址存入R0 R0 EOR R1,R1EOR R1,R1,R1 R1 ;R1R1保存长度,先清零。(逻辑异或指令)保存长度,先清零。(逻辑异或指令) Loop Loop LDRB R2LDRB R2,R0R0,#1 #1 ;取出一个字符到;取出一个字符到R2R2,更新,更新R0 R0 CMP R2CMP R2,#CR #CR ;比较是否为回车符;比较是否为回车符 BEQ BEQ Done Done ;是回车符,循环结束;是回车符,循

28、环结束ADD R1ADD R1,R1R1,#1 #1 ;不是回车符,长度加;不是回车符,长度加1 1 B Loop B Loop ;下一次循环;下一次循环 Done Done LDR ROLDR RO,=Number =Number ;结果的单元地址存入;结果的单元地址存入R0 R0 STRB R1STRB R1,R0 R0 ;保存字符串长度;保存字符串长度 Here Here B Here B Here ;结束;结束 AREA Data1AREA Data1,DATA DATA String String DCB DCB “Hello,ChinaHello,China”,CR CR ;字符串

29、;字符串 ALIGN ALIGN Number Number DCB 0 DCB 0 ;保存结果的单元;保存结果的单元 END END 这是按直到型循环写的程序。取出一个字符后先判断是否为回车符,再决定这是按直到型循环写的程序。取出一个字符后先判断是否为回车符,再决定是否长度加是否长度加l l。6060 在嵌入式程序设计中,有些场合(如对具体在嵌入式程序设计中,有些场合(如对具体的硬件资源进行访问)必须用汇编语言来实现,的硬件资源进行访问)必须用汇编语言来实现,可以采用在嵌入式可以采用在嵌入式C语言程序中语言程序中嵌入汇编语言嵌入汇编语言或嵌或嵌入式入式C语言语言调用汇编语言调用汇编语言来实现

30、。来实现。 4.5 4.5 汇编语言与汇编语言与C C语言的混合编程语言的混合编程6161 ATPCS(ARM-Thumb Produce Call Standard)是)是ARM程序和程序和Thumb程序中子程序调程序中子程序调用的基本规则,目的是为了使单独编译的用的基本规则,目的是为了使单独编译的C语言程语言程序和汇编程序之间能够相互调用。序和汇编程序之间能够相互调用。包括:包括:子程序调用过程中寄存器的使用规则子程序调用过程中寄存器的使用规则数据栈的使用规则数据栈的使用规则参数的传递规则参数的传递规则4.5.1 ATPCS4.5.1 ATPCS介绍介绍一一 寄存器使用规则寄存器使用规则(

31、1)子程序间通过寄存器)子程序间通过寄存器R0R3传递参数传递参数,寄存,寄存器器R0R3可记作可记作A1A4。被调用的子程序在返。被调用的子程序在返回前回前无须恢复无须恢复寄存器寄存器R0R3的内容。的内容。(2)在子程序中,)在子程序中,ARM状态下使用寄存器状态下使用寄存器R4R11来保存局部变量,寄存器来保存局部变量,寄存器R4R11可记作可记作V1V8;Thumb状态下只能使用状态下只能使用R4R7来保存局来保存局部变量。部变量。 (3)寄存器)寄存器R12用作子程序间调用时临时保存栈指针,函数用作子程序间调用时临时保存栈指针,函数返回时使用该寄存器进行出栈,记作返回时使用该寄存器进

32、行出栈,记作IP;在子程序间的链;在子程序间的链接代码中常有这种使用规则。接代码中常有这种使用规则。(4)通用寄存器)通用寄存器R13用作数据栈指针,记作用作数据栈指针,记作SP。 (5)通用寄存器)通用寄存器R14用作链接寄存器用作链接寄存器 ;(6)通用寄存器)通用寄存器R15用作程序计数器,记作用作程序计数器,记作PC 。二、数据栈使用规则二、数据栈使用规则 过程调用标准规定数据栈为过程调用标准规定数据栈为FD类型类型,并且对,并且对数据栈的操作时要求数据栈的操作时要求8字节对齐的。字节对齐的。 三、参数传递规则三、参数传递规则1参数个数可变的子程序参数传递规则参数个数可变的子程序参数传

33、递规则 对于参数个数可变的子程序,对于参数个数可变的子程序, 当参数个数不超过当参数个数不超过4个时,可以使用寄存器个时,可以使用寄存器R0R3来传递;来传递; 当参数个数超过当参数个数超过4个时,还可以使用数据栈个时,还可以使用数据栈进行参数传递。进行参数传递。参数个数固定的子程序参数传递规则参数个数固定的子程序参数传递规则 如果如果系统不包含浮点运算的硬件部件且没有浮点系统不包含浮点运算的硬件部件且没有浮点参数时,则依次将各参数传送到寄存器参数时,则依次将各参数传送到寄存器R0R3中,中,如果参数个数多于如果参数个数多于4个,将剩余的字数据通过数据栈个,将剩余的字数据通过数据栈来传递来传递

34、;入栈的顺序与参数顺序相反,即最后一个字入栈的顺序与参数顺序相反,即最后一个字数据先入栈数据先入栈。 3、子程序结果返回规则、子程序结果返回规则 (1)结果为一个)结果为一个32位的整数时,通过位的整数时,通过寄存器寄存器R0返回;返回;结果为一个结果为一个64位整数时,通过位整数时,通过寄存器寄存器R0,R1返回。返回。(2)对于位数更多的结果,需要通过内存来传递。)对于位数更多的结果,需要通过内存来传递。4.5.2 内嵌汇编内嵌汇编(1)ARM开发工具编译环境下内嵌汇编语法格式开发工具编译环境下内嵌汇编语法格式ARM开发工具编译环境下实例开发工具编译环境下实例ARM开发环境下汇编可直接使用

35、开发环境下汇编可直接使用C中的变量!中的变量!(2)GNU ARM环境下内嵌汇编语法格式环境下内嵌汇编语法格式GNU ARM环境下实例环境下实例GNU开发环境下汇编不可直接使用开发环境下汇编不可直接使用C中的变量!中的变量!内嵌汇编应用举例内嵌汇编应用举例中断使能中断使能【例子例子】通过读取程序状态寄存器(通过读取程序状态寄存器(CPSR)并设置它)并设置它的中断使能位的中断使能位bit7来禁止来禁止/打开中断。需要注意的是,该打开中断。需要注意的是,该例只能运行在系统模式下,因为用户模式是无权修改程序例只能运行在系统模式下,因为用户模式是无权修改程序状态寄存器的。状态寄存器的。_inline

36、 void enable_IRQ(void) int tmp; _asm MRS tmp, CPSR BIC tmp, tmp, #0 x80 MSR CPSR_c, tmp _inline void disable_IRQ(void) int tmp; _asm MRS tmp, CPSR ORR tmp, tmp, #0 x80 MSR CPSR_c, tmp 73int main(void) disable_IRQ(); enable_IRQ();第一操作数怎么第一操作数怎么不是不是Rd?内嵌汇编的注意事项内嵌汇编的注意事项 后缀后缀.S文件中的汇编指令是用文件中的汇编指令是用armas

37、m汇编器进行汇编的汇编器进行汇编的,而,而C语言程序中的内嵌汇编指令则是用内嵌汇编器进行汇语言程序中的内嵌汇编指令则是用内嵌汇编器进行汇编的。编的。这两种汇编器存在一定的差异,所以在内嵌汇编时要注意。这两种汇编器存在一定的差异,所以在内嵌汇编时要注意。(1)必须小心使用物理寄存器必须小心使用物理寄存器,如,如R0R3、IP(R12)、)、LR(R14)和)和CPSR中的中的N、Z、C、V标志位。因为计算汇标志位。因为计算汇编代码中的编代码中的C表达式时,可能使用这些物理寄存器,并会修表达式时,可能使用这些物理寄存器,并会修改改N、Z、C、V标志位。标志位。例如例如 实现实现y = x+x/y。

38、_asm MOV R0, x /把把x的值给的值给R0 ADD y, R0, x/y /计算计算x/y时时R0的值会被修改的值会被修改在计算在计算x/y时时R0会被修改,从而影响会被修改,从而影响R0+x/y的结果。的结果。内嵌内嵌汇编程序中允许使用变量,用变量来代替寄存器汇编程序中允许使用变量,用变量来代替寄存器R0可以解决可以解决上述问题上述问题。这时内嵌汇编器将会为变量。这时内嵌汇编器将会为变量var分配合适的存储分配合适的存储单元,从而避免冲突的发生。如果内嵌汇编器不能分配合适单元,从而避免冲突的发生。如果内嵌汇编器不能分配合适的存储单元,它将会报告错误。的存储单元,它将会报告错误。_

39、asm MOV var, x /把把x的值给的值给R0 ADD y, var, x/y /计算计算x/y时时R0的值会被修改的值会被修改(2)不要使用寄存器代替变量不要使用寄存器代替变量。例如实现对例如实现对x加加1的操作。的操作。int INC_f (int x) /x存放在存放在R0中中 _asm ADD R0, R0, #1 /发生寄存器冲突,实际上发生寄存器冲突,实际上x的值没有变化的值没有变化 return(x); /返回返回x 当调用当调用INC_f(x)函数时,编译器会用其他寄存器代替函数时,编译器会用其他寄存器代替R0存放参数存放参数x,使得该函数将,使得该函数将x 原封不动地

40、返回。原封不动地返回。这段代码的正确写法如下:这段代码的正确写法如下:int INC_f (int x) /x存放在存放在R0中中 _asm ADD x,x, #1 /直接使用变量直接使用变量x return(x); /返回返回x内嵌汇编的局限性内嵌汇编的局限性 ARM开发工具编译环境下内嵌汇编语言,开发工具编译环境下内嵌汇编语言,指令操作数可以是寄存器、常量或指令操作数可以是寄存器、常量或C语言表达式。语言表达式。可以是可以是char、short或或int类型,而且是作为无符号类型,而且是作为无符号数进行操作。数进行操作。 但是但是当表达式过于复杂时需要使用当表达式过于复杂时需要使用较多的物

41、理寄存器,有可能产生冲突较多的物理寄存器,有可能产生冲突。 GNU ARM编译环境下内嵌汇编语言编译环境下内嵌汇编语言ARM开发工具稍有差别,开发工具稍有差别,不能直接引用不能直接引用C语言中的变量语言中的变量。 只有只有B指令可以使用指令可以使用C语言程序中的标号,语言程序中的标号,BL指令不能使用指令不能使用C语言程序中的标号。语言程序中的标号。 内存单元的分配都是通过内存单元的分配都是通过C语言程序完成的。语言程序完成的。 使用内嵌汇编器,不能通过对程序计数器使用内嵌汇编器,不能通过对程序计数器PC赋值,实现程序返回或跳转。赋值,实现程序返回或跳转。 指令中使用的指令中使用的C变量不能与

42、任何物理寄存器同变量不能与任何物理寄存器同名,否则会造成混乱。名,否则会造成混乱。4.5.3 汇编与嵌入式汇编与嵌入式C程序相互调用程序相互调用1汇编程序调用汇编程序调用C程序程序2 C程序调用汇编程序程序调用汇编程序1汇编程序调用汇编程序调用C程序程序在在GNU ARM编译环境下,汇编程序中要使用编译环境下,汇编程序中要使用.extern伪操作声明将要调用的伪操作声明将要调用的C程序;程序;在在ARM开发工具编译环境下,汇编程序中要使用开发工具编译环境下,汇编程序中要使用IMPORT伪操作声明将要调用的伪操作声明将要调用的C程序。程序。 汇编程序调用汇编程序调用C程序示例程序示例在在GNU ARM编译环境下编译环境下设计程序,用设计程序,用ARM汇汇编语言调用编语言调用C语言实

温馨提示

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

评论

0/150

提交评论