了解溢出标志和进位标志之间的区别

5

我正在基于现有的RISC ISA在verilog中设计一个16位ALU。ISA规定,当操作是无符号数时,进位标志被设置,当操作是带符号数时溢出标志被设置。有趣的是,ISA实现了ADDSUB指令,可以对有符号和无符号数字进行操作。由于有符号和无符号只是一种解释方式,我的初步想法是像下面这样做。这个想法是溢出和进位只是一种解释方式,所以可以为两者使用相同的函数。


module ALU();
    input wire [15:0]x;
    input wire [15:0]y;
    input wire [8:0]opcode;
    output reg [15:0] result;
    output reg CFlag; // Carry
    output reg FFlag;  // Overflow

    if(opcode == ADD) begin
        result = x + y;
        // x and y have the same sign, result has a different sign.
        CFlag = FFlag = (x[15] ~^ y[15]) & res[15] ^ x[15];
    end
endmodule

但是对于这种边缘情况呢(以4位为例)?

x = -1
y = 1

1111 + 0001 = 0000

在这种情况下,使用2s补码表示的答案是正确的,并且不需要设置标志位。但在无符号解释中,答案是错误的,应该设置进位标志位。我一直理解进位和溢出是相同的,只是不同的解释,但现在我不确定了。一个现代ALU如何处理这种边缘情况?

1个回答

27

进位和溢出并不是完全相同的概念。

进位指的是当作为无符号数解释时结果在数学上不正确,而溢出指的是当作为有符号数解释时结果在数学上不正确。以你的四位ALU为例:

  • 1111 + 0001 = 0000应设置进位(15 + 1 = 0 不成立),清除溢出(-1 + 1 = 0 成立)。

  • 0111 + 0010 = 1001应清除进位(7 + 2 = 9 成立),设置溢出(7 + 2 = -7 不成立)。

  • 1001 + 1001 = 0010应设置进位和溢出(9 + 9 = 2 和 -7 + -7 = 2 都不成立)。


3
http://teaching.idallen.com/dat2343/10f/notes/040_overflow.txt有很好的示例和解释,说明了ALU可以计算的不同方式。但它没有提到减法/借位。 - Peter Cordes
他们两个只是检查最左边位中是否有1(该位未在内存中呈现),这正确吗?唯一的区别是它们处理的数字类型吗? - CrazyMan
1
@CrazyMan:最左边的位是进位位;也就是说,如果在更宽的ALU中使用零扩展操作数进行加法运算,结果的第4位(从0开始计数)将是什么。因此,上面的第一个和第二个示例表明,这与溢出标志不同。溢出标志不仅仅是结果的函数(即使它被扩展了);它还取决于产生它的输入。如果010010111 + 0100的结果,则应设置溢出标志,但如果它是1000 + 0001的结果,则应清除它。 - Nate Eldredge
@NateEldredge 谢谢,我现在对它有了更好的理解。您能否请解释一下,处理器如何确定在仅添加两个数字时是否应设置溢出标志?数字类型的信息是否也存储在某个地方? - CrazyMan
5
@CrazyMan说:不,这正是重点所在;机器并不知道输入数字的“类型”,它们只是位。因此,溢出标志将始终根据是否存在溢出(如果将输入解释为有符号数)而设置。形式上,它始终等于进入第3位的进位和进入第4位的进位的异或运算结果(后者通常是进位标志)。 - Nate Eldredge
3
@CrazyMan:所以,如果你打算进行纯无符号算术运算,并且认为0111 + 0010 = 1001等于7+9,那么溢出标志位仍然会被设置,你只需要忽略它。同样地,如果你打算进行有符号算术运算,你应该检查溢出标志位并忽略进位标志位。 - Nate Eldredge

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接