133
VHDL Verification Course Verification is an important part of any ASIC design cycle. It's important that complex designs are simulated fully before prototypes are built, as it's difficult to find bugs in silicon and going through additional layout cycles is costly and time consuming. VHDL is well suited for verification. This course is an introduction to VHDL verification techniques. It assumes some familiarity with VHDL. © Stefan Doll, [email protected] Table of Contents Basic Stimulus Generation Testbench Structure Definition of Terms Writing to Files Reading from Files More Reading from Files The World of Perl SRAM modeling Passive SRAM Model Signal Monitors Generating Clock and Reset Stimulus Approaches to Test Generation File Read Method VHDL pre-processing Method Test-specific Entities Configuration controlled Test Selection Using Transaction Logs Using Transaction Logs II Using Behavioural Models Recommended Directory Structure Test Strategy The End Sponsor: BIO-SMG http://www.stefanvhdl.com/vhdl/html/index.html [1/13/2009 3:54:26 PM]

Stefan Doll-VHDL Verification Course-UPDATED

Embed Size (px)

Citation preview

Page 1: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Verification is an important part of any ASIC design cycle. It's important that complex designs are simulated fully before prototypes are built, as it's difficult to find bugs in silicon and going through additional layout cycles is costly and time consuming.

VHDL is well suited for verification. This course is an introduction to VHDL verification techniques. It assumes some familiarity with VHDL.

© Stefan Doll, [email protected]

Table of Contents

Basic Stimulus Generation Testbench Structure Definition of Terms Writing to Files Reading from Files More Reading from Files The World of Perl SRAM modeling Passive SRAM Model Signal Monitors Generating Clock and Reset Stimulus

Approaches to Test Generation File Read Method VHDL pre-processing Method Test-specific Entities Configuration controlled Test Selection Using Transaction Logs Using Transaction Logs II Using Behavioural Models Recommended Directory Structure Test Strategy The End

Sponsor: BIO-SMG

http://www.stefanvhdl.com/vhdl/html/index.html [1/13/2009 3:54:26 PM]

Page 2: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Basic stimulus generation and verification

First basic stimulus generation is demonstrated. A simple XOR build from AND and OR gates is used as an example. An extra term is added to deliberately introduce an error.

y <= (x1 and not x2) or (x2 and not x1) or (x1 and x2);

It's possible to generate stimulus using a process with signal assignments and wait statements as shown below:

test_seq: process

begin

x1 <= '0'; x2 <= '0'; wait for 10 ns;

x1 <= '1'; x2 <= '0'; wait for 10 ns;

x1 <= '0'; x2 <= '1'; wait for 10 ns;

x1 <= '1'; x2 <= '1'; wait for 10 ns;

x1 <= 'X'; x2 <= 'X';

...

end process test_seq;

http://www.stefanvhdl.com/vhdl/html/basic_stim_gen.html (1 of 4) [1/13/2009 3:54:30 PM]

Page 3: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

This code can now be simulated and it's possible to identify the design error by observing the waveforms:

However it's more efficient to build in checks which automatically verify the result of a simulation. This can be accomplished with the use of assert statements. An assert statement verifies that a certain condition holds true. If the condition is violated it will generate the associated message and will attach the specified severity level to it. The example VHDL code could be extended like this:

....

wait for 10 ns;

x1 <= '1'; x2 <= '1'; assert y = (x1 xor x2) report "E@TB: circuit failed" severity Error;

wait for 10 ns;

...

A simulator executing the code will produce output similar to this:

# ** Error: E@TB: circuit failed # Time: 40 ns Iteration: 0 Instance: /tb1

Ideally the assert statement should provide information about the condition in which the error occurred.

http://www.stefanvhdl.com/vhdl/html/basic_stim_gen.html (2 of 4) [1/13/2009 3:54:30 PM]

Page 4: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

This will aid debugging substantially. Below are two alternatives to the previous assert statements. One uses the 'image attribute from the VHDL 93 standard. The other uses the conversion function str() from package txt_util.vhd which is used extensively throughout this course. The package provides a somewhat less cumbersome way to handle string processing and similar tasks.

assert y = (x1 xor x2) report "E@TB: failure at: x1="& std_logic'image(x1)& " x2="& std_logic'image(x2) severity Error;

assert y = (x1 xor x2) report "E@TB: failure at: x1="& str(x1)& " x2="& str(x2) severity Error;

Shown below is the output of the two assert statements. It's now much easier to identify the cause of the problem.

# ** Error: E@TB: failure at: x1='1' x2='1' # Time: 40 ns Iteration: 0 Instance: /tb1

# ** Error: E@TB: failure at: x1=1 x2=1 # Time: 40 ns Iteration: 0 Instance: /tb1

A standard format for error messages will also help to identify the location of a bug. The standard adopted here uses the first letter to indicate the severity (I=Information, W=Warning, E=Error, F=Failure) followed by "@" and the entity name of the unit which generated the message. The "E@" notation makes it very easy to grep long logfiles and identify problems. Knowing the entity which detected a bug will aid fixing it, too.

Below are the files which have been simulated in this section:

txt_util.vhd

tb1.vhd

Note: The txt_util package requires a VHDL 93 compatible simulator.

http://www.stefanvhdl.com/vhdl/html/basic_stim_gen.html (3 of 4) [1/13/2009 3:54:30 PM]

Page 5: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

http://www.stefanvhdl.com/vhdl/html/basic_stim_gen.html (4 of 4) [1/13/2009 3:54:30 PM]

Page 6: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Testbench Structure

In the previous section both the design and the test code were located in the same file. This approach was only taken for demonstration purposes and is not recommended in the general case. Typical testbench code - such as text output and assert statements - can not be synthesized and will at the very least create a number of unnecessary warnings from the tool. Also testbench code can have similar complexity as design code and if it's well structured, is quite likely to be reusable.

The following diagram shows a typical testbench structure:

In this example the top level entity (testbench) instantiates four components: the processor transactor, the RAM model, the I2C-Controller transactor and the design which needs to be tested (DUT). Each testbench component and the top level testbench are in their own files, the DUT is also in a separate file.

http://www.stefanvhdl.com/vhdl/html/tb_structure.html (1 of 2) [1/13/2009 3:54:31 PM]

Page 7: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

The testbench components produce stimulus and verify the response from the DUT.

http://www.stefanvhdl.com/vhdl/html/tb_structure.html (2 of 2) [1/13/2009 3:54:31 PM]

Page 8: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Definition of Terms

The following terms are used frequently in literature. Despite of the statement in the heading, there are no hard definitions, but the following should reflect common usage:

● Model A model is a description of the device which behaves just like the device does. Generally the behaviour can not be controlled by any other way then applying stimulus to it's input pins. RAMs are usually described in this way.

● Transactor Transactors have additional control mechanisms: they can read control data from a file or contain test specific code. They control which test is run in the testbench in which they are instantiated.

● Bus Functional Model (BFM) A BFM is a model of a device as it appears on a bus. E.g. a processor model coded in this fashion would only contain read and write processes, and none of the internal processing (no ALU, registers etc).

http://www.stefanvhdl.com/vhdl/html/definitions.html [1/13/2009 3:54:32 PM]

Page 9: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Writing to Files

Writing to files can be useful in a VHDL simulation. This section will illustrate how to implement that with VHDL 93.

Here is the header of an example program:

library ieee; use ieee.std_logic_1164.all;

use std.textio.all; use work.txt_util.all;

entity FILE_LOG is generic ( log_file: string := "res.log" ); port( CLK : in std_logic; RST : in std_logic; x1 : in std_logic; x2 : in std_logic_vector(7 downto 0) ); end FILE_LOG;

For the purpose of this example two signals x1 and x2 shall be logged to a file on every rising clock edge.

To operate on files they need to be declared:

architecture log_to_file of FILE_LOG is

file l_file: TEXT open write_mode is log_file;

begin

Here l_file is the file, it's of type TEXT and opened in write mode. The log_file parameter is of type

http://www.stefanvhdl.com/vhdl/html/file_write.html (1 of 4) [1/13/2009 3:54:34 PM]

Page 10: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

string and usually assigned with a generic as shown above.

The following loop will log x1 and x2 into the file specified by log_file:

while true loop write(l, str(x1)&" "& hstr(x2)& "h"); writeline(l_file, l); end loop;

As can be seen VHDL writes to a file in two steps: first a string is written to a variable of type line (that's what the write command does), then the line is appended to a file with the writeline command.

In the example shown here x1 is of type std_logic and x2 of type std_logic_vector. The function str() will convert x1 in a string, the function hstr() will convert x2 in a string in hex format. (Both functions are in txt_util.vhd). Strings and characters can be combined into a larger string with the & operator.

The txt_util package provides a simpler way to write to a file, e.g. with:

print(l_file, str(x1)& " "& hstr(x2)& "h");

Which fits into a single line and doesn't require a line type variable. Also since the input to print is always a string no type casting is necessary.

The usage can be illustrated by inserting the lines below in front of the while-loop. (The code will generate a header for the log file.)

print(l_file, "# x1 x2 "); print(l_file, "#----------"); print(l_file, " ");

wait until RST='1'; wait until RST='0';

while true loop . . .

If the waveforms shown below are applied to the entity:

http://www.stefanvhdl.com/vhdl/html/file_write.html (2 of 4) [1/13/2009 3:54:34 PM]

Page 11: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Then the following will be the contents of res.log:

# x1 x2 #----------

0 01h 0 02h 0 03h ... 0 0Fh 1 10h 1 11h ...

Below are the files which have been simulated in this section:

txt_util.vhd

file_log.vhd

stim_gen2.vhd

tb_file_log.vhd

http://www.stefanvhdl.com/vhdl/html/file_write.html (3 of 4) [1/13/2009 3:54:34 PM]

Page 12: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

http://www.stefanvhdl.com/vhdl/html/file_write.html (4 of 4) [1/13/2009 3:54:34 PM]

Page 13: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Reading from Files

Reading from files is very important for VHDL simulation. Apart from using it in self-designed testbenches, many commercially available testbench components make use of this method, too. This section will illustrate how to read file using VHDL 93 syntax.

Here is an example entity header:

entity FILE_READ is generic( stim_file: string :="sim.dat" ); port( CLK : in std_logic; RST : in std_logic; Y : out std_logic_vector(4 downto 0); EOG : out std_logic ); end FILE_READ;

In this example data is read from a file sim.dat at every rising clock edge and applied to the output vector Y. Once every line of the file is read the EOG (End Of Generation) flag is set.

The declaration of the input file is shown below:

architecture read_from_file of FILE_READ is file stimulus: TEXT open read_mode is stim_file; begin

The file is stimulus, it's of type TEXT and opened in read mode. The file name is defined in the string stim_file. (stim_file is a generic, defined in the entity header).

Just as a file write, a file read is done in two steps. The first step fetches a line from a file and stores it in

http://www.stefanvhdl.com/vhdl/html/file_read.html (1 of 3) [1/13/2009 3:54:35 PM]

Page 14: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

a line type variable (readline command) the second reads a string from the line (read command):

EOG <= '0';

-- wait for Reset to complete wait until RST='1'; wait until RST='0';

while not endfile(stimulus) loop

-- read digital data from input file readline(stimulus, l); read(l, s); Y <= to_std_logic_vector(s);

wait until CLK = '1';

end loop;

print("I@FILE_READ: reached end of "& stim_file); EOG <= '1';

wait;

Since a string is read from the input file, a conversion function is required to obtain a std_logic_vector. The function to_std_logic_vector(s) achieves that, it is part of the txt_util package.

With the following contents of sim.dat:

00010 00011 11100 1UXZW HL111 11111

...file_read.vhd will generate these waveforms:

http://www.stefanvhdl.com/vhdl/html/file_read.html (2 of 3) [1/13/2009 3:54:35 PM]

Page 15: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Below are the files which have been simulated in this section:

txt_util.vhd

file_read.vhd

sim.dat

tb_file_read.vhd

http://www.stefanvhdl.com/vhdl/html/file_read.html (3 of 3) [1/13/2009 3:54:35 PM]

Page 16: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

More Reading from Files

In addition to reading data, it's also possible to read commands from files. This will be discussed in this section by extending the already introduced file_read.vhd.

The new version will read hex data and will also understand a command: #count. Each time it is found in the input file the file reader shall shall count from 1 to 5 in binary format and present that count on the output port. Unfortunately the file I/O of VHDL is not very sophisticated. It's not allowed to read a string from a file where the string is longer than the number of characters in that line.

Here is what needs to be done in order to read variable length strings from an input file:

readline(stimulus, l); s := (others => ' '); for i in s'range loop read(l, c, in_string); s(i) := c; if not in_string then -- found end of line exit; end if; end loop;

The read function will return false for in_string once the last character of the line has been read.

The above function has been placed in txt_util.vhd and named str_read(stimulus, s). The length of s determines the maximum number of characters in a line which can be evaluated.

Using this function the following code will implement the set task:

while not endfile(stimulus) loop str_read(stimulus, s);

if s(1 to 6) = "#count" then -- check for command "count" for i in 1 to 5 loop Y <= conv_std_logic_vector(i,5); wait until CLK = '1'; end loop; else -- if it's not a command -> process data normally Y <= to_std_logic_vector(s to 5); wait until CLK = '1'; end if;

end loop;

http://www.stefanvhdl.com/vhdl/html/file_read2.html (1 of 2) [1/13/2009 3:54:37 PM]

Page 17: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

print("I@FILE_READ: reached end of "& stim_file); EOG <= '1';

wait;

Note that the appropriate sub-section of the string s needs to be compared with #count as comparing different length strings will always yield the result false.

Here is an input file making use of the #count-command.

00010 00011 #count 11100 1UXZW HL111 11111

The resulting waveforms are thus:

Below are the files which have been simulated in this section:

txt_util.vhd

file_read2.vhd

sim2.dat

tb_file_read2.vhd

http://www.stefanvhdl.com/vhdl/html/file_read2.html (2 of 2) [1/13/2009 3:54:37 PM]

Page 18: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

The World of Perl

As it could be seen in the last section, it's possible to read more from files than just data. Many commercially available testbenches support sophisticated commands. There are limits however: in most cases structural elements like loops and procedures are missing. It's theoretically possible to extend the file reader into a proper parser and add these language elements, however VHDL is not really suited for these tasks and access to the source code may not always be possible. A way to get around these problems is to generate the input files with a different language such as perl.

The perl script below will generate an input file which can be read by file_read.vhd.

print "00011\n"; print "11100\n"; for ($i=0;$i<10;$i++) { print num2binary($i,5)."\n"; }

print "1UXZW\n"; print "11111\n";

Resulting Stimulus File:

00011 11100 00000 00001 00010 00011 00100 00101 00110 00111 01000 01001 01010 1UXZW

http://www.stefanvhdl.com/vhdl/html/perl.html (1 of 2) [1/13/2009 3:54:38 PM]

Page 19: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

HL111 11111

It's straightforward to extend this approach e.g. for 256 iterations if all values of a 8 bit word are to be covered. Entering these values manually would be very cumbersome. The script actually calls a procedure num2binary which can be found in the complete script. More complex procedures like PRBS patterns or CRC generators could be used in a similar fashion.

Here is the complete perl script:

tgen.pl

http://www.stefanvhdl.com/vhdl/html/perl.html (2 of 2) [1/13/2009 3:54:38 PM]

Page 20: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

SRAM modeling

SRAM models are used quite frequently and many devices have bus interfaces which are similar to SRAMs. It's therefore valuable to have a standard approach for modeling these interfaces.

Below is the data for a simplified SRAM:

Parameter Description Min Max Unit tSU A,D valid to WE_L asserted 4 - ns

tH WE_L deasserted to A,D invalid 3 - ns

tW_WE WE_L asserted to WE_L deasserted 40 - ns

For the purpose of this example reading from the SRAM is ignored, and only writes are implemented. It's easier to code transactors rather than models, so initially this approach is taken.

Core of the implementation is test_prg, a process which contains the write procedure and the test program. The purpose of the write procedure is to verify the timing of a write access to the SRAM as well as to verify whether data and address are as expected.

procedure write(wadd: std_logic_vector(7 downto 0); wdat: std_logic_vector(7 downto 0) ) is

variable start_cycle: time;

The parameters wadd and wdat specify address and data for the expected write access.

begin

D <= (others => 'Z');

http://www.stefanvhdl.com/vhdl/html/sram.html (1 of 4) [1/13/2009 3:54:41 PM]

Page 21: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

wait until WE_L = '0';

The data bus is assigned to 'Z' (=tristate) values. This means the SRAM model will not drive the data bus and therefore will not corrupt the data input. The procedure will wait for the start of the write access which is equivalent to waiting for WE_L to be asserted (active low).

start_cycle := now; -- check setup times assert A'last_event >= tSU report "E@SIMPLE_SRAM: Address setup time violated" severity Error; assert D'last_event >= tSU report "E@SIMPLE_SRAM: Data setup time violated" severity Error;

The variable start_cycle will be assigned to the simulation time. This means it will contain the time at which WE_L was first asserted in the access cycle. (The contents of that variable will be used later.) The attribute 'last_event is very useful for testbenches, it returns the time which has expired since the last event of a signal. (Example: if WE_L was asserted at 35 ns, and the current simulation time is 73 ns, then WE_L'last_event will return 73 ns - 35 ns = 38 ns.)

In this case the A'last_event returns the time A has been stable before WE_L was asserted. This is the actual setup time and should be greater or equal to tSU. If this is not the case, the assert statement will issue the message "E@SIMPLE_SRAM:

Address setup time violated". The same mechanism is used to verify the setup time for the data lines.

-- report action for transaction log print("I@SIMPLE_SRAM: "& hstr(D)& "h written to "& hstr(A)& "h");

In any case the access to the SRAM will be reported. The hstr function is part of the txt_util.vhd package, of course. It returns the value of a std_logic_vector in hex format.

-- verify address assert A = wadd report "E@SIMPLE_SRAM: Address incorrect, expected "& str(wadd)& " received "& str(A) severity Error;

Next the address is verified, if it's incorrect a message is issued which reports the expected and the actual value. This time it's in binary format, so that it's easier to identify which bit was corrupted.

-- verify data for i in wdat'range loop if wdat(i) /= '-' and wdat(i) /= D(i) then print("E@SIMPLE_SRAM: Write Data Invalid, written data = "& str(D)& " expected data = "& str(wdat) );

http://www.stefanvhdl.com/vhdl/html/sram.html (2 of 4) [1/13/2009 3:54:41 PM]

Page 22: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

exit; end if; end loop;

Somewhat more effort is put into verifying the data bus. Bits which are marked with "-" (=don't care bits) in the expected data are not compared with the actual data. This can be useful especially when modeling devices with a SRAM like interface when not all control bits at a particular address are actually relevant. (Example: wdat="00010--" and D="0001011" => not error would be indicated.)

The loop will go through all bits of the expected data word, compare or skip it and issue an error message when a discrepancy is found. In that latter case the loop is exited, to avoid reporting the same error several times.

wait until WE_L = '1'; -- verify pulse width on WE_L assert now - start_cycle >= tW_WE report "E@SIMPLE_SRAM: WE_L pulse width violated" severity Error; -- verify address and data haven't changed during the cycle assert A'last_event >= (now - start_cycle) report "E@SIMPLE_SRAM: Address hold time violated" severity Error; assert D'last_event >= (now - start_cycle) report "E@SIMPLE_SRAM: Data hold time violated" severity Error;

The cycle completes when WE_L is deasserted. Now it's possible to verify the pulse width by comparing the current time with the time at the beginning of the cycle (= start_cycle). The 'last_event attribute can not be used for this purpose since that would now refer to the time expired since WE_L returned to '1' (= 0 ns).

It's now also possible to verify that A hasn't changed during the cycle. If that was the case then A'last_event would be smaller than the time which has expired since the beginning of the cycle (= now - start_cycle). The same steps are taken to verify that D hasn't changed.

-- now make sure the hold times are maintained add_hold <= true, false after tH; dat_hold <= true, false after tH; add_val <= A; dat_val <= D;

end write;

The cycle is not totally complete yet, as the address and data hold times have not been verified. The code above activates

http://www.stefanvhdl.com/vhdl/html/sram.html (3 of 4) [1/13/2009 3:54:41 PM]

Page 23: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

two separate processes (the hold time monitors) to check the values of A and D.

-- hold time monitors add_monitor: process begin wait until A'event; assert not add_hold or A = add_val report "E@SIMPLE_SRAM: Address hold time violated" severity Error; end process add_monitor;

As long as add_hold is true (which it will be for a time tH after WE_L was deasserted) the hold time memory will verify the

value of A, each time an event on A occurs. The simulation diagram below shows how the signals add_hold and dat_hold are true (activating the hold time monitors) for 3 ns (the value of tH) and then return to false (deactivating the monitors).

Below are the files which have been simulated in this section:

txt_util.vhd

simple_sram.vhd

stim_gen.vhd

tb_simple.vhd

http://www.stefanvhdl.com/vhdl/html/sram.html (4 of 4) [1/13/2009 3:54:41 PM]

Page 24: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Passive SRAM Model

Modeling RAMs as models rather than as transactors has advantages and disadvantages. A transactor implementation doesn't need to represent memory and can verify the correct address and data. In case of a write it's possible to identify the problem at the time the write access occurs, rather than the time at which reading back occurs. However a passive implementation does not need to know which test is executed and is in that respect more generic than the transactor version.

One of the problems of implementing RAM models is representing internal memory. A large array of std_logic_vectors (eg. 2Mx64 bits) needs a large chunk of memory on the machine it's simulated on.

A possible approach is to represent the memory cells with integers (of an appropriate range) rather than std_logic_vectors. (One such approach can be found on Ben Cohen's website.) The approach taken here is based on the observation that most tests only access a tiny fraction of the modeled memory. For each write access the data as well as the address is stored into the internal array. For a subsequent access the model searches the array and identifies whether the address is already present. So if there are only 32 different addresses which are accessed, then there is no reason to have more than that number of memory locations in the model. However searching the array is more time intensive than using the address as an index, therefore there is likely to be a cross over point, where searching requires more resources than having a large array.

Here is the VHDL for this memory representation:

-- Internal Memory type mem_add_type is array (integer range <>) of std_logic_vector(A'range); type mem_dat_type is array (integer range <>) of std_logic_vector(D'range); variable mem_add: mem_add_type(mem_words-1 downto 0); variable mem_dat: mem_dat_type(mem_words-1 downto 0); variable used_pnt: integer := 0;

The parameter mem_words is a generic defined in the header, it can be set during instantiation for the required number of memory locations.

One of the additional tasks for the passive memory model, is to decide whether to call the read or the write procedure. The code below will take care of that:

D <= (others => 'Z'); wait until WE_L'event or RD_L'event; assert (WE_L /= 'X' and WE_L /= 'Z' and WE_L /= 'U' and WE_L /= '-') or no_reset_yet report "E@SRAM2: WE_L="& str(WE_L)& " invalid value" severity Error;

http://www.stefanvhdl.com/vhdl/html/sram_passive.html (1 of 3) [1/13/2009 3:54:42 PM]

Page 25: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

assert (RD_L /= 'X' and RD_L /= 'Z' and RD_L /= 'U' and WE_L /= '-') or no_reset_yet report "E@SRAM2: RD_L="& str(RD_L)& " invalid value" severity Error; assert to_X01(RD_L) /= '0' or to_X01(WE_L) /= '0' report "E@SRAM2: both read and write are asserted"& "RD_L="& str(RD_L)& " WE_L="& str(WE_L) severity Error;

-- decide whether read or write access

if to_X01(WE_L) = '0' then write; end if; if to_X01(RD_L) = '0' then read; end if;

end process test_proc;

The process will wait until activity either on RD_L or WE_L occurs. Illegal values for these signals ('U', 'X', '-' and 'Z') are reported as errors, they should never occur during simulation. Also if both signals are asserted simultaneously an error is reported. The function to_X01 will convert 'H' and 'L' values to '1' and '0' respectively. This is useful on busses which are pulled up or down and reflects the actual behaviour of the SRAM.

The write process is similar to the one for the transactor version. However the address and data verification can no longer be performed. Also the write access now has to be stored in the memory array:

... wait until to_X01(WE_L) = '1'; -- Store written data for i in 0 to used_pnt loop if i = used_pnt then -- access to a new address mem_add(i) := A; mem_dat(i) := D; if used_pnt < mem_words - 1 then used_pnt := used_pnt + 1; else print("W@SRAM2: Simulation model can't handle additional addresses"); end if;

http://www.stefanvhdl.com/vhdl/html/sram_passive.html (2 of 3) [1/13/2009 3:54:42 PM]

Page 26: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

end if; if mem_add(i) = A then -- access to an existing address mem_dat(i) := D; exit; end if; end loop;

The code loops through the already written array until a match for the address is found. If no match can be found and there is still room in the array, the new address is entered and the usage pointer is incremented. If there is no more space available a warning is issued.

The counterpart of this code can be found in the read procedure:

-- Retrieve data from internal memory for i in 0 to used_pnt+1 loop if i = used_pnt+1 then -- access to a new address print("W@SRAM2: Address has not been written to yet"); print("I@SIMPLE_SRAM: "& hstr(xx)& " provided for "& hstr(A)& "h"); D <= (others => 'X'); exit; end if; if mem_add(i) = A then -- access to an existing address D <= mem_dat(i) after tRD; print("I@SIMPLE_SRAM: "& hstr(mem_dat(i))& "h provided for "& hstr(A)& "h"); exit; end if; end loop;

The loop will investigate all written memory locations and try to establish a match. If successful it will take the data from that location and drive it onto the bus, otherwise it will issue a warning and drive all X's on the data bus.

Below are the files which have been simulated in this section:

txt_util.vhd

sram2.vhd

mp.vhd

tb_simple2.vhd

http://www.stefanvhdl.com/vhdl/html/sram_passive.html (3 of 3) [1/13/2009 3:54:42 PM]

Page 27: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Signal Monitors

Often it's desirable to monitor the status of a signal and display messages whenever it changes. A good example for this is an interrupt signal. Here presented are two possibilities for implementing this:

-- report changes of the interrupt signal

monitor: process(INT_L)

begin print("I@TB: INT_L="& str(INT_L));

end process monitor;

The process will be executed each time there is an event on INT_L. Whenever that happens a message will be printed.

Here is an alternative using an extensions of the print command which is available in txt_util.vhd:

-- report when interrupt is asserted print(INT_L'event and INT_L = '0', "I@TB: INT_L="& str(INT_L));

This function has as a first parameter a boolean expression and as the second parameter a message text. The message text will be printed whenever the boolean expression is true. (In this case whenever INT_L changes to '0'). The function does not need to be part of a process, it can be used as a concurrent statement.

Below are the files which have been simulated in this section:

txt_util.vhd

simple_mon.vhd

http://www.stefanvhdl.com/vhdl/html/monitor.html (1 of 2) [1/13/2009 3:54:42 PM]

Page 28: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

http://www.stefanvhdl.com/vhdl/html/monitor.html (2 of 2) [1/13/2009 3:54:42 PM]

Page 29: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Generating Clock and Reset Stimulus

Practically every testbench needs a clock and a reset signal. This section shows a simple way to implement them:

. . . signal clk: std_logic := '0'; signal rst: std_logic; begin rst <= '0', '1' after 10 ns, '0' after 30 ns; clk <= not clk after 8 ns; . . .

Note that the clk signal needs to be initialized in the declaration, as the inverse of 'U' (=uninitialized) is also 'U'. Here is the simulation result:

Below are the files which have been simulated in this section:

http://www.stefanvhdl.com/vhdl/html/clk_rst.html (1 of 2) [1/13/2009 3:54:44 PM]

Page 30: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

tb_clk_rst.vhd

http://www.stefanvhdl.com/vhdl/html/clk_rst.html (2 of 2) [1/13/2009 3:54:44 PM]

Page 31: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Approaches to Test Generation

A variety of methods are available to set up transactors for specific tests, some of the more popular methods are introduced here.

File Read Method

This method is very common, especially in commercially available testbenches.

The transactor reads commands from an input file and executes them, creating stimulus and verifying responses for the testbench. For each simulation the input files for the simulated test need to be copied into the working directory. Usually this method is combined with a pre-processor which generates the input files, as described in the perl section.

http://www.stefanvhdl.com/vhdl/html/test_approach.html (1 of 3) [1/13/2009 3:54:46 PM]

Page 32: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Some problems of this approach are:

● Usually the input file format does not support sophisticated structural elements (loops, procedures etc) and VHDL is not really suited to implement a sophisticated parser

● Syntactical errors in the input file are usually only found during simulation time (this may result in the loss of valuable computing time)

● Lack of feedback: it's usually not possible to react flexibly on the response of the DUT by examining the value of signals etc

● The input "language" is not standard VHDL and therefore not immediately understandable to other designers

Some of the benefits are:

● The testbench VHDL can remain clean and should run on all platforms without any changes ● The testbench structure is straightforward, no configuration statements are required

http://www.stefanvhdl.com/vhdl/html/test_approach.html (2 of 3) [1/13/2009 3:54:46 PM]

Page 33: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

http://www.stefanvhdl.com/vhdl/html/test_approach.html (3 of 3) [1/13/2009 3:54:46 PM]

Page 34: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

VHDL pre-processing Method

In this approach the test specific code is written in VHDL. It is stored in a file separate from the transactor code. To set up the transactor for a specific test, a pre-processor will insert that file into the transactor code and then the transactor is recompiled. The place where the file is inserted is marked with a special comment e.g. "--insert_file inp.cmd" where inp.cmd is the file name.

In Unix the pre-processor would be run like this:

awk -f insert.awk < transactor.vhd > precompiled_transactor.vhd

http://www.stefanvhdl.com/vhdl/html/pre_processing.html (1 of 2) [1/13/2009 3:54:47 PM]

Page 35: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

vcom precompiled_transactor.vhd

The file test_code.vhd is assumed to be in the current directory. (The compilation command would be appropriate for the MTI simulator, it needs to be replaced by an equivalent command for other simulators.)

Some problems of this approach are:

● Reliance on OS specific tools (not strictly pure VHDL) ● Recompilation adds to simulation time

Some of the benefits are:

● Tests can be compiled before simulation, so syntax errors are detected before the simulation runs ● Tests can be readily understood by designers who are familiar with VHDL ● All structural elements of VHDL are available ● Tests can react flexibly on the response of the DUT, full access to all signals known to the

transactor is possible

Below are the files which have been executed in this section:

insert.awk

test_code.vhd

transactor.vhd

http://www.stefanvhdl.com/vhdl/html/pre_processing.html (2 of 2) [1/13/2009 3:54:47 PM]

Page 36: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Test-specific Entities

For each test there is a separate testbench which uses test-specific transactors. For example there may be a microprocessor transactor mp.vhd. The testbench tb_test1 would then instantiate a test-specific microprocessor transactor mp_test1.vhd which would be coded by enhancing the mp.vhd template.

Some problems of this approach are:

● Bug fixes in the transactor code may have to be made in many files ● Results in a large number of files which are difficult to handle

Some of the benefits are:

● Pure VHDL, no dependency on OS specific tools ● Tests can be compiled before simulation, so syntax errors are detected before the simulation runs ● Tests can be readily understood by designers who are familiar with VHDL ● All structural elements of VHDL are available

http://www.stefanvhdl.com/vhdl/html/test_specific_entities.html (1 of 2) [1/13/2009 3:54:48 PM]

Page 37: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

● Tests can react flexibly on the response of the DUT, full access to all signals known to the transactor is possible

http://www.stefanvhdl.com/vhdl/html/test_specific_entities.html (2 of 2) [1/13/2009 3:54:48 PM]

Page 38: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Configuration controlled Test Selection

In this approach the transactors contain the code for all tests. The behaviour of the transactor can be controlled by a generic. The value of the generic defines which test is run. For each test a configuration statement exists which selects the test in the transactor by assigning the appropriate value to the generic parameter. (For example: configuration tb_A selects test A in the transactor by assigning the value "test_a" to the generic testselector of the transactor.)

Some problems of this approach are:

● Transactor code becomes very large and difficult to handle ● Modifying the transactor code for one test could potentially cause a problem in another test (e.g.

accidental editing)

Some of the benefits are:

http://www.stefanvhdl.com/vhdl/html/all_in_one.html (1 of 2) [1/13/2009 3:54:50 PM]

Page 39: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

● Pure VHDL, no dependency on OS specific tools ● Tests can be compiled before simulation, so syntax errors are detected before the simulation runs ● Tests can be readily understood by designers who are familiar with VHDL ● All structural elements of VHDL are available ● Tests can react flexibly on the response of the DUT, full access to all signals known to the

transactor is possible

http://www.stefanvhdl.com/vhdl/html/all_in_one.html (2 of 2) [1/13/2009 3:54:50 PM]

Page 40: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Using Transaction Logs

The purpose of this section is to show how to use transaction logs and to demonstrate why they are useful. First the usefulness shall be demonstrated.

Below are the requirements for two output signals of a device:

Parameter Description Min Max Unit

tSU_W Setup time for W asserted 6 - ns

tSU_R Setup time for R asserted 5 - ns

In this example a circuit has been synthesized already, and the simulation shall verify the VHDL description of the synthesized design. The following process shall check whether the timing requirements on the pins R and W are fulfilled. (The assumption of this test is that the design will execute write and read accesses alternatingly.)

timing_check: process variable w_asserted: time; variable r_asserted: time; begin -- wait for DUT to be reset wait until RST = '1'; wait until RST = '0'; -- verify write access wait until W = '0';

http://www.stefanvhdl.com/vhdl/html/transaction_logs.html (1 of 3) [1/13/2009 3:54:51 PM]

Page 41: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

w_asserted := now; wait until W = '1'; assert (now - w_asserted) >= tSU_W report "E@TB: W setup time too short" severity Error;

-- verify read access wait until R = '0'; r_asserted := now; wait until R = '1'; assert (now - r_asserted) >= tSU_R report "E@TB: R setup time too short" severity Error; end process timing_check;

Here is the description of the circuit's timing behaviour:

-- description of the timing behaviour -- of the DUT implemenation dut: process begin W <= '1'; R <= '1';

wait until RST = '1'; wait until RST = '0'; wait for 10 ns; -- write access W <= '0', '1' after 8 ns; wait for 10 ns; -- read access R <= '0', '1' after 9 ns; wait for 10 ns;

http://www.stefanvhdl.com/vhdl/html/transaction_logs.html (2 of 3) [1/13/2009 3:54:51 PM]

Page 42: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

-- write access W <= '0', '1' after 7 ns; wait for 10 ns; -- read access R <= '0', '1' after 4 ns; -- this is a violation we want to detect wait for 10 ns; -- write access W <= '0', '1' after 8 ns; wait for 10 ns; wait; end process dut;

As can be seen, the circuit does not meet the requirements. The second read pulse is too short. A simulation results in the following output, however:

VSIM 26> run -all VSIM 27>

Closer examination of the timing_check process reveals that it contains an error causing it to verify only one write and one read access, as it won't progress after the read unless a second reset pulse occurs. However the simulation output is exactly as would be expected for a correctly functioning circuit.

This kind of error is not infrequent and can be avoided by using transaction logs. This is shown in the next section.

Below are the files which have been simulated in this section:

txt_util.vhd

hang.vhd

http://www.stefanvhdl.com/vhdl/html/transaction_logs.html (3 of 3) [1/13/2009 3:54:51 PM]

Page 43: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Using Transaction Logs II

Using the same synthesized circuit the timing checker will be enhanced with transaction reporting:

-- verify the setup time on W and R signals -- we assume W and R are asserted alternatingly

timing_check: process variable w_asserted: time; variable r_asserted: time;

begin

-- wait for DUT to be reset wait until RST = '1'; wait until RST = '0';

-- verify write access wait until W = '0'; w_asserted := now; wait until W = '1';

print("I@TB: detected W access");

assert (now - w_asserted) >= tSU_W report "E@TB: W setup time too short" severity Error;

-- verify read access wait until R = '0'; r_asserted := now; wait until R = '1';

print("I@TB: detected R access");

http://www.stefanvhdl.com/vhdl/html/transaction_logs2.html (1 of 3) [1/13/2009 3:54:52 PM]

Page 44: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

assert (now - r_asserted) >= tSU_R report "E@TB: R setup time too short" severity Error;

end process timing_check;

Rerunning the simulation, the problem becomes immediately apparent:

VSIM 31> run -all # I@TB: detected W access # I@TB: detected R access VSIM 32>

The transaction log contains an insufficient number of write and read cycles. The problem can be fixed in the timing checker as shown:

-- wait for DUT to be reset wait until RST = '1'; wait until RST = '0';

loop -- verify write access wait until W = '0';

...

end loop;

end process timing_check;

And now the problem in the circuit is detected:

VSIM 8> run -all # I@TB: detected W access # I@TB: detected R access # I@TB: detected W access # I@TB: detected R access # ** Error: E@TB: R setup time too short # Time: 64 ns Iteration: 0 # I@TB: detected W access VSIM 9>

http://www.stefanvhdl.com/vhdl/html/transaction_logs2.html (2 of 3) [1/13/2009 3:54:52 PM]

Page 45: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

In order to effectively work with transaction logs it's helpful to write them to files. Here is a way to do this with the MTI simulator:

vsim tb1 -c -do "run 400 ns ; exit -f" > sim.log

These logs should be kept for each test, so that in a later simulation run the current log can be automatically compared with the golden log.

Below are the files which have been simulated in this section:

txt_util.vhd

hang2.vhd

tloop.vhd

http://www.stefanvhdl.com/vhdl/html/transaction_logs2.html (3 of 3) [1/13/2009 3:54:52 PM]

Page 46: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Using Behavioural Models

A behavioural model of a design can be used to verify that design. Such a model is used when there exists a way to represent the design's behaviour in a significantly simplified manner (e.g. if the objective is to build a very fast adder, the design's behaviour could be modeled with a simple "+"). Typically only the main functionality of the design would be modeled while other parts (like processor interface and RAM interfaces) would be ignored. Also in many cases there is no need to model the exact timing relationship as occurs in the design.

In principle the behavioural model will receive the same stimulus as the design and produce the same output. However often the stimulus and response can be represented in a more abstract format. For example if the actual design works on data blocks which are received one byte at a time in four clock cycles, the behavioural model could just operate on a simple hex number.

Often behavioural models are used to generate expected (golden) log files. In this case the the behavioural model operates on a stimulus file and creates a result file. The design is stimulated with the same input file via a file reader (see Reading from Files) and will protocol it's response into a transaction log (see Using Transaction Logs). The transaction log can then be compared with the expected results from the behavioural model (e.g. with Unix' diff utility).

http://www.stefanvhdl.com/vhdl/html/behavioural_models.html (1 of 2) [1/13/2009 3:54:53 PM]

Page 47: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

http://www.stefanvhdl.com/vhdl/html/behavioural_models.html (2 of 2) [1/13/2009 3:54:53 PM]

Page 48: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Recommended Directory Structure

It's useful to have a standardized directory structure for every module in an ASIC project. It makes it easier for designers to understand each others code and scripts can be shared more easily.

Below is a recommended directory structure which works well for the author. Many other structures are of course just as useful. (Instead of module the name of the module should be used.)

Directory Contents bin Scripts for running tests doc Module documentation

sim Simulation directory, contains the VHDL work library, simulator setup files, current transaction log etc

synth Synthesis directory, contains the work directory for intermediate files of the synthesis tool, synthesis scripts, constraint files

http://www.stefanvhdl.com/vhdl/html/dir_struct.html (1 of 2) [1/13/2009 3:54:55 PM]

Page 49: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

tbench VHDL testbench code

test

Test case directory, contains a directory for each test that is run with the following subdirectories cmd: command files, any files which are required to run the test exp: expected (golden) log files to compare the results with res: result files of the last simulation run

vhdl VHDL design code (synthesizable VHDL)

http://www.stefanvhdl.com/vhdl/html/dir_struct.html (2 of 2) [1/13/2009 3:54:55 PM]

Page 50: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

Test Strategy

Testing should normally be done in a bottom-up fashion, which means that blocks will be simulated in separate testbenches before they are integrated. This has the advantage that simulating smaller blocks requires less computing resources, which means the simulation runs faster and it's easier to find errors. Also since there is less code it's easier to identify the problem area. Of course there are limits to splitting the testing effort into sub-blocks. The designer needs choose the right level of hierarchies by comparing the effort to write additional testbenches against the effort to locate bugs in a more complex testbench. Usually if several designers are involved there should be at least one testbench for each designer's module and a testbench for the complete device.

There should be a testplan for the device which makes sure that every part of the design is exercised. Each test should have a unique identifier (ideally the directory name in which the test files are kept) and a description of the test.

If several designers work on the same device it's useful to have a bug log, a file that is kept in a central location and has an entry for every bug which is found. Here is a possible format:

Bug No Status Found by / Date Test

Case Description Fixed by / Date

1 open Stefan / 3/16/99 mp_test_1 back to back cycles fail on MP interface -

2 closed Bryan / 3/17/99 sdr_1 CRC values inverted Paul / 3/19/99 3 ... ... ... ... ...

There are also tools which help to maintain these logs and (among other things) prevent that entries are accidentally deleted.

Any small change in a minor file of the design could potentially cause the design to fail. It's therefore important that all tests are run after the last change has been made to the design code (and before the design is manufactured). To make this task feasible all tests should be automated and self-checking, so that they can be run from a script instead of having to run every test manually and having to check every log file line by line.

http://www.stefanvhdl.com/vhdl/html/test_strategy.html (1 of 2) [1/13/2009 3:54:56 PM]

Page 51: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

http://www.stefanvhdl.com/vhdl/html/test_strategy.html (2 of 2) [1/13/2009 3:54:56 PM]

Page 52: Stefan Doll-VHDL Verification Course-UPDATED

VHDL Verification Course

The End

I hope this course has been useful, I'm looking forward to your comments at: [email protected]

Thanks

© Stefan Doll

Below are the files which have been simulated in this section:

txt_util.vhd

finish.vhd

http://www.stefanvhdl.com/vhdl/html/end.html [1/13/2009 3:54:56 PM]

Page 53: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/convert.vhd

function to_std_logic(c: character) return std_logic is variable sl: std_logic; begin case c is when 'U' => sl := 'U'; when 'X' => sl := 'X'; when '0' => sl := '0'; when '1' => sl := '1'; when 'Z' => sl := 'Z'; when 'W' => sl := 'W'; when 'L' => sl := 'L'; when 'H' => sl := 'H'; when '-' => sl := '-'; when others => sl := 'X'; end case; return sl; end to_std_logic;

-- converts a string into std_logic_vector

function to_std_logic_vector(s: string) return std_logic_vector is variable slv: std_logic_vector(s'high-s'low downto 0); variable k: integer;begin k := s'high-s'low; for i in s'range loop slv(k) := to_std_logic(s(i)); k := k - 1; end loop; return slv;end to_std_logic_vector;

http://www.stefanvhdl.com/vhdl/vhdl/convert.vhd (1 of 2) [1/13/2009 3:54:57 PM]

Page 54: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/convert.vhd

http://www.stefanvhdl.com/vhdl/vhdl/convert.vhd (2 of 2) [1/13/2009 3:54:57 PM]

Page 55: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd

library ieee;use ieee.std_logic_1164.all;use std.textio.all;

package txt_util is

-- prints a message to the screen procedure print(text: string);

-- prints the message when active -- useful for debug switches procedure print(active: boolean; text: string);

-- converts std_logic into a character function chr(sl: std_logic) return character;

-- converts std_logic into a string (1 to 1) function str(sl: std_logic) return string;

-- converts std_logic_vector into a string (binary base) function str(slv: std_logic_vector) return string;

-- converts boolean into a string function str(b: boolean) return string;

-- converts an integer into a single character -- (can also be used for hex conversion and other bases) function chr(int: integer) return character;

-- converts integer into string using specified base function str(int: integer; base: integer) return string;

-- converts integer to string, using base 10 function str(int: integer) return string;

-- convert std_logic_vector into a string in hex format function hstr(slv: std_logic_vector) return string;

-- functions to manipulate strings -----------------------------------

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd (1 of 14) [1/13/2009 3:54:59 PM]

Page 56: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd

-- convert a character to upper case function to_upper(c: character) return character;

-- convert a character to lower case function to_lower(c: character) return character;

-- convert a string to upper case function to_upper(s: string) return string;

-- convert a string to lower case function to_lower(s: string) return string;

-- functions to convert strings into other formats -------------------------------------------------- -- converts a character into std_logic function to_std_logic(c: character) return std_logic; -- converts a string into std_logic_vector function to_std_logic_vector(s: string) return std_logic_vector;

-- file I/O ----------- -- read variable length string from input file procedure str_read(file in_file: TEXT; res_string: out string); -- print string to a file and start new line procedure print(file out_file: TEXT; new_string: in string); -- print character to a file and start new line procedure print(file out_file: TEXT; char: in character); end txt_util;

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd (2 of 14) [1/13/2009 3:54:59 PM]

Page 57: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd

package body txt_util is

-- prints text to the screen

procedure print(text: string) is variable msg_line: line; begin write(msg_line, text); writeline(output, msg_line); end print;

-- prints text to the screen when active

procedure print(active: boolean; text: string) is begin if active then print(text); end if; end print;

-- converts std_logic into a character

function chr(sl: std_logic) return character is variable c: character; begin case sl is when 'U' => c:= 'U'; when 'X' => c:= 'X'; when '0' => c:= '0'; when '1' => c:= '1'; when 'Z' => c:= 'Z'; when 'W' => c:= 'W';

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd (3 of 14) [1/13/2009 3:54:59 PM]

Page 58: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd

when 'L' => c:= 'L'; when 'H' => c:= 'H'; when '-' => c:= '-'; end case; return c; end chr;

-- converts std_logic into a string (1 to 1)

function str(sl: std_logic) return string is variable s: string(1 to 1); begin s(1) := chr(sl); return s; end str;

-- converts std_logic_vector into a string (binary base) -- (this also takes care of the fact that the range of -- a string is natural while a std_logic_vector may -- have an integer range)

function str(slv: std_logic_vector) return string is variable result : string (1 to slv'length); variable r : integer; begin r := 1; for i in slv'range loop result(r) := chr(slv(i)); r := r + 1; end loop; return result; end str;

function str(b: boolean) return string is

begin if b then return "true";

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd (4 of 14) [1/13/2009 3:54:59 PM]

Page 59: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd

else return "false"; end if; end str;

-- converts an integer into a character -- for 0 to 9 the obvious mapping is used, higher -- values are mapped to the characters A-Z -- (this is usefull for systems with base > 10) -- (adapted from Steve Vogwell's posting in comp.lang.vhdl)

function chr(int: integer) return character is variable c: character; begin case int is when 0 => c := '0'; when 1 => c := '1'; when 2 => c := '2'; when 3 => c := '3'; when 4 => c := '4'; when 5 => c := '5'; when 6 => c := '6'; when 7 => c := '7'; when 8 => c := '8'; when 9 => c := '9'; when 10 => c := 'A'; when 11 => c := 'B'; when 12 => c := 'C'; when 13 => c := 'D'; when 14 => c := 'E'; when 15 => c := 'F'; when 16 => c := 'G'; when 17 => c := 'H'; when 18 => c := 'I'; when 19 => c := 'J'; when 20 => c := 'K'; when 21 => c := 'L'; when 22 => c := 'M'; when 23 => c := 'N'; when 24 => c := 'O'; when 25 => c := 'P'; when 26 => c := 'Q';

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd (5 of 14) [1/13/2009 3:54:59 PM]

Page 60: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd

when 27 => c := 'R'; when 28 => c := 'S'; when 29 => c := 'T'; when 30 => c := 'U'; when 31 => c := 'V'; when 32 => c := 'W'; when 33 => c := 'X'; when 34 => c := 'Y'; when 35 => c := 'Z'; when others => c := '?'; end case; return c; end chr;

-- convert integer to string using specified base -- (adapted from Steve Vogwell's posting in comp.lang.vhdl)

function str(int: integer; base: integer) return string is

variable temp: string(1 to 10); variable num: integer; variable abs_int: integer; variable len: integer := 1; variable power: integer := 1;

begin

-- bug fix for negative numbers abs_int := abs(int);

num := abs_int;

while num >= base loop -- Determine how many len := len + 1; -- characters required num := num / base; -- to represent the end loop ; -- number.

for i in len downto 1 loop -- Convert the number to temp(i) := chr(abs_int/power mod base); -- a string starting power := power * base; -- with the right hand end loop ; -- side.

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd (6 of 14) [1/13/2009 3:54:59 PM]

Page 61: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd

-- return result and add sign if required if int < 0 then return '-'& temp(1 to len); else return temp(1 to len); end if;

end str;

-- convert integer to string, using base 10 function str(int: integer) return string is

begin

return str(int, 10) ;

end str;

-- converts a std_logic_vector into a hex string. function hstr(slv: std_logic_vector) return string is variable hexlen: integer; variable longslv : std_logic_vector(67 downto 0) := (others => '0'); variable hex : string(1 to 16); variable fourbit : std_logic_vector(3 downto 0); begin hexlen := (slv'left+1)/4; if (slv'left+1) mod 4 /= 0 then hexlen := hexlen + 1; end if; longslv(slv'left downto 0) := slv; for i in (hexlen -1) downto 0 loop fourbit := longslv(((i*4)+3) downto (i*4)); case fourbit is when "0000" => hex(hexlen -I) := '0'; when "0001" => hex(hexlen -I) := '1'; when "0010" => hex(hexlen -I) := '2'; when "0011" => hex(hexlen -I) := '3'; when "0100" => hex(hexlen -I) := '4'; when "0101" => hex(hexlen -I) := '5';

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd (7 of 14) [1/13/2009 3:54:59 PM]

Page 62: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd

when "0110" => hex(hexlen -I) := '6'; when "0111" => hex(hexlen -I) := '7'; when "1000" => hex(hexlen -I) := '8'; when "1001" => hex(hexlen -I) := '9'; when "1010" => hex(hexlen -I) := 'A'; when "1011" => hex(hexlen -I) := 'B'; when "1100" => hex(hexlen -I) := 'C'; when "1101" => hex(hexlen -I) := 'D'; when "1110" => hex(hexlen -I) := 'E'; when "1111" => hex(hexlen -I) := 'F'; when "ZZZZ" => hex(hexlen -I) := 'z'; when "UUUU" => hex(hexlen -I) := 'u'; when "XXXX" => hex(hexlen -I) := 'x'; when others => hex(hexlen -I) := '?'; end case; end loop; return hex(1 to hexlen); end hstr;

-- functions to manipulate strings -----------------------------------

-- convert a character to upper case

function to_upper(c: character) return character is

variable u: character;

begin

case c is when 'a' => u := 'A'; when 'b' => u := 'B'; when 'c' => u := 'C'; when 'd' => u := 'D'; when 'e' => u := 'E'; when 'f' => u := 'F'; when 'g' => u := 'G'; when 'h' => u := 'H'; when 'i' => u := 'I';

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd (8 of 14) [1/13/2009 3:54:59 PM]

Page 63: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd

when 'j' => u := 'J'; when 'k' => u := 'K'; when 'l' => u := 'L'; when 'm' => u := 'M'; when 'n' => u := 'N'; when 'o' => u := 'O'; when 'p' => u := 'P'; when 'q' => u := 'Q'; when 'r' => u := 'R'; when 's' => u := 'S'; when 't' => u := 'T'; when 'u' => u := 'U'; when 'v' => u := 'V'; when 'w' => u := 'W'; when 'x' => u := 'X'; when 'y' => u := 'Y'; when 'z' => u := 'Z'; when others => u := c; end case;

return u;

end to_upper;

-- convert a character to lower case

function to_lower(c: character) return character is

variable l: character;

begin

case c is when 'A' => l := 'a'; when 'B' => l := 'b'; when 'C' => l := 'c'; when 'D' => l := 'd'; when 'E' => l := 'e'; when 'F' => l := 'f'; when 'G' => l := 'g'; when 'H' => l := 'h'; when 'I' => l := 'i';

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd (9 of 14) [1/13/2009 3:54:59 PM]

Page 64: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd

when 'J' => l := 'j'; when 'K' => l := 'k'; when 'L' => l := 'l'; when 'M' => l := 'm'; when 'N' => l := 'n'; when 'O' => l := 'o'; when 'P' => l := 'p'; when 'Q' => l := 'q'; when 'R' => l := 'r'; when 'S' => l := 's'; when 'T' => l := 't'; when 'U' => l := 'u'; when 'V' => l := 'v'; when 'W' => l := 'w'; when 'X' => l := 'x'; when 'Y' => l := 'y'; when 'Z' => l := 'z'; when others => l := c; end case;

return l;

end to_lower;

-- convert a string to upper case

function to_upper(s: string) return string is

variable uppercase: string (s'range);

begin

for i in s'range loop uppercase(i):= to_upper(s(i)); end loop; return uppercase;

end to_upper;

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd (10 of 14) [1/13/2009 3:54:59 PM]

Page 65: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd

-- convert a string to lower case

function to_lower(s: string) return string is

variable lowercase: string (s'range);

begin

for i in s'range loop lowercase(i):= to_lower(s(i)); end loop; return lowercase;

end to_lower;

-- functions to convert strings into other types

-- converts a character into a std_logic

function to_std_logic(c: character) return std_logic is variable sl: std_logic; begin case c is when 'U' => sl := 'U'; when 'X' => sl := 'X'; when '0' => sl := '0'; when '1' => sl := '1'; when 'Z' => sl := 'Z'; when 'W' => sl := 'W'; when 'L' => sl := 'L'; when 'H' => sl := 'H'; when '-' =>

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd (11 of 14) [1/13/2009 3:54:59 PM]

Page 66: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd

sl := '-'; when others => sl := 'X'; end case; return sl; end to_std_logic;

-- converts a string into std_logic_vector

function to_std_logic_vector(s: string) return std_logic_vector is variable slv: std_logic_vector(s'high-s'low downto 0); variable k: integer;begin k := s'high-s'low; for i in s'range loop slv(k) := to_std_logic(s(i)); k := k - 1; end loop; return slv;end to_std_logic_vector; ------------------ file I/O ------------------

-- read variable length string from input file procedure str_read(file in_file: TEXT; res_string: out string) is variable l: line; variable c: character; variable is_string: boolean;

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd (12 of 14) [1/13/2009 3:54:59 PM]

Page 67: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd

begin readline(in_file, l); -- clear the contents of the result string for i in res_string'range loop res_string(i) := ' '; end loop; -- read all characters of the line, up to the length -- of the results string for i in res_string'range loop read(l, c, is_string); res_string(i) := c; if not is_string then -- found end of line exit; end if; end loop; end str_read;

-- print string to a fileprocedure print(file out_file: TEXT; new_string: in string) is variable l: line; begin write(l, new_string); writeline(out_file, l); end print;

-- print character to a file and start new lineprocedure print(file out_file: TEXT; char: in character) is variable l: line; begin

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd (13 of 14) [1/13/2009 3:54:59 PM]

Page 68: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd

write(l, char); writeline(out_file, l); end print;

-- appends contents of a string to a file until line feed occurs-- (LF is considered to be the end of the string)

procedure str_write(file out_file: TEXT; new_string: in string) is begin for i in new_string'range loop print(out_file, new_string(i)); if new_string(i) = LF then -- end of string exit; end if; end loop; end str_write;

end txt_util;

http://www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd (14 of 14) [1/13/2009 3:54:59 PM]

Page 69: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/tb1.vhd

library ieee;use ieee.std_logic_1164.all;use std.textio.all;use ieee.std_logic_arith.all;

use work.txt_util.all; entity TB1 isend TB1;

architecture test of TB1 is

signal x1: std_logic;signal x2: std_logic;signal y: std_logic;

begin

test_seq: process

variable cnt: integer := 0;--*variable slv: std_logic_vector(X2'range);

begin x1 <= '0';x2 <= '0';

wait for 10 ns;

x1 <= '1';x2 <= '0';

wait for 10 ns; x1 <= '0';x2 <= '1';

http://www.stefanvhdl.com/vhdl/vhdl/tb1.vhd (1 of 3) [1/13/2009 3:55:00 PM]

Page 70: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/tb1.vhd

wait for 10 ns;

x1 <= '1';x2 <= '1'; wait for 10 ns;

assert y = (x1 xor x2) report "E@TB: circuit failed" severity Error;

assert y = (x1 xor x2) report "E@TB: failure at: x1="& std_logic'image(x1)& " x2="& std_logic'image(x2) severity Error; assert y = (x1 xor x2) report "E@TB: failure at: x1="& str(x1)& " x2="& str(x2) severity Error;

x1 <= 'X';x2 <= 'X';

wait for 30 ns;

x1 <= '1', '0' after 10 ns, '1' after 20 ns, '0' after 30 ns;x2 <= '1', '0' after 20 ns;

wait; -- stop process

end process test_seq;

-- this is supposed to be an xor ... but it isn'ty <= (x1 and not x2) or (x2 and not x1) or (x1 and x2);

http://www.stefanvhdl.com/vhdl/vhdl/tb1.vhd (2 of 3) [1/13/2009 3:55:00 PM]

Page 71: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/tb1.vhd

end test;

http://www.stefanvhdl.com/vhdl/vhdl/tb1.vhd (3 of 3) [1/13/2009 3:55:00 PM]

Page 72: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/file_log.vhd

library ieee;use ieee.std_logic_1164.all;

use std.textio.all;use work.txt_util.all; entity FILE_LOG is generic ( log_file: string := "res.log" ); port( CLK : in std_logic; RST : in std_logic; x1 : in std_logic; x2 : in std_logic_vector(7 downto 0) );end FILE_LOG; architecture log_to_file of FILE_LOG is file l_file: TEXT open write_mode is log_file;

begin

-- write data and control information to a file

receive_data: process

variable l: line; begin

-- print header for the logfile print(l_file, "# x1 x2 "); print(l_file, "#----------"); print(l_file, " ");

http://www.stefanvhdl.com/vhdl/vhdl/file_log.vhd (1 of 2) [1/13/2009 3:55:00 PM]

Page 73: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/file_log.vhd

wait until RST='1'; wait until RST='0';

while true loop

-- write digital data into log file --* write(l, str(x1)& " "& hstr(x2)& "h"); --* writeline(l_file, l); print(l_file, str(x1)& " "& hstr(x2)& "h");

wait until CLK = '1'; end loop;

end process receive_data;

end log_to_file;

http://www.stefanvhdl.com/vhdl/vhdl/file_log.vhd (2 of 2) [1/13/2009 3:55:00 PM]

Page 74: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen2.vhd

library ieee;use ieee.std_logic_1164.all;use std.textio.all;use ieee.std_logic_arith.all;

use work.txt_util.all; entity STIM_GEN2 is port( RST: out std_logic; CLK: out std_logic; X1: out std_logic; X2: out std_logic_vector(7 downto 0) );end STIM_GEN2;

architecture test of STIM_GEN2 is

signal i_clk: std_logic := '0';

begin

RST <= '0', '1' after 10 ns, '0' after 30 ns;i_clk <= not i_clk after 8 ns;CLK <= i_clk;

test_seq: process

variable cnt: integer := 0;variable slv: std_logic_vector(X2'range);

begin wait until i_clk = '1';

slv := conv_std_logic_vector(cnt, 8);X2 <= slv;X1 <= slv(4);

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen2.vhd (1 of 2) [1/13/2009 3:55:01 PM]

Page 75: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen2.vhd

cnt := cnt + 1;

end process test_seq;

end test;

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen2.vhd (2 of 2) [1/13/2009 3:55:01 PM]

Page 76: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/tb_file_log.vhd

library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_arith.all;

entity tb_file_log isend tb_file_log;

architecture structure of tb_file_log is

component file_log generic ( log_file: string := "res.log" ); port( CLK : in std_logic; RST : in std_logic; x1 : in std_logic; x2 : in std_logic_vector(7 downto 0) );end component;

component stim_gen2 port( RST: out std_logic; CLK: out std_logic; X1: out std_logic; X2: out std_logic_vector(7 downto 0) );end component;

signal RST: std_logic;signal CLK: std_logic;signal X1: std_logic;signal X2: std_logic_vector(7 downto 0);

http://www.stefanvhdl.com/vhdl/vhdl/tb_file_log.vhd (1 of 2) [1/13/2009 3:55:03 PM]

Page 77: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/tb_file_log.vhd

begin

U_FILE_LOG: FILE_LOG port map ( CLK => clk, RST => rst, x1 => x1, x2 => x2 );

U_STIM_GEN2: STIM_GEN2 port map ( RST => rst, CLK => clk, X1 => x1, X2 => x2 );

end structure;

http://www.stefanvhdl.com/vhdl/vhdl/tb_file_log.vhd (2 of 2) [1/13/2009 3:55:03 PM]

Page 78: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/file_read.vhd

library ieee;use ieee.std_logic_1164.all;

use std.textio.all;use work.txt_util.all; entity FILE_READ is generic ( stim_file: string := "sim2.dat" ); port( CLK : in std_logic; RST : in std_logic; Y : out std_logic_vector(4 downto 0); EOG : out std_logic );end FILE_READ;

-- I/O Dictionary---- Inputs:---- CLK: new cell needed-- RST: reset signal, wait with reading till reset seq complete-- -- Outputs:---- Y: Output vector-- EOG: End Of Generation, all lines have been read from the file-- architecture read_from_file of FILE_READ is file stimulus: TEXT open read_mode is stim_file;

begin

http://www.stefanvhdl.com/vhdl/vhdl/file_read.vhd (1 of 2) [1/13/2009 3:55:03 PM]

Page 79: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/file_read.vhd

-- read data and control information from a file

receive_data: process

variable l: line;variable s: string(y'range); begin

EOG <= '0'; -- wait for Reset to complete wait until RST='1'; wait until RST='0';

while not endfile(stimulus) loop

-- read digital data from input file readline(stimulus, l); read(l, s); Y <= to_std_logic_vector(s); wait until CLK = '1';

end loop; print("I@FILE_READ: reached end of "& stim_file); EOG <= '1'; wait;

end process receive_data;

end read_from_file;

http://www.stefanvhdl.com/vhdl/vhdl/file_read.vhd (2 of 2) [1/13/2009 3:55:03 PM]

Page 80: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/sim.dat

0001000011111001UXZWHL11111111

http://www.stefanvhdl.com/vhdl/vhdl/sim.dat [1/13/2009 3:55:04 PM]

Page 81: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/tb_file_read.vhd

library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_arith.all;

entity TB_FILE_READ isend TB_FILE_READ;

architecture test of TB_FILE_READ is

component FILE_READ generic ( stim_file: string := "sim.dat" ); port( CLK : in std_logic; RST : in std_logic; Y : out std_logic_vector(4 downto 0); EOG : out std_logic );end component;

signal rst: std_logic;signal clk: std_logic := '0';signal eog: std_logic;signal y: std_logic_vector(4 downto 0);

begin

rst <= '0', '1' after 40 ns, '0' after 100 ns; clk <= not clk after 10 ns;

input_stim: FILE_READ port map( CLK => clk, RST => rst, Y => y, EOG => eog

http://www.stefanvhdl.com/vhdl/vhdl/tb_file_read.vhd (1 of 2) [1/13/2009 3:55:04 PM]

Page 82: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/tb_file_read.vhd

);

end test;

http://www.stefanvhdl.com/vhdl/vhdl/tb_file_read.vhd (2 of 2) [1/13/2009 3:55:04 PM]

Page 83: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/file_read2.vhd

library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_arith.all;

use std.textio.all;use work.txt_util.all; entity FILE_READ2 is generic ( stim_file: string := "sim.dat" ); port( CLK : in std_logic; RST : in std_logic; Y : out std_logic_vector(4 downto 0); EOG : out std_logic );end FILE_READ2;

-- I/O Dictionary---- Inputs:---- CLK: new cell needed-- RST: reset signal, wait with reading till reset seq complete-- -- Outputs:---- Y: Output vector-- EOG: End Of Generation, all lines have been read from the file-- architecture read_from_file of FILE_READ2 is file stimulus: TEXT open read_mode is stim_file;

begin

http://www.stefanvhdl.com/vhdl/vhdl/file_read2.vhd (1 of 3) [1/13/2009 3:55:05 PM]

Page 84: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/file_read2.vhd

-- read data and control information from a file

receive_data: process

variable l: line;variable s: string(1 to 80);variable c: character;variable in_string: boolean;

begin

EOG <= '0'; wait until RST='1'; wait until RST='0';

while not endfile(stimulus) loop

--*-- read variable length string --*-- from input file --*readline(stimulus, l); --*s := (others => ' '); --*for i in s'range loop --* read(l, c, in_string); --* s(i) := c; --* if not in_string then -- found end of line --* exit; --* end if; --*end loop; str_read(stimulus, s); if s(1 to 6) = "#count" then -- check for command "count" for i in 1 to 5 loop Y <= conv_std_logic_vector(i,5); wait until CLK = '1'; end loop;

http://www.stefanvhdl.com/vhdl/vhdl/file_read2.vhd (2 of 3) [1/13/2009 3:55:05 PM]

Page 85: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/file_read2.vhd

else -- if it's not a command -> process data normally Y <= to_std_logic_vector(s(1 to 5)); wait until CLK = '1'; end if;

end loop; print("I@FILE_READ: reached end of "& stim_file); EOG <= '1'; wait;

end process receive_data;

end read_from_file;

http://www.stefanvhdl.com/vhdl/vhdl/file_read2.vhd (3 of 3) [1/13/2009 3:55:05 PM]

Page 86: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/sim2.dat

0001000011#count111001UXZWHL11111111

http://www.stefanvhdl.com/vhdl/vhdl/sim2.dat [1/13/2009 3:55:06 PM]

Page 87: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/tb_file_read2.vhd

library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_arith.all;

entity TB_FILE_READ2 isend TB_FILE_READ2;

architecture test of TB_FILE_READ2 is

component FILE_READ2 generic ( stim_file: string := "sim2.dat" ); port( CLK : in std_logic; RST : in std_logic; Y : out std_logic_vector(4 downto 0); EOG : out std_logic );end component;

signal rst: std_logic;signal clk: std_logic := '0';signal eog: std_logic;signal y: std_logic_vector(4 downto 0);

begin

rst <= '0', '1' after 40 ns, '0' after 100 ns; clk <= not clk after 10 ns;

input_stim: FILE_READ2 port map( CLK => clk, RST => rst, Y => y, EOG => eog

http://www.stefanvhdl.com/vhdl/vhdl/tb_file_read2.vhd (1 of 2) [1/13/2009 3:55:07 PM]

Page 88: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/tb_file_read2.vhd

);

end test;

http://www.stefanvhdl.com/vhdl/vhdl/tb_file_read2.vhd (2 of 2) [1/13/2009 3:55:07 PM]

Page 89: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/simple_sram.vhd

library ieee;use ieee.std_logic_1164.all;use std.textio.all;use ieee.std_logic_arith.all;

use work.txt_util.all; entity SIMPLE_SRAM is port( A: in std_logic_vector(7 downto 0); WE_L: in std_logic; D: inout std_logic_vector(7 downto 0) );end SIMPLE_SRAM;

-- I/O Dictionary---- A: Address bus-- WE_L: Write Enable-- D: Data bus----

architecture transactor of SIMPLE_SRAM is

constant tSU : time := 4 ns;constant tH : time := 3 ns;constant tW_WE : time := 40 ns;

signal add_hold: boolean := false;signal dat_hold: boolean := false;signal add_val: std_logic_vector(A'range);signal dat_val: std_logic_vector(D'range); begin

http://www.stefanvhdl.com/vhdl/vhdl/simple_sram.vhd (1 of 5) [1/13/2009 3:55:08 PM]

Page 90: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/simple_sram.vhd

-- hold time monitorsadd_monitor: processbegin wait until A'event; assert not add_hold or A = add_val report "E@SIMPLE_SRAM: Address hold time violated" severity Error; end process add_monitor;

dat_monitor: processbegin wait until D'event; assert not dat_hold or D = dat_val report "E@SIMPLE_SRAM: Data hold time violated" severity Error; end process dat_monitor;

test_prg: process

procedure write(wadd: std_logic_vector(7 downto 0); wdat: std_logic_vector(7 downto 0) ) is

variable start_cycle: time;

begin

D <= (others => 'Z'); wait until WE_L = '0';

http://www.stefanvhdl.com/vhdl/vhdl/simple_sram.vhd (2 of 5) [1/13/2009 3:55:08 PM]

Page 91: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/simple_sram.vhd

start_cycle := now; -- check setup times assert A'last_event >= tSU report "E@SIMPLE_SRAM: Address setup time violated" severity Error; assert D'last_event >= tSU report "E@SIMPLE_SRAM: Data setup time violated" severity Error; -- report action for transaction log print("I@SIMPLE_SRAM: "& hstr(D)& "h written to "& hstr(A)& "h"); -- verify address assert A = wadd report "E@SIMPLE_SRAM: Address incorrect, expected "& str(wadd)& " received "& str(A) severity Error; -- verify data for i in wdat'range loop if wdat(i) /= '-' and wdat(i) /= D(i) then print("E@SIMPLE_SRAM: Write Data Invalid, written data = "& str(D)& " expected data = "& str(wdat) ); exit; end if; end loop;

wait until WE_L = '1'; -- verify pulse width on WE_L assert now - start_cycle >= tW_WE report "E@SIMPLE_SRAM: WE_L pulse width violated" severity Error; -- verify address and data haven't changed during the cycle assert A'last_event >= (now - start_cycle) report "E@SIMPLE_SRAM: Address hold time violated"

http://www.stefanvhdl.com/vhdl/vhdl/simple_sram.vhd (3 of 5) [1/13/2009 3:55:08 PM]

Page 92: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/simple_sram.vhd

severity Error; assert D'last_event >= (now - start_cycle) report "E@SIMPLE_SRAM: Data hold time violated" severity Error; -- now make sure the hold times are maintained add_hold <= true, false after tH; dat_hold <= true, false after tH; add_val <= A; dat_val <= D; end write;

procedure read(radd: std_logic_vector(A'range); rdat: std_logic_vector(D'range)) is begin

end read;

begin

-- Test Program----------------

write("00000000", "11110000");write("00000001", "00001111");

-------------- End Test

end process test_prg;

end transactor;

http://www.stefanvhdl.com/vhdl/vhdl/simple_sram.vhd (4 of 5) [1/13/2009 3:55:08 PM]

Page 93: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/simple_sram.vhd

http://www.stefanvhdl.com/vhdl/vhdl/simple_sram.vhd (5 of 5) [1/13/2009 3:55:08 PM]

Page 94: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen.vhd

library ieee;use ieee.std_logic_1164.all;use std.textio.all;

use work.txt_util.all; entity STIM_GEN is port( A: out std_logic_vector(7 downto 0); WE_L: out std_logic; D: out std_logic_vector(7 downto 0) );end STIM_GEN;

architecture test of STIM_GEN is

constant tSU : time := 4 ns;constant tH : time := 3 ns;constant tW_WE : time := 40 ns;

signal clk: std_logic := '0';signal rst: std_logic;

begin

rst <= '0', '1' after 10 ns, '0' after 30 ns;clk <= not clk after 8 ns;

test_seq: processbegin A <= (others => 'X');D <= (others => 'Z');WE_L <= '1';

wait for 20 ns;

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen.vhd (1 of 7) [1/13/2009 3:55:09 PM]

Page 95: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen.vhd

-----------------------------

print(" ");print(" one correct access");

A <= "00000000";D <= "11110000";

wait for 4 ns;

WE_L <= '0';

wait for 40 ns;

WE_L <= '1';

wait for 3 ns;

A <= (others => 'X');D <= (others => 'Z');

wait for 10 ns; -----------------------------

print(" ");print(" wrong address and wrong data");

A <= "00000000";D <= "11110000";

wait for 4 ns;

WE_L <= '0';

wait for 40 ns;

WE_L <= '1';

wait for 3 ns;

A <= (others => 'X');D <= (others => 'Z');

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen.vhd (2 of 7) [1/13/2009 3:55:09 PM]

Page 96: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen.vhd

wait for 10 ns;

-----------------------------

print(" ");print(" violate address setup and data hold time");

D <= "11110000";

wait for 1 ns;

A <= "00000000";

wait for 3 ns;

WE_L <= '0';

wait for 40 ns;

WE_L <= '1';

wait for 2 ns;

D <= (others => 'Z');

wait for 1 ns;

A <= (others => 'X');

wait for 10 ns;

-----------------------------

print(" ");print(" violate data setup and address hold time");

A <= "00000001";

wait for 1 ns;

D <= "00001111";

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen.vhd (3 of 7) [1/13/2009 3:55:09 PM]

Page 97: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen.vhd

wait for 3 ns;

WE_L <= '0';

wait for 40 ns;

WE_L <= '1';

wait for 2 ns;

A <= (others => 'X');

wait for 1 ns;

D <= (others => 'Z');

wait for 10 ns;

-----------------------------

print(" ");print(" pulse width too short");

A <= "00000000";D <= "11110000";

wait for 4 ns;

WE_L <= '0';

wait for 30 ns;

WE_L <= '1';

wait for 3 ns;

A <= (others => 'X');D <= (others => 'Z');

wait for 10 ns;

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen.vhd (4 of 7) [1/13/2009 3:55:09 PM]

Page 98: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen.vhd

-----------------------------

print(" ");print(" unstable address");

A <= "00000001";D <= "00001111";

wait for 4 ns;

WE_L <= '0';

wait for 30 ns;

A <= "00000000", "00000001" after 2 ns;

wait for 10 ns;

WE_L <= '1';

wait for 3 ns;

A <= (others => 'X');D <= (others => 'Z');

wait for 10 ns;

-----------------------------

print(" ");print(" unstable data");

A <= "00000000";D <= "11110000";

wait for 4 ns;

WE_L <= '0';

wait for 30 ns;

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen.vhd (5 of 7) [1/13/2009 3:55:09 PM]

Page 99: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen.vhd

D <= "00000000";

wait for 10 ns;

WE_L <= '1';

wait for 3 ns;

A <= (others => 'X');D <= (others => 'Z');

wait for 10 ns;

-----------------------------

print(" ");print(" one correct access");

A <= "00000001";D <= "00001111";

wait for 4 ns;

WE_L <= '0';

wait for 40 ns;

WE_L <= '1';

wait for 3 ns;

A <= (others => 'X');D <= (others => 'Z');

wait for 10 ns;

wait;

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen.vhd (6 of 7) [1/13/2009 3:55:09 PM]

Page 100: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen.vhd

end process test_seq;

end test;

http://www.stefanvhdl.com/vhdl/vhdl/stim_gen.vhd (7 of 7) [1/13/2009 3:55:09 PM]

Page 101: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/tb_simple.vhd

library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_arith.all;

entity tb_simple isend tb_simple;

architecture structure of tb_simple is

component simple_sram port( A: in std_logic_vector(7 downto 0); WE_L: in std_logic; D: inout std_logic_vector(7 downto 0) );end component;

component stim_gen port( A: out std_logic_vector(7 downto 0); WE_L: out std_logic; D: out std_logic_vector(7 downto 0) );end component;

signal D: std_logic_vector(7 downto 0);signal A: std_logic_vector(7 downto 0);signal WE_L: std_logic;

begin

U_SIMPLE_SRAM: SIMPLE_SRAM port map ( A => a, WE_L => we_l, D => d

http://www.stefanvhdl.com/vhdl/vhdl/tb_simple.vhd (1 of 2) [1/13/2009 3:55:10 PM]

Page 102: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/tb_simple.vhd

);

U_STIM_GEN: STIM_GEN port map ( A => a, WE_L => we_l, D => d );

end structure;

http://www.stefanvhdl.com/vhdl/vhdl/tb_simple.vhd (2 of 2) [1/13/2009 3:55:10 PM]

Page 103: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/sram2.vhd

library ieee;use ieee.std_logic_1164.all;use std.textio.all;use ieee.std_logic_arith.all;

use work.txt_util.all; entity SRAM2 is generic( mem_words: integer := 32 ); port( RST: in std_logic; -- doesn't go to RAM, but is useful for testing A: in std_logic_vector(7 downto 0); WE_L: in std_logic; RD_L: in std_logic; D: inout std_logic_vector(7 downto 0) );end SRAM2;

-- I/O Dictionary---- A: Address bus-- WE_L: Write Enable-- RD_L: Read Enable-- D: Data bus----

architecture model of SRAM2 is

constant tSU : time := 4 ns;constant tH : time := 3 ns;constant tW_WE : time := 40 ns;constant tRD : time := 6 ns;constant tW_RD : time := 40 ns;

http://www.stefanvhdl.com/vhdl/vhdl/sram2.vhd (1 of 7) [1/13/2009 3:55:11 PM]

Page 104: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/sram2.vhd

signal add_hold: boolean := false;signal dat_hold: boolean := false;signal add_val: std_logic_vector(A'range);signal dat_val: std_logic_vector(D'range);

signal no_reset_yet: boolean := true;

begin

wait_for_reset: processbegin wait until RST = '1'; wait until RST = '0'; no_reset_yet <= false;end process wait_for_reset;

-- hold time monitorsadd_monitor: processbegin wait until A'event; assert not add_hold or A = add_val report "E@SIMPLE_SRAM: Address hold time violated" severity Error; end process add_monitor;

dat_monitor: processbegin wait until D'event; assert not dat_hold or D = dat_val report "E@SIMPLE_SRAM: Data hold time violated" severity Error; end process dat_monitor;

http://www.stefanvhdl.com/vhdl/vhdl/sram2.vhd (2 of 7) [1/13/2009 3:55:11 PM]

Page 105: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/sram2.vhd

test_proc: process

-- Internal Memorytype mem_add_type is array (integer range <>) of std_logic_vector(A'range);type mem_dat_type is array (integer range <>) of std_logic_vector(D'range);

variable mem_add: mem_add_type(mem_words-1 downto 0);variable mem_dat: mem_dat_type(mem_words-1 downto 0);variable used_pnt: integer := 0;

procedure write is

variable start_cycle: time;

begin start_cycle := now; -- check setup times assert A'last_event >= tSU report "E@SIMPLE_SRAM: Address setup time violated" severity Error; assert D'last_event >= tSU report "E@SIMPLE_SRAM: Data setup time violated" severity Error; -- report action for transaction log print("I@SIMPLE_SRAM: "& hstr(D)& "h written to "& hstr(A)& "h"); -- can't do this anymore: --*-- verify address --*assert A = wadd --* report "E@SIMPLE_SRAM: Address incorrect, expected "& --* str(wadd)& " received "& str(A) --* severity Error;

http://www.stefanvhdl.com/vhdl/vhdl/sram2.vhd (3 of 7) [1/13/2009 3:55:11 PM]

Page 106: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/sram2.vhd

-- can't do this anymore: --*-- verify data --*for i in wdat'range loop --* if wdat(i) /= '-' and wdat(i) /= D(i) then --* print("E@SIMPLE_SRAM: Write Data Invalid, written data = "& str(D)& --* " expected data = "& str(wdat) ); --* exit; --* end if; --*end loop; wait until to_X01(WE_L) = '1';

-- Store written data for i in 0 to used_pnt loop if i = used_pnt then -- access to a new address mem_add(i) := A; mem_dat(i) := D; if used_pnt < mem_words - 1 then used_pnt := used_pnt + 1; else print("W@SRAM2: Simulation model can't handle additional addresses"); end if; end if; if mem_add(i) = A then -- access to an existing address mem_dat(i) := D; exit; end if; end loop; -- verify pulse width on WE_L assert now - start_cycle >= tW_WE report "E@SIMPLE_SRAM: WE_L pulse width violated" severity Error; -- verify address and data haven't changed during the cycle assert A'last_event >= (now - start_cycle) report "E@SIMPLE_SRAM: Address hold time violated" severity Error;

http://www.stefanvhdl.com/vhdl/vhdl/sram2.vhd (4 of 7) [1/13/2009 3:55:11 PM]

Page 107: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/sram2.vhd

assert D'last_event >= (now - start_cycle) report "E@SIMPLE_SRAM: Data hold time violated" severity Error; -- now make sure the hold times are maintained add_hold <= true, false after tH; dat_hold <= true, false after tH; add_val <= A; dat_val <= D; end write;

procedure read is

constant xx: std_logic_vector(D'range) := (others => 'X'); variable start_cycle: time;

begin start_cycle := now; -- check setup times assert A'last_event >= tSU report "E@SIMPLE_SRAM: Address setup time violated" severity Error; assert D = (D'range => 'Z') report "E@SIMPLE_SRAM: Data bus is driven" severity Error; -- can't do this anymore: --*-- verify address --*assert A = wadd --* report "E@SIMPLE_SRAM: Address incorrect, expected "& --* str(wadd)& " received "& str(A) --* severity Error; -- Retrieve data from internal memory

http://www.stefanvhdl.com/vhdl/vhdl/sram2.vhd (5 of 7) [1/13/2009 3:55:11 PM]

Page 108: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/sram2.vhd

for i in 0 to used_pnt+1 loop if i = used_pnt+1 then -- access to a new address print("W@SRAM2: Address has not been written to yet"); print("I@SIMPLE_SRAM: "& hstr(xx)& " provided for "& hstr(A)& "h"); D <= (others => 'X'); exit; end if; if mem_add(i) = A then -- access to an existing address D <= mem_dat(i) after tRD; print("I@SIMPLE_SRAM: "& hstr(mem_dat(i))& "h provided for "& hstr(A)& "h"); exit; end if; end loop; wait until to_X01(RD_L) = '1';

-- verify pulse width on RD_L assert now - start_cycle >= tW_RD report "E@SIMPLE_SRAM: RD_L pulse width violated" severity Error; -- verify address and data haven't changed during the cycle assert A'last_event >= (now - start_cycle) report "E@SIMPLE_SRAM: Address hold time violated" severity Error; -- now make sure the hold times are maintained add_hold <= true, false after tH; dat_hold <= false; add_val <= A; end read;

begin

http://www.stefanvhdl.com/vhdl/vhdl/sram2.vhd (6 of 7) [1/13/2009 3:55:11 PM]

Page 109: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/sram2.vhd

D <= (others => 'Z');

wait until WE_L'event or RD_L'event; assert (WE_L /= 'X' and WE_L /= 'Z' and WE_L /= 'U' and WE_L /= '-') or no_reset_yet report "E@SRAM2: WE_L="& str(WE_L)& " invalid value" severity Error;

assert (RD_L /= 'X' and RD_L /= 'Z' and RD_L /= 'U' and WE_L /= '-') or no_reset_yet report "E@SRAM2: RD_L="& str(RD_L)& " invalid value" severity Error; assert to_X01(RD_L) /= '0' or to_X01(WE_L) /= '0' report "E@SRAM2: both read and write are asserted"& "RD_L="& str(RD_L)& " WE_L="& str(WE_L) severity Error;

-- decide whether read or write access if to_X01(WE_L) = '0' then write;end if;

if to_X01(RD_L) = '0' then read;end if;

end process test_proc;

end model;

http://www.stefanvhdl.com/vhdl/vhdl/sram2.vhd (7 of 7) [1/13/2009 3:55:11 PM]

Page 110: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/mp.vhd

library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_arith.all;use ieee.std_logic_unsigned.conv_integer;

use std.textio.all;use work.txt_util.all; entity MP is port( RST: in std_logic; A: out std_logic_vector(7 downto 0); WE_L: out std_logic; RD_L: out std_logic; D: inout std_logic_vector(7 downto 0) );end MP;

architecture test of MP is

constant tSU : time := 4 ns;constant tH : time := 3 ns;constant tW_WE : time := 40 ns;constant tRD : time := 6 ns;constant tW_RD : time := 40 ns;

begin

transactor: process

procedure write(wadd: std_logic_vector(A'range); wdat: std_logic_vector(D'range); flag: string) isbegin print("I@MP: write "& hstr(wdat)& "h to "& hstr(wadd)& "h");

http://www.stefanvhdl.com/vhdl/vhdl/mp.vhd (1 of 5) [1/13/2009 3:55:12 PM]

Page 111: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/mp.vhd

A <= wadd; D <= wdat;

wait for tSU;

WE_L <= '0'; if flag = "weak" then WE_L <= 'L'; end if; wait for tW_WE;

WE_L <= '1'; if flag = "weak" then WE_L <= 'H'; end if;

wait for tH;

A <= (others => 'X'); D <= (others => 'Z'); end procedure write;

procedure write(wadd: std_logic_vector(A'range); wdat: std_logic_vector(D'range)) isbegin write(wadd, wdat, "none");end procedure write;

procedure read(radd: std_logic_vector(A'range); rdat: std_logic_vector(D'range); flag: string) isbegin

A <= radd; D <= (others => 'Z');

http://www.stefanvhdl.com/vhdl/vhdl/mp.vhd (2 of 5) [1/13/2009 3:55:12 PM]

Page 112: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/mp.vhd

wait for tSU;

RD_L <= '0'; if flag = "weak" then RD_L <= 'L'; end if; wait for tW_RD; RD_L <= '1'; if flag = "weak" then RD_L <= 'H'; end if; print("I@MP: read "& hstr(D)& "h from "& hstr(radd)& "h"); assert D = rdat report "E@MP: read incorrect value" severity Error;

wait for tH;

A <= (others => 'X'); end procedure read;

procedure read(radd: std_logic_vector(A'range); rdat: std_logic_vector(D'range)) isbegin read(radd, rdat, "none");end procedure read;

begin

A <= (others => 'X');D <= (others => 'Z');WE_L <= '1';RD_L <= '1';

http://www.stefanvhdl.com/vhdl/vhdl/mp.vhd (3 of 5) [1/13/2009 3:55:12 PM]

Page 113: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/mp.vhd

wait until RST='1';wait until RST='0';

write("00001111","10101111");wait for 5 ns;read("00001111","10101111");wait for 5 ns;

-- fill up model spacefor i in 0 to 32 loop write(conv_std_logic_vector(i,8),conv_std_logic_vector(i,8));end loop;

-- read back all locationsfor i in 0 to 33 loop read(conv_std_logic_vector(i,8),conv_std_logic_vector(i,8));end loop;

print(" ");print("change the values of existing addresses");print(" ");

write("00000011","10101111");write("00000010","00000000");

print(" ");print("and verify the changes");print(" ");read("00000011","10101111");read("00000010","00000000");

print(" ");print("do two weak writes");print(" ");write("00000100","10101010","weak");write("00000101","01010101","weak");

print(" ");print("do two weak reads");print(" ");read("00000100","10101010","weak");read("00000101","01010101","weak");

http://www.stefanvhdl.com/vhdl/vhdl/mp.vhd (4 of 5) [1/13/2009 3:55:12 PM]

Page 114: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/mp.vhd

wait;

end process transactor;

end test;

http://www.stefanvhdl.com/vhdl/vhdl/mp.vhd (5 of 5) [1/13/2009 3:55:12 PM]

Page 115: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/tb_simple2.vhd

library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_arith.all;

entity tb_simple2 isend tb_simple2;

architecture structure of tb_simple2 is

component sram2 generic( mem_words: integer := 32 ); port( RST: in std_logic; -- doesn't go to RAM, but is useful for testing A: in std_logic_vector(7 downto 0); WE_L: in std_logic; RD_L: in std_logic; D: inout std_logic_vector(7 downto 0) );end component;

component mp port( RST: in std_logic; A: out std_logic_vector(7 downto 0); WE_L: out std_logic; RD_L: out std_logic; D: inout std_logic_vector(7 downto 0) );end component;

signal D: std_logic_vector(7 downto 0);signal A: std_logic_vector(7 downto 0);

http://www.stefanvhdl.com/vhdl/vhdl/tb_simple2.vhd (1 of 2) [1/13/2009 3:55:13 PM]

Page 116: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/tb_simple2.vhd

signal WE_L: std_logic;signal RD_L: std_logic;signal RST: std_logic;

begin RST <= '0', '1' after 1 ns, '0' after 2 ns;

U_SIMPLE_SRAM: SRAM2 port map ( RST => rst, A => a, WE_L => we_l, RD_L => rd_l, D => d );

U_MP: MP port map ( RST => rst, A => a, WE_L => we_l, RD_L => rd_l, D => d );

end structure;

http://www.stefanvhdl.com/vhdl/vhdl/tb_simple2.vhd (2 of 2) [1/13/2009 3:55:13 PM]

Page 117: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/simple_mon.vhd

library ieee;use ieee.std_logic_1164.all;use std.textio.all;use ieee.std_logic_arith.all;

use work.txt_util.all; entity SIMPLE_MON isend SIMPLE_MON;

architecture test of SIMPLE_MON is

signal INT_L: std_logic;

begin

-- example stimulusINT_L <= '1', '0' after 30 ns, '1' after 200 ns;

-- report changes of the interrupt signal

monitor: process(INT_L)

begin print("I@TB: INT_L="& str(INT_L)); end process monitor;

-- report when interrupt is asserted print(INT_L'event and INT_L = '0', "I@TB: INT_L="& str(INT_L)); end test;

http://www.stefanvhdl.com/vhdl/vhdl/simple_mon.vhd [1/13/2009 3:55:14 PM]

Page 118: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/tb_clk_rst.vhd

library ieee;use ieee.std_logic_1164.all; entity TB_CLK_RST isend TB_CLK_RST;

architecture test of TB_CLK_RST is

signal clk: std_logic := '0';signal rst: std_logic;

begin

rst <= '0', '1' after 10 ns, '0' after 30 ns;clk <= not clk after 8 ns; end test;

http://www.stefanvhdl.com/vhdl/vhdl/tb_clk_rst.vhd [1/13/2009 3:55:14 PM]

Page 119: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/insert.awk

## File insertion script#

BEGIN {skip=0}

/--insert_file/ { print "-- inserted file: " $2; system("cat " $2); print "-- -----------------------------------------------------------"; print ""; skip = 1}

// { if(skip==0) {print $0}; skip = 0 }

http://www.stefanvhdl.com/vhdl/vhdl/insert.awk [1/13/2009 3:55:15 PM]

Page 120: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/test_code.vhd

Y <= '0', '1' after 30 ns, '0' after 80 ns;

http://www.stefanvhdl.com/vhdl/vhdl/test_code.vhd [1/13/2009 3:55:15 PM]

Page 121: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/transactor.vhd

library ieee;use ieee.std_logic_1164.all;use std.textio.all;

entity TRANSACTOR is port( Y: out std_logic );end TRANSACTOR;

architecture test of TRANSACTOR is

begin

--insert_file test_code.vhd end test;

http://www.stefanvhdl.com/vhdl/vhdl/transactor.vhd [1/13/2009 3:55:16 PM]

Page 122: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/hang.vhd

library ieee;use ieee.std_logic_1164.all;use std.textio.all;use ieee.std_logic_arith.all;

use work.txt_util.all; entity HANG isend HANG;

architecture test of HANG is

constant tSU_R: time := 5 ns;constant tSU_W: time := 6 ns; signal W: std_logic;signal R: std_logic;signal RST: std_logic;

begin

RST <= '0', '1' after 12 ns, '0' after 20 ns;

-- verify the setup time on W and R signals-- we assume W and R are asserted alternatingly

timing_check: process

variable w_asserted: time;variable r_asserted: time;

begin

-- wait for DUT to be resetwait until RST = '1';wait until RST = '0'; -- verify write access wait until W = '0';w_asserted := now;

http://www.stefanvhdl.com/vhdl/vhdl/hang.vhd (1 of 3) [1/13/2009 3:55:17 PM]

Page 123: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/hang.vhd

wait until W = '1';

assert (now - w_asserted) >= tSU_W report "E@TB: W setup time too short" severity Error; -- verify read access wait until R = '0';r_asserted := now;wait until R = '1';

assert (now - r_asserted) >= tSU_R report "E@TB: R setup time too short" severity Error; end process timing_check;

-- description of the timing behaviour-- of the DUT implemenation dut: process

begin

W <= '1';R <= '1';

wait until RST = '1';wait until RST = '0';

wait for 10 ns;

-- write accessW <= '0', '1' after 8 ns;wait for 10 ns;

-- read accessR <= '0', '1' after 9 ns;wait for 10 ns;

http://www.stefanvhdl.com/vhdl/vhdl/hang.vhd (2 of 3) [1/13/2009 3:55:17 PM]

Page 124: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/hang.vhd

-- write accessW <= '0', '1' after 7 ns;wait for 10 ns;

-- read accessR <= '0', '1' after 4 ns; -- this is a violation we want to detectwait for 10 ns;

-- write accessW <= '0', '1' after 8 ns;wait for 10 ns;

wait;

end process dut; end test;

http://www.stefanvhdl.com/vhdl/vhdl/hang.vhd (3 of 3) [1/13/2009 3:55:17 PM]

Page 125: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/hang2.vhd

library ieee;use ieee.std_logic_1164.all;use std.textio.all;use ieee.std_logic_arith.all;

use work.txt_util.all; entity HANG2 isend HANG2;

architecture test of HANG2 is

constant tSU_R: time := 5 ns;constant tSU_W: time := 6 ns; signal W: std_logic;signal R: std_logic;signal RST: std_logic;

begin

RST <= '0', '1' after 12 ns, '0' after 20 ns;

-- verify the setup time on W and R signals-- we assume W and R are asserted alternatingly

timing_check: process

variable w_asserted: time;variable r_asserted: time;

begin

-- wait for DUT to be resetwait until RST = '1';wait until RST = '0'; -- verify write access wait until W = '0';w_asserted := now;

http://www.stefanvhdl.com/vhdl/vhdl/hang2.vhd (1 of 3) [1/13/2009 3:55:18 PM]

Page 126: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/hang2.vhd

wait until W = '1';

print("I@TB: detected W access");

assert (now - w_asserted) >= tSU_W report "E@TB: W setup time too short" severity Error; -- verify read access wait until R = '0';r_asserted := now;wait until R = '1';

print("I@TB: detected R access");

assert (now - r_asserted) >= tSU_R report "E@TB: R setup time too short" severity Error; end process timing_check;

-- description of the timing behaviour-- of the DUT implemenation dut: process

begin

W <= '1';R <= '1';

wait until RST = '1';wait until RST = '0';

wait for 10 ns;

-- write accessW <= '0', '1' after 8 ns;wait for 10 ns;

http://www.stefanvhdl.com/vhdl/vhdl/hang2.vhd (2 of 3) [1/13/2009 3:55:18 PM]

Page 127: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/hang2.vhd

-- read accessR <= '0', '1' after 9 ns;wait for 10 ns;

-- write accessW <= '0', '1' after 7 ns;wait for 10 ns;

-- read accessR <= '0', '1' after 4 ns; -- this is a violation we want to detectwait for 10 ns;

-- write accessW <= '0', '1' after 8 ns;wait for 10 ns;

wait;

end process dut; end test;

http://www.stefanvhdl.com/vhdl/vhdl/hang2.vhd (3 of 3) [1/13/2009 3:55:18 PM]

Page 128: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/tloop.vhd

library ieee;use ieee.std_logic_1164.all;use std.textio.all;use ieee.std_logic_arith.all;

use work.txt_util.all; entity TLOOP isend TLOOP;

architecture test of TLOOP is

constant tSU_R: time := 5 ns;constant tSU_W: time := 6 ns; signal W: std_logic;signal R: std_logic;signal RST: std_logic;

begin

RST <= '0', '1' after 12 ns, '0' after 20 ns;

-- verify the setup time on W and R signals-- we assume W and R are asserted alternatingly

timing_check: process

variable w_asserted: time;variable r_asserted: time;

begin

-- wait for DUT to be resetwait until RST = '1';wait until RST = '0'; loop wait until W = '0'; w_asserted := now;

http://www.stefanvhdl.com/vhdl/vhdl/tloop.vhd (1 of 3) [1/13/2009 3:55:18 PM]

Page 129: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/tloop.vhd

wait until W = '1';

print("I@TB: detected W access");

assert (now - w_asserted) >= tSU_W report "E@TB: W setup time too short" severity Error; -- verify read access wait until R = '0'; r_asserted := now; wait until R = '1';

print("I@TB: detected R access");

assert (now - r_asserted) >= tSU_R report "E@TB: R setup time too short" severity Error; end loop;

end process timing_check;

-- description of the timing behaviour-- of the DUT implemenation dut: process

begin

W <= '1';R <= '1';

wait until RST = '1';wait until RST = '0';

wait for 10 ns;

-- write accessW <= '0', '1' after 8 ns;wait for 10 ns;

http://www.stefanvhdl.com/vhdl/vhdl/tloop.vhd (2 of 3) [1/13/2009 3:55:18 PM]

Page 130: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/tloop.vhd

-- read accessR <= '0', '1' after 9 ns;wait for 10 ns;

-- write accessW <= '0', '1' after 7 ns;wait for 10 ns;

-- read accessR <= '0', '1' after 4 ns; -- this is a violation we want to detectwait for 10 ns;

-- write accessW <= '0', '1' after 8 ns;wait for 10 ns;

wait;

end process dut; end test;

http://www.stefanvhdl.com/vhdl/vhdl/tloop.vhd (3 of 3) [1/13/2009 3:55:18 PM]

Page 131: Stefan Doll-VHDL Verification Course-UPDATED

http://www.stefanvhdl.com/vhdl/vhdl/finish.vhd

use std.textio.all;use work.txt_util.all;

entity finish isend finish;

architecture text of finish is

begin pr_proc: processbegin print(" "); print("I hope this course has been useful, I'm looking forward"); print("to your comments at: [email protected]"); print(" "); print("Thanks"); print(" "); print("© Stefan Doll"); wait;

end process;

end text;

http://www.stefanvhdl.com/vhdl/vhdl/finish.vhd [1/13/2009 3:55:19 PM]

Page 132: Stefan Doll-VHDL Verification Course-UPDATED

###########################################################################

# Generates some test patterns # Stefan Doll, [email protected]#

# Usage:## perl tgen.pl > _output_file_##

###########################################################################

print "00010\n";print "00011\n";print "11100\n";

for ($i=0;$i<10;$i++) { print num2binary($i,5)."\n";}

print "1UXZW\n";print "HL111\n";print "11111\n";

sub num2binary { my($num) = @_; my $binary = $num ? '' : '0'; # in case $num is zero my $len = $_[1]; my $result;

while ($num) { $binary .= $num & 1 ? 1 : 0; # do the LSB $num >>= 1; # on to the next bit }

$result = scalar reverse $binary; while (length($result)<$len) { $result = "0".$result;

Page 133: Stefan Doll-VHDL Verification Course-UPDATED

}

return $result;}