Seyed Masoud Hosseini · Overview · Study log · Ideas · Transcript · RSS feed

FPGA & Verilog Design · Lecture 6 of 12 · 16:34

Part 6: Verilog Modules and Parameters

Introduction to FPGA Part 6 - Verilog Modules and Parameters | Digi-Key Electronics on YouTube

Study guide

What this lecture covers

This lecture addresses a scaling problem: putting all logic in one file quickly becomes unmanageable. It answers how to factor a design into separate Verilog modules - using the clock divider from Part 4's challenge as the example - and instantiate multiple, independently configured copies of that module from a top-level design.

By the end you can write a module with parameter and localparam constants, instantiate it more than once with different settings using both the older defparam style and the newer ANSI-style parameter list, and wire module instances together in a top-level file. The lecture ends with a challenge to build a modular up/down counter.

Key ideas

  • Modular design: keeping one module per file makes designs easier to debug and lets you reuse a building block (like a clock divider) multiple times instead of copy-pasting code.
  • localparam vs parameter: localparam constants are fixed inside a module; parameter constants have a default value but can be overridden by the code that instantiates the module.
  • Instantiation: a module is used elsewhere by naming it, giving the instance a name, and connecting its ports to the instantiating module's wires and registers using dot notation (.clk(clk)).
  • Registered outputs need a wire in between: a module's registered output can only connect to a wire on the instantiating side, not directly to another register.
  • defparam: the older (pre-2001) way to override a parameter's default value from outside the module, kept separate from the port connection list.
  • ANSI-style parameters: the newer syntax declares parameters in a #(...) list before the port list, both when defining the module and when instantiating it, removing the need for defparam.
  • apio and multi-file projects: apio hands all Verilog files in a project folder to Yosys, which resolves module instantiation across files as long as they're in the same directory.

Walkthrough

Why split designs into modules (0:18)

The lecture frames modules as similar to classes: you define a building block once (a clock divider) and instantiate it as many times as needed, each with its own settings, avoiding duplicated code and letting each module's file stay small and easy to debug.

Parameters versus local parameters (3:05)

The clock divider module is rewritten to use parameter instead of localparam for its count width and max count, giving each value a default that can still be overridden from outside. A parameter is also used to size a vector (count_width bits wide), showing that parameters can control structural details, not just numeric values.

Building the clock divider module (4:29)

The module reuses the clock-divider logic from earlier episodes, with the reset signal now assumed active-high (inversion is left to the top-level design) and its physical constraints file declaring the clock, LED, and reset pins.

Top-level design and instantiation (6:57)

The top-level module inverts the reset button, then instantiates the clock divider module twice (div1, div2), connecting each instance's clock, reset, and output ports to top-level wires via dot notation. Both dividers share the same clock and reset but drive different LEDs.

Overriding parameters with defparam (9:35)

For div1, defparam overrides the default count_width and max_count values to make that LED blink faster (about 4 Hz), while div2 is left with its defaults (about 1 Hz). After building and uploading, the two LEDs are shown blinking at different rates, confirming the parameters took effect.

ANSI-style parameters (13:42)

The lecture rewrites the same design using the 2001-era ANSI-style syntax: parameters are declared in a #(...) list before the module's ports, and overridden the same way at instantiation, removing the need for separate defparam statements. Rebuilding and uploading produces identical behavior to the defparam version.

Before you watch

  • Complete Part 4 ("Clocks and Procedural Assignments"), since this lecture reuses its clock-divider solution as the module being factored out.
  • Having attempted the clock-divider challenge from Part 4 will make the parameter examples easier to follow.

Check your understanding

  1. Why can't a module's registered output connect directly to another register in the instantiating module?
  2. What is the practical difference between localparam and parameter?
  3. How does defparam differ from the ANSI-style parameter list introduced later in the lecture?
  4. Why does apio need all of a project's Verilog files to be in the same folder for a simple project?
  5. What does the lecture's up/down counter challenge ask you to build using modules?

Chapters

From the YouTube description

A field-programmable gate array (FPGA) is an integrated circuit (IC) that lets you implement custom digital circuits. You can use an FPGA to create optimized digital logic for things like digital signal processing (DSP), machine learning, and cryptocurrency mining. Because of the FPGA’s flexibility, you can often implement entire processors using its digital logic. You can find FPGAs in consumer electronics, satellites, and in servers used to perform specialized calculations.
In this series, we will see how an FPGA works and demonstrate how to create custom digital logic using the Verilog hardware description language (HDL).

Previously, we showed how to create finite state machines in Verilog and deploy them to our FPGA (https://youtu.be/pK6XN7sFosI). In this episode, we demonstrate how to write modules in Verilog and use parameters to make hierarchical designs.

The solution to the challenge at the end of the episode can be found here: https://www.digikey.com/en/maker/projects/introduction-to-fpga-part-6-verilog-modules-and-parameters/c7d4d01274be43278d8bc531e6b7acb7

All code examples and solutions for this series can be found here: https://github.com/ShawnHymel/introduction-to-fpga

A module in Verilog is similar to a function or class in programming languages. It allows you to reuse code without needing to copy-and-paste parts of your design. In addition, you can create hierarchical designs that are often easier to diagram and understand from a high-level perspective.

We demonstrate how to create a module out of our clock divider code from a previous episode. This code is wrapped in a module header so that we can instantiate it in another module. Note that it’s often considered good practice to have one module per file.

We also introduce the concept of parameters. Unlike the “defparam” keyword, the “parameter” keyword allows the instantiating code to change values and functionality within the instantiated module. For example, instead of using a static MAX_COUNT value that creates the same clock divider every time, we turn MAX_COUNT into a parameter. This allows the instantiating code to change how much the module divides the input clock by.

In addition, we demonstrate how to use a variable bit-width value as a parameter. The instantiating code can change COUNT_WIDTH, which changes how many bits are used for the counter in the clock divider module.

Finally, we create a top-level design that instantiates two different versions of the module to blink LEDs at different rates (by setting the parameters for each divider module differently).
We show how to define parameters using the 1995 version of Verilog as well as the more common ANSI-style introduced in the 2001 version.

Your challenge is to create a design that continuously counts up and down (alternating between counting up from 0x0 to 0xF and down from 0xF to 0x0). You are to use modules to accomplish this goal. Note that you are welcome to use the clock divider code and counter code from this and previous episodes as a starting point.

Product Links:
https://www.digikey.com/en/products/detail/lattice-semiconductor-corporation/ICE40HX1K-STICK-EVN/4289604

Related Videos:
https://www.youtube.com/watch?v=z8Oldd-nrfs
https://www.youtube.com/watch?v=5kNXX67mchE
https://www.youtube.com/watch?v=iwcxLQ6AB88

Related Project Links:
https://www.digikey.com/en/maker/projects/introduction-to-fpga-part-6-verilog-modules-and-parameters/c7d4d01274be43278d8bc531e6b7acb7

Product Links:
https://www.digikey.com/en/products/detail/lattice-semiconductor-corporation/ICE40HX1K-STICK-EVN/4289604

Related Videos:
https://www.youtube.com/watch?v=z8Oldd-nrfs
https://www.youtube.com/watch?v=5kNXX67mchE
https://www.youtube.com/watch?v=iwcxLQ6AB88

Related Project Links:
https://www.digikey.com/en/maker/projects/introduction-to-fpga-part-6-verilog-modules-and-parameters/c7d4d01274be43278d8bc531e6b7acb7

Related Articles:
https://www.digikey.com/en/pdf/r/renesas-electronics-america/powering-fpga-applications
https://www.digikey.com/en/videos/d/dsp/edge-machine-deep-learning-on-fpga

Learn more:
Maker.io - https://www.digikey.com/en/maker
Digi-Key’s Blog – TheCircuit https://www.digikey.com/en/blog
Connect with Digi-Key on Facebook https://www.facebook.com/digikey.electronics/
And follow us on Twitter https://twitter.com/digikey

← Part 5: Finite State Machines · Part 7: Verilog Testbenches and Simulation →