没有溢出标志的处理器如何执行带符号算术?

par*_*nce 4 math assembly signed 8085 integer-arithmetic

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

Cod*_*ray 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;
}
Run Code Online (Sandbox Code Playgroud)

(当然,有很多不同的方法可以写这个.)

或者,将其置于Iwillnotexist Idonotexist在评论中所做的术语中:"溢出可以定义为进出符号位的异或." 如果进溢出发生不等于随身携带在那个特定的(最左边)位.

更正式的定义是溢出标志是结果的高两位的进位的XOR.符号上,对于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"和作为肯解释这里,在恰好上面所讨论的方式来实现,通过异或进位最-显著位进位最-显著比特的Ç 6 ^ C 7,这些值直接来自ALU.(他还在同一篇文章中描述了另一个未记录的标志,即"K"标志是如何用"V"标志和符号标志实现的,产生一个在签名比较中有用的标志,但有点超出了这个答案的范围.)