In this post we talk about the FPGA design process in more detail. This includes a discussion of all of the main stages of the design process - architecting the design, modelling the FPGA design and testing our design. We also look at the differences between the two major hardware description languages (HDL) - verilog and VHDL.
In the previous post in this series, we saw an overview of the entire FPGA development process.
We saw from this how there are three main processes involved in an FPGA project - design, verification and implementation.
In the rest of this post we talk about the tasks which form the design process.
Whilst the main task here is writing code to create a model, there are other important aspects of this process. This includes architecting our chip and testing our model.
We talk about the FPGA implementation process and FPGA verification in more detail in separate posts.
The first stage of the design process is architecting the our design.
This involves breaking the design into a number of smaller blocks in order to simplify the VHDL coding process.
For large designs, this is especially beneficial as it allows engineers to work in parallel.
In this case, we should consider this an integral part of the process.
For smaller projects, we don't need to formally carry out this step. However, it is always worth considering the architecture closely before starting detailed design work.
The next stage in the process is the creation of a model of the design. We use this model to simulate the behaviour of our design and to build a programming file for our FPGA.
There are two main styles of modelling which we use for this process. These are commonly referred to as Register Transfer Level (RTL) and Gate Level.
Let's look at both of these in more detail.
Designs which use the RTL approach consist of code which describes the flow of data between registers within the FPGA.
Let's consider the example circuit below to demonstrate this concept.
In an RTL model of this circuit, we would write code which describes the behaviour of the two D type flip flops and the not gate.
The code shown below gives the VHDL implementation of this circuit. Don't worry if the syntax is unfamiliar at this point as it is not important.
dff1_d <= not dff2_q; dff1: process (clock) is begin if rising_edge(clock) then dff1_q <= dff1_d; end if; end process dff1; dff2: process (clock) is begin if rising_edge(clock) then dff2_q <= dff1_q; end ill end process dff2;
In this code, the first line models the behaviour of the not gate.
The flip flops, labelled as dff1 and dff2, are modelled using VHDL processes.
These processes latch the value of the input whenever there is a rising edge on the clock. This matches the expected behaviour of a D type flip flop.
We can see from this example how we are describing the behavior of the components in our design, as well as the interconnections between them.
This is the defining feature of RTL modeling in comparison to other types of modeling which simply define the connections between components.
Gate level modelling consists of code which defines the interconnection of different pre-existing components.
The code shown below is an example of gate level modelling. This implements the same double flip flop circuit we previously considered.
inverter : component not_gate port map ( inv_in => dff2_q, inv_out => dff1_d ); dff1 : component dff port map ( clock => clock, D => dff1_d, Q => dff1_q, Q_bar => open ); dff2 : component dff port map ( clock => clock, D => dff1_q, Q => dff2_q, Q_bar => open );
We can see that there are three separate components in this example model.
There are two instances of the dff component, which is an implementation of a D type flip flop.
In addition, there is a single instance of a not gate component.
We use signals to wire the IO of these components one another. This results in a physical implementation of the circuit we saw above.
It is rare that we will ever want to create a gate level model.
We discuss both of these processes in more detail in the post on the FPGA build process.
However, it is common to use RTL models which we have previously written as components in a similar manner.
The syntax for instantiating the components and wiring them up is the same as that used in gate level modelling.
Although this is similar to gate level modelling, the difference is that we don't directly use cells in the FPGA. This approach is known as structural RTL modelling.
Although HDL languages are commonly referred to as programming languages, they have little in common with traditional languages.
The way the CPU actually implement this program is unlikely to be of any real interest to us.
In contrast, when we write HDL code we are describing the behaviour of a digital circuit.
It is important to remember this different approach when designing FPGAs.
In fact, we have already seen this process in the simple example we used for RTL modelling. We started with a basic circuit and then wrote some VHDL which describes the behaviour of the circuit.
As this is an introductory post, we don't fully consider the details of verilog and VHDL in this post.
After reading these introductory posts, learning one of these languages should be the next step towards learning FPGA design.
One of the first questions many people have when learning FPGA design is whether they should learn VHDL or Verilog.
For anyone with ambitions of becoming a professional FPGA designer, it will be beneficial to learn both of these languages. So a more important question in this case is which language to learn first.
Whilst the two languages do have a number of differences, these are probably too subtle for beginners to fully appreciate.
In fact, even for professional engineers, a lot of the time it will come down to either personal preference or a pre-existing policy within a company.
When it comes to RTL modelling, geography is usually the main deciding factor in the choice of language to learn.
Verilog is the most used language by the big tech companies in California. Therefore, it makes sense to learn Verilog first for anyone hoping to work there.
In Europe, VHDL is more widely used and it makes sense to start with this language.
For hobbyists, verilog is also a good choice as it is generally less verbose.
For gate level modelling, Verilog is more popular than VHDL.
This is mainly due to the fact that it has an inherent ability to define the behavior of primitives. This means that we can define the behaviour of the cells within the FPGA using a language feature known as user defined primitives.
This is particularly useful for chip vendors who must develop libraries which define the behavior of cells in their chips.
Simulations which use verilog based models also tend to have faster execution times than VHDL equivalents.
After architecting and coding our FPGA design, we then need to test our model.
This is essential for identifying bugs and proving that our model functions as expected.
Although we often have a separate verification teams for larger designs, some tests should be conducted by the designer.
This will eliminate the most obvious and easy to find bugs before verification begins.
As a result, the verification team can focus on more thoroughly testing the design, identifying more subtle bugs.
Typically, our testing will consist of 2 parts - fixing compilation errors and functional simulations.
Let's look at both of these in more detail.
As a first step in simulating a design, we must compile the code.
This process turns the functional HDL code into a model or executable file. This file is then used by the simulation tool to emulate the behaviour of the design.
During this process, the compilation tool will create a number of warnings. These are issues with the code which won't prevent compilation but may lead to simulation errors.
Some examples of this include deprecated code constructs, non-synthesizable code or errors in vector sizing.
One example common example of a warning is attempting to assign an 8 bit signal with 9 bits of data.
It is normal for the designer to correct these warnings before running any simulations.
For large designs, this can be a time consuming task and it is likely that not all warnings are fixable.
It is also common for the solution to the warnings to alter the behaviour of our model.
If using a formal process, we should at least fix the warnings before beginning the verification process.
When a separate verification process isn't required, we should fix these warnings before beginning the implementation stage.
Even when working with a formal verification process, the FPGA designer is normally expected to carry out basic functional testing.
This is where the lines between verification and design can start to become quite blurred, particularly for small chips.
Functional simulations in this context involve creating tests which emulate the normal operating conditions of the circuit.
This allows the designer to fix the most obvious functional bugs before verification begins.
This means the verification team can utilise their time developing more sophisticated tests. This is likely to lead to the verification process discovering more subtle bugs.
For hobbyists, there is no need to go any further than this level of simulation. There is also no need to do any more testing than this for small projects.
The exception to this is for projects where we are following a formal process such as DO-254.
When we are working on large projects then verification is going to be much more comprehensive than this.
This is also the case when we are following a formal design process.
In these cases, we should treat the verification of our FPGA as a separate, formal process.