URL
https://opencores.org/ocsvn/rng_lib/rng_lib/trunk
Subversion Repositories rng_lib
Compare Revisions
- This comparison shows the changes necessary to convert path
/rng_lib/trunk/bench/vhdl
- from Rev 7 to Rev 8
- ↔ Reverse comparison
Rev 7 → Rev 8
/math_lib.vhd
0,0 → 1,232
---------------------------------------------------------------------- |
---- ---- |
---- Math function library. ---- |
---- ---- |
---- This file is part of the Random Number Generator project ---- |
---- http://www.opencores.org/cores/rng_lib/ ---- |
---- ---- |
---- Description ---- |
---- These math function are copied from the draft version of the ---- |
---- IEEE MATH_REAL package. ---- |
---- ---- |
---- To Do: ---- |
---- - ---- |
---- ---- |
---- Author(s): ---- |
---- - Geir Drange, gedra@opencores.org ---- |
---- ---- |
---------------------------------------------------------------------- |
---- ---- |
---- Copyright (C) 2004 Authors and OPENCORES.ORG ---- |
---- ---- |
---- This source file may be used and distributed without ---- |
---- restriction provided that this copyright statement is not ---- |
---- removed from the file and that any derivative work contains ---- |
---- the original copyright notice and the associated disclaimer. ---- |
---- ---- |
---- This source file is free software; you can redistribute it ---- |
---- and/or modify it under the terms of the GNU General ---- |
---- Public License as published by the Free Software 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 GNU General Public License for more details.---- |
---- ---- |
---- You should have received a copy of the GNU General ---- |
---- Public License along with this source; if not, download it ---- |
---- from http://www.gnu.org/licenses/gpl.txt ---- |
---- ---- |
---------------------------------------------------------------------- |
-- |
-- CVS Revision History |
-- |
-- $Log: not supported by cvs2svn $ |
-- Revision 1.1 2004/09/28 15:02:56 gedra |
-- Math functions library. |
-- |
-- |
-- |
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.numeric_std.all; |
|
package math_lib is |
|
function sqrt(x : real) return real; -- returns square root |
function ln(x : real) return real; -- natural logarithm |
function log(x : real) return real; -- base 10 logarithm |
function exp(x : real) return real; -- exponential function |
|
-- Some mathematical constants |
constant MATH_E : real := 2.71828_18284_59045_23536; |
|
end math_lib; |
|
package body math_lib is |
|
-- Square root calculation |
function sqrt (x : real) return real is |
-- returns square root of X; X >= 0 |
-- |
-- Computes square root using the Newton-Raphson approximation: |
-- F(n+1) = 0.5*[F(n) + x/F(n)]; |
-- |
|
constant inival : real := 1.5; |
constant eps : real := 0.000001; |
constant relative_err : real := eps*X; |
|
variable oldval : real; |
variable newval : real; |
|
begin |
-- check validity of argument |
if x < 0.0 then |
report "x < 0 in sqrt(x)" |
severity failure; |
return (0.0); |
end if; |
|
-- get the square root for special cases |
if x = 0.0 then |
return 0.0; |
else |
if x = 1.0 then |
return 1.0; -- return exact value |
end if; |
end if; |
|
-- get the square root for general cases |
oldval := inival; |
newval := (X/oldval + oldval)/2.0; |
|
while (abs(newval -oldval) > relative_err) loop |
oldval := newval; |
newval := (X/oldval + oldval)/2.0; |
end loop; |
|
return newval; |
end sqrt; |
|
-- Natural logarithm calculation |
function ln (x : real) return real is |
-- returns natural logarithm of X; X > 0 |
-- |
-- This function computes the exponential using the following series: |
-- log(x) = 2[ (x-1)/(x+1) + (((x-1)/(x+1))**3)/3.0 + ...] ; x > 0 |
-- |
|
constant eps : real := 0.000001; -- precision criteria |
|
variable xlocal : real; -- following variables are |
variable oldval : real; -- used to evaluate the series |
variable xlocalsqr : real; |
variable factor : real; |
variable count : integer; |
variable newval : real; |
|
begin |
-- check validity of argument |
if x <= 0.0 then |
report "x <= 0 in ln(x)" |
severity failure; |
return(real'low); |
end if; |
|
-- compute value for special cases |
if x = 1.0 then |
return 0.0; |
else |
if x = MATH_E then |
return 1.0; |
end if; |
end if; |
|
-- compute value for general cases |
xlocal := (x - 1.0)/(x + 1.0); |
oldval := xlocal; |
xlocalsqr := xlocal*xlocal; |
factor := xlocal*xlocalsqr; |
count := 3; |
newval := oldval + (factor/real(count)); |
|
while (abs(newval - oldval) > eps) loop |
oldval := newval; |
count := count +2; |
factor := factor * xlocalsqr; |
newval := oldval + factor/real(count); |
end loop; |
|
newval := newval * 2.0; |
return newval; |
end ln; |
|
-- Base 10 logarithm calculation |
function log (x : real) return real is |
-- returns logarithm base 10 of x; x > 0 |
begin |
-- check validity of argument |
if x <= 0.0 then |
assert false report "x <= 0.0 in log(x)" |
severity error; |
return(real'low); |
end if; |
|
-- compute the value |
return (ln(x)/2.30258509299); |
end log; |
|
-- Calculate e**x |
function exp (x : real) return real is |
-- returns e**X; where e = MATH_E |
-- |
-- This function computes the exponential using the following series: |
-- exp(x) = 1 + x + x**2/2! + x**3/3! + ... ; x > 0 |
-- |
constant eps : real := 0.000001; -- precision criteria |
|
variable reciprocal : boolean := x < 0.0; -- check sign of argument |
variable xlocal : real := abs(x); -- use positive value |
variable oldval : real; -- following variables are |
variable num : real; -- used for series evaluation |
variable count : integer; |
variable denom : real; |
variable newval : real; |
|
begin |
-- compute value for special cases |
if x = 0.0 then |
return 1.0; |
else |
if x = 1.0 then |
return MATH_E; |
end if; |
end if; |
|
-- compute value for general cases |
oldval := 1.0; |
num := xlocal; |
count := 1; |
denom := 1.0; |
newval := oldval + num/denom; |
|
while (abs(newval - oldval) > eps) loop |
oldval := newval; |
num := num*xlocal; |
count := count +1; |
denom := denom*(real(count)); |
newval := oldval + num/denom; |
end loop; |
|
if reciprocal then |
newval := 1.0/newval; |
end if; |
|
return newval; |
end exp; |
|
end math_lib; |
/tb_rng.vhd
0,0 → 1,158
---------------------------------------------------------------------- |
---- ---- |
---- Testbench for Rand number generator library. ---- |
---- ---- |
---- This file is part of the Random Number Generator project ---- |
---- http://www.opencores.org/cores/rng_lib/ ---- |
---- ---- |
---- Description ---- |
---- The test bench will generate 10000 random numbers from each ---- |
---- distribution and do a simple plot of the distributions. ---- |
---- ---- |
---- To Do: ---- |
---- - ---- |
---- ---- |
---- Author(s): ---- |
---- - Geir Drange, gedra@opencores.org ---- |
---- ---- |
---------------------------------------------------------------------- |
---- ---- |
---- Copyright (C) 2004 Authors and OPENCORES.ORG ---- |
---- ---- |
---- This source file may be used and distributed without ---- |
---- restriction provided that this copyright statement is not ---- |
---- removed from the file and that any derivative work contains ---- |
---- the original copyright notice and the associated disclaimer. ---- |
---- ---- |
---- This source file is free software; you can redistribute it ---- |
---- and/or modify it under the terms of the GNU General ---- |
---- Public License as published by the Free Software 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 GNU General Public License for more details.---- |
---- ---- |
---- You should have received a copy of the GNU General ---- |
---- Public License along with this source; if not, download it ---- |
---- from http://www.gnu.org/licenses/gpl.txt ---- |
---- ---- |
---------------------------------------------------------------------- |
-- |
-- CVS Revision History |
-- |
-- $Log: not supported by cvs2svn $ |
-- Revision 1.1 2004/09/28 15:12:52 gedra |
-- Test bench for random numbers. |
-- |
-- |
-- |
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.numeric_std.all; |
use std.textio.all; |
use work.rng_lib.all; |
|
entity tb_rng is |
|
end tb_rng; |
|
architecture behav of tb_rng is |
|
constant BIN_COUNT : integer := 15; |
constant PLOT_HEIGHT : real := 40.0; |
constant RAND_COUNT : integer := 10000; |
|
type rand_array is array (0 to RAND_COUNT - 1) of real; -- array used for plot |
type bin_array is array (0 to BIN_COUNT - 1) of integer; |
|
-- Plot a distribution of the numbers that are between lo,hi values |
impure function plot_dist (numbs : rand_array; lo, hi : real) return integer is |
variable bins : bin_array; |
variable bin_size, height : real; |
variable idx, max : integer; |
variable bar : line; |
begin |
-- reset bins |
for i in 0 to BIN_COUNT - 1 loop |
bins(i) := 0; |
end loop; |
-- sort numbers into bins |
bin_size := (hi - lo) / real(BIN_COUNT); |
for i in 0 to RAND_COUNT - 1 loop |
if numbs(i) > lo and numbs(i) < hi then |
idx := integer(((numbs(i) - lo) / bin_size) - 0.5); |
if idx > BIN_COUNT - 1 then |
idx := BIN_COUNT - 1; |
elsif idx < 0 then |
idx := 0; |
end if; |
bins(idx) := bins(idx) + 1; |
end if; |
end loop; |
-- find largest bin |
max := 0; |
for i in 0 to BIN_COUNT - 1 loop |
if bins(i) > max then |
max := bins(i); |
end if; |
end loop; |
-- plot bins |
for i in 0 to BIN_COUNT - 1 loop |
height := PLOT_HEIGHT * real(bins(i)) / real(max); |
for j in 1 to integer(height) loop |
write(bar, string'("*")); |
end loop; |
writeline(OUTPUT, bar); |
end loop; |
return 0; |
end plot_dist; |
|
begin |
|
p1 : process |
variable r_uni, r_gauss, r_exp : rand_var; |
variable r_poisson : rand_var; |
variable txt : line; |
variable a : integer; |
variable numbs : rand_array; |
begin |
-- Test the uniform distribution |
r_uni := init_uniform(0, 0, 0, 0.0, 10.0); -- range 0 to 10 |
t1 : for i in 0 to RAND_COUNT - 1 loop |
r_uni := rand(r_uni); |
numbs(i) := r_uni.rnd; |
end loop t1; |
write(txt, string'("Uniform distribution:")); |
writeline(OUTPUT, txt); |
a := plot_dist (numbs, 0.0, 10.0); |
-- Test the gaussian distribution |
r_gauss := init_gaussian(0, 0, 0, 0.0, 10.0); -- mean=0, stdev=10 |
t2 : for i in 0 to RAND_COUNT - 1 loop |
r_gauss := rand(r_gauss); |
numbs(i) := r_gauss.rnd; |
end loop t2; |
write(txt, string'("Gaussian distribution:")); |
writeline(OUTPUT, txt); |
a := plot_dist (numbs, -20.0, 20.0); |
-- Test the exponential distribution |
r_exp := init_exponential(0, 0, 0, 10.0); -- mean=10 |
t3 : for i in 0 to RAND_COUNT - 1 loop |
r_exp := rand(r_exp); |
numbs(i) := r_exp.rnd; |
end loop t3; |
write(txt, string'("Exponential distribution:")); |
writeline(OUTPUT, txt); |
a := plot_dist (numbs, 0.0, 20.0); |
|
wait for 1 ns; |
|
report "End of simulation! (ignore this failure)" |
severity failure; |
wait; |
end process p1; |
|
end behav; |
/rng_lib.vhd
0,0 → 1,255
---------------------------------------------------------------------- |
---- ---- |
---- Rand number generator library. ---- |
---- ---- |
---- This file is part of the Random Number Generator project ---- |
---- http://www.opencores.org/cores/rng_lib/ ---- |
---- ---- |
---- Description ---- |
---- This library has function for generation random numbers with ---- |
---- the following distributions: ---- |
---- - Uniform (continous) ---- |
---- - Exponential (continous) ---- |
---- - Gaussian (continous) ---- |
---- ---- |
---- Random numbers are produced with a combination of 3 ---- |
---- Tausworthe generators which gives very good statistical ---- |
---- properties. ---- |
---- ---- |
---- NOTE! These functions will NOT synthesize. They are for test ---- |
---- bench use only! ---- |
---- ---- |
---- To Do: ---- |
---- - ---- |
---- ---- |
---- Author(s): ---- |
---- - Geir Drange, gedra@opencores.org ---- |
---- ---- |
---------------------------------------------------------------------- |
---- ---- |
---- Copyright (C) 2004 Authors and OPENCORES.ORG ---- |
---- ---- |
---- This source file may be used and distributed without ---- |
---- restriction provided that this copyright statement is not ---- |
---- removed from the file and that any derivative work contains ---- |
---- the original copyright notice and the associated disclaimer. ---- |
---- ---- |
---- This source file is free software; you can redistribute it ---- |
---- and/or modify it under the terms of the GNU General ---- |
---- Public License as published by the Free Software 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 GNU General Public License for more details.---- |
---- ---- |
---- You should have received a copy of the GNU General ---- |
---- Public License along with this source; if not, download it ---- |
---- from http://www.gnu.org/licenses/gpl.txt ---- |
---- ---- |
---------------------------------------------------------------------- |
-- |
-- CVS Revision History |
-- |
-- $Log: not supported by cvs2svn $ |
-- Revision 1.1 2004/09/28 15:12:28 gedra |
-- Random number library functions. |
-- |
-- |
-- |
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.numeric_std.all; |
use std.textio.all; |
use work.math_lib.all; |
|
package rng_lib is |
|
type distribution is (UNIFORM, GAUSSIAN, EXPONENTIAL); |
type rand_var is record -- random variable record |
rnd : real; -- random number |
rnd_v : unsigned(31 downto 0); -- random number vector |
dist : distribution; -- distribution type |
y, z : real; -- distribution parameters |
s1, s2, s3 : unsigned(31 downto 0); -- seeds |
mask1, mask2, mask3 : unsigned(31 downto 0); |
shft1, shft2, shft3 : natural; |
end record; |
|
function rand (rnd : rand_var) return rand_var; |
function init_uniform(constant a, b, c : natural; |
constant lo, hi : real) return rand_var; |
function init_gaussian(constant a, b, c : natural; |
constant mean, stdev : real) return rand_var; |
function init_exponential(constant a, b, c : natural; |
constant mean : real) return rand_var; |
|
constant q1 : natural := 13; |
constant q2 : natural := 2; |
constant q3 : natural := 3; |
constant p1 : natural := 12; |
constant p2 : natural := 4; |
constant p3 : natural := 17; |
|
end rng_lib; |
|
package body rng_lib is |
|
-- Function to convert 32bit unsigned vector to real |
-- Integers only go to 2**31 (VHDL'87), so do it clever |
function unsigned_2_real (constant a : unsigned(31 downto 0)) return real is |
variable r : real; |
begin |
r := 2.0*real(to_integer(a(31 downto 1))); |
if a(0) = '1' then |
r := r + 1.0; |
end if; |
return(r); |
end unsigned_2_real; |
|
-- Generate random number using a combination of 3 tausworthe generators |
-- Source: Pierre L'Ecuyer, "Maximally Equidistributed Combined Tausworthe |
-- Generators". Mathematics of Computation, vol.65, no.213(1996), pp203--213. |
function rng (rnd : rand_var) return rand_var is |
variable new_rnd : rand_var; |
variable b : unsigned(31 downto 0); |
begin |
new_rnd := rnd; |
b := ((new_rnd.s1 sll q1) xor new_rnd.s1) srl new_rnd.shft1; |
new_rnd.s1 := ((new_rnd.s1 and new_rnd.mask1) sll p1) xor b; |
b := ((new_rnd.s2 sll q2) xor new_rnd.s2) srl new_rnd.shft2; |
new_rnd.s2 := ((new_rnd.s2 and new_rnd.mask2) sll p2) xor b; |
b := ((new_rnd.s3 sll q3) xor new_rnd.s3) srl new_rnd.shft3; |
new_rnd.s3 := ((new_rnd.s3 and new_rnd.mask3) sll p3) xor b; |
new_rnd.rnd_v := new_rnd.s1 xor new_rnd.s2 xor new_rnd.s3; |
-- normalize to range [0,1) |
new_rnd.rnd := unsigned_2_real(new_rnd.rnd_v) / 65536.0; |
new_rnd.rnd := new_rnd.rnd / 65536.0; |
return (new_rnd); |
end rng; |
|
-- rand function generates a random variable with different distributions |
function rand (rnd : rand_var) return rand_var is |
variable rnd_out : rand_var; |
variable x, y, z : real; |
variable t : real := 0.0; |
begin |
case rnd.dist is |
-- Uniform distribution |
when UNIFORM => |
rnd_out := rng(rnd); |
rnd_out.rnd := rnd.y + (rnd_out.rnd * (rnd.z - rnd.y)); |
-- Gaussian distribution |
when GAUSSIAN => -- Box-Mueller method |
z := 2.0; |
rnd_out := rnd; |
while z > 1.0 or z = 0.0 loop |
-- choose x,y in uniform square (-1,-1) to (+1,+1) |
rnd_out := rng(rnd_out); |
x := -1.0 + 2.0 * rnd_out.rnd; |
rnd_out := rng(rnd_out); |
y := -1.0 + 2.0 * rnd_out.rnd; |
z := (x * x) + (y * y); |
end loop; |
-- Box-Mueller transform |
rnd_out.rnd := rnd_out.y + rnd_out.z * y * sqrt(-2.0 * log(z)/z); |
-- Exponential distribution |
when EXPONENTIAL => |
rnd_out := rng(rnd); |
rnd_out.rnd := -rnd_out.y * log(1.0 - rnd_out.rnd); |
when others => |
report "rand() function encountered an error!" |
severity failure; |
end case; |
return (rnd_out); |
end rand; |
|
-- Initialize seeds, used by all init_ functions |
function gen_seed (constant a, b, c : natural) return rand_var is |
variable seeded : rand_var; |
variable x : unsigned(31 downto 0) := "11111111111111111111111111111111"; |
constant k1 : natural := 31; |
constant k2 : natural := 29; |
constant k3 : natural := 28; |
begin |
seeded.shft1 := k1-p1; |
seeded.shft2 := k2-p2; |
seeded.shft3 := k3-p3; |
seeded.mask1 := x sll (32-k1); |
seeded.mask2 := x sll (32-k2); |
seeded.mask3 := x sll (32-k3); |
seeded.s1 := to_unsigned(390451501, 32); |
seeded.s2 := to_unsigned(613566701, 32); |
seeded.s3 := to_unsigned(858993401, 32); |
if to_unsigned(a, 32) > (to_unsigned(1, 32) sll (32-k1)) then |
seeded.s1 := to_unsigned(a, 32); |
end if; |
if to_unsigned(b, 32) > (to_unsigned(1, 32) sll (32-k2)) then |
seeded.s2 := to_unsigned(b, 32); |
end if; |
if to_unsigned(c, 32) > (to_unsigned(1, 32) sll (32-k3)) then |
seeded.s3 := to_unsigned(c, 32); |
end if; |
return(seeded); |
end gen_seed; |
|
-- Uniform distribution random variable initialization |
-- a,b,c are seeds |
-- lo,hi is the range for the uniform distribution |
function init_uniform(constant a, b, c : natural; |
constant lo, hi : real) return rand_var is |
variable rnd, rout : rand_var; |
begin |
if lo >= hi then |
report "Uniform parameter error: 'hi' must be > 'lo'!" |
severity failure; |
end if; |
rnd := gen_seed(a, b, c); |
rnd.dist := UNIFORM; |
rnd.y := lo; |
rnd.z := hi; |
rout := rand(rnd); |
return(rout); |
end init_uniform; |
|
-- Gaussian distribution random variable initialization |
-- a,b,c are seeds |
-- mean,stdev is mean and standard deviation |
function init_gaussian(constant a, b, c : natural; |
constant mean, stdev : real) return rand_var is |
variable rnd, rout : rand_var; |
begin |
if stdev = 0.0 then |
report "Gaussian parameter error: 'stdev' must be non-zero!" |
severity failure; |
end if; |
rnd := gen_seed(a, b, c); |
rnd.dist := GAUSSIAN; |
rnd.y := mean; |
rnd.z := stdev; |
rout := rand(rnd); |
return(rout); |
end init_gaussian; |
|
-- Exponential distribution random variable initialization |
-- a,b,c are seeds |
-- mean: mean value |
function init_exponential(constant a, b, c : natural; |
constant mean : real) return rand_var is |
variable rnd, rout : rand_var; |
begin |
if mean <= 0.0 then |
report "Exponential parameter error: 'mean' must be > 0!" |
severity failure; |
end if; |
rnd := gen_seed(a, b, c); |
rnd.dist := EXPONENTIAL; |
rnd.y := mean; |
rout := rand(rnd); |
return(rout); |
end init_exponential; |
|
end rng_lib; |