assembly 有人能解释一下我的代码有什么问题吗?我的教师代码是如何工作的?

vxf3dgd4  于 2023-01-17  发布在  其他
关注(0)|答案(1)|浏览(117)

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

我猜这个问题可能与乘法运算结果为负数有关,但我不知道如何解决它。
有人能解释一下这段代码中上述指令的用途吗?它们如何影响整个过程?为什么我自己的代码是错误的?除此之外,有没有其他方法可以解决这个问题,而不必使用这些指令?

e5nszbig

e5nszbig1#

您所看到的是使用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中,dx:axidiv的隐式输入,然后在ax中产生商。
您的代码是错误的,因为sub BX, AX将结果保留在bx中,而idiv根本不使用该结果,因为它隐式地对dx:ax进行操作。然后您存储的bx甚至不是idiv的输出。您还仅使用低16位进行计算,因此结果为2000-31072=-29072=0x8E70
是的,您可以使用其他指令模拟cwdsbb,例如使用显式条件跳转。cwd只是将ax符号扩展为dx,这意味着如果ax为负,则dx将设置为0xffff,否则设置为零。您可以简单地手动完成此操作。或者使用算术移位用符号位填充dx,或者如果允许您知道x总是正的,则仅将dx清零。代替sbb,您可以仅检查是否存在进位(借位),如果存在,则从结果中减去1,然后使用普通sub处理其余部分。

相关问题