当前位置: 首页 > 知识库问答 >
问题:

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

顾正初
2023-03-14

我知道,两个大于给定处理器总线大小的无符号整数的相加可以通过进位标志实现。通常,使用溢出标志的有符号整数也是如此。然而,Intel 8085只具有符号标志,而不具有溢出标志,因此它如何处理有符号整数算术?

共有1个答案

夏景胜
2023-03-14

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

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

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

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

举几个例子:

  • 0100 0001=0101(溢出标志关闭)

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

(显然,这一切都假设了两个补运算。)

因此,即使处理器的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;
}

当然,你可以用很多不同的方式来写这篇文章。)

或者,用Iwilnotexist Idonot存在在评论中所说的话来说:“溢出可以定义为符号位进位和出位的异或。”如果进位不等于该特定(最左边)位的进位,就会发生溢出。

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

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

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

>

  • 如果最高有效位(符号位)有进位,则在加法过程中设置进位标志。

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

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

    • 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在这里解释的那样,它完全按照上面讨论的方式实现,通过将进位与最高有效位C-6的进位异或,这些值直接来自ALU。(他还在同一篇文章中描述了另一个未记录的标志“K”标志是如何根据“V”标志和符号标志实现的,从而产生了一个在符号比较中有用的标志,但有点超出了本答案的范围。)

  •  类似资料:
    • 整个旗帜的事情让我很困惑。网络上的定义看起来很简单。对于这一切,我似乎找不到一个真正合适的解释。 根据它们的定义,-进位:表示无符号整数溢出-溢出:表示有符号整数溢出-零:由零产生的运算-符号:由负数产生的运算 那么下面的句子到底是怎么回事以下说明将设置符号标志:(这里的答案是252不是负数。那么为什么设置符号标志?) > 在8位寄存器中添加7Fh和05h设置溢出标志。(这里的答案是132。它不高

    • 技巧 有时编译程序会遇到如下类似的错误, In file included from foo.c:15, from a.h:45, b.h:53: error: ... ... 如果错误是由于你所定义的一个很复杂的宏所引起的,你可能会需要先手动编译生成相应的预处理文件,查看下预处理文件中的宏扩展代码。比如,先运行 gcc -E foo.c -o foo.i 来生成foo.i预处理文件。然后,还

    • 我在看的书:CS-app 2。c有无符号和有符号的int类型,并且在大多数架构中使用二进制补码算法来实现有符号值;但是学了一些汇编代码之后,发现很少有指令区分无符号和有符号。所以我的问题是: > 区分有符号和无符号是编译器的责任吗?如果是,它是如何做到的? 谁实现两个补码算法——CPU还是编译器? 添加更多信息: 在学习了更多的指令后,实际上有一些指令区分有符号和无符号,例如setg、seta等。

    • 基于比较有符号整数的跳转使用零、符号和溢出标志来确定操作数之间的关系。在具有两个有符号操作数的CMP之后,有三种可能的情况: -目标=来源 -目的地 我很难理解场景2和场景3。我已经研究了可能的组合,并看到它们确实有效——但我仍然不明白它们为什么有效。 有人能解释为什么比较符号和溢出标志反映符号整数关系吗? 编辑: 似乎对我的要求有一些理解。基于签名比较的跳转使用零、符号和进位标志——这些包括、等

    • 我想处理面板标题项的溢出。当按钮数超过屏幕宽度时,折叠图标和按钮不可见。我想使标题可以滚动,或者在下拉菜单中显示溢出项。

    • 我们有一个用C#/WPF/Prism构建的相当大的应用程序。应用程序有几个静态模块和未知数量的动态加载模块。 我的影响范围是静态模块和shell。 我被要求实现一个将重启shell的特性,但只有在查询所有当前打开的模块是否允许重启之后。如果至少有一个模块表示不允许(例如:仍然未保存的更改),则重新启动将被推迟。 现在shell和模块通过进行通信。这意味着我可以发布一个事件,然后查看是否有任何订阅服