Compare commits

...

10 Commits

12 changed files with 744 additions and 56 deletions

View File

@ -16,21 +16,55 @@ These PRNGs are a good alternative to linear feedback shift registers (LFSR).
Although LFSRs are commonly used, their output exhibits strong correlations.
Furthermore, correctly generating multi-bit random words with LFSRs is tricky.
NOTE: None of the RNGs in this package are cryptographic random number
generators. These generators are not suitable for cryptography.
NOTE: This library is not designed for cryptographic applications
(such as generating passwords, encryption keys).
Most of the RNGs in this library are cryptographically weak.
Xoshiro128++ RNG
----------------
Xoshiro128++ is a random number generator developed in 2019 by
David Blackman and Sebastiano Vigna. The Xoshiro construction is
based on the Xorshift concept invented by George Marsaglia.
See also http://prng.di.unimi.it/
This RNG produces a sequence of 32-bit words. It passes all known
statistical tests and has a relatively long period (2**128 - 1).
The VHDL implementation produces 32 new random bits on every (enabled)
clock cycle. It is quite efficient in terms of FPGA resources, but it
requires two cascaded 32-bit adders which limit its speed. An optional
pipeline stage can be inserted between the adders to improve the timing
performance of the circuit.
Output word length: 32 bits
Seed length: 128 bits
Period: 2**128 - 1
FPGA resources: general logic and two 32-bit adders
Synthesis results: 201 LUTs, 194 registers on Spartan-6
149 LUTs, 194 registers on Spartan-7
Timing results: 400 MHz on Spartan-6 LX45-3
350 MHz on Spartan-7 S25-1
Xoroshiro128+ RNG
------------------
-----------------
Xoroshiro128+ is an RNG algorithm developed in 2016 by David Blackman
and Sebastiano Vigna. It is a further development of the Xorshift algorithm
invented by George Marsaglia
and Sebastiano Vigna. The VHDL code matches an updated version of
the algorithm called "xoroshiro128+ 1.0", released in 2018.
The Xoroshiro algorithm is based on the Xorshift concept invented
by George Marsaglia.
See also http://xoroshiro.di.unimi.it/
See also http://prng.di.unimi.it/
This RNG passes many statistical tests. Its period, 2**128 - 1, is long
compared to a typical LFSR, but much shorter than the Mersenne Twister.
This RNG passes many statistical tests, but the least significant
output bits are known to be not fully random and fail certain tests.
The generator has a long period (2**128 - 1) compared to a typical LFSR,
but much shorter than the Mersenne Twister.
The output is 1-dimensionally equidistributed.
The VHDL implementation produces 64 new random bits on every (enabled)
@ -42,7 +76,7 @@ Seed length: 128 bits
Period: 2**128 - 1
FPGA resources: general logic and 64-bit adder
Sythesis results: 194 LUTs, 192 registers on Spartan-6
Synthesis results: 198 LUTs, 193 registers on Spartan-6
Timing results: 333 MHz on Spartan-6 LX45-3
@ -79,31 +113,72 @@ Seed length: 32 bits
Period: 2**19937 - 1
FPGA resources: RAM block, 32 bits x 1024 elements
Sythesis results: 279 LUTs, 297 registers, 2x RAMB16 on Spartan-6
Synthesis results: 279 LUTs, 297 registers, 2x RAMB16 on Spartan-6
Timing results: 300 MHz on Spartan-6 LX45-3
Trivium RNG
-----------
Trivium is a stream cipher published in 2005 by Christophe De Canniere
and Bart Preneel as part of the eSTREAM project.
See also C. De Canniere, B. Preneel, "Trivium Specifications",
http://www.ecrypt.eu.org/stream/p3ciphers/trivium/trivium_p3.pdf
See also the eSTREAM portfolio page for Trivium:
http://www.ecrypt.eu.org/stream/e2-trivium.html
This library uses the key stream of the Trivium cipher as a sequence
of random bits. The VHDL implementation produces up to 64 new random bits
on every (enabled) clock cycle. The number of bits per clock cycle is
configurade as a synthesis parameter.
This RNG passes all known statistical tests. However, little is known
about its period. The period depends on the seed value, and is believed
to be long (at least 2**80) for the vast majority of seed choices.
After reset and after each reseeding, the RNG must process 1152 bits
to initialize its state. This takes up to 1152 clock cycles, depending
on the configured number of bits per cycle. The RNG can not provide random
data during this time.
Output word length: configurable from 1 to 64 bits (must be power-of-2)
Seed length: 80 bits key + 80 bits IV
Period: unknown, depends on seed
FPGA resources: only general logic (AND, XOR ports, registers)
Synthesis results: 202 LUTs, 332 registers on Spartan-6 (32 bits output)
145 LUTs, 332 registers on Spartan-7 (32 bits output)
Timing results: 380 MHz on Spartan-6 LX45-3 (32 bits output)
440 MHz on Spartan-7 S25-1 (32 bits output)
Code organization
-----------------
rtl/ Synthesizable VHDL code
rtl/rng_xoroshiro128plus.vhdl Implementation of Xoroshiro128+ RNG
rtl/rng_mt19937.vhdl Implementation of Mersenne Twister RNG
rtl/ Synthesizable VHDL code
rtl/rng_xoshiro128plusplus.vhdl Implementation of Xoshiro128++ RNG
rtl/rng_xoroshiro128plus.vhdl Implementation of Xoroshiro128+ RNG
rtl/rng_mt19937.vhdl Implementation of Mersenne Twister RNG
rtl/rng_trivium.vhdl Implementation of Trivium RNG
sim/ Test benches
sim/Makefile Makefile for building test benches with GHDL
sim/tb_xoroshiro128plus.vhdl Test bench for Xoroshiro128+ RNG
sim/tb_mt19937.vhdl Test bench for Mersenne Twister RNG
sim/ Test benches
sim/Makefile Makefile for building test benches with GHDL
sim/tb_xoshiro128plusplus.vhdl Test bench for Xoshiro128++ RNG
sim/tb_xoroshiro128plus.vhdl Test bench for Xoroshiro128+ RNG
sim/tb_mt19937.vhdl Test bench for Mersenne Twister RNG
sim/tb_trivium.vhdl Test bench for Trivium RNG
refimpl/ Reference software implementations of RNGs
refimpl/ Reference software implementations of RNGs
synth/ Top-level wrappers for synthesis testruns
synth/ Top-level wrappers for synthesis testruns
License
-------
Copyright (C) 2016 Joris van Rantwijk
Copyright (C) 2016-2020 Joris van Rantwijk
This VHDL library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License

View File

@ -4,19 +4,28 @@
# This makefile works with GCC under Linux.
#
.PHONY: all
all: ref_xoroshiro ref_mt19937 ref_trivium
CC = gcc
CXX = g++
CFLAGS = -std=c11 -Wall -O2
CXXFLAGS = -std=c++11 -Wall -O2
ref_xoroshiro: ref_xoroshiro.c
$(CC) -std=c11 -Wall -O2 -o $@ $<
.PHONY: all
all: ref_xoshiro128plusplus \
ref_xoroshiro128plus \
ref_mt19937 \
ref_trivium
ref_xoshiro128plusplus: ref_xoshiro128plusplus.c
ref_xoroshiro128plus: ref_xoroshiro128plus.c
ref_mt19937: ref_mt19937.cpp
$(CXX) -std=c++11 -Wall -O2 -o $@ $<
ref_trivium: ref_trivium.cpp
$(CXX) -std=c++11 -Wall -O2 -o $@ $<
.PHONY: clean
clean:
$(RM) ref_xoroshiro ref_mt19937 ref_trivium
$(RM) ref_xoshiro128plusplus
$(RM) ref_xoroshiro128plus
$(RM) ref_mt19937
$(RM) ref_trivium

View File

@ -13,14 +13,13 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
/* ========== BEGIN of reference implementation of xoroshiro128+ ==========
* Source: http://xoroshiro.di.unimi.it/
* Source: http://prng.di.unimi.it/
*/
/* Written in 2016 by David Blackman and Sebastiano Vigna (vigna@acm.org)
/* Written in 2016-2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
@ -28,22 +27,48 @@ worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
int64_t s[2];
#include <stdint.h>
/* This is xoroshiro128+ 1.0, our best and fastest small-state generator
for floating-point numbers. We suggest to use its upper bits for
floating-point generation, as it is slightly faster than
xoroshiro128++/xoroshiro128**. It passes all tests we are aware of
except for the four lower bits, which might fail linearity tests (and
just those), so if low linear complexity is not considered an issue (as
it is usually the case) it can be used to generate 64-bit outputs, too;
moreover, this generator has a very mild Hamming-weight dependency
making our test (http://prng.di.unimi.it/hwd.php) fail after 5 TB of
output; we believe this slight bias cannot affect any application. If
you are concerned, use xoroshiro128++, xoroshiro128** or xoshiro256+.
We suggest to use a sign test to extract a random Boolean value, and
right shifts to extract subsets of bits.
The state must be seeded so that it is not everywhere zero. If you have
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
output to fill s.
NOTE: the parameters (a=24, b=16, b=37) of this version give slightly
better results in our test than the 2016 version (a=55, b=14, c=36).
*/
static inline uint64_t rotl(const uint64_t x, int k) {
return (x << k) | (x >> (64 - k));
return (x << k) | (x >> (64 - k));
}
static uint64_t s[2];
uint64_t next(void) {
const uint64_t s0 = s[0];
uint64_t s1 = s[1];
const uint64_t result = s0 + s1;
const uint64_t s0 = s[0];
uint64_t s1 = s[1];
const uint64_t result = s0 + s1;
s1 ^= s0;
s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b
s[1] = rotl(s1, 36); // c
s1 ^= s0;
s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b
s[1] = rotl(s1, 37); // c
return result;
return result;
}
/* ========== END of reference implementation of xoroshiro128+ ========== */
@ -58,12 +83,12 @@ int main(int argc, const char **argv)
if (argc != 4) {
fprintf(stderr, "Reference implementation of RNG xoroshiro128+\n");
fprintf(stderr, "\n");
fprintf(stderr, "Usage: ref_xoroshiro SEED0 SEED1 NUMVALUE\n");
fprintf(stderr, "Usage: ref_xoroshiro128plus SEED0 SEED1 NUMVALUE\n");
fprintf(stderr, " SEED0 seed value in range 0 .. (2**64-1)\n");
fprintf(stderr, " SEED1 seed value in range 0 .. (2**64-1)\n");
fprintf(stderr, " NUMVALUE number of values to get from generator\n");
fprintf(stderr, "\n");
fprintf(stderr, "Example: ref_xoroshiro 0x3141592653589793 "
fprintf(stderr, "Example: ref_xoroshiro128plus 0x3141592653589793 "
"0x0123456789abcdef 100\n");
exit(1);
}

View File

@ -0,0 +1,119 @@
/*
* Reference implementation of "xoshiro128++" in C.
*
* Algorithm code by David Blackman and Sebastiano Vigna <vigna@acm.org>
* Main program wrapper by Joris van Rantwijk <joris@jorisvr.nl>
*
* To the extent possible under law, the author has dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* See <http://creativecommons.org/publicdomain/zero/1.0/>
*/
#include <stdlib.h>
#include <stdio.h>
/* ========== BEGIN of reference implementation of xoshiro128++ ==========
* Source: http://prng.di.unimi.it/
*/
/* Written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include <stdint.h>
/* This is xoshiro128++ 1.0, one of our 32-bit all-purpose, rock-solid
generators. It has excellent speed, a state size (128 bits) that is
large enough for mild parallelism, and it passes all tests we are aware
of.
For generating just single-precision (i.e., 32-bit) floating-point
numbers, xoshiro128+ is even faster.
The state must be seeded so that it is not everywhere zero. */
static inline uint32_t rotl(const uint32_t x, int k) {
return (x << k) | (x >> (32 - k));
}
static uint32_t s[4];
uint32_t next(void) {
const uint32_t result = rotl(s[0] + s[3], 7) + s[0];
const uint32_t t = s[1] << 9;
s[2] ^= s[0];
s[3] ^= s[1];
s[1] ^= s[2];
s[0] ^= s[3];
s[2] ^= t;
s[3] = rotl(s[3], 11);
return result;
}
/* ========== END of reference implementation of xoshiro128++ ========== */
int main(int argc, const char **argv)
{
char *p;
unsigned long numval;
unsigned long k;
unsigned long long seed_tmp;
if (argc != 4) {
fprintf(stderr, "Reference implementation of RNG xoshiro128++\n");
fprintf(stderr, "\n");
fprintf(stderr, "Usage: ref_xoshiro128plusplus SEED0 SEED1 NVALUE\n");
fprintf(stderr, " SEEDn seed value in range 0 .. (2**64-1)\n");
fprintf(stderr, " NVALUE number of values to get from generator\n");
fprintf(stderr, "\n");
fprintf(stderr, "Example: ref_xoshiro128plusplus 0x3141592653589793 "
"0x0123456789abcdef 100\n");
exit(1);
}
seed_tmp = strtoull(argv[1], &p, 0);
if (p == argv[1] || *p != '\0') {
fprintf(stderr, "ERROR: Invalid value for SEED0\n");
exit(1);
}
s[0] = (uint32_t)seed_tmp;
s[1] = (uint32_t)(seed_tmp >> 32);
seed_tmp = strtoull(argv[2], &p, 0);
if (p == argv[2] || *p != '\0') {
fprintf(stderr, "ERROR: Invalid value for SEED1\n");
exit(1);
}
s[2] = (uint32_t)seed_tmp;
s[3] = (uint32_t)(seed_tmp >> 32);
numval = strtoul(argv[3], &p, 0);
if (p == argv[3] || *p != '\0') {
fprintf(stderr, "ERROR: Invalid value for NVALUE\n");
exit(1);
}
for (k = 0; k < numval; k++) {
printf("0x%08lx\n", (unsigned long) next());
}
return 0;
}

View File

@ -1,5 +1,5 @@
--
-- Pseudo Random Number Generator "xoroshiro128+".
-- Pseudo Random Number Generator "xoroshiro128+ 1.0".
--
-- Author: Joris van Rantwijk <joris@jorisvr.nl>
--
@ -7,9 +7,9 @@
-- The generator can produce 64 new random bits on every clock cycle.
--
-- The algorithm "xoroshiro128+" is by David Blackman and Sebastiano Vigna.
-- See also http://xoroshiro.di.unimi.it/
-- See also http://prng.di.unimi.it/
--
-- The generator requires a 128-bit seed value, not equal to zero.
-- The generator requires a 128-bit seed value, not equal to all zeros.
-- A default seed must be supplied at compile time and will be used
-- to initialize the generator at reset. The generator also supports
-- re-seeding at run time.
@ -19,12 +19,12 @@
--
-- NOTE: This is not a cryptographic random number generator.
--
-- NOTE: The least significant output bit is less random than
-- all other output bits.
-- NOTE: The least significant output bits are not fully random and
-- fail certain statistical tests.
--
--
-- Copyright (C) 2016 Joris van Rantwijk
-- Copyright (C) 2016-2020 Joris van Rantwijk
--
-- This code is free software; you can redistribute it and/or
-- modify it under the terms of the GNU Lesser General Public
@ -131,12 +131,12 @@ begin
-- Update internal state.
reg_state_s0 <= reg_state_s0 xor
reg_state_s1 xor
shiftl(reg_state_s0, 14) xor
shiftl(reg_state_s1, 14) xor
rotl(reg_state_s0, 55);
rotl(reg_state_s0, 24) xor
shiftl(reg_state_s0, 16) xor
shiftl(reg_state_s1, 16);
reg_state_s1 <= rotl(reg_state_s0, 36) xor
rotl(reg_state_s1, 36);
reg_state_s1 <= rotl(reg_state_s0, 37) xor
rotl(reg_state_s1, 37);
end if;

View File

@ -0,0 +1,200 @@
--
-- Pseudo Random Number Generator "xoshiro128++ 1.0".
--
-- Author: Joris van Rantwijk <joris@jorisvr.nl>
--
-- This is a 32-bit random number generator in synthesizable VHDL.
-- The generator can produce 32 new random bits on every clock cycle.
--
-- The algorithm "xoshiro128++" is by David Blackman and Sebastiano Vigna.
-- See also http://prng.di.unimi.it/
--
-- The generator requires a 128-bit seed value, not equal to all zeros.
-- A default seed must be supplied at compile time and will be used
-- to initialize the generator at reset. The generator also supports
-- re-seeding at run time.
--
-- After reset and after re-seeding, one or two clock cycles are needed
-- before valid random data appears on the output. The exact delay
-- depends on the setting of the "pipeline" parameter.
--
-- NOTE: This is not a cryptographic random number generator.
--
--
-- Copyright (C) 2020 Joris van Rantwijk
--
-- This code is free software; you can redistribute it and/or
-- modify it under the terms of the GNU Lesser General Public
-- License as published by the Free Software Foundation; either
-- version 2.1 of the License, or (at your option) any later version.
--
-- See <https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html>
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity rng_xoshiro128plusplus is
generic (
-- Default seed value.
init_seed: std_logic_vector(127 downto 0);
-- Enable optional pipeline stage in output calculation.
-- This uses an extra 32-bit register but tends to improve
-- the timing performance of the circuit.
-- If the pipeline stage is enabled, two clock cycles are needed
-- before valid output appears after reset and after re-seeding.
-- If the pipeline stage is disabled, just one clock cycle is needed.
pipeline: boolean := true );
port (
-- Clock, rising edge active.
clk: in std_logic;
-- Synchronous reset, active high.
rst: in std_logic;
-- High to request re-seeding of the generator.
reseed: in std_logic;
-- New seed value (must be valid when reseed = '1').
newseed: in std_logic_vector(127 downto 0);
-- High when the user accepts the current random data word
-- and requests new random data for the next clock cycle.
out_ready: in std_logic;
-- High when valid random data is available on the output.
-- This signal is low for 1 or 2 clock cycles after reset and
-- after re-seeding, and high in all other cases.
out_valid: out std_logic;
-- Random output data (valid when out_valid = '1').
-- A new random word appears after every rising clock edge
-- where out_ready = '1'.
out_data: out std_logic_vector(31 downto 0) );
end entity;
architecture xoshiro128plusplus_arch of rng_xoshiro128plusplus is
-- Internal state of RNG.
signal reg_state_s0: std_logic_vector(31 downto 0) := init_seed(31 downto 0);
signal reg_state_s1: std_logic_vector(31 downto 0) := init_seed(63 downto 32);
signal reg_state_s2: std_logic_vector(31 downto 0) := init_seed(95 downto 64);
signal reg_state_s3: std_logic_vector(31 downto 0) := init_seed(127 downto 96);
-- Optional pipeline register.
signal reg_sum_s0s3: std_logic_vector(31 downto 0) := (others => '0');
-- Output register.
signal reg_valid: std_logic := '0';
signal reg_nvalid: std_logic := '0';
signal reg_output: std_logic_vector(31 downto 0) := (others => '0');
begin
-- Drive output signal.
out_valid <= reg_valid;
out_data <= reg_output;
-- Synchronous process.
process (clk) is
variable v_prev_s0: std_logic_vector(31 downto 0) := (others => '0');
begin
if rising_edge(clk) then
if out_ready = '1' or reg_valid = '0' then
-- Prepare output word.
if pipeline then
-- Use a pipelined output stage.
reg_valid <= reg_nvalid;
reg_nvalid <= '1';
-- Calculate the previous value of s0.
v_prev_s0 := reg_state_s0 xor
std_logic_vector(
rotate_right(unsigned(reg_state_s3),
11));
-- Derive output from prev_s0 and intermediate result
-- (prev_s0 + prev_s3) calculated in the previous cycle.
reg_output <= std_logic_vector(
unsigned(v_prev_s0) +
rotate_left(unsigned(reg_sum_s0s3),
7));
-- Update the intermediate register (s0 + s3).
reg_sum_s0s3 <= std_logic_vector(
unsigned(reg_state_s0) +
unsigned(reg_state_s3));
else
-- Derive output directly from s0 and s3.
-- This requires two cascaded 32-bit adders and
-- may limit the timing performance of the circuit.
reg_valid <= '1';
reg_output <= std_logic_vector(
rotate_left(
unsigned(reg_state_s0) +
unsigned(reg_state_s3), 7) +
unsigned(reg_state_s0));
end if;
-- Update internal state.
reg_state_s0 <= reg_state_s0 xor
reg_state_s1 xor
reg_state_s3;
reg_state_s1 <= reg_state_s0 xor
reg_state_s1 xor
reg_state_s2;
reg_state_s2 <= reg_state_s0 xor
reg_state_s2 xor
std_logic_vector(
shift_left(unsigned(reg_state_s1), 9));
reg_state_s3 <= std_logic_vector(
rotate_left(
unsigned(reg_state_s1 xor
reg_state_s3), 11));
end if;
-- Re-seed function.
if reseed = '1' then
reg_state_s0 <= newseed(31 downto 0);
reg_state_s1 <= newseed(63 downto 32);
reg_state_s2 <= newseed(95 downto 64);
reg_state_s3 <= newseed(127 downto 96);
reg_valid <= '0';
reg_nvalid <= '0';
end if;
-- Synchronous reset.
if rst = '1' then
reg_state_s0 <= init_seed(31 downto 0);
reg_state_s1 <= init_seed(63 downto 32);
reg_state_s2 <= init_seed(95 downto 64);
reg_state_s3 <= init_seed(127 downto 96);
reg_valid <= '0';
reg_nvalid <= '0';
reg_output <= (others => '0');
end if;
end if;
end process;
end architecture;

View File

@ -6,7 +6,14 @@ GHDL = ghdl
GHDLFLAGS =
.PHONY: all
all: tb_xoroshiro128plus tb_mt19937 tb_trivium
all: tb_xoshiro128plusplus \
tb_xoroshiro128plus \
tb_mt19937 \
tb_trivium
tb_xoshiro128plusplus: tb_xoshiro128plusplus.o rng_xoshiro128plusplus.o
tb_xoshiro128plusplus.o: tb_xoshiro128plusplus.vhdl rng_xoshiro128plusplus.o
rng_xoshiro128plusplus.o: ../rtl/rng_xoshiro128plusplus.vhdl
tb_xoroshiro128plus: tb_xoroshiro128plus.o rng_xoroshiro128plus.o
tb_xoroshiro128plus.o: tb_xoroshiro128plus.vhdl rng_xoroshiro128plus.o

View File

@ -28,6 +28,8 @@ architecture arch of tb_trivium is
type test_vectors is array (natural range <>) of test_vector;
-- This is a small subset of the test vectors from
-- the ECRYPT stream cipher project.
constant testvec: test_vectors(0 to 4) := (
0 => ( key => x"0053A6F94C9FF24598EB",
iv => x"0D74DB42A91077DE45AC",

View File

@ -0,0 +1,188 @@
--
-- Test bench for PRNG "xoshiro128++".
--
use std.textio.all;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tb_xoshiro128plusplus is
end entity;
architecture arch of tb_xoshiro128plusplus is
signal clk: std_logic;
signal clock_active: boolean := false;
signal s_rst: std_logic;
signal s_reseed: std_logic;
signal s_newseed: std_logic_vector(127 downto 0);
signal s_ready: std_logic;
signal s_valid: std_logic;
signal s_data: std_logic_vector(31 downto 0);
function to_hex_string(s: std_logic_vector)
return string
is
constant alphabet: string(1 to 16) := "0123456789abcdef";
variable y: string(1 to s'length/4);
begin
for i in y'range loop
y(i) := alphabet(to_integer(unsigned(s(s'high+4-4*i downto s'high+1-4*i))) + 1);
end loop;
return y;
end function;
begin
-- Instantiate PRNG.
inst_prng: entity work.rng_xoshiro128plusplus
generic map (
init_seed => x"0123456789abcdef3141592653589793" )
port map (
clk => clk,
rst => s_rst,
reseed => s_reseed,
newseed => s_newseed,
out_ready => s_ready,
out_valid => s_valid,
out_data => s_data );
-- Generate clock.
clk <= (not clk) after 10 ns when clock_active else '0';
-- Main simulation process.
process is
file outf1: text is out "sim_xoshiro128plusplus_seed1.dat";
file outf2: text is out "sim_xoshiro128plusplus_seed2.dat";
variable lin: line;
variable nskip: integer;
variable v: std_logic_vector(31 downto 0);
begin
report "Start test bench";
-- Reset.
s_rst <= '1';
s_reseed <= '0';
s_newseed <= (others => '0');
s_ready <= '0';
-- Start clock.
clock_active <= true;
-- Wait 2 clock cycles, then end reset.
wait for 30 ns;
wait until falling_edge(clk);
s_rst <= '0';
-- Wait 1 clock cycle to initialize generator.
wait until falling_edge(clk);
s_ready <= '1';
-- Optionally wait an additional pipeline cycle.
if s_valid = '0' then
report "Detected pipeline delay";
wait until falling_edge(clk);
end if;
-- Produce numbers
for i in 0 to 999 loop
-- Check that output is valid.
assert s_valid = '1' report "Output not valid";
-- Write output to file.
write(lin, "0x" & to_hex_string(s_data));
writeline(outf1, lin);
-- Sometimes skip cycles.
if i mod 5 = 1 then
nskip := 1;
if i mod 3 = 0 then
nskip := nskip + 1;
end if;
if i mod 11 = 0 then
nskip := nskip + 1;
end if;
v := s_data;
s_ready <= '0';
for t in 1 to nskip loop
wait until falling_edge(clk);
assert s_valid = '1' report "Output not valid";
assert s_data = v report "Output changed while not ready";
end loop;
s_ready <= '1';
end if;
-- Go to next cycle.
wait until falling_edge(clk);
end loop;
-- Re-seed generator.
report "Re-seed generator";
s_reseed <= '1';
s_newseed <= x"3141592653589793fedcba9876543210";
s_ready <= '0';
wait until falling_edge(clk);
s_reseed <= '0';
s_newseed <= (others => '0');
-- Wait 1 clock cycle to re-seed generator.
wait until falling_edge(clk);
s_ready <= '1';
-- Optionally wait an additional pipeline cycle.
if s_valid = '0' then
report "Detected pipeline delay";
wait until falling_edge(clk);
end if;
-- Produce numbers
for i in 0 to 999 loop
-- Check that output is valid.
assert s_valid = '1' report "Output not valid";
-- Write output to file.
write(lin, "0x" & to_hex_string(s_data));
writeline(outf2, lin);
-- Sometimes skip cycles.
if i mod 5 = 2 then
nskip := 1;
if i mod 3 = 0 then
nskip := nskip + 1;
end if;
if i mod 11 = 0 then
nskip := nskip + 1;
end if;
v := s_data;
s_ready <= '0';
for t in 1 to nskip loop
wait until falling_edge(clk);
assert s_valid = '1' report "Output not valid";
assert s_data = v report "Output changed while not ready";
end loop;
s_ready <= '1';
end if;
-- Go to next cycle.
wait until falling_edge(clk);
end loop;
-- End simulation.
report "End testbench";
clock_active <= false;
wait;
end process;
end architecture;

33
synth/top_trivium.vhdl Normal file
View File

@ -0,0 +1,33 @@
library ieee;
use ieee.std_logic_1164.all;
entity toptriv is
port (
clk : in std_logic;
rst : in std_logic;
ready: in std_logic;
valid: out std_logic;
data: out std_logic_vector(31 downto 0) );
end toptriv;
architecture arch of toptriv is
begin
inst_prng: entity work.rng_trivium
generic map (
num_bits => 32,
init_key => x"31415926535897932384",
init_iv => x"0123456789abcdefa50f" )
port map (
clk => clk,
rst => rst,
reseed => '0',
newkey => (others => '0'),
newiv => (others => '0'),
out_ready => ready,
out_valid => valid,
out_data => data );
end arch;

View File

@ -2,16 +2,16 @@
library ieee;
use ieee.std_logic_1164.all;
entity topxs is
entity top_xoroshiro128plus is
port (
clk : in std_logic;
rst : in std_logic;
ready: in std_logic;
valid: out std_logic;
data: out std_logic_vector(63 downto 0) );
end topxs;
end top_xoroshiro128plus;
architecture arch of topxs is
architecture arch of top_xoroshiro128plus is
begin
inst_prng: entity work.rng_xoroshiro128plus

View File

@ -0,0 +1,30 @@
library ieee;
use ieee.std_logic_1164.all;
entity top_xoshiro128plusplus is
port (
clk : in std_logic;
rst : in std_logic;
ready: in std_logic;
valid: out std_logic;
data: out std_logic_vector(31 downto 0) );
end top_xoshiro128plusplus;
architecture arch of top_xoshiro128plusplus is
begin
inst_prng: entity work.rng_xoshiro128plusplus
generic map (
init_seed => x"0123456789abcdef3141592653589793" )
port map (
clk => clk,
rst => rst,
reseed => '0',
newseed => (others => '0'),
out_ready => ready,
out_valid => valid,
out_data => data );
end arch;