Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 28 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
28
Dung lượng
311,84 KB
Nội dung
CPU: RTLSimulation In this chapter, a VHDL simulator is used to verify the functionality of the CPU VHDL RTL description. The VHDL RTL description of the CPU is simulated with a standard VHDL simulator to verify that the description is correct. A simulator needs two inputs: the description of the design and stimulus to drive the design. Sometimes designs are self-stimulating and do not need any external stimulus, but in most cases, VHDL designers use a VHDL testbench of one kind or another to drive the design being tested. The structure of the design looks like Figure 14-1. The top-level design description instantiates two components: the first being the design under test (DUT) and the second the stimulus driver. These components are connected with signals that represent the external envi- ronment of the DUT. The top level of the design does not contain any external ports, just internal signals that con- nect the two instantiated components. 14 14 CHAPTER Chapter Fourteen 330 Top Level Stimulus Driver Design Under Test Figure 14-1 Top-Level Design Structure. Testbenches A testbench is used to verify the functionality of a design. The testbench allows the design to verify the functionality of the design at each step in the HDL synthesis-based methodology. When the designer makes a small change to fix an error, the change can be tested to make sure that it did not affect other parts of the design. New versions of the design can be verified against known good results to verify compatibility. A testbench is at the highest level in the hierarchy of the design. The testbench instantiates the design under test (DUT). The testbench provides the necessary input stimulus to the DUT and examines the output from the DUT. Figure 14-2 shows a block diagram of how this process appears. The testbench encapsulates the stimulus driver, known good results, and DUT, and contains internal signals to make the proper connections. The stimulus driver drives inputs into the DUT. The DUT responds to the input signals and produces output results. Finally, a compare function within the testbench compares the results from the DUT against those known good results and reports any discrepancies. That is the basic function of a testbench, but there are a number of methods of writing a testbench and each method has advantages and disadvantages. 331 CPU: RTLSimulation Testbench Stimulus Driver DUT OK Errors Good Results Figure 14-2 Testbench Block Diagram. Kinds of Testbenches There is a myriad of ways to write a testbench, but some of the most com- mon are described in this section. The following are the most common testbench types: ■ Stimulus only — Contains only the stimulus driver and DUT; does not contain any results verification. ■ Full testbench — Contains stimulus driver, known good results, and results comparison. ■ Simulator specific — Testbench is written in a simulator-specific format. ■ Hybrid testbench — Combines techniques from more than one testbench style. ■ Fast testbench — Testbench written to get ultimate speed from simulation. To show the different types of testbenches, a common example is used. To make it simple to understand the stimulus and response, a counter example is used. The following description is the package, entity, and ar- chitecture for an 8-bit counter: Chapter Fourteen 332 PACKAGE count_types IS SUBTYPE bit8 is INTEGER RANGE 0 to 255; END count_types; LIBRARY IEEE; USE IEEE.std_logic_1164.all; USE work.count_types.all; ENTITY count IS PORT (clk : IN std_logic; ld : IN std_logic; up_dwn : IN std_logic; clk_en : IN std_logic; din : IN bit8; qout : INOUT bit8); END count; ARCHITECTURE synthesis OF count IS SIGNAL count_val : bit8; BEGIN PROCESS(ld, up_dwn, din, qout) BEGIN IF ld = ‘1’ THEN count_val <= din; ELSIF up_dwn = ‘1’ THEN IF (qout >= 255) THEN count_val <= 0; ELSE count_val <= count_val + 1; END IF; ELSE IF (qout <= 0) THEN count_val <= 255; ELSE count_val <= count_val - 1; END IF; END IF; END PROCESS; PROCESS BEGIN WAIT UNTIL clk’EVENT AND clk = ‘1’; IF clk_en = ‘1’ THEN qout <= count_val; END IF; END PROCESS; END synthesis; Package count_types contains the type declaration for the 8-bit signal type used in the counter. The counter is loadable, counts up and down, and contains a clock enable. The counter is implemented as two processes: a 333 CPU: RTLSimulation combinational process and a sequential process. The combinational process calculates the next state of the counter, and the sequential process keeps track of the current state of the counter and updates the next state of the counter on a rising edge of the clk input. We use the counter to dis- cuss a number of different types of testbenches. Stimulus Only The stimulus only testbench contains the stimulus driver and DUT blocks of a testbench. The verification process is left to the designer. This type of testbench is useful at the beginning of a design project when no known good vectors exist, or for a quick check of an entity. Following is an example stimulus only testbench: ENTITY testbench IS END; ----------------------------------------------------------- -- STIMULUS ONLY -- testbench for 8-bit loadable counter -- reads from file “counter.txt” ----------------------------------------------------------- LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE std.textio.ALL; USE ieee.std_logic_textio.all; USE WORK.count_types.all; ARCHITECTURE stimonly OF testbench IS ----------------------------------- -- component declaration for counter ----------------------------------- COMPONENT count PORT (clk : IN std_logic; ld : IN std_logic; up_dwn : IN std_logic; clk_en : IN std_logic; din : IN bit8; qout : INOUT bit8); END COMPONENT; SIGNAL clk, ld, up_dwn, clk_en : std_logic; SIGNAL qout, din : bit8; BEGIN -- instantiate the component uut: count PORT MAP(clk => clk, ld => ld, up_dwn => up_dwn, Chapter Fourteen 334 clk_en => clk_en, din => din, qout => qout); -- provide stimulus and check the result test: PROCESS VARIABLE tmpclk, tmpld, tmpup_dwn, tmpclk_en : std_logic; VARIABLE tmpdin : integer; FILE vector_file : text IS IN “counter.txt”; VARIABLE l : line; VARIABLE vector_time : time; VARIABLE r : real; VARIABLE good_number, good_val : boolean; VARIABLE space : character; BEGIN WHILE NOT endfile(vector_file) LOOP readline(vector_file, l); -- read the time from the beginning of the line -- skip the line if it doesn’t start with a number read(l, r, good => good_number); NEXT WHEN NOT good_number; vector_time := r * 1 ns; -- convert real number to time IF (now < vector_time) THEN -- wait until the vector time WAIT FOR vector_time - now; END IF; read(l, space); --- skip a space -- read clk value read(l, tmpclk, good_val); assert good_val REPORT “bad clk value “; -- read ld value read(l,tmpld, good_val); assert good_val REPORT “bad ld value “; -- read up_dwn value read(l,tmpup_dwn, good_val); assert good_val REPORT “bad up_dwn value “; -- read clk_en value read(l,tmpclk_en, good_val); assert good_val REPORT “bad clk_en value “; read(l, space); --- skip a space 335 CPU: RTLSimulation -- read din value read(l, tmpdin, good_val); assert good_val REPORT “bad din value “; clk <= tmpclk; ld <= tmpld; up_dwn <= tmpup_dwn; clk_en <= tmpclk_en; din <= tmpdin; END LOOP; ASSERT false REPORT “Test complete”; WAIT; END PROCESS; END; The beginning of the testbench declares entity testbench as an entity with no ports. This is completely legal as the testbench is the topmost en- tity and does not interract with any other entities. Next is the architecture declaration. The architecture uses a number of packages including IEEE standard packages and counter. The next section in the model declares the component for the DUT (Device Under Test), the counter. The ports and types on this component should match the DUT. Next, the local interconnect signals are declared. After the archi- tecture declaration section, the DUT component is instantiated and con- nected to the local interconnect signals. A process called test is declared which contains the stimulus generation capability. First, a number of local variables are declared to receive data from the TextIO procedures used to read the stimulus information from a file. TextIO can only assign to variable objects not signals; therefore, local variables are assigned by the TextIO procedures, and these variables are assigned to the internal interconnect signals. Inside the process is a single while loop that reads data from the stimulus file until an end-of-file condition is reached. Each pass through the loop reads another line from the file and reads the appropriate data from that line. The first data read from the line is the time that this vector is to be applied. The process checks to make sure that the value read is a valid number. If not, the line is discarded because it does not represent a valid stimulus line. This allows comment lines to be inserted in the vector files. If a valid number was not read, the process skips this iteration through the loop and goes to the next iteration using the next clause. If the value read was a good number, then the vector is assumed to be valid. The process reads each data value from the vector and applies the values to the locally declared variables. Chapter Fourteen 336 In the counter example, the first value read is the clk signal. The Tex- tIO statement reads a STD_LOGIC value from line l and assigns the value read to variable tmpclk . Later, the tmpclk variable is assigned to the signal clk . The process continues to read a line, read a time value, wait until that time value occurs, read all vector values, and apply vector values until the end of the file is reached. When the end of the file is reached, the loop terminates, an assertion message is written to standard output, and the process waits forever. The WAIT statement after the assertion at the end of the loop doesn’t have a termination condition and, therefore, waits forever, effectively stopping execution of this process. The TEXTIO readline statement inside the while loop reads a vector line from a vector file. Following is an example vector file: --- vector file for counter -- time clk ld up_dwn clk_en din 10 0001 0 20 1101 50 30 0001 0 40 1001 0 50 0001 0 60 1001 0 70 0001 0 80 1001 0 90 0001 0 100 1101 10 110 0001 0 120 1001 0 130 0001 0 140 1001 0 150 0001 0 160 1001 0 The first two lines of the vector file do not start with valid numbers and are treated as comment lines. Comment lines can be embedded anywhere in the file. Comments can also be placed at the end of a vector because any data after the last field of the vector are ignored. Each vector line starts with a time value and then contains a string of values to be assigned to the DUT at that time. Spaces can be embedded between vector values if a corresponding read function exists in the while loop to skip the space. For the stimulus only testbench, the test process reads a vector from the file and applies the stimulus to the DUT. The stimulus only testbench does not check the output results of the DUT in reaction to the applied stimulus. The stimulus only testbench is most useful for a quick check of a piece of a design that is easy for the designer to verify manually or for 337 CPU: RTLSimulation early in the design process when no known good results exist to verify against. When the results are verified, these results become the known good results to verify future versions or minor changes to the design. Full Testbench A full testbench is very similar to a stimulus only testbench except that the full testbench also includes the capability to check the output of the DUT. The full testbench applies the stimulus to the design and then examines the outputs of the design to see if the output results of the DUT match known good results. Following is a full testbench for the counter: ENTITY testbench IS END; ------------------------------------------------------------ -- FULL TESTBENCH -- testbench for counter -- reads from file “counter.txt” ------------------------------------------------------------ LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE std.textio.ALL; USE ieee.std_logic_textio.all; USE WORK.count_types.all; ARCHITECTURE full OF testbench IS ----------------------------------- -- component declaration for counter ----------------------------------- COMPONENT count PORT (clk : IN std_logic; ld : IN std_logic; up_dwn : IN std_logic; clk_en : IN std_logic; din : IN bit8; qout : INOUT bit8); END COMPONENT; SIGNAL clk, ld, up_dwn, clk_en : std_logic; SIGNAL qout, din : bit8; BEGIN -- instantiate the component uut: count PORT MAP(clk => clk, ld => ld, Chapter Fourteen 338 up_dwn => up_dwn, clk_en => clk_en, din => din, qout => qout); -- provide stimulus and check the result test: PROCESS VARIABLE tmpclk, tmpld, tmpup_dwn, tmpclk_en : std_logic; VARIABLE tmpqout, tmpdin : bit8; FILE vector_file : text IS IN “counter.txt”; VARIABLE l : line; VARIABLE vector_time : time; VARIABLE r : real; VARIABLE good_number, good_val : boolean; VARIABLE space : character; BEGIN WHILE NOT endfile(vector_file) LOOP readline(vector_file, l); -- read the time from the beginning of the line -- skip the line if it doesn’t start with a number read(l, r, good => good_number); NEXT WHEN NOT good_number; vector_time := r * 1 ns; -- convert real number to time IF (now < vector_time) THEN -- wait until the vector time WAIT FOR vector_time - now; END IF; read(l, space); --- skip a space -- read clk value read(l, tmpclk, good_val); assert good_val REPORT “bad clk value”; -- read ld value read(l, tmpld, good_val); assert good_val REPORT “bad ld value”; -- read up_dwn value read(l, tmpup_dwn, good_val); assert good_val REPORT “bad up_dwn value”; -- read clk_en value read(l, tmpclk_en, good_val); assert good_val REPORT “bad clk_en value”; [...]... advances simulation time and runs the simulation All of the input values are propagated appropriately through the design After the run command has finished, the new input stimulus values are set up with more force commands, and the simulation is run again This process continues until all stimulus has been run through the design The write command near the end of the file writes the results of the simulation. .. signal conditions force ld 0 force up_dwn 0 force clk_en 1 force din 16#00 run the simulation run 100 - set next signal conditions force ld 1 force up_dwn 0 force clk_en 1 force din 16#AA - run the simulation run 200 - set next signal conditions force ld 1 force up_dwn 0 force clk_en 1 force din 16#55 - run the simulation run 200 write list data.out quit -f The command language used for this testbench... designs, load designs, create libraries, set breakpoints, run the simulation, and lots of other tasks using the simulator command language Most of these simulators also allow the designer to set signals to new values Using command languages, the designer can write a testbench Following is an example of a simulator-specific testbench: CPU: RTLSimulation 341 setup the clock force -repeat 20 clk 0 0, 1... and Disadvantages Stimulus Only Full Simulator Specific Hybrid Fast Speed Slow Slow Medium Medium Extremely Fast Flexibility High High High Medium Low Portability High High Low High High CPU: RTLSimulation 349 CPU Simulation Simulating the CPU design is different from most other entities because the CPU design doesn’t need much outside stimulus The memory device provides the input data for the CPU much... Array Chapter Fourteen CPU: RTLSimulation 355 at 16 Figure 14-10 shows the destination array before the copy operation has completed The destination array starts at location 48 and ends at location 63 The destination array is shown after two copy operations have been performed Notice that location 48 has the first value, and location 49 has the second value A complete simulation run completely copies... testbench for 8-bit loadable updown counter reads from file “counter.txt” -LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE std.textio.ALL; USE ieee.std_logic_textio.all; CPU: RTLSimulation 343 USE WORK.count_types.all; ARCHITECTURE hybrid OF testbench IS component declaration for counter COMPONENT count PORT (clk : IN std_logic; ld : IN std_logic;... clock from the vector file The vector file contains changes only on signals other than clock This results in a much smaller file that can be read much faster Following is the hybrid vector file: CPU: RTLSimulation 345 - vector file for counter time ld up_dwn clk_en din 10 001 0 20 101 50 30 001 0 100 101 0 110 001 0 250 101 35 260 001 0 If this example were a full testbench, the vector file would... how fast a simulation can run This is especially true of the testbenches that read data from vector files These files can become very large, and the time it takes to read a vector and process the vector can be the limiting factor in how fast the simulator executes The same can be true of the simulator-specific testbench if the simulator does not read the entire command file in at the start of simulation. .. file in at the start of simulation If the file is read in chunks, the file read operation can significantly slow the simulation To get around these problems, a designer can elect to use a fast testbench The fast testbench is optimized for speed and typically does not limit the speed of the simulation, unless the design is very small Following is an example fast testbench: ENTITY testbench IS END; ... 10), (20 ns, ‘1’, ‘0’, ‘1’, 100, 2), (30 ns, ‘0’, ‘0’, ‘1’, 0, 0), (100 ns, ‘1’, ‘0’, ‘1’, 55, 8), (110 ns, ‘0’, ‘0’, ‘1’, 0, 0), (150 ns, ‘1’, ‘0’, ‘1’, 150, 58), (160 ns, ‘0’, ‘0’, ‘1’, 0, 151), CPU: RTLSimulation 347 (250 ns, ‘1’, ‘0’, ‘1’, 201, 160), (260 ns, ‘0’, ‘0’, ‘1’, 0, 161)); VARIABLE ev_time : time; BEGIN FOR i in stim_array’RANGE LOOP ev_time := stim_array(i).event_time; IF (now < ev_time) . CPU: RTL Simulation In this chapter, a VHDL simulator is used to verify the functionality of the CPU VHDL RTL description. The VHDL RTL description. writing a testbench and each method has advantages and disadvantages. 331 CPU: RTL Simulation Testbench Stimulus Driver DUT OK Errors Good Results Figure 14-2