[转译][马基 杰斯特(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 (相等条件分支) 指令
浙公网安备 33010602011771号