Signed Arithmetic

Signed Integers in Verilog

A bit vector can be declared signed in Verilog, so it is interpreted as an integer in 2’s Complement Format. The table below shows all 3-bit binary vectors and the corresponding 2’s complement interpretation:

Binary (2’s Comp) Decimal Binary (2’s Comp) Decimal
000 0 111 -1
001 1 110 -2
010 2 101 -3
011 3 100 NA

The value 100 is Not Allowed (NA).

The syntax for declaring a signed 3-bit integer a is:

   reg signed  [2:0]  a;

In 2’s Complement, a negative number -N is obtained from a positive number N by two steps:

  1. Flip all bits of N
  2. Add 1 to ~N using normal addition, discarding the final carry

In Verilog syntax, these steps are expressed as ~N+1 or just -N.

Exercise: 4-bit 2’s Comp Negation Table

Complete the negative values in the table below.

Pos Dec Pos Bin N Inv Bin ~N Neg Bin Neg Dec
0 0000 1111 0000 -0
+1 0001 1110 1111 -1
+2 0010 1101 1110 -2
+3 0011 -3
+4 0100 -4
+5 0101 -5
+6 0110 -6
+7 0111 -7

Exercise: 3-bit 2’s Comp Addition Table

Complete the binary addition table below. For each entry, write the binary result and, in parentheses, the decimal interpretation. Do the addition using binary arithmetic, and indicate overflow cases with an exclamation point (!).

101 (-3) 110 (-2) 111 (-1) 000 (0) 001 (1) 010 (2) 011 (3)
101 (-3) 010 (2)!
110 (-2) 011 (3)!
111 (-1) 100 (NA)!
000 (0) 101 (-3)
001 (1) 110 (-2)
010 (2) 111 (-1)
011 (3) 000 (1)

Exercise: 2’s Comp Overflow

Study the results from the 3-bit addition table. Is there an efficient way to detect overflow cases? Give a precise logic solution that detects all overflow events.

Sign Extension

Sometimes we need to do operations on vectors of different bit width. Consider the snippet:

reg [2:0] a;
reg [3:0] b;

always @(a) begin
   b = a;
end

This case is implemented in src/testbench.v. Open the file and study its contents. Run make to perform the simulation. In the output, notice that a is copied into b as a positive number. For example, a=101 yields b=0101.

But what if a is a signed value? In that case a=101 corresponds to a decimal value of -3. Try modifying the declaration of a:

reg signed [2:0] a;
reg        [3:0] b;

always @(a) begin
   b = a;
end

With this change, when a=101 (-3), b is sign extended to be the same width as ‘b’, resulting in 1101 (-3). This creates a bug potential since b is not signed, so its value will be interpreted as +13.

Consider this modification:

reg signed [2:0] a;
reg        [3:0] b;
reg        [4:0] c;

always @(a) begin
   b = a;
   c = b;
end

In this chain of assignments, when a=101, it is sign-extended so that b=1101, but since b is unsigned it is zero extended to 01101, resulting in c=01101 (+13).

To avoid this bug, the best practice is to declare all vectors as signed if they could receive signed assignments.

Exercise: signed assignments

Modify src/testbench.v by adding the signed keyword to vectors b and c. Repeat the simulation and verify that the assignments are correctly sign-extended.

Assigned Tasks

Modify your up/down counter so that it uses signed operations. Copy your module and testbench code into src. Also copy your build.tcl and XDC files into your working directory. Add them to your repository using git add. Edit them to support signed operation and detect signed overflow.

Your testbench should cover all overflow cases and log results in test_results.txt. Verify your signed counter in simulation, then implement it on the Basys3 board and demonstrate the following cases:

  1. a=53, b=13, press rst then up until q stops changing
  2. a=-17, b=37, press rst then dn until q stops changing
  3. a=29, b=-17, press rst then up until q stops changing
  4. a=-47, b=-43, press rst then dn until q stops changing

Photograph the results and save the photos as case1, case2, etc with an appropriate graphics extension. Then turn in your results using git:

git add *.txt *.bit *.rpt src/*.v *.xdc *.tcl case*
git commit . -m "Complete"
git push origin main

Indicate on Canvas that your work is done.