[转译][马基 杰斯特(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

对于状态标志的修改它们也是一样的。当然了,这种情况下VC状态标志永远都会是0

这条指令的好处是它比CMP更小更快,所以如果你想要做与0的比较的话,用TST指令是一种更优的选择

BTST 指令

BTST (TeST a bit) - 测试一个

这条指令会测试目的操作数中的某一看看它是0还是1,具体是哪一取决于源操作数,然后结果会被放到Z状态标志中

例子

如果你还记得在第三章第五节的时候,我们学习了BSETBCLRBCHG指令。这条指令和它们的工作方式有点类似,源操作数目的操作数的一些约束条件是一样的 (比如源操作数只能是立即数或是数据寄存器,目的操作数是数据寄存器时指令使用的长度只能是长字,而目的操作数是地址的时候指令使用的长度只能是字节,等等)

不同点在于这条指令并不会修改目的操作数,它只是会检查相应的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中的030,由于它是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中的111,由于它是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 (相等条件分支) 指令

posted @ 2020-03-13 12:08  草帽过客  阅读(1069)  评论(0编辑  收藏  举报