Lab2: Verilog Exploration
Time Estimate2-4 Hours Grade Impact2.5% DueSep 23 @ 3pm Required for Pass
Welcome to this course.
Objective
Get to know the Vivado user interface by practicing the design workflow for this course.
Additional Materials & Formats
Check Box for the most up-to-date versions of this lecture’s materials.
Warning
Before starting any lab, always read the entire lab description. You are working with expensive, fragile hardware. Look particularly closely at these boxes, which warn you of potential problems.
Before the Lab
Repository
Accept the invitation to this lab assignment’s Github repository on Canvas.
Equipment
Please bring the following equipment to this lab:
- Digilent Basys 3 FPGA board
- Compatible (power-and-data) USB cable
- Note taking mechanism (laptop, notebook, etc.)
Pre-Lab Work
This lab does not have pre-lab tasks. Future labs will require some work in advance.
Lab Setup
This lab provides brief instructions under the assumption that you have already done several of these steps successfully. Refer back to Lab1 for more detailed instructions.
- Clone the assignment repository:
git clone <url> <custom_name> - Start Vivado and create a new project with the following specification:
- Project name:
moreandgates - Project location: directory of this assignment’s repository
Create project subdirectoryshould be checked- Constraints: Select the
Basys3Master.xdcfile, which can be downloaded from Canvas - Choose the Basys3 board in board selection
- Don’t worry about inputs and outputs for now
- Project name:
Alternative Designs
The design and testbench from Lab1 are far from the only way to design this system. Throughout this course, you will design a variety of systems, and some systems call for different approaches. Let’s try some alternative designs for this system.
Let’s design an alternative implementation of an AND gate. Let’s design some behavioral descriptions of our AND gate as an alternative to the structural description we made before.
The previous version was called structural because we instantiated an and module, thus defining the structure of our circuit rather than defining explicit behaviors. In a behavioral description, we will define the behavior of the circuit ourselves.
Design 1: Continuous Assignment
Add a new design source to your project using the plus button in the Sources panel or by clicking Alt + A.
Make sure you choose to Add or create design sources. Name your source continuousand.v.
You can skip the screen that asks about inputs and outputs, since now you know how to quickly specify them in the model’s source code.
Design
The following Verilog code defines a circuit that continuously evaluates the function $F = A \land B$. In Verilog, continuous assignment is often extremely simple.
module continuousand (
output F,
input A,
input B
);
assign F = A & B;
endmoduleImplement your own continuous assignment AND gate.
Simulate
Now, it’s time to simulate your design. Let’s create a testbench for continuousand. Add a simulation source like we did in Lab1. Call this simulation source testbench_continuousand.v.
Using the following template, your task is to design a testbench that simulates every possible input/output combination of continuousand.
module testbench_continuousand (
);
reg in1, in2;
wire out;
// Something should go here
initial begin
in1 = 0; in2 = 0;
#10
in1 = 1; in2 = 0;
#10
in1 = 0; in2 = 1;
#10
in1 = 1; in2 = 1;
#10
$finish;
end
endmoduleSimulate your design, ensuring that the simulated behavior matches your expectations exactly.
Program
In case continuousand.v is not your top-level file in the Sources panel, right-click it and select Set as Top.
We now need to write the same constraints as we did in Lab1 that tell Vivado which of the board’s physical resources (e.g., buttons, switches, LEDs, etc.) should be associated with the signals A, B, and F from continuousand. Since A and B are both inputs, it is sensible to associate them with switches. Since F is an output, it is sensible to associate it with an LED.
In the Sources browser, double-click Basys3_Master.xdc to edit it. First locate the lines corresponding to our desired output: led[0] and un-comment the lines by deleting the # symbols. In both lines, replace get_ports led[0] with get_ports {F}. The resulting lines should appear as follows:
set_property PACKAGE_PIN U16 [get_ports {F}]
set_property IOSTANDARD LVCMOS33 [get_ports {F}]Now locate the lines corresponding to the inputs: sw[0] and sw[1]. Follow a similar process, un-commenting the lines and replacing the switch names with A and B. The resulting lines should appear as follows:
set_property PACKAGE_PIN V17 [get_ports {A}]
set_property IOSTANDARD LVCMOS33 [get_ports {A}]
set_property PACKAGE_PIN V16 [get_ports {B}]
set_property IOSTANDARD LVCMOS33 [get_ports {B}]These six lines should be the only active (un-commented) lines in your constraint file. Save your changes. Then go through the automated CAD steps that lead you to a programmable design, fixing errors as they arise.
- Click
Run Linterin theFlow Navigatorpanel. - Click
Run Synthesis. This process can be quite slow. - Click
Run Implementation. - Click
Generate Bitstream. - Click
Open Hardware Manager.
After verifying the jumpers, connect your Basys3 board to your computer using a USB cable, then turn on the board using its built-in power switch.
Back in Vivado’s Hardware Manager, click Open Target, then click Auto Connect. You should see a Xilinx device appear in the hardware list. If it does not, try the following debug steps:
- Ensure the board is connected and turned on. If the board is powered and turned on, the red power indicator light will be on.
- Ensure the jumpers are in the correct positions. If they are not, shame on you for failing to follow the above instructions. Power off the board, disconnect it, then fix the jumpers.
- Ensure your USB cable is functional for both power and data. An easy way to test this is by borrowing a classmate’s functional USB cable to test on your board.
Once your device appears in the list, click Program Device and select your device. It should be the only device listed. In the dialogue, click OK. A progress indicator will appear to show that the device is being programmed.
After programming, verify your design by manipulating sw0 and sw1, found on the lower-right of the board. When both switches are in the on position, the right-most LED led0 should light up. If this does not happen, work with your classmates and instructor to debug your design.
Deliverable Checkpoint
Demonstrate your successful program to the instructor in-person or by recording a video of all possible input configurations. If you submit videos, please upload them to Box or OneDrive, ensure anyone with the link can view them, then share the link. Submit your code at this stage by tagging your current commitcontinuousand pushing tags.
Design 2: always Block
Add a new design source called alwaysand.v to your project.
Design
The following Verilog code defines a circuit that evaluates the function $F = A \land B$ only when A or B is updated. In Verilog, an always block allows you to specify exactly when you would like a function to be evaluated.
module alwaysand (
output F,
input A,
input B
);
always @(A, B) begin
F = A & B;
end
endmoduleImplment an AND gate using an always block.
Simulate
Now, it’s time to simulate your design. Let’s create a testbench for alwaysand. Add a simulation source like we did in Lab1. Call this simulation source testbench_alwaysand.v.
In case testbench_alwaysand.v is not your top-level simulation file in the Sources panel, right-click it and select Set as Top.
Using the following template, your task is to design a testbench that simulates every possible input/output combination of alwaysand.
module testbench_alwaysand (
);
reg in1, in2;
wire out;
// Something should go here
initial begin
in1 = 0; in2 = 0;
#10
in1 = 1; in2 = 0;
#10
in1 = 0; in2 = 1;
#10
in1 = 1; in2 = 1;
#10
$finish;
end
endmoduleSimulate your design, ensuring that the simulated behavior matches your expectations exactly.
Program
Deliverable Checkpoint
Submit your work at this stage by tagging your current commitalwaysand pushing tags.
Heirarchical Design
Now that you have implemented two different AND gates (continuousand and alwaysand), let’s combine them into a single top-level circuit in the moreandgates model. This will allow us to observe both gates working together.
Design
- Add a new design source to your project called
moreandgates.v. - In this module, instantiate both
continuousandandalwaysandmodules. Use the following Verilog template as a starting point:
module moreandgates (
input A, B, C, D,
output F1, F2
);
// Instantiate the continuous AND gate
continuousand u1 (
.F(F1),
.A(A),
.B(B)
);
// Instantiate the always AND gate
alwaysand u2 (
.F(F2),
.A(C),
.B(D)
);
endmoduleIn this design:
F1is the output of thecontinuousandmodule.F2is the output of thealwaysandmodule.- Both modules share the same inputs
AandB.
Simulate
- Create a new simulation source called
testbench_moreandgates.v. - Write a testbench to simulate all possible input combinations for
AandB. Use the following template:
module testbench_moreandgates (
);
reg in1, in2, in3, in4;
wire out1, out2;
// Instantiate the top-level module
moreandgates DUT (
.F1(out1),
.F2(out2),
.A(in1),
.B(in2),
.C(in3),
.D(in4)
);
initial begin
in1 = 0; in2 = 0; in3 = 0; in4 = 0;
#10
in1 = 1; in2 = 0; in3 = 0; in4 = 0;
#10
in1 = 0; in2 = 1; in3 = 0; in4 = 0;
#10
in1 = 1; in2 = 1; in3 = 0; in4 = 0;
#10
in1 = 0; in2 = 0; in3 = 1; in4 = 0;
#10
in1 = 1; in2 = 0; in3 = 1; in4 = 0;
#10
in1 = 0; in2 = 1; in3 = 1; in4 = 0;
#10
in1 = 1; in2 = 1; in3 = 1; in4 = 0;
#10
in1 = 0; in2 = 0; in3 = 0; in4 = 1;
#10
in1 = 1; in2 = 0; in3 = 0; in4 = 1;
#10
in1 = 0; in2 = 1; in3 = 0; in4 = 1;
#10
in1 = 1; in2 = 1; in3 = 0; in4 = 1;
#10
in1 = 0; in2 = 0; in3 = 1; in4 = 1;
#10
in1 = 1; in2 = 0; in3 = 1; in4 = 1;
#10
in1 = 0; in2 = 1; in3 = 1; in4 = 1;
#10
in1 = 1; in2 = 1; in3 = 1; in4 = 1;
#10
$finish;
end
endmodule- Simulate your design and verify that both
F1andF2produce the correct outputs for all input combinations.
Program
- Set
moreandgates.vas the top-level module in your Vivado project. - Update the constraints file to map
AandBto switches andF1andF2to LEDs. For example:A->sw[0]B->sw[1]C->sw[2]D->sw[3]F1->led[0]F2->led[1]
- Follow the same steps as before to synthesize, implement, and program the design onto the FPGA.
After programming the FPGA, test the circuit by toggling the switches sw[0] and sw[1]. Verify that:
led[0]lights up according to the behavior of thecontinuousandmodule.led[1]lights up according to the behavior of thealwaysandmodule.
Deliverable Checkpoint
Submit your work at this stage by tagging your current commitheirarchicaland pushing tags.
Alternative Testbench
The original testbench works for the simple AND gates with only 4 input combinations. However, manually enumerating every combination of inputs can be a pain, especially when the number of combinations increases. If you want to automatically iterate through every possible combination, the always block can be a very helpful tool.
Let’s re-build our testbench for the moreandgates module. In order to automatically change our inputs every clock cycle, let’s define a clock signal within our testbench. In our initial block, we can define behavior that will repeat forever. Let’s make our clock signal oscillate every 10 timesteps.
Study the following code.
module testbench_moreandgates(
);
reg in1, in2, in3, in4, clk;
wire out1, out2;
moreandgates DUT (.A(in1), .B(in2), .C(in3), .D(in4), .F1(out1), .F2(out2));
initial begin
in1 = 0; in2 = 0; in3 = 0; in4 = 0; clk = 0;
forever #10 clk = ~clk;
end
// We still need to controll the inputs
endmoduleNow we have a clock that ticks on regular intervals! Next, we need a way to update our inputs. Let’s use an always block, since it allows us to evaluate a function when a specific behavior occurs.
Take a look at the following code.
module testbench_moreandgates(
);
reg in1, in2, in3, in4, clk;
wire out1, out2;
moreandgates DUT (.A(in1), .B(in2), .C(in3), .D(in4), .F1(out1), .F2(out2));
initial begin
in1 = 0; in2 = 0; in3 = 0; in4 = 0; clk = 0;
forever #10 clk = ~clk;
end
always @(posedge clk) begin
{in1, in2, in3, in4} = {in1, in2, in3, in4} + 1;
end
endmoduleThe testbench provided above is designed to simulate the moreandgates module by automatically cycling through all possible input combinations for its four inputs (in1, in2, in3, in4). It achieves this by using a clock signal (clk) that toggles every 10 time units, and an always block that updates the inputs on every positive edge of the clock. The always block increments the combined value of the inputs, effectively iterating through all 16 possible combinations of the 4-bit input vector. This approach ensures that the simulation is exhaustive and eliminates the need for manually specifying each input combination.
The Verilog trick of putting inputs in brackets, such as {in1, in2, in3, in4}, is called concatenation. Concatenation allows you to group multiple signals into a single vector. This is particularly useful when you want to treat multiple inputs as a single entity for operations like assignments or arithmetic.
In the example {in1, in2, in3, in4} = {in1, in2, in3, in4} + 1;, the concatenation groups the four individual inputs (in1, in2, in3, in4) into a 4-bit vector. The + 1 operation increments this 4-bit vector, effectively cycling through all possible combinations of the inputs. This approach simplifies the process of iterating through input combinations in a testbench.
Modify your testbench_moreandgates module in Vivado to automatically evaluate every combination of inputs using a clock. Then simulate your most recent implementation of moreandgates and describe your findings in your lab notes.
Deliverable Checkpoint
Submit your work at this stage by tagging your current commitbenchand pushing tags.
Deliverables
Indicate to your instructor that you’re ready to submit your work by leaving a comment on the Feedback PR and requesting a review from @mossbiscuits. Ensure that your submission is on the main branch. Create a tag named done to mark your submission:
git tag -a done -m "Lab2 submission"
git push origin doneIf you took photos, screenshots, or videos, remember to upload them to Box or OneDrive and link to them in the Feedback PR. Alternatively, you can submit these items directly on Canvas.
To receive 100 points, submissions must include evidence of the following:
- (10) Correct use of Github repository for this course
- (30) Correct simulation of the behavioral AND gates
- (30) Working implementations of the behavioral AND gate descriptions on the FPGA board
- (30) Correct simulation of
moreandgatesusing alternative testbench