嵌入式系统基础 第6章--ARM程序设计_第1页
嵌入式系统基础 第6章--ARM程序设计_第2页
嵌入式系统基础 第6章--ARM程序设计_第3页
嵌入式系统基础 第6章--ARM程序设计_第4页
嵌入式系统基础 第6章--ARM程序设计_第5页
已阅读5页,还剩73页未读 继续免费阅读

下载本文档

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

文档简介

1、.,第6章 arm程序设计,本章的主要内容,1、arm汇编语言程序设计,2、arm程序的框架结构,3、c语言程序对汇编程序的调用,4、arm与c语言混合程序设计,.,6.1 arm工程,由于c语言便于理解,有大量的支持库,所以它是当前arm程序设计所使用的主要编程语言。,对硬件系统的初始化、cpu状态设定、中断使能、主频设定以及ram控制参数初始化等c程序力所不能及的底层操作,还是要由汇编语言程序来完成。,.,用汇编语言或c/c+语言编写的程序叫做源程序,对应的文件叫做源文件。,一个arm工程应由多个文件组成,其中包括扩展名为.s的汇编语言源文件、扩展名为.c的c语言源文件,扩展名为.cpp的

2、c+源文件、扩展名为.h的头文件等。,arm工程的各种源文件之间的关系,以及最后形成可执行文件的过程如下:,.,汇编语言 源文件,汇编器,目标文件,c/c+语言 源文件,编译器,目标文件,头文件,c/c+库文件,连接器,可执行文件,.,arm提供的开发工具code warrior for arm中包含的编译器如下:,.,除了c和c+编译器,code warrior for arm开发工具还提供了汇编器armasm。,编译器负责生成目标文件,它是一种包含了调试信息的elf格式文件。,编译器还要生成列表文件等相关文件:,.,.,各种源文件先由编译器和汇编器将它们分别编译或汇编成汇编语言文件及目标文

3、件。,连接器负责将所有目标文件连接成一个文件并确定各指令的确定地址,从而形成最终可执行文件。,连接器有三个功能:,.,(1)生成与地址相关的代码,把所有文件连接成一个可执行文件。,(2)根据程序员所指定的选项,为程序分配地址空间。,(3)给出连接信息,以说明连接过程和连接结果。,.,6.2 arm汇编语言程序设计,6.2.1 段,汇编语言编写的程序叫做汇编语言源程序,包含源程序的文件叫做汇编语言程序文件。,一个工程可以有多个源文件,汇编源文件的扩展名为.s。,.,在arm(thumb)汇编语言程序中,通常以段为单位来组织代码。段是具有特定名称且功能相对独立的指令或数据序列。,根据段的内容,分为

4、代码段和数据段。,一个汇编程序至少应该有一个代码段,当程序较长时,可以分割为多个代码段和数据段。,.,以下是一个汇编语言程序段的基本结构:,area init, code, readonly /只读的代码段init entry /程序入口点 start ldr r0,#0x3ff5000 ldr r1,0xff str r1,r0 ldr r0,#0x3ff5008 ldr r1,0x01 str r1,r0 . end /段结束,.,6.2.2 分支程序设计,具有两个或两个以上可选执行路径的程序叫做分支程序。,1、普通分支程序设计,使用带有条件码的指令可以很容易地实现分支程序。,.,例:编写

5、一个分支程序段,如果寄存器r5中的数据等于10,就把r5中的数据存如寄存器r1;否则把r5中的数据分别存储寄存器r0和r1。,.,(1)用条件指令实现的分支程序段,cmp r5,#10 movne r0,r5 mov r1,r5,(2)用条件转移指令来实现分支,cmp r5,#10 beq doequal mov r0,r5 doequal mov r1,r5,.,例:编写一个程序段,当寄存器r1中的数据大于r2中数据时,将r2中的数据加10存入寄存器r1;否则将r2中数据加5存入寄存器r1。,.,cmp r1,r2 addhi r1,r2,#10 addls r1,r2,#5,2、多分支(散

6、转)程序设计,程序分支点上有多于两个以上的执行路径的程序叫做多分支程序。利用条件测试指令或跳转表可以实现多分支程序。,.,例、编写一个程序段,判断寄存器r1中数据是否为10、15、12、22。如果是,则将r0中的数据加1;否则将r0设置为0xf。,.,mov r0,#0 teq r1,#10 teqne r1,#15 teqne r1,#12 teqne r1,#22 addeq r0,r0,#1 movne r0,#0xf,.,当多分支程序的每个分支所对应的是一个程序段时,常常把各个分支程序段的首地址依次存放在一个叫做跳转地址表的存储区域,然后在程序的分支点处使用一个可以将跳转表中的目标地址

7、传送到pc的指令来实现分支。,一个具有3个分支的跳转地址表示意图如下:,.,.,mov r0,n adr r5,jptb ldr pc,r5,r0,lsl #2 jptab ;跳转表 dcd fun0 dcd fun1 ecd fun2 fun0 . ;分支fun0的程序段 fun1 . ;分支fun1的程序段 fun2 . ;分支fun2的程序段,.,3、带arm/thumb状态切换的分支程序设计,在arm程序中经常需要在程序跳转的同时还要进行处理器状态的转移,即从arm指令程序段跳转到thumb指令程序段(或相反)。为了实现这个功能,系统提供了一条专用的、可以实现4gb空间范围内的绝对跳转

8、交换指令bx。,.,.,下面是一段从arm指令程序段跳转到thumb指令程序的状态切换例程。,;arm指令程序 code32 . add r0,into_thumb +1 bx r0 . ;thumb指令程序 code16 into_thumb .,.,下面是一段从thumb 指令程序段跳转到arm指令程序的状态切换例程。,; thumb 指令程序 code16 . add r5,back_to_arm bx r0 . ; arm指令程序 code32 back_to_arm .,.,6.2.3 循环程序设计,当条件满足时,需要重复执行同一个程序段做同样工作的程序叫做循环程序。,被重复执行的程

9、序段叫做循环体,需要满足的条件叫做循环条件。,循环程序有两种结构:do-while结构和do-until结构。,.,do-while结构,do-until结构,.,在汇编语言程序设计中,常用的是do-until结构循环程序。,mov r1,#10 loop . sub r1,r1,#1 bne loop,例、编写一个程序,把首地址为data_src的80个字的数据复制到首地址为data_dst的目标数据块中。,.,ldr r1,#data_src ldr r0,#data_dst mov r10,#10 loop ldmia r1!,r2-r9 stmia r0!,r2-r9 subs r10

10、,r10,#1 bne loop,6.2.4 子程序及其调用,.,1、子程序的调用与返回,人们把这种可以多次反复调用的、能完成指定功能的程序段称为“子程序”。把调用子程序的程序称为“主程序”。,为进行识别,子程序的第1条指令之前必须赋予一个标号,以便其他程序可以用这个标号调用子程序。,.,在arm汇编语言程序中,主程序一般通过bl指令来调用子程序。该指令在执行时完成如下操作:将子程序的返回地址存放在连接寄存器lr中,同时将程序计数器pc指向子程序的入口点。,为使子程序执行完毕能返回主程序的调用处,子程序末尾处应有mov、b、bx、stmfd等指令,并在指令中将返回地址重新复制到pc中。,.,在

11、调用子程序的同时,也可以使用r0r3来进行参数的传递和从子程序返回运算结果。,例、一个使用mov指令实现返回的子程序。,relay . mov pc, lr,使用b指令实现返回的子程序。,relay . b lr,.,例、一个使用bl指令调用子程序的汇编语言缘程序的基本结构。,aera init, code, readonly entry start ldr r0,#0x3ff5000 ldr r1,0xff str r1,r0 ldr r0,#0x3ff5008 ldr r1,0x01 str r1,r0 bl pr .,.,pr mov pc,lr end,2、子程序中堆栈的使用,rela

12、y stmfd r13!,r0r12,lr;压入堆栈 ;子程序代码 ldmfd r13!,r0r12,pc ;弹出堆栈并返回,.,6.2.5 汇编程序访问全局c变量,一般来说,汇编语言程序与c语言程序不在同一个文件上,所以实质上这是一个引用不同文件定义的变量问题。解决这个问题的办法就是使用关键字import和export。,例、下面是一个汇编代码的函数,它引用了一个在其他文件中定义的全局变量globvar,将其加2后写回globvar 。,.,area globvar, code, readonly export asmsubrouttine import globvar asmsubrout

13、tine ldr r1,# globvar ldr r0,r1 add r0,r0,#2 str r0,r1 mov pc,lr end,.,6.3 arm程序框架,在应用系统的程序设计中,若所有的编程任务均用汇编语言来完成,其工作量是可想而知的,这样做也不利于系统升级或应用软件移植。,通常汇编语言部分完成系统硬件的初始化;高级语言部分完成用户的应用。,.,执行时,首先执行初始化部分,然后再跳转到c/c+部分。整个程序结构显得清晰明了,容易理解。程序的基本结构如下:,硬件初始化的汇编语 言程序(特权模式) b main,完成用户任务的 c/c+程序(用户模式),跳转,.,6.3.1 初始化程序

14、部分,由于在用于完成初始化任务的汇编语言程序中需要在特权模式下做一些诸如修改cpsr等特权操作,所以不能过早地进入用户模式。,通常,初始化过程大致会经历如下所示的一些模式变化。,.,启动,管理模式svc,其他特权模式,用户模式usr,汇编语言 程序段,.,6.3.2初始化部分与主应用程序部分的衔接,当所有的系统初始化工作完成之后,就需要把程序流程转入主应用程序。最简单的方法是,在汇编语言程序末尾使用跳转指令b或bl直接从启动代码转移到c/c+程序入口。,b main ;跳转到c/c+程序,.,同时在汇编文件中有如下代码: import main,完整的汇编语言程序如下:,import main

15、 area init, code, readonly entry ldr r0,#0x3ff000 ldr r1,#0xe7ffff80 str r1,r0 ldr sp,#0x3ee1000 bl main end,.,c程序如下:,void main(void) . ,6.3.3 arm开发环境提供的程序框架,.,为方便工程开发,arm公司的开发环境arm ads为用户提供了一个可以选用的应用程序框架。该框架把为用户程序做准备工作的程序分成了启动代码和应用程序初始化两部分。,用于硬件初始化的汇编语言部分叫做启动代码;用于应用程序初始化的c部分叫做初始化部分。整个程序如下所示:,.,impo

16、rt_main 启动代码 b_main,应用程序初始化,主用程序,_main(),main(),.,6.4 c与汇编之间的函数调用,在arm工程中,c程序调用汇编函数和汇编程序调用c函数是经常发生的事情。为此人们制定了arm-thumb过程调用标准atpcs(arm-thumb procedure call standard)。,6.4.1 atpcs简介,.,1、堆栈与寄存器在函数调用中的作用,函数是通过寄存器和堆栈来传递参数和返回函数值的。,下面是c语言程序调用c函数的情况。,int addint(int x, int y) int s; s = x + y; return s; ,.,在

17、c程序中,主函数main()调用该函数的方法如下:,void main(void) . addint(a,b); /调用 ,.,arm编译器使用的函数调用规则就是atpcs标准。atpcs标准既是arm编译器的规则,也是设计可被c程序调用的汇编函数的编写规则。,2、atpcs关于堆栈和寄存器的使用规则,atpcs规定,arm的数据堆栈为fd型堆栈,即递减满堆栈。,.,atpcs标准规定,对于参数个数不多于4的函数,编译器必须按参数在列表中的顺序,自左向右为它们分配寄存器r0r3。其中函数返回时,r0还被用来存放函数的返回值。,.,如果函数的参数多于4个,那么多余的参数则按自右向做的顺序压入数据

18、堆栈,即参数入栈顺序与采纳书顺序相反。,.,下表列举了arm-thumb过程调用标准规定的寄存器的名称和使用方法。,.,寄存器的别名和特殊名称都是arm编译器和汇编器预定义的,用户可以直接使用。,6.4.2 c程序可调用汇编函数实例,下面是一个用汇编语言编写的函数,该函数把r1指向的数据块复制到r0指向的存储快。,.,area strcopy, code, readonly export strcopy strcopy ldrb r2,r1,#1 strb r2,r0,#1 cmp r2,#0 bne strcopy mov pc,lr end,.,根据atpcs的c语言程序调用汇编函数,参数

19、由左向右依次传递给寄存器r0r3的规则,可知汇编函数strcopy在c程序中原型应该为:,void strcopy(char *d, const char *s);,在c语言文件中,调用strcopy函数的方法如下:,.,extern void strcopy(char *d, const char *s); int main(void) const char *src = “source”; char dest10; . strcopy(dest, src; . ,.,6.4.3 汇编程序调用c函数实例,现有c函数g()如下:,int g(int a, int b, int c, int d

20、, int e) return a+b+c+d+e; ,汇编函数f中调用c函数g(),以实现下面的功能。,.,整个汇编函数f的代码如下:,int f(int i) return g(i, 2*i, 3*i, 4*i,5*i),export f area f, code, readonly import g ;声名g为外部引用符号 str lr, sp,#-4 ;断点存入堆栈 add r1,r0,r0 ;(r1)= i*2 add r2,r1,r0 ; (r2)= i*3 add r3,r1,r2 ; (r3)= i*5 str r3,sp,#-4 ;将(r3)即第5个参数i*5存入堆栈 add

21、 r3,r1,r1 ;(r3)= i*4,.,bl g ;调用c函数g(),返回值在寄存器r0中 add sp,sp,#4 ;清栈 rsb r0,r0,#0 ;函数f的返回值(r0)=0-(r0) ldr pc,sp,#4 ;恢复断点并返回 end,.,6.5 c/c+语言和汇编语言的混合编程,除了上面介绍的函数调用方法之外,arm编译器armcc中含有内嵌汇编器还允许在c程序中内联或嵌入式汇编代码,以提高程序的效率。,6.5.1 内联汇编,1、定义内联汇编程序,.,所谓内联汇编程序,就是在c程序中直接编写汇编程序段而形成一个语句块,这个语句块可以使用除了bx和blx之外的全部arm指令来编写

22、,从而可以使程序实现一些不能从c获得的底层功能。,其格式为:,_asm 汇编语句块 ,.,例: void enable_irq(void) int tmp; _asm /声名内联汇编代码 mrs tmp, cpsr bic tmp, tmp, #0 x80 msr cpsr_c, tmp ,.,2、内联汇编的限制,内联汇编与真实汇编之间有很大区别,会受到很多限制。,(1)它不支持thumb指令;除了程序状态寄存器psr之外,不能直接访问其他任何物理寄存器等。,(2)如果在内联汇编程序指令中出现了以某个寄存器名称命名的操作数,那么它,.,被叫做虚拟寄存器,而不是实际的物理寄存器。编译器在生成和优

23、化代码的过程中,会给每个虚拟寄存器分配实际的物理寄存器,但这个物理寄存器可能与在指令中指定的不同。唯一的一个例外就是状态寄存器psr,任何对psr的引用总是执行指向物理psr。,.,(3)在内联汇编代码中不能使用寄存器pc(r15)、lr(r14)和sp(r13),任何试图使用这些寄存器的操作都会导致出现错误消息。,(4)鉴于上述情况,在内联汇编语句块中最好使用c或c+变量作为操作数。,(5)虽然内联汇编代码可以更改处理器模式,但更改处理器模式会禁止使用c操,.,作数或对已编译c代码的调用,直到将处理器模式恢复为原设置之后。,6.5.2 嵌入式汇编,嵌入式汇编程序是一个编写在c程序外的单独汇编

24、程序,该程序段可以像函数那样被c程序调用。,.,与内联汇编不同,嵌入式汇编具有真实汇编的所有特性,数据交换符合atpcs标准,同时支持arm和thumb,所以它可以对目标处理器进行不受限制的低级访问。但是不能直接引用c/c+的变量。,用_asm声明的嵌入式汇编程序像c函数那样可以有参数和返回值。定义一个嵌入式汇编函数的语法格式为:,.,_asm returntype functionname(parameter-list) 汇编程序段 ,returntype:函数返回值类型; functionname:函数名; parameter-list:函数参数列表。,嵌入式汇编在形式上看起来就像使用关键字_asm进行了声明的函数,如下所示:,.,_

温馨提示

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

评论

0/150

提交评论