We have all been there -- we've written some code, everything looks good, it compiles without problems, we load it into our FPGA, and... it doesn't work! We jump up and down, we break out the scope, and we swear at it, all to no avail. So we go to fetch the mending hammer... but wait! Before we use the hammer with "extreme prejudice," there is another way, which is to simulate the design using a testbench to show that it does what we expect it to do under all circumstances before we commit the little rascal to hardware.
The basic idea of the testbench is to take the design we wish to verify and instantiate it as the DUT (device under test) in a higher level module. This new top-level module then applies stimulus to the DUT and monitors its responses.
Testbenches can exhibit a wide range of complexity. For example, a simple testbench might apply a "reset" signal and a "clock" and verify that the design sort of does what we expect. By comparison, a more complex testbench might verify that the design meets all of its timing requirements and is strictly consistent with its original specification. In some cases, the testbench can be more complex than the DUT.
In order to illustrate some of these points, I have written a simple piece of code this is supposed to take a clock signal as an input and to divide that signal to a lower frequency using a linear feedback shift register (LFSR) as a counter (see also Max's LFSR Tutorial); so here is our code (click here to see a larger, more detailed version of this image):
Now, looking at this code, one might be forgiven for thinking "it does what it says on the tin." When the LFSR counter reaches a certain value, the "clock" output signal toggles and the LFSR is reset. However, there is a flaw in the code, which means that although it will compile with no errors, it won't actually work.
jandecaluwe 12/2/2012 12:58:15 PM User Rank Blogger
Re: My take-away from this article.
@rfrisbee "My take-away from the article is don't use hideous code as an example."
Really? Then I suggest to clean up the code to your liking, and check what you still have left.
What I take away from this article is that, currently on this site, it is possible for a blogger:
to write an article that is demonstrably wrong on any single technical point that it touches, including basic ones that are bound to confuse newbies hopelessly;
to draw nonsensical conclusions from the alledged behavior of his own public code, which turns out to behave in exactly the opposite way upon simple verification;
to publicly state that he does not care whether said code works or not;
rfrisbee 11/29/2012 5:50:29 AM User Rank Clever Clogs
Re: My take-away from this article.
My take-away from the article is don't use hideous code as an example. :-)
Particularly ugly was the use of a sensitivity list when the registers use a synchronous reset. To be brutally honest the code in the example looked like a software engineer (or someone who didn't think about the hardware circuit they were trying to describe) had written it.
More generally, what are people using async resets in FPGA designs for? The state of every FF can be defined after configuration by specifying a value in the signal declaration. The primary reason I see for using them is if there is a desire to port the design to an ASIC in the future.
My suggestion for writing reliable, understandable code is to stay away from processes with both synchronous and asynchronous signal assignments. A simple way to do this is start every sync process with a 'wait until rising_edge(clk);' statement. Simulation and synthesis tools will throw an error if such a process has a sensitivity list. E.g.,
count_ctrl : process
begin
wait until rising_edge(clk);
count <= count + 1;
end process count_ctrl;
I second the recommendation to spend time modelling the IO interfaces the FPGA connects to. The time spent writing a behavioural VHDL model of, say, an ADC which reads values from a text file generated by Scilab/Matlab/Excel is paid back tenfold when one can examine realistic data flowing through the datapath of a design.
jandecaluwe 11/27/2012 4:24:22 PM User Rank Blogger
Re: My take-away from this article.
"Provided my analysis is correct, we can be 100% sure that the code that was posted is not the code that he actually used."
I must correct myself here. Somebody pointed out to me that perhaps he was looking at the wrong place in the waveform - maybe he just didn't bother to do a full view to see the output clock toggling. That would be such a silly error that I didn't consider it.
Moreover, it wouldn't explain the FPGA behavior. So I stick to my hypothesis that the code he used was different from the one that was posted.
Here's a short list of problems I can think of from the top of my head, where simulation doesn't match reality.
- Async relase of resets always works in simulation, but not in practice
- In general any async input in general always work as expected in simulation - there are no delays in the IO block
- Simulation doesn't suffer from metastability induced errors
- Generated signals have no skew relative to each other. My memory controller simulatied fine but didn't work until I packed the output resisters ito the I/O block. It had data signals generated deep in the fabric, while the control signals were latched in the IOBs.
- Of course any errors in the vendor's models will trap you up.
Most of these are resolved by application of design standards, such as a solid reset strategy, always use synchronisers on async inputs, always constrain your I/O timings and so on.
I have also had something wierd happen with ODDR2 registers - I wanted |01|10|00, and saw that in simulation, but got |10|01|00| when I hooked up a logic analyser. Most probably my fault...
The proof in the pudding simulation wise is often the Post Place and Route Simulation -- that shows the CLB's and routes operating with the testbench post synthesis.
Simulation is just a simulation. Just as how RTL implemented in and FPGA may not work as it "should" due to physical limitations of the device and sematics of the synthisis tool, simulation has its own limitations and sematics too.
I must strongly disagree here.
Regarding physical limitations of the device. By that I assume you mean timing constraints and whether you meet them or not? Obviously, if the static timing analyzer says you lose, then you lose and all bets are off. If the static timing analyzer says you win, then you win, and a functional simulation that covers all cases correctly will work in real hardware. If if did not, then the millions of man-hours spent simulating HDL over the last three decades is little more than wanking.
jandecaluwe 11/27/2012 5:12:42 AM User Rank Blogger
Re: My take-away from this article.
@hamster "I'm not suprised that Jan might not be able to recreate Jerremy's issue - my timing differences for different use of IF and CASE statements was not apparent to somebody using Synopsys..."
No, that is an incorrect comparsion.
Your problem was related to synthesis. It is entirely normal that different synthesis tools give different results. The quality of the tools can be quite different, as is their pricing.
You should be very surprized that I'm not able to recreate the issue. I am not talking about synthesis or FPGAs here. This is just standard VHDL simulation. Any simulator should give exactly the same result.
My point is simply that the code with the delays added doesn't behave as he says it does. (He says that the output clock never toggles, but what I see is that it does, just like in the version without delays.) The code has been posted. You or anybody else interested can verify this in 15 minutes.
Provided my analysis is correct, we can be 100% sure that the code that was posted is not the code that he actually used.
And of course, that would explain why it didn't seem to work in the FPGA either. See my hypothesis of what may have happened - I owe it to you ;-)
Simulation is just a simulation. Just as how RTL implemented in and FPGA may not work as it "should" due to physical limitations of the device and sematics of the synthisis tool, simulation has its own limitations and sematics too.
When the sematics of synth and sim are closely two aligned (hopefully with you use one vendor's tools, and conservative design practices) then it is easy to avoid divergent results.
You can sometimes work around these issues by making your simulation closer to the physical implementation, by simulating propegation delays and so on, but doing so is a very tedious and tricky process.
The best thing an engineer can do is to think about what those limitations are, and stay clear of them them as much as you can.
The other problem for us engineers is that different device technologies and different toolsets have different issues. I'm not suprised that Jan might not be able to recreate Jerremy's issue - my timing differences for different use of IF and CASE statements was not apparent to somebody using Synopsys...
The Zynq-7000 All Programmable SoC uses the AXI protocol and buses to allow its Cortex-A9 processor system to communicate with, and control, custom logic implemented in the programmable fabric.
As an experiment I created a pipelined implementation of the DES algorithm in an FPGA. The result was an enormous improvement over what can be achieved in a software solution, even when using multi-core processors with multiple execution threads.
In which we define how each CA looks to the outside world -- it has a "clock" signal and a "reset" signal, and it also has signals that communicate its state to its neighbors along with signals that let it read its neighbors' states.
To save this item to your list of favorite All Programmable Planet content so you can find it later in your Profile page, click the "Save It" button next to the item.
If you found this interesting or useful, please use the links to the services below to share it with other readers. You will need a free account with each service to share an item via that service.