• No results found

Testbenches for sequential building blocks

In document Digital System Design With VHDL (Page 165-169)

sequential logic blocks

Q, Qbar : out std_logic);

6.8 Testbenches for sequential building blocks

In the last chapter, we considered testbenches for state machines. The function of those testbenches was to generate clock and reset signals, together with other data inputs. We considered how signals could be synchronized with the clock and how to monitor the states of output signals. In this chapter, we have seen how warnings can be generated when timing constraints of sequential elements are violated. While the testbench structures of the last chapter can be used to verify sequential building blocks in general, it would clearly also be desirable to simulate conditions under which timing violations can be checked. In this section, therefore, we will see how inputs can be generated at random times and how uncertainty can be added to the times of clock and data input changes. Later we will also use assert statements in testbenches to monitor outputs. First, however, we will see how to generate a clock with unequal high and low periods (mark to space ratio).

6.8.1 Asymmetric clock

This clock generation example in the last chapter models a clock with equal high and low periods. The following example shows a clock generator in which the frequency and mark/space ratio are parameters. Notice that the clock frequency is specified as a real number. This must be done for the example given to simulate correctly. If the fre-quency were specified as an integer, a mark period of, say, 45% would cause a clock to be generated with a period of 9 ns, and mark and space times of 4 ns and 5 ns, respec-tively, because of rounding errors. (Of course an integer could be converted to a real to achieve the same effect.) Note also that to get 4.5 and 5.5 ns, the resolution of the simulator must be set to 100 ps or less.

library IEEE;

use IEEE.std_logic_1164.all;

entity clock_gen is

generic (Freq : REAL := 1.0E8; -- 100 MHz

Mark: POSITIVE := 45); -- Mark length % end entity clock_gen;

architecture cg of clock_gen is -- Mark time in ns

constant ClockHigh :TIME := (REAL(Mark)*1.0E7/Freq)*NS;

-- Space time in ns

constant ClockLow :TIME := (REAL(100-Mark)*1.0E7/Freq)*NS;

signal clock : std_logic := '0';

Testbenches for sequential building blocks 151

begin

process is begin

wait for ClockLow;

clock <= '1';

wait for ClockHigh;

clock <= '0';

end process;

end architecture cg;

6.8.2 Random pulse generator

The VHDL Math Package (1076.2) contains a pseudo-random number generator, uniform, in addition to many other functions. A pseudo-random number generator uses techniques similar to that of the LFSR described above. From a given pair of start-ing values, or seeds, the same sequence will always be generated. The function uniformreturns a pseudo-random real number in the range 0.0 to 1.0.

We can use this function to generate, for example, a clock that changes on average every 10 ns, but with a random variation of 1 ns. As with the asymmetric clock, the resolution of the simulator must be set to 100 ps or better, otherwise the variation will always round to 0. This clock generator could be written as a process, as in previous examples. Having written such a generator, however, we might want to put it into a package for use elsewhere. We cannot put a process into a package, but we can write a procedure instead and put that into a package. Moreover a procedure can take parame-ters. For example, a complete package definition could be:

library IEEE;

use IEEE.std_logic_1164.all;

use IEEE.math_real.all;

package clocks is

procedure noisy_clk (signal clock : out std_logic;

delay : in DELAY_LENGTH);

end package clocks;

package body clocks is

procedure noisy_clk (signal clock : out std_logic;

delay : in DELAY_LENGTH) is variable seed1, seed2 : INTEGER := 42;

variable rnd : REAL;

begin loop

clock <= '0';

uniform (seed1, seed2, rnd);

wait for delay + (rnd - 0.5) * NS;

clock <= '1';

152 VHDL models of sequential logic blocks

uniform (seed1, seed2, rnd);

wait for delay + (rnd - 0.5) * NS;

end loop;

end procedure noisy_clk;

end package body clocks;

Notice that there is a loop in the procedure. A procedure can be called concurrently or from within a process or another sub-program. If this procedure is called concur-rently, it will execute once and finish. This is because a concurrent procedure call is equivalent to putting the procedure call inside a process, with wait statements trig-gered by the procedure input signals. As there are no input signals, the procedure would execute once. A suitable concurrent procedure call is:

c0: noisy_clk (clock, 7 NS);

If we want to model the behaviour of a clock and data whose relative timing is imperfect, it makes no difference if we apply the ‘jitter’ to the clock or to the data. We may also wish to model totally unsynchronized data. One widely used approximation to the random events arriving with a mean interval is the negative exponential function.

We can use a random event generator as follows:

library IEEE;

use IEEE.std_logic_1164.all;

use IEEE.math_real.all;

entity testrnd is end entity testrnd;

architecture testrnd of testrnd is signal r : std_logic := '0';

function negexp(rnd: REAL; t : TIME) return TIME is begin

return INTEGER (-log(rnd)*(REAL(t / NS))) * NS;

end function negexp;

begin

rand_wav: process is

variable seed1, seed2 : INTEGER := 199;

variable rnd : REAL;

begin

uniform (seed1, seed2, rnd);

wait for negexp(rnd, 10 NS);

r <= not r;

end process rand_wav;

end architecture testrnd;

This will generate a signal that toggles with a mean interval of 10 ns, but with a variation between 0.0 and infinity. This contains another example of a sub-program definition, in this case a function. Both procedures and functions can be included in packages or in architecture declarations, as shown.

Summary 153

6.8.3 Checking responses with assertstatements

In Section 6.2.5, the assert statement was introduced. In the examples given, the behav-iour of a model was checked within the model. It is just as valid to use assert statements to check responses within a testbench. Unlike most other VHDL statements, an assert statement can be used concurrently (outside a process) or sequentially (within a process).

Suppose two versions of a design are to be compared (for example, a gate level model and an RTL model). The two versions take the same inputs. To avoid contention, their outputs must have different signals. The two versions might be instantiated and their outputs compared as follows:

v0 : entity WORK.design(struct) port map (in_a, in_b, out_s);

v1 : entity WORK.design(rtl) port map (in_a, in_b, out_b);

assert out_s = out_b

report "Mismatch in behavioural and structural outputs"

severity NOTE;

Although simple to implement, this approach is flawed because any timing differences, however slight, will generate warning messages. In practice, it is very likely that there will be some differences between the outputs of two models at different levels of abstraction, but these differences will probably not be significant.

Therefore, it is preferable to compare responses only at specified strobe times. For exam-ple, we might wish to check responses 5 ns after a rising clock edge. This could be done as follows. Again, we will put the check inside a procedure so that it can be reused later.

procedure check(signal clock, out_s, out_b : in std_logic) is

begin

wait until clock = '1';

wait for 5 NS;

assert out_s = out_b

report "Mismatch in behavioural and structural outputs"

severity NOTE;

end procedure check;

As there are three inputs, note that we do not need a loop in this example – the proce-dure restarts whenever an input changes. All the inputs must be declared as signals. It is possible to pass the current value of a signal to a procedure by omitting the signal object declaration, in which case the value is passed as a constant. If this is done, the procedure will not restart when that signal changes.

Summary

In this chapter we have discussed a number of common sequential building blocks.

VHDL models of these blocks have been written using processes. Most of these models are synthesizable using RTL synthesis tools. We have also considered further examples of testbenches for sequential circuits.

154 VHDL models of sequential logic blocks

Further reading

As with combinational blocks, manufacturers’ data sheets are a good source of infor-mation about typical SSI devices. In particular, it is worth looking in some detail at the timing specifications for SRAM and DRAM devices. The multiplier is an example of how relatively complicated computer arithmetic can be performed. Hennessy and Patterson have a good description of computer arithmetic units.

Exercises

6.1 Explain how positive edge-triggered behaviour can be described in VHDL, where the std_logic type is used to represent bits and only a ‘0’ to ‘1’ transition is considered valid.

6.2 Write a behavioural VHDL model of a negative edge-triggered D flip-flop with set and clear.

6.3 Include tests for setup and hold time violation in the D flip-flop of Exercise 6.2.

6.4 Write a VHDL model of a negative edge-triggered T-type flip-flop.

6.5 Write a VHDL model of a 10-state synchronous counter that asserts an output when the count reaches 10.

6.6 Write a VHDL model of an N-bit counter with a control input ‘Up’. When the con-trol input is ‘1’ the counter counts up; when it is ‘0’ the counter counts down. The counter should not, however, wrap round. When the all 1s or all 0s states are reached the counter should stop.

6.7 Write a VHDL model of an n-bit parallel to serial converter.

6.8 Write a VHDL testbench for this parallel to serial converter.

6.9 What are the advantages and disadvantages of ripple counters as opposed to syn-chronous counters?

In document Digital System Design With VHDL (Page 165-169)