如何解决为什么没有实现 DIV 指令来设置 CF 而不是引发异常 没有其他 8086 数学指令需要截断,如果你考虑 FLAGShigh_half < divisor 是 无符号除法的证明
我知道在汇编中分割时必须非常小心,即 这样做:
mov ah,10h
mov al,00h ; dividend = 1000h
mov bl,10h ; divisor = 10h
div bl ; Integer overflow exception,/result 100h cannot fit into al
我已经编写了一些可能无法证明的逻辑来为除法创建一个更友好的环境:
mov ah,00h
mov bl,10h
TryDivide:
cmp bl,ah
jna CatchClause
div bl
clc
jmp TryEnd
CatchClause:
stc
TryEnd:
有没有人知道类似这样的事情没有实现的技术原因,我们有例外而不是标志设置/寄存器被截断?
解决方法
要获得明确的答案,您必须询问 8086 指令集的设计者 Stephen Morse。
其他英特尔工程师负责实际实施,但apparently the ISA was designed on paper first几乎完全由一个人完成。他还被誉为 8086 的首席架构师。PC World interviewed him 在 2008 年,为纪念 8086 成立 30 周年,更重要的是他写了一本书,8086/8088 Primer(1982 年)。我没有读过它,但显然他讨论了一些设计决策以及如何对其进行编程。如果幸运的话,也许他写了一些关于选择使用 div/idiv 陷阱的内容。
没有理由必须这样;设置 CF 和/或 OF 和截断本来是有效的设计。但是在被零除1的情况下,您仍然需要选择一些值放入商/余数输出寄存器。 (我认为对于具有硬件除法的 ISA 来说,至少除以零时出现除法错误异常是很常见的,但不幸的是,On which platforms does integer divide by zero trigger a floating point exception? 只提到 x86 作为带有陷阱的 ISA。如果除法确实 陷阱和 POSIX 操作系统根本没有传递信号,对于算术异常,它必须是 SIGFPE。)
请注意,其他 ISA 确实会做出不同的选择。 例如,ARM 部门从不出错,也不设置标志。 (虽然它不提供双倍宽度的红利,所以只有 the INT_MIN / -1
signed overflow 和除以 0 的情况是特殊的。)
IDK 如果构建一个硬件除法单元(或微码)可以获得正确截断的溢出情况的商(当确切的商大于 16 位时)将比简单地检测溢出和救助更困难。如果是这样,那将是一个很好的理由。
(在输出寄存器中留下垃圾并设置 FLAGS 是可能的,但不是很好;如果想要避免使用垃圾的可能性,每个除法都需要事后检查结果。)
注 1:在某些方面 0 的 div 是这种情况的一个特例:high_half < divisor
对于 any 被除数的除数 = 0 为假。但是没有定义明确的数学结果可以截断。 IEEE FP 除法通过将除数接近 0(即 +-无穷大)视为极限来解决此问题。但是整数 0 应该被假定为正好是 0,而不是一些很小的数字,并且无论如何都没有带内 NaN 或 Inf 值可以使用,只有一个有限的 0xFFFF...
没有其他 8086 数学指令需要截断,如果你考虑 FLAGS
请注意,8086 仅包括 mul
和 imul
的单操作数形式,它们进行加宽乘法:DX:AX = AX * src
。 (如果高半部分不为零(对于 mul
),或者如果高半部分不是低半部分的符号扩展(对于 imul
),则设置 CF 和 OF)。只有后来的 CPU 引入了截断形式,如 imul r,r/m,imm
(186) 和 imul r,r/m
(386),它们不会浪费时间在任何地方写入高半部分,尽管仍然设置 FLAGS 以便您可以检测签名包装如果你想要。 (大多数用途都没有,所以后来的 CPU 只提供 imul,除了 FLAGS 之外,mul 的版本是相同的。)
add
/sub
可以进位/借位,但加法的完整结果可作为 CF : reg
使用,进位标志中有额外的位。
如果您将 sar / shr / shl reg,cl
视为按位逻辑运算,而不是数学运算,那么即使它可以移出多个位而不将它们留在任何地方,它也不算数。 (最后一位保留在 CF 中,因此可以通过循环进位来撤消 1 移位。)
剩下的就是 DIV / IDIV,因为我认为只有算术指令可以产生更广泛的结果,但无处可放。这可能是动机的一部分选择让他们过错。
high_half < divisor
是 无符号除法的证明
这是在操作数大小中商拟合的确切条件。 1:0
(例如,对于 8 位操作数大小的 0x0100
)是不适合的最小商,因此 0x0100 * divisor
是产生不适合 8 位的商。
当分成与股息宽度相同的 hi:lo 一半时,该股息为 divisor:0
。
任何小于该数字的数字都必须从高半部分“借用”,使其严格小于 divisor
。
(有符号除法也有 INT_MIN / -1
溢出边角情况,高半检查可能必须是绝对值。)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。