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
= a + b;
q 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 |
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 b
dn
causes the counter to
decrement by b
rst
forces the count to
equal a
q
The logic should look something like this:
always @(posedge clk) begin
if (rst)
<= a;
q else begin
if (up)
<= q + b;
q else if (dn)
<= q - b;
q 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.
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 main
Then indicate on Canvas that your work is submitted.