深度探索嵌入式操作系统:从零开始设计、架构和开发
上QQ阅读APP看书,第一时间看更新

3.8.2 分支跳转指令

如果一个处理器不能跳转执行指令,那么程序的判断、循环结构以及函数调用将不能实现。这样的处理器是不是糟透了,我想肯定是的。庆幸的是,大部分处理器都支持跳转执行指令,ARM920T也不例外。

ARM920T支持如下几条分支跳转指令,来实现程序的跳转执行。

□b。

□bl。

□bx。

□blx。

1.b、bl指令

指令在汇编程序中的用法:

b{l}{cond} <lable_offset>|<Rn>

□{}中的表示可选项。

□<>中的表示必需项。

□|表示多选一。

□cond表示条件码,如EQ、NE、CS。

□l为链接位,如果在“b”后面写上“l”表示在执行跳转动作的同时,将原来的PC值写入当前模式下的R14寄存器中。

□lable_offset表示跳转标号即跳转地址。

□Rn表示一个合法的寄存器,一般通用寄存器都行。

分支跳转指令中包含了一个有符号补码的24位偏移量。该值左移两位后并将其有符号位扩展到32位,因为有效位数为25位加1位符号位,所以最多能表示32MB,然后加入R15中。因此该指令可以指定±32MB的分支跳转。分支跳转偏移还必须考虑预取操作,因为PC超前于当前指令的2个字。分支跳转地址如果超过了±32MB,必须将这个地址事先装载到某一通用寄存器中。例如,将这个地址先装入R0中,再执行“bl r0”。

例如:

main:            ;标号,汇编器和程序链接器最后会把它转换成地址
  mov r0,#2      ;r0=2
  mov r1,#3      ;r1=3
  bl addfunc1    ;r14=pc;pc=pc+offset(addfunc1)。保存pc至r14并跳转到addfunc1   ;地址上运行。注意offset(addfunc1)是编译工具处理的,表示当前pc和addfunc1
                 ;的绝对地址之间的差值
lable:           ;标号
  b lable        ;PC=offset(lable)死循环。注意offset(lable)是编译工具处理的,
                 ;表示当前pc和lable的绝对地址之间的差值
addfunc1:        ;标号
  add r0,r0,r1   ;r0=r0+r1
  b r14          ;pc=r14实现子程序返回

这段程序非常简单,看代码注释就能明白它是干什么的,但我们主要是为了解b、bl指令的使用方式,当然没有写条件码,所以默认情况下指令总是会执行。

2.bx指令

bx指令是将一个寄存器中的内容(通常这个内容是一个程序的地址),放进PC寄存器中,导致程序的跳转执行并且它还改变处理器的状态:ARM状态到Thumb状态或者Thumb状态到ARM状态。bx指令用Rn寄存器中的数据和0xFFFFFFFE进行与操作,把结果写到PC寄存器中,然后根据Rn寄存器第0位的值决定处理器的运行状态,即用这个值设置CPSR寄存器的T位,也就是处理器的状态位。

汇编程序中的用法:

bx{cond} <Rn>

□{}中的表示可选项。

□<>中的表示必需项。

□cond表示条件码。

□Rn表示一个合法的寄存器。

例如:

.code32                     ;32位的ARM状态指令
main:
    adr r0,thumb_ins+1      ;r0=thumb_ins+1
    bx r0                   ;pc=r0,并进行处理器状态切换
.code16                     ;16位的thumb状态指令
thumb_ins:
    adr r0,main             ;r0=main, main的地址
    bx r0                   ;pc=r0,并进行处理器状态切换

3.blx指令

blx指令有两种情况,一种是无条件执行,只能跳转到Thumb指令的地址并切换处理器状态为Thumb状态;另一种是有条件执行的,可以在ARM状态和Thumb状态之间互相切换和跳转。这两种情况都会在跳转的同时先保存PC至R14中。

在汇编中的用法:

第1种为blx<lable_offset>。

□<>中的表示必需项。

□lable_offset表示跳转标号即跳转地址。使用规则和bl指令一样。

第2种为blx{cond}<Rn>。

□{}中的表示可选项。

□<>中的表示必需项。

□cond表示条件码。

□Rn表示一个合法的寄存器。

例如:

.code32                        ;32位的ARM状态指令
main:
    adr r0,thumb_ins+1         ;r0=thumb_ins+1
    blx r0                     ;r14=pc,pc=r0并且进行处理器状态切换
.code16                        ;16位的thumb状态指令
thumb_ins:
    adr r1,main                ;r1=main,r1=main的地址
    blx r1                     ;r14=pc,pc=r1,并进行处理器状态切换