| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| #include "sw/device/lib/testing/rand_testutils.h" |
| |
| #include <stdbool.h> |
| #include <stdint.h> |
| |
| #include "sw/device/lib/arch/device.h" |
| #include "sw/device/lib/base/memory.h" |
| #include "sw/device/lib/dif/dif_rv_core_ibex.h" |
| #include "sw/device/lib/runtime/log.h" |
| #include "sw/device/lib/testing/rv_core_ibex_testutils.h" |
| #include "sw/device/lib/testing/test_framework/check.h" |
| |
| #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" |
| |
| /** |
| * The polynomial co-efficients used in the 32-bit LFSR implementation. |
| * |
| * This implementation matches the RTL design at `hw/ip/prim/rtl/prim_lfsr.sv`. |
| */ |
| static const uint32_t kLfsrPolynomialCoefficients = 0x80000057; |
| |
| /** |
| * The default timeout in usecs for fetching data from the entropy source. |
| */ |
| static const uint32_t kEntropyFetchTimeoutMicros = 100000; |
| |
| rand_testutils_rng_t rand_testutils_init(dif_rv_core_ibex_t *rv_core_ibex) { |
| CHECK(rv_core_ibex != NULL); |
| // For the simulation platforms (DV and Verilator), the LFSR reseed frequency |
| // is arbitrarily set to 255. The test may choose to update this value if |
| // needed. |
| rand_testutils_rng_t ctx = (rand_testutils_rng_t){ |
| .rv_core_ibex = rv_core_ibex, |
| .entropy_fetch_timeout_usec = kEntropyFetchTimeoutMicros, |
| .lfsr = 0xdeadbeef, // Arbitrary. |
| .polynomial_coefficients = kLfsrPolynomialCoefficients, |
| .reseed_frequency = 256, |
| .op_counter = UINT32_MAX}; |
| // For non-runtime-sensitive simulations (for example, using FPGA or the |
| // debug board), always fetch random data from the hardware. |
| if (kDeviceType != kDeviceSimDV && kDeviceType != kDeviceSimVerilator) { |
| ctx.reseed_frequency = 0; |
| } |
| return ctx; |
| } |
| |
| static inline void reseed_lfsr(void) { |
| rand_testutils_rng_ctx.lfsr = rv_core_ibex_testutils_get_rnd_data( |
| rand_testutils_rng_ctx.rv_core_ibex, |
| rand_testutils_rng_ctx.entropy_fetch_timeout_usec); |
| rand_testutils_rng_ctx.op_counter = 0; |
| } |
| |
| static inline void advance_lfsr(void) { |
| bool lsb = rand_testutils_rng_ctx.lfsr & 0x1u; |
| rand_testutils_rng_ctx.lfsr >>= 1; |
| if (lsb) { |
| rand_testutils_rng_ctx.lfsr ^= |
| rand_testutils_rng_ctx.polynomial_coefficients; |
| } |
| rand_testutils_rng_ctx.op_counter++; |
| } |
| |
| extern void rand_testutils_reseed(void); |
| |
| uint32_t rand_testutils_gen32(void) { |
| if (rand_testutils_rng_ctx.op_counter >= |
| rand_testutils_rng_ctx.reseed_frequency) { |
| reseed_lfsr(); |
| } else { |
| advance_lfsr(); |
| } |
| return rand_testutils_rng_ctx.lfsr; |
| } |
| |
| uint32_t rand_testutils_gen32_range(uint32_t min, uint32_t max) { |
| CHECK(max >= min); |
| uint32_t range = max - min; |
| if (range == 0) { |
| return min; |
| } |
| uint32_t result = min + (rand_testutils_gen32() % (range + 1)); |
| CHECK(result >= min && result <= max); |
| return result; |
| } |
| |
| void rand_testutils_shuffle(void *array, size_t size, size_t length) { |
| if (length <= 1) { |
| return; |
| } |
| unsigned char temp[size]; |
| unsigned char *array8 = array; |
| uint32_t reseed_frequency = rand_testutils_rng_ctx.reseed_frequency; |
| rand_testutils_rng_ctx.reseed_frequency = UINT32_MAX; |
| for (size_t i = length - 2; i > 0; i--) { |
| size_t j = rand_testutils_gen32_range(0, i + 1); |
| memcpy(temp, array8 + j * size, size); |
| memcpy(array8 + j * size, array8 + i * size, size); |
| memcpy(array8 + i * size, temp, size); |
| } |
| rand_testutils_rng_ctx.reseed_frequency = reseed_frequency; |
| } |