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
endmoduleThis 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 |
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.
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).
Make a module called up_down_counter with behavior
specified as follows:
clk inputa sets the initial
valueb sets the “step” valueup causes the counter to
increment by bdn causes the counter to
decrement by brst forces the count to
equal aqThe 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
endThe 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.
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.
Once your module is verified, implement it with these port mappings:
a: switches 0 through 7b: switches 8 through
15up: button Udn: button Drst: button Lq: LEDs 0 through 7Also 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:
a=128,
b=65,
press rst then up until q stops changinga=17,
b=3,
press rst then dn until q stops changingSave 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 mainThen indicate on Canvas that your work is submitted.