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

ric*_*i90 6 verilog cpu-architecture alu carryflag signed-overflow

我正在基于现有的 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
Run Code Online (Sandbox Code Playgroud)

但是这种边缘情况(以 4 位显示)又如何呢?

x = -1
y = 1

1111 + 0001 = 0000
Run Code Online (Sandbox Code Playgroud)

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

Nat*_*dge 30

进位和溢出根本不一样。

进位表示当解释为无符号时结果在数学上不正确,溢出表示当解释为有符号时结果在数学上不正确。作为 4 位 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 均为 false)。

  • @CrazyMan:不,这就是重点;机器不知道输入数字的“类型”,它们只是位。因此,如果输入被解释为有符号*,则溢出标志将*始终*根据是否存在溢出来设置。形式上,它始终等于位 3 中的进位和位 4 中的进位(后者是通常的进位标志)的异或。 (5认同)
  • http://teaching.idallen.com/dat2343/10f/notes/040_overflow.txt 有一些很好的示例,并解释了 ALU 计算它的不同方式。但它没有提到减法/借位。 (4认同)
  • @CrazyMan:因此,如果您打算进行纯粹的无符号算术,并且您将“0111 + 0010 = 1001”视为7+9,则溢出标志无论如何都会被设置,您只需忽略它即可。同样,如果您打算进行有符号算术,您将检查溢出标志并忽略进位标志。 (3认同)