分享
第8章 ARM汇编语言与嵌入式C混合编程_精简.ppt
下载文档

ID:3452456

大小:220.50KB

页数:66页

格式:PPT

时间:2024-05-08

收藏 分享赚钱
温馨提示:
1. 部分包含数学公式或PPT动画的文件,查看预览时可能会显示错乱或异常,文件下载后无此问题,请放心下载。
2. 本文档由用户上传,版权归属用户,汇文网负责整理代发布。如果您对本文档版权有争议请及时联系客服。
3. 下载前请仔细阅读文档内容,确认文档内容符合您的需求后进行下载,若出现内容与标题不符可向本站投诉处理。
4. 下载文档时可能由于网络波动等原因无法下载或下载错误,付费完成后未能成功下载的用户请联系客服处理。
网站客服:3074922707
第8章 ARM汇编语言与嵌入式C混合编程_精简 ARM 汇编语言 嵌入式 混合 编程 精简
第8章 ARM汇编语言与嵌入式C混合编程,本章首先简要的介绍了嵌入式C语言的编程规范,嵌入式开发中常用的位运算与控制位域及在嵌入式C程序设计中要注意的问题,为读者进行嵌入式C程序设计打基础。然后介绍在ARM汇编语言与嵌入式C语言进行相互调用的标准(AAPCS),并以大量的实例说明了相互调用应注意的问题。,内容提要,81 嵌入式C编程规范82 嵌入式C程序设计中的位运算83 嵌入式C程序设计中的几点说明84 嵌入式C程序设计格式85 过程调用标准ATPCS与AAPCS86 ARM汇编语言与嵌入式C混合编程,8.2 嵌入式C程序设计中的位运算,在嵌入式程序设计中,位操作是最常用的运算之一,因为在很多情况下要对寄存器中的某位或某个管脚进行操作,这些都需要用位操作来完成。,8.2.1 按位与操作,按位与运算符“&”是把参与运算的两个操作数所对应的各个二进制位进行按位相与。只有当对应的两个二进制位全为1时,结果才为1,否则为0。参与运算的两个操作数以补码形式出现。例如7&3,补码分别为0000 0111与0000 0011 按位与运算后结果为0000 0011等于十进制的3。按位与操作可以实现将特定的位清零,也可以用于提取出某数的指定位。,8.2.1 按位与操作,例8-1 通过取出LedStatus的特定位进行判断选择对端口B的数据寄存器进行特定的清零,控制LED1和LED2灯的点亮,其中端口B(rPDATAB)第2、3管脚分别连接LED1、LED2(管脚从0管脚开始编号,低电平点亮,程序不更改其他位)解:(1)根据LedStatus第0位的状态确定是否点亮LED1if(LedStatus,8.2.2 按位或操作,按位或操作运算符“|”是把参与运算的两个操作数对应的各个二进制位进行按位相或。对应的两个二进制位中只要有一个为1,结果就为1,当两个对应的二进制位都为0时,结果位为0。参与运算的两个操作数均以补码形式出现。例如7|3,7的补码为0000 0111,3的补码为0000 0011,结果为0000 0111。按位与操作可以实现将特定位的置位操作,也可以用于提取出某数的指定位。,8.2.2 按位或操作,例8-2 通过取出LedStatus的特定位进行判断选择对端口B的数据寄存器进行特定的置1,控制LED1和LED2灯的熄灭,其中端口B(rPDATAB)第2、3管脚分别连接LED1、LED2(管脚从0管脚开始编号,低电平点亮,程序不更改其他位)解:(1)根据LedStatus第0位的状态确定是否熄灭LED1if(LedStatus,8.2.3 按位异或操作,按位异或运算符“”是将参与运算的两个操作数对应的各个二进制位进行相异或,当对应的两个二进制位相异时,结果位为1,相同时为0。参与运算的两个操作数均以补码形式出现。例如7|3,7的补码为0000 0111,3的补码为0000 0011,结果为0000 0100。,例8-3 按位异或操作可以实现将特定位的值取反,也可以实现在不引入第三个变量的情况下,交换两个变量的内容。(1)改变端口B的数据寄存器的第2位的值,如果原来为1则清零,如果原来为0则置1:rPDATAB=rPDATAB 0 x04(2)将rPDATAB 与变量tmp的值进行交换 rPDATAB=rPDATAB tmptmp=tmp rPDATAB rPDATAB=rPDATAB tmp,8.2.3 按位异或操作,8.2.4 取反操作,取反运算符“”实现对参与运算的操作数对应的各个二进制位按位求反。取反运算符“”具有右结合性。所有1变为0,0变为1例如(0101 1001)=1010 0110。在程序中主要用于将操作数的某位或某些位取反,为其他操作提供数据准备。tmp=tmp&1 作用是什么?,8.2.5 移位操作,移位操作分为左移操作与右移操作。左移运算符“”实现将“”左边的操作数的各个二进制位向左移动“”右边操作数所指定的位数,高位丢弃,低位补0。其值相当于乘以2左移位数。应用:设置相应的位#define BIT_UTXD1(0 x12)#define BIT_UTXD0(0 x15),右移运算符“”实现将“”左边的操作数的各个二进制位向右移动“”右边操作数所指定的位数。对于空位的补齐方式,无符号数与有符号数是有区别的。对无符号数进行右移时,低位丢弃,高位用0补齐,其值相当于除以2右移位数。对有符号数进行右移时,根据处理器的支持不同,有的采取逻辑右移,有的则采取算术右移。,8.2.5 移位操作,8.3 嵌入式C程序设计中的几点说明,8.3.1 volatile限制符8.3.2 地址强制转换与多级指针8.3.3 预处理的使用,8.3.1 volatile限制符,volatile的本意为“暂态的”或“易变的”,该说明符起到抑制编译器优化的作用。对于一个变量,如果编译器发现赋值后没有变化,编译器就可能优化代码,直接从内部高速缓存CACHE或寄存器获取数据,而不是从内存中读取。如果这段时间里,变量被中断服务或外围设备输入等编译器未知的原因更改,程序可能没有获得最新的值而导致运行结果异常,8.3.1 volatile限制符,如果在声明时用“volatile”关键进行修饰,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供特殊地址的稳定访问。下列情况应该使用volatile限制符:存储器映射的硬件寄存器;中断服务程序中修改的供其他程序检测的变量;多任务环境下各任务间共享的标志。,8.3.1 volatile限制符,例:(1)硬件端口寄存器读取char x=0,y=0,z=0;/读取I/O空间0 x5400000端口的内容存入x变量x=ReadChar(0 x5400000);y=x;/再次读取I/O空间0 x5400000端口的内容存入x变量x=ReadChar(0 x5400000);z=x;,8.3.1 volatile限制符,例:(1)硬件端口寄存器读取上面的程序很可能被编译器优化为:x=ReadChar(0 x5400000);y=x;z=x;因此声明时应改为:volatile char x;char y=0,z=0;,8.3.1 volatile限制符,例:(2)中断服务程序中修改供其他程序检测的变量static char flg=0;main(void)while(1)if(flg)/程序块A else/程序块B,8.3.1 volatile限制符,例:(2)中断服务程序中修改供其他程序检测的变量/*中断服务程序*/void ISR_INT1(void)flg=1;上页的代码很可能被优化为:static char flg=0;main(void)while(1)/程序块B,8.3.2 地址强制转换与多级指针,1.地址强制转换在C程序设计中,绝对地址0 x0FA00只是被当成一个整型数,如果要把它当成一个地址来使用就需要进行地址强制转换。如定义一个整形指针int*p,然后把绝对地址0 x0FA00转换成一个整形的地址值赋给这个整形指针,p=(int*)0 x0FA00。,在嵌入式程序设计中,经常可以可以看到寄存器用如下方式进行定义:#define rPCONA(*(volatile unsigned*)0 x1D20000)#define rPDATA(*(volatile unsigned*)0 x1D20004)其中,0 x1D20000为S3C44B0端口A的控制寄存器地址,0 x1D20004为S3C44B0端口A的数据寄存器地址。,8.3.2 地址强制转换与多级指针,8.3.3 预处理的使用,常见预处理命令:#define#undef#include#ifdef#ifndef#if#elif#else#endif,8.3.3 预处理的使用,1.宏定义(#define)(1)不带参数的宏 不带参数的宏定义的一般形式为:#define 宏名 宏体功能:用指定表示符(宏名)代替字符序列(宏体),可以定义在任何位置,一般定义在函数外面。如果没有使用#undef,它的作用域是从定义命令开始到文件的结束为止。#undef语法格式:#undef 宏名,8.3.3 预处理的使用,1.宏定义(#define)(1)不带参数的宏 例:#define YES 1#define NO 0if(x=YES)printf(“welcome!n”);else if(x=NO)printf(“error!n”);展开后:if(x=1)printf(“welcome!n”);else if(x=0)printf(“error!n”);,8.3.3 预处理的使用,1.宏定义(#define)(1)不带参数的宏 引号内与宏名相同的内容不进行替换,如:#define PI 3.14printf(“2*PI=%fn”,PI*2);展开后:printf(“2*PI=%fn”,3.14*2);,8.3.3 预处理的使用,(2)带参数的宏定义带参数的宏定义一般形式为:#define 宏名(参数表)宏体注意:宏名与后面的括号之间没有空格;宏的展开是将形参用实参进行替换,其他字符保留,宏体及各形参一般应加括号()。,8.3.3 预处理的使用,(2)带参数的宏定义例:#define POWER(x)x*xx=4;y=6;z=POWER(x+y);展开后,8.3.3 预处理的使用,2.文件包含(#include)文件包含的功能是使得一个源文件可以将另一个源文件的内容全部包含进来,它的一般形式为:#include“文件名”/先搜索当前目录,再搜索标准目录,可以指定目录#include/直接按标准目录搜索 一般在头文件(.h)中包含宏定义、数据结构定义、函数说明等,然后在源文件(.c)中使用文件包含命令,8.3.3 预处理的使用,2.文件包含(#include)例8-9/头文件#define SQR(x)(x)*(x)#define CUBE(x)(x)*(x)*(x)#define QUAD(x)(x)*(x)*(x)*(x)/源文件#include#include ex8_9.h#define MAX_POWER 10int main()int n;printf(numbert exp2t exp3t exp4tn);printf(-t-t-t-n);for(n=1;nMAX_POWER;n+)printf(%2dt%3dt%4dt%5dn,n,SQR(n),CUBE(n),QUAD(n);return 0;gcc只进行预编译的选项是什么?,8.6 ARM汇编语言与嵌入式C混合编程,在嵌入式程序设计中,有些场合(如对具体的硬件资源进行访问)必须用汇编语言来实现,可以采用在嵌入式C语言程序中嵌入汇编语言或嵌入式C语言调用汇编语言来实现。包括3种形式:C程序中内嵌汇编程序、C程序调用汇编程序、汇编程序调用C程序。,8.6.1 内嵌汇编,内嵌汇编是在嵌入式C程序中嵌入一段汇编代码,这段代码在形式上表现为独立定义的函数体。1.ARM开发工具编译环境下内嵌汇编语法格式,ARM开发工具编译环境下实例,void enable_IRQ(void)_asmmrs R5,CPSRBIC R5,R5,#0 x80MSR CPSR_c,R5int main(void)enable_IRQ();,ARM开发工具编译环境下实例,特点:可直接引用C语言中的变量。,void enable_IRQ(void)int temp;_asmMRS temp,CPSRBIC temp,temp,#0 x80MSR CPSR_c,tempint main(void)enable_IRQ();,8.6.1 内嵌汇编,2.内嵌汇编的局限性1)操作数ARM开发工具编译环境下内嵌汇编语言,指令操作数可以是寄存器、常量或C语言表达式。可以是char、short或int类型,而且是作为无符号数进行操作。表达式不要过于复杂,当表达式过于复杂时需要使用较多的物理寄存器,有可能产生冲突。GNU ARM编译环境下不能直接引用C语言中的变量。,8.6.1 内嵌汇编,2.内嵌汇编的局限性(2)物理寄存器不要直接向程序计数器PC赋值,程序的跳转只能通过B或BL指令实现。一般将寄存器R0R3、R12及R14用于子程序调用存放中间结果,因此在内嵌汇编指令中,一般不要将这些寄存器同时指定为指令中的物理寄存器。,8.6.1 内嵌汇编,2.内嵌汇编的局限性(2)物理寄存器在内嵌的汇编指令中使用物理寄存器时,如果有C语言变量使用了该物理寄存器,则编译器将在合适的时候保存并恢复该变量的值。通常在内嵌汇编指令中不要指定物理寄存器,因为有可能会影响编译器分配寄存器,进而可能影响代码的效率。,8.6.1 内嵌汇编,2.内嵌汇编的局限性(3)内存单元的分配 内嵌汇编器不支持汇编语言中用于内存分配的伪操作。所用的内存单元的分配都是通过C语言程序完成的,分配的内存单元通过变量以供内嵌的汇编器使用。,8.6.2 ARM汇编语言与嵌入式C程序相互调用,1汇编程序调用C程序2 C程序调用汇编程序,8.6.2 ARM汇编语言与嵌入式C程序相互调用,1汇编程序调用C程序在ARM开发工具编译环境下,汇编程序中要使用IMPORT/EXTERN伪操作声明将要调用的C程序。预备知识:汇编程序如何调用汇编程序(主程序和子程序在不同的文件中),8.6.2 ARM汇编语言与嵌入式C程序相互调用,例8-17在ARM开发工具编译环境下设计程序,用ARM汇编语言调用C语言实现20!的阶乘操作,并将64位结果保存到寄存器R0、R1中,其中R1中存放高32位结果。,8.6.2 ARM汇编语言与嵌入式C程序相互调用,建立C语言源文件factorial.c,其中定义求阶乘的函数,long long jiecheng(void)long long result=1;int temp;for(temp=20;temp1;temp-)result*=temp;return result;,8.6.2 ARM汇编语言与嵌入式C程序相互调用,怎么在汇编程序中调用C语言程序中定义的函数?,IMPORT jiechengAREA mainProgram,CODE,READONLYENTRYCODE32MOV R0,#0MOV R1,#0BL jiechengstopB stopEND,8.6.2 ARM汇编语言与嵌入式C程序相互调用,在汇编程序中将C语言函数的函数名视为程序标号进行处理。结果是如何返回的?,8.5.3 参数传递规则,3.子程序结果返回规则(1)结果为一个32位的整数时,通过寄存器R0返回;结果为一个64位整数时,通过寄存器R0,R1返回。(2)结果为一个浮点数时,可以通过浮点运算部件的寄存器F0、D0或者S0来返回;结果为复合型的浮点数(如复数)时,可以通过寄存器F0Fn或者0n来返回。(3)对于位数更多的结果,需要通过内存来传递。,8.6.2 ARM汇编语言与嵌入式C程序相互调用,能不能传递参数?将上述求阶乘的程序改写为更加通用的方式:求n的阶乘,long long jiecheng(int n)long long result=1;int temp;for(temp=n;temp1;temp-)result*=temp;return result;,8.6.2 ARM汇编语言与嵌入式C程序相互调用,汇编程序中调用C语言程序时如何给参数n传值?,IMPORT jiechengAREA mainProgram,CODE,READONLYENTRYCODE32MOV R0,#10MOV R1,#0BL jiechengstopB stopEND,8.6.2 ARM汇编语言与嵌入式C程序相互调用,R0传给了n?调用多个参数的子程序时如何传递参数?,8.5.3 参数传递规则,参数个数固定的子程序参数传递规则 如果系统不包含浮点运算的硬件部件且没有浮点参数时,则依次将各参数传送到寄存器R0R3中,如果参数个数多于4个,将剩余的字数据通过数据栈来传递;如果参数多于4个,将剩余字数据传送到数据栈中,入栈的顺序与参数顺序相反,即最后一个字数据先入栈。,8.5.3 参数传递规则,例 传递的参数多于4个时的情况,EXTERN sum AREA main,CODE,READONLY ENTRY CODE32start MOV R0,#100 MOV R1,#100,MOV R2,#100 MOV R3,#100 STMFD SP!,R4 MOV R4,#100 STMFD SP!,R4 BL sumexit B exit END,int sum(int a,int b,int c,int d,int e)return a+b+c+d+e;,8.6.2 ARM汇编语言与嵌入式C程序相互调用,2 C程序调用汇编程序在ARM开发工具编译环境下,C程序中要用关键字extern声明要调用的汇编语言程序。同时也要在汇编程序中使用EXPORT伪操作声明本程序可以被其他程序调用。在GNU ARM编译环境下,在C程序中要用关键字extern声明要调用的汇编语言程序,同时在汇编程序中要使用.global伪操作声明汇编程序为全局的函数,可被外部函数调用。,8.6.2 ARM汇编语言与嵌入式C程序相互调用,例8-18在ARM开发工具编译环境下设计程序,用C语言调用ARM汇编语言实现20的阶乘(20!)操作,并将64位结果保存到0 xFFFFFFF0开始的内存地址单元,按照小端格式低位数据存放在低地址单元。,8.6.2 ARM汇编语言与嵌入式C程序相互调用,汇编语言子程序,AREA Fctrl,CODE,READONLY EXPORT jiechengjiechengMOVR8,#20MOVR9,#0SUBR0,R8,#1LoopMOVR1,R9UMULLR8,R9,R0,R8MLAR9,R1,R0,R9SUBSR0,R0,#1BNELoopLDRR0,=0 xFFFFFFF0STMIAR0,R8,R9MOVPC,LREND,8.6.2 ARM汇编语言与嵌入式C程序相互调用,如果主程序也是汇编语言编写,则用BL指令调用子程序,IMPORT jiechengAREA mainProgram,CODE,READONLYENTRYCODE32BL jiechengstopB stopEND,主程序是C语言编写,如何转移到汇编程序某标号处执行呢?,8.6.2 ARM汇编语言与嵌入式C程序相互调用,答案是:以函数调用的方式调用汇编子程序,函数名为汇编程序第一条指令前的标号。,extern void jiecheng(void);main()char N=20;jiecheng();while(1);,程序运行结果如下:,8.6.2 ARM汇编语言与嵌入式C程序相互调用,C语言程序调用汇编语言子程序时如何传递参数?如何返回结果?,8.6.2 ARM汇编语言与嵌入式C程序相互调用,汇编语言子程序,AREA Fctrl,CODE,READONLY EXPORT jiechengjiechengMOVR8,R0MOVR9,#0SUBR0,R8,#1LoopMOVR1,R9UMULLR8,R9,R0,R8MLAR9,R1,R0,R9SUBSR0,R0,#1BNELoopLDRR0,=0 xFFFFFFF0STMIAR0,R8,R9MOVPC,LREND,8.6.2 ARM汇编语言与嵌入式C程序相互调用,extern void jiecheng(char x);main()char N=4;jiecheng(N);while(1);,8.5 过程调用标准ATPCS与AAPCS,过程调用标准ATPCS(ARM-Thumb Produce Call Standard)规定了子程序间相互调用的基本规则,ATPCS规定子程序调用过程中寄存器的使用规则、数据栈的使用规则及参数的传递规则。2007年,ARM公司推出了新的过程调用标准AAPCS(ARM Architecture Produce Call Standard),它只是改进了原有的ATPCS的二进制代码的兼容性。,8.5.1 寄存器使用规则,(1)子程序间通过寄存器R0R3传递参数,寄存器R0R3可记作A1A4。被调用的子程序在返回前无须恢复寄存器R0R3的内容。(2)在子程序中,ARM状态下使用寄存器R4R11来保存局部变量,寄存器R4R11可记作V1V8;Thumb状态下只能使用R4R7来保存局部变量。,8.5.1 寄存器使用规则,(3)寄存器R12用作子程序间调用时临时保存栈指针,函数返回时使用该寄存器进行出栈,记作IP;在子程序间的链接代码中常有这种使用规则。(4)通用寄存器R13用作数据栈指针,记作SP。在子程序中R13不能用于其他用途。SP在进入子程序时的值和退出子程序时的值必须相等。(5)通用寄存器R14用作链接寄存器。如果在子程序中保存了返回地址,如果R14可用于其他用途。(6)通用寄存器R15用作程序计数器,记作PC,不能用于其他用途。,8.5.2 数据栈使用规则,过程调用标准规定数据栈为FD类型,并且对数据栈的操作时要求8字节对齐(通过伪操作PRESERVE8来设置)。相关概念:数据栈指针SP:最后一个写入栈的数据的内存地址;数据栈基地址:数据栈的最高地址;数据栈界限:可使用的最低的地址单元;已占用的数据栈:基地址和SP之间的内存区域;未占用的数据栈:SP和数据栈界限之间的内存区域;数据栈中的数据帧:为子程序分配的用来保存寄存器和局部变量的区域。,8.5.3 参数传递规则,1参数个数可变的子程序参数传递规则对于参数个数可变的子程序,当参数个数不超过4个时,可以使用寄存器R0R3来传递;当参数个数超过4个时,还可以使用数据栈进行参数传递。在参数传递时,将所有参数看作是存放在连续的内存子单元中的字数据。然后依次将各个字数据传送到寄存器R0、R1、R2、R3中,如果参数多于4 个,将剩余字数据传送到数据栈中,入栈的顺序与参数顺序相反,即最后一个字数据先入栈。,8.5.3 参数传递规则,2.参数个数固定的子程序参数传递规则 如果系统不包含浮点运算的硬件部件且没有浮点参数时,则依次将各参数传送到寄存器R0R3中,如果参数个数多于4个,将剩余的字数据通过数据栈来传递;如果参数多于4个,将剩余字数据传送到数据栈中,入栈的顺序与参数顺序相反,即最后一个字数据先入栈。,8.5.3 参数传递规则,例8-15 在C语言程序中定义字符串string1和string2,通过调用ARM汇编语言程序将两个字符串内容进行互换。,EXTERN _mainAREA str_Swap,CODE,READONLYENTRYstartBL_mainstopBstopEND,externvoid string_swap(char,char);void _main(void)char string1100=ARM9TDMI-S;char string2100=I study ARM;string_swap(string1,string2);,8.5.3 参数传递规则,例8-15,EXPORT string_swapAREA str_swap,CODE,READONLYstring_swapLDRBR2,R0,#1LDRBR3,R1,#1STRBR2,R1,#-1STRBR3,R0,#-1CMPR2,#0CMPNER3,#0BNEstring_swapSUBSR2,R2,R3BMIcopy_string2,copy_string1LDRBR2,R0,#1STRBR2,R1,#1CMPR2,#0BNEcopy_string1MOVPC,LRcopy_string2LDRBR3,R1,#1STRBR3,R0,#1CMPR3,#0BNEcopy_string2MOVPC,LREND,

此文档下载收益归作者所有

下载文档
收起
展开