diff --git a/test/Makefile b/test/Makefile index 341fbfd..14ccd3a 100644 --- a/test/Makefile +++ b/test/Makefile @@ -3,12 +3,16 @@ SYN_SRC = ../syn VHD_STD = 02 .PHONY: sim -sim: vhdl2008 queuet simt spit +sim: vhdl2008 osvvm queuet simt spit .PHONY: vhdl2008 vhdl2008 : env_c.vhd numeric_std_additions.vhd numeric_std_unsigned_c.vhd standard_additions_c.vhd standard_textio_additions_c.vhd std_logic_1164_additions.vhd ghdl -a --std=$(VHD_STD) --work=ieee_proposed standard_additions_c.vhd standard_textio_additions_c.vhd std_logic_1164_additions.vhd numeric_std_additions.vhd numeric_std_unsigned_c.vhd env_c.vhd +.PHONY: osvvm +osvvm : vhdl2008 osvvm_2.1/SortListPkg_int.vhd osvvm_2.1/RandomBasePkg.vhd osvvm_2.1/RandomPkg.vhd + ghdl -a --std=$(VHD_STD) --work=osvvm --ieee=synopsys osvvm_2.1/SortListPkg_int.vhd osvvm_2.1/RandomBasePkg.vhd osvvm_2.1/RandomPkg.vhd + queuet : QueueT.vhd $(SIM_SRC)/QueueP.vhd $(SIM_SRC)/AssertP.vhd ghdl -a --std=$(VHD_STD) --work=libvhdl $(SIM_SRC)/AssertP.vhd $(SIM_SRC)/QueueP.vhd ghdl -a --std=$(VHD_STD) QueueT.vhd @@ -21,11 +25,11 @@ simt : vhdl2008 SimT.vhd $(SIM_SRC)/AssertP.vhd $(SIM_SRC)/SimP.vhd ghdl -e --std=$(VHD_STD) SimT ghdl -r --std=$(VHD_STD) SimT -spit : vhdl2008 SpiT.vhd $(SIM_SRC)/AssertP.vhd $(SIM_SRC)/SimP.vhd $(SYN_SRC)/SpiSlaveE.vhd $(SYN_SRC)/SpiMasterE.vhd - ghdl -a --std=$(VHD_STD) --work=libvhdl $(SIM_SRC)/AssertP.vhd $(SIM_SRC)/SimP.vhd +spit : vhdl2008 osvvm SpiT.vhd $(SIM_SRC)/AssertP.vhd $(SIM_SRC)/SimP.vhd $(SIM_SRC)/QueueP.vhd $(SYN_SRC)/SpiSlaveE.vhd $(SYN_SRC)/SpiMasterE.vhd + ghdl -a --std=$(VHD_STD) --work=libvhdl $(SIM_SRC)/AssertP.vhd $(SIM_SRC)/SimP.vhd $(SIM_SRC)/QueueP.vhd ghdl -a --std=$(VHD_STD) -fpsl $(SYN_SRC)/SpiSlaveE.vhd $(SYN_SRC)/SpiMasterE.vhd - ghdl -a --std=$(VHD_STD) -fpsl SpiT.vhd - ghdl -e --std=$(VHD_STD) SpiT + ghdl -a --std=$(VHD_STD) --ieee=synopsys -fpsl SpiT.vhd + ghdl -e --std=$(VHD_STD) --ieee=synopsys SpiT ghdl -r --std=$(VHD_STD) SpiT --wave=spit.ghw .PHONY: clean diff --git a/test/SpiT.vhd b/test/SpiT.vhd index 92378ea..10537b1 100644 --- a/test/SpiT.vhd +++ b/test/SpiT.vhd @@ -2,16 +2,22 @@ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; -library libvhdl; - use libvhdl.AssertP.all; - use libvhdl.SimP.all; - --+ including vhdl 2008 libraries +--+ These lines can be commented out when using +--+ a simulator with built-in VHDL 2008 support library ieee_proposed; use ieee_proposed.standard_additions.all; use ieee_proposed.std_logic_1164_additions.all; use ieee_proposed.numeric_std_additions.all; +library osvvm; + use osvvm.RandomPkg.all; + +library libvhdl; + use libvhdl.AssertP.all; + use libvhdl.SimP.all; + use libvhdl.QueueP.all; + entity SpiT is @@ -117,18 +123,24 @@ begin signal s_dout_valid : std_logic; signal s_dout_accept : std_logic; + shared variable sv_mosi_queue : t_list_queue; + shared variable sv_miso_queue : t_list_queue; + begin SpiMasterStimP : process is + variable v_random : RandomPType; begin + v_random.InitSeed(v_random'instance_name); wait until s_reset_n = '1'; for i in 0 to integer'(2**C_DATA_WIDTH-1) loop - s_din <= std_logic_vector(to_unsigned(i, C_DATA_WIDTH)); + s_din <= v_random.RandSlv(C_DATA_WIDTH); s_din_valid <= '1'; wait until rising_edge(s_clk) and s_din_accept = '1'; s_din_valid <= '0'; + sv_mosi_queue.push(s_din); wait until rising_edge(s_clk); end loop; wait; @@ -162,12 +174,14 @@ begin SpiMasterCheckP : process is + variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); begin wait until s_reset_n = '1'; for i in 0 to integer'(2**C_DATA_WIDTH-1) loop wait until rising_edge(s_clk) and s_dout_valid = '1'; s_dout_accept <= '1'; - assert_equal(s_dout, std_logic_vector(to_unsigned(i, C_DATA_WIDTH))); + sv_miso_queue.pop(v_queue_data); + assert_equal(s_dout, v_queue_data); wait until rising_edge(s_clk); s_dout_accept <= '0'; end loop; @@ -180,11 +194,18 @@ begin -- Unit test of spi slave procedure, checks all combinations -- of cpol & cpha against spi master procedure SpiSlaveP : process is - variable v_master_data : std_logic_vector(7 downto 0) := (others => '0'); + variable v_send_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); + variable v_receive_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); + variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); + variable v_random : RandomPType; begin + v_random.InitSeed(v_random'instance_name); + wait until s_reset_n = '1'; for i in 0 to integer'(2**C_DATA_WIDTH-1) loop - spi_slave (data_in => v_master_data, - data_out => v_master_data, + v_send_data := v_random.RandSlv(C_DATA_WIDTH); + sv_miso_queue.push(v_send_data); + spi_slave (data_in => v_send_data, + data_out => v_receive_data, sclk => s_sclk, ste => s_ste, mosi => s_mosi, @@ -192,8 +213,8 @@ begin cpol => mode / 2, cpha => mode mod 2 ); - assert_equal(v_master_data, std_logic_vector(to_unsigned(i, C_DATA_WIDTH))); - v_master_data := std_logic_vector(unsigned(v_master_data) + 1); + sv_mosi_queue.pop(v_queue_data); + assert_equal(v_receive_data, v_queue_data); end loop; wait; end process SpiSlaveP; diff --git a/test/osvvm_2.1/RandomBasePkg.vhd b/test/osvvm_2.1/RandomBasePkg.vhd new file mode 100644 index 0000000..67d0736 --- /dev/null +++ b/test/osvvm_2.1/RandomBasePkg.vhd @@ -0,0 +1,224 @@ +-- +-- File Name: RandomBasePkg.vhd +-- Design Unit Name: RandomBasePkg +-- Revision: STANDARD VERSION, revision 2.0, VHDL-2008 +-- +-- Maintainer: Jim Lewis email: jim@synthworks.com +-- Contributor(s): +-- Jim Lewis jim@synthworks.com +-- +-- +-- Description: +-- Defines Base randomization, seed definition, seed generation, +-- and seed IO functionality for RandomPkg.vhd +-- Defines: +-- Procedure Uniform - baseline randomization +-- Type RandomSeedType - the seed as a single object +-- function GenRandSeed from integer_vector, integer, or string +-- IO function to_string, & procedures write, read +-- +-- In revision 2.0 these types and functions are included by package reference. +-- Long term these will be passed as generics to RandomGenericPkg +-- +-- +-- Developed for: +-- SynthWorks Design Inc. +-- VHDL Training Classes +-- 11898 SW 128th Ave. Tigard, Or 97223 +-- http://www.SynthWorks.com +-- +-- Revision History: +-- Date Version Description +-- 01/2008: 0.1 Initial revision +-- Numerous revisions for 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 ; +-- 03/01/2011 2.0 STANDARD VERSION +-- Fixed abstraction by moving RandomParmType to RandomPkg.vhd +-- +-- +-- Copyright (c) 2008, 2009, 2010, 2011 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 +-- + +library ieee ; +use ieee.math_real.all ; +use std.textio.all ; + +-- comment out following 2 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 + + +package RandomBasePkg is + + -- RandomSeedType and Uniform can be replaced by any procedure that + -- produces a uniform distribution with 0 <= Value < 1 or 0 < Value < 1 + -- and maintains the same call interface + type RandomSeedType is array (1 to 2) of integer ; + procedure Uniform (Result : out real ; Seed : inout RandomSeedType) ; + + -- Translate from integer_vector, integer, or string to RandomSeedType + -- Required by RandomPkg.InitSeed + -- GenRandSeed makes sure all values are in a valid range + function GenRandSeed(IV : integer_vector) return RandomSeedType ; + function GenRandSeed(I : integer) return RandomSeedType ; + function GenRandSeed(S : string) return RandomSeedType ; + + -- IO for RandomSeedType. If use subtype, then create aliases here + -- in a similar fashion VHDL-2008 std_logic_textio. + -- Not required by RandomPkg + function to_string(A : RandomSeedType) return string ; + procedure write(variable L: inout line ; A : RandomSeedType ) ; + procedure read (variable L: inout line ; A : out RandomSeedType ; good : out boolean ) ; + procedure read (variable L: inout line ; A : out RandomSeedType ) ; + +end RandomBasePkg ; + ----------------------------------------------------------------- + ----------------------------------------------------------------- +package body RandomBasePkg is + + ----------------------------------------------------------------- + -- Uniform + -- Generate a random number with a Uniform distribution + -- Required by RandomPkg. All randomization is derived from here. + -- Value produced must be either: + -- 0 <= Value < 1 or 0 < Value < 1 + -- + -- Current version uses ieee.math_real.Uniform + -- This abstraction allows higher precision version + -- of a uniform distribution to be used provided + -- + procedure Uniform ( + Result : out real ; + Seed : inout RandomSeedType + ) is + begin + ieee.math_real.Uniform (Seed(Seed'left), Seed(Seed'right), Result) ; + end procedure Uniform ; + + + ----------------------------------------------------------------- + -- GenRandSeed + -- Convert integer_vector to RandomSeedType + -- Uniform requires two seed values of the form: + -- 1 <= SEED1 <= 2147483562; 1 <= SEED2 <= 2147483398 + -- + -- if 2 seed values are passed to GenRandSeed and they are + -- in the above range, then they must remain unmodified. + -- + function GenRandSeed(IV : integer_vector) return RandomSeedType is + alias iIV : integer_vector(1 to IV'length) is IV ; + variable Seed1 : integer ; + variable Seed2 : integer ; + constant SEED1_MAX : integer := 2147483562 ; + constant SEED2_MAX : integer := 2147483398 ; + begin + if iIV'Length <= 0 then -- no seed + report "%%FATAL: GenRandSeed received NULL integer_vector" severity failure ; + return (3, 17) ; -- if continue seed = (3, 17) + + elsif iIV'Length = 1 then -- one seed value + -- inefficient handling, but condition is unlikely + return GenRandSeed(iIV(1)) ; -- generate a seed + + else -- only use the left two values + -- 1 <= SEED1 <= 2147483562 + -- mod returns 0 to MAX-1, the -1 adjusts legal values, +1 adjusts them back + Seed1 := ((iIV(1)-1) mod SEED1_MAX) + 1 ; + -- 1 <= SEED2 <= 2147483398 + Seed2 := ((iIV(2)-1) mod SEED2_MAX) + 1 ; + return (Seed1, Seed2) ; + end if ; + end function GenRandSeed ; + + + ----------------------------------------------------------------- + -- GenRandSeed + -- transform a single integer into the internal seed + -- + function GenRandSeed(I : integer) return RandomSeedType is + variable result : integer_vector(1 to 2) ; + begin + result(1) := I ; + result(2) := I/3 + 1 ; + return GenRandSeed(result) ; -- make value ranges legal + end function GenRandSeed ; + + + ----------------------------------------------------------------- + -- GenRandSeed + -- transform a string value into the internal seed + -- usage: RV.GenRandSeed(RV'instance_path)); + -- + function GenRandSeed(S : string) return RandomSeedType is + constant LEN : integer := S'length ; + constant HALF_LEN : integer := LEN/2 ; + alias revS : string(LEN downto 1) is S ; + variable result : integer_vector(1 to 2) ; + variable temp : integer := 0 ; + begin + for i in 1 to HALF_LEN loop + temp := (temp + character'pos(revS(i))) mod (integer'right - 2**8) ; + end loop ; + result(1) := temp ; + for i in HALF_LEN + 1 to LEN loop + temp := (temp + character'pos(revS(i))) mod (integer'right - 2**8) ; + end loop ; + result(2) := temp ; + return GenRandSeed(result) ; -- make value ranges legal + end function GenRandSeed ; + + + ----------------------------------------------------------------- + function to_string(A : RandomSeedType) return string is + begin + return to_string(A(A'left)) & " " & to_string(A(A'right)) ; + end function to_string ; + + + ----------------------------------------------------------------- + procedure write(variable L: inout line ; A : RandomSeedType ) is + begin + write(L, to_string(A)) ; + end procedure ; + + + ----------------------------------------------------------------- + procedure read(variable L: inout line ; A : out RandomSeedType ; good : out boolean ) is + variable iGood : boolean ; + begin + for i in A'range loop + read(L, A(i), iGood) ; + exit when not iGood ; + end loop ; + good := iGood ; + end procedure read ; + + + ----------------------------------------------------------------- + procedure read(variable L: inout line ; A : out RandomSeedType ) is + variable good : boolean ; + begin + read(L, A, good) ; + assert good report "read[line, RandomSeedType] failed" severity error ; + end procedure read ; + +end RandomBasePkg ; \ No newline at end of file diff --git a/test/osvvm_2.1/RandomPkg.vhd b/test/osvvm_2.1/RandomPkg.vhd new file mode 100644 index 0000000..ba35915 --- /dev/null +++ b/test/osvvm_2.1/RandomPkg.vhd @@ -0,0 +1,1078 @@ +-- +-- File Name: RandomPkg.vhd +-- Design Unit Name: RandomPkg +-- Revision: STANDARD VERSION, revision 2.1 +-- +-- 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 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 STANDARD VERSION +-- Major clean-up. +-- Moved RandomParmType and control to here +-- 07/2011 2.1 STANDARD VERSION +-- Bug fix to convenience functions for slv, unsigned, and signed. +-- +-- +-- Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011 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 +-- + +library osvvm; +use osvvm.RandomBasePkg.all ; +use osvvm.SortListPkg_int.all ; + +use std.textio.all ; + +library ieee ; +use ieee.std_logic_1164.all ; +use ieee.numeric_std.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 ; + -- ) ; + + + constant NULL_INTV : integer_vector (0 downto 1) := (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 ; + + -- Favor_small + -- Generate random numbers with a greater number of small + -- values than large values + impure function Favor_small (Min, Max : real) return real ; + impure function Favor_small (Min, Max : integer) return integer ; + impure function Favor_small (Min, Max : integer ; Exclude: integer_vector) return integer ; + + -- Favor_big + -- Generate random numbers with a greater number of large + -- values than small values + impure function Favor_big (Min, Max : real) return real ; + impure function Favor_big (Min, Max : integer) return integer ; + impure function Favor_big (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 ; + + + -- real randomization with a range + impure function RandReal(Min, Max: Real) return real ; + + -- integer randomization with a range + impure function RandInt (Min, Max : integer) return integer ; + 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 ; + + -- integer randomization with a range and exclude vector + impure function RandInt (Min, Max : integer; Exclude: integer_vector ) return integer ; + 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 ; + + -- Randomly select a value within a set of values + impure function RandInt ( A : integer_vector ) return integer ; + 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 ; + + -- Randomly select a value within a set of values with exclude values (so can skip last or last n) + impure function RandInt ( A : integer_vector; Exclude: integer_vector ) return integer ; + impure function RandSlv (A : integer_vector; Exclude: integer_vector; Size : natural) return std_logic_vector ; + impure function RandUnsigned (A : integer_vector; Exclude: integer_vector ; Size : natural) return Unsigned ; + impure function RandSigned (A : integer_vector; Exclude: integer_vector ; Size : natural ) return Signed ; + + -- 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 ; + + -- 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 (Size : natural) return std_logic_vector ; + impure function RandSlv (Max, Size : natural) return std_logic_vector ; + impure function RandUnsigned (Size : natural) return Unsigned ; + impure function RandUnsigned (Max, Size : natural) return Unsigned ; + impure function RandSigned (Size : natural) return Signed ; + impure function RandSigned (Max : integer; Size : natural ) return Signed ; + + end protected RandomPType ; + +end RandomPkg ; + +-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +package body RandomPkg is + + ----------------------------------------------------------------- + -- Local Randomization Support + ----------------------------------------------------------------- + + ----------------------------------------------------------------- + -- Scale -- Scale a value to be within a given range + -- + function Scale (A, Min, Max : real) return real is + variable ValRange : Real ; + begin + assert (Max >= Min) report "%%RandomPkg Error: Max < Min" severity FAILURE ; + ValRange := Max - Min ; + return A * ValRange + Min ; + end function Scale ; + + function Scale (A : real ; Min, Max : integer) return integer is + variable ValRange : real ; + variable rMin, rMax : real ; + begin + assert (Max >= Min) report "%%RandomPkg Error: Max < Min" severity FAILURE ; + rMin := real(Min) - 0.5 ; + rMax := real(Max) + 0.5 ; + ValRange := rMax - rMin ; + return integer(round(A * ValRange + rMin)) ; + end function Scale ; + + -- create more smaller values + function favor_small (A : real) return real is + begin + return 1.0 - sqrt(A) ; + end favor_small ; + + -- create more larger values + -- alias favor_big is sqrt[real return real] ; + function favor_big (A : real) return real is + begin + return sqrt(A) ; + end favor_big ; + + + ----------------------------------------------------------------- + -- 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 good : boolean ; + begin + read(L, A, good) ; + assert good report "read[line, RandomDistType] failed" severity error ; + 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 good : boolean ; + begin + read(L, A, good) ; + assert good report "read[line, RandomParmType] failed" severity error ; + 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 + Uniform(rRandomVal, RandomSeed) ; + return scale(rRandomVal, Min, Max) ; + end function Uniform ; + + impure function Uniform (Min, Max : integer) return integer is + variable rRandomVal : real ; + begin + 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 ; + + + -- + -- Favor_small + -- Generate random numbers with a greater number of small + -- values than large values + -- + impure function Favor_small (Min, Max : real) return real is + variable rRandomVal : real ; + begin + Uniform(rRandomVal, RandomSeed) ; + return scale(favor_small(rRandomVal), Min, Max) ; -- real + end function Favor_small ; + + impure function Favor_small (Min, Max : integer) return integer is + variable rRandomVal : real ; + begin + Uniform(rRandomVal, RandomSeed) ; + return scale(favor_small(rRandomVal), Min, Max) ; -- integer + end function Favor_small ; + + impure function Favor_small (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 := Favor_small(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 Favor_small ; + + + -- + -- Favor_big + -- Generate random numbers with a greater number of large + -- values than small values + -- + impure function Favor_big (Min, Max : real) return real is + variable rRandomVal : real ; + begin + Uniform(rRandomVal, RandomSeed) ; + return scale(favor_big(rRandomVal), Min, Max) ; -- real + end function Favor_big ; + + impure function Favor_big (Min, Max : integer) return integer is + variable rRandomVal : real ; + begin + Uniform(rRandomVal, RandomSeed) ; + return scale(favor_big(rRandomVal), Min, Max) ; -- integer + end function Favor_big ; + + impure function Favor_big (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 := Favor_big(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 Favor_big ; + + + ----------------------------------------------------------------- + -- 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 + report "standard deviation must be >= 0.0" severity 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 + loop + rRandomVal := Normal (Mean, StdDeviation) ; + exit when rRandomVal >= Min and rRandomVal <= Max ; + end loop ; + 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 + loop + iRandomVal := integer(round( Normal(Mean, StdDeviation) )) ; + exit when iRandomVal >= Min and iRandomVal <= Max and + not inside(iRandomVal, Exclude) ; + end loop ; + 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 + report "Poisson: Mean < 0 or too large. Mean = " & real'image(Mean) severity failure ; + return -1.0 ; + 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 + loop + rRandomVal := Poisson (Mean) ; + exit when rRandomVal >= Min and rRandomVal <= Max ; + end loop ; + 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 + loop + iRandomVal := integer(round( Poisson (Mean) )) ; + exit when iRandomVal >= Min and iRandomVal <= Max and + not inside(iRandomVal, Exclude) ; + end loop ; + return iRandomVal ; + end function Poisson ; + + + -- + -- real randomization with a range + -- Distribution determined by RandomParm + -- + impure function RandReal(Min, Max: Real) return real is + begin + assert Max >= Min report "RandReal: Range Error" severity FAILURE ; + case RandomParm.Distribution is + when NONE | UNIFORM => return Uniform(Min, Max) ; + when FAVOR_SMALL => return Favor_small(Min, Max) ; + when FAVOR_BIG => return Favor_big (Min, Max) ; + when NORMAL => return Normal(RandomParm.Mean, RandomParm.StdDeviation, Min, Max) ; + when POISSON => return Poisson(RandomParm.Mean, Min, Max) ; + when others => + report "RandomPkg: distribution not implemented" severity failure ; + return real(integer'low) ; + end case ; + end function RandReal ; + + + -- + -- integer randomization with a range + -- Distribution determined by RandomParm + -- + impure function RandInt (Min, Max : integer) return integer is + begin + assert (Max >= Min) report "RandInt: Range Error" severity FAILURE ; + case RandomParm.Distribution is + when NONE | UNIFORM => return Uniform(Min, Max) ; + when FAVOR_SMALL => return Favor_small(Min, Max) ; + when FAVOR_BIG => return Favor_big (Min, Max) ; + when NORMAL => return Normal(RandomParm.Mean, RandomParm.StdDeviation, Min, Max) ; + when POISSON => return Poisson(RandomParm.Mean, Min, Max) ; + when others => + report "RandomPkg: distribution not implemented" severity failure ; + return integer'low ; + end case ; + end function RandInt ; + + 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 ; + + + -- + -- integer randomization with a range and exclude vector + -- Distribution determined by RandomParm + -- + impure function RandInt (Min, Max : integer; Exclude: integer_vector ) return integer is + variable iRandomVal : integer ; + begin + assert (Max >= Min) report "RandInt: Range Error" severity FAILURE ; + case RandomParm.Distribution is + when NONE | UNIFORM => return Uniform(Min, Max, Exclude) ; + when FAVOR_SMALL => return Favor_small(Min, Max, Exclude) ; + when FAVOR_BIG => return Favor_big (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 => + report "RandomPkg: distribution not implemented" severity failure ; + return integer'low ; + end case ; + end function RandInt ; + + 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 ; + + + -- + -- 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 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 ; + + + -- + -- 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 : integer_vector; Exclude: integer_vector ) return integer is + alias A_norm : integer_vector(1 to A'length) is A ; + variable ExcludeIndexList : SortListPType ; + variable iVal : integer ; + begin + -- convert exclude list into indices of A_norm to exclude + -- necessary to preserve ordering of the distribution (such as NORMAL) + for i in A_norm'range loop + if inside(A_norm(i), Exclude) then + ExcludeIndexList.add(i) ; + end if ; + end loop ; + -- Randomize an index into A_Norm with exclude index list + iVal := RandInt(1, A'length, ExcludeIndexList.to_array (EraseList => TRUE)) ; + -- return the value at the randomized index + return A_norm(iVal) ; + end function RandInt ; + + impure function RandSlv (A : integer_vector; 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 : integer_vector; Exclude: integer_vector; Size : natural) return Unsigned is + begin + return to_unsigned(RandInt(A, Exclude), Size) ; + end function RandUnsigned ; + + impure function RandSigned (A : integer_vector; Exclude: integer_vector; Size : natural ) return Signed is + begin + return to_signed(RandInt(A, Exclude), Size) ; + end function RandSigned ; + + + -- + -- Basic Discrete Distributions + -- Always uses Uniform + -- + impure function DistInt ( Weight : integer_vector ) return integer is + variable DistArray : integer_vector(0 to Weight'length-1) ; + variable sum : integer ; + variable iRandomVal : integer ; + begin + DistArray := Weight ; + for i in 1 to DistArray'right loop + DistArray(i) := DistArray(i) + DistArray(i-1) ; + end loop ; + sum := DistArray(DistArray'right) ; + assert sum >= 1 report "DistInt failed: no elements" severity failure ; + iRandomVal := Uniform(1, sum) ; + for i in DistArray'range loop + if iRandomVal <= DistArray(i) then + return i ; + end if; + end loop ; + return integer'left ; -- can't get here + 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(0 to Weight'length-1) ; + variable ExcludeTemp : integer ; + begin + DistArray := Weight ; + for i in Exclude'range loop + ExcludeTemp := Exclude(i) ; + if ExcludeTemp >= 0 and ExcludeTemp <= Weight'length-1 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 ; + + + -- + -- Convenience Functions. Resolve into calls into the other functions + -- + impure function RandReal return real is + variable RandomValue : real ; + 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) ; + -- assert Max >= 0.0 report "RandReal: Range Error" severity FAILURE ; + -- return RandReal * Max ; + end function RandReal ; + + impure function RandInt (Max : integer) return integer is + begin + return RandInt(0, Max) ; + end function RandInt ; + + impure function RandSlv (Size : natural) return std_logic_vector is + begin + return std_logic_vector(to_unsigned(RandInt(0, 2**Size-1), Size)) ; + end function RandSlv ; + + 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 (Size : natural) return Unsigned is + begin + return to_unsigned(RandInt(0, 2**Size-1), Size) ; + end function RandUnsigned ; + + impure function RandUnsigned (Max, Size : natural) return Unsigned is + begin + return to_unsigned(RandInt(0, Max), Size) ; + end function RandUnsigned ; + + impure function RandSigned (Size : natural) return Signed is + begin + return to_signed(RandInt(-2**(Size-1), 2**(Size-1)-1), Size) ; + end function RandSigned ; + + 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 ; diff --git a/test/osvvm_2.1/SortListPkg_int.vhd b/test/osvvm_2.1/SortListPkg_int.vhd new file mode 100644 index 0000000..80f43b5 --- /dev/null +++ b/test/osvvm_2.1/SortListPkg_int.vhd @@ -0,0 +1,375 @@ +-- +-- File Name: SortListPkg_int.vhd +-- Design Unit Name: SortListPkg_int +-- Revision: STANDARD VERSION, revision 2.1 +-- +-- Maintainer: Jim Lewis email: jim@synthworks.com +-- Contributor(s): +-- Jim Lewis jim@synthworks.com +-- +-- Description: +-- Sorting utility for array of scalars +-- Uses protected type so as to shrink and expand the data structure +-- +-- Developed for: +-- SynthWorks Design Inc. +-- VHDL Training Classes +-- 11898 SW 128th Ave. Tigard, Or 97223 +-- http://www.SynthWorks.com +-- +-- Revision History: +-- Date Version Description +-- 06/2008: 0.1 Initial revision +-- Numerous revisions for 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/16/2010 1.2 Added EraseList parameter to to_array +-- 3/2011 2.0 added inside as non protected type +-- 6/2011 2.1 added sort as non protected type +-- +-- +-- Copyright (c) 2008, 2009, 2011 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 std.textio.all ; + +library ieee ; +use ieee.std_logic_1164.all ; +use ieee.numeric_std.all ; +use ieee.std_logic_textio.all ; + +-- comment out following 2 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; + + +package SortListPkg_int is + -- with VHDL-2008, convert package to generic package + -- convert subtypes ElementType and ArrayofElementType to generics + -- package SortListGenericPkg is + subtype ElementType is integer ; + subtype ArrayofElementType is integer_vector ; + + function inside (constant E : ElementType; constant A : in ArrayofElementType) return boolean ; + impure function sort (constant A : in ArrayofElementType) return ArrayofElementType ; + + type SortListPType is protected + procedure add ( constant A : in ElementType ) ; + procedure add ( constant A : in ArrayofElementType ) ; + procedure add ( constant A : in ArrayofElementType ; Min, Max : integer ) ; + procedure add ( variable A : inout SortListPType ) ; + -- Count items in list + impure function count return integer ; + impure function find_index ( constant A : ElementType) return integer ; + impure function inside (constant A : ElementType) return boolean ; + procedure insert ( constant A : in ElementType; constant index : in integer := 1 ) ; + impure function get ( constant index : in integer := 1 ) return ElementType ; + procedure erase ; + impure function Empty return boolean ; + procedure print ; + + procedure remove ( constant A : in ElementType ) ; + procedure remove ( constant A : in ArrayofElementType ) ; + procedure remove ( variable A : inout SortListPType ) ; + + impure function to_array (constant EraseList : boolean := FALSE) return ArrayofElementType ; + end protected SortListPType ; + +end SortListPkg_int ; +-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +package body SortListPkg_int is + + function inside (constant E : ElementType; constant A : in ArrayofElementType) return boolean is + begin + for i in A'range loop + if E = A(i) then + return TRUE ; + end if ; + end loop ; + return FALSE ; + end function inside ; + + type SortListPType is protected body + type ListType ; + type ListPointerType is access ListType ; + type ListType is record + A : ElementType ; + -- item_num : integer ; + NextPtr : ListPointerType ; + -- PrevPtr : ListPointerType ; + end record ; + variable HeadPointer : ListPointerType := NULL ; + -- variable TailPointer : ListPointerType := NULL ; + + procedure add ( constant A : in ElementType ) is + variable CurPtr, tempPtr : ListPointerType ; + begin + if HeadPointer = NULL then + HeadPointer := new ListType'(A, NULL) ; + + elsif A = HeadPointer.A then -- ignore duplicates + return ; + + elsif A < HeadPointer.A then + tempPtr := HeadPointer ; + HeadPointer := new ListType'(A, tempPtr) ; + + else + CurPtr := HeadPointer ; + loop + exit when CurPtr.NextPtr = NULL ; + exit when A < CurPtr.NextPtr.A ; + if A = CurPtr.NextPtr.A then return ; end if; -- exit + CurPtr := CurPtr.NextPtr ; + end loop ; + tempPtr := CurPtr.NextPtr ; + CurPtr.NextPtr := new ListType'(A, tempPtr) ; + end if ; + end procedure add ; + + procedure add ( constant A : in ArrayofElementType ) is + begin + for i in A'range loop + add(A(i)) ; + end loop ; + end procedure add ; + + procedure add ( constant A : in ArrayofElementType ; Min, Max : integer ) is + begin + for i in A'range loop + if A(i) >= Min and A(i) <= Max then + add(A(i)) ; + end if ; + end loop ; + end procedure add ; + + procedure add ( variable A : inout SortListPType ) is + begin + for i in 1 to A.Count loop + add(A.Get(i)) ; + end loop ; + end procedure add ; + + -- Count items in list + impure function count return integer is + variable result : positive := 1 ; + variable CurPtr : ListPointerType ; + begin + if HeadPointer = NULL then + return 0 ; + else + CurPtr := HeadPointer ; + loop + exit when CurPtr.NextPtr = NULL ; + result := result + 1 ; + CurPtr := CurPtr.NextPtr ; + end loop ; + return result ; + end if ; + end function count ; + + impure function find_index (constant A : ElementType) return integer is + variable result : positive := 2 ; + variable CurPtr : ListPointerType ; + begin + if HeadPointer = NULL then + return 0 ; + elsif A <= HeadPointer.A then + return 1 ; + else + CurPtr := HeadPointer ; + loop + exit when CurPtr.NextPtr = NULL ; + exit when A <= CurPtr.NextPtr.A ; + result := result + 1 ; + CurPtr := CurPtr.NextPtr ; + end loop ; + return result ; + end if ; + end function find_index ; + + impure function inside (constant A : ElementType) return boolean is + variable CurPtr : ListPointerType ; + begin + if HeadPointer = NULL then + return FALSE ; + end if ; + if A = HeadPointer.A then + return TRUE ; + else + CurPtr := HeadPointer ; + loop + exit when CurPtr.NextPtr = NULL ; + exit when A < CurPtr.NextPtr.A ; + if A = CurPtr.NextPtr.A then + return TRUE ; -- exit + end if; + CurPtr := CurPtr.NextPtr ; + end loop ; + end if ; + return FALSE ; + end function inside ; + + + procedure insert( constant A : in ElementType; constant index : in integer := 1 ) is + variable CurPtr, tempPtr : ListPointerType ; + begin + if index <= 1 then + tempPtr := HeadPointer ; + HeadPointer := new ListType'(A, tempPtr) ; + else + CurPtr := HeadPointer ; + for i in 3 to index loop + exit when CurPtr.NextPtr = NULL ; -- end of list + CurPtr := CurPtr.NextPtr ; + end loop ; + tempPtr := CurPtr.NextPtr ; + CurPtr.NextPtr := new ListType'(A, tempPtr) ; + end if; + end procedure insert ; + + impure function get ( constant index : in integer := 1 ) return ElementType is + variable CurPtr : ListPointerType ; + begin + if index > Count then + report "%%FAILURE: SortListPType index out of range" severity failure ; + return ElementType'left ; + elsif HeadPointer = NULL then + return ElementType'left ; + elsif index <= 1 then + return HeadPointer.A ; + else + CurPtr := HeadPointer ; + for i in 2 to index loop + CurPtr := CurPtr.NextPtr ; + end loop ; + return CurPtr.A ; + end if; + end function get ; + + + procedure erase (variable CurPtr : inout ListPointerType ) is + begin + if CurPtr.NextPtr /= NULL then + erase (CurPtr.NextPtr) ; + end if ; + deallocate (CurPtr) ; + end procedure erase ; + + procedure erase is + begin + if HeadPointer /= NULL then + erase(HeadPointer) ; + -- deallocate (HeadPointer) ; + HeadPointer := NULL ; + end if; + end procedure erase ; + + impure function Empty return boolean is + begin + return HeadPointer = NULL ; + end Empty ; + + procedure print is + variable buf : line ; + variable CurPtr : ListPointerType ; + begin + if HeadPointer = NULL then + write (buf, string'("( )")) ; + else + CurPtr := HeadPointer ; + write (buf, string'("(")) ; + loop + write (buf, CurPtr.A) ; + exit when CurPtr.NextPtr = NULL ; + write (buf, string'(", ")) ; + CurPtr := CurPtr.NextPtr ; + end loop ; + write (buf, string'(")")) ; + end if ; + writeline(OUTPUT, buf) ; + end procedure print ; + + procedure remove ( constant A : in ElementType ) is + variable CurPtr, tempPtr : ListPointerType ; + begin + if HeadPointer = NULL then + return ; + elsif A = HeadPointer.A then + tempPtr := HeadPointer ; + HeadPointer := HeadPointer.NextPtr ; + deallocate (tempPtr) ; + else + CurPtr := HeadPointer ; + loop + exit when CurPtr.NextPtr = NULL ; + if A = CurPtr.NextPtr.A then + tempPtr := CurPtr.NextPtr ; + CurPtr.NextPtr := CurPtr.NextPtr.NextPtr ; + deallocate (tempPtr) ; + exit ; + end if ; + exit when A < CurPtr.NextPtr.A ; + CurPtr := CurPtr.NextPtr ; + end loop ; + end if ; + end procedure remove ; + + procedure remove ( constant A : in ArrayofElementType ) is + begin + for i in A'range loop + remove(A(i)) ; + end loop ; + end procedure remove ; + + procedure remove ( variable A : inout SortListPType ) is + variable item : natural ; + begin + for i in 1 to A.Count loop + remove(A.Get(i)) ; + end loop ; + end procedure remove ; + + impure function to_array (constant EraseList : boolean := FALSE) return ArrayofElementType is + variable result : ArrayofElementType(1 to Count) ; + begin + for i in 1 to Count loop + result(i) := Get(i) ; + end loop ; + if EraseList then + erase ; + end if ; + return result ; + end function to_array ; + + end protected body SortListPType ; + + + impure function sort (constant A : in ArrayofElementType) return ArrayofElementType is + variable Result : SortListPType ; + begin + Result.Add(A) ; + return Result.to_array(EraseList => TRUE) ; + end function sort ; + +end SortListPkg_int ;