Configurable Logic Devices like FPGAs and CPLDs are powerful tools in the hands of an HDL designer. (figure 1.)

Hardware Description Languages; What are they and why should I care?

A Brief Introduction to Verilog and FPGAs

Alex Bucknall
Major League Hacking
16 min readMay 14, 2016

--

HDLs or Hardware Description Languages can be a strange world even to an experienced programmer. There are for-loops and case-switchs but also non-blocking statements and wires, which behave completely differently to how one might imagine they would in a conventional programming language.

Hardware Description Languages, as one might assume from the name, are used to describe the layout of a circuit or hardware application. Similar to the relationship of HTML and CSS to web development, Verilog/VHDL have a similar relationship to FPGAs and other configurable logic devices. HDLs can be used to design and describe the layout of digital systems from simple flip-flop memory units to complex communications protocols.

HDLs allow for behavioural, register transfer, gate and switch level logic providing designers with the ability to define levels detail. Behavioural level logic allows for a set of instructions executed sequentially, register transfer level logic allows for the transfer of data between registers, driven by an explicit clock and gate level logic, which defines the individual gate level logic.

This article will briefly cover a range of topics including,

  • Logic, combinational and sequential
  • Basic Verilog Syntax
  • Examples of circuits you can build in Verilog
  • FPGA’s and what they are
  • Why you might use an FPGA over a Micro-Controller

The best way to understand how HDLs work is to treat them like a markup language; remember you’re describing the layout of a circuit not instructions for a CPU.

Throughout this article, I will be using Verilog for code snippets and as reference.

Let’s go back to basics with some logic…

Remember your logic gates? Don’t worry if you can’t, we’ll start by briefly covering the different types and explaining how Verilog can be used to build both combinational and sequential logic circuits.

Logic Gates (Boolean Logic)

Logic gates are the building blocks of the digital world. Almost all digital circuits use some form of logic to accomplish their intended purpose, whether that is to sample data from a thermometer or to perform arithmetic operations like multiplication and addition. They take boolean inputs (true or false; 1 or 0) and output a value based upon their type/function.

Logic gates and their Truth Tables (figure 2.)

Lets take the example of an OR gate; say the values at its inputs (A and B) are 1 and 0, respectively. This combination of values will result in an output of 1 as either of the input were ‘high’ or equal to 1. You can see in the diagram above the functionality of each type of gate via their truth table.

Combinational Logic

Combinational logic is a form of digital logic which is implemented by boolean circuits, where the output is a function of the present input only. This means that the inputs and outputs of the implemented logic are independent; in other words if you input a 1 and get out a 1, this will always be the case. A good way to think about combinational logic is to compare it to a mathematical equation.

An input produces an output (figure 3.)

E.g. if you take an input of 5 and add it to 10, you get a result of 15. If you take 4 boolean inputs (A, B, C and D) then use a selection of logic gates to create functions that produce a selection of 3 outputs (X, Y and Z) you might end up with a combinational circuit like the one below:

Block diagram example of combinational logic (figure 4.)

The circuit shown in figure 3. takes inputs for A, B, C and D and produces outputs for X, Y and Z. No matter the point in time, the same combination of inputs will always produce the same output.

( & = AND ), ( ~ = NOT ), ( | = OR ), ( ^ = XOR ), ( ^~ = XNOR )

Now if you wanted to produce the same circuit using Verilog, you could do this by using the definitions shown above. The code sample in figure 5 shows how the 4 inputs can be mapped to the 3 outputs using the same combinational logic as seen in figure 4.

Logic gates implemented in Verilog (figure 5.)

Don’t worry if you don’t understand some of elements in the code such as module/endmodule or assign statements, we’ll explain them later on. For now, appreciate how quick it is to build a combinational circuit in Verilog that can replicate the complex the block diagram we created just a minute ago!

Sequential Logic

Combinational logic is great if you want a simple function that takes an input and produces and output but what if you want to feedback your output to modify future behaviour of the circuit? That’s where sequential logic comes in. Sequential logic is the addition of memory elements of combinational logic that extends the simple functionality to include a feedback loop. This means that you can affect the future outputs of your circuit based upon the values you produce right now!

Generalised Sequential Logic Circuit (figure 6.)

The ability to feedback any given output is essential to many digital systems. If you want to build a thermostat that checks the current state of a room and then increases the temperature to a desired value, you’ll need some sort of sequential logic! In the next section, we’ll see an example of how we can use sequential logic to build simple counter circuit. Sequential logic can be broken down into two further categories, synchronous and asynchronous logic.

Synchronous Logic

Synchronous circuits are sequential circuits driven by a clock signal; an input that repeats regularly across a set period of time. This clock signal allows for precise timing operations which make it easy to stage outputs to affect future operations/functions. You might be wondering, well what good is that? Well this lets you do a whole range of really interesting things like building counters and feedback circuits!

Generalise Synchronous Logic Circuit (figure 7.)

You can create systems that change over time depending on the current state of the circuit. For example, say you want to build a simple resetable counter circuit that can count from 1 to 255, clear itself and start again. You would need some method of remembering what the previous number in the counter was, a method of knowing when to increment and some form of clearing the current value. How best to do this? With a synchronous logic circuit of course!

8-bit counter implemented using synchronous logic (figure 8.)

The example above shows how the simple counter circuit might be implemented using Verilog. Once again, do not worry about the syntax or understanding of the language; I’ll explain this later on!

Asynchronous Logic

Asynchronous logic is form of sequential logic that takes place without the use of a clock signal and feedback the output of the circuit based upon the changing state or pulsing of the input. This article won’t go into great detail explaining asynchronous logic as most modern digital circuits and devices like CPUs using synchronous logic to combat the effects of propagation delay within the logic gates themselves. Propagation delay is the time that it takes for an input signal to traverse a logic gate and cause an effect on the output. Synchronous circuits make use of clock signals to ensure that all the arriving inputs have propagated throughout the circuit correctly such that all of the outputs are exact. All inputs and outputs change upon the change of the clock signal.

Let’s take a closer look at Verilog as a language

We’ll look at some of the code snippets we showed off earlier and explain what specific parts of the code mean. Please bear in mind that this is only but a few of the features of HDLs! I’ll look to cover more specifics in later articles.

A question that is often asked is, ‘Which language should I learn, Verilog or VHDL?’. A better question would be ‘Which language should I learn first?’ as when you start working with FPGAs and other programmable logic devices, you’ll no doubtably end up using both! I’ve picked Verilog as the language of choice for this tutorial as it shares a lot of syntatic similarities to the programming language C as well as being compact, it is often easier to read than VHDL. An experienced programmer will quickly notice the similarities between Verilog and C but should be aware that not all functionality is the same.

An example of a comment — Serves no functional purpose but explains to the reader what is happening! (figure 9.)

Basic Syntax

Verilog is built around the construction of modules; blocks of code that have specified inputs and outputs. All modules must start with the ‘module’ declaration and close with an ‘endmodule’. Within the module declaration the inputs and outputs of the module are specified. For example, in the code snippet below, a module with the name ‘example_1’ is instantiated with 2 inputs and 1 output.

Declaration of a Verilog Module — the shell to your code! (figure 10.)

Input ‘x’ is declared as a single bit (1 or 0) and y has been declared as multi-bit signal. Multi-bit signals like ‘y’ are indexed most significant bit to least significant bit such that in the example above ‘[3:0] y’ is a 4-bit wide signal . It is worth remembering that Verilog, like C, starts counting from zero.

Wires

Wires are connections between elements. You can use a wire to connect other signals to one another. It’s best to think of wires in a physical sense; they are not variables and do not hold a value but rather join up other elements of the circuit. Wires can be treated as a way to connect two points in your design.

wire data_out; // data_out has been declared as a wire

Assign Statements

Assign statements are used make simple connections between elements of a module. These statements are known as continuous assignments as the values that are reference are permanently assigned to one another and also occur concurrently. A programmer might consider this similar to declaring a variable in a conventional programming language but should be aware that in Verilog, the assign statement does not behave the same as something like ‘int x = 10;’ in the programming language C.

Elements w1, w2 and w3 are all declared as wires in this adder module (figure 11.)

Figure 11 shows how wires are used to connect the three elements of a full adder module together. Remember wires are not variables, they do not store values; they connect up different elements of the circuit.

assign w1 = sum; // Assigning a wire the sum of two values

The example above shows how the output wire ‘data_out’ is being assigned the sum of the inputs ‘x’ and ‘y’. You should visualise an assign statement as a connection. The element at on the immediate right of the assign statement is connected to the elements on the right of the equals symbol.

Somewhat confusingly implicit assign statements, which both declare to and assign to wires, can be used. This odd behaviour often leads to confusion as people assume they behave the same way as variables.

wire data_out = x ^ y; // An example of an implicit assignment using a wire 

Remember — You’re designing a circuit, not programming a set of instructions for a processor!

Registers

Registers (regs) are an essential part of HDL designs that allow for the storage of values. A designer will use registers to manage incoming and outgoing data allowing for operations to be stage/staggered. Regs are commonly used with the synchronous latching of inputs to outputs based upon a clock signal which I’ll demonstrate in a later example.

reg y; // An element y has been declared as a reg

Unlike a wire which is modelled a connection, regs are used hold values. Regs can be treated like storage elements for values that are particularily useful in sequential circuits to allow for the latching in and out of values.

Assigning to regs is a little different from wires; you can only make assignments to a reg within an always block and cannot use the assign statement. I’ll explain how this works in the next section!

reg [3:0] input_x = 4'b0010;

Although registers cannot be directly assigned to on their own, initial values can be set (as in the example above). Here a 4-bit wide binary value of 2 is set to the 4-bit wide reg ‘input_x’. The notation for describing values in Verilog is shown below. Binary, Decimal and Hexadecimal values can be represented in Verilog.

Representing various numerical notations in Verilog (figure 12.)

It’s also important to remember that in Verilog you must handle arithmetic at a binary level of abstraction, meaning you should assign your regs enough bits to store your desired value without overflowing them (thus potentially truncating your and reducing the accuracy of your result)!

Remember — If you want to design synchronous logic, you should use regs at the input and outputs of your circuits so that you receive data at the same instance you output it!

Another advantage of regs is that they allow you control the flow of data across your circuit; forcing the data to move in steps or stages across your circuit. If you don’t stage your synchronous circuit with regs, you’ll likely come across unpredicted timing behaviour. For example, you might be trying to perform a calculation on the the temperature of a sensor but didn’t use regs at the beginning of your circuit. If your temperature sensors outputs values at a rate faster than you can perform the calculation, you’ll quickly notice that the data your receive vs the expected result of the calculation do not match up as the incoming data could have changed in the middle of the calculation, before it could have even been completed!

Combinational Always Block

Always blocks are another important element of behaviour in Verilog; they let you use higher level descriptions to build complex combinational blocks that produce 1 or more outputs from a selection of inputs.

Example of an Always block which makes assignments upon ‘a’ or ‘b’ changing state. (figure 13.)

In the example above, we’ve said that always on the changing behaviour of ‘a’ or ‘b’ that the contained logic should be produced. Always blocks make it easier to create large assignment statements without having to ‘assign’ each element. It’s important to note that assignments made inside of an always block should be previously declared as regs. ‘begin’ and ‘end’ are using in Verilog to open and close blocks containing multiple statements (the same way ‘{‘ and’}’ are used in C).

Example of letting the Verilog Compiler decide which inputs to assign upon. (figure 14.)

In the figure 14, we’ve added a new symbol ‘*’ to our always block. This is effectively a shortcut that tells the Verilog compiler (one of tools used to turn your code into an actual circuit) that you want all of the assignments to take place upon any of the changing inputs within that specified block. It’s a nice trick to ensure you haven’t missed any regs.

Synchronous Always Blocks

Drawing on the knowledge of the different types of logic from earlier, we’ll now use a clock in addition to the always block to provide synchronous behaviour to our Verilog. We can take the always blocks we just learnt about and add synchronous behaviour with a simple statement.

Posedge Clock — Synchronous Logic in Verilog (figure 15.)

The only thing that’s changed here is the term ‘posedge’; we’re still describing that the contents of the always statement should change with that of the input ‘clk’ but now we’re telling it that it should change on the rising edge of this input.

The rising or positive edge of a signal (figure 16.)

What this means is that whenever the ‘clk’ signal transitions from a zero to a one, the contents of the always block should update to whatever values are present at the wires and regs inside of it. You can also use ‘negedge’ to do the opposite; change on the falling edge.

Non-blocking assignments in Verilog (figure 17.)

So I’ve leapt ahead and thrown some more concepts into the mix. You can see that the assignments are now being made with what looks like a ‘less than or equals’ symbol (‘<=’). This is known as a non-blocking assignment and is an extremely powerful feature in Verilog. Previously, we’ve used ‘=’ to make assignments and similarily to conventional programming language like C, order in which you make these assignments is significant.

Blocking assignments in Verilog (figure 18.)

In figure 18, each of the assignments are performed in order. First ‘x’ then ‘y’ and finally ‘z’ are assigned to, resulting in whatever was stored at ‘x’ prior to the changing of the ‘clk’ is lost. Instead you can use a non-blocking statement ‘<=’ to allow for all of the assignments to take place simulatenously. The non-blocking statement allows all the value assignments to take place simultaneously. This is powerful because it allows for the construction of complex synchronous circuits like counters, shift-registers and memory circuits.

Conditionals

These should hopefully have a little more of a household functionality! As with conventional programming languages, Verilog also has ‘if’ and ‘else’ statements to perform conditional operations. For example you could check the inputs of a circuit and decide what to do dependent on those values.

Conditional ‘if’ and ‘else’ in Verilog (figure 19.)

In the case above, if ‘a’ is not equal to a value of 1, then ‘y’ is assigned the value at ‘x’. Else ‘y’ is assigned a 2-bit wide value of zero (‘00’). Once again these conditional checks are only performed upon the positive edge of the ‘clk’ signal.

Example — A Simple 8-bit Counter

Hopefully I haven’t lost you by this point! If you’re confused by anything or have noticed that I’ve made a mistake, please drop me a comment and I’ll get back to you/make any corrections!

We can tie all of the concepts in the example that we covered briefly at the beginning of this article; the 8-bit counter. Using your new found knowledge Verilog, see if you can understand the counter example way back in figure 8! Scroll down once you think you’ve understood the general concept and I’ve provided a commented code snippet explaining the specifics!

Annotated version of figure 7. (figure 20.)

You can see how we’ve used elements from all of topic covered earlier to build a nice, easy to use counter! This is just the start of what you can design using HDLs. It’s possible to design entire processors that have their own assembly languages to execute instructions from! A processor inside of an FPGA… talk about confusing!

Test Benches

So you might be wondering how do you actually run/simulate one of these modules? Well that’s where test benches come in. Verilog designers use test benches to simulate the inputs to a circuit and observe the outputs. Often this is an important way to verify that the functionality of a design is correct before attempting to flash it to an FPGA or other device. Many tools will allow test benches to output waveform (.vcd) files which contain information about the simulation of the circuit and can be plotted against time to give a graphical representation of the simulation. I’ll keep this brief as I’d like to write a more detailed tutorial on these; content for a future tutorial/article!

An example testbench for a slightly more complex counter! (figure 21.)

“You mentioned FPGAs… What is one of those?”

You’re right, I’ve mentioned FPGAs previously and now’s a good time as any to explain a little more about them. FPGA or Field Programmable Gate Arrays are work horse of the HDL world; they’re rapidly configurable logic devices that can be synthesised to replicate any digital logic that the designer wishes.

A Mojo FPGA Development Board from Adafruit.com (figure 22.)

FPGAs are complex devices consisting of four main resources that allow for the design of any desired digital circuit; Flexible Logic, Flexible Routing, Flexible I/O and Embedded Hard Modules. The secret to the flexibility of the FPGA comes from the way it implements low level logic; via the use of LUTs or Look-Up Tables. These LUTs can be configure to match any logic the user desires/describes so long as the FPGA has enough capacity!

FGPAs, along with other configurable logic devices, are fascinating in design and construction but this is another topic for another later article as I couldn’t do them justice in the time we have here today!

“This sounds cool… But why would I use an FPGA, when I have a Micro-Controller?”

HDL’s are slowly reaching a consumer/hobbyist market as the price of configurable logic devices like FPGAs has begun to reach an affordable point. FPGAs can provide huge performance advantages over microcontrollers.

You can use non-standard data widths (i.e. 256-bit wide signals!), handle large parallel inputs, avoid the fetch, decode and execute process that a CPU has to abide by and more. Incredible things can be done with FGPAs like manipulating huge throughputs of data such as 4K video and managing hundreds of incoming connections like a network router might do.

Interestingly, FPGAs were actually used in the first generations of WiFi routers whilst the wireless standard was still being agreed upon. The configurability of FPGAs allowed for network engineers to adapt and make changes with the devices as specifications were changed/updated without sacrificing the performance required for handling all incoming/outgoing connections.

Altera - One of the two leading manufacturers of FPGA devices (figure 23.)

Final Thoughts…

This tutorial has only scratched the surface of what you can do with HDLs such as Verilog. There are a huge range of features to the language such as additional data types, other forms of conditional switching, a ton of testbench tools and loads more that I haven’t mentioned. Unfortunately, a much of this isn’t very well documented or presented in an understandable manner for students/those wishing to learn more about it.

As an attempt to combat all the terrible tutorials out there, I’m planning to write a number of follow up guides/articles aiming to teach people more about Verilog/FPGAs and world of hardware design. I currently have two further articles in the works; ‘Designing Digitial Circuits with Verilog’ & ‘FPGA Architecture; A Closer Look’.

If you’re curious and can’t wait for me to finish writing the next article in this series, I’d suggest heading over to EDA Playground (http://www.edaplayground.com) and attempting to build some simple circuits using their compiler and simulation tools. These are great to get started as you do not need to install any complicated toolchain software as the EDA tools are cloud based (i.e. accessible via your web browser).

I’m a big believer in learning by example and the best way to learn about Hardware Description Languages is try writing some code yourself!

A little bit about me. I’m a final year EE student with a passion for making the tech scene more accessible for those who don’t come from a technical background. I founded WarwickTECH in 2014, with the intention to make the world of programming, startups and tech something that everyone at my university could get involved with. I spend my weekends helping/hanging out with students at hackathons as a coach for Major League Hacking (EU League). If you want to reach out, chat to me about programming/electronics or grab a coffee, drop me a tweet!

--

--