Reader small image

You're reading from  FPGA Programming for Beginners

Product typeBook
Published inMar 2021
Reading LevelIntermediate
PublisherPackt
ISBN-139781789805413
Edition1st Edition
Languages
Tools
Right arrow
Author (1)
Frank Bruno
Frank Bruno
author image
Frank Bruno

Frank Bruno is an experienced high-performance design engineer specializing in FPGAs with some ASIC experience. He has experience working for companies like SpaceX, GM Cruise, Belvedere Trading, Allston Trading, and Number Nine. He is currently working as an FPGA engineer for Belvedere Trading.
Read more about Frank Bruno

Right arrow

Chapter 2: Combinational Logic

Designs are typically composed of combinational and sequential logic. Combinational logic is made up simply of gates, as we saw in Chapter 1, Introduction to FPGA Architectures and Xilinx Vivado. Sequential logic maintains state, usually based on a clock edge, but it can be level-based as well, as we will discuss when we learn what not to do when inferring sequential logic.

In this chapter, we are going to explore writing a complete SystemVerilog module from scratch that can perform some basic real-world operations that you may use one day in your actual designs.

In this chapter, we are going to cover the following main topics:

  • Creating SystemVerilog modules
  • Introducing data types
  • Packaging up code using functions
  • Project – creating combinational logic

Technical requirements

The technical requirements for this chapter are the same as those for Chapter 1, Introduction to FPGA Architectures and Xilinx Vivado.

To follow along with the examples and the project, please take a look at the code files for this chapter at the following GitHub repository: https://github.com/PacktPublishing/Learn-FPGA-Programming/tree/master/CH2.

Creating SystemVerilog modules

At the heart of every design are the modules that compose it. From the testbench that's used to verify the design to any instantiated components, they are all declared somewhere as a module. For the example design we'll be covering in this chapter, we'll be creating a set of modules representing the functions that we can access via the buttons and switches on the evaluation board. We'll use these switches to set values, and we'll use five buttons to perform operations.

Let's take a look at the components of a module declaration:

module project_2
#(parameter SELECTOR,
  Parameter BITS = 16)
(input wire [BITS-1:0]          SW,
 input wire                     BTNC,
 input wire              ...

Introducing data types

All computer programming languages need variables. These are places in memory or registers that store values that the program that's running can access. Hardware Design Languages (HDLs) are a little different in that you are building hardware. There are variable equivalents in terms of storage/sequential logic, which we'll discuss in the next chapter, but we also need wires to move data around the hardware we're building using the FPGA routing resources, even if they are never stored:

Figure 2.1 – Program flow versus HDL flow

As we can see, in a traditional flow, you have a computer that has a processor and memory. The program flows linearly; however, with modern machines, there are increasing levels of parallelism. When you write SystemVerilog, you are using data types to create hardware that will store or move data around physically from Lookup Tables (LUTs) to LUTs. If you want to use external memory, which is...

Packaging up code using functions

Often, we'll have code that we will be reusing within the same module or that's common to a group of modules. We can package this code up in a function:

function [4:0] func_addr_decode(input [31:0] addr);
  func_addr_decode = '0;
  for (int i = 0; i < 32; i++) begin
    if (addr[i]) begin
      return(i);
    end
  end
endfunction

Here, we created a function called func_addr_decode that returns a 5-bit value. function takes a 32-bit input called address. Functions can have multiple outputs, but we will not be using this feature. To return the function's value, you can assign the result to the function name or use the return statement.

Creating combinational logic

The two main ways of creating logic are via assign statements and always blocks. assign statements are convenient when creating purely combinational logic...

Project 1 – creating combinational logic

In this chapter, we've discussed signal types and how to create combinational logic. This project will contain multiple components that allow us to come up with a small calculator. It will be a rather simple one and will have the following capabilities:

  • Find the leading-one position of a vector's input via switches
  • Add, subtract, or multiply two numbers
  • Count the number of switches that have been set

The following diagram shows what the Nexys A7 board looks like:

Figure 2.4 – Nexys A7 board I/O

In the previous chapter's project, we learn how to use switches for input and LEDs for output. In this project, we'll be using all the switches in the preceding diagram for the number of ones calculator and the leading-one detector. For the leading-one detector, we'll detect the position of the left-most switch that's been set out of the 16 positions.

For the...

Summary

In this chapter, we learned how to create combinational logic, how to create different modules, and how to test them as utilize self-checking testbenches. We also explored different optimizations we can perform on the case statement and showed you how to get substantial area savings in some cases, but also how we may have problems if our design assumptions are incorrect. We then mentioned latches and the problems they cause, even when they should be safe.

At this point, hopefully, you have some confidence in how to create logic and test it. In the next chapter, we'll introduce sequential logic; that is, using registers to store values and perform operations. We'll expand upon our simple calculator and see how we can improve it now that we have some storage elements.

Questions

  1. A packed array is used to infer memories. True or false?
  2. A break statement can be used in a for loop when?

    a) Any time.

    b) If it's possible to rewrite the for loop in such a way as to not need the break.

    c) Only if you can reverse the direction of the loop; that is, go from low to high instead of high to low.

  3. Size the add_unsigned, add_signed, and mult signals:
    Logic unsigned [7:0] a_unsigned;
    logic unsigned [7:0] b_unsigned;
    logic signed [7:0] a_signed;
    logic signed [7:0] b_signed;
    assign add_unsigned = a_unsigned + b_unsigned;
    assign add_signed = a_signed + b_signed;
    assign mult = a_unsigned * b_unsigned;
  4. Division is a very costly operation. Look at the supported Vivado constructs in the Vivado Synthesis manual (Further reading). Can you easily replace the multiply operation with a division operation? What is possible without custom code?

Challenge

Look at the following add_sub module:

  logic signed [BITS/2-1:0]   ...

Further reading

Please refer to the following links for more information regarding what was covered in this chapter:

lock icon
The rest of the chapter is locked
You have been reading a chapter from
FPGA Programming for Beginners
Published in: Mar 2021Publisher: PacktISBN-13: 9781789805413
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Frank Bruno

Frank Bruno is an experienced high-performance design engineer specializing in FPGAs with some ASIC experience. He has experience working for companies like SpaceX, GM Cruise, Belvedere Trading, Allston Trading, and Number Nine. He is currently working as an FPGA engineer for Belvedere Trading.
Read more about Frank Bruno