Lab6: Arithmetic Circuits

Time Estimate2 Hours   Grade Impact2.5%   DueSep 16 @ 3pm   Required for Pass  

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.

Basic Design Workflow

You will repeat this process dozens of times throughout this course, so it is important to internalize each of these steps. You can always come back to this lab description for a reminder during a future lab.

Cloning the Assignment Repository

To begin working on this lab, you need to clone the repository for this assignment. Follow these steps:

  1. Make sure you’ve joined this assignment using the invitation link on Canvas. This creates a repository for this assignment for you.

  2. Go to your assignment repository on the GitHub web interface (something like github.com/ece2700/lab1-hello-world-<username>) and click the < > Code button. Assuming you’re using a Personal Access Token, click HTTPS, then copy the address that appears.

  3. Open a terminal on your computer.

  4. Navigate to the directory where you want to store your lab files.

  5. Clone the repository using the URL you previously copied. Replace <repo-url> with the actual URL and <custom-name> with the folder name you’d like to clone the repo into:

    git clone <repo-url> <custom-name>
  6. Navigate into the newly created directory:

    cd <custom-name>
  7. Verify that the repository was cloned successfully by listing its contents:

    ls

You are now ready to proceed with creating a new project in Vivado.

Starting Vivado

You will be designing systems using a software tool called Vivado. To open Vivado, click Activities in the top left corner of your screen, or use the meta key (i.e., the “Windows” key). Start typing Vivado until it appears in the menu, then select it. Vivado should begin to load.

Once Vivado loads, it will show the following dashboard:

Creating a New Project

From the Vivado dashboard shown above, click Create Project >, which is found in the Quick Start section.

For this specific demo, enter the following information:

  • Project name: Enter myandgate.
  • Project location: Click ... and select the repository for this lab.
  • Create project subdirectory: This box should be checked.

Click Next to move to the next screen in the New Project Wizard. When prompted, select RTL Project and click Next again.

Add Sources

Now, in the Add Sources screen, click Create File. In the dialogue titled Create Source File, enter myandgate.v in the File Name textbox. This creates a Verilog (.v) source file. Click OK to return to the New Project Wizard, then click Next.

Add Constraints

The current screen is titled Add Constraints. A constraint file is an essential component of any physical design. It specifies how the signals in your Verilog code map to the physical resources on the Basys3 FPGA board, such as connecting internal logic to pins on the device. Without a constraint file, your design cannot interact with the board’s hardware, rendering it non-functional.

Download the constraint file, Basys3Master.xdc, from the Canvas landing or “Files” page.

Back in the New Project Wizard, click Add Files and locate Basys3 Master.xdc, which you just downloaded. Click OK and return to the New Project Wizard. Check the box titled copy constraints files into project. This copies the file into your project directory and allows you to modify the template Basys3 Master.xdc for this project without modifying it for every project. Click Next in the New Project Wizard.

Board Selection

In the New Project Wizard, navigate to the Boards tab. Search Basys3 and select the option with display name Basys3. If it does not appear, click Refresh as shown in the figure below.

If the board is not yet downloaded, it will show a download icon, like in the figure below. Click the download icon to download the part specification.

Selecting the right board
If you select the wrong board, you will encounter strange errors that can be nearly impossible to debug.

Ensure the Basys3 row is highlighted, then click Next in the New Project Wizard.

The final screen of the New Project Wizard shows an overview of the settings for the new project. Actually check them. If you are satisfied with the settings, click Finish to create and open the new project.

Writing Verilog Specification

After the New Project Wizard, a dialogue titled Define Module encourages you to specify input and output for your new module. Using this window is optional, but it can save you time.

For this lab, we are designing a custom AND gate with 2 inputs called A and B and 1 output called F. Click the + icon in the dialogue to specify the inputs and output. Make sure the Direction column reflects the specification; do not worry about Bus, MSB, or LSB. Click OK to populate your module with these specifications.

Vivado now shows the Project Manager, where you will spend most of your time. Navigate to the Design Sources tab, and double-click myandgate to open its Verilog source file (myandgate.v, which you created earlier).

Notice the first line of the file. Don’t worry too much about what it does for now. Do not edit it.

timescale 1 ns / 1 ps

Vivado pre-populates a substantial header at the top of each Verilog file. Complete all the information you deem important in this header, with an example shown below:

/////////////////////////////////////////////////////////
// Company : Utah State University
// Engineer : Landon Taylor
//
// Create Date : 07/31/2026 04:31:24 PM
// Design Name : Lab 1
// Module Name : myandgate
// Project Name : myandgate
// Target Devices : Basys3
// Tool Versions : Vivado 2021.4
// Description : a trivial module to implement an and gate
// Dependencies : none 
// Revision : 0.01
// Additional Comments :
//
/////////////////////////////////////////////////////////

Following the header is the main Verilog module for this design. Some of this file is pre-populated with the output and inputs specified in the dialogue during the previous step.

Your task is to create a structural description of an AND gate using the verilog primitive and. Modify your module to include the and specification as shown below. This specification creates an AND gate, calls it GATE, and evaluates the Boolean function $F = A \land B$.

module myandgate (
    output F ,
    input A ,
    input B
);
    
    and GATE1 (F, A, B);

endmodule

This module represents a simple circuit containing only one AND gate. Now it’s time to actually do something with this circuit.

Writing a Testbench

A testbench allows for a software evaluation of a hardware specification. It automates the control of inputs to allow you to observe outputs and ensure they match your expectations. Let’s create a simple testbench to evaluate our simple myandgate circuit.

Navigate to the Flow Navigator panel on the left of the Vivado interface. Under the Project Manager tab, select Add Sources. Alternatively, you can click + within the toolbar of the Source panel in the upper middle of the screen.

In the wizard that opens, select Add or create simulation sources, then click Next to open the Simulation Source Wizard.

In this wizard, click Create File, and enter testbench.v as the file name. Click OK, then click Finish to exit the wizard.

In the dialogue titled Define Module, simply click OK because a testbench should not have inputs and outputs of its own. As a wrapper environment for the circuit under test, it should use all internal variables to control the circuit.

The file testbench.v should appear in the Source panel under Simulation Sources. It should contain a simple module that resembles the following:

module testbench(
);
endmodule

Your task is now to design this module in such a way that it effectively evaluates the performance of myandgate. Let’s walk through this process together.

First, the testbench needs some signals to control. Let’s define two inputs and an output for our circuit. For reasons we’ll explore later, signals that will be used as inputs tend to be type reg, and signals that are connected to outputs tend to be type wire. Let’s define those signals like this:

module testbench(
);
    reg in1, in2;
    wire out;
endmodule

This gives us signals to work with, but we’re not doing anything interesting with them. Let’s automate some test behavior with an initial block:

module testbench(
);
    reg in1, in2;
    wire out;

    initial begin
        in1 = 0; in2 = 0;
        #10
        in1 = 1; in2 = 0;
        #10
        in1 = 0; in2 = 1;
        #10
        in1 = 1; in2 = 1;
        #10
        $finish;
    end
endmodule

We’ll explore these initial blocks later, but we are effectively automating the process of waiting 10 time units between tests of (in1, in2) = (0,0), (1,0), (0,1), and (1,1). Because we know the truth table for an AND gate, we know what to expect the output to be in each of these input configurations.

We now have simulated inputs, and we have a wire ready to capture our circuit’s output. Like we described earlier, the testbench is a wrapper for the circuit under test. So let’s add a line that connects our myandgate circuit into this testbench module:

module testbench(
);
    reg in1, in2;
    wire out;

    myandgate DUT (.A(in1), .B(in2), .F(out));

    initial begin
        in1 = 0; in2 = 0;
        #10
        in1 = 1; in2 = 0;
        #10
        in1 = 0; in2 = 1;
        #10
        in1 = 1; in2 = 1;
        #10
        $finish;
    end
endmodule

The line myandgate DUT (.A(in1), .B(in2), .F(out)); declares an instance of myandgate within the testbench module. This is similar in concept to calling a function within a function in programming languages. However, remember you are working on hardware, not software. When we create an instance of a design, we say the design is instantiated.

To better visualize this, imagine you are setting up a computer workstation. A monitor is a module in this system. It has already been designed, so you can simply plug it in (i.e., instantiate it) in your workstation. If you want to add another monitor, you can easily plug in a second one, creating two monitor instances.

The syntax to instantiate a module in Verilog is as follows:

    <module type> <name of this instance> (<input/output mapping>)

In the same way you need to correctly configure the power and HDMI inputs to the monitor in a computer workstation, you need to correctly map inputs and outputs when instantiating a module. Let’s take a look at the line we added to instantiate myandgate:

    myandgate DUT (.A(in1), .B(in2), .F(out));

In this example, we are instantiating the module myandgate. We are naming the instance DUT, which customarily stands for Device Under Test in digital design. We then map the inputs and outputs specified in myandgate to the signals we have created in testbench. Specifically, we map myandgate.A to testbench.in1, myandgate.B to testbench.in2, and myandgate.F to testbench.out.

This syntax might look familiar: this is how we added the AND gate to our myandgate module earlier. Vivado provides a built-in and module, and we instantiated the and module within myandgate.

Remember: this is hardware design. Instantiating a module is not the same as calling a function; we are using our myandgate circuit as a black-box component in a larger circuit design. We are effectively “plugging in” a myandgate circuit in the same way we plug in a computer monitor.

Simulating the Design

You’ve now created your first Verilog design, complete with a testbench. Congratulations! Now it’s time to see if it works as we expect.

Near the bottom of the Project window are a set of tabs named TCL Console, Messages, Log, Reports, and Design Runs. These tabs are where you’ll get most of the feedback about your designs. Click on the Messages tab to see if there are any “Errors” or “Critical Warnings”. A syntax error appears automatically as a “Critical Warning”. If you see these messages, correct the issues before continuing.

When no “Errors” or “Critical Warnings” appear, navigate to the Simulation tab on the leftmost panel, then click Run Simulation. In the drop-down menu, click Run Behavioral Simulation. A simulation view will appear. If it does not, click on the Untitled # tab that opens.

This view may be zoomed out. If you only see flat lines, click the zoom-to-fit button that looks like this:

You should see waveforms that reflect the behavior of an AND gate. The screenshots on this page are for demonstration only and do not reflect what you should see as the result from an AND gate. Please take a screenshot of these waveforms or draw them in your lab notes.

Notice the yellow cursor. Click and drag it to move it to different times throughout the waveforms, and notice the behavior of the values in the table on the left. Create a truth table for an AND gate in your lab notes, and verify that each input-output combination is correct for all four combinations.

Deliverable Checkpoint
Submit your work at this stage by tagging your current commit sim and pushing tags.

Programming the FPGA

Once you have determined your design is correct, you are ready to program your design onto your FPGA board. This is the most exciting part!

Return to the Project Manager view by clicking Project Manager in the Flow Navigator on the left in Vivado.

We now need to write constraints 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 myandgate. 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.

Your board has 16 switches named sw0, sw1, … , sw15, and 16 LEDs named led0, led1, … , led15. Identify these labels on your board as a sanity check. We will use the lowest-numbered resources for this lab: sw0, sw1, and led0.

In Vivado, we will define constraints by modifying the Basys3_Master.xdc file we previously added to the project. In the Sources browser, double-click Basys3_Master.xdc to edit it. You should see a large set of commented-out lines containing examples of constraint definitions. Every constraint contains two lines. The first defines the associated pin on the FPGA chip. The second defines the voltage for the logical signal. Note that the constraint syntax is quite different from Verilog. Comments are entered with #, and lines do not require semicolons at the end.

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.

Click Run Linter in the Flow Navigator panel. This performs some checks of your design.

Next, click Run Synthesis. This maps the design to the types of logic cells available within the FPGA chip. You should see a loading indicator in the upper-right corner of Vivado, indicating that synthesis is in progress. This process can be quite slow.

When synthesis is complete, a dialogue will appear. If synthesis was successful, select Run Implementation. Otherwise, corrections must be made to your design, according to the resulting error messages.

Implementation maps the synthesized design onto specific resources within the FPGA. When implementation is complete, another dialogue will appear. If implementation was successful, click Generate Bitstream to create the final program to send to the FPGA. This can be very slow.

If this process completes without errors, another dialogue will open. In this dialogue, click Open Hardware Manager. If you have errors, attempt to debug them, and you may always ask your instructor or peers for help.

Critical instructions ahead
If you do not follow these instructions exactly, you can damage your board. Please read them completely before doing anything with your hardware.

On your Basys3 board, locate jumper JP1 in the upper-right corner of the board. Jumper JP1 needs to be in the middle position. Now locate jumper JP2 in the upper-left corner. Jumper JP2 needs to be in the lower position. The power switch should be in the off position A correct configuration is shown below:

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:

  1. Ensure the board is connected and turned on. If the board is powered and turned on, the red power indicator light will be on.
  2. 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.
  3. 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.

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.

Deliverable Checkpoint
Submit your work at this stage by tagging your current commit program and 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 "Lab1 submission"
git push origin done

If 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 on this lab, submissions must include evidence of the following:

  • (20) Correct use of Github repository for this course
  • (40) Demonstration of simulation of the AND gate using testbench
  • (40) Working implementation of the structural AND gate description on the FPGA board