您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 其它行业文档 > 嵌入式系统基础第6章--ARM程序设计
第6章ARM程序设计本章的主要内容1、ARM汇编语言程序设计2、ARM程序的框架结构3、C语言程序对汇编程序的调用4、ARM与C语言混合程序设计6.1ARM工程由于C语言便于理解,有大量的支持库,所以它是当前ARM程序设计所使用的主要编程语言。对硬件系统的初始化、CPU状态设定、中断使能、主频设定以及RAM控制参数初始化等C程序力所不能及的底层操作,还是要由汇编语言程序来完成。用汇编语言或C/C++语言编写的程序叫做源程序,对应的文件叫做源文件。一个ARM工程应由多个文件组成,其中包括扩展名为.S的汇编语言源文件、扩展名为.C的C语言源文件,扩展名为.CPP的C++源文件、扩展名为.H的头文件等。ARM工程的各种源文件之间的关系,以及最后形成可执行文件的过程如下:汇编语言源文件汇编器目标文件C/C++语言源文件编译器目标文件头文件C/C++库文件连接器可执行文件ARM提供的开发工具CodeWarriorforARM中包含的编译器如下:编译器语言种类源文件类型源文件扩展名目标文件类型ArmccCC.cARM代码TccCC.cThumb代码ArmcppC++c/c++.c/.cppARM代码tcppC++c/c++.c/.cppThumb代码除了C和C++编译器,CodeWarriorforARM开发工具还提供了汇编器ARMASM。编译器负责生成目标文件,它是一种包含了调试信息的ELF格式文件。编译器还要生成列表文件等相关文件:文件扩展名说明.h头文件.oELF格式的目标文件.s汇编代码文件.lst错误及警告信息列表文件各种源文件先由编译器和汇编器将它们分别编译或汇编成汇编语言文件及目标文件。连接器负责将所有目标文件连接成一个文件并确定各指令的确定地址,从而形成最终可执行文件。连接器有三个功能:(1)生成与地址相关的代码,把所有文件连接成一个可执行文件。(2)根据程序员所指定的选项,为程序分配地址空间。(3)给出连接信息,以说明连接过程和连接结果。6.2ARM汇编语言程序设计6.2.1段汇编语言编写的程序叫做汇编语言源程序,包含源程序的文件叫做汇编语言程序文件。一个工程可以有多个源文件,汇编源文件的扩展名为.S。在ARM(Thumb)汇编语言程序中,通常以段为单位来组织代码。段是具有特定名称且功能相对独立的指令或数据序列。根据段的内容,分为代码段和数据段。一个汇编程序至少应该有一个代码段,当程序较长时,可以分割为多个代码段和数据段。以下是一个汇编语言程序段的基本结构:AREAInit,CODE,READONLY//只读的代码段InitENTRY//程序入口点startLDRR0,#0X3FF5000LDRR1,0XFFSTRR1,[R0]LDRR0,#0X3FF5008LDRR1,0X01STRR1,[R0]…….END//段结束6.2.2分支程序设计具有两个或两个以上可选执行路径的程序叫做分支程序。1、普通分支程序设计使用带有条件码的指令可以很容易地实现分支程序。例:编写一个分支程序段,如果寄存器R5中的数据等于10,就把R5中的数据存如寄存器R1;否则把R5中的数据分别存储寄存器R0和R1。(1)用条件指令实现的分支程序段CMPR5,#10MOVNER0,R5MOVR1,R5(2)用条件转移指令来实现分支CMPR5,#10BEQdoequalMOVR0,R5doequalMOVR1,R5例:编写一个程序段,当寄存器R1中的数据大于R2中数据时,将R2中的数据加10存入寄存器R1;否则将R2中数据加5存入寄存器R1。CMPR1,R2ADDHIR1,R2,#10ADDLSR1,R2,#52、多分支(散转)程序设计程序分支点上有多于两个以上的执行路径的程序叫做多分支程序。利用条件测试指令或跳转表可以实现多分支程序。例、编写一个程序段,判断寄存器R1中数据是否为10、15、12、22。如果是,则将R0中的数据加1;否则将R0设置为0XF。MOVR0,#0TEQR1,#10TEQNER1,#15TEQNER1,#12TEQNER1,#22ADDEQR0,R0,#1MOVNER0,#0XF当多分支程序的每个分支所对应的是一个程序段时,常常把各个分支程序段的首地址依次存放在一个叫做跳转地址表的存储区域,然后在程序的分支点处使用一个可以将跳转表中的目标地址传送到PC的指令来实现分支。一个具有3个分支的跳转地址表示意图如下:MOVR0,NADRR5,JPTBLDRPC,[R5,R0,LSL#2]JPTAB;跳转表DCDFUN0DCDFUN1ECDFUN2FUN0…..;分支FUN0的程序段FUN1…..;分支FUN1的程序段FUN2…..;分支FUN2的程序段3、带ARM/Thumb状态切换的分支程序设计在ARM程序中经常需要在程序跳转的同时还要进行处理器状态的转移,即从ARM指令程序段跳转到Thumb指令程序段(或相反)。为了实现这个功能,系统提供了一条专用的、可以实现4GB空间范围内的绝对跳转交换指令BX。下面是一段从ARM指令程序段跳转到Thumb指令程序的状态切换例程。;ARM指令程序CODE32…..ADDR0,Into_Thumb+1BXR0…..;Thumb指令程序CODE16Into_Thumb…….下面是一段从Thumb指令程序段跳转到ARM指令程序的状态切换例程。;Thumb指令程序CODE16…..ADDR5,Back_to_ARMBXR0…..;ARM指令程序CODE32Back_to_ARM…….6.2.3循环程序设计当条件满足时,需要重复执行同一个程序段做同样工作的程序叫做循环程序。被重复执行的程序段叫做循环体,需要满足的条件叫做循环条件。循环程序有两种结构:DO-WHILE结构和DO-UNTIL结构。DO-WHILE结构DO-UNTIL结构在汇编语言程序设计中,常用的是DO-UNTIL结构循环程序。MOVR1,#10LOOP…….SUBR1,R1,#1BNELOOP例、编写一个程序,把首地址为DATA_SRC的80个字的数据复制到首地址为DATA_DST的目标数据块中。LDRR1,#DATA_SRCLDRR0,#DATA_DSTMOVR10,#10LOOPLDMIAR1!,{R2-R9}STMIAR0!,{R2-R9}SUBSR10,R10,#1BNELOOP6.2.4子程序及其调用1、子程序的调用与返回人们把这种可以多次反复调用的、能完成指定功能的程序段称为“子程序”。把调用子程序的程序称为“主程序”。为进行识别,子程序的第1条指令之前必须赋予一个标号,以便其他程序可以用这个标号调用子程序。在ARM汇编语言程序中,主程序一般通过BL指令来调用子程序。该指令在执行时完成如下操作:将子程序的返回地址存放在连接寄存器LR中,同时将程序计数器PC指向子程序的入口点。为使子程序执行完毕能返回主程序的调用处,子程序末尾处应有MOV、B、BX、STMFD等指令,并在指令中将返回地址重新复制到PC中。在调用子程序的同时,也可以使用R0~R3来进行参数的传递和从子程序返回运算结果。例、一个使用MOV指令实现返回的子程序。relay…..MOVPC,LR使用B指令实现返回的子程序。relay…..BLR例、一个使用BL指令调用子程序的汇编语言缘程序的基本结构。AERAInit,CODE,READONLYENTRYstartLDRR0,#0X3FF5000LDRR1,0XFFSTRR1,[R0]LDRR0,#0X3FF5008LDRR1,0X01STRR1,[R0]BLPR…….PR……MOVPC,LR……END2、子程序中堆栈的使用relaySTMFDR13!,{R0~R12,LR};压入堆栈……;子程序代码LDMFDR13!,{R0~R12,PC};弹出堆栈并返回6.2.5汇编程序访问全局C变量一般来说,汇编语言程序与C语言程序不在同一个文件上,所以实质上这是一个引用不同文件定义的变量问题。解决这个问题的办法就是使用关键字IMPORT和EXPORT。例、下面是一个汇编代码的函数,它引用了一个在其他文件中定义的全局变量globvar,将其加2后写回globvar。AREAglobvar,CODE,READONLYEXPORTasmsubrouttineIMPORTglobvarAsmsubrouttineLDRR1,#globvarLDRR0,[R1]ADDR0,R0,#2STRR0,[R1]MOVPC,LREND6.3ARM程序框架在应用系统的程序设计中,若所有的编程任务均用汇编语言来完成,其工作量是可想而知的,这样做也不利于系统升级或应用软件移植。通常汇编语言部分完成系统硬件的初始化;高级语言部分完成用户的应用。执行时,首先执行初始化部分,然后再跳转到C/C++部分。整个程序结构显得清晰明了,容易理解。程序的基本结构如下:硬件初始化的汇编语言程序(特权模式)Bmain完成用户任务的C/C++程序(用户模式)跳转6.3.1初始化程序部分由于在用于完成初始化任务的汇编语言程序中需要在特权模式下做一些诸如修改CPSR等特权操作,所以不能过早地进入用户模式。通常,初始化过程大致会经历如下所示的一些模式变化。启动管理模式svc其他特权模式用户模式usr汇编语言程序段6.3.2初始化部分与主应用程序部分的衔接当所有的系统初始化工作完成之后,就需要把程序流程转入主应用程序。最简单的方法是,在汇编语言程序末尾使用跳转指令B或BL直接从启动代码转移到C/C++程序入口。Bmain;跳转到C/C++程序同时在汇编文件中有如下代码:IMPORTmain完整的汇编语言程序如下:IMPORTmainAREAInit,CODE,READONLYENTRYLDRR0,#0X3FF000LDRR1,#0XE7FFFF80STRR1,[R0]LDRSP,#0X3EE1000BLmainENDC程序如下:voidmain(void){…..}6.3.3ARM开发环境提供的程序框架为方便工程开发,ARM公司的开发环境ARMADS为用户提供了一个可以选用的应用程序框架。该框架把为用户程序做准备工作的程序分成了启动代码和应用程序初始化两部分。用于硬件初始化的汇编语言部分叫做启动代码;用于应用程序初始化的C部分叫做初始化部分。整个程序如下所示:IMPORT__main启动代码B__main应用程序初始化主用程序__main()main()6.4C与汇编之间的函数调用在ARM工程中,C程序调用汇编函数和汇编程序调用C函数是经常发生的事情。为此人们制定了ARM-Thumb过程调用标准ATPCS(ARM-ThumbProcedureCallStandard)。6.4.1ATPCS简介1、堆栈与寄存器在函数调用中的作用函数是通过寄存器和堆栈来传递参数和返回函数值的。下面是C语言程序调用C函数的情况。intAddInt(intx,inty){ints;s=x+y;returns;}在C程序中,主函数main()调用该函数的方法如下:voidmain(void){…..AddInt(a,b);//调用………}ARM编译器使用的函数调用规则就是ATPCS标准。ATPCS标准既是ARM编译器的规则,也是设计可被C程序调用的汇编函数的编写规则。2、ATPCS关于堆栈和寄存器的使用规则ATPCS规定,ARM的数据堆栈为FD型堆栈,即递减满堆栈。ATPCS标准规定,对于参数个数不多于4的函数,编译器必须按参数在列表中的顺序,自左向右为它们分配寄存器R0~R3。其中函数返回时,R0还被用来存放函数的返回值。如果函数的参数多于4个,那么多余的参数则按自右向做的顺序压入数据堆栈,即参数入栈顺序与采纳书顺序相反。下表列举了ARM-Thumb过程调用标准规定的寄存器的名称和使用方法。寄存器别名1别名2用法R0~R3A1~A4参数寄存器,其中R0又被用作函数返回值寄存器R4~R8V1~V5函数局部变量寄存器R9V6Sb在RWPI情况下保存静态基地址R10V7Sl用来保存堆栈边界地址R11
本文标题:嵌入式系统基础第6章--ARM程序设计
链接地址:https://www.777doc.com/doc-2440395 .html