难道我们不能用ADD指令把8086中的两个16位数字相加吗?
Can't we use the ADD instruction to add two 16-bit numbers in 8086?
由于 8086 有一个带 16 位寄存器的 16 位 ALU,这就是我描绘的添加两个 16 位数字的方式:
MOV BX,12FFh
MOV CX,0001h
ADD BX,CX
但是我的教授说 8086 通过将 8 位数字对中的数字相加分两步而不是一步完成此操作。她说如果直接用ADD指令,lower sum产生的进位是不会结转的。她是这样解决的:
MOV BX,12FFh
MOV CX,0001h
ADD BL,CL
ADC BH,CH
她的解决方案是唯一可以接受的将两个 16 位数字相加的方法吗?
您的第一个代码块在 BX 中产生与第二个代码块相同的结果。 (在 CF 和 SF 中,我认为是 OF。不过,出于显而易见的原因,不是 ZF、PF 或 AF。)
16 位 add
不是两个单独字节加法的 SIMD 加法。如果需要,请使用 movd xmm0, ebx
/ movd xmm1, ecx
/ paddb xmm0, xmm1
。 MMX / SSE2 paddb
is SIMD addition with separate byte elements. Scalar integer add
是对整个操作数大小的单个整数加法运算,CF 和 OF 根据寄存器的顶部确定,无论是什么。
您可以通过构造一个进位跨 8 位边界传播的测试用例来简单地证明这一点。在调试器中单步执行此操作并在添加后查看寄存器。
mov ax, 0x80
add ax, ax ; ax = 0x0100 = 0x0080 << 1
或查看编译器输出,例如 https://godbolt.org/z/xKfK6h4d5,其中 GCC 使用 add eax, edx
来实现两个 short
变量的加法,或使用 add
的任何现有代码示例例如,做指针数学。
也许您的教授不得不自己学习汇编来教授一门课程,并且没有太多经验。 add
和其他整数寄存器操作是对整数的单一操作这一事实是非常基本的,并且在所有(?)ISA 中都是如此。 (虽然 8086 是少数具有别名到 low/high 一半的部分寄存器之一)。希望她能纠正她的误解,让 class 知道汇编是如何工作的。
But my professor said that 8086 did this operation in two steps instead of one ...
她错了:
根据8086数据sheet(第2-52页),两个16位数字相加与两个8位数字相加所用时间完全相同:3个时钟周期。
有CPUs(如8085)分两步执行16位加法;但是8086不这样做。
She said that the carry generated by lower sum won't be carried over if we used ADD instruction directly.
这意味着在添加 12FFh
和 0001h
时,ADD BX, CX
运算结果为 1200h
。
这完全是胡说八道:
即使是Z80CPU(只有4位ALU)在这个加法中也会计算出1300h
的结果;带有 16 位 ALU 的 8086(或 8088)无论如何都会计算出正确的结果!
可能她和808混淆了5:
8085 不会在 16 位加法后设置所有标志(例如零标志);然而,即使是 8085 也会计算出正确的结果并正确设置进位标志。
Is her solution the only accepted way of adding two 16-bit numbers?
在这种情况下,每个编译器都会使用 ADD BX, CX
指令。
你的教授想看看你是否了解如何使用 ADC
指令。
因此,使用ADD BX, CX
并不是她想看到的。
但是,如果她没有告诉您应该只使用 8 位加法,那么您的解决方案是正确的!
由于 8086 有一个带 16 位寄存器的 16 位 ALU,这就是我描绘的添加两个 16 位数字的方式:
MOV BX,12FFh
MOV CX,0001h
ADD BX,CX
但是我的教授说 8086 通过将 8 位数字对中的数字相加分两步而不是一步完成此操作。她说如果直接用ADD指令,lower sum产生的进位是不会结转的。她是这样解决的:
MOV BX,12FFh
MOV CX,0001h
ADD BL,CL
ADC BH,CH
她的解决方案是唯一可以接受的将两个 16 位数字相加的方法吗?
您的第一个代码块在 BX 中产生与第二个代码块相同的结果。 (在 CF 和 SF 中,我认为是 OF。不过,出于显而易见的原因,不是 ZF、PF 或 AF。)
16 位 add
不是两个单独字节加法的 SIMD 加法。如果需要,请使用 movd xmm0, ebx
/ movd xmm1, ecx
/ paddb xmm0, xmm1
。 MMX / SSE2 paddb
is SIMD addition with separate byte elements. Scalar integer add
是对整个操作数大小的单个整数加法运算,CF 和 OF 根据寄存器的顶部确定,无论是什么。
您可以通过构造一个进位跨 8 位边界传播的测试用例来简单地证明这一点。在调试器中单步执行此操作并在添加后查看寄存器。
mov ax, 0x80
add ax, ax ; ax = 0x0100 = 0x0080 << 1
或查看编译器输出,例如 https://godbolt.org/z/xKfK6h4d5,其中 GCC 使用 add eax, edx
来实现两个 short
变量的加法,或使用 add
的任何现有代码示例例如,做指针数学。
也许您的教授不得不自己学习汇编来教授一门课程,并且没有太多经验。 add
和其他整数寄存器操作是对整数的单一操作这一事实是非常基本的,并且在所有(?)ISA 中都是如此。 (虽然 8086 是少数具有别名到 low/high 一半的部分寄存器之一)。希望她能纠正她的误解,让 class 知道汇编是如何工作的。
But my professor said that 8086 did this operation in two steps instead of one ...
她错了:
根据8086数据sheet(第2-52页),两个16位数字相加与两个8位数字相加所用时间完全相同:3个时钟周期。
有CPUs(如8085)分两步执行16位加法;但是8086不这样做。
She said that the carry generated by lower sum won't be carried over if we used ADD instruction directly.
这意味着在添加 12FFh
和 0001h
时,ADD BX, CX
运算结果为 1200h
。
这完全是胡说八道:
即使是Z80CPU(只有4位ALU)在这个加法中也会计算出1300h
的结果;带有 16 位 ALU 的 8086(或 8088)无论如何都会计算出正确的结果!
可能她和808混淆了5:
8085 不会在 16 位加法后设置所有标志(例如零标志);然而,即使是 8085 也会计算出正确的结果并正确设置进位标志。
Is her solution the only accepted way of adding two 16-bit numbers?
在这种情况下,每个编译器都会使用 ADD BX, CX
指令。
你的教授想看看你是否了解如何使用 ADC
指令。
因此,使用ADD BX, CX
并不是她想看到的。
但是,如果她没有告诉您应该只使用 8 位加法,那么您的解决方案是正确的!