[转译][马基 杰斯特(MarkeyJester) 摩托罗拉68000 入门教程] 陆 - 条件分支 | 2. CMP, TST & BTST (测试) 指令
注意:本文经过原作者授权转译,转载请标明出处
原文地址:http://mrjester.hapisan.com/04_MC68/Sect06Part02/Index.html
条件允许建议阅读原文,网上非中文资料还是较多,当作锻炼英文岂不美哉
翻译若有不足之处欢迎批评指正
译文:
"你的过去和未来与你的内心相比,微不足道" ---- 拉尔夫 沃尔多 爱默生 (Ralph Waldo Emerson, 1803-1882),美国思想家、文学家、诗人
简介:
这些指令会去检查目标操作数
的某些特定条件的状态,然后去相应的设置CCR
的某些状态标志,目标操作数
的内容保持不变
CMP 指令
CMP (CoMPare) - 比较
这条指令通过用目标操作数
减去源操作数
的结果来获得CCR
的状态,目标操作数
的内容保持不变
例子
你在之前的小节中已经见过CMP
指令了:
cmpi.w #$0F20, d0
假定d0
的内容是FF940F21
,由于指令指定的有效长度是.w
,也就是字
,所以只有0F21
会被拿来比较,CMP
指令比较的方式是用目标操作数
减去源操作数
,但是并不会保存计算的结果,所以0F21
- 0F20
= 0001
现在,它会开始设置状态标志 (flag):
- C (进位) -
0
,因为计算结果并没有超出一个字
的表示范围 - V (溢出) -
0
,因为正数
-正数
=正数
,结果很符合数学逻辑 - Z (零结果) -
0
,因为计算结果不是0
(不是0000
) - N (负结果) -
0
,因为计算结果不是个负数 (0001
) - X (扩展) -
CMP
指令不会修改这个状态标志
指令执行之后d0
的内容仍然是FF940F21
,但是CCR
里的状态标志已经有所改变,接下来的指令就可以使用这些状态标志
你可能又一次的发现CMP
指令带了一个i
表示立即数
,别忘了在使用立即数
的时候加上那个i
(当然,你的汇编程序可能会自动的帮你加上如果你忘了的话)
你可以使用字节
,字
或是长字
来做比较。CMP
指令也可以用来比较数据寄存器,地址寄存器,内存地址,使用地址寄存器表示的内存地址等等,有个例外是当你比较地址寄存器时,不可以使用字节
(.b
)有效长度的指令
TST 指令
TST (TeST an operand) - 测试一个操作数
这条指令会把目标操作数
与0
作比较然后更新CCR
状态标志,目标操作数
的内容不会被改变
例子
tst.w d0
它和这条指令的效果差不多:
cmpi.w #$0000, d0
对于状态标志的修改它们也是一样的。当然了,这种情况下V
和C
状态标志永远都会是0
这条指令的好处是它比CMP
更小更快,所以如果你想要做与0
的比较的话,用TST
指令是一种更优的选择
BTST 指令
BTST (TeST a bit) - 测试一个位
这条指令会测试目的操作数
中的某一位
看看它是0
还是1
,具体是哪一位
取决于源操作数
,然后结果会被放到Z
状态标志中
例子
如果你还记得在第三章第五节的时候,我们学习了BSET
,BCLR
和BCHG
指令。这条指令和它们的工作方式有点类似,源操作数
和目的操作数
的一些约束条件是一样的 (比如源操作数
只能是立即数或是数据寄存器,目的操作数
是数据寄存器时指令使用的长度只能是长字
,而目的操作数
是地址的时候指令使用的长度只能是字节
,等等)
不同点在于这条指令并不会修改目的操作数
,它只是会检查相应的位
是1
还是0
:
btst.l #$03, d0
在这条指令中,d0
中的03
位
会被检查,假设d0
的内容是7FF290F5
,表示成二进制就是
1F | 1E | 1D | 1C | 1B | 1A | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 0F | 0E | 0D | 0C | 0B | 0A | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 1 |
如你所见,d0
中的03
位
是0
,由于它是0
,所以Z
(零结果) 状态标志会被设置为1
再康一个例子:
btst.l #$11, d0
然后d0
的内容是7FF290F5
:
1F | 1E | 1D | 1C | 1B | 1A | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 0F | 0E | 0D | 0C | 0B | 0A | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 1 |
此时d0
中的11
位
是1
,由于它是1
,所以Z
(零结果) 状态标志会被设置为0
总结
这些指令会在需要的时候用来设置CCR
里的状态标志,你可能会经常把它们与一些条件跳转/分支
的指令连在一起使用 (比如BEQ
指令),然而很有必要提醒一下 m68k 是一个很特别的架构,它的指令是正交的,许多指令都会去设置,擦除或是修改CCR
的状态标志,比如:
add.b d1, d0
tst.b d0
beq.s ValueIsZero
这个例子中,首先d1
中的一个字节
会被加到d0
中,然后会去检查d0
的内容是不是0
,然后如果是0
的话,BEQ
指令就会跳转到标记ValueIsZero
处,如果不是0
,那指令就会继续顺序往下执行
问题在于,ADD
指令已经设置了Z
状态标志了,所以如果你把TST
指令删掉:
add.b d1, d0
beq.s ValueIsZero
其实执行的效果跟之前是一样的,不一样的是,你用了更少的指令,也就是说程序的代码量会更小,程序会执行的更快
目录
上一篇:[转译][马基 杰斯特(MarkeyJester) 摩托罗拉68000 入门教程] 陆 - 条件分支 | 1. CCR (状态字寄存器)
下一篇:[转译][马基 杰斯特(MarkeyJester) 摩托罗拉68000 入门教程] 陆 - 条件分支 | 3. BEQ & BNE (相等条件分支) 指令