Introduction to FPGA Part 3 - Getting Started with Verilog
2021-11-22 | By ShawnHymel
License: Attribution
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:
- FPGA development board based on the Lattice iCE40. I recommend the iCEstick for this series. However, any of the development boards listed as “supported” by the apio project should work.
- Breadboard
- Pushbuttons
- Jumper wires
- (Optional) USB extension cable
Hardware Connections
The PMOD connector at the end of the iCEstick has the following 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.
Resources
The following datasheets and guides might be helpful as you tackle the challenges:
- GitHub repository - contains all examples and solutions for this series
- Verilog documentation
- Apio tool usage
- iCE40 LP/HX Datasheet
- iCEstick Evaluation Kit User’s Guide
Challenge
Create a full adder as shown in the diagram below using Verilog.
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
# 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
// 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”).
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
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.
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):
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’.
// 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.
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).
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:
- Nuts and Volts magazine has a fantastic intro to digital logic article if you need a refresher
- Here is another set of articles on digital logic from i-programmer.info
- Wikipedia article on the adder
- Stanford has a great Introduction to Verilog guide
- Matt Venn demonstrates how to use yosys, nextpnr, and icepack/iceprog in a 3-part video series (if you would like to see how to use the tools without apio)
Introduction to FPGA Part 1 - What is an FPGA?
Introduction to FPGA Part 2 - Toolchain Setup
Introduction to FPGA Part 4 - Clocks and Procedural Assignments
Introduction to FPGA Part 5 - Finite State Machine (FSM)
Introduction to FPGA Part 6 - Verilog Modules and Parameters
Introduction to FPGA Part 7 - Verilog Testbenches and Simulation
Introduction to FPGA Part 8 - Memory and Block RAM
Introduction to FPGA Part 9 - Phase-Locked Loop (PLL) and Glitches
Introduction to FPGA Part 10 - Metastability and FIFO
Introduction to FPGA Part 11 - RISC-V Softcore Processor
Introduction to FPGA Part 12 - RISC-V Custom Peripheral
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.
Visit TechForum