How to write HDL code that works!
This is the season that people are scrambling for Main projects for their B-Tech and I had written some posts about how to go about selecting your final year project (So you want to do a VLSI Project Part I, Part II and Part III) I have got tremendous response for those posts but, I have found that lots of people are finding it hard to make the transition from a computer programming language background to coding using HDL(when I say HDL I am talking about Verilog and VHDL since these are the HDL’s I know about, so some of my generalizations may not hold good for other HDL’s and thus any such mistakes are due to my ignorance and any comments are welcome. But the point is that this post is aimed at college level projects and for them HDL should have the same meaning as I do). So here are some tips to do that.
As you would find in most text books ( For Verilog I would recommend Samir Palnitkar’s Verilog HDL- A Guide To Digital Design and synthesis ), the different level of abstractions are behavioral, data-flow gate level and switch level. Enough has be written about them and I would recommend reading about them (LINK) Generally most code you write would be a combination of behavioral and data-flow styles of coding. What an abstraction provides is a different way to describe the hardware, which will be useful depending on the context.
It is very important to understand the philosophy/History behind HDL’s to use them. This is that there are two major motivations behind most HDL’s the two motivations are -:
1. To describe Hardware
2. To describe Hardware stimulus
This is a very simplistic view, but one I feel, that should be adopted initially. The basic problem with this is that, most people think only about the 1st motivation and assume that the synthesizer is some magic wand which will be able to construct hardware for any code we write. While this might be true in the future since we are moving more and more to algorithmic/behavioral level description of the hardware with higher level synthesis tools, with current Verilog and VHDL its not the case. Hence there is part of the language that is non-synthesizable What this means is that the some code that you write may not be automatically converted into equivalent hardware by the synthesizer. There are two reasons this
You are using the so called non synthesizable constructs in the language. To give a simple example, to model external stimulus or to model real behavior we can use “wait” command which is a delay command. But if we try to synthesize it, it will either give a error or a warning. It will give an error for a stimulus block since stimulus is a sequence of signals and their timing information and hence do not have any hardware equivalent and if we are using the wait to model delays within a module, the module will the synthesized and the delays ignored.
To understand this better lets see an example. Assume that you are writing a code that interfaces with an external EEPROM. Now once you write the code of your module you need to prove that it will work once we burn it on to a FPGA. To do this we move on to a phase known as “simulation” where the description we made of the hardware is used to model the behavior of our device. Now this will result in a Zero-Delay or Ideal simulation as all the constructs we use will happen instantaneously (but they will still be controlled by a generated clock and a sense of time will be there but the output of ,say, a inferred AND gate will be propagated instantaneously without accounting for the actual propagation delay in hardware) in the simulation where as when hardware works in FPGA, the delays will be present. Also since you need to interface to the EEPROM, you need to have a “Model” of the EEPROM to test your design against. This HDL model, which will be provided by the EEPROM vendor, will not contain the functional definition of the EEPROM but will be a behavioral model specified using actual observed delays (it can be best-case, worst-case or average delays depending on the model) so that it can be simulated. So here in this example, the module/block you write will be (should be) synthesizable where as the EEPROM will be a non-synthesisable model just for simulation. Also there will be a “test-bench” which will ensure that the correct connections between the modules are done and also any other external stimulus the two blocks requires are provided, for example your module might be controlled by a micro controller whose signals will be simulated by a micro-controller model within your test bench which will be a striped down model to give the control signals for your module. I hope this example makes the use of both styles of coding clear.
You are writing code that does not make sense from a hardware point of view. One common error is a doubly clocked flop or signals with multiple drivers.For example if you write code like
always @ (posedge clk or negedge clk)
it will throw an error while synthesizing. Why? From a C view this is fine since you are asking the always block to be activated at either of two events. But think of it from the hardware perspective
Consider the following code
always @ (posedge clk or negedge rst)
begin
if ( rst==0)
D<=1′=b0;
else
D <= Q ;
end
seeing this code a hardware engineer should see a simple D flip flop and not an if statement. Taking this analogy back to the earlier code you will see that you are asking the synthesizer to infer a doubly clocked flop which is not possible in hardware.
Another important problem that confronts a new HDL coder is called the “Synthesis-Simulation mismatch”. What this essentially means is that unless certain rules are maintained, the simulator will interpret and model what you write in a different way than what the actual generated hardware will behave like. This can lead to two cases, one in which the Simulation will work and actual hardware wont and vice versa. Both are dangerous since in the fist case your hardware wont work and in the second case you wont go to the hardware level as your simulation fails. This is generally due to small issues like leaving out signals from the sensitivity list etc. Instead of re inventing the wheel, I would suggest you read the paper [1] for a better understanding of this phenomenon
It is always encouraged that you have a very good understanding of how the simulator and synthesis process works to help eliminate errors. While should be the aim in the long run, adherence to some basic rules would help weed out most issues.
-
Always think about get an image of the hardware that you want to produce in your mind and then code it. Though it might seem really hard to do this the idea is not to think of all the hardware at once but to split the design into blocks of combinational logic followed by flops (Sequential design lends itself to this)
-
Always try to separate the combinational block and sequential blocks into different always/process blocks. This helps in debugging errors later and also simplifies coding
-
When modeling sequential logic, use non-blocking assignments. For reasons for 3-10 see [2]
-
When modeling latches, use non-blocking assignments.
-
When modeling combinational logic with an always block, use blocking assignments
-
When modeling both sequential and combinational logic within the same always block, use non-blocking assignments.
-
Do not mix blocking and non-blocking assignments in the same always block.
-
Do not make assignments to the same variable from more than one always block.
-
Use $strobe to display values that have been assigned using non-blocking assignments
-
Do not make assignments using #0 delays.
-
If you are having to use #1 delays read this Verilog Non-blocking Assignments With Delays, Myths & Mysteries
-
Use asynchronous resets wherever possible ( Being a DFT engineer I should not say this as it complicates DFT ;)). Read [3] To understand more.
-
If you are using state machines in your design read State Machine Coding Styles for Synthesis.
-
Try to avoid Dangling wires Due to misspelling (very common!) or unused signals, there might be dangling wires in the design. The synthesis tool might optimize these wires away.
-
Specify all conditions explicitly for ‘case’ Statement or “if else” Statements - To avoid problems with inferred latches
-
Understand the differences between ‘case’ vs. ‘if – else’ Statements - In general, case statements would translate to parallel muxes in hardware. Meanwhile, the use of if – else statements results in priority-based hardware, which can slow down the overall implementation of the design. Thus, only use if – else statement when priority-based hardware is required. Otherwise, use case statements to avoid possible inefficient implementation of the design.
-
When using an always statement to implement combinational logic, the sensitivity list has to include all signals that appear on the right hand side of the assignments inside the. This is to avoid synthesis simulation mismatches.
Finally but a very important time saver can be to try and get hold of a good Linting tool so that a lot of these errors and others are caught before going to the FPGA stage.
I hope that this was helpful and more comments/tips/questions are welcome.
References
[1] RTL Coding Styles That Yield Simulation and Synthesis Mismatches (SunBust Design)
[2] Non-blocking Assignments in Verilog Synthesis, Coding Styles That Kill!(SunBurst Design)
[3] Synchronous Resets? Asynchronous Resets?I am so confused!How will I ever know which to use?(SunBurst Design)


Daa.. am not a hardware guy.. but started reading the post out of curiosity.. but stopped at this:
“when I say HDL I am talking about Verilog and VHDL since these are the HDL’s I know about, so some of my generalizations may not hold good for other HDL’s and thus any such mistakes are due to my ignorance and any comments are welcome but the point is that this post is aimed at college level projects and for them HDL should have the same meaning as mine”
WTF! so many lines of one single sentence! I felt breathless after reading thru it da
Comment by King Vishy — January 16, 2008 @ 12:30 pm
hehe
….that sentence can be called a exit-point for any future criticisms, so the more complex and exhaustive it is, the better 
Comment by cafm — January 16, 2008 @ 1:09 pm
The post was very helpful. I have encountered a few myself. The most common mistake i used to make was that of inferred latch since no errors are thrown up.
good reads those pdfs which u have linked to.
btw any forums or online journal sites which youve found resourceful.
Comment by ak_iyer — February 14, 2008 @ 11:39 pm
Hi AK,
I dont use any site other than synopsys solvent and the cadance equivalent.
Also there is a good yahoo group ASICDESIGN for it. Ever Clifford E Cummings sometimes posts in it.
For rest of the stuff my motto is…never fear, google is here
cafm-
Comment by cafm — February 18, 2008 @ 1:58 pm
Hi,
I am a B.E student ang my team has decided to work on vlsi project.Can u tell me some project titles suitable for B.E. level.
Comment by preshita — July 25, 2008 @ 10:07 am