ENGR210

Vivado Tutorial: Logic Gates

Table of Contents

  1. Overview
  2. Background
  3. Launching Vivado
  4. Creating a Vivado Project
  5. Creating a Design Source File
  6. Creating a Constraints File
  7. Create Simulation File
  8. Project Checkpoint
  9. Running a Simulation
  10. Hardware Synthesis
  11. Programming the FPGA
  12. Testing your FPGA

Board/Part Number

The Basys3 uses Xilinx Part Number:

xc7a35ticpg236-1L

Overview

This tutorial shows the steps in a digital design project using Xilinx Vivado design suite and Digilent Basys 3 FPGA board. You will learn how to use Vivado tools to create a design and implement it on the Basys3's FPGA. This is a starter project with very little hands-on work, but it is a good reference if you ever forget how to start and complete a lab project. Logic gates are the foundation of all computer systems. They allow for the application of logical processing to be mapped onto physical circuits. In this lab project you will design and implement a digital system that uses three basic logic gates: the AND gate, the OR gate, and the NOT gate. The logic schematic of the digital system is given below.

Project Schematic

Background

AND Gate

The truth table for a 2-input AND gate is:
A B Out
0 0 0
0 1 0
1 0 0
1 1 1
And is denoted by the following schematic symbol:

And

The verilog keyword is: &

OR Gate

The truth table for a 2 input OR gate is:
A B Out
0 0 0
0 1 1
1 0 1
1 1 1
And is denoted by the following schematic symbol:

Or

The verilog keyword is: |

NOT Gate

The truth table for a 1-input NOT gate is:
A Out
0 1
1 0
And is denoted by the following schematic symbol:

Not

The verilog keyword is: ~

Creating a Vivado Project

Vivado Create Project Screen

Vivado Basys3 Part

Vivado Main Screen

Creating a Design Source File

Now we will add our first SystemVerilog source file

Vivado Add Source

Vivado Project Manager

module top (
input a,
input b,
output myAND,
output myOR,
output myNOT
);
assign myAND = a & b;
assign myOR = a | b;
assign myNOT = ~a;
endmodule

Vivado Verilog

Creating a Constraints File

Now we will add our first constraints source file. This tells Vivado how the inputs and outputs of the verilog code map to the real inputs and outputs of the Basys3 board.
Verilog Signal Basys switch/LED
a sw
b sw
myAND led
myNOT led
myOR led
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}]
set_property PACKAGE_PIN U16 [get_ports {myAND}]
    set_property IOSTANDARD LVCMOS33 [get_ports {myAND}]
set_property PACKAGE_PIN E19 [get_ports {myOR}]
    set_property IOSTANDARD LVCMOS33 [get_ports {myOR}]
set_property PACKAGE_PIN U19 [get_ports {myNOT}]
    set_property IOSTANDARD LVCMOS33 [get_ports {myNOT}]
Later in the semester, we will make use of the `"Basys3_Master.xdc"` constraints file uploaded on the website. It can be found under the `Downloads` quick link.

Create Simulation File (AKA a ‘testbench’)

We are now going to run a simulation to ensure that our verilog code is correct.
`timescale 1ns/1ps //specify how detailed of a simulation we want to run
module testbench();
    logic a, b; //logic (or 'reg') for module inputs
    wire myand, myor, mynot; //wires for module outputs
    //
    // connect our module for testing
    // This is sometimes called a DUT - Device Under Test
    //
    top top0 (
        .a(a),
        .b(b),
        .myAND(myand),
        .myOR(myor),
        .myNOT(mynot)
    );
    initial begin
        //print out these signals whenever anything changes
        $monitor("a:%h b:%h myand:%h myor:%h mynot:%h", a, b, myand, myor, mynot);

        #100 // a 100 nanosecond delay
        a = 0; b = 0; //set inputs a and b to logical 0
        #100 // a 100 nanosecond delay
        // check if any of our outputs are incorrect.
        // if so, fail the simulation with an error message
        assert( myand == 0) else $fatal(1, "myand");
        assert( myor == 0) else $fatal(1, "myor");
        assert( mynot == 1) else $fatal(1, "mynot");
        #100 // a 100 nanosecond delay
        a = 0; b = 1; // now set a=0, b=1, and repeat the test
        #100 // a 100 nanosecond delay
        assert( myand == 0) else $fatal(1, "myand");
        assert( myor == 1) else $fatal(1, "myor");
        assert( mynot == 1) else $fatal(1, "mynot");
        #100
        a = 1; b = 0; //continue testing input combinations
        #100
        assert( myand == 0) else $fatal(1, "myand");
        assert( myor == 1) else $fatal(1, "myor");
        assert( mynot == 0) else $fatal(1, "mynot");
        #100
        a = 1; b = 1; //last input combination
        #100
        assert( myand == 1) else $fatal(1, "myand");
        assert( myor == 1) else $fatal(1, "myor");
        assert( mynot == 0) else $fatal(1, "mynot");
        #100

        // now we've tested all possible input combinations to
        // ensure correct output for each
        $display("@@@Passed");
        $finish;
    end
endmodule

Project Checkpoint

Now we should have all of our source files. Your setup should look like the following:

Vivado Finished Project

Running a Simulation

Now we are going to run our simulation, and use the testbench to drive inputs and observe the outputs of our verilog module.

Vivado Simulation Console

Vivado Click Waveform Tab

Vivado Non Zoomed Out Waveform

- Now click on the ![Vivado Zoom Out Button](/projects/assets/VV_Tutorial/vivado_zoom_out_button.png) button:

Vivado Click Zoom Out Button

- Now your wave window should display the entire waveform. Waveforms allow us to observe how signals change through time. Time moves from left to right, it starts at `0ns` (nanoseconds), and moves to `900ns`.

Vivado Zoomed Out Waveform

- The simulator looks for an initial block to run the simulations.
initial begin
- It starts at `0ns`, but everything is red. Red lines means that the simulation doesn't know the value for a signal. Before `100ns`, we haven't assigned `a` or `b` to anything, so the simulation doesn't have a value for them. Because the simulation doesn't know the value for the inputs, it can't figure out the value for the outputs `myAND, myOR,` and `myNOT`. - At `100ns`, everything changes to green. This is because we used
#100 // a 100 nanosecond delay
a = 0; b = 0; //set inputs a and b to logical 0
in our simulation file. We told the simulation to set a and b to 0, so now it knows their values. Once the simulation knew the value for a and b, it could calculate the value for myAND, because we told it
assign myAND = a & b;
in our source file.
- FPGAs require a small amount of time to update an output signal given changes in the input. Therefore, we need another `#100` delay before the updates in `a` and `b` show up in the outputs. - At `200ns`, we test the values of `myAND, myOR,` and `myNOT` to make sure they are correct. Assert statements test a boolean equation `(myand == 0)` and does nothing if it is `true`. If it is `false`, it will terminate the simulation and report an error (`$fatal(1, "myand")`).
assert( myand == 0) else $fatal(1, "myand");
assert( myor == 0) else $fatal(1, "myor");
assert( mynot == 1) else $fatal(1, "mynot");
- This process repeats for every possible combination of `a` and `b`. - Waveform simulations are a great way to visualize and understand what is happening when problems arise. We will use them frequently in this class. The autograder uses a command-line version of these same simulations for its tests.

Hardware Synthesis

- Now that we're (mostly) sure our logic is correct, we can move on to "Synthesis". Synthesis is roughly equivalent to "Compiling" for FPGAs. - On the left hand menu select "`SYNTHESIS`" -> "Run Synthesis." If prompted where to launch runs, select "Launch runs on local host'. This tells Vivado to run synthesis on your local machine. - Even for simple designs, synthesis takes a surprisingly long time, usually 1-2 minutes. For large industrial designs, it can take days. This process translates our verilog code into `LUTs`, or "Look-Up Tables". It can also translate our code into basic logic gates. We'll discuss this later in class. - After the Synthesis is complete, select "Run Implementation". This is also called "`Auto Place and Route`". This process decides which locations within the `FPGA` to use for each `LUT`, and how best to connect then. - After the Implementation is complete, select "Generate Bitstream". This generates a configuration file that is read by the `FPGA` when it boots up to decide how to configure itself. - After the Generate Bitstream is complete, select "Open Hardware Manager".

Programming the FPGA

This process will (finally) program the FPGA. - If you haven't already, make sure your Basys3 board is connected. - On the right-hand side, select "Programming and Debug" -> "Open Hardware Manager" -> "Open Target" -> "Autoconnect" - This should automatically detect the Basys - Now select "Programming and Debug" -> "Open Hardware Manager" -> "Program Device" -> 'xc7a35t_0'. (Your device might be named differently) - You will need to select your 'bitstream' file. Xilinx did not make this easy. The bitstream is located at './project_0.runs/impl_1/top.bit' within your project. See the example below:

Vivado Program Bitstream

- With the bitstream selected, hit "program". This should only take a few seconds.

Testing your FPGA

You should now be able to test your FPGA. When you flip the right-most switches, the corresponding LEDs should also toggle.

Basys3 Programmed

This concludes the Vivado tutorial lab.