Unsigned Arithmetic

Unsigned Arithmetic in Verilog

Verilog supports several synthesizable arithmetic operations, most importantly addition (a+b) and multiplication (a*b). By default, a vector is handled as an unsigned integer. So for a three-bit vector, the equivalent decimal values are

Binary Decimal Binary Decimal
000 0 100 4
001 1 101 5
010 2 110 6
011 3 111 7

Now consider a simple adder module:

module simple_adder
  (
    input  [2:0] a,
    input  [2:0] b,
    output [2:0] q
  );

  always @(a,b) begin
     q = a + b;
  end

endmodule

This module uses a blocking assignment to implement a combinational (non- clocked) sum. The inputs and output are all 3-bit values. For this module, the operation table is

+ 0 1 2 3 4 5 6 7
0 0 1 2 3 4 5 6 7
1 1 2 3 4 5 6 7 0
2 2 3 4 5 6 7 0 1
3 3 4 5 6 7 0 1 2
4 4 5 6 7 0 1 2 3
5 5 6 7 0 1 2 3 4
6 6 7 0 1 2 3 4 5
7 7 0 1 2 3 4 5 6

Note that whenever the sum is “too big”, the numbers “roll over” to zero. So 7+1=0, and so on. This is called an overflow. In some algorithms, overflow is useful. In others, it’s a bug. Sometimes it creates a hazard for safety or security.

A similar thing happens with subtraction. The operation table below shows a-b, with the rows indicating a and the columns as b:

- 0 1 2 3 4 5 6 7
0 0 7 6 5 4 3 2 1
1 1 0 7 6 5 4 3 2
2 2 1 0 7 6 5 4 3
3 3 2 1 0 7 6 5 4
4 4 3 2 1 0 7 6 5
5 5 4 3 2 1 0 7 6
6 6 5 4 3 2 1 0 7
7 7 6 5 4 3 2 1 0

Simple Overflow Application

As a simple useful application, recall the testbench from our first assignment, where if/then statements were used to cycle through all cases of {en,d}. We later simplified the statements to two assignments, en <= d; d <= ~en;. This could be made even simpler by using an addition statement:

   {en,d} <= {en,d}+1;

At each clock cycle, the 2-bit value increments by 1, so the pattern is

  00
  01
  10
  11

When 11 is incremented, it overflows and rolls back to zero.

Avoiding Overflow

To avoid overflow problems, there are two approaches:

These options are fairly straightforward when dealing with addition or subtraction: you either increase the output width by 1 bit, or capture the last carry-out as an overflow indicator. For multiplication it is more subtle. Consider multiplying two 3-bit numbers. The largest product is 7x7=49=6’b100001, a six-bit number. To multiply two 4-bit numbers, the largest product is 15x15=225=8’b11100001, an eight-bit number.

As the input width grows, generally the output width needs to be the sum of the input widths. This is a problem for algorithms that perform repeated multiplications, since the bit-width must grow geometrically with each operation.

A common computing scenario uses the same bit-width for all integers, let’s say 8 bits. Given two 8-bit inputs, a multiplier produces an 8-bit output. How can the multiplier detect overflow? See if you can come up with a solution (Hint: consider the most significant non-zero digit in each of the inputs).

Assigned Tasks

Create an Up/Down Counter

Make a module called up_down_counter with behavior specified as follows:

The logic should look something like this:

  always @(posedge clk) begin
     if (rst)
        q <= a;
     else begin
        if (up)
           q <= q + b;
        else if (dn)
           q <= q - b;
     end
  end

The logic above seems simple enough, but you need to modify this logic so that it detects overflow. If an overflow would occur, then q should not be changed.

Verify the Counter in Simulation

Edit the testbench to test overflow cases, and verify that your module never overflows on up or dn events. You will need to choose appropriate test patterns and an algorithm to generate them.

Implement and Program

Once your module is verified, implement it with these port mappings:

Also don’t forget the clock. You will need to make appropriate edits in build.tcl and unsigned_arithmetic.xdc.

Once built, program the board and verify its function. In particular, test these cases and photograph them:

  1. a=128, b=65, press rst then up until q stops changing
  2. a=17, b=3, press rst then dn until q stops changing

Save the images as case1 and case2 in your working directory, then submit your work using git:

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

Then indicate on Canvas that your work is submitted.