Tải bản đầy đủ (.pdf) (28 trang)

CPU- RTL Simulation

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (311.84 KB, 28 trang )

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 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: RTL Simulation
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: RTL Simulation
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: RTL Simulation
-- 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: RTL Simulation
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”;
339
CPU: RTL Simulation
read(l, space); --- skip a space
-- read din value
read(l, tmpdin, good_val);
assert good_val REPORT “bad din value”;
read(l, space); --- skip a space
---- the difference in the file is below
-- read good output value
read(l, tmpqout, good_val);
assert good_val REPORT “bad qout value”;
-- Compare outputs
assert tmpqout = qout REPORT “vector mismatch”;
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 full;
The full testbench looks exactly the same as the stimulus only test-
bench for most of the file. The full testbench has a top-level entity with
no ports, an architecture that instantiates the DUT, and a
while
loop that
reads a vector file. The differences are in the
while
loop itself. The first
part of the
while
loop is exactly the same. The process reads a time value
and waits for that time value to occur. The full testbench is different in that,
not only does the full testbench read the input values, but it also reads the
output values and then performs a compare operation between the output
values from the DUT versus the values read from the file. If a mismatch
is found, an assertion message is generated to let the designer know that
the output results did not match the known good results.
The full testbench also reads from a vector file to get the stimulus for
the design and the expected results. The vector file contains a time value,
the input values, and the expected output values. Following is the full
testbench vector file:
--- vector file for counter
-- time clk ld up_dwn clk_en din dout
0 0001 0 0
10 1001 0 255

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×