我正在尝试用emu8086编写一些代码。我是组装新手,所以对我来说仍然有点困惑。在我的作业中,对于其中一个练习,我必须:
创建一个代码来求解:r=(x-y*z)/t
值为:x = 2000; y = -500; z = 200; t = 300; r = ?
我检查了我们课程中给出的解决方案:
x dw 2000 y dw -500 z dw 200 t dw 300 r dw ? ____________________ mov ax, y imul z mov cx, dx mov bx, ax mov ax, x cwd sub ax, bx sbb dx, cx idiv t mov r, ax
和我不明白为什么需要使用cwd
和sbb
的说明,以及以下行:
mov cx, dx mov bx, ax
sbb dx, cx
这是我自己编写的代码:
mov AX, y
imul z
mov BX, x
sub BX, AX
idiv t
mov r, BX
这些是我得到的结果:
x = 07D0h
y = 0FE0Ch
z = 00C8h
t = 012Ch
r = 8E70h
(https://i.stack.imgur.com/9CU9Q.png)
r的值应该是0154h
,十进制为 340。
我想问题可能与乘法导致负数有关,但我不明白如何解决它。
有人可以解释上述目的吗 此代码中的说明,它们如何影响整个过程以及为什么我自己的代码是错误的?除此之外,还有其他方法可以解决此问题而无需使用这些说明吗?
您所看到的是使用 16 位寄存器实现 32 位算术。这是必需的,因为计算的中间值不适合 16 位,部分原因是idiv
和imul
在 32 位寄存器对上运行dx
和ax
。
imul z
结果是-100000
,但这不适合 16 位,并且已经自动拆分为dx=0xFFFE=-2
和ax=0x7960=31072
。为了做减法,x-y*z
x
也扩展到32位,使用cwd
指令。在此之前,临时y*z
被移开到cx:bx
对。减法是通过首先使用普通sub
进行低 16 位,并使用sbb
进行前 16 位来传播进位(借用)来完成的。结果保留在dx:ax
这是对idiv
的隐式输入。然后以ax
产生商。
您的代码是错误的,因为sub BX, AX
将结果保留在bx
中,idiv
根本不使用,因为它隐式地dx:ax
操作。然后存储该bx
,它甚至不是idiv
的输出。您也只使用低 16 位进行计算,因此结果为2000-31072=-29072=0x8E70
。
是的,您可以使用其他指令模拟cwd
和sbb
,例如使用显式条件跳转。cwd
just 符号将ax
扩展到dx
意思,如果ax
为负数,则dx
将被设置为0xffff
,否则设置为 0。您可以简单地手动执行此操作,或者使用算术移位填充符号位dx
或者如果您被允许知道x
总是正数,那么只需零dx
。而不是sbb
您可以检查是否有进位(借用)并从结果中减去 1,如果是这样,然后再用普通sub
处理其余部分。