«Бог не меняет того, что (происходит) с людьми, пока они сами не изменят своих помыслов.» Коран, Сура 12:13

Open Source VHDL Verification Methodology/Примеры

Материал из Wiki
< Open Source VHDL Verification Methodology
Версия от 01:43, 10 ноября 2012; ANA (обсуждение | вклад)

(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Это снимок страницы. Он включает старые, но не удалённые версии шаблонов и изображений.
Перейти к: навигация, поиск
Проект OS-VVM

Исходные коды

Описание примеров

Презентации

Coverage

* VHDL * PSL *

Содержание


FIFO

Файл: fifo.vhd
--#####################################################################
--# (c) Aldec, Inc.
--# All rights reserved.
--#
--# FIFO example with Randomization and Coverage Packages
--# Date Modified: Dec-20-2011
--#
--#  Verbatim copies of this source file may be used and
--#  distributed without restriction.
--#####################################################################
 
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.numeric_std.all;
 
entity fifo is
	generic
		(
		data_width  : integer := 8;
		fifo_depth  : integer := 128
	);
	port
		(
		rst       : in std_logic;
		wr_en     : in std_logic;
		wr_clk    : in std_logic;
		wr_data   : in std_logic_vector( data_width-1 downto 0 );
		rd_en     : in std_logic;
		rd_clk    : in std_logic;
		rd_data   : out std_logic_vector( data_width-1 downto 0 );
		empty     : out std_logic;
		full      : out std_logic
	);
end entity;
 
 
architecture behav of fifo is
 
	type memory_type is array ( 0 to fifo_depth-1 ) of std_logic_vector(wr_data'range);
 
	signal memory : memory_type;
 
 
	signal wr_ptr : integer := 0 ;--range memory'range(1);
	signal rd_ptr : integer := 0;--range memory'range(1);
	-- Used for PSL Checkers.
	-- signal wr_cnt : std_logic_vector(6 downto 0);
	--	signal rd_cnt : std_logic_vector(6 downto 0);
 
	signal empty_int    : std_logic;
	signal full_int     : std_logic;
	--signal full_delayed : std_logic;
 
begin
 
	process ( wr_clk, rst )
	begin
 
		if rising_edge(wr_clk) then
 
			if rst='1' then
				wr_ptr       <= 0;
 
 
			elsif wr_en='1' then
 
				if full_int ='0' then
					memory(wr_ptr) <= wr_data;
				end if;
 
				if full_int='0' then
					wr_ptr <= (wr_ptr+1) mod fifo_depth;
				end if;				
 
			end if;
 
		end if;
 
	end process;
 
 
	process ( rd_clk, rst )
	begin
 
		if rising_edge(rd_clk) then
 
			if rst='1' then
				rd_ptr <= 0;
			elsif rd_en='1' then
 
				if empty_int='0' then
					rd_ptr <= (rd_ptr+1) mod fifo_depth;
				end if;
 
			end if;
 
		end if;
 
	end process;
 
	rd_data <= memory(rd_ptr);
 
	empty_int <= '1' when rd_ptr=wr_ptr else '0';
	empty     <= empty_int;
 
	full_int  <= '1' when ((wr_ptr+1) mod fifo_depth)=rd_ptr else '0';
 
	full <= full_int;
 
 
end architecture;


Файл: tb_top.vhd
--------------------------------------------------------------------
-- (c) Aldec, Inc.
-- All rights reserved.
--
-- FIFO example with Randomization and Coverage Packages
-- Date Modified: Dec-20-2011
--
--  Verbatim copies of this source file may be used and
--  distributed without restriction.
--------------------------------------------------------------------
 
library ieee;
USE ieee.std_logic_1164.ALL;
--USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.ALL;
use ieee.math_real.all;
use std.textio.all;
 
use work.RandomBasePkg.all ; 
use work.RandomPkg.all ;
use work.CoveragePkg.all;
 
 
entity tb_top is
	generic
		(
		log_file: string  := "res.log";
		data_width  : integer := 8;
		clk_period : time := 40 ns;
		TimeOut : time := 200 us;
		fifo_dpth :integer := 128
	);
 
 
end tb_top;
 
 
architecture behavior of tb_top is
 
	file l_file: TEXT open write_mode is log_file;
 
	------- Component Declaration for the Unit Under Test (UUT)
 
	component fifo
		generic(
			data_width : INTEGER := 8;
			fifo_depth : INTEGER := 128
		);
		port(
			rst : in STD_LOGIC;
			wr_en : in STD_LOGIC;
			wr_clk : in STD_LOGIC;
			wr_data : in STD_LOGIC_VECTOR (data_width-1 downto 0);
			rd_en : in STD_LOGIC;
			rd_clk : in STD_LOGIC;
			rd_data : out STD_LOGIC_VECTOR (data_width-1 downto 0);
			empty : out STD_LOGIC;
			full : out STD_LOGIC
		);
	end component;
 
	----------------------------------------------------------------------------------------------------------------
 
	--the number of coverage bins (coverage points)
	constant numcb : integer := 3;
 
	signal reset     :std_logic := '1';
	signal clk    :std_logic := '0';
	signal fifo_re   :std_logic ;   
	signal dataout   :std_logic_vector(data_width-1 downto 0);		
	signal end_sim   :std_logic  :='0';
	signal full      :std_logic;
	signal empty     :std_logic;
	signal burstnum :integer := 0;
	signal wordnum   :integer := 0;
 
	--new changes
	signal cnt      :unsigned (1 downto 0) := "00";
	type state_type is (S_IDLE,S_DELAY,S_READ);  
	signal state: state_type; 
	signal rd_clk   :std_logic;
 
	--coverage objects
	shared variable cp1_full : CovPType;
	shared variable cp2_empty : CovPType;
	shared variable cp3_cross_we_full    : CovPType;
	shared variable cp4_illegal_re_empty   : CovPType;
 
 
	type FifoWrInfType is record 
		we     : std_logic ;
		datain   : std_logic_vector( data_width-1 downto 0 );
	end record;
	signal FifoWrInf : FifoWrInfType := (we => '0', datain => (others=>'0')) ;
 
 
	procedure GloablReset (signal reset : out std_logic ) is
	begin 
		reset <='1' ;
		wait for 80 ns;
		reset <='0' ;
	end procedure;
 
	procedure FifoWriteWord (
		word : in std_logic_vector(data_width-1 downto 0);
		signal	FifoWrInf : out FifoWrInfType ) is 
	begin		
		--setting the bus for fifo
		FifoWrInf.we <= '1';
		FifoWrInf.datain <= word;
		wait until rising_edge(clk);					
		--clearing write enable 
		FifoWrInf.we <= '0';
 
	end procedure;
 
	procedure FifoRandBurstWrite( 
		len : in integer;
		signal	FifoWrInf : out FifoWrInfType) is
		variable RV : RandomPType ;
		variable wordgen : std_logic_vector(data_width-1 downto 0);
	begin			
		--Sending len number of words to the fifo
		for i in 1 to len loop
			--Creating the random value to be sent to fifo
			wordgen := RV.RandSlv(0, 255, 8);
			--writing the word to fifo
			FifoWriteWord(wordgen, FifoWrInf);
		end loop;
	end procedure;	
 
	impure function getFC return Integer is
		--getFC function calculates the FC value as a persentage 
		variable tmp : real;
	begin
		--the illegal bins are not taken into account
		tmp := (real(to_integer(cp1_full.IsCovered)+to_integer(cp2_empty.IsCovered)+to_integer(cp3_cross_we_full.IsCovered))/real(numcb)) * 100.0;
		return integer(tmp);
	end function getFC;
 
	--adjustknobs procedure analyzes all bins and adjuct the constraints for random data to improve the probability of hitting 
	--uncovered bins
	procedure adjustknobs
		(	
		minlen : inout integer ;
		maxlen : inout integer ; 
		mindelay: inout integer ;
		maxdelay : inout integer
		)
		is	
		variable tmp : real;
	begin
		--the algorith below is just used as an example and 
		--by no means is the most effecient in adjusting left and right range for values generation		
 
		if (cp1_full.IsCovered = FALSE or cp3_cross_we_full.IsCovered = FALSE) then
			----reduce mindelay
			tmp := real(mindelay); --to real type
			tmp := tmp - tmp*0.3; --reducing by 30%
			--make sure mindelay is always >= 1
			if (integer(tmp) >= 1) then
				mindelay := integer(tmp); --back to integer
			else
				mindelay := 1; --to avoid going under 1
			end if;
			--reduce maxdelay
			tmp := real(maxdelay); --to real type
			tmp := tmp - tmp*0.3; --reducing by 30%
			--make sure maxdelay is always > then mindelay
			if (integer(tmp) > mindelay) then
				maxdelay := integer(tmp); --back to integer
			else
				maxdelay := mindelay + 1; --to avoid going under mindelay
			end if;
 
			--and increase the packet length
			tmp := real(maxlen); --to real type
			tmp := tmp + tmp*0.5; --increase by 50%			
			maxlen := integer(tmp); --back to integer			
 
		else 
			if (cp2_empty.IsCovered = FALSE) then
				-- to empty the fifo increase the delay between packets
				--increase mindelay
				tmp := real(mindelay); --to real type
				tmp := tmp + tmp*0.3; --increase by 30%
				mindelay := integer(tmp); --back to integer
 
				--increase maxdelay
				tmp := real(maxdelay); --to real type
				tmp := tmp + tmp*0.3; --increase by 30%
				maxdelay := integer(tmp); --back to integer
 
				--and reduce the packet lengh
				--reduce minlen
				tmp := real(minlen); --to real type
				tmp := tmp - tmp*0.3; --reducing by 30%				
				if (integer(tmp) >= 1) then
					minlen := integer(tmp); --back to integer
				else
					minlen := 1; --to avoid going under value 1
				end if;
 
				--reduce maxlen
				tmp := real(maxlen); --to real type
				tmp := tmp - tmp*0.3; --reducing by 30%				
				if (integer(tmp) > minlen) then
					maxlen := integer(tmp); --back to integer
				else
					maxlen := minlen + 1; --to avoid going under value 1
				end if;
			end if;
		end if;
 
	end procedure adjustknobs;
 
	procedure Message ( str : string ) is
		variable buf : LINE;
	begin
		write(buf, str);
		writeline(output, buf);
	end;
 
 
begin
	----------------------------------------------------------------------------------------------------------------	
 
	DUT: fifo
	generic map(
		data_width => 8,
	fifo_depth => 128)
	port map(
		rst => reset, 
		wr_en => FifoWrInf.we, 
		wr_clk => clk, 
		wr_data => FifoWrInf.datain, 
		rd_en => fifo_re, 
		rd_clk => rd_clk, 
		rd_data => dataout, 
		empty => empty,
		full => full
	);
 
	----------------------------------------------------------------------------------------------------------------
 
	TestFlow: process
		--This process implements writing to FIFO and also checking 
		--the FC results and adjusting the randomization if necessary
		variable delay : integer;
		variable len : integer;
		variable RV : RandomPType ; 
		variable FC_prev : integer:=0;
		variable FC : integer;
		variable minlen : integer := 10;
		variable maxlen : integer := 64;
		variable mindelay: integer := 1;
		variable maxdelay : integer := 20;
	begin
		--initializing the generator with the seed
		RV.InitSeed(RV'instance_name) ; 
 
		--reseting the DUT
		GloablReset(reset);
 
		--Main loop
		while (end_sim = '0') loop
 
			--random delay between sending the next packet			
			delay := RV.RandInt(mindelay, maxdelay);
			wait for delay * clk_period;
 
			-- Generating the random size packet and sending it to the fifo
			len := RV.RandInt(minlen, maxlen);
			FifoRandBurstWrite(len,FifoWrInf);
			--counting number of workds transfered (for statistics)
			wordnum <= wordnum + len;
 
			--checking the functional coverage
			FC := getFC;
			if FC = FC_prev then
				adjustknobs(minlen, maxlen, mindelay, maxdelay);				
			end if;
			--updating the FC_prev
			FC_prev := FC;
			--incrementing the packet counter ( for statistics)
			burstnum <= burstnum +1;
		end loop;
 
		wait;
	end process; 
	----------------------------------------------------------------------------------------------------------------	
	CoverageMonitor: process 		
		variable we_integer:integer;
		variable full_integer:integer; 	
		variable re_integer,empty_integer:integer;
		variable re_empty_illegal: std_logic;
		variable re_empty_illegal_integer: integer;
		variable RV : RandomPType ;
		variable bin_1d: CovBinBaseType;
		variable bin_2d: CovMatrix2BaseType;
		variable status_notFull, status_notEmpty, status_notWeFull: bit;
	begin		
		--creating bins for cover points
		--coverage point 1 - for fifo's full signal (High). The coverage goal is set to 3
		cp1_full.AddBins(3,GenBin(1));
		--coverage point 2 - for fifo's empty signal (High). The coverage goal is set to 3
		cp2_empty.AddBins(3,GenBin(1));
		--coverage point 3 - cross coverage for simultaneous FifoWrInfType.we and full signal. The coverage goal is set to 3
		cp3_cross_we_full.AddCross(3,GenBin(1), GenBin(1));
 
		-- coverage point 4 - creating illegal bin when empty and re are high at the same time
		cp4_illegal_re_empty.AddBins(IllegalBin(1));
 
		--setting the initial statuses. Statuses are used for proper coverage event counting towards the goal. For instance,
		--when FIFO gets full we don't want to increment the full coverage point again on the next clock cycle. Instead, we 
		--want to count the event when FIFO transitions from not being full to full.
		status_notFull := '1';
		status_notEmpty := '1';
		status_notWeFull := '1';
 
		--collecting coverage
		MainCovLoop: while not (cp1_full.IsCovered and cp2_empty.IsCovered and cp3_cross_we_full.IsCovered)	loop 
 
			wait until rising_edge(clk) and reset = '0';
			we_integer := to_integer(FifoWrInf.we);
			full_integer := to_integer(full);
			if full = '0' then
				status_notFull := '1';
			end if;
 
			re_integer := to_integer(fifo_re);
			empty_integer := to_integer(empty);
			if empty = '0' then 
				status_notEmpty := '1';
			end if;
 
			if not (FifoWrInf.we = '1' and full = '1') then
				status_notWeFull := '1';
			end if;
 
			re_empty_illegal := fifo_re and empty;
			re_empty_illegal_integer := to_integer(re_empty_illegal);
 
			--check if cp1 is covered
			if (cp1_full.IsCovered = FALSE and status_notFull = '1') then
				--if not then sample it
				cp1_full.ICover(to_integer(full) ) ;				
				if (full = '1') then
					status_notFull := '0';					
					if (cp1_full.IsCovered) then					
						Message("Covered condition *FIFO Full* @ " & time'image(now) );
					else 
						Message("Hit condition *FIFO Full* @ " & time'image(now) );						
					end if;
					cp1_full.WriteBin;
				end if;
			end if;
 
			--check if cp2 is covered
			if (cp2_empty.IsCovered = FALSE and status_notEmpty = '1') then 			
				--if not then sample it
				cp2_empty.ICover(to_integer(empty)) ;				
				if (empty = '1') then
					status_notEmpty := '0';
					if (cp2_empty.IsCovered) then
						Message("Covered condition *FIFO Empty* @ " & time'image(now) );
					else
						Message("Hit condition *FIFO Empty* @ " & time'image(now) );
					end if;
					cp2_empty.WriteBin ;
				end if;
			end if;
 
 
			--check if cp3 is covered
			if (cp3_cross_we_full.IsCovered = FALSE and status_notWeFull = '1') then 			
				--if not then sample it
				cp3_cross_we_full.ICover((we_integer, full_integer));				
				if (FifoWrInf.we = '1' and full = '1') then
					status_notWeFull := '0';
					if (cp3_cross_we_full.IsCovered) then					
						Message("Covered condition *Writing to full FIFO (we and full)* @ " & time'image(now) );
					else 
						Message("Hit condition *Writing to full FIFO (we and full)* @ " & time'image(now) );
					end if;
					cp3_cross_we_full.WriteBin ; 
				end if;
			end if;
 
			--check for the cp4 as long as the simulation is running
			cp4_illegal_re_empty.ICover(re_empty_illegal_integer);
 
			--Check for TimeOut and force exit when now is greater than TimeOut value
			exit MainCovLoop when now >= TimeOut;
 
		end loop;
 
 
		--Final reporting
		if now >= TimeOut then
			Message("TIME OUT. Cannot achieve the target functional coverage. You may try increasing the TimeOut generic in the tb_top instance.");
		else
			Message("SUCCESS. The functional coverage goal  is achieved.");			
		end if;
		Message("Number of burst transfers: " & integer'image(burstnum));
		Message("Total words transferred: " & integer'image(wordnum));
		Message("Coverage Goal: 100%");
		Message("Achieved Coverage: " & integer'image(getFC) & "%");
 
	    cp3_cross_we_full.WriteCovDb ("we_full.txt", OpenKind => WRITE_MODE );
		Message("Database written to 'we_full.txt' text file.");
		cp2_empty.WriteCovDb ("empty.txt", OpenKind => WRITE_MODE );
		Message("Database written to 'empty.txt' text file.");
		cp1_full.WriteCovDb ("full.txt", OpenKind => WRITE_MODE );
		Message("Database written to 'full.txt' text file.");
 
		--let the simulation run for a little longer before stopping it
		wait for 1 us;
		--end the simulation by suspending all the processes
		end_sim <= '1';
 
		wait;
	end process;
 
 
	---------------------------------------------------------------------------------------------------
	readInf:process (rd_clk,reset)
		variable RV :RandomPType;
		variable count: integer :=0;
		--mindelay and maxdelay are set to introduce some delay in CPU reaction to not empty fifo
		constant mindelay : integer:= 5;
		constant maxdelay : integer:= 30;
 
	begin
		--initializing the generator with the seed
		RV.InitSeed(RV'instance_name) ; 		
 
		if reset = '1' then
			state <= S_IDLE;
			--set random delay before CPU starts reading
			count := RV.RandInt(mindelay, maxdelay);
		elsif rising_edge(rd_clk)then
			case state is				
				--in IDLE state CPU waits until fifo becomes not empty				
				when S_IDLE => 
				if(empty ='1') then
					--set random delay before CPU starts reading
					count := RV.RandInt(mindelay, maxdelay);
				else
					state <= S_DELAY;
				end if;   
				--DELAY state inserts a delay before CPU starts actual reading
				when S_DELAY =>
				if(count > 0) then
					--decrement the counter and state in the same state			
					count := count - 1;					
				else
					state <= S_READ;					
				end if;
				--In READ state the read enable strobe will be set to high
				when S_READ =>
				--unless fifo is empty stay in the same state
				if(empty = '1') then  
					state <= S_IDLE;
				end if;
 
				when others  =>
				state <= S_IDLE;				
 
			end case;
		end if;
	end process;
 
	fifo_re <= '1' when (state = S_READ and empty = '0') else '0';	--added empty='0' to instantly disable reading when empty goes High.
	-------------------------------------------------------------------------------------------	
	clkGen : process
	begin
		if (end_sim = '0') then
			clk <= '0';
			wait for clk_period/2;
			clk <= '1';
			wait for clk_period/2;
		else 
			wait;--suspend the simulation
		end if;
	end process;
	-------------------------------------------------------------------------------------------	
	clk_slow:process (reset, clk)
	begin		
		if rising_edge(clk) then
			if (reset = '1') then 
				cnt <= (others => '0');
			else
				cnt <= cnt + 1;
			end if;
		end if;
	end process;
 
	rd_clk <= '1' when cnt = "11" else '0';
 
end architecture;


Sensors

Файл: sensors.vhd
-- ######################################################################################
-- # File: sensors.vhd
-- # Version: 1.1
-- # Dependencies: RandomPkg
-- #               CoveragePkg (revision 2.3 or newer)
-- # Functionality: This unit emulates reading from 8x8 matrix of sensors.
-- # Sensors are randomly filled with data (normal distribution, Mean and SD controlled
-- # with generics). Index values for reading from sensor matrix are either generated
-- # using uniform RNG or intelligent randomization feature of CoveragePkg (selection
-- # is controlled by generic).
-- # Coverage is collected for sensor index pairs and for sensor data. Current coverage
-- # results are used to control index generation (intelligent mode) and to flatten
-- # sensor data distribution for faster coverage.
-- # The test prints report in the console and saves coverage databases in two files.
-- ######################################################################################
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
use work.CoveragePkg.all;
use work.RandomPkg.all;
 
use std.textio.all;
 
entity sensors is
    generic
    (
        Intelligent : boolean := True;      -- Intelligent or Uniform index randomization
        DataMean : real := 128.0;           -- Mean value of sensor data distribution
        DataSDstart: real := 32.0;          -- SD of sensor data distribution
        DataSDinc: real := 4.0              -- increment of SD value auto-adjustment
    );
end entity sensors;
 
 
architecture behavior of sensors is
    signal END_TEST : boolean := false;         -- Flag that ends clock generation
    signal CLK: std_logic;                      -- Universal clocking signal
 
    type sensorsPType is protected              -- Type handling setting/retrieving sensor data
        procedure set ( X,Y,Val : integer );
        impure function get ( X,Y : integer ) return integer;
    end protected;
 
    type sensorsPType is protected body
        type data_array is array (0 to 7, 0 to 7) of integer;
        variable data : data_array := (others=>(others=>0));
 
        procedure set ( X,Y,Val : integer ) is  -- sets sensor data at position (X,Y)
        begin
            data(X, Y) := Val;
        end;
 
        impure function get ( X,Y : integer ) return integer is
        begin                                   -- gets sensor data from position (X,Y)
            return data(X, Y);
        end;
 
    end protected body;
 
    shared variable sensors : sensorsPType;     -- 8x8 sensor matrix
 
--    shared variable Rsens   : RandomPType;      -- Object for generating one sensor data
--    shared variable Rxy     : RandomPType;      -- Object for generating sensor indices
 
    shared variable DCov  : CovPType;           -- Object for sensor data coverpoint
    shared variable XYCov : CovPType;           -- Object for sensor address cross
 
    procedure Message ( str : string ) is       -- prints string argument to the console
        variable buf : LINE;
    begin
        write(buf, str);
        writeline(output, buf);
    end;
 
begin
-- This process provides initialization of random and coverage objects.
-- Data Collection loop runs until full data coverage is achieved.
-- Message is displayed within the loop when index coverage is achieved.
-- When all tests are done, END_TEST flag turns off clock generation.
-- Messages describing verification progress and final reports are printed from here.
  CollectCv : process
        variable Rxy : RandomPType;             -- object for generating sensor indices
        variable X,Y,SensorData : integer;      -- index and sensor data buffers
        variable buf : LINE;                    -- line buffer for direct text IO
        variable xycnt, dcnt : integer;         -- loop counters
        variable bin_1d: CovBinBaseType;        -- 1 dimensional bin data buffer
        variable bin_2d: CovMatrix2BaseType;    -- 2 dimensional bin data buffer
 
    begin
        Rxy.InitSeed(Rxy'instance_name);        -- seed array index random variable Rxy'instance_name
        DCov.AddBins(GenBin(0, 255, 16));           -- 16 bins (0 to 15, 16 to 31, ...)
        XYCov.AddCross(GenBin(0,7), GenBin(0,7));   -- 8x8 bin matrix.
        XYCov.InitSeed(XYCov'instance_name);    -- seed for intelligent coverage
        Message("*** Initialized Randomization and Coverage Structures ***");
        Message("  Data mean value set to " & real'image(DataMean));
        Message("  Data SD value set to " & real'image(DataSDstart));
 
        dcnt  := 0;                             -- initialize collection loop counter
        xycnt := 0;                             -- initialize index coverage counter
        Collect: while not DCov.IsCovered loop  -- collection loop runs until data covered
           wait until rising_edge(CLK);         -- sampling event detection
           if Intelligent then
              (X, Y) := XYCov.RandCovPoint;     -- randomize uncovered indices
           else
              X := Rxy.RandInt(0,7);            -- generate X array index
              Y := Rxy.RandInt(0,7);            -- generate Y array index
           end if;
           DCov.ICover(sensors.get(X, Y));      -- collect coverpoint data
           XYCov.ICover((X, Y));                -- collect cross data
           dcnt := dcnt + 1;                    -- incr. collection loop counter
           if xycnt=0 and XYCov.IsCovered then  -- index coverage just achieved
		      xycnt := dcnt;
              Message("# Index Coverage achieved after " & integer'image(xycnt) 
                       & " iterations.");
           end if;
        end loop Collect;
        Message("$ Sensor Data Coverage achieved after " & integer'image(dcnt) 
                 & " iterations.");
 
        END_TEST <= true;       -- We are done with testing - only reporting left...
        Message("*** Complete Coverage achieved !!! ***");
        Message("*******   Reporting Stage...   *******");
 
        -- DCov.WriteBin;  -- writing extensive report for coverpoint would be very long!
        Message("$$$ Sensor Data Coverage Results $$$");
        DmpD: for i in 1 to 16 loop     -- print 16 lines of data coverage results
            bin_1d := DCov.GetBin(i);   -- get 1 bin data
            Message("  Bin: " & integer'image(bin_1d.BinVal(1).min)     -- print bin value range
                     & " to " & integer'image(bin_1d.BinVal(1).max) 
                     & "; Count: " & integer'image(bin_1d.Count)    );  -- print bin count
        end loop DmpD;
        DCov.WriteCovDb ("quicktest_Dcovdb.txt", OpenKind => WRITE_MODE );  -- dump database
        Message("Database written to 'quicktest_Dcovdb.txt' text file.");
 
        --XYCov.WriteBin; -- writing extensive report for cross would be very long
        Message("####### Sensor Matrix Index Coverage Results #######");
        DmpRows: for i in 0 to 7 loop               -- sweep rows
            DmpY: for j in 0 to 7 loop              -- sweep columns
                bin_2d := XYCov.GetBin(1+i*8+j);    -- get 1 bin data
                write(buf, bin_2d.Count, FIELD=>6); -- write 6 characters per sensor
            end loop DmpY;                          -- buffer full now
            writeline(output, buf);                 -- dump buffer to the console
        end loop DmpRows;
        XYCov.WriteCovDb ("quicktest_XYcovdb.txt", OpenKind => WRITE_MODE );-- dump database
        Message("Database written to 'quicktest_XYcovdb.txt' text file.");
        Message("*** Goodbye! :-) ***");
 
        wait;                                   -- end of report - halt process
    end process CollectCv;    
 
-- This process generates sensor data for the entire matrix on every 64th falling clock edge.
-- If sensor index values are covered but sensor data is not covered yet, the process increases 
--  SD parameter of Normal distribution to speed up data coverage goal achievement.
-- Mean value, initial SD and SD increment are controlled by generics and can be changed 
--  from simulator command line without recompilation (-Gname=value).
  GenSensData : process
        variable Rsens : RandomPType;           -- object for generating one sensor data
        variable cnt6b : unsigned(5 downto 0) := (others=>'1');
        variable DataSD : real := DataSDstart;
    begin
        Rsens.InitSeed(Rsens'instance_name);    -- seed sensor data random variable
		wait for 0 ns;							-- force order of process execution
        GenSens: while not DCov.IsCovered loop
            wait until falling_edge(CLK);
            cnt6b := cnt6b + 1;         -- increment 6-bit counter
            if cnt6b=0 then             -- generate sensor data every 64th clock
                if not DCov.IsCovered and DataSDinc/= 0.0 then
                  -- When data coverage not yet achieved and SD incrementation allowed,
                  --  print current hole count and increment SD
                    Message("  Data coverage holes count is: " & integer'image(DCov.CountCovHoles));
                    DataSD := DataSD + DataSDinc;
                    Message("    Standard Deviation for data generation increased to " & real'image(DataSD));
                end if;
                for i in 0 to 7 loop
                    for j in 0 to 7 loop
                        sensors.set(i,j, Rsens.Normal(DataMean, DataSD, 1, 255));
                    end loop;
                end loop;
            end if;
        end loop GenSens;
        wait;
    end process GenSensData;
 
-- This process generates CLK signal (100MHz, 50%) as long as END_TEST flag is False
  ClkGen: process
    begin
        while not END_TEST loop         -- stop clock when test done
            CLK <= '0'; wait for 5 ns;
            CLK <= '1'; wait for 5 ns;
        end loop;
        wait;                           -- stop process forever
    end process ClkGen;
 
end architecture behavior;