blob: d79a70a4048fd9f5d9b33b48240d99faac3a9fde [file] [log] [blame]
// 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;
}