OK. Concept. Design for Debug. Yes. This probably means thinking more about the code before we write it, and probably writing more code, too. Is it worth it?
Well, we generally find that it takes 4 to 5 times longer for engineers to debug the code they write on our training courses, than it does for them to think about the design and write the code. Yep, the old 80 : 20 rule strikes again.
Let's look at one approach to designing easily debuggable code. We'll call the approach “destination assignment design” (TLA = DAD!).
Let's write a testbench for an arbitrary design. It can be any design, but the key issue is that the design has four modes of operation. For each mode we will need to define the stimulus for the design. The source of the stimulus we write is the mode of operation. Thus we can define the stimulus for each mode in a process, as follows...
-- inside an architecture -- assume signals are std_logic mode1: process begin -- assignments to input_1, input_2, input_3 end process mode1; mode2: process begin -- assignments to input_1, input_2, input_3 end process mode2; mode3: process begin -- assignments to input_1, input_2, input_3 end process mode3; mode4: process begin -- assignments to input_1, input_2, input_3 end process mode4; DUT: arbitrary port map (in_1 => input_1, in_2 => input_2, in_3 => input_3, out_1 => output_1, out_2 => output_2);
Using this coding style, we will need to ensure that the signal assignments are made in the correct temporal order, too.
Let's imagine that during simulation, we notice that the waveform of the signal input_3 is not as we intended. Yes, we need to debug the code.
Where do we begin? Any one (or two!) of the four processes could need examination; they might all need looking into. There's worse to come. It is possible there is a clash between the drivers in two of the processes on the signal input_3; this would show up as X's in the waveform viewer. This kind of problem is particularly hard to debug. Oh, of course! When you've found the clash between the mode1 and mode4 processes, you run the simulation again only to discover the clash is now between the mode1 and mode3 processes. Aaaaaarrrgh!
It is better to write the code as one process, as follows...
all_modes: process begin -- mode variable assigned here case mode is when mode_1 => -- assignments to input_1, input_2, input_3 when mode_2 => -- assignments to input_1, input_2, input_3 when mode_3 => -- assignments to input_1, input_2, input_3 when mode_4 => -- assignments to input_1, input_2, input_3 end case; end process all_modes;
In the single process style, we don't have to worry about temporal ordering of signal assignments and there is no possibility of multiple drivers.
We can take this approach one stage further. Each stimulus signal and the assignments to that signal are made in independent processes.
-- one of four processes sig_3: process (mode) begin case mode is when mode_1 => -- assignment to input_3 when mode_2 => -- assignment to input_3 -- and so on... end case; end process sig_3;
In the original code, we were writing code determined by the source of the stimulus behaviour, i.e., the mode of operation is the source.
The approach we have taken here is to write our code with a view to assigning values to the DUT inputs, the destinations of the stimulus functionality. If we need to debug the input_3 signal, we know exactly in which process to look. In addition, we won't get side tracked by other signal assignments floating around in that same process.
Oh, one last tip - wait until the bus stops before you get off!
Your e-mail comments are welcome - send email
Copyright 1995-2002 Doulos