Introduction to FPGA Part 3 - Getting Started with Verilog

By ShawnHymel

Verilog is a hardware description language (HDL), which is a type of computer language used to describe the structure and behavior of electrical circuits (usually digital circuits). In this series, we will use Verilog, as it is supported by the yosys synthesis tool.

If you have not already done so, please set up your toolchain using apio, as detailed in the previous lesson.

In this tutorial, we present one possible solution to creating a full adder in an FPGA using Verilog. We focus on using continuous assignments in Verilog to create digital logic circuits.

Video

If you have not done so, please watch the following video, which explains the concepts required to complete the challenge. It also demonstrates a working version of the challenge:

 

Required Hardware

For this challenge, you will need the following hardware:

Hardware Connections

The PMOD connector at the end of the iCEstick has the following pinout:

iCEstick PMOD connector pinout

A full pinout of the iCEstick (including the pins on either side of the PMOD connector) can be found here.

Connect 4 pushbuttons to the iCEstick as follows. Note that you do not need pull-up resistors on the buttons. We will use the internal pull-up resistors available in the FPGA.

Connect buttons to iCEstick PMOD connector

Resources

The following datasheets and guides might be helpful as you tackle the challenges:

Challenge

Create a full adder as shown in the diagram below using Verilog.

Full adder digital logic circuit and truth table

A full adder adds two binary numbers together. The full adder shown is a 1-bit adder and contains carry-in (Cin) and carry-out (Cout) bits. There are several possible ways to implement a full adder, but your solution should output a sum (S) bit along with a Cout bit that adds the 1-bit value A to 1-bit value B and also adds the Cin bit.

Note that there are multiple circuits that can create a full adder. I have provided one possible way to accomplish the goal of adding two 1-bit numbers. See this Wikipedia article for more information on the adder.

Upload your design to the FPGA and test it. Try pressing different combinations of buttons and compare it to the truth table to ensure that your design works.

Solution

Spoilers below! I highly encourage you to try the challenge on your own before comparing your answer to mine. Note that my solution may not be the only way to solve the challenge.

full-adder.pcf

Copy Code
# LEDs
set_io led[0] 99
set_io led[1] 98

# PMOD I/O
set_io -pullup yes pmod[0] 78
set_io -pullup yes pmod[1] 79
set_io -pullup yes pmod[2] 80

full-adder.v

Copy Code
// Solution to full adder challenge
//
// Inputs:
// pmod[2:0] - pushbuttons (x3)
//
// Outputs:
// led[1:0] - LEDs (x2)
//
// LED 0 turns on if 1 or 3 buttons are pressed. LED 1 turns on if 2 or 3
// buttons are pressed.
//
// Date: October 25, 2021
// Author: Shawn Hymel
// License: 0BSD

// Full adder with button inputs
module full_adder (

// Inputs
input [2:0] pmod,

// Output
output [1:0] led
);

// Wire (net) declarations (internal to module)
wire a;
wire b;
wire c_in;
wire a_xor_b;

// A, B, and C_IN are inverted button logic
assign a = ~pmod[0];
assign b = ~pmod[1];
assign c_in = ~pmod[2];

// Create intermediate wire (net)
assign a_xor_b = a ^ b;

// Create output logic
assign led[0] = a_xor_b ^ c_in;
assign led[1] = (a_xor_b & c_in) | (a & b);

endmodule

Save these files in a single directory on your computer. Open a command prompt and navigate to your project directory. Build and upload the design with apio. If you are not using the iCEstick, change the board name to the board tag found in the apio supported boards file (for example, the tag for the “iCEstick Evaluation Kit” is “icestick”).

Copy Code
apio init -b icestick
apio build
apio upload

When the process is done uploading the design, you should be able to press the buttons on your breadboard to verify that the full adder works!

Explanation

Let’s first look at the physical constraints file (.pcf). This should look very much like the examples shown in the video. We define 2 input/output pins connected to physical pins 98 and 99 on the FPGA

Copy Code
set_io              led[0]  99
set_io led[1] 98

Next, we define 3 input/output pins with pull-up resistors connected to physical pins 78, 79, and 80 on the FPGA.

Copy Code
set_io  -pullup yes pmod[0] 78
set_io -pullup yes pmod[1] 79
set_io -pullup yes pmod[2] 80

In the full-adder.v Verilog file, we start by declaring the name of our module with the required inputs and outputs (these names should match those in the .pcf file):

Copy Code
module full_adder (

// Inputs
input [2:0] pmod,

// Output
output [1:0] led
);

While not necessary, I demonstrate using wires as intermediary names for the input signals, as the buttons are active-low. For example, ~pmod[0] is renamed (using a wire) to ‘a’.

Copy Code
    // Wire (net) declarations (internal to module)
wire a;
wire b;
wire c_in;
wire a_xor_b;

// A, B, and C_IN are inverted button logic
assign a = ~pmod[0];
assign b = ~pmod[1];
assign c_in = ~pmod[2];

Next, I assign a wire name to the combination of the A XOR B operation. Once again, this is not strictly necessary, but it does demonstrate how to use wires.

Copy Code
    assign a_xor_b = a ^ b;

Finally, the output logic is created using the named wires. Here, the first LED (S) is given by (A XOR B) XOR Cin. The second LED (Cout) is given by ((A XOR B) AND Cin) OR (A AND B).

Copy Code
    assign led[0] = a_xor_b ^ c_in;
assign led[1] = (a_xor_b & c_in) | (a & b);

Finally, we close the module with “endmodule.” When synthesized, this should produce a truth table similar to the one given in the challenge section. Note that the only difference is that the buttons must be inverted, as they are active low.

Recommended Reading

The following content might be helpful if you would like to dig deeper:

Key Parts and Components

Add all Digi-Key Parts to Cart
  • 220-2656-ND