Stefan Doll-VHDL Verification Course-UPDATED

Post on 02-Apr-2015

122 views 3 download

transcript

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, vc3@stefanVHDL.com

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]

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]

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]

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]

VHDL Verification Course

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

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]

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]

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]

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]

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]

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]

VHDL Verification Course

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

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

VHDL Verification Course

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

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]

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]

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]

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]

VHDL Verification Course

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

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

VHDL Verification Course

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

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]

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]

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]

VHDL Verification Course

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

VHDL Verification Course

The End

I hope this course has been useful, I'm looking forward to your comments at: vc2@stefanVHDL.com

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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

0001000011111001UXZWHL11111111

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

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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]

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: sdoll@intrinsix.com"); 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]

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

# Generates some test patterns # Stefan Doll, sdoll@intrinsix.com#

# 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;

}

return $result;}