0

我有这些代码行应该将进位标志设置为1。我通过emu8086中的模拟器运行了这段代码,它告诉我没有设置进位标志。在我看来,进位标志应该设置,因为数字0xC7(二进制:1100 0111)被移到左边,所以进位标志应该返回1。希望有人能帮忙。

.model small

.data

.code

main proc
mov ax, 0xC7          
xor cl , cl 
shl ax,1 
jnc a1 
inc cl
a1:
shl ax,1 
jnc a2 
inc cl
a2:
shl ax,1 
jnc a3 
inc cl
a3:
shl ax,1 
jnc a4 
inc cl
a4:

endp

end main
4

1 回答 1

1

所以你想做一个 16 位移位,但从低半部分的顶部设置 CF?我不知道你为什么想要那个,特别是如果你打算jnc而不是使用adc cl, 0CL += CF。

有更有效的方法来弹出寄存器的高半字节,例如复制寄存器并实际将位移出而不是仅仅使用寄存器。或者popcnt在隔离寄存器中的这些位之后使用指令,如果你可以假设一个现代 CPU。


无论如何,没有一条指令可以做到这一点,但是有几个选项可以根据您的需要设置 CF,具体取决于您需要的 CPU 兼容性。最直接的就是:

;; 386 for BT/BTS
   shl   ax, 1
   bt    ax, 8        ; set CF from the bit that was previously the top of AL

   adc   cl, 0        ; CL += CF

还有一种方式在旧 CPU 上可能很慢:x86 移位/旋转用&31(或&6364 位移位)掩盖计数,因此小于 32 位的移位/旋转可以使用与操作数大小一样大的计数并拥有它不计为 0。

rol根据从高到低“环绕”的最后一位设置 CF。8 位寄存器的计数为 8 时保持不变,最后一位旋转为低位。此外,286 之前的 CPU 无论如何都不会屏蔽计数,它们只需要与移位计数一样多的时钟周期。(因此,在没有用于恒定时间旋转的桶形移位器的旧 CPU 上,这非常慢。)

或者如果手册的 Operation 部分反映了实际的 286 实现,mod size则为实际的移位工作而旋转,但count != 0检查它是否设置了 FLAGS 是基于count & 1Fhnot count mod 8。如果确实如此,CF = LSB(dest)

;; 186 for immediate-count shifts/rotates
   shl   ax, 1
   rol   ah, 8        ; set CF from the bit that was previously the top of AL

   adc   cl, 0        ; CL += CF

显然,根据特定位设置 ZF 更容易,例如

   add   ax, ax     ; AX <<= 1
   test  ah, 1      ; ZF = low bit of AH

   ;test  ax, 1<<8   ; ZF = low bit of AH   same code size, actually
   jz   no_increment
   inc   cl
no_increment:

但是分支很糟糕adc

请注意,shlby 1 基本上没有任何优势,除非您可以将其与注册目标一起使用。add ax,ax在某些 CPU 上,使用左移更有效。它甚至以相同的方式设置 CF(根据之前的最高位)。

于 2019-06-09T22:11:29.513 回答