I thought I ordered a copy, but instead, a copy of Circuit Design and Simulation with VHDL arrived in the mail. I'm not quite sure how this happened, but this book was one of several listed in a column here on All Programmable Planet (APP) written by my fellow blogger William Murray: Learning FPGAs: What Do Other Engineers Recommend?. This book has a chapter on testbenches, so it will have to do (along with all of the Xilinx materials and the entire Internet, of course).
In my previous column, I created my project and used ISE to create the testbench. First, here's the original VHDL counter code. (Click here to see a larger, more detailed version of this image):
And here's the UCF (user constraints file). The UCF isn't needed for simulation, but it will be required for synthesis, so I created it at the same time. (Click here to see a larger, more detailed version of this image):
My code creates a simple 8-bit counter that displays on some LEDs (light-emitting diodes). To quickly recap the steps:
Create a project in ISE called "VHDLcountTB"
Add the two source files "VHDLcounter.vhd" and "VHDLcounter.ucf" to the project
Create a new source of type "VHDL Test Bench" named "VHDLcountTB"
Make sure that the radio button for "Simulation," at the top of the design window, is checked and the drop-down below it is set to "Behavioral"
@Duane, @Max, @Devel: This is a very interesting discussion for two reasons:
a) Although I am a humble beginner in VHDL/FPGA, I can completely follow the discussion. That is a very good ego massage;
b) I faced the types of critical thinking that is implied in the conversation in the classroom when I had schools of sophomore students come to me frustrated as they anxiously tried to simulate their digital circuits and got the "ugly" amber signal plots and the "ugly" label of their initial state as "U".
It appears all of you are on the same page. The "ugly" U label is a good device to be used for simulating realistic conditions during the start up phase of the system.
Duane: It looks to me like the specific VCC that a pin is pulled to with HSWAPEN enabled depends on the voltage of the bank the pin is in. Is that correct?
Duane Benson 3/8/2013 11:02:16 AM User Rank Blogger
Re: Uninitialized
Devel - "...those pins were on a 3.3V bank. But! The ADC's digital supply had to be 1.8V. LVDS..." This is exactly the scenario I was thinking about about. I had missed the HSWAPEN pin in my readings in the datasheet thus far. So, that pin would be physically tied to ground or one of the various VCCs which puts I/O pins into a specified state.
It looks to me like the specific VCC that a pin is pulled to with HSWAPEN enabled depends on the voltage of the bank the pin is in. Is that correct?
Duane, I can see if the input of a gate is undefined, then of course, so would the output. Thus whatever that gate output connects to would also be undefined, ad infinitum. But that seems overly simplistic.
Simple and correct.
If any input to a function is unknown or undefined, then necessarily the output of that function must be unknown or undefined. This really should be obvious. In my mind, what you should do is; say you really want a register to start at a 0 state, but you can't control what state it will power up in. It might start as either a 0 or a 1. You would need to ensure that having an initial value of 1 won't cause an undesirable result prior to the point at which it get initialized to 0.
And what you say above is exactly why resets and initializers are required. They force your logic into a known starting state. Prior to coming out of reset or prior to initialization, the state of the logic is completely unknown.
Now further think about real hardware. When the board powers up, all of the logic is in unknown states. And in the case of FPGAs, before the device is configured the I/O pins are in an unknown state too. What effect does the unknown state of an I/O pin have on the external device to which it is connected?
Well, in many cases, you actually don't care. Smart system design includes system-wide reset. Perhaps you have a reset supervisor which holds everything in reset until power supplies are stable. Perhaps you let a microcontroller boot and then it waits for the FPGA configuration to complete. At some point after power-up, all logic comes out of reset and is ready to go. But here is an interesting situation we ran into. We were using ADCs with an LVDS digital interface, connected to an FPGA. On the FPGA those pins were on a 3.3V bank. But! The ADC's digital supply had to be 1.8V. LVDS of course works (it's a 300mV-ish swing about 1.25V).
Xilinx FPGAs have the HSWAPEN (called something else on other families) which indicates whether all I/O pins should float during configuration or should be pulled up. The board with the FPGA and the ADCs configured the signals to be pulled up. (Nobody remembers why, and when the first rev of the board was designed, it was something that simply wasn't considered.) So this basically put 3.3V onto the ADC's outputs until configuration completed and the I/O pins turned into LVDS inputs. Yes, it's a weak pull-up but still I didn't know if the ADC's digital outputs had diode clamps. The fix, of course, was to put HSWAPEN into the other state and allow all of the I/O pins to float during configuration.
The good news is that in this particular case, the ADC digital output drivers weren't destroyed and the converters weren't degraded, so I was able to do a lot of testing while the board was re-spun (lots of other things to fix too).
Duane Benson 3/5/2013 11:32:29 AM User Rank Blogger
Re: Uninitialized
Devel - I'm struggling to wrap my head around the idea of an unknown state propagating through a design.
I can see if the input of a gate is undefined, then of course, so would the output. Thus whatever that gate output connects to would also be undefined, ad infinitum. But that seems overly simplistic.
In my mind, what you should do is; say you really want a register to start at a 0 state, but you can't control what state it will power up in. It might start as either a 0 or a 1. You would need to ensure that having an initial value of 1 won't cause an undesirable result prior to the point at which it get initialized to 0.
Duane Benson 3/5/2013 11:17:36 AM User Rank Blogger
Re: question for the VHDL experts
Devel - I almost went into "thinking like software mode" when reading your comment. Needing to put the library declaration at the start of each unit makes sense, as does putting the header file declaration at the top of each C file.
Then I started to wonder if the design unit would just call the entity from the library rather than creating it for each use... But, fortunately, I caught myself before going any further down that path.
Max Maxfield 3/5/2013 9:41:45 AM User Rank Blogger
Re: Uninitialized
@Duane: ...there could very well be two schools of thought on uninitialized / unknown start up states. One method could be to ensure that power-on states are as you want them. The other way would be to ensure that you design could operate properly regardless of the power-up state.
I would say that this is true as far as it goes -- but my own preference would be to ensure that the system comes up in a known state.
One other problem is when the power-on reset state differs from a regular reset. This often catches people out -- when they power up the system (board, chip, ...) they specifically force registers to certain values ... but later when they "pull a reset by hand" or whatever, they forget to explicitly set the state of some of the registers -- which means that sometimes a register might contain a 0 and sometimes a 1 (from whatever it was doing before the reset is pulled).
Duane: it just occurred to me that there could very well be two schools of thought on uninitialized / unknown start up states. One method could be to ensure that power-on states are as you want them. The other way would be to ensure that you design could operate properly regardless of the power-up state.
As we all should well know, you always want your simulation to match the real hardware.
So to that end: in your synthesizable code, go ahead and always include the initializers, even if they initialize a flip-flop to '0'. The bitstream will configure those registers as '0' anyways. Make the simulation match.
Do note, though, that a signal which is the target of a continuous (combinatorial) assignment can get an initializer BUT since there is no storage element involved, it makes no sense. So don't bother coding the initializer for such signals.
Now in your test bench, remember that you're modeling the stimulus that drives your DUT. In the real world, unless that stimulus has been properly reset, the values are not defined. Hence letting them be driven by 'U' until something resets them is reasonable. By default a signal that has not had an assignment goes out as 'U' and not 'X'.
Certainly, the 'U's will propagate through your FPGA. As you should expect. So adding initializers to the test bench signals is helpful but might mask the possibly bad things that happen when unexpected signal values are driven to your design's inputs.
Duane -- in your test bench, you include a component declaration for the DUT. It's not necessary. You can use the standard "direct instantiation" of the DUT entity. In the main part of the architecture (after the first begin), do the usual:
DUT : entity work.VHDLcounter
port map (
CLK_66MHz => CLK_66MHz,
LED => LED);
For most things, component declarations are completely unnecessary. Other advice threads here mention using this direct-instantiation technique instead of declaring components and then instantiating them in synthesizable code. There is no difference between that sort of use and here in a test bench.
Consider what happens if you have to add or remove signals from the DUT. You obviously edit the DUT source code to add/subtract the signals from the entity port list. Then you have to add/subtract them in the testbench in both the component declaration and the component instantiation. Too many places to make mistakes.
Now, here's a question for you VHDL experts: Did I need to uncomment Line 33 to declare "ieee.numeric_std.ALL" in the testbench? I already have this declared in my original VHDL counter code, so does that cover it?
You must always put all of the library use clauses at the start of any new design unit. (A design unit can be an entity or a package or a package body or the like. It is most common to have one design unit per source file, and a reasonable person gives the source file name the same thing as the design unit. So an entity called toplevel should be in a source file called toplevel.vhdl.)
The testbench entity is a different design unit from the DUT entity, therefore you must re-specify the library/use stuff.
But if you do not actually use anything that's pulled from a particular library in a given design unit, then you need not put the library/use clause before that design unit. So if the DUT needs numeric_std but the testbench entity doesn't, then the test bench doesn't need to have the use ieee.numeric_std.all specified.
Likewise, if your entity doesn't need std_logic_arith and std_logic_unsigned, then those library/use statements shouldn't be there -- even though Xilinx' stupid templates automatically include them.
Duane has decided that the time is ripe to get his ZedBoard bolted onto his robot with a Linux distribution up and running. That was the ultimate plan anyway, so why wait?
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.