4.4 Overflow and the adder/subtractor
Why this matters
An adder always gives an answer of the right width, and sometimes the answer is not the number you wanted. A result that does not fit is called overflow, and a program that ignores it computes wrong values with no sign of trouble. There are two different ways for a result to not fit, one for each reading of the bits, and mixing them up is the most common arithmetic mistake in hardware. This section separates them, builds the circuit that reports both, and uses it to repair the guessing-game comparator that called −4 bigger than its secret.
Learning goals
Section titled “Learning goals”- Define unsigned overflow and signed overflow, and decide each from the readings of the operands.
- Show with four examples that carry and overflow are independent.
- Find signed overflow from the carry into the top bit and the carry out of it.
- Build an adder and subtractor with
subas an input, a parameterized width and both flags. - State exactly when the top bit of a difference gives a wrong comparison, and write a comparison that is right for signed and for unsigned numbers.
Intuition first
Section titled “Intuition first”An adder is a counter that wraps around: add to the top of its range and it returns to the bottom. That wrap is one alarm. The carry out says that the result went past the top of the unsigned range, from the largest pattern back to 0, and the carry fires on exactly the additions where an unsigned result is wrong.
A signed reading has a different seam. The signed numbers on the wheel of Section 4.3 break between the largest positive value and the most negative one, and a signed result is wrong when the true result lies on the other side of that seam. The two seams are in different places, so an addition can cross one without the other, both, or neither. Both alarms are needed because the same bits mean different numbers under the two readings, and the hardware does not know which reading you meant.
Two kinds of overflow
Section titled “Two kinds of overflow”An operation on unsigned numbers has unsigned overflow when its true result is outside to , so that it does not fit in bits. For an addition that happens exactly when the carry out of the top column is 1. For a subtraction it happens when the second number is larger than the first, which needs a borrow out of the top column.
An operation on two's complement numbers has signed overflow when its true result is outside to . For an addition that can happen only when the two operands have the same sign bit and the result has the opposite sign bit. Two nonnegative operands can give a result that reads as negative, and two negative operands can give a result that reads as nonnegative, which includes zero: in 4 bits, would be , which does not fit, and the stored sum is 0000. Adding numbers of opposite signs can never overflow.
The four additions below use 4-bit operands, and each shows one combination of the two alarms. Every row of each table is a generated reading of the same bits.
Five plus three:
| 4-bit pattern | unsigned | signed | |
|---|---|---|---|
| A | 0101 | 5 | 5 |
| + B | 0011 | 3 | 3 |
| = | 1000 | 8 | -8 |
carry = 0overflow = 1
Read as unsigned numbers the result fits, so there is no carry. Read as signed numbers the true sum is 8, which is above the largest 4-bit value, 7, so the signed result overflows: it reads as −8. This is overflow without a carry.
Negative seven plus negative two:
| 4-bit pattern | unsigned | signed | |
|---|---|---|---|
| A | 1001 | 9 | -7 |
| + B | 1110 | 14 | -2 |
| = | 0111 | 7 | 7 |
carry = 1overflow = 1
Here both alarms ring. As unsigned numbers the sum is 9 plus 14, which is past 15, so the carry is 1. As signed numbers it is −7 plus −2, which is −9, below the smallest value, −8, and the result reads as the positive number 7.
Five plus two:
| 4-bit pattern | unsigned | signed | |
|---|---|---|---|
| A | 0101 | 5 | 5 |
| + B | 0010 | 2 | 2 |
| = | 0111 | 7 | 7 |
carry = 0overflow = 0
The result fits in both readings, so neither alarm rings.
Negative four plus four:
| 4-bit pattern | unsigned | signed | |
|---|---|---|---|
| A | 1100 | 12 | -4 |
| + B | 0100 | 4 | 4 |
| = | 0000 | 0 | 0 |
carry = 1overflow = 0
The signed result, 0, is right, so there is no overflow. The same bits as unsigned numbers are 12 plus 4, which is 16, past the top of the range, so the carry is 1. This is a carry without overflow.
So the carry says that an unsigned result is wrong, and the overflow flag says that a signed result is wrong, and either can occur without the other. A designer reads the flag that matches the reading in use. The next question is how a circuit can find each flag.
Finding signed overflow
Section titled “Finding signed overflow”Unsigned overflow is the carry out of the top column, which the adder already produces. Signed overflow has a short rule too.
For an addition, the signed overflow is the exclusive OR of the carry into the top column and the carry out of the top column.
Check it by cases on the signs of the operands, which are the top bits and of the two numbers. If both are 0, the top column adds 0, 0 and the carry in, so it never carries out; the exclusive OR is then just the carry in, and the carry in is 1 exactly when the result's top bit is 1, which is the "two nonnegatives give a negative" case. If both are 1, the top column adds 1, 1 and the carry in, so it always carries out; the exclusive OR is 1 exactly when the carry in is 0, which is when the result's top bit is 0: "two negatives give a nonnegative", and a result of zero counts. If the two top bits differ, the column adds 1 and the carry in and carries out exactly when the carry in is 1, so the two carries are equal, the exclusive OR is 0, and no overflow is reported, as it should be. A subtraction is an addition of with a carry in of 1, so the same rule serves it.
The adder/subtractor
Section titled “The adder/subtractor”Subtracting is adding the inverted second operand with a carry in of 1 (Section 4.3). An exclusive OR of each bit of with a control signal sub inverts when sub is 1 and leaves it alone when it is 0, and the same sub goes in as the carry in. So one adder does both.
Illustration a block diagram that explains an idea; its behavior is not checked
A block diagram with inputs sub, B and A and outputs out, carry_out and overflow.
Block "flip B" flip: sub is sub, B is B, Bx is n2.
Block "adder" add: cin is sub, Bx is n2, A is A, out is out, carry_out is carry_out, last_carry is n1.
XOR gate ovf: inputs carry_out and n1; output overflow.
This diagram is illustrative: its behavior is not checked.
Description: A block diagram. The input sub goes to a box labeled flip B and also, by a long wire along the top, to the cin input of a box labeled adder. The input B goes to the other input of the flip B box, whose output Bx goes to the adder. The input A goes to the adder. The adder has outputs out, carry_out and last_carry. The out output leaves the diagram. The carry_out output leaves the diagram and also goes to one input of an XOR gate, and last_carry goes to the other input of the gate. The gate gives overflow.
In SystemVerilog
Section titled “In SystemVerilog”// An N-bit adder and subtractor with two flags. With sub = 1 it computes A - B as A + ~B + 1.// N must be at least 2. carry_out is the carry out of the top bit of that addition, and overflow is signed overflow.module add_sub #(parameter N = 4) ( input logic [N-1:0] A, input logic [N-1:0] B, input logic sub, output logic [N-1:0] out, output logic carry_out, output logic overflow); logic [N-1:0] B_xor; // B, flipped when subtracting logic last_carry; // the carry into the top bit
always_comb begin B_xor = B ^ {N{sub}}; {last_carry, out[N-2:0]} = A[N-2:0] + B_xor[N-2:0] + (N-1)'(sub); {carry_out, out[N-1]} = A[N-1] + B_xor[N-1] + last_carry; overflow = carry_out ^ last_carry; endendmoduleThe low bits are added first. The left side {last_carry, out[N-2:0]} is bits wide, so the addition is carried out in bits and the carry out of bit , the carry into the top bit, is kept in last_carry. The top bit is added separately: A[N-1] + B_xor[N-1] + last_carry has the left side {carry_out, out[N-1]}, so the carry out of the top bit is kept in carry_out. The overflow rule is the last line. The width must be at least 2, so both parts exist.
The size cast (N-1)'(sub) makes the one-bit sub an bit number, with sub in its lowest bit and zeros above it. It does not change the width of the addition, which is set by the left side, {last_carry, out[N-2:0]}, and that is bits wide: without the cast, sub is extended with zeros to that width anyway, so the cast changes no bit of the result. It only states the widening where a reader and the tools can see it. Without it, one of the tools reports an addition of operands of different types, as Exercise 4.2.3 shows. The cast is the book's own addition: Lecture 4 shows the same module under the name addN, without that cast. (fact ch04/lecture-addn) You do not need to copy it.
// Four additions and four subtractions on four-bit values. The first four additions show every combination of carry and overflow.module add_sub_tb(); logic [3:0] A, B, out; logic sub, carry_out, overflow;
add_sub #(.N(4)) dut(.*);
initial begin sub = 0; A = 4'b0101; B = 4'b0011; #10; // expect: out=4'b1000, carry_out=0, overflow=1 sub = 0; A = 4'b1001; B = 4'b1110; #10; // expect: out=4'b0111, carry_out=1, overflow=1 sub = 0; A = 4'b0101; B = 4'b0010; #10; // expect: out=4'b0111, carry_out=0, overflow=0 sub = 0; A = 4'b1100; B = 4'b0100; #10; // expect: out=4'b0000, carry_out=1, overflow=0 sub = 1; A = 4'b0101; B = 4'b1101; #10; // expect: out=4'b1000, carry_out=0, overflow=1 sub = 1; A = 4'b1001; B = 4'b0010; #10; // expect: out=4'b0111, carry_out=1, overflow=1 sub = 1; A = 4'b0110; B = 4'b0010; #10; // expect: out=4'b0100, carry_out=1, overflow=0 sub = 1; A = 4'b0010; B = 4'b0110; #10; // expect: out=4'b1100, carry_out=0, overflow=0 $stop; endendmoduleThe first four lines of the testbench are the four additions above. The last four are subtractions. Here is the run.
Time in ps; one column is 10 ps.
Timing diagram from simulation, ch04/add-sub-trace: time in ps from 0 to 80, 8 columns of 10 ps.
sub: 0 at 0, then 1 at 40.
A (4 bits, bin): 0101 at 0, then 1001 at 10, 0101 at 20, 1100 at 30, 0101 at 40, 1001 at 50, 0110 at 60, 0010 at 70.
B (4 bits, bin): 0011 at 0, then 1110 at 10, 0010 at 20, 0100 at 30, 1101 at 40, 0010 at 50, 0110 at 70.
out (4 bits, bin): 1000 at 0, then 0111 at 10, 0000 at 30, 1000 at 40, 0111 at 50, 0100 at 60, 1100 at 70.
carry_out: 0 at 0, then 1 at 10, 0 at 20, 1 at 30, 0 at 40, 1 at 50, 0 at 70.
overflow: 1 at 0, then 0 at 20, 1 at 40, 0 at 60.
dut.last_carry: 1 at 0, then 0 at 10, 1 at 30, 0 at 50, 1 at 60, 0 at 70.
Description: A timing diagram of sub, A, B, out, carry_out, overflow and dut.last_carry over eight steps, with A, B and out in binary. The first four steps have sub low and the last four have sub high.
Read Figure 4.4.2 in the first step: A is 0101 and B is 0011, which gives 1000. last_carry is 1 and carry_out is 0, so overflow is their exclusive OR, 1. In the second step the carry into the top bit is 0 and the carry out is 1, and overflow is again 1. In the third step neither carry is set and overflow is 0. In the fourth step both carries are 1, so their exclusive OR is 0, although the carry out is 1: that is the carry without overflow. A separate program applied every combination of A, B and sub at width 4, 512 in all, and compared out, carry_out and overflow with whole-number arithmetic: the result modulo 16, whether the adder's unsigned sum (A + B, or A + ~B + 1 when subtracting) reached 16, and whether the signed result fell outside −8 to 7. All 512 agreed. In the seventh step, 6 − 2, carry_out is 1: no borrow was needed.
Carry out in a subtraction
Section titled “Carry out in a subtraction”For a subtraction the adder computes , and its carry_out has the opposite sense to what a borrow has. The two tables below show the same flag read both ways.
| 4-bit pattern | unsigned | signed | |
|---|---|---|---|
| A | 0110 | 6 | 6 |
| − B | 0010 | 2 | 2 |
| = | 0100 | 4 | 4 |
carry = 1borrow = 0overflow = 0
| 4-bit pattern | unsigned | signed | |
|---|---|---|---|
| A | 0010 | 2 | 2 |
| − B | 0110 | 6 | 6 |
| = | 1100 | 12 | -4 |
carry = 0borrow = 1overflow = 0
In the first the second number is smaller than the first, so no borrow is needed and the carry out is 1. In the second the second number is larger, a borrow is needed, and the carry out is 0. So for a subtraction, carry out 1 means no borrow, and a borrow is the inverse of carry_out. Lecture 4 calls overflow the x86-64 OF flag and carry_out the CF flag. (fact ch04/lecture-flags) The first is right. The second is right for addition. On x86, after a subtraction the CF flag is the borrow, which is the inverse of carry_out. (fact ch04/x86-borrow) ARM's C flag keeps the sense of carry_out after a subtraction, so a 1 means no borrow. (fact ch04/arm-carry) When you read a flag from a processor manual, check which of the two senses it uses.
Comparing with a subtraction
Section titled “Comparing with a subtraction”Sections 2.7 and 3.2 built a guessing game on this idea: to compare with , subtract and look at the top bit of the difference. With the secret 2 the game gets exactly two guesses wrong: it says that −4 and −3 are greater than 2. Section 3.2 debugs the game and tabulates the pairs where it goes wrong. Now the cause can be named. The top bit of an -bit difference is the sign of the true difference only when the true difference fits in bits. When it does not fit, which is signed overflow, the top bit is the wrong way round.
A testbench ran the top-bit rule on every pair of 4-bit values, 256 pairs.
// The first attempt at "A is less than B": subtract, then look at the top bit of the N-bit difference.module compare_msb #(parameter N = 4) ( input logic [N-1:0] A, input logic [N-1:0] B, output logic lt); logic [N-1:0] diff;
assign diff = A - B; assign lt = diff[N-1];endmodule// Tries the top-bit rule on every pair of 4-bit values and counts the pairs where it disagrees with the true answer,// once for signed numbers and once for unsigned numbers.module compare_msb_tb(); logic [3:0] A, B; logic lt;
compare_msb #(.N(4)) dut(.*);
int sa, sb; int wrong_signed, wrong_unsigned; int wrong_signed_without_overflow, overflow_but_right, far_rule_mismatch; logic overflow_true;
initial begin A = 4'b0011; B = 4'b0101; #10; // expect: lt=1 A = 4'b1000; B = 4'b0001; #10; // expect: lt=0 wrong_signed = 0; wrong_unsigned = 0; wrong_signed_without_overflow = 0; overflow_but_right = 0; far_rule_mismatch = 0; for (int i = 0; i < 256; i++) begin {A, B} = i[7:0]; #1; sa = A[3] ? int'(A) - 16 : int'(A); sb = B[3] ? int'(B) - 16 : int'(B); overflow_true = (sa - sb < -8) || (sa - sb > 7); if (lt != (sa < sb)) wrong_signed++; if (lt != (int'(A) < int'(B))) wrong_unsigned++; if (lt != (sa < sb) && !overflow_true) wrong_signed_without_overflow++; if (lt == (sa < sb) && overflow_true) overflow_but_right++; // unsigned: the rule is wrong exactly when A is at least 8 above B, or B is more than 8 above A if ((lt != (int'(A) < int'(B))) != ((int'(A) - int'(B) >= 8) || (int'(B) - int'(A) > 8))) far_rule_mismatch++; end $display("DD wrong_signed=%0d", wrong_signed); $display("DD wrong_unsigned=%0d", wrong_unsigned); $display("DD wrong_signed_without_overflow=%0d", wrong_signed_without_overflow); $display("DD overflow_but_right=%0d", overflow_but_right); $display("DD far_rule_mismatch=%0d", far_rule_mismatch); $stop; endendmoduleRead as signed numbers, the rule is wrong for 64 of the 256 pairs. Of those, the number that had no overflow is 0, and the number of pairs with overflow where the rule was right anyway is 0. So the rule fails for signed numbers when the subtraction overflows and at no other time.
Read as unsigned numbers, the same rule is wrong for 64 pairs, which is a different set. For 4 bits it fails when is at least 8 greater than , and when is more than 8 greater than ; the count of pairs where this description and the rule's failures disagree is 0. The signed and unsigned failures are different because the top bit of a difference means "negative" only for the signed reading, and the unsigned reading of is about a borrow.
Both comparisons have a correct form that uses the flags of the subtractor.
- Signed: is the exclusive OR of the top bit of the difference and the overflow flag. Overflow turns the wrong top bit round, and nothing else needs correcting.
- Unsigned: is a borrow, which is
carry_outequal to 0. - Equal: when every bit of the difference is 0. That is right for both readings: the -bit difference of two patterns is zero exactly when the patterns are the same.
// A comparator that is right for signed numbers and for unsigned numbers. It subtracts with add_sub.// Signed: A < B when the sign of the N-bit difference and the overflow flag differ. Unsigned: A < B when the subtraction needs a borrow, which is when carry_out is 0.module compare_n #(parameter N = 4) ( input logic [N-1:0] A, input logic [N-1:0] B, output logic lt_signed, output logic lt_unsigned, output logic eq); logic [N-1:0] diff; logic carry_out, overflow;
add_sub #(.N(N)) subtract(.A, .B, .sub(1'b1), .out(diff), .carry_out, .overflow);
assign lt_signed = diff[N-1] ^ overflow; assign lt_unsigned = ~carry_out; assign eq = ~|diff;endmoduleGreater than is the remaining case: when and are both false.
// The pairs that fooled the top-bit rule, and an equal pair, on the comparator that uses the overflow flag.module compare_n_tb(); logic [3:0] A, B; logic lt_signed, lt_unsigned, eq;
compare_n #(.N(4)) dut(.*);
initial begin A = 4'b1000; B = 4'b0001; #10; // expect: lt_signed=1, lt_unsigned=0, eq=0 A = 4'b0111; B = 4'b1000; #10; // expect: lt_signed=0, lt_unsigned=1, eq=0 A = 4'b0101; B = 4'b0101; #10; // expect: lt_signed=0, lt_unsigned=0, eq=1 $stop; endendmoduleThe first two lines are pairs on which the top-bit rule gives the wrong answer for signed numbers, and on both of them the signed and the unsigned answer differ. A program applied all 256 pairs and compared lt_signed, lt_unsigned and eq with the whole-number comparisons, and all 256 agreed. With N set to 3, the module is a repaired version of the first-attempt comparator compare3 of Section 2.7. This testbench puts the two side by side, old being the first attempt, and tries every 3-bit guess against the secret 2, the negative guesses first:
// The guesses that fooled the first guessing game, with the secret 2 and three-bit values, every guess in turn.// `old` is the first-attempt comparator of Section 2.7. `dut` is the repaired one.module compare_n_guess_tb(); logic [2:0] A, B; logic lt_signed, lt_unsigned, eq; logic old_lt, old_eq, old_gt;
compare_n #(.N(3)) dut(.*); compare3 old(.a(A), .b(B), .lt(old_lt), .eq(old_eq), .gt(old_gt));
initial begin B = 3'b010; A = 3'b100; #5; // expect: lt_signed=1, lt_unsigned=0, eq=0, old_lt=0, old_eq=0, old_gt=1 A = 3'b101; #5; // expect: lt_signed=1, lt_unsigned=0, eq=0, old_lt=0, old_eq=0, old_gt=1 A = 3'b110; #5; // expect: lt_signed=1, lt_unsigned=0, eq=0, old_lt=1, old_eq=0, old_gt=0 A = 3'b111; #5; // expect: lt_signed=1, lt_unsigned=0, eq=0, old_lt=1, old_eq=0, old_gt=0 A = 3'b000; #5; // expect: lt_signed=1, lt_unsigned=1, eq=0, old_lt=1, old_eq=0, old_gt=0 A = 3'b001; #5; // expect: lt_signed=1, lt_unsigned=1, eq=0, old_lt=1, old_eq=0, old_gt=0 A = 3'b010; #5; // expect: lt_signed=0, lt_unsigned=0, eq=1, old_lt=0, old_eq=1, old_gt=0 A = 3'b011; #5; // expect: lt_signed=0, lt_unsigned=0, eq=0, old_lt=0, old_eq=0, old_gt=1 $stop; endendmoduleThe first two lines are the guesses −4 and −3. The first attempt reports old_gt as 1 for both, which is wrong, and the repaired comparator gives lt_signed as 1: both are less than 2. The exact differences, −6 and −5, are below the 3-bit range −4 to 3, so the subtraction overflows and the top bit of the wrapped difference is the wrong way round. For −2 the difference is −4, which fits, so both comparators are right. In the remaining lines the first attempt is right too, so it is wrong on exactly those two of the eight guesses, and in all eight lines lt_signed and eq agree with the comparison of the numbers themselves.
Course conventions
Section titled “Course conventions”How CSE 369 writes this
The course names the flags overflow and carry_out and builds the subtractor from sub, as above. The book keeps both names and adds borrow where a table needs the other sense. For a subtraction, carry_out is 1 when no borrow is needed, and every figure in this chapter that shows a carry for a subtraction uses that sense.
Pitfalls
Section titled “Pitfalls”Common pitfall
- Using the carry out as the signed overflow, or the overflow flag as the unsigned one. Each flag belongs to one reading, and either can occur without the other.
- Reading
carry_outafter a subtraction as a borrow. It is the inverse: a carry out of 1 means no borrow was needed. - Looking for overflow when the operands of an addition have opposite signs. That sum always fits.
- Comparing by the top bit of a difference. It is wrong for signed numbers when the subtraction overflows, and wrong for unsigned numbers whenever the operands are far apart.
- Using the signed comparison on an unsigned value, or the reverse. The two answers differ whenever the top bits of the operands differ.
Check your understanding
Section titled “Check your understanding”Take the quiz (5 questions)
Adding 0101 and 0011 as 4-bit numbers, does the signed result overflow?
Adding 1100 and 0100 as 4-bit numbers, what is the carry out?
Subtracting 0110 from 0010 as 4-bit numbers, what is the carry out of the adder?
For how many of the 256 pairs of 4-bit signed numbers does the top-bit comparison give the wrong answer?
Which expression gives signed from a subtraction?
Exercises
Section titled “Exercises”Add 0111 and 0001 as 4-bit numbers. Give the carry out and the overflow flag, and say what each tells you.
Hint
Solution
| 4-bit pattern | unsigned | signed | |
|---|---|---|---|
| A | 0111 | 7 | 7 |
| + B | 0001 | 1 | 1 |
| = | 1000 | 8 | -8 |
carry = 0overflow = 1
The carry out is 0, so the unsigned result fits: the result row's unsigned value is right. The overflow flag is 1, so the signed result does not fit: it adds two positive numbers and reads as negative. The same bits are a correct unsigned sum and a wrong signed one.
Subtract 1000 from 0000 as 4-bit numbers. Give the result, carry_out and overflow, and say what the unsigned and signed readings of this subtraction are.
Hint
Solution
| 4-bit pattern | unsigned | signed | |
|---|---|---|---|
| A | 0000 | 0 | 0 |
| − B | 1000 | 8 | -8 |
| = | 1000 | 8 | -8 |
carry = 0borrow = 1overflow = 1
In the signed reading this is 0 minus −8, which is +8, and +8 does not fit in four bits, so the overflow flag is 1 and the result reads as −8. In the unsigned reading it is 0 minus 8, which is below zero, so a borrow is needed and the carry out is 0. Both readings have a wrong result here, and each is reported by its own flag.
Add 1001 and 1110 as 4-bit numbers by columns. Find the carry into the top column and the carry out of it, and check that their exclusive OR is the overflow flag.
Hint
Solution
Column 0 adds 1 and 0, column 1 adds 0 and 1, and column 2 adds 0 and 1, so each writes 1 and carries nothing. The carry into column 3, the top column, is 0. Column 3 adds 1, 1 and that carry of 0, which is two: it writes 0 and carries out 1. So the carry into the top column is 0 and the carry out is 1, and their exclusive OR is 1.
| 4-bit pattern | unsigned | signed | |
|---|---|---|---|
| A | 1001 | 9 | -7 |
| + B | 1110 | 14 | -2 |
| = | 0111 | 7 | 7 |
carry = 1overflow = 1
The overflow flag is 1, as the rule says. The carry out is 1 as well, because both alarms ring for this pair.
Explain why the sum of a non-negative number and a negative number can never overflow in two's complement.
Hint
Solution
Let be non-negative and be negative. Then , because adding the non-negative to cannot make it smaller and adding the negative to makes it smaller. Both and are inside the range of -bit signed numbers, and is between them, so it is inside the range too. A result in the range does not overflow. The same fact appears in the carries: when the two top bits differ, the top column carries out exactly when a carry arrives, so the carry into the top column and the carry out are always equal, and their exclusive OR is 0.
Write a module at_most with two 4-bit inputs A and B and two outputs, le_signed and le_unsigned, that say whether when both are read as signed numbers and as unsigned numbers. Use the comparator compare_n of this section.
Hint
Solution
The comparator already gives both orderings and equality. Each output is the matching ordering OR the equality:
// "A is at most B", once for signed numbers and once for unsigned numbers, built on the comparator compare_n.module at_most( input logic [3:0] A, input logic [3:0] B, output logic le_signed, output logic le_unsigned); logic lt_s, lt_u, eq;
compare_n #(.N(4)) cmp(.A, .B, .lt_signed(lt_s), .lt_unsigned(lt_u), .eq);
assign le_signed = lt_s | eq; assign le_unsigned = lt_u | eq;endmoduleThe module's testbench is a pair where the patterns 1000 and 0001 give different answers under the two readings, an equal pair, and the reverse pair.
// Three pairs: the patterns 1000 and 0001 (the signed and unsigned answers differ), an equal pair, and the same patterns the other way round.module at_most_tb(); logic [3:0] A, B; logic le_signed, le_unsigned;
at_most dut(.*);
initial begin A = 4'b1000; B = 4'b0001; #10; // expect: le_signed=1, le_unsigned=0 A = 4'b0110; B = 4'b0110; #10; // expect: le_signed=1, le_unsigned=1 A = 4'b0001; B = 4'b1000; #10; // expect: le_signed=0, le_unsigned=1 $stop; endendmoduleA program applied all 256 pairs and compared both outputs with the whole-number comparison, signed for one output and unsigned for the other, and they all agreed.