parameter
in
Verilog ModulesIn this assignment, you will complete a design that adds four 4-bit numbers in an adder tree configuration:
sum = (a+b) + (c+d)
To compute this sum, we need three additions. Each
addition is performed by a module named simple_adder
.
Open the file simple_adder.v
and examine it line-by-line. In the module declaration, a
parameter is declared:
module simple_adder
( // Use #( ) to declare parameters before I/O signals
#parameter W=2 // `parameter` keyword, name `W`, default value 2
)
The parameter W
sets the
bit-width of the inputs. The default width is set at 2; we will need to
override the default value when instantiating the
design.
A parameter is fundamentally different from a signal or variable. In essence, the parameter allows us to modify the module design on a per-instance basis. To see why we need parameters in this design, consider the bit-width of a sum:
a
has 4 bitsb
has 4 bitsa+b
has 5 bitsWe have to allow an extra bit for the carry overflow. For instance,
if a=12
and b=7
,
then the sum is a+b=19
,
which has binary value 11001
. So we
need 5 bits for the sum (a+b)
.
Similarly, we need 5 bits for the sum (c+d)
.
For the next addition, we need to change W
to 5 bits in order
to add (a+b)
with (c+d)
,
and the final sum
output has
6 bits. To accomodate the changing bit- width, we could
design separate 4-bit and 5-bit adder modules, but it is much more
efficient to create a single parameterized module.
In the file src/top.v
,
notice how the modules are instantiated:
(.W(4)) SA1
simple_adder #(
(clk),
.clk(a),
.a(b),
.b(a_plus_b)
.sum);
The W
parameter for instance
SA1 is specified by the syntax #(.W(4))
.
Without this specification, W
would default to 2. Using this syntax, we can customize the bit-width
for every single instance of simple_adder
.
top
designOpen the file src/top.v
and
examine the instance definitions for SA1
and SA2
. Notice the syntax for overriding
the W
parameter. Then complete
the instance definition for SA3
.
Next, open the file src/testbench.v
and note how it has been changed from the previous assignments. We have
four 4-bit reg
signals:
reg [3:0] a; // by the testbench
reg [3:0] b;
reg [3:0] c;
reg [3:0] d;
To test all combinations of these inputs, we would
need to run 2^16 test patterns, which amounts to 65,536 unique cases. In
our previous testbench, we coded each test case individually – you
probably don’t want to individually code over 65k else if
cases. Also, we probably don’t need to verify every single case
exhaustively. An alternative method is random pattern
testing, which is employed in the new testbench:
// CREATE STIMULI:
always @(posedge clk) begin
<= $random();
a <= $random();
b <= $random();
c <= $random();
d end
Here the $random()
function is used to generate test cases. This is a very useful and
common strategy for verifying complex prototypes. Be warned, however,
that $random is not a synthesizable function. You can
use it in testbenches but not in physical designs.
Also notice that both $write
and
$fwrite
lines are used, so the test results will be printed to the console and
also written to a text file.
Run make
to simulate your
design. The first few output lines should look like this:
clk: 0 a: 0(0000) b: 0(0000) c: 0(0000) d: 0(0000) sum: x(xxxxxx)
clk: 1 a: 4(0100) b: 1(0001) c: 9(1001) d: 3(0011) sum: x(xxxxxx)
clk: 2 a: 13(1101) b: 13(1101) c: 5(0101) d: 2(0010) sum: 0(000000)
clk: 3 a: 1(0001) b: 13(1101) c: 6(0110) d: 13(1101) sum: 17(010001)
clk: 4 a: 13(1101) b: 12(1100) c: 9(1001) d: 6(0110) sum: 33(100001)
Notice the two-cycle delay. Initially, the sum
output is undefined, so it shows
as x
. After two cycles, the
initially zero a,b,c,d
values propagate to the sum
output, which is zero (as expected). In cycle 3, we see the sum of a,b,c,d
values from cycle 1: 4 + 1 + 9 + 3 = 17
,
and so on.
Open the file simple_adder.xdc
and observe that the
a
, b
, c
, and d
inputs are mapped to the sliding
switches in groups of 4. The sum
output is mapped to the lower 6 LEDs.
Next, open the file build.tcl
and notice differences compared to the previous assignments. The read_xdc
command now points to simple_adder.xdc
, and the synth_design
command now declares
top
as the top-module name:
-top top -part xc7a35tcpg236-1 synth_design
The bitstream is also renamed to simple_adder.bit
:
-force simple_adder.bit write_bitstream
Type make implement
to run
the implementation. After it completes, open the timing and utilization
report files. Verify that the WNS is positive, and take note of the
value. In the utilization file, note that the adder logic is implemented
entirely with slice LUTs, no DSP modules are used.
Now use the Vivado Hardware Manager to program your design onto the
Basys3 board. Test the three cases listed below, and take photos of each
case. Place the photos in the same directory as the bitstream, and name
them case1.jpg
, case2.jpg
, and case3.jpg
(a different image type,
like .png, is acceptable).
Cases to test:
To turn in your work, run these commands:
git add test_result.txt post_synth.v *.rpt
git add case*
git add *.bit
git commit . -m "Completed"
git push origin main
Then indicate on Canvas that your work is done.