HDLs and basics of hardware design
Introduction
I am not covering the entire process of silcon design in this tutorial. After a quick intro, we will jump into setting up a HDL simulator and get our hands dirty.
For an embedded engineer, hardware design generally referrs to physical components and printed circuit boards (and breadboards at times). While they form the basics of hardware design, when we move towards designing tiny circuits that pack millions, maybe billions of transistors into a tiny silicon die the size of a pencil head, it becomes obvious that we cannot design them in the conventional way. Here we are talking about the design and development of the components we mount on the PCBs themselves.
The design cycle of an application specific integrated circuit (ASIC) starts off with the description of the circuit itself. While schematic based design entry is a way out, over the years we have perfected advanced tools that can convert the logic description of a circuit into hardware schematics. Since traditional programming languages rely on sequential execution (among many other reasons) we have created a class of languages tailor-made to describe asynchronous and combinatorial logic, and we call them hardware description languages (HDLs).
Verilog and VHDL are the two most commonly used HDLs, and we will be using Verilog here.
Note: A caveat to using a high level language is the tendency for a noob to describe all the hardware logic as “behavioral logic” and leaving it for the tool to synthesize the hardware for it. Take extra care to avoid this mistake.
There are numerous in-depth articles available to wrap your head around the nitty gritties of Verilog and I will not be covering it here. I will however guide you through setting up a free and open-source Verilog simulator to experiment with the concepts. I will also run through the basic concepts that will help us go ahead with HDL based design in the following parts of Fun With FPGAs.
Icarus Verilog
Icarus Verilog (or iverilog) is a free and open sourced Verilog synthesizer and simulator. It runs on Linux as well as windows and is powerful enough to work with complex designs.
Installation of iverilog is quiet straight forward .
In Ubuntu, install it from the official repositories using the following command or compile it from source.
sudo apt-get install iverilog
The windows port for iverilog is available here
iverilog comes with two main tools.
- iverilog : the verilog compiler
- vpp : the simulator
To view simulation output waveform, we will use GTKWave.
Verilog design file
Each design file typically contains a Verilog module
. A module is nothing but a basic building block of a design with a set of inputs and outputs. Later on in the design flow, these files will be synthesized into actual hardware blocks.
A typical block for an inverter will look like:
module myInv(A,B);
input wire A;
output wire B;
assign B = !A;
endmodule
This code goes into myInv.v
in this sample design.
Breaking it down:
myModule
is the name of the module and A
and B
are the associated signals
. Further , we declare that A
is the input wire
and B
is the output wire
. Wire
means that the signal needs to be driven always and it cannot hold a value on its own . Signals that can hold values are called reg
. A signal can be inout
as well.
assign
keyword is used here to invert the input and assign it to the output.
=
is a blocking assignment
and all statements assigning using a =
will happen sequentially. Non-blocking assignments
are denoted using <=
. All non-blocking assignments
in a block happens in parallel, at the same time.
Testbench
A testbench
is written as a seperate file, primarily since it is the “non-synthesizable” portion of the design, and is used to just validate the design. Consequently, it can have implement some “exotic” constraints and gimmicks.
Essentially, a testbench is like a top level module that encapsulates the design, feeds the design with input, and monitor the output. Generally, a test bench will not have any I/O signals.
A sample testbench file (myInv_tb.v
) for our ivnerter will look like:
module myModule_tb();
wire out;
reg clock;
initial begin
$dumpfile("inv.vcd");
$dumpvars(0,notGate);
clock=0;
#10
$finish;
end
always begin
#1
clock = !clock;
end
myInv notGate(clock,out);
endmodule
Breaking it down:
As described above, there are no I/O lines for a test bench. However, there is an internal register named clock
that will act as an input to myInv
and a wire out
that will capture the output.
This file illustrates one of the main concepts of HDL design. Unlike sequential programming languages, each block (initial and the “always”) executes in parallel. The designer has to keep this in mind always.
The initial
block will execute only once at t=0
, whereas the always
block is like an infinite loop.
Statements that starts with a $
sign are called tasks and are used by the simulator.
Statements starting with a #
are delay statements
. Execution will halt in that block for number of time units mentioned after the #
sign.
Thus, as per the initial
clock will be initialised to 0
at t=0
, and execution will end ($finish
) after 10
time units.
As per the always
block, clock will be inverted every one time unit.
An important point to note about the always block is that it can drive only reg type data and not wire type data.
Line 19
creates an instance of myInv
by the name notGate
and assigns clock
and out
to A
and B
.
$dumpfile
is the task used to open a waveform file named inv to capture the behavior of clock
and out
during simulation.
The 0
passed as first argument to $dumpvars
instructs the simulator to capture all signals of module instance notGate
. If a 1
is passed, only the signals named in the argument list will be captured in the output file.
“Synthesis” and Simulation
Execute the below command to synthesize
the module and test bench.
iverilog -o myInv.vvp myInv.v myInv_tb.v
This is not similar to hardware synthesis where we end up with a hardware netlist. Rather, here we synthesize a netlist named myInv.vvp
that the simulator can use.
To simulate this model, issue the following command
vvp myInv.vvp
At the end of simulation, a file named inv.vcd
will be created. This is the waveform file that can be opened in GTKWave.
Issue the following command to view the waveform. Expand the signal tree and drag & drop the signals the view to the Signals
list
gtkwave inv.vcd
More Verilog concepts
To introduce more verilog concepts, let us design a simple arbitrator. An arbitrator is a mechanism to avoid a collision (much like a mutex in software) . For example, when a device wants to access a bus along with many other devicec connected to the bus, instead of directly accessing it, the device will place a request the arbitrator for bus access and wait for the “grant” signal. The arbitrator liaisons all such requests.
Internally, an arbitrator is a simple statemachine with the below state diagram
At a block level, an arbitrator looks like the below figure:
This article is a work in progress. I will be updating it soon with more infomration as soon as I get some time off my dayjob. :smile:
Leave a comment