嵌入式:ARM转移指令(分支指令)

时间:2022-12-24 09:58:26

ARM有2种方法可实现程序的转移:

  • 一种是利用传送指令直接向PC寄存器R15中写入转移的目标地址,通过改变PC的值实现程序的转移;
  • 另一种就是利用转移指令。

ARM的转移指令可以从当前指令向前或向后的32MB的地址空间跳转,根据完成的功能它可以分为以下4种 :

  • B 转移指令
  • BL 带链接的转移指令
  • BX 带状态切换的转移指令
  • BLX 带链接和状态切换的转移指令

转移和转移链接指令(B,BL)

转移指令B在程序中完成简单的跳转指令,可以跳转到指令中指定的目的地址。BL指令完全象转移指令一样地执行转移,同时把转移后面紧接的一条指令的地址保存到链接寄存器LR(r14),这样可以实现子程序的返回。

二进制编码

嵌入式:ARM转移指令(分支指令)

跳转目标地址的计算方法:先对指令中定义的有符号的24位转移量用符号扩展为32位,并将该32位左移2位形成字的偏移,然后将它加到程序计数器PC中(相加前程序计数器的内容为转移指令地址加8字节)。一般情况下汇编器将会计算正确的偏移。

转移范围为±32MB。

L标志为1时,为转移连接指令。

汇编格式

B{L}{<cond>}  <target address>

L指定转移与连接属性,如果不包括L,便产生没有连接的转移。<cond>是条件执行的助记符扩展,缺省为AL,即无条件转移。<target address>一般是汇编代码中的标号,是转移到的目标地址。

举例:

(1)无条件转移
B  LABEL  ;无条件跳转
……
LABEL ……
(2)执行10次循环
MOV  R0,#10    ;初始化循环计数器
LOOP ……
SUBS R0,R0,#1 ;计数器减1,设置条件码
BNE LOOP ;如果计数器R0≠0,重复循环
(3)调用子程序
…  …
BL SUB ;转移连接到子程序SUB
…… ;返回到这里
SUB … … ;子程序入口
MOV PC,R14 ;返回

注意:在子程序返回之前,不应再调用下一级嵌套子程序。

汇编语言子程序调用及返回

在ARM汇编语言中,子程序调用是通过BL指令来完成的。BL指令的语法格式如下:

BL   subname

其中,subname是被调用的子程序的名称。BL指令完成两个操作:将子程序的返回地址放在LR寄存器(r14)中,同时将PC寄存器值设置成目标子程序的第一条指令地址。

在返回调用子程序时,转移链接指令保存到LR寄存器(r14)中的值需要拷贝回程序寄存器PC(r15)。

(4)子程序的嵌套调用

为了实现子程序的嵌套调用,应该在调用嵌套子程序之前,先将R14内容压栈保存。如:

BL  SUB1          ;转移连接到子程序SUB1
…… ;返回到这里
SUB1 … … ;子程序1入口
STMFD SP!,{R14}
BL SUB2
LTMFD SP!,{R14}
… …
MOV PC,R14 ;返回
SUB2 …… 子程序入口2
(5)条件子程序调用
……
CMP R0,#5 ;如果R0<5
BLLT SUB1 ;然后调用SUB1
BLGE SUB2 ;否则调用SUB2
……

注意:只有SUB1不改变条件,这里才能正常运行。

当转移指令转移到32MB地址空间之外时,将产生不可预测的结果。

转移交换和转移链接交换(BX,BLX)

这些指令用于支持Thumb(16位)指令集的ARM芯片,程序可以通过这些指令完成处理器从ARM状态到Thumb状态的切换。类似的Thumb指令可以使处理器切换回32位ARM指令。

嵌入式:ARM转移指令(分支指令)

在第一种格式中,寄存器Rm的值是转移目标,Rm的第0位拷贝到CPSR中的T位,进而决定是切换到Thumb状态还是ARM状态。[31:1]位移入PC。

如果Rm[0]是1,则切换到Thumb状态,并在Rm中的地址处开始执行,但需将最低位清0,使之半字对齐。

如果Rm[0]是0,则切换到ARM状态,并在Rm中的地址处开始执行,但需将Rm[1]清0,使之半字对齐 。

ARM的状态寄存器CPSR中的状态控制位T-bit(位[5])决定了当前处理器的运行状态,因此,可以通过MSR和MRS指令来直接修改CPSR的状态位,也能够改变处理器运行状态
但由于ARM采用多级流水线的结构,这样做会造成流水线上预取指令的执行错误,而如果用BX指令,则不会出现这样的问题

下面是一段直接进行状态切换的例程。

;从ARM状态开始
CODE32 ;表明以下是ARM指令
ADR R0, Into_Thumb+1; 得到目标地址,末位置1,
; 表示转移到Thumb
BX R0 ;转向Thumb
…… ;执行其它代码
CODE16 ;表明以下是Thumb指令
Into_Thumb : ;Thumb代码
ADR R5, Back_to_ARM ;得到目标地址,末位缺省为0,
; 转移到ARM
BX R5 ;转向ARM
…… ;执行其它代码
CODE32 ;表明以下是ARM指令
Back_to_ARM: ;ARM代码段起始地址

参考文献:

孟祥莲.嵌入式系统原理及应用教程(第2版)[M].北京:清华大学出版社,2017.