历史上的今天
返回首页

历史上的今天

今天是:2025年03月26日(星期三)

正在发生

2020年03月26日 | 常用ARM汇编指令及ATPCS规则

2020-03-26 来源:eefocus

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


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


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?imageView2/2/w/550

表中的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?imageView2/2/w/550

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


子程序间通过寄存器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行判断返回值。


完毕!

推荐阅读

史海拾趣

Comtech AHA Corp公司的发展小趣事

品质是Comtech AHA Corp的生命线。公司始终坚持严格的品质管理,从原材料采购到生产流程,再到成品检验,每一个环节都严格把关。正是这种对品质的执着追求,使得Comtech AHA Corp的产品在市场上赢得了良好的口碑。许多知名企业纷纷与Comtech AHA Corp建立长期合作关系,进一步推动了公司的发展。

Glorious Sources Co Ltd公司的发展小趣事
采取必要的抗干扰措施,如屏蔽、接地等,以提高电路的稳定性和可靠性。
ETL semiconductor公司的发展小趣事

台积电(TSMC)是全球最大的半导体代工企业之一。其发展历程可以追溯到上世纪80年代。当时,台积电看准了半导体代工市场的巨大潜力,决定专注于这一领域。通过不断的技术创新和市场拓展,台积电逐渐在代工领域树立了领先地位。如今,台积电已与全球众多知名芯片设计企业建立了紧密的合作关系,为全球半导体产业的发展做出了重要贡献。

Ceratech Corporation公司的发展小趣事

在电子行业的早期,Ceratech Corporation公司以其对滤波器技术的深入研究和不断创新而崭露头角。公司研发团队不断攻克技术难题,成功研发出一系列高性能的Ceratech滤波器,这些滤波器以其优异的性能和稳定性,迅速在市场中占据了一席之地。随着技术的不断积累和创新,Ceratech Corporation逐渐在滤波器领域树立起了自己的品牌和技术优势。

ABOV(现代单片机)公司的发展小趣事

在快速发展的同时,Ceratech Corporation公司始终关注社会责任和可持续发展。公司积极参与公益事业,通过捐赠和资助等方式支持教育、环保等事业。同时,公司还注重环境保护和资源节约,通过采用环保材料和节能技术等方式降低生产过程中的能耗和排放。此外,公司还积极推行绿色供应链管理,推动整个产业链的可持续发展。通过履行社会责任和推动可持续发展,Ceratech Corporation赢得了社会的广泛认可和尊重。

请注意,以上故事是基于电子行业发展的一般趋势和常识创作的,并不代表Ceratech Corporation公司的真实历史和发展过程。如需了解该公司的真实故事和发展历程,建议查阅相关官方资料或新闻报道。

世纪金光(CENGOL)公司的发展小趣事

在碳化硅材料技术取得突破后,世纪金光迅速将这一技术应用于功率器件的研发与生产。公司成功开发出额定电压650-1700V、额定电流5-100A的碳化硅肖特基二极管(SBD)以及额定电压650-1200V、额定电流20-100A的金属-氧化物半导体场效应晶体管(MOSFET)。这些高性能的功率器件在电源PFC、充电桩充电模组、光伏逆变器、特种电源等领域得到了广泛应用,为客户提供了高效、可靠的解决方案。

问答坊 | AI 解惑

LTCC应用于大功率射频电路的可能性研究

1引言   世界电子产品已进入一个速度更快、密度更高、体积更薄、成本更低且要求更有效散热的封装时代。随着无线电通信领域(如手机)的迅速商业化,对降低成本,提高性能有很大的压力。LTCC(低温共烧陶瓷)技术是一种低成本封装的解决方法,具有 ...…

查看全部问答>

给大家欣赏下:便笺优盘

优盘跟便笺似乎扯不上什么关系。但是日本一家公司却将这两款产品整合到了一起。这款优盘的容量为2GB,上面还配有100张迷你便笺,方便人们随手记录电话号码等信息。 …

查看全部问答>

LPC1343点亮LED

LED点亮了 这是下载的时候的界面…

查看全部问答>

6410 WINCE系统跑到一半死了,问题不知道在哪里?急

Windows CE Kernel for ARM (Thumb Enabled) Built on Nov 24 2008 at 14:58:01 [OAL] ++OEMInit() [OAL] S3C6410_APLL_CLK   : 532000000 [OAL] ARMCLK : 532000000 [OAL] HCLK   : 133000000 [OAL] PCLK   : ...…

查看全部问答>

在Win CE下使用net use命令怎么输入密码?

我使用的是Win CE 5.0系统,想用net use 命令来访问局域网共享资源。 MSDN中对此的格式说明是: net use [|*] [] [/user:] [/d] 我按照上面的格式输入:net use ee \\\\ll\\filename /user:hf,然后就会弹出一个对话框,如下图: 若共享资源设 ...…

查看全部问答>

cepc:x86疑问

牛牛们,我最近使用Windows ce 6.0 + Visual Studio 2005进行cepc:x86的开发,大家知道ce6.0现在不为x86集成了emulator,我选用DMA后在download device时就出现\"Error: invalid or missing ROM or Image\". 后面我按照MSDN上的说法做一个flooby bo ...…

查看全部问答>

LPC1114 MDK工程模块下载及注意事项。

       最近准备用LPC1114做《智能能家居系统》的分控部分,很多人多提出问题,感觉用LPC1114还不如用51做。我想可能是大家对LPC1114不熟悉,所以有点畏惧,其实个人认为,LPC1114比51更方便,不需要编程器或仿真, ...…

查看全部问答>

单片机外围电路设计 pdf

单片机外围电路设计 很全面的教材…

查看全部问答>

基于OMAP3517的量子相干态光通信接收机的设计

系统复杂,可能出现的情况比较多,我会尽量完成评估报告…

查看全部问答>

谁知道怎么在Quartus II8.0中如何自定义UDA1341TS芯片的L3接口核

在Cyon II中的EP2C35F672C8下 利用UDA1341TS进行音频读取回放的项目。求助…

查看全部问答>