有人可以解释我的代码有什么问题以及我老师的代码是如何工作的吗?



我正在尝试用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

和我不明白为什么需要使用cwdsbb的说明,以及以下行:

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 位,部分原因是idivimul在 32 位寄存器对上运行dxax

imul z结果是-100000,但这不适合 16 位,并且已经自动拆分为dx=0xFFFE=-2ax=0x7960=31072。为了做减法,x-y*zx也扩展到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

是的,您可以使用其他指令模拟cwdsbb,例如使用显式条件跳转。cwdjust 符号将ax扩展到dx意思,如果ax为负数,则dx将被设置为0xffff,否则设置为 0。您可以简单地手动执行此操作,或者使用算术移位填充符号位dx或者如果您被允许知道x总是正数,那么只需零dx。而不是sbb您可以检查是否有进位(借用)并从结果中减去 1,如果是这样,然后再用普通sub处理其余部分。

最新更新