作者:行侠客人生_983 | 来源:互联网 | 2023-09-16 16:27
第3章Cortex-A8处理器编程3.6指令系统ARM伪指令不属于ARM指令集中的指令,是为了编程方便而定义的。伪指令可以像其它ARM指令一样使用,但在编译时这些指令将被等效的ARM指令代替。A
第3章 Cortex-A8处理器编程
3.6 指令系统
ARM伪指令不属于ARM指令集中的指令,是为了编程方便而定义的。伪指令可以像其它ARM指令一样使用,但在编译时这些指令将被等效的ARM指令代替。ARM伪指令有四条,分别为ADR伪指令、ADRL伪指令、LDR伪指令、NOP伪指令。
ARM伪指令——小范围的地址读取
ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中。在汇编编译器编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错误,编译失败。
地址表达式expr的取指范围:
当地址值不是字对齐时,其取值范围为-255~255;
当地址值是字对齐时,其取值范围为-1020~1020;
当地址值是16字节对齐时,其取值范围将更大。
应用示例(源程序):
...
ADR R0,Delay
...
Delay
MOV R0,r14
...
使用伪指令将程序标号Delay的地址存入R0
ARM伪指令——中等范围的地址读取
ADRL伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中,比ADR伪指令可以读取更大范围的地址 。在汇编编译器编译源程序时,ADRL伪指令被编译器替换成两条合适的指令。若不能用两条指令实现,则产生错误,编译失败。
地址表达式expr的取指范围:
当地址值不是字对齐时,其取址范围为-64K~64K;
当地址值是字对齐时,其取址范围为-256K~256K;
当地址值是16字节对齐时,其取址范围将更大。
应用示例(源程序):
...
ADRL R0,Delay
...
Delay
MOV R0,r14
...
使用伪指令将程序标号Delay的地址存入R0
ARM伪指令——大范围的地址读取
LDR伪指令用于加载32位的立即数或一个地址值到指定寄存器。在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指令。若加载的常数未超出MOV或MVN的范围,则使用MOV或MVN指令代替该LDR伪指令,否则汇编器将常量放入文字池,并使用一条程序相对偏移的LDR指令从文字池读出常量。
应用示例(源程序):
...
LDR R1,=InitStack
...
InitStack
MOV R0, LR
...
使用伪指令将程序标号InitStack的地址存入R1
注意:
1.从指令位置到文字池的偏移量必须小于4KB;
2.与ARM指令的LDR相比,伪指令的LDR的参数有“=”号。
ARM伪指令——空操作伪指令
NOP伪指令在汇编时将会被代替成ARM中的空操作,比如可能是“MOV R0,R0”指令等。NOP可用于延时操作。
应用示例(延时子程序):
Delay
NOP;空操作
NOP
NOP
SUBS R1,R1,#1 ;循环次数减一
BNE Delay ;如果循环没有结束,跳转Delay继续
MOV PC,LR ;子程序返回
3.7 ARM汇编程序规范
在只关心系统所具有功能的设计中,采用高级编程语言编写程序更合适,由于其隐藏了CPU执行指令的许多细节。但是,CPU执行指令的细节差异会反应在系统的非功能特性上,例如系统程序的规模和运行速度。因此,掌握汇编语言程序设计对于嵌入式系统的设计者来说是非常必要的。
ARM汇编程序中每一行的通用格式为:
{标号} {指令|指示符|伪指令} {;注解}
在ARM汇编语言源程序中,除了标号和注释外,指令、伪指令和指示符都必须有前导空格,而不能顶格书写。如果每一行的代码太长,可以使用字符“\”将其分行书写,并允许有空行。指令助记符、指示符和寄存器名既可以用大写字母,也可以用小写字母,但不能混用。注释从“;”开始,到该行结束为止。
标号
标号代表一个地址,段内标号的地址值在汇编时确定,段外标号的地址值在链接时确定。在此要区别程序相对寻址和寄存器相对寻址。在程序段中,标号代表其所在位置与段首地址的偏移量,根据程序计数器PC和偏移量计算地址称为程序相对寻址。在映像中定义的标号代表标号到映像首地址的偏移量,映像的首地址通常被赋予一个寄存器,根据该寄存器值与偏移量计算地址称为寄存器相对寻址。
指示符
预定义变量
ARM汇编器对ARM的寄存器进行了预定义,所有的寄存器和协处理器名都是大小写敏感的。预定义的寄存器如下:
·R0~R15或r0~r15;
·a1~a4(参数、结果或临时寄存器,与r0~r3同义);
·v1~v8(变量寄存器,与r4~r11同义);
·sb和SB(静态基址寄存器,与r9同义);
·sl和SL(堆栈限制寄存器,与r10同义);
·fp和FP(帧指针,与r11同义);
·ip和IP(过程调用中间临时寄存器,与r12同义);
·sp和SP(堆栈指针,与r13同义);
·lr和LR(链接寄存器,与r14同义);
·pc和PC(程序计数器,与r15同义);
·cpsr和CPSR(程序状态寄存器);
·spsr和SPSR(程序状态寄存器);
·f0~f7和F0~F7(FPA寄存器);
·s0~s31和S0~S31(VFP单精度寄存器);
·d0~d15和D0~D15(VFP双精度寄存器);
·p0~p15(协处理器0~15);
·c0~c15(协处理器寄存器0~15)。
内置变量
ARM汇编器所定义的内置变量如表所示。值得注意的是内置变量的设置不能用SETA、SETL或SETS等指示符来设置,只能用表达式或条件来设置。例如:
IF {ARCHITECTURE} = “4T”
子程序调用规则
ARM9处理器的子程序调用指令有别于Intel X86的子程序调用指令CALL,此小节再对这一特点进行归纳。另外,本小节还将介绍C或C++语言编写的程序与汇编语言编写的程序之间相互调用的规则。
汇编子程序调用
程序设计时,通常会把完成某个特定功能的一段程序代码编写成子程序,在需要的地方进行调用。ARM汇编程序中,使用下面语句调用子程序。
BL next
其中,next为子程序中的第一条指令代码的标号。
任何一个子程序进入前,处理器需要保存主程序中的现场,即需要保存当前工作寄存器(注意:当采用了子程序嵌套调用时,应该保存LR寄存器)。汇编指令BL的功能是将BL指令的下一条指令地址放到LR寄存器中,作为返回地址。并将子程序的第一条指令地址赋予PC寄存器,实现程序转移,即进入子程序执行。子程序执行完后,通过把LR寄存器值赋予PC寄存器,实现返回。
C、C++语言程序中内嵌汇编
C、C++语言编写的程序要比汇编语言编写的程序易读性、移植性好,因此,在嵌入式系统开发时,编写系统程序大多还是采用C、C++语言。但是在某些场合有时需要采用汇编指令编写程序,以实现一些高级语言没有的功能,并提高执行效率。ARM汇编工具支持在C、C++语言程序中嵌入汇编编写的程序段,其语法格式如下:
__asm{“指令[;指令]”}
汇编程序序实例--系统引导程序
掌握汇编语言程序设计对于嵌入式系统的设计者来说是非常必要的。大多数嵌入式系统加电后运行的第一段程序(在此称为系统引导程序,有时也称启动代码),往往是采用汇编语言编写的。
系统引导程序是依赖于具体硬件环境的,除了依赖于CPU的体系结构外,还依赖于具体的板级硬件配置。
·关看门狗定时器,关中断。
·有时需要设置系统CPU的速度和时钟频率。
·设置好堆栈。系统堆栈初始化取决于用户使用哪些异常,以及系统需要处理哪些错误类型。
一般情况下,管理模式堆栈必须设置;若使用了IRQ中断,则IRQ中断堆栈必须设置。
·如果系统应用程序是运行在用户模式下,可在系统引导程序中将系统改为用户模式并初始
化用户堆栈指针。
·若系统使用了DRAM或其他外设,需要设置相关寄存器,以确定其刷新频率、总线宽度
等信息。
·初始化所需的存储器空间。将系统需要读写的数据和变量从ROM拷贝到RAM里;要求快
速响应的程序,如中断程序,也需要在RAM中运行;对Flash的擦除和写入操作也一定
要在RAM里运行。
·跳转到C程序的入口点。
系统上电或复位后,首先执行的是“b reset”指令,系统跳转到标号为reset处接着执行,在完成了关中断、使能管理模式、初始化各模式的堆栈等功能后,执行指令“b main”跳转到C语言的主函数处执行。