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

标签 math assembly signed integer-arithmetic 8085

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

最佳答案

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

在两种情况下,在二进制算术运算中将打开溢出标志:


输入都具有关闭的符号位,而结果具有打开的符号位。
输入都具有打开的符号位,而结果具有关闭的符号位。


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

举几个例子:


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 did in a comment表示:“溢出可以定义为进位和出位标志位的XOR。”如果进位不等于该特定(最左边)位的进位,则发生溢出。

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

另请参见Ken Shirriff's article on how the overflow flag works arithmetically(这在另一个流行的8位处理器6502的上下文中)。 He also explains the implementation of the overflow flag at the silicon level in the 6502



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


如果有最高有效位(符号位)的进位,则进位标志在加法期间设置。
如果在最高有效位(符号位)有一个借位,则在减法期间设置进位标志。


在所有其他情况下,进位标志都将关闭。同样,示例:


1111 + 0001 = 0000(进位标记开启)
0111 + 0001 = 1000(进位标记关闭)
0000-0001 = 1111(带进位标记)
1000-0001 = 0111(进位标记关闭)


万一它不是很明显,它需要明确指出减法与两者的补码求反相同,因此后两个示例可以用加法重写为:


0000 + 1111 = 1111(带进位标记)
1000 + 1111 = 0111(进位标记关闭)


…但请注意,减法的进位与加法设置的进位相反。



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

有趣的是,肯·希尔里夫(Ken Shirriff)的reverse-engineering of the 8085 processor表明它确实有一个溢出标志-只是没有记载。这是8位标志状态寄存器的位1。它被称为“ V”,并且按照上述完全相同的方式通过将进位与最高有效位C6 ^ C7的进位进行异或,将进位与最高有效位C6 ^ C7异或来实现。值直接来自ALU。 (他在同一篇文章中还描述了如何用“ V”标志和正负号标志实现另一个未记录的正负号“ K”标志,产生了一个在正负比较中有用的标志,但超出了此答案的范围。)

关于math - 没有溢出标志的处理器如何执行带符号算术?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45261231/

相关文章:

c++ - 将 asm 指令编码为操作码

loops - 如果我在循环中使用 ECX(汇编),正确的循环方法是什么

c++ - 使用 reinterpret_cast 的签名别名

python - 我怎样才能让我的程序打印 float ?

php - 区分数学用户输入和其他所有输入

math - 以数学方式从UNIX时间戳计算天数?

assembly - 需要 AT&T 汇编语法的良好来源

javascript - 快速安全地删除 JavaScript 中有符号数字符号的方法

vhdl - 二进制定点乘法

java - BigInteger 的 N 次方根