4

我知道添加两个大于给定处理器总线大小的无符号整数可以通过进位标志来实现。通常,使用溢出标志的有符号整数也是如此。但是Intel 8085只有一个Sign标志,没有Overflow标志,那么它是如何处理有符号整数运算的呢?

4

1 回答 1

7

如您所知,溢出标志仅与有符号整数运算有关。在 ALU 同时具有溢出和进位标志的处理器(如 x86)上,这两个标志都根据二进制算术运算的结果设置,但由程序员决定如何解释它们。有符号算术使用溢出标志;无符号算术使用进位标志。看错了会给你毫无意义的数据。

有两种情况会在二进制算术运算期间打开溢出标志:

  1. 输入都有一个关闭的符号位,而结果有一个开启的符号位。
  2. 输入都具有打开的符号位而结果具有关闭的符号位。

基本上,当结果的符号位与输入操作数的符号位不匹配时,溢出标志被设置。在所有其他情况下,溢出标志被关闭。

举几个例子:

  • 0100 + 0001 = 0101(溢出标志关闭
  • 0100 + 0100 = 1000(溢出标志开启
  • 0110 + 1001 = 1111(溢出标志关闭
  • 1000 + 1000 = 0000(溢出标志打开
  • 1000 + 0001 = 1001(溢出标志关闭
  • 1100 + 1100 = 1000(溢出标志关闭

请注意,溢出标志的状态取决于三个数字的符号位;因此,您只需要查看这些位。这很直观。如果你将两个正数相加得到一个负数,那么答案一定是错误的,因为两个正数应该给出一个肯定的结果。相反,如果你将两个负数相加得到一个正数,那也一定是错误的。加到负数上的正数永远不会溢出,因为和位于两个输入值之间。因此,混合符号值的算术永远不会打开溢出标志。

(显然,这一切都假设了补码算术。)

因此,即使处理器的 ALU 没有自动为您计算溢出标志的状态,您也可以轻松计算。您需要做的就是查看三个值的符号位,特别是符号位的二进制和符号位的二进制进位。当一位进位到符号位并且没有发生相应的进位时,就会发生溢出。

这些 C 函数实现了以下逻辑:

// For the binary (two's complement) addition of two signed integers,
// an overflow occurs if the inputs have the same sign AND ALSO the
// sign of the result is different from the signs of the inputs.
bool GetOverflowFlagForAddition(int op1, int op2, int result)
{
   return (~(op1 ^ op2) & (op1 ^ result)) < 0;
}

// For the binary (two's complement) subtraction of two signed integers,
// an overflow occurs if the inputs have the same sign AND ALSO the
// sign of the result matches the signs of the inputs.
bool GetOverflowFlagForSubtraction(int op1, int op2, int result)
{
   return ((op1 ^ op2) & (op1 ^ result)) < 0;
}

(当然,你可以用许多不同的方式来写这个。)

或者,用Iwillnotexist Idonotexist 在评论中所做的术语来说:“溢出可以定义为进位进出符号位的异或。” 如果进不等于该特定(最左边)位的进位,则会发生溢出。

更正式的定义是溢出标志是结果的高两位进位的异或。象征性地,对于 8 位值:O = C 6 ^ C 7,其中O表示“溢出”,C表示“进位”。这只是对我已经给出的定义的重申:如果进位与最高位(在本例中为位 7)的进位不同,则会发生溢出。

另请参阅Ken Shirriff 关于溢出标志如何在算术上工作的文章(这是在另一个流行的 8 位处理器 6502 的上下文中)。他还解释了在 6502 的芯片级上溢出标志的实现


好的,那么进位标志是什么意思?进位标志表示无符号算术中的溢出条件。再次设置它的情况有两种:

  1. 如果最高有效位(符号位)有进位,则在加法期间设置进位标志。

  2. 如果向最高有效位(符号位)借位,则在减法期间设置进位标志。

在所有其他情况下,进位标志被关闭。再次,示例:

  • 1111 + 0001 = 0000(继续标志
  • 0111 + 0001 = 1000(举旗
  • 0000 - 0001 = 1111(继续标志
  • 1000 - 0001 = 0111(举旗

以防万一不明显,需要明确指出减法与二进制补码否定的加法相同,因此后两个示例可以根据加法重写为:

  • 0000 + 1111 = 1111(继续标志
  • 1000 + 1111 = 0111(举旗

…但请注意,减法的进位是加法设置的进位的倒数。


然后,将所有这些放在一起,您绝对可以根据进位和符号标志来实现溢出标志。如果您对最高有效位(符号位)进行了进位,则设置进位标志。如果结果设置了符号位,则设置符号标志,这意味着最高有效位有进位。根据我们上面对溢出标志的定义,OF == CF ^ SF,因为溢出是来自符号位的进位与进入符号位的进位异或。如果进不等于进,则发生有符号溢出。

然而,有趣的是,Ken Shirriff对 8085 处理器的逆向工程表明它确实有一个溢出标志——只是没有记录。这是 8 位标志状态寄存器的第 1 位。它被称为“V”,正如Ken 在此处解释的那样,它的实现方式与上面讨论的完全相同,通过将进与最高有效位的进位进行异或运算- <strong>C 6 ^ 7 _,这些值直接来自 ALU。(他还在同一篇文章中描述了另一个未记录的标志“K”标志是如何根据“V”标志和符号标志实现的,产生一个在有符号比较中有用的标志,但有点超出这个答案的范围。)

于 2017-07-23T05:41:07.453 回答