diff options
Diffstat (limited to 'testsuite/gna/issue317/OSVVM/RandomPkg.vhd')
-rw-r--r-- | testsuite/gna/issue317/OSVVM/RandomPkg.vhd | 1647 |
1 files changed, 1647 insertions, 0 deletions
diff --git a/testsuite/gna/issue317/OSVVM/RandomPkg.vhd b/testsuite/gna/issue317/OSVVM/RandomPkg.vhd new file mode 100644 index 000000000..8c5065881 --- /dev/null +++ b/testsuite/gna/issue317/OSVVM/RandomPkg.vhd @@ -0,0 +1,1647 @@ +-- +-- File Name : RandomPkg.vhd +-- Design Unit Name : RandomPkg +-- Revision : STANDARD VERSION +-- +-- Maintainer : Jim Lewis email : jim@synthworks.com +-- Contributor(s) : +-- Jim Lewis email : jim@synthworks.com +-- * +-- +-- * In writing procedures normal, poisson, the following sources were referenced : +-- Wikipedia +-- package rnd2 written by John Breen and Ken Christensen +-- package RNG written by Gnanasekaran Swaminathan +-- +-- +-- Description : +-- RandomPType, a protected type, defined to hold randomization RandomSeeds and +-- function methods to facilitate randomization with uniform and weighted +-- distributions +-- +-- Developed for : +-- SynthWorks Design Inc. +-- VHDL Training Classes +-- 11898 SW 128th Ave. Tigard, Or 97223 +-- http ://www.SynthWorks.com +-- +-- Revision History : +-- Date Version Description +-- 12/2006 : 0.1 Initial revision +-- Numerous revisions for SynthWorks' Advanced VHDL Testbenches and Verification +-- 02/2009 : 1.0 First Public Released Version +-- 02/25/2009 1.1 Replaced reference to std_2008 with a reference to +-- ieee_proposed.standard_additions.all ; +-- 06/2010 1.2 Added Normal and Poisson distributions +-- 03/2011 2.0 Major clean-up. Moved RandomParmType and control to here +-- 07/2011 2.1 Bug fix to convenience functions for slv, unsigned, and signed. +-- 06/2012 2.2 Removed '_' in the name of subprograms FavorBig and FavorSmall +-- 04/2013 2013.04 Changed DistInt. Return array indices now match input +-- Better Min, Max error handling in Uniform, FavorBig, FavorSmall, Normal, Poisson +-- 5/2013 - Removed extra variable declaration in functions RandInt and RandReal +-- 5/2013 2013.05 Big vector randomization added overloading RandUnsigned, RandSlv, and RandSigned +-- Added NULL_RANGE_TYPE to minimize null range warnings +-- 1/2014 2014.01 Added RandTime, RandReal(set), RandIntV, RandRealV, RandTimeV +-- Made sort, revsort from SortListPkg_int visible via aliases +-- 1/2015 2015.01 Changed Assert/Report to Alert +-- 5/2015 2015.06 Revised Alerts to Alert(OSVVM_ALERTLOG_ID, ...) ; +-- 11/2016 2016.11 No changes. Updated release numbers to make documentation and +-- package have consistent release identifiers. +-- +-- Copyright (c) 2006 - 2016 by SynthWorks Design Inc. All rights reserved. +-- +-- Verbatim copies of this source file may be used and +-- distributed without restriction. +-- +-- This source file is free software ; you can redistribute it +-- and/or modify it under the terms of the ARTISTIC License +-- as published by The Perl Foundation ; either version 2.0 of +-- the License, or (at your option) any later version. +-- +-- This source is distributed in the hope that it will be +-- useful, but WITHOUT ANY WARRANTY ; without even the implied +-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +-- PURPOSE. See the Artistic License for details. +-- +-- You should have received a copy of the license with this source. +-- If not download it from, +-- http ://www.perlfoundation.org/artistic_license_2_0 +-- + +use work.OsvvmGlobalPkg.all ; +use work.AlertLogPkg.all ; +use work.RandomBasePkg.all ; +use work.SortListPkg_int.all ; + +use std.textio.all ; + +library ieee ; +use ieee.std_logic_1164.all ; +use ieee.numeric_std.all ; +use ieee.numeric_std_unsigned.all ; +use ieee.math_real.all ; + +-- comment out following 3 lines with VHDL-2008. Leave in for VHDL-2002 +-- library ieee_proposed ; -- remove with VHDL-2008 +-- use ieee_proposed.standard_additions.all ; -- remove with VHDL-2008 +-- use ieee_proposed.standard_textio_additions.all ; -- remove with VHDL-2008 + + +package RandomPkg is +-- Uncomment the following with VHDL-2008 package generics. +-- For now they are defined in the package RandomBasePkg.vhd +-- package RandomGenericPkg is + -- generic ( + -- type RandomSeedType ; -- base type for randomization + -- procedure Uniform (Result : out real ; Seed : inout RandomSeedType) ; + -- function GenRandSeed(IV : integer_vector) return RandomSeedType ; + -- function GenRandSeed(I : integer) return RandomSeedType ; + -- function GenRandSeed(S : string) return RandomSeedType ; + -- ) ; + + -- make things from SortListPkg_int visible + alias sort is work.SortListPkg_int.sort[integer_vector return integer_vector] ; + alias revsort is work.SortListPkg_int.revsort[integer_vector return integer_vector] ; + + -- note NULL_RANGE_TYPE should probably be in std.standard + subtype NULL_RANGE_TYPE is integer range 0 downto 1 ; + constant NULL_INTV : integer_vector (NULL_RANGE_TYPE) := (others => 0) ; + + -- Supports DistValInt functionality + type DistRecType is record + Value : integer ; + Weight : integer ; + end record ; + type DistType is array (natural range <>) of DistRecType ; + + + -- Parameters for randomization + -- RandomDistType specifies the distribution to use for randomize + type RandomDistType is (NONE, UNIFORM, FAVOR_SMALL, FAVOR_BIG, NORMAL, POISSON) ; + + type RandomParmType is record + Distribution : RandomDistType ; + Mean : Real ; -- also used as probability of success + StdDeviation : Real ; -- also used as number of trials for binomial + end record ; + + -- RandomParm IO + function to_string(A : RandomDistType) return string ; + procedure write(variable L : inout line ; A : RandomDistType ) ; + procedure read(variable L : inout line ; A : out RandomDistType ; good : out boolean ) ; + procedure read(variable L : inout line ; A : out RandomDistType ) ; + function to_string(A : RandomParmType) return string ; + procedure write(variable L : inout line ; A : RandomParmType ) ; + procedure read(variable L : inout line ; A : out RandomParmType ; good : out boolean ) ; + procedure read(variable L : inout line ; A : out RandomParmType ) ; + + + type RandomPType is protected + -- Seed Manipulation + -- Known ambiguity between InitSeed with string and integer_vector + -- Recommendation, use : RV.InitSeed(RV'instance_path) ; + -- For integer_vector use either : RV.InitSeed(IV => (1,5)) ; + -- or : RV.InitSeed(integer_vector'(1,5)) ; + procedure InitSeed (S : string ) ; + procedure InitSeed (I : integer ) ; + procedure InitSeed (IV : integer_vector ) ; + + -- SetSeed & GetSeed : Used to save and restore seed values + procedure SetSeed (RandomSeedIn : RandomSeedType ) ; + impure function GetSeed return RandomSeedType ; + -- SeedRandom = SetSeed & GetSeed for SV compatibility + -- replace with aliases when they work in popular simulators + procedure SeedRandom (RandomSeedIn : RandomSeedType ) ; + impure function SeedRandom return RandomSeedType ; + -- alias SeedRandom is SetSeed [RandomSeedType] ; + -- alias SeedRandom is GetSeed [return RandomSeedType] ; + + -- Setting Randomization Parameters + -- Allows RandInt to have distributions other than uniform + procedure SetRandomParm (RandomParmIn : RandomParmType) ; + procedure SetRandomParm ( + Distribution : RandomDistType ; + Mean : Real := 0.0 ; + Deviation : Real := 0.0 + ) ; + impure function GetRandomParm return RandomParmType ; + impure function GetRandomParm return RandomDistType ; + + -- For compatibility with previous version - replace with alias + procedure SetRandomMode (RandomDistIn : RandomDistType) ; + -- alias SetRandomMode is SetRandomParm [RandomDistType, Real, Real] ; + + -- Base Randomization Distributions + -- Uniform : Generate a random number with a Uniform distribution + impure function Uniform (Min, Max : in real) return real ; + impure function Uniform (Min, Max : integer) return integer ; + impure function Uniform (Min, Max : integer ; Exclude : integer_vector) return integer ; + + -- FavorSmall + -- Generate random numbers with a greater number of small + -- values than large values + impure function FavorSmall (Min, Max : real) return real ; + impure function FavorSmall (Min, Max : integer) return integer ; + impure function FavorSmall (Min, Max : integer ; Exclude : integer_vector) return integer ; + + -- FavorBig + -- Generate random numbers with a greater number of large + -- values than small values + impure function FavorBig (Min, Max : real) return real ; + impure function FavorBig (Min, Max : integer) return integer ; + impure function FavorBig (Min, Max : integer ; Exclude : integer_vector) return integer ; + + -- Normal : Generate a random number with a normal distribution + impure function Normal (Mean, StdDeviation : real) return real ; + -- Normal + RandomVal >= Min and RandomVal < Max + impure function Normal (Mean, StdDeviation, Min, Max : real) return real ; + impure function Normal ( + Mean : real ; + StdDeviation : real ; + Min : integer ; + Max : integer ; + Exclude : integer_vector := NULL_INTV + ) return integer ; + + -- Poisson : Generate a random number with a poisson distribution + -- Discrete distribution = only generates integral values + impure function Poisson (Mean : real) return real ; + -- Poisson + RandomVal >= Min and RandomVal < Max + impure function Poisson (Mean, Min, Max : real) return real ; + impure function Poisson ( + Mean : real ; + Min : integer ; + Max : integer ; + Exclude : integer_vector := NULL_INTV + ) return integer ; + + -- randomization with a range + impure function RandInt (Min, Max : integer) return integer ; + impure function RandReal(Min, Max : Real) return real ; + impure function RandTime (Min, Max : time ; Unit : time := ns) return time ; + impure function RandSlv (Min, Max, Size : natural) return std_logic_vector ; + impure function RandUnsigned (Min, Max, Size : natural) return Unsigned ; + impure function RandSigned (Min, Max : integer ; Size : natural ) return Signed ; + impure function RandIntV (Min, Max : integer ; Size : natural) return integer_vector ; + impure function RandIntV (Min, Max : integer ; Unique : natural ; Size : natural) return integer_vector ; + impure function RandRealV (Min, Max : real ; Size : natural) return real_vector ; + impure function RandTimeV (Min, Max : time ; Size : natural ; Unit : time := ns) return time_vector ; + impure function RandTimeV (Min, Max : time ; Unique : natural ; Size : natural ; Unit : time := ns) return time_vector ; + + -- randomization with a range and exclude vector + impure function RandInt (Min, Max : integer ; Exclude : integer_vector ) return integer ; + impure function RandTime (Min, Max : time ; Exclude : time_vector ; Unit : time := ns) return time ; + impure function RandSlv (Min, Max : natural ; Exclude : integer_vector ; Size : natural ) return std_logic_vector ; + impure function RandUnsigned (Min, Max : natural ; Exclude : integer_vector ; Size : natural ) return Unsigned ; + impure function RandSigned (Min, Max : integer ; Exclude : integer_vector ; Size : natural ) return Signed ; + impure function RandIntV (Min, Max : integer ; Exclude : integer_vector ; Size : natural) return integer_vector ; + impure function RandIntV (Min, Max : integer ; Exclude : integer_vector ; Unique : natural ; Size : natural) return integer_vector ; + impure function RandTimeV (Min, Max : time ; Exclude : time_vector ; Size : natural ; Unit : in time := ns) return time_vector ; + impure function RandTimeV (Min, Max : time ; Exclude : time_vector ; Unique : natural ; Size : natural ; Unit : in time := ns) return time_vector ; + + -- Randomly select a value within a set of values + impure function RandInt ( A : integer_vector ) return integer ; + impure function RandReal ( A : real_vector ) return real ; + impure function RandTime (A : time_vector) return time ; + impure function RandSlv (A : integer_vector ; Size : natural) return std_logic_vector ; + impure function RandUnsigned (A : integer_vector ; Size : natural) return Unsigned ; + impure function RandSigned (A : integer_vector ; Size : natural ) return Signed ; + impure function RandIntV (A : integer_vector ; Size : natural) return integer_vector ; + impure function RandIntV (A : integer_vector ; Unique : natural ; Size : natural) return integer_vector ; + impure function RandRealV (A : real_vector ; Size : natural) return real_vector ; + impure function RandRealV (A : real_vector ; Unique : natural ; Size : natural) return real_vector ; + impure function RandTimeV (A : time_vector ; Size : natural) return time_vector ; + impure function RandTimeV (A : time_vector ; Unique : natural ; Size : natural) return time_vector ; + + -- Randomly select a value within a set of values with exclude values (so can skip last or last n) + impure function RandInt ( A, Exclude : integer_vector ) return integer ; + impure function RandReal ( A, Exclude : real_vector ) return real ; + impure function RandTime (A, Exclude : time_vector) return time ; + impure function RandSlv (A, Exclude : integer_vector ; Size : natural) return std_logic_vector ; + impure function RandUnsigned (A, Exclude : integer_vector ; Size : natural) return Unsigned ; + impure function RandSigned (A, Exclude : integer_vector ; Size : natural ) return Signed ; + impure function RandIntV (A, Exclude : integer_vector ; Size : natural) return integer_vector ; + impure function RandIntV (A, Exclude : integer_vector ; Unique : natural ; Size : natural) return integer_vector ; + impure function RandRealV (A, Exclude : real_vector ; Size : natural) return real_vector ; + impure function RandRealV (A, Exclude : real_vector ; Unique : natural ; Size : natural) return real_vector ; + impure function RandTimeV (A, Exclude : time_vector ; Size : natural) return time_vector ; + impure function RandTimeV (A, Exclude : time_vector ; Unique : natural ; Size : natural) return time_vector ; + + -- Randomly select between 0 and N-1 based on the specified weight. + -- where N = number values in weight array + impure function DistInt ( Weight : integer_vector ) return integer ; + impure function DistSlv ( Weight : integer_vector ; Size : natural ) return std_logic_vector ; + impure function DistUnsigned ( Weight : integer_vector ; Size : natural ) return unsigned ; + impure function DistSigned ( Weight : integer_vector ; Size : natural ) return signed ; + + -- Distribution with just weights and with exclude values + impure function DistInt ( Weight : integer_vector ; Exclude : integer_vector ) return integer ; + impure function DistSlv ( Weight : integer_vector ; Exclude : integer_vector ; Size : natural ) return std_logic_vector ; + impure function DistUnsigned ( Weight : integer_vector ; Exclude : integer_vector ; Size : natural ) return unsigned ; + impure function DistSigned ( Weight : integer_vector ; Exclude : integer_vector ; Size : natural ) return signed ; + + -- Distribution with weight and value + impure function DistValInt ( A : DistType ) return integer ; + impure function DistValSlv ( A : DistType ; Size : natural) return std_logic_vector ; + impure function DistValUnsigned ( A : DistType ; Size : natural) return unsigned ; + impure function DistValSigned ( A : DistType ; Size : natural) return signed ; + + -- Distribution with weight and value and with exclude values + impure function DistValInt ( A : DistType ; Exclude : integer_vector ) return integer ; + impure function DistValSlv ( A : DistType ; Exclude : integer_vector ; Size : natural) return std_logic_vector ; + impure function DistValUnsigned ( A : DistType ; Exclude : integer_vector ; Size : natural) return unsigned ; + impure function DistValSigned ( A : DistType ; Exclude : integer_vector ; Size : natural) return signed ; + + -- Large vector handling. + impure function RandUnsigned (Size : natural) return unsigned ; + impure function RandSlv (Size : natural) return std_logic_vector ; + impure function RandSigned (Size : natural) return signed ; + impure function RandUnsigned (Max : Unsigned) return unsigned ; + impure function RandSlv (Max : std_logic_vector) return std_logic_vector ; + impure function RandSigned (Max : signed) return signed ; + impure function RandUnsigned (Min, Max : unsigned) return unsigned ; + impure function RandSlv (Min, Max : std_logic_vector) return std_logic_vector ; + impure function RandSigned (Min, Max : signed) return signed ; + + -- Convenience Functions + impure function RandReal return real ; -- 0.0 to 1.0 + impure function RandReal(Max : Real) return real ; -- 0.0 to Max + impure function RandInt (Max : integer) return integer ; + impure function RandSlv (Max, Size : natural) return std_logic_vector ; + impure function RandUnsigned (Max, Size : natural) return Unsigned ; + impure function RandSigned (Max : integer ; Size : natural ) return Signed ; + + end protected RandomPType ; + +end RandomPkg ; + +--- /////////////////////////////////////////////////////////////////////////// +--- /////////////////////////////////////////////////////////////////////////// +--- /////////////////////////////////////////////////////////////////////////// + +package body RandomPkg is + + ----------------------------------------------------------------- + -- Local Randomization Support + ----------------------------------------------------------------- + constant NULL_SLV : std_logic_vector (NULL_RANGE_TYPE) := (others => '0') ; + constant NULL_UV : unsigned (NULL_RANGE_TYPE) := (others => '0') ; + constant NULL_SV : signed (NULL_RANGE_TYPE) := (others => '0') ; + + ----------------------------------------------------------------- + -- Scale -- Scale a value to be within a given range + -- + function Scale (A, Min, Max : real) return real is + variable ValRange : Real ; + begin + if Max >= Min then + ValRange := Max - Min ; + return A * ValRange + Min ; + else + return real'left ; + end if ; + end function Scale ; + + function Scale (A : real ; Min, Max : integer) return integer is + variable ValRange : real ; + variable rMin, rMax : real ; + begin + if Max >= Min then + rMin := real(Min) - 0.5 ; + rMax := real(Max) + 0.5 ; + ValRange := rMax - rMin ; + return integer(round(A * ValRange + rMin)) ; + else + return integer'left ; + end if ; + end function Scale ; + + -- create more smaller values + function FavorSmall (A : real) return real is + begin + return 1.0 - sqrt(A) ; + end FavorSmall ; + + -- create more larger values + -- alias FavorBig is sqrt[real return real] ; + function FavorBig (A : real) return real is + begin + return sqrt(A) ; + end FavorBig ; + + -- local. + function to_time_vector (A : integer_vector ; Unit : time) return time_vector is + variable result : time_vector(A'range) ; + begin + for i in A'range loop + result(i) := A(i) * Unit ; + end loop ; + return result ; + end function to_time_vector ; + + -- local + function to_integer_vector (A : time_vector ; Unit : time) return integer_vector is + variable result : integer_vector(A'range) ; + begin + for i in A'range loop + result(i) := A(i) / Unit ; + end loop ; + return result ; + end function to_integer_vector ; + + -- Local. Remove the exclude list from the list - integer_vector + procedure RemoveExclude(A, Exclude : integer_vector ; variable NewA : out integer_vector ; variable NewALength : inout natural ) is + alias norm_NewA : integer_vector(1 to NewA'length) is NewA ; + begin + NewALength := 0 ; + for i in A'range loop + if not inside(A(i), Exclude) then + NewALength := NewALength + 1 ; + norm_NewA(NewALength) := A(i) ; + end if ; + end loop ; + end procedure RemoveExclude ; + + -- Local. Inside - real_vector + function inside(A : real ; Exclude : real_vector) return boolean is + begin + for i in Exclude'range loop + if A = Exclude(i) then + return TRUE ; + end if ; + end loop ; + return FALSE ; + end function inside ; + + -- Local. Remove the exclude list from the list - real_vector + procedure RemoveExclude(A, Exclude : real_vector ; variable NewA : out real_vector ; variable NewALength : inout natural ) is + alias norm_NewA : real_vector(1 to NewA'length) is NewA ; + begin + NewALength := 0 ; + for i in A'range loop + if not inside(A(i), Exclude) then + NewALength := NewALength + 1 ; + norm_NewA(NewALength) := A(i) ; + end if ; + end loop ; + end procedure RemoveExclude ; + + -- Local. Inside - time_vector + function inside(A : time ; Exclude : time_vector) return boolean is + begin + for i in Exclude'range loop + if A = Exclude(i) then + return TRUE ; + end if ; + end loop ; + return FALSE ; + end function inside ; + + -- Local. Remove the exclude list from the list - time_vector + procedure RemoveExclude(A, Exclude : time_vector ; variable NewA : out time_vector ; variable NewALength : inout natural ) is + alias norm_NewA : time_vector(1 to NewA'length) is NewA ; + begin + NewALength := 0 ; + for i in A'range loop + if not inside(A(i), Exclude) then + NewALength := NewALength + 1 ; + norm_NewA(NewALength) := A(i) ; + end if ; + end loop ; + end procedure RemoveExclude ; + + + ----------------------------------------------------------------- + -- RandomParmType IO + ----------------------------------------------------------------- + ----------------------------------------------------------------- + function to_string(A : RandomDistType) return string is + begin + return RandomDistType'image(A) ; + end function to_string ; + + + ----------------------------------------------------------------- + procedure write(variable L : inout line ; A : RandomDistType ) is + begin + write(L, to_string(A)) ; + end procedure write ; + + + ----------------------------------------------------------------- + procedure read(variable L : inout line ; A : out RandomDistType ; good : out boolean ) is + variable strval : string(1 to 40) ; + variable len : natural ; + begin + -- procedure SREAD (L : inout LINE ; VALUE : out STRING ; STRLEN : out NATURAL) ; + sread(L, strval, len) ; + A := RandomDistType'value(strval(1 to len)) ; + good := len > 0 ; + end procedure read ; + + + ----------------------------------------------------------------- + procedure read(variable L : inout line ; A : out RandomDistType ) is + variable ReadValid : boolean ; + begin + read(L, A, ReadValid) ; + AlertIfNot( OSVVM_ALERTLOG_ID, ReadValid, "RandomPkg.read[line, RandomDistType] failed", FAILURE) ; + end procedure read ; + + + ----------------------------------------------------------------- + function to_string(A : RandomParmType) return string is + begin + return RandomDistType'image(A.Distribution) & " " & + to_string(A.Mean, 2) & " " & to_string(A.StdDeviation, 2) ; + end function to_string ; + + + ----------------------------------------------------------------- + procedure write(variable L : inout line ; A : RandomParmType ) is + begin + write(L, to_string(A)) ; + end procedure write ; + + + ----------------------------------------------------------------- + procedure read(variable L : inout line ; A : out RandomParmType ; good : out boolean ) is + variable strval : string(1 to 40) ; + variable len : natural ; + variable igood : boolean ; + begin + loop + -- procedure SREAD (L : inout LINE ; VALUE : out STRING ; STRLEN : out NATURAL) ; + sread(L, strval, len) ; + A.Distribution := RandomDistType'value(strval(1 to len)) ; + igood := len > 0 ; + exit when not igood ; + + read(L, A.Mean, igood) ; + exit when not igood ; + + read(L, A.StdDeviation, igood) ; + exit ; + end loop ; + good := igood ; + end procedure read ; + + + ----------------------------------------------------------------- + procedure read(variable L : inout line ; A : out RandomParmType ) is + variable ReadValid : boolean ; + begin + read(L, A, ReadValid) ; + AlertIfNot( OSVVM_ALERTLOG_ID, ReadValid, "RandomPkg.read[line, RandomParmType] failed", FAILURE) ; + end procedure read ; + + + + ----------------------------------------------------------------- + ----------------------------------------------------------------- + type RandomPType is protected body + -- + -- RandomSeed manipulation + -- + variable RandomSeed : RandomSeedType := GenRandSeed(integer_vector'(1,7)) ; + + procedure InitSeed (S : string ) is + begin + RandomSeed := GenRandSeed(S) ; + end procedure InitSeed ; + + procedure InitSeed (I : integer ) is + begin + RandomSeed := GenRandSeed(I) ; + end procedure InitSeed ; + + procedure InitSeed (IV : integer_vector ) is + begin + RandomSeed := GenRandSeed(IV) ; + end procedure InitSeed ; + + procedure SetSeed (RandomSeedIn : RandomSeedType ) is + begin + RandomSeed := RandomSeedIn ; + end procedure SetSeed ; + + procedure SeedRandom (RandomSeedIn : RandomSeedType ) is + begin + RandomSeed := RandomSeedIn ; + end procedure SeedRandom ; + + impure function GetSeed return RandomSeedType is + begin + return RandomSeed ; + end function GetSeed ; + + impure function SeedRandom return RandomSeedType is + begin + return RandomSeed ; + end function SeedRandom ; + + + -- + -- randomization mode + -- + variable RandomParm : RandomParmType ; -- left most values ok for init + + procedure SetRandomParm (RandomParmIn : RandomParmType) is + begin + RandomParm := RandomParmIn ; + end procedure SetRandomParm ; + + procedure SetRandomParm ( + Distribution : RandomDistType ; + Mean : Real := 0.0 ; + Deviation : Real := 0.0 + ) is + begin + RandomParm := RandomParmType'(Distribution, Mean, Deviation) ; + end procedure SetRandomParm ; + + + impure function GetRandomParm return RandomParmType is + begin + return RandomParm ; + end function GetRandomParm ; + + + impure function GetRandomParm return RandomDistType is + begin + return RandomParm.Distribution ; + end function GetRandomParm ; + + + -- For compatibility with previous version + procedure SetRandomMode (RandomDistIn : RandomDistType) is + begin + SetRandomParm(RandomDistIn) ; + end procedure SetRandomMode ; + + + -- + -- Base Randomization Distributions + -- + -- + -- Uniform : Generate a random number with a Uniform distribution + -- + impure function Uniform (Min, Max : in real) return real is + variable rRandomVal : real ; + begin + AlertIf (OSVVM_ALERTLOG_ID, Max < Min, "RandomPkg.Uniform: Max < Min", FAILURE) ; + Uniform(rRandomVal, RandomSeed) ; + return scale(rRandomVal, Min, Max) ; + end function Uniform ; + + impure function Uniform (Min, Max : integer) return integer is + variable rRandomVal : real ; + begin + AlertIf (OSVVM_ALERTLOG_ID, Max < Min, "RandomPkg.Uniform: Max < Min", FAILURE) ; + Uniform(rRandomVal, RandomSeed) ; + return scale(rRandomVal, Min, Max) ; + end function Uniform ; + + impure function Uniform (Min, Max : integer ; Exclude : integer_vector) return integer is + variable iRandomVal : integer ; + variable ExcludeList : SortListPType ; + variable count : integer ; + begin + ExcludeList.add(Exclude, Min, Max) ; + count := ExcludeList.count ; + iRandomVal := Uniform(Min, Max - count) ; + -- adjust count, note iRandomVal changes while checking. + for i in 1 to count loop + exit when iRandomVal < ExcludeList.Get(i) ; + iRandomVal := iRandomVal + 1 ; + end loop ; + ExcludeList.erase ; + return iRandomVal ; + end function Uniform ; + + + -- + -- FavorSmall + -- Generate random numbers with a greater number of small + -- values than large values + -- + impure function FavorSmall (Min, Max : real) return real is + variable rRandomVal : real ; + begin + AlertIf (OSVVM_ALERTLOG_ID, Max < Min, "RandomPkg.FavorSmall: Max < Min", FAILURE) ; + Uniform(rRandomVal, RandomSeed) ; + return scale(FavorSmall(rRandomVal), Min, Max) ; -- real + end function FavorSmall ; + + impure function FavorSmall (Min, Max : integer) return integer is + variable rRandomVal : real ; + begin + AlertIf (OSVVM_ALERTLOG_ID, Max < Min, "RandomPkg.FavorSmall: Max < Min", FAILURE) ; + Uniform(rRandomVal, RandomSeed) ; + return scale(FavorSmall(rRandomVal), Min, Max) ; -- integer + end function FavorSmall ; + + impure function FavorSmall (Min, Max : integer ; Exclude : integer_vector) return integer is + variable iRandomVal : integer ; + variable ExcludeList : SortListPType ; + variable count : integer ; + begin + ExcludeList.add(Exclude, Min, Max) ; + count := ExcludeList.count ; + iRandomVal := FavorSmall(Min, Max - count) ; + -- adjust count, note iRandomVal changes while checking. + for i in 1 to count loop + exit when iRandomVal < ExcludeList.Get(i) ; + iRandomVal := iRandomVal + 1 ; + end loop ; + ExcludeList.erase ; + return iRandomVal ; + end function FavorSmall ; + + + -- + -- FavorBig + -- Generate random numbers with a greater number of large + -- values than small values + -- + impure function FavorBig (Min, Max : real) return real is + variable rRandomVal : real ; + begin + AlertIf (OSVVM_ALERTLOG_ID, Max < Min, "RandomPkg.FavorBig: Max < Min", FAILURE) ; + Uniform(rRandomVal, RandomSeed) ; + return scale(FavorBig(rRandomVal), Min, Max) ; -- real + end function FavorBig ; + + impure function FavorBig (Min, Max : integer) return integer is + variable rRandomVal : real ; + begin + AlertIf (OSVVM_ALERTLOG_ID, Max < Min, "RandomPkg.FavorBig: Max < Min", FAILURE) ; + Uniform(rRandomVal, RandomSeed) ; + return scale(FavorBig(rRandomVal), Min, Max) ; -- integer + end function FavorBig ; + + impure function FavorBig (Min, Max : integer ; Exclude : integer_vector) return integer is + variable iRandomVal : integer ; + variable ExcludeList : SortListPType ; + variable count : integer ; + begin + ExcludeList.add(Exclude, Min, Max) ; + count := ExcludeList.count ; + iRandomVal := FavorBig(Min, Max - count) ; + -- adjust count, note iRandomVal changes while checking. + for i in 1 to count loop + exit when iRandomVal < ExcludeList.Get(i) ; + iRandomVal := iRandomVal + 1 ; + end loop ; + ExcludeList.erase ; + return iRandomVal ; + end function FavorBig ; + + + ----------------------------------------------------------------- + -- Normal + -- Generate a random number with a normal distribution + -- + -- Use Box Muller, per Wikipedia : + -- http ://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform + -- + -- Use polar method, per Wikipedia : + -- http ://en.wikipedia.org/wiki/Marsaglia_polar_method + -- + impure function Normal (Mean, StdDeviation : real) return real is + variable x01, y01 : real ; + variable StdNormalDist : real ; -- mean 0, variance 1 + begin + -- add this check to set parameters? + if StdDeviation < 0.0 then + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.Normal: Standard deviation must be >= 0.0", FAILURE) ; + return -1.0 ; + end if ; + + -- Box Muller + Uniform (x01, RandomSeed) ; + Uniform (y01, RandomSeed) ; + StdNormalDist := sqrt(-2.0 * log(x01)) * cos(math_2_pi*y01) ; + + -- Polar form rejected due to mean 50.0, std deviation = 5 resulted + -- in a median of 49 + -- -- find two Uniform distributed values with range -1 to 1 + -- -- that satisify S = X **2 + Y**2 < 1.0 + -- loop + -- Uniform (x01, RandomSeed) ; + -- Uniform (y01, RandomSeed) ; + -- x := 2.0 * x01 - 1.0 ; -- scale to -1 to 1 + -- y := 2.0 * y01 - 1.0 ; + -- s := x*x + y*y ; + -- exit when s < 1.0 and s > 0.0 ; + -- end loop ; + + -- -- Calculate Standard Normal Distribution + -- StdNormalDist := x * sqrt((-2.0 * log(s)) / s) ; + + -- Convert to have Mean and StdDeviation + return StdDeviation * StdNormalDist + Mean ; + end function Normal ; + + + -- Normal + RandomVal >= Min and RandomVal <= Max + impure function Normal (Mean, StdDeviation, Min, Max : real) return real is + variable rRandomVal : real ; + begin + if Max < Min then + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.Normal: Max < Min", FAILURE) ; + return Mean ; + else + loop + rRandomVal := Normal (Mean, StdDeviation) ; + exit when rRandomVal >= Min and rRandomVal <= Max ; + end loop ; + end if ; + return rRandomVal ; + end function Normal ; + + -- Normal + RandomVal >= Min and RandomVal <= Max + impure function Normal ( + Mean : real ; + StdDeviation : real ; + Min : integer ; + Max : integer ; + Exclude : integer_vector := NULL_INTV + ) return integer is + variable iRandomVal : integer ; + begin + if Max < Min then + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.Normal: Max < Min", FAILURE) ; + return integer(round(Mean)) ; + else + loop + iRandomVal := integer(round( Normal(Mean, StdDeviation) )) ; + exit when iRandomVal >= Min and iRandomVal <= Max and + not inside(iRandomVal, Exclude) ; + end loop ; + end if ; + return iRandomVal ; + end function Normal ; + + + ----------------------------------------------------------------- + -- Poisson + -- Generate a random number with a poisson distribution + -- Discrete distribution = only generates integral values + -- + -- Use knuth method, per Wikipedia : + -- http ://en.wikipedia.org/wiki/Poisson_distribution + -- + impure function Poisson (Mean : real) return real is + variable Product : Real := 1.0 ; + variable Bound : Real := 0.0 ; + variable UniformRand : Real := 0.0 ; + variable PoissonRand : Real := 0.0 ; + begin + Bound := exp(-1.0 * Mean) ; + Product := 1.0 ; + + -- add this check to set parameters? + if Mean <= 0.0 or Bound <= 0.0 then + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.Poisson: Mean < 0 or too large. Mean = " & real'image(Mean), FAILURE) ; + return Mean ; + end if ; + + while (Product >= Bound) loop + PoissonRand := PoissonRand + 1.0 ; + Uniform(UniformRand, RandomSeed) ; + Product := Product * UniformRand ; + end loop ; + return PoissonRand ; + end function Poisson ; -- no range + + -- Poisson + RandomVal >= Min and RandomVal < Max + impure function Poisson (Mean, Min, Max : real) return real is + variable rRandomVal : real ; + begin + if Max < Min then + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.Poisson: Max < Min", FAILURE) ; + return Mean ; + else + loop + rRandomVal := Poisson (Mean) ; + exit when rRandomVal >= Min and rRandomVal <= Max ; + end loop ; + end if ; + return rRandomVal ; + end function Poisson ; + + impure function Poisson ( + Mean : real ; + Min : integer ; + Max : integer ; + Exclude : integer_vector := NULL_INTV + ) return integer is + variable iRandomVal : integer ; + begin + if Max < Min then + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.Poisson: Max < Min", FAILURE) ; + return integer(round(Mean)) ; + else + loop + iRandomVal := integer(round( Poisson (Mean) )) ; + exit when iRandomVal >= Min and iRandomVal <= Max and + not inside(iRandomVal, Exclude) ; + end loop ; + end if ; + return iRandomVal ; + end function Poisson ; + + + -- + -- integer randomization with a range + -- Distribution determined by RandomParm + -- + impure function RandInt (Min, Max : integer) return integer is + begin + case RandomParm.Distribution is + when NONE | UNIFORM => return Uniform(Min, Max) ; + when FAVOR_SMALL => return FavorSmall(Min, Max) ; + when FAVOR_BIG => return FavorBig (Min, Max) ; + when NORMAL => return Normal(RandomParm.Mean, RandomParm.StdDeviation, Min, Max) ; + when POISSON => return Poisson(RandomParm.Mean, Min, Max) ; + when others => + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.RandInt: RandomParm.Distribution not implemented", FAILURE) ; + return integer'low ; + end case ; + end function RandInt ; + + -- + -- real randomization with a range + -- Distribution determined by RandomParm + -- + impure function RandReal(Min, Max : Real) return real is + begin + case RandomParm.Distribution is + when NONE | UNIFORM => return Uniform(Min, Max) ; + when FAVOR_SMALL => return FavorSmall(Min, Max) ; + when FAVOR_BIG => return FavorBig (Min, Max) ; + when NORMAL => return Normal(RandomParm.Mean, RandomParm.StdDeviation, Min, Max) ; + when POISSON => return Poisson(RandomParm.Mean, Min, Max) ; + when others => + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.RandReal: Specified RandomParm.Distribution not implemented", FAILURE) ; + return real(integer'low) ; + end case ; + end function RandReal ; + + impure function RandTime (Min, Max : time ; Unit :time := ns) return time is + variable IntVal : integer ; + begin + -- if Max - Min > 2**31 result will be out of range + IntVal := RandInt(0, (Max - Min)/Unit) ; + Return Min + Unit*IntVal ; + end function RandTime ; + + impure function RandSlv (Min, Max, Size : natural) return std_logic_vector is + begin + return std_logic_vector(to_unsigned(RandInt(Min, Max), Size)) ; + end function RandSlv ; + + impure function RandUnsigned (Min, Max, Size : natural) return Unsigned is + begin + return to_unsigned(RandInt(Min, Max), Size) ; + end function RandUnsigned ; + + impure function RandSigned (Min, Max : integer ; Size : natural ) return Signed is + begin + return to_signed(RandInt(Min, Max), Size) ; + end function RandSigned ; + + impure function RandIntV (Min, Max : integer ; Size : natural) return integer_vector is + variable result : integer_vector(1 to Size) ; + begin + for i in result'range loop + result(i) := RandInt(Min, Max) ; + end loop ; + return result ; + end function RandIntV ; + + impure function RandIntV (Min, Max : integer ; Unique : natural ; Size : natural) return integer_vector is + variable result : integer_vector(1 to Size) ; + variable iUnique : natural ; + begin + -- if Unique = 0, it is more efficient to call RandIntV(Min, Max, Size) + iUnique := Unique ; + if Max-Min+1 < Unique then + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.(RandIntV | RandRealV | RandTimeV): Unique > number of values available", FAILURE) ; + iUnique := Max-Min+1 ; + end if ; + for i in result'range loop + result(i) := RandInt(Min, Max, result(maximum(1, 1 + i - iUnique) to Size)) ; + end loop ; + return result ; + end function RandIntV ; + + impure function RandRealV (Min, Max : real ; Size : natural) return real_vector is + variable result : real_vector(1 to Size) ; + begin + for i in result'range loop + result(i) := RandReal(Min, Max) ; + end loop ; + return result ; + end function RandRealV ; + + impure function RandTimeV (Min, Max : time ; Size : natural ; Unit : time := ns) return time_vector is + variable result : time_vector(1 to Size) ; + begin + for i in result'range loop + result(i) := RandTime(Min, Max, Unit) ; + end loop ; + return result ; + end function RandTimeV ; + + impure function RandTimeV (Min, Max : time ; Unique : natural ; Size : natural ; Unit : time := ns) return time_vector is + begin + -- if Unique = 0, it is more efficient to call RandTimeV(Min, Max, Size) + return to_time_vector(RandIntV(Min/Unit, Max/Unit, Unique, Size), Unit) ; + end function RandTimeV ; + + + -- + -- integer randomization with a range and exclude vector + -- Distribution determined by RandomParm + -- + impure function RandInt (Min, Max : integer ; Exclude : integer_vector ) return integer is + begin + case RandomParm.Distribution is + when NONE | UNIFORM => return Uniform(Min, Max, Exclude) ; + when FAVOR_SMALL => return FavorSmall(Min, Max, Exclude) ; + when FAVOR_BIG => return FavorBig (Min, Max, Exclude) ; + when NORMAL => return Normal(RandomParm.Mean, RandomParm.StdDeviation, Min, Max, Exclude) ; + when POISSON => return Poisson(RandomParm.Mean, Min, Max, Exclude) ; + when others => + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.RandInt: Specified RandomParm.Distribution not implemented", FAILURE) ; + return integer'low ; + end case ; + end function RandInt ; + + impure function RandTime (Min, Max : time ; Exclude : time_vector ; Unit : time := ns) return time is + variable IntVal : integer ; + begin + -- if Min or Max > 2**31 value will be out of range + return RandInt(Min/Unit, Max/Unit, to_integer_vector(Exclude, Unit)) * Unit ; + end function RandTime ; + + impure function RandSlv (Min, Max : natural ; Exclude : integer_vector ; Size : natural ) return std_logic_vector is + begin + return std_logic_vector(to_unsigned(RandInt(Min, Max, Exclude), Size)) ; + end function RandSlv ; + + impure function RandUnsigned (Min, Max : natural ; Exclude : integer_vector ; Size : natural ) return Unsigned is + begin + return to_unsigned(RandInt(Min, Max, Exclude), Size) ; + end function RandUnsigned ; + + impure function RandSigned (Min, Max : integer ; Exclude : integer_vector ; Size : natural ) return Signed is + begin + return to_signed(RandInt(Min, Max, Exclude), Size) ; + end function RandSigned ; + + impure function RandIntV (Min, Max : integer ; Exclude : integer_vector ; Size : natural) return integer_vector is + variable result : integer_vector(1 to Size) ; + begin + for i in result'range loop + result(i) := RandInt(Min, Max, Exclude) ; + end loop ; + return result ; + end function RandIntV ; + + impure function RandIntV (Min, Max : integer ; Exclude : integer_vector ; Unique : natural ; Size : natural) return integer_vector is + variable ResultPlus : integer_vector(1 to Size + Exclude'length) ; + begin + -- if Unique = 0, it is more efficient to call RandIntV(Min, Max, Size) + ResultPlus(Size+1 to ResultPlus'right) := Exclude ; + for i in 1 to Size loop + ResultPlus(i) := RandInt(Min, Max, ResultPlus(maximum(1, 1 + i - Unique) to ResultPlus'right)) ; + end loop ; + return ResultPlus(1 to Size) ; + end function RandIntV ; + + impure function RandTimeV (Min, Max : time ; Exclude : time_vector ; Size : natural ; Unit : in time := ns) return time_vector is + begin + return to_time_vector( RandIntV(Min/Unit, Max/Unit, to_integer_vector(Exclude, Unit), Size), Unit ) ; + end function RandTimeV ; + + impure function RandTimeV (Min, Max : time ; Exclude : time_vector ; Unique : natural ; Size : natural ; Unit : in time := ns) return time_vector is + begin + -- if Unique = 0, it is more efficient to call RandIntV(Min, Max, Size) + return to_time_vector( RandIntV(Min/Unit, Max/Unit, to_integer_vector(Exclude, Unit), Unique, Size), Unit ) ; + end function RandTimeV ; + + + + -- + -- Randomly select a value within a set of values + -- Distribution determined by RandomParm + -- + impure function RandInt ( A : integer_vector ) return integer is + alias A_norm : integer_vector(1 to A'length) is A ; + begin + return A_norm( RandInt(1, A'length) ) ; + end function RandInt ; + + impure function RandReal ( A : real_vector ) return real is + alias A_norm : real_vector(1 to A'length) is A ; + begin + return A_norm( RandInt(1, A'length) ) ; + end function RandReal ; + + impure function RandTime ( A : time_vector ) return time is + alias A_norm : time_vector(1 to A'length) is A ; + begin + return A_norm( RandInt(1, A'length) ) ; + end function RandTime ; + + impure function RandSlv (A : integer_vector ; Size : natural) return std_logic_vector is + begin + return std_logic_vector(to_unsigned(RandInt(A), Size)) ; + end function RandSlv ; + + impure function RandUnsigned (A : integer_vector ; Size : natural) return Unsigned is + begin + return to_unsigned(RandInt(A), Size) ; + end function RandUnsigned ; + + impure function RandSigned (A : integer_vector ; Size : natural ) return Signed is + begin + return to_signed(RandInt(A), Size) ; + end function RandSigned ; + + impure function RandIntV (A : integer_vector ; Size : natural) return integer_vector is + variable result : integer_vector(1 to Size) ; + begin + for i in result'range loop + result(i) := RandInt(A) ; + end loop ; + return result ; + end function RandIntV ; + + impure function RandIntV (A : integer_vector ; Unique : natural ; Size : natural) return integer_vector is + variable result : integer_vector(1 to Size) ; + variable iUnique : natural ; + begin + -- if Unique = 0, it is more efficient to call RandIntV(A, Size) + -- require A'length >= Unique + iUnique := Unique ; + if A'length < Unique then + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.RandIntV: Unique > length of set of values", FAILURE) ; + iUnique := A'length ; + end if ; + for i in result'range loop + result(i) := RandInt(A, result(maximum(1, 1 + i - iUnique) to Size)) ; + end loop ; + return result ; + end function RandIntV ; + + impure function RandRealV (A : real_vector ; Size : natural) return real_vector is + variable result : real_vector(1 to Size) ; + begin + for i in result'range loop + result(i) := RandReal(A) ; + end loop ; + return result ; + end function RandRealV ; + + impure function RandRealV (A : real_vector ; Unique : natural ; Size : natural) return real_vector is + alias A_norm : real_vector(1 to A'length) is A ; + variable result : real_vector(1 to Size) ; + variable IntResult : integer_vector(result'range) ; + begin + -- randomly generate indices + IntResult := RandIntV(1, A'length, Unique, Size) ; + -- translate indicies into result values + for i in result'range loop + result(i) := A_norm(IntResult(i)) ; + end loop ; + return result ; + end function RandRealV ; + + impure function RandTimeV (A : time_vector ; Size : natural) return time_vector is + variable result : time_vector(1 to Size) ; + begin + for i in result'range loop + result(i) := RandTime(A) ; + end loop ; + return result ; + end function RandTimeV ; + + impure function RandTimeV (A : time_vector ; Unique : natural ; Size : natural) return time_vector is + alias A_norm : time_vector(1 to A'length) is A ; + variable result : time_vector(1 to Size) ; + variable IntResult : integer_vector(result'range) ; + begin + -- randomly generate indices + IntResult := RandIntV(1, A'length, Unique, Size) ; + -- translate indicies into result values + for i in result'range loop + result(i) := A_norm(IntResult(i)) ; + end loop ; + return result ; + end function RandTimeV ; + + + -- + -- Randomly select a value within a set of values with exclude values (so can skip last or last n) + -- Distribution determined by RandomParm + -- + + impure function RandInt ( A, Exclude : integer_vector ) return integer is + variable NewA : integer_vector(1 to A'length) ; + variable NewALength : natural ; + begin + -- Remove Exclude from A + RemoveExclude(A, Exclude, NewA, NewALength) ; + -- Randomize Index + return NewA(RandInt(1, NewALength)) ; + end function RandInt ; + + impure function RandReal ( A, Exclude : real_vector ) return real is + variable NewA : real_vector(1 to A'length) ; + variable NewALength : natural ; + begin + -- Remove Exclude from A + RemoveExclude(A, Exclude, NewA, NewALength) ; + -- Randomize Index + return NewA(RandInt(1, NewALength)) ; + end function RandReal ; + + impure function RandTime ( A, Exclude : time_vector ) return time is + variable NewA : time_vector(1 to A'length) ; + variable NewALength : natural ; + begin + -- Remove Exclude from A + RemoveExclude(A, Exclude, NewA, NewALength) ; + -- Randomize Index + return NewA(RandInt(1, NewALength)) ; + end function RandTime ; + + impure function RandSlv (A, Exclude : integer_vector ; Size : natural) return std_logic_vector is + begin + return std_logic_vector(to_unsigned(RandInt(A, Exclude), Size)) ; + end function RandSlv ; + + impure function RandUnsigned (A, Exclude : integer_vector ; Size : natural) return Unsigned is + begin + return to_unsigned(RandInt(A, Exclude), Size) ; + end function RandUnsigned ; + + impure function RandSigned (A, Exclude : integer_vector ; Size : natural ) return Signed is + begin + return to_signed(RandInt(A, Exclude), Size) ; + end function RandSigned ; + + impure function RandIntV (A, Exclude : integer_vector ; Size : natural) return integer_vector is + variable result : integer_vector(1 to Size) ; + variable NewA : integer_vector(1 to A'length) ; + variable NewALength : natural ; + begin + -- Remove Exclude from A + RemoveExclude(A, Exclude, NewA, NewALength) ; + -- Randomize Index + for i in result'range loop + result(i) := NewA(RandInt(1, NewALength)) ; + end loop ; + return result ; + end function RandIntV ; + + impure function RandIntV (A, Exclude : integer_vector ; Unique : natural ; Size : natural) return integer_vector is + variable result : integer_vector(1 to Size) ; + variable NewA : integer_vector(1 to A'length) ; + variable NewALength, iUnique : natural ; + begin + -- if Unique = 0, it is more efficient to call RandIntV(Min, Max, Size) + -- Remove Exclude from A + RemoveExclude(A, Exclude, NewA, NewALength) ; + -- Require NewALength >= Unique + iUnique := Unique ; + if NewALength < Unique then + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.RandIntV: Unique > Length of Set A - Exclude", FAILURE) ; + iUnique := NewALength ; + end if ; + -- Randomize using exclude list of Unique # of newly generated values + for i in result'range loop + result(i) := RandInt(NewA(1 to NewALength), result(maximum(1, 1 + i - iUnique) to Size)) ; + end loop ; + return result ; + end function RandIntV ; + + impure function RandRealV (A, Exclude : real_vector ; Size : natural) return real_vector is + variable result : real_vector(1 to Size) ; + variable NewA : real_vector(1 to A'length) ; + variable NewALength : natural ; + begin + -- Remove Exclude from A + RemoveExclude(A, Exclude, NewA, NewALength) ; + -- Randomize Index + for i in result'range loop + result(i) := NewA(RandInt(1, NewALength)) ; + end loop ; + return result ; + end function RandRealV ; + + impure function RandRealV (A, Exclude : real_vector ; Unique : natural ; Size : natural) return real_vector is + variable result : real_vector(1 to Size) ; + variable NewA : real_vector(1 to A'length) ; + variable NewALength, iUnique : natural ; + begin + -- if Unique = 0, it is more efficient to call RandRealV(Min, Max, Size) + -- Remove Exclude from A + RemoveExclude(A, Exclude, NewA, NewALength) ; + -- Require NewALength >= Unique + iUnique := Unique ; + if NewALength < Unique then + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.RandRealV: Unique > Length of Set A - Exclude", FAILURE) ; + iUnique := NewALength ; + end if ; + -- Randomize using exclude list of Unique # of newly generated values + for i in result'range loop + result(i) := RandReal(NewA(1 to NewALength), result(maximum(1, 1 + i - iUnique) to Size)) ; + end loop ; + return result ; + end function RandRealV ; + + impure function RandTimeV (A, Exclude : time_vector ; Size : natural) return time_vector is + variable result : time_vector(1 to Size) ; + variable NewA : time_vector(1 to A'length) ; + variable NewALength : natural ; + begin + -- Remove Exclude from A + RemoveExclude(A, Exclude, NewA, NewALength) ; + -- Randomize Index + for i in result'range loop + result(i) := NewA(RandInt(1, NewALength)) ; + end loop ; + return result ; + end function RandTimeV ; + + impure function RandTimeV (A, Exclude : time_vector ; Unique : natural ; Size : natural) return time_vector is + variable result : time_vector(1 to Size) ; + variable NewA : time_vector(1 to A'length) ; + variable NewALength, iUnique : natural ; + begin + -- if Unique = 0, it is more efficient to call RandRealV(Min, Max, Size) + -- Remove Exclude from A + RemoveExclude(A, Exclude, NewA, NewALength) ; + -- Require NewALength >= Unique + iUnique := Unique ; + if NewALength < Unique then + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.RandTimeV: Unique > Length of Set A - Exclude", FAILURE) ; + iUnique := NewALength ; + end if ; + -- Randomize using exclude list of Unique # of newly generated values + for i in result'range loop + result(i) := RandTime(NewA(1 to NewALength), result(maximum(1, 1 + i - iUnique) to Size)) ; + end loop ; + return result ; + end function RandTimeV ; + + + -- + -- Basic Discrete Distributions + -- Always uses Uniform + -- + impure function DistInt ( Weight : integer_vector ) return integer is + variable DistArray : integer_vector(weight'range) ; + variable sum : integer ; + variable iRandomVal : integer ; + begin + DistArray := Weight ; + sum := 0 ; + for i in DistArray'range loop + DistArray(i) := DistArray(i) + sum ; + if DistArray(i) < sum then + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.DistInt: negative weight or sum > 31 bits", FAILURE) ; + return DistArray'low ; -- allows debugging vs integer'left, out of range + end if ; + sum := DistArray(i) ; + end loop ; + if sum >= 1 then + iRandomVal := Uniform(1, sum) ; + for i in DistArray'range loop + if iRandomVal <= DistArray(i) then + return i ; + end if ; + end loop ; + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.DistInt: randomization failed", FAILURE) ; + else + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.DistInt: No randomization weights", FAILURE) ; + end if ; + return DistArray'low ; -- allows debugging vs integer'left, out of range + end function DistInt ; + + impure function DistSlv ( Weight : integer_vector ; Size : natural ) return std_logic_vector is + begin + return std_logic_vector(to_unsigned(DistInt(Weight), Size)) ; + end function DistSlv ; + + impure function DistUnsigned ( Weight : integer_vector ; Size : natural ) return unsigned is + begin + return to_unsigned(DistInt(Weight), Size) ; + end function DistUnsigned ; + + impure function DistSigned ( Weight : integer_vector ; Size : natural ) return signed is + begin + return to_signed(DistInt(Weight), Size) ; + end function DistSigned ; + + + -- + -- Basic Distributions with exclude values (so can skip last or last n) + -- Always uses Uniform via DistInt + -- + impure function DistInt ( Weight : integer_vector ; Exclude : integer_vector ) return integer is + variable DistArray : integer_vector(weight'range) ; + variable ExcludeTemp : integer ; + begin + DistArray := Weight ; + for i in Exclude'range loop + ExcludeTemp := Exclude(i) ; + if ExcludeTemp >= DistArray'low and ExcludeTemp <= DistArray'high then + DistArray(ExcludeTemp) := 0 ; + end if ; + end loop ; + return DistInt(DistArray) ; + end function DistInt ; + + impure function DistSlv ( Weight : integer_vector ; Exclude : integer_vector ; Size : natural ) return std_logic_vector is + begin + return std_logic_vector(to_unsigned(DistInt(Weight, Exclude), Size)) ; + end function DistSlv ; + + impure function DistUnsigned ( Weight : integer_vector ; Exclude : integer_vector ; Size : natural ) return unsigned is + begin + return to_unsigned(DistInt(Weight, Exclude), Size) ; + end function DistUnsigned ; + + impure function DistSigned ( Weight : integer_vector ; Exclude : integer_vector ; Size : natural ) return signed is + begin + return to_signed(DistInt(Weight, Exclude), Size) ; + end function DistSigned ; + + + -- + -- Distribution for sparse values + -- Always uses Uniform via DistInt + -- + impure function DistValInt ( A : DistType ) return integer is + variable DistArray : integer_vector(0 to A'length -1) ; + alias DistRecArray : DistType(DistArray'range) is A ; + begin + for i in DistArray'range loop + DistArray(i) := DistRecArray(i).Weight ; + end loop ; + return DistRecArray(DistInt(DistArray)).Value ; + end function DistValInt ; + + impure function DistValSlv ( A : DistType ; Size : natural ) return std_logic_vector is + begin + return std_logic_vector(to_unsigned(DistValInt(A), Size)) ; + end function DistValSlv ; + + impure function DistValUnsigned ( A : DistType ; Size : natural ) return unsigned is + begin + return to_unsigned(DistValInt(A), Size) ; + end function DistValUnsigned ; + + impure function DistValSigned ( A : DistType ; Size : natural ) return signed is + begin + return to_signed(DistValInt(A), Size) ; + end function DistValSigned ; + + + -- + -- Distribution for sparse values with exclude values (so can skip last or last n) + -- Always uses Uniform via DistInt + -- + impure function DistValInt ( A : DistType ; Exclude : integer_vector ) return integer is + variable DistArray : integer_vector(0 to A'length -1) ; + alias DistRecArray : DistType(DistArray'range) is A ; + begin + for i in DistRecArray'range loop + if inside(DistRecArray(i).Value, exclude) then + DistArray(i) := 0 ; -- exclude + else + DistArray(i) := DistRecArray(i).Weight ; + end if ; + end loop ; + return DistRecArray(DistInt(DistArray)).Value ; + end function DistValInt ; + + impure function DistValSlv ( A : DistType ; Exclude : integer_vector ; Size : natural ) return std_logic_vector is + begin + return std_logic_vector(to_unsigned(DistValInt(A, Exclude), Size)) ; + end function DistValSlv ; + + impure function DistValUnsigned ( A : DistType ; Exclude : integer_vector ; Size : natural ) return unsigned is + begin + return to_unsigned(DistValInt(A, Exclude), Size) ; + end function DistValUnsigned ; + + impure function DistValSigned ( A : DistType ; Exclude : integer_vector ; Size : natural ) return signed is + begin + return to_signed(DistValInt(A, Exclude), Size) ; + end function DistValSigned ; + + + -- + -- Large vector handling. + -- + impure function RandUnsigned (Size : natural) return unsigned is + constant NumLoops : integer := integer(ceil(real(Size)/30.0)) ; + constant Remain : integer := (Size - 1) mod 30 + 1 ; -- range 1 to 30 + variable RandVal : unsigned(1 to Size) ; + begin + if size = 0 then + return NULL_UV ; -- Null array + end if ; + for i in 0 to NumLoops-2 loop + RandVal(1 + 30*i to 30 + 30*i) := to_unsigned(RandInt(0, 2**30-1), 30) ; + end loop ; + RandVal(1+30*(NumLoops-1) to Remain + 30*(NumLoops-1)) := to_unsigned(RandInt(0, 2**Remain-1), Remain) ; + return RandVal ; + end function RandUnsigned ; + + impure function RandSlv (Size : natural) return std_logic_vector is + begin + return std_logic_vector(RandUnsigned(Size)) ; + end function RandSlv ; + + impure function RandSigned (Size : natural) return signed is + begin + return signed(RandUnsigned(Size)) ; + end function RandSigned ; + + + impure function RandUnsigned (Max : unsigned) return unsigned is + alias normMax : unsigned (Max'length downto 1) is Max ; + variable Result : unsigned(Max'range) := (others => '0') ; + alias normResult : unsigned(normMax'range) is Result ; + variable Size : integer ; + begin + -- Size = -1 if not found or Max'length = 0 + Size := find_leftmost(normMax, '1') ; + + if Size > 0 then + loop + normResult(Size downto 1) := RandUnsigned(Size) ; + exit when normResult <= Max ; + end loop ; + return Result ; -- = normResult with range same as Max + else + return resize("0", Max'length) ; + end if ; + end function RandUnsigned ; + + -- Working version that scales the value + -- impure function RandUnsigned (Max : unsigned) return unsigned is + -- constant MaxVal : unsigned(Max'length+3 downto 1) := (others => '1') ; + -- begin + -- if max'length > 0 then + -- -- "Max'length+3" creates 3 guard bits + -- return resize( RandUnsigned(Max'length+3) * ('0'&Max+1) / ('0'&MaxVal+1), Max'length) ; + -- else + -- return NULL_UV ; -- Null Array + -- end if ; + -- end function RandUnsigned ; + + impure function RandSlv (Max : std_logic_vector) return std_logic_vector is + begin + return std_logic_vector(RandUnsigned( unsigned(Max))) ; + end function RandSlv ; + + impure function RandSigned (Max : signed) return signed is + begin + if max'length > 0 then + AlertIf (OSVVM_ALERTLOG_ID, Max < 0, "RandomPkg.RandSigned: Max < 0", FAILURE) ; + return signed(RandUnsigned( unsigned(Max))) ; + else + return NULL_SV ; -- Null Array + end if ; + end function RandSigned ; + + + impure function RandUnsigned (Min, Max : unsigned) return unsigned is + constant LEN : integer := maximum(Max'length, Min'length) ; + begin + if LEN > 0 and Min <= Max then + return RandUnsigned(Max-Min) + Min ; + else + if Len > 0 then + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.RandUnsigned: Max < Min", FAILURE) ; + end if ; + return NULL_UV ; + end if ; + end function RandUnsigned ; + + + impure function RandSlv (Min, Max : std_logic_vector) return std_logic_vector is + constant LEN : integer := maximum(Max'length, Min'length) ; + begin + if LEN > 0 and Min <= Max then + return RandSlv(Max-Min) + Min ; + else + if Len > 0 then + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.RandSlv: Max < Min", FAILURE) ; + end if ; + return NULL_SlV ; + end if ; + end function RandSlv ; + + + impure function RandSigned (Min, Max : signed) return signed is + constant LEN : integer := maximum(Max'length, Min'length) ; + begin + if LEN > 0 and Min <= Max then + return resize(RandSigned(resize(Max,LEN+1) - resize(Min,LEN+1)) + Min, LEN) ; + else + if Len > 0 then + Alert(OSVVM_ALERTLOG_ID, "RandomPkg.RandSigned: Max < Min", FAILURE) ; + end if ; + return NULL_SV ; + end if ; + end function RandSigned ; + + + -- + -- Convenience Functions. Resolve into calls into the other functions + -- + impure function RandReal return real is + begin + return RandReal(0.0, 1.0) ; + end function RandReal ; + + impure function RandReal(Max : Real) return real is -- 0.0 to Max + begin + return RandReal(0.0, Max) ; + end function RandReal ; + + impure function RandInt (Max : integer) return integer is + begin + return RandInt(0, Max) ; + end function RandInt ; + + impure function RandSlv (Max, Size : natural) return std_logic_vector is + begin + return std_logic_vector(to_unsigned(RandInt(0, Max), Size)) ; + end function RandSlv ; + + impure function RandUnsigned (Max, Size : natural) return Unsigned is + begin + return to_unsigned(RandInt(0, Max), Size) ; + end function RandUnsigned ; + + + impure function RandSigned (Max : integer ; Size : natural ) return Signed is + begin + -- chose 0 to Max rather than -Max to +Max to be same as RandUnsigned, either seems logical + return to_signed(RandInt(0, Max), Size) ; + end function RandSigned ; + + end protected body RandomPType ; + +end RandomPkg ;
\ No newline at end of file |