“Did it overflow?” has a different answer for each interpretation of the same bits.
Interpretation | Overflow means… | Flag | How to detect (add) |
|---|---|---|---|
Unsigned | The true sum is larger than 2ᴺ − 1 | C (carry) | The carry out of the top bit: |
Signed | The true sum is outside −2ᴺ⁻¹…2ᴺ⁻¹−1 | V (overflow) | Operands have the same sign but the result sign differs. |
The two flags are independent. 7 + 1 in 4 bits is 0111 + 0001 = 1000: no carry out, but signed overflow (+8 exceeds −8…7).
15 + 1 is the opposite: carry out, but as signed it is −1 + 1 = 0 with no overflow.
Read each addition right to left as on paper; the small grey digits are the carries into each column.
C looks at one cell: the boxed fifth bit of the sum. It is 0 for 7 + 1 and 1 for 15 + 1.
V looks at one column: the dashed sign column. In 7 + 1 both operands have sign 0 and the result has sign 1, so V = 1.
In 15 + 1 the operand signs differ (1 and 0), so V cannot be 1 whatever the result.
Flag | Name | Meaning | Formula |
|---|---|---|---|
N | Negative | Result's top bit |
|
Z | Zero | Result is all zeros |
|
C | Carry | Unsigned overflow on add |
|
V | Overflow | Signed overflow on add |
|
Adding two numbers of opposite sign can never overflow. The result lies between them.
Overflow is possible only when both operands share a sign and the true result is too large. Then the wrapped result has the opposite sign.
For a − b, form a + ~b + 1. Signed overflow occurs when the operands have different signs and the result sign differs from a.
The formula is V = (a[N-1] != b[N-1]) && (res[N-1] != a[N-1]). The carry flag for subtraction is the inverted borrow.
Here C means no unsigned borrow, computed by a five-bit addition of zero-extended a, the four-bit complement of b and 1. Complement b within four bits before widening; complementing a five-bit zero-extended operand changes the carry interpretation.
Operation / interpretation | Four-bit a + ~b + 1 | Stored result | C = no borrow | V |
|---|---|---|---|---|
3 - 5 | 0011 + 1010 + 0001 = 0_1110 | 1110 = signed -2 | 0: unsigned borrow | 0 |
5 - 3 | 0101 + 1100 + 0001 = 1_0010 | 0010 = 2 | 1: no unsigned borrow | 0 |
7 - (-1) | 0111 + 0000 + 0001 = 0_1000 | 1000 = signed -8, not mathematical +8 | 0: unsigned 7 - 15 borrows | 1: signed overflow |
The same operand bits mean unsigned 7 and 15, so unsigned subtraction borrows. As signed they mean +7 and -1, whose difference +8 exceeds the four-bit maximum +7. C and V describe different interpretations.
module tb_subtract_flags;
logic [3:0] a, b, inv_b, res;
logic [4:0] wide;
logic c, v;
int difference, sa, sb, errors = 0;
initial begin
for (int i = 0; i < 256; i++) begin
{a, b} = i[7:0];
inv_b = ~b;
wide = {1'b0, a} + {1'b0, inv_b} + 5'd1;
res = wide[3:0]; c = wide[4];
v = (a[3] != b[3]) && (res[3] != a[3]);
difference = int'(a) - int'(b);
sa = int'($signed(a)); sb = int'($signed(b));
if (res !== difference[3:0] || c !== (int'(a) >= int'(b)) ||
v !== ((sa - sb < -8) || (sa - sb > 7))) errors++;
end
if (errors != 0) $fatal(1, "FAIL: subtraction flag errors=%0d", errors);
$display("PASS: subtraction result, no-borrow and signed overflow over 256 binary pairs");
$finish;
end
endmodulemodule add_flags #(parameter int N = 4) (
input logic [N-1:0] a, b,
output logic [N-1:0] res,
output logic c, v, n, z
);
logic [N:0] sum;
always_comb begin
sum = {1'b0, a} + {1'b0, b};
res = sum[N-1:0];
c = sum[N];
v = (a[N-1] == b[N-1]) && (res[N-1] != a[N-1]);
n = res[N-1];
z = (res == '0);
end
endmodule
module tb_flags;
logic [3:0] a, b, res;
logic c, v, n, z;
add_flags #(4) dut (.*);
int ua, ub, sa, sb, errors = 0;
initial begin
for (int i = 0; i < 256; i++) begin
{a, b} = i[7:0]; #1;
ua = a; ub = b; sa = $signed(a); sb = $signed(b);
if (c !== ((ua + ub) > 15)) errors++;
if (v !== (((sa + sb) > 7) || ((sa + sb) < -8))) errors++;
if (z !== (res == 0)) errors++;
if (n !== res[3]) errors++;
end
if (errors == 0) $display("PASS: C, V, N, Z correct for all 256 input pairs");
$finish;
end
endmoduleThe testbench checks the flags against ordinary integer arithmetic on all 256 input pairs. Exhaustive testing is cheap at this width.
100 + 100 is computed. What are C and V?100 + 100 = 200. As unsigned, 200 fits in 8 bits (≤255), so C = 0. As signed, 200 exceeds 127, so the result wraps to −56: operands both positive, result negative, so V = 1.
The true sum lies between the two operands, and both operands are already representable, so the sum is too.