我已经开始了解 CMP
指令,比较两个整数。
当使用无符号整数时,我读到:
-
ZF=1
意味着目的地和来源相同。 -
ZF=0 && CF = 0
意味着destination > source
-
ZF=0 && CF = 1
意味着destination < source
据我了解,CMP 指令使用隐式减法,而不更改操作数的值。
减法没有意义!
假设我执行以下指令:
CMP 1, 4
1 - 4 = 1 + (-4)
...001
.+.100
= 101
我在这里没有看到进位,我的意思是,进位位是 0
,不是吗?所以我上面说的,我读到的是正确的,是错误的。
我只是不明白为什么这个减法会设置进位标志。 我没有进位!如果进位位只是数字的(在本例中)第 4 位,则它为零。
我花了几个小时试图弄清楚。
最佳答案
所以让我们尝试 3 位系统中的所有 3 位数字
000 - 000 = 0000 : +0 - +0 = + 0 Z
000 - 001 = 1111 : +0 - +1 = +15 [-1] C
000 - 010 = 1110 : +0 - +2 = +14 [-2] C
000 - 011 = 1101 : +0 - +3 = +13 [-3] C
000 - 100 = 1100 : +0 - +4 = +12 [-4] C
000 - 101 = 1011 : +0 - +5 = +11 [-5] C
000 - 110 = 1010 : +0 - +6 = +10 [-6] C
000 - 111 = 1001 : +0 - +7 = + 9 [-7] C
001 - 000 = 0001 : +1 - +0 = + 1
001 - 001 = 0000 : +1 - +1 = + 0 Z
001 - 010 = 1111 : +1 - +2 = +15 [-1] C
001 - 011 = 1110 : +1 - +3 = +14 [-2] C
001 - 100 = 1101 : +1 - +4 = +13 [-3] C
001 - 101 = 1100 : +1 - +5 = +12 [-4] C
001 - 110 = 1011 : +1 - +6 = +11 [-5] C
001 - 111 = 1010 : +1 - +7 = +10 [-6] C
010 - 000 = 0010 : +2 - +0 = + 2
010 - 001 = 0001 : +2 - +1 = + 1
010 - 010 = 0000 : +2 - +2 = + 0 Z
010 - 011 = 1111 : +2 - +3 = +15 [-1] C
010 - 100 = 1110 : +2 - +4 = +14 [-2] C
010 - 101 = 1101 : +2 - +5 = +13 [-3] C
010 - 110 = 1100 : +2 - +6 = +12 [-4] C
010 - 111 = 1011 : +2 - +7 = +11 [-5] C
011 - 000 = 0011 : +3 - +0 = + 3
011 - 001 = 0010 : +3 - +1 = + 2
011 - 010 = 0001 : +3 - +2 = + 1
011 - 011 = 0000 : +3 - +3 = + 0 Z
011 - 100 = 1111 : +3 - +4 = +15 [-1] C
011 - 101 = 1110 : +3 - +5 = +14 [-2] C
011 - 110 = 1101 : +3 - +6 = +13 [-3] C
011 - 111 = 1100 : +3 - +7 = +12 [-4] C
100 - 000 = 0100 : +4 - +0 = + 4 [-4]
100 - 001 = 0011 : +4 - +1 = + 3
100 - 010 = 0010 : +4 - +2 = + 2
100 - 011 = 0001 : +4 - +3 = + 1
100 - 100 = 0000 : +4 - +4 = + 0 Z
100 - 101 = 1111 : +4 - +5 = +15 [-1] C
100 - 110 = 1110 : +4 - +6 = +14 [-2] C
100 - 111 = 1101 : +4 - +7 = +13 [-3] C
101 - 000 = 0101 : +5 - +0 = + 5 [-3]
101 - 001 = 0100 : +5 - +1 = + 4 [-4]
101 - 010 = 0011 : +5 - +2 = + 3
101 - 011 = 0010 : +5 - +3 = + 2
101 - 100 = 0001 : +5 - +4 = + 1
101 - 101 = 0000 : +5 - +5 = + 0 Z
101 - 110 = 1111 : +5 - +6 = +15 [-1] C
101 - 111 = 1110 : +5 - +7 = +14 [-2] C
110 - 000 = 0110 : +6 - +0 = + 6 [-2]
110 - 001 = 0101 : +6 - +1 = + 5 [-3]
110 - 010 = 0100 : +6 - +2 = + 4 [-4]
110 - 011 = 0011 : +6 - +3 = + 3
110 - 100 = 0010 : +6 - +4 = + 2
110 - 101 = 0001 : +6 - +5 = + 1
110 - 110 = 0000 : +6 - +6 = + 0 Z
110 - 111 = 1111 : +6 - +7 = +15 [-1] C
111 - 000 = 0111 : +7 - +0 = + 7 [-1]
111 - 001 = 0110 : +7 - +1 = + 6 [-2]
111 - 010 = 0101 : +7 - +2 = + 5 [-3]
111 - 011 = 0100 : +7 - +3 = + 4 [-4]
111 - 100 = 0011 : +7 - +4 = + 3
111 - 101 = 0010 : +7 - +5 = + 2
111 - 110 = 0001 : +7 - +6 = + 1
111 - 111 = 0000 : +7 - +7 = + 0 Z
其中 C 是进位/借位,Z 为零
您的规则严格来说是一个未签名的规则。对于有符号,我认为这就像如果 N != V 则签名小于,如果 N == V 则签名大于。
所以 0 - 0 是 0 Z 标志它们相等 然后是 0 - 1 和 0 - 2 等等。第二个操作数大于 Z 未设置且进位设置。
直到我们达到 1 - 0(不为零)且 C 未设置时,左边的数字才会更大。
然后我们得到相等的 (1 - 1)
还有一些 Z 未设置 C 设置,因此正确的数字更大。
然后 2 - 0、2 - 1 左侧更大(Z 未设置 C 未设置),然后 2 - 2 Z 已设置,然后 2 - 3 到 2 - 7 Z 未设置 C 已设置,因此右侧更大。
并且这种模式会重复。
当然,诀窍在于源和目标的定义是什么,这通常没有记录在指令集中,您必须通过实验来确定这一点,并且出于某种原因,至少对我来说,我总是猜错。
您的具体示例
1 与 4 相比 1 - 4 = 1 + (-4), 4 = 0b100,因此 -4 = 011 + 1
送入加法器,减法意味着反转进位并将第二个操作数反转:
1
001
+ 011
=======
填写
0111
001
+ 011
=======
101
1 - 4 = -3。 Z 是 0 C 是 0 所以 1 < 4
请注意,要从进位位中获取借位,请反转进位(借位 = ~ 进位)。进位为 0 意味着发生了借位,如果您尝试使用铅笔和纸以十进制形式从 1 中减去 4,这一点是显而易见的。
如果没有借位,则设置进位,例如取 4 - 1:
1001
100
+ 110
========
011
4 - 1 = 3,无借位。 Z 未设置 C 已设置,因此 4 > 1
我认为这里的底线是哪个操作数是源,哪个是目标,为什么他们很少正确记录它?任何时候你在指令集中使用比较,你都必须用固定的数字做一些实验来看看哪个操作数是哪个。您还必须非常小心地使用有符号或无符号大于或小于它会产生差异。有些指令集不提供一种或另一种风格,但这没关系,你真的不需要一长串有符号和无符号的 this 和 that 左右切换操作数并理解标志,你可以找到一个简单的 if 进位或不进位或如果什么给你几乎一切,有时你会得到额外的好处,当 Z 设置时,那么进位是零右,这意味着未设置的进位是“或等于”。
关于assembly - CMP 和 2 的补码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28287354/