I am designing a 16 bit ALU in verilog based on an existing RISC ISA. The ISA says that the carry flag is set when the operation is unsigned, and overflow is set when the operation is signed. The interesting thing is that the ISA implements ADD
and SUB
instructions that operate on both signed and unsigned numbers. Since signed vs unsigned is simply a matter of interpretation, my initial idea was to do something like below. The idea being that overflow vs carry is only a matter of interpretation, so use the same function for both.
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
But what about this edge case (shown in 4 bits)?
x = -1
y = 1
1111 + 0001 = 0000
In this case the answer is correct in 2s compliment and no flag needs to be set. But the answer is incorrect in unsigned interpretation and the carry flag should be set. I always understood carry and overflow to be the same, just different interpretation, but now I'm not sure. How would a modern ALU handle this edge case?
Carry and overflow are not the same at all.
Carry indicates the result isn't mathematically correct when interpreted as unsigned, overflow indicates the result isn't mathematically correct when interpreted as signed. So as examples for your 4-bit ALU:
1111 + 0001 = 0000
should set carry (15 + 1 = 0 is false) and clear overflow (-1 + 1 = 0 is true).0111 + 0010 = 1001
should clear carry (7 + 2 = 9 is true) and set overflow (7 + 2 = -7 is false).1001 + 1001 = 0010
should set both (9 + 9 = 2 and -7 + -7 = 2 are both false).