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  */
22 static const uint32_t kLfsrPolynomialCoefficients = 0x80000057;
23 
24 /**
25  * The default timeout in usecs for fetching data from the entropy source.
26  */
27 static const uint32_t kEntropyFetchTimeoutMicros = 100000;
28 
29 rand_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.
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 
49 static 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 
57 static 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 
67 extern void rand_testutils_reseed(void);
68 
69 uint32_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 
79 uint32_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 
90 void 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 }