Software APIs
rand_testutils.c
1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5#include "sw/device/lib/testing/rand_testutils.h"
6
7#include <stdbool.h>
8#include <stdint.h>
9
12#include "sw/device/lib/dif/dif_rv_core_ibex.h"
14#include "sw/device/lib/testing/rv_core_ibex_testutils.h"
15#include "sw/device/lib/testing/test_framework/check.h"
16
17/**
18 * The polynomial co-efficients used in the 32-bit LFSR implementation.
19 *
20 * This implementation matches the RTL design at `hw/ip/prim/rtl/prim_lfsr.sv`.
21 */
22static const uint32_t kLfsrPolynomialCoefficients = 0x80000057;
23
24/**
25 * The default timeout in usecs for fetching data from the entropy source.
26 */
27static const uint32_t kEntropyFetchTimeoutMicros = 100000;
28
29rand_testutils_rng_t rand_testutils_init(dif_rv_core_ibex_t *rv_core_ibex) {
30 CHECK(rv_core_ibex != NULL);
31 // For the simulation platforms (DV and Verilator), the LFSR reseed frequency
32 // is arbitrarily set to 255. The test may choose to update this value if
33 // needed.
34 rand_testutils_rng_t ctx = (rand_testutils_rng_t){
35 .rv_core_ibex = rv_core_ibex,
36 .entropy_fetch_timeout_usec = kEntropyFetchTimeoutMicros,
37 .lfsr = 0xdeadbeef, // Arbitrary.
38 .polynomial_coefficients = kLfsrPolynomialCoefficients,
39 .reseed_frequency = 256,
40 .op_counter = UINT32_MAX};
41 // For non-runtime-sensitive simulations (for example, using FPGA or the
42 // debug board), always fetch random data from the hardware.
44 ctx.reseed_frequency = 0;
45 }
46 return ctx;
47}
48
49static inline void reseed_lfsr(void) {
50 CHECK_STATUS_OK(rv_core_ibex_testutils_get_rnd_data(
51 rand_testutils_rng_ctx.rv_core_ibex,
52 rand_testutils_rng_ctx.entropy_fetch_timeout_usec,
53 &rand_testutils_rng_ctx.lfsr));
54 rand_testutils_rng_ctx.op_counter = 0;
55}
56
57static inline void advance_lfsr(void) {
58 bool lsb = rand_testutils_rng_ctx.lfsr & 0x1u;
59 rand_testutils_rng_ctx.lfsr >>= 1;
60 if (lsb) {
61 rand_testutils_rng_ctx.lfsr ^=
62 rand_testutils_rng_ctx.polynomial_coefficients;
63 }
64 rand_testutils_rng_ctx.op_counter++;
65}
66
67extern void rand_testutils_reseed(void);
68
69uint32_t rand_testutils_gen32(void) {
70 if (rand_testutils_rng_ctx.op_counter >=
71 rand_testutils_rng_ctx.reseed_frequency) {
72 reseed_lfsr();
73 } else {
74 advance_lfsr();
75 }
76 return rand_testutils_rng_ctx.lfsr;
77}
78
79uint32_t rand_testutils_gen32_range(uint32_t min, uint32_t max) {
80 CHECK(max >= min);
81 uint32_t range = max - min;
82 if (range == 0) {
83 return min;
84 }
85 uint32_t result = min + (rand_testutils_gen32() % (range + 1));
86 CHECK(result >= min && result <= max);
87 return result;
88}
89
90void rand_testutils_shuffle(void *array, size_t size, size_t length) {
91 if (length <= 1) {
92 return;
93 }
94 unsigned char temp[size];
95 unsigned char *array8 = array;
96 uint32_t reseed_frequency = rand_testutils_rng_ctx.reseed_frequency;
97 rand_testutils_rng_ctx.reseed_frequency = UINT32_MAX;
98 for (size_t i = length - 2; i > 0; i--) {
99 size_t j = rand_testutils_gen32_range(0, i + 1);
100 memcpy(temp, array8 + j * size, size);
101 memcpy(array8 + j * size, array8 + i * size, size);
102 memcpy(array8 + i * size, temp, size);
103 }
104 rand_testutils_rng_ctx.reseed_frequency = reseed_frequency;
105}