第4章 ARM7TDMI(-S)指令系统
… DATA_BUF
6. Thumb 伪指令
ADR——小范围的地址读取伪指令
ADR 指令将基于 PC 相对偏移的地址值读取到寄存器中。ADR 伪指令格式如下:
ADR register,expr
其中: register 加载的目标寄存器。
expr 地址表达式。偏移量必须是正数并小于 1KB。Expr 必须局部定义,
不能被导入。
ADR 伪指令举例如下:
ADR R0,TxtTab
… TxtTab
DCB "ARM7TDMI",0
LDR——大范围的地址读取伪指令
LDR 伪指令用于加载 32 位的立即数或一个地址值到指定寄存器。在汇编编译源程序时,
LDR 伪指令被编译器替换成一条合适的指令。若加载的常数未超出 MOV 的范围,则使用 MOV 或 MVN 指令代替该 LDR 伪指令,否则汇编器将常量放入文字池,并使用一条程序相 对偏移的LDR 指令从文字池读出常量。LDR 伪指令格式如下:
LDR register,=expr/label-expr
其中: register 加载的目标寄存器。
expr 32 位立即数。
label-expr 基于 PC 的地址表达式或外部表达式。
- - 110 LDR 伪指令举例如下:
LDR R0,=0x12345678 ; 加载32 位立即数 0x12345678 LDR R0,=DATA_BUF+60 ; 加载DATA_BUF 地址+60
…
LTORG ; 声明文字池
…
从 PC 到文字池的偏移量必须是正数并小于 1KB。
与 Thumb 指令的 LDR 相比,伪指令的 LDR 的参数有“=”号。
NOP——空操作伪指令
NOP 伪指令在汇编时将会被代替成 ARM 中的空操作,比如可能为 MOV R0,R0 指令 等。NOP 伪指令格式如下:
NOP
NOP 可用于延时操作。
2.6 本章小结
本章详细地价绍了ARM 指令集、Thumb 指令集,并列出了各条指令的编码格式及相关 应用举例,使读者对ARM7TDMI(-S)的指令系统有全面的了解。
思考与练习 1 基础知识
a) ARM7TDMI(-S)有几种寻址方式?LDR R1,[R0,#0x08]属于哪种寻址方式?
b) ARM 指令的条件码有多少个?默认条件码是什么?
c) ARM 指令中第二个操作数有哪几种形式?列举 5 个 8 位图立即数。
d) LDR/STR 指令的偏移形式有哪 4 种?LDRB 和 LDRSB 有何区别?
e) 请指出 MOV 指令与 LDR 加载指令的区别及用途。
f) CMP 指令的操作是什么?写一程序,判断 R1 的值是否大于 0x30,是则将 R1 减去 0x30。
g) 调用子程序是用 B 还是用 BL 指令?请写出返回子程序的指令?
h) 请指出 LDR 伪指令的用法。指令格式与 LDR 加载指令的区别是什么?
i) ARM 状态与 Thumb 状态的切换指令是什么?请举例说明。
j) Thumb 状态与 ARM 状态的寄存器有区别吗?Thumb 指令对哪些寄存器的访问受到 一定即制?
k) Thumb 指令集的堆栈入栈、出栈指令是哪两条?
l) Thumb 指令集的 BL 指令转移范围为何能达到±4MB?其指令编码是怎样的?
2 有符号和无符号加法
下面给出A 和 B 的值,您可先手动计算 A+B,并预测 N、Z、V 和 C 标志位的值。然 后修改程序清单4.1 中 R0、R1 的值,将这两个值装载到这两个寄存器中(使用 LDR 伪指令,
如LDR R0,=0x FFFF0000),使其执行两个寄存器的加法操作。调试程序,每执行一次加法 操作就将标志位的状态记录下来,并将所得结果与您预先计算得出的结果相比较。如果两个 操作数看作是有符号数,如何解释所得标志位的状态?同样,如果这两个操作数看作是无符
- - 111 号数,所得标志位又当如何理解?
0xFFFF000F 0x7FFFFFFF 67654321 (A) + 0x0000FFF1 + 0x02345678 + 23110000 (B)
结果: ( ) ( ) ( )
3 数据访问
把下面的C 代码转换成汇编代码。数组 a 和 b 分别存放在以 0x4000 和 0x5000 为起始 地址的存储区内,类型为long(即 32 位)。把编写的汇编语言进行编译连接,并进行调试。
for (i=0; i<8; i++) { a[i] = b[7-i];
}
4 阶乘计算
计算一个数n 的阶乘,即 n!=n*(n-1)*(n-2)…(1)。
给定n 的值后,整个算法就是不断使当前值与前一次乘数减一所得值相乘,这里所说的 当前值即是乘法运算的结果。程序不断循环执行乘法操作,每次循环先将乘数减一,若所得 值为0 则循环结束。在程序中,使用条件执行的思想来做乘法。在编写含有循环和转移指令 的程序时,由于可以用 Z 标志来迅速判断是否到达循环次数,很多编程者通常使用一个非 零数向下计数而不是向上计数的方法来起动程序。
请填充下面的代码段,并加入相应的段声明信息,然后调试程序的正确性。设定n 的值 为10,说明程序执行结果,并观察程序运行之前和之后寄存器的内容。
FACTORIAL MOV R6,#10 ; 将10 存放到 R6 (n)
MOV R4,R6 ; 初始化保存结果的寄存器 R4 (n 的结果) LOOP SUBS _____________ ; 本次乘数减一
MULNE _____________ ; 乘法运算
BNE LOOP ; 如果循环未结束,转去执行下次循环
- - 112