我正在尝试用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 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。
我猜这个问题可能与乘法运算结果为负数有关,但我不知道如何解决它。
有人能解释一下这段代码中上述指令的用途吗?它们如何影响整个过程?为什么我自己的代码是错误的?除此之外,有没有其他方法可以解决这个问题,而不必使用这些指令?
1条答案
按热度按时间e5nszbig1#
您所看到的是使用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
中,dx:ax
是idiv
的隐式输入,然后在ax
中产生商。您的代码是错误的,因为
sub BX, AX
将结果保留在bx
中,而idiv
根本不使用该结果,因为它隐式地对dx:ax
进行操作。然后您存储的bx
甚至不是idiv
的输出。您还仅使用低16位进行计算,因此结果为2000-31072=-29072=0x8E70
。是的,您可以使用其他指令模拟
cwd
和sbb
,例如使用显式条件跳转。cwd
只是将ax
符号扩展为dx
,这意味着如果ax
为负,则dx
将设置为0xffff
,否则设置为零。您可以简单地手动完成此操作。或者使用算术移位用符号位填充dx
,或者如果允许您知道x
总是正的,则仅将dx
清零。代替sbb
,您可以仅检查是否存在进位(借位),如果存在,则从结果中减去1,然后使用普通sub
处理其余部分。