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.
Next page >