常用ARM汇编指令及ATPCS规则

发布者:pcwg最新更新时间:2020-03-26 来源: eefocus关键字:ARM  汇编指令  ATPCS规则 手机看文章 扫描二维码
随时随地手机看文章

嵌入式开发中,汇编程序常常用于非常关键的地方,比如系统启动时的初始化,进出中断时的环境保存、恢复,对性能要求非常苛刻的函数等。


只在必要情况下使用汇编指令,只涉及几条汇编指令。


1.相对跳转指令:b、bl


这两条指令的不同之处在于bl指令除了跳转之外,还将返回地址(bl的下一条指令的地址)保存在lr寄存器中。


这两条指令的可跳转范围是当前指令的前后32M:-32M~+32M。它们是位置无关的指令。使用示例:


b fun1

......

fun1:

bl fun2

......

fun2:

......

2.数据传送指令mov,地址读取伪指令ldr


mov指令可以把一个寄存器的值赋给另一个寄存器,或者把一个常数赋给寄存器。例子如下:


mov r1, r2 /* r1=r2 */

mov r1, #4096 /* r1=4096 */

mov指令传送的常数必须能用"立即数"来表示。


当不知道一个数能否用"立即数"来表示时,可以使用ldr命令来赋值。ldr是伪指令,它不是真实存在的指令,编译器会把它扩展成真正的指令;如果该常数能用"立即数"来表示,则使用mov指令;否则编译时将该常数保存在某个位置,使用内存读取指令把它读出来。例子如下:


ldr r1, =4097 /* r1=4097 */

ldr本意为"大范围的地址读取伪指令",上面的例子使用它来将常数赋给寄存器r1。下面的例子是获得代码的绝对地址:


ldr r1, =label

label:

......

3.内存访问指令:ldr、str、ldm、stm


注意:"ldr"指令既可能是前面所述的"大范围的地址读取伪指令",也可能是内存访问指令。当它的第二个参数前面有"="号时,表示伪指令,否则表示内存访问指令。


ldr指令从内存中读取数据到寄存器,str指令把寄存器的值存储到内存中,它们操作的数据都是32位的。示例如下:


ldr r1, [r2, #4] /* 将地址为 r2+4 的内存单元数据读取到 r1 中 */

ldr r1, [r2] /* 将地址为 r2 的内存单元位数据读取到 r1 中 */

ldr r1, [r2], #4 /* 将地址为 r2 的内存单元数据读取到 r1 中,然后 r2=r2+4 */

str r1, [r2, #4] /* 将 r1 的数据保存到地址为 r2+4 的内存单元中 */

str r1, [r2] /* 将 r1 的数据保存到地址为 r2 的内存单元中 */

str r1, [r2], #4 /* 将 r1 的数据保存到地址为 r2 的内存单元中,然后 r2=r2+4 */

ldm和stm属于批量内存访问指令,只用一条指令就可以读写多个数据。它们的格式如下:


ldm {cond}   {!}  {^}

stm {cond}   {!}  {^}

其中{cond}表示指令的执行条件。

表示地址变化模式,有以下4种方式:


ia(Increment After)     事后递增方式

ib(Increment Before)     事先递增方式

da(Decrement After)     事后递减方式

db(Decrement Before)     事先递减方式

中保存内存的地址,如果后面加上了感叹号,指令执行后,rn的值会更新:等于下一个内存单元的地址。


表示寄存器列表,对于ldm指令,从所对应的内存块中取出数据,写入这些寄存器;对于stm指令,把这些寄存器的值,写入所对应的内存块中。


{^}有两种含义:如果中有pc寄存器,它表示指令执行后,spsr寄存器的值将自动复制到cpsr寄存器中——这常用于从中断处理函数中返回;如果中没有pc寄存器,{^}表示操作的是用户模式下的寄存器,而不是当前特权模式的寄存

器。


指令中寄存器列表和内存单元的对应关系为:编号低的寄存器对应内存中的低地址单元,编号高的寄存器对应内存中的高地址单元。


ldm和stm指令示例如下:


//中断入口函数

HandleIRQ:

sub lr, lr, #4 //计算返回地址

stmdb sp!, {r0-r12,lr} //保存使用到的寄存器

//r0-r12,lr被保存在sp表示的内存中,

//"!"使得指令执行后,sp=sp-14*4

 

ldr lr, =int_return //设置调用IRQ_Handle函数后的返回地址

ldr pc, =IRQ_Handle //调用中断分发函数

int_return:

ldmia sp!, {r0-r12,pc}^ //中断返回,^表示将spsr的值复制到cpsr

//于是从irq模式返回被中断的工作模式

//"!"使得指令执行后,sp=sp+14*4

4.加减指令:add、sub


例子如下:


add r1, r2, #1 /* 表示 r1=r2+1,即寄存器r1的值等于寄存器r2的值加上1 */

sub r1, r2, #1 /* 表示 r1=r2-1 */

5.程序状态寄存器的访问指令:msr、mrs


ARM处理器有一个程序状态寄存器(cpsr),它用来控制处理器的工作模式、设置中断的总开关。示例如下:


msr cpsr, r0 /* 复制r0到cpsr中 */

mrs r0, cpsr /* 复制cpsr到r0中 */

6.其他伪指令


在本书的汇编程序中,常常见到如下语句:


.extern main

.text

.global _start

_start:

".extern"定义一个外部符号(可以是变量也可以是函数),上面的代码表示本文件中引用的main是一个外部函数。


".text"表示下面的语句都属于代码段。


".global"将本文件中的某个程序标号定义为全局的,比如上面的代码表示_start个全局函数。


7.汇编指令的执行条件


大多数ARM指令都可以条件执行,即根据cpsr寄存器中的条件标志位决定是否执行该指令:如果条件不满足,该指令相当于一条nop指令。


每条ARM指令包含4位的条件码域,这表明可以定义16个执行条件。可以将这些执行条件的助记符附加在汇编指令后,比如moveq、 movgt等。这16个条件码和它们的助记符、含义如下表所示:


表. 指令的条件码

image.png

表中的cpsr条件标志位N、Z、C、V分别表示:Negative、Zero、Cary、oVerflow。影响条件标志位的因素比较多,比如比较指令cmp、cmn、teq及tst等。


2.ARM-THUMB子程序调用规则ATPCS


为了使C语言程序和汇编程序之间能够互相调用,必须为子程序间的调用制定规则,在ARM处理器中,这个规则被称为ATPCS;ARM程序和Thumb程序中子程序调用的规则。基本的ATPCS规则包括寄存器使用规则、数据栈使用规则、参数传递规则。


1.寄存器使用规则


ARM处理器中有r0~r15共16个寄存器,它们的用途有一些约定的习惯,并依具这些用途定义了别名,如下表所示:


ATPCS中各寄存器的使用规则及其名称:

image.png

寄存器的使用规则总结如下:


子程序间通过寄存器r0~r3来传递参数,这时可以使用它们的别名a0~a3。被调用的子程序返回前无需恢复r0~r3的内容。


在子程序中,使用r4~r11来保存局部变量,这时可以使用它们的别名v1~v8。如果在子程序中使用了它们的某些寄存器,子程序进入时要保存这些寄存器的值,在返回前恢复它们;对于子程序中没有使用到的寄存器则不必进行这些操作。在Thumb程序中,通常只能使用寄存器r4~r7来保存局部变量。


寄存器r12用作子程序间scratch寄存器,别名为ip。


寄存器r13用作数据栈指针,别名为sp。在子程序中寄存器r13不能用作其他用途。它的值在进入、退出子程序时必须相等。


寄存器r14被称为连接寄存器,别名为lr。它用于保存子程序的返回地址。如果在子程序中保存了返回地址(比如将lr值保存到数据栈中),r14可以用作其他用途。


寄存器r15是程序计数器,别名为pc。它不能用作其他用途。


2.数据栈使用规则


数据栈有两个增长方向:向内存地址减小的方向增长时,称为DESCENDING栈;向内地址增加的方向增长时,称为ASCENDING栈。


所谓数据栈的增长就是移动栈指针。当栈指针指向栈顶元素(最后一个入栈的数据)时,称为FULL栈;当栈指针指向栈顶元素(最后一个入栈的数据)相邻的一个空的数据单元时,称为EMPTY栈。


综合这两个特点,数据栈可以分为以下4种:


FD Full Descending,满递减

ED Empty Descending,空递减

FA Full Ascending,满递增

EA Empty Ascending,空递增

ATPCS规定数据栈为FD类型,并且对数据栈的操作是8字节对齐的。使用stmdb/ldmia批量内存访问指令来操作FD数据栈。


使用stmdb命令往数据栈中保存内容时,"先递减sp指针,再保存数据",使用ldmia命令从数据栈中恢复数据时,"先获得数据,再递增sp指针"——sp指针总是指向栈顶元素,这刚好是FD栈的定义。


3.参数传递规则


一般来说,当参数个数不超过4个时,使用r0~r3这4个寄存器来传递参数;如果参数个数超过4个,剩余的参数通过数据栈来传递。


对于一般的返回结果,通常使用a0~a3来传递。示例:


假设CopyCode2SDRAM函数是用C语言实现的,它的数据原型如下:


int CopyCode2SDRAM(unsigned char *buf, unsigned long start_addr, int size)

在汇编代码中,使用下面的代码调用它,并判断返回值:


ldr r0, =0x30000000 //1.目标地址=0x30000000,这是SDRAM的起始地址

mov r1, #0 //2.源地址=0

mov r2, #16*1024 //4.复制长度=16K

bl CopyCode2SDRAM //调用C函数CopyCode2SDRAM

cmp a0, #0 //判断函数返回值

第1行将r0设为0x30000000,则CopyCode2SDRAM函数执行时,它的第一个参数buf的指向的内存地址为0x30000000。


第2行将r1设为0,CopyCode2SDRAM函数的第二个参数start_addr等于0。


第3行将r2设为16*1024,CopyCode2SDRAM函数的第三个参数start_addr等于16*1024。


第5行判断返回值。


完毕!

关键字:ARM  汇编指令  ATPCS规则 引用地址:常用ARM汇编指令及ATPCS规则

上一篇:tiny4412开发板时钟操作示例
下一篇:常用的汇编指令介绍

推荐阅读最新更新时间:2024-11-12 18:39

基于FPGA的ARM并行总线设计与仿真分析
  在数字系统的设计中,FPGA+ARM的系统架构得到了越来越广泛的应用,FPGA主要实现高速数据的处理;ARM主要实现系统的流程控制。人机交互。外部通信以及FPGA控制等功能。I2C、SPI等串行总线接口只能实现FPGA和ARM之间的低速通信; 当传输的数据量较大。要求高速传输时,就需要用并行总线来进行两者之间的高速数据传输。   下面基于ARM处理器LPC2478 以及FPGA器件EP2C20Q240,以ARM外部总线的读操作时序为例,研究两者之间高速传输的并行总线;其中,数据总线为32位;并在FPGA内部构造了1024x32bits的SRAM高速存储缓冲器,以便于ARM处理器快速读写FPGA内部数据。   1 ARM并行
[单片机]
基于FPGA的<font color='red'>ARM</font>并行总线设计与仿真分析
ARM核流水线——ARM7,ARM9E,ARM11,Cortex-A系列处理器
本文主要介绍ARM7,ARM9E,ARM11以及Cortex-A系列处理器的流水线,从指令读取fetch,指令解码decode到指令执行的各个阶段。 参考ARM的网站http://www.arm.com/about/company-profile/index.php,ARM公司成立于1990年,目前已经销售了超过150亿个芯片,并向超过200多加公司销售了超过600个处理器的授权,目前全世界有超过95%的手机以及超过25%的消费电子产品使用ARM作为处理器核心。 ARM(Advanced RISC Machines)是专注于RISC(Reduced Instruction Set computer)架构的处理器公司,最早的ARM1
[单片机]
ARM Linux S3C2440 之UART分析
在分析ARM-Linux s3c2440中UART的时有必要先了解 s3c2440A中串口的硬件知识。 硬件篇: S3c2440A串口提供三个独立的异步串行通信I/O端口(asynchronousserial I/O ports)。每一个串口均可以以普通中断方式或者DMA方式进行数据收发。采用系统时钟时,最大速率为115.2kbps.如果采用外部时钟(UEXTCLK),UART速度可以更快。每个串口包含有2个64-byte的FIFO缓存区用来发送或传输数据。S3c2440A 串口具有可编程波特率,红外(IR)收发数据,1或者2 位的停止位(stop),5/6/7/8 位数据宽度和奇偶校验功能(parity checking)。
[单片机]
<font color='red'>ARM</font> Linux S3C2440 之UART分析
ARM学习笔记6——程序状态寄存器访问指令
  这两条指令结合,可用于对CPSR或SPSR进行读/写操作。 当需要保存或修改当前模式下CPSR或SPSR的内容时,首先必须将这些内容传递到通用寄存器中 1、MRS指令(Move to Register from Status Register)   1.1、作用     它将程序状态寄存器内容传输到通用寄存器   1.2、语法格式     MRS{ condition } Rd ,CPSR     MRS{ condition } Rd ,SPSR   1.3、参数说明      Rd :确定指令的目标寄存器,如果R15被用作目标寄存器,指令的执行结果不可预知,因为每执行一个指令,PC都会改变。   1.4、使用场合   
[单片机]
ARM】S5PV210芯片的启动流程
S5PV210芯片的设计者的思想 (1)芯片启动后执行iRom(BL0)的内容,进行时钟和看门狗等外设的初始化,将BL1和BL2拷贝到片内SRAM; (2)跳转到片内SRAM执行,完成外部SDRAM的初始化,并将OS从存储设备拷贝到SDRAM内; (3)跳转到SRAM内执行OS的起始代码。 由于U-BOOT的大小的限制,无法全部拷贝到片内的SRAM,所以U-BOOT的设计者设计了一下流程 (1)芯片启动后执行iRom(BL0)的内容,进行时钟和看门狗等外设的初始化,将BL1拷贝到片内SRAM; (2)跳转到片内SRAM内进行执行,完成SDRAM的初始化,将BL2拷贝到SDRAM内,执行。 (3)跳转到SDRAM内的BL2进行执行
[单片机]
【<font color='red'>ARM</font>】S5PV210芯片的启动流程
嵌入式Linux之我行——ARM MMU工作原理剖析
一、MMU的产生 许多年以前,当人们还在使用DOS或是更古老的操作系统的时候,计算机的内存还非常小,一般都是以K为单位进行计算,相应的,当时的程序规模也不大,所以内存容量虽然小,但还是可以容纳当时的程序。但随着图形界面的兴起还用用户需求的不断增大,应用程序的规模也随之膨胀起来,终于一个难题出现在程序员的面前,那就是应用程序太大以至于内存容纳不下该程序,通常解决的办法是把程序分割成许多称为覆盖块(overlay)的片段。覆盖块0首先运行,结束时他将调用另一个覆盖块。虽然覆盖块的交换是由OS完成的,但是必须先由程序员把程序先进行分割,这是一个费时费力的工作,而且相当枯燥。人们必须找到更好的办法从根本上解决这个问题。不久人们找到了一
[单片机]
年底发布,微软推搭载骁龙835的Win 10 ARM笔记本
   微软 已经在和OEM伙伴承诺在今年晚些时间推出搭载高通 骁龙835 处理器的笔记本,这些Windows 10 ARM笔记本将可以运行现状的Win32/x86和UWP程序,并且可以长时间接入LTE网络还有极佳的电池续航时间。下面就随嵌入式小编一起来了解一下相关内容吧。   虽然经过了Windows RT这样惨痛的失败经历,但是 微软 并没有放弃让ARM处理器运行Windows系统,在很早之前就有消息称 微软 在开发ARM版Windows 10,并且是完整版的Windows 10桌面版,使用体验上与PC是一样的,虽然有来自Intel方面的阻力,但是微软和高通好像并不怕他。   微软已经在和OEM伙伴承诺在今年晚些时间推出搭载
[嵌入式]
ARM体系架构—ARMv7-A处理器模式及寄存器
一、ARMv7-A处理器模式 ARMv7架构支持安全扩展,如果使能了安全扩展,ARMv7-A架构分为安全模式(Secure State)和非安全模式(Non-secure State)两个世界。 在非安全模式下,存在三种运行特权PL0,PL1和PL2(privilege level)。 If the Virtualization Extensions are implemented there is a privilege model different to that of previous architectures. In Non-secure state there can be three privilege l
[单片机]
<font color='red'>ARM</font>体系架构—ARMv7-A处理器模式及寄存器
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved