Line 60... |
Line 60... |
}
|
}
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Enable and configure true random number generator. The TRNG control register bits are listed in #NEORV32_TRNG_CT_enum.
|
* Enable true random number generator. The TRNG control register bits are listed in #NEORV32_TRNG_CT_enum.
|
*
|
|
* @param[in] tap_mask 16-bit tap mask for GARO array.
|
|
* @return Returns 0 if the provided tap_mask works correctly (GARO-array is oscillating), returns 1 otherwise.
|
|
**************************************************************************/
|
**************************************************************************/
|
int neorv32_trng_setup(uint16_t tap_mask) {
|
void neorv32_trng_enable(void) {
|
|
|
|
int i;
|
|
|
TRNG_CT = 0; // reset
|
TRNG_CT = 0; // reset
|
|
|
// configure
|
for (i=0; i<1000; i++) {
|
uint32_t tap_config = (uint32_t)(tap_mask);
|
asm volatile ("nop");
|
tap_config = tap_config << TRNG_CT_TAP_LSB;
|
|
TRNG_CT = (1 << TRNG_CT_EN) | tap_config;
|
|
|
|
neorv32_cpu_delay_ms(1);
|
|
|
|
// check if TRNG is oscillating
|
|
uint16_t trng_data;
|
|
if (neorv32_trng_get(&trng_data) == 0) {
|
|
return 0;
|
|
}
|
}
|
else {
|
|
return 1;
|
TRNG_CT = 1 << TRNG_CT_EN; // activate
|
|
|
|
for (i=0; i<1000; i++) {
|
|
asm volatile ("nop");
|
}
|
}
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
Line 99... |
Line 92... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Get random data from TRNG.
|
* Get random data from TRNG.
|
*
|
*
|
* @param[in,out] data uint16_t pointer for storing random data word
|
* @note The TRNG is automatically reset if a stuck-at-one/stuck-at-zero error is detected.
|
* @return Valid data when 0, invalid data when 1
|
|
**************************************************************************/
|
|
int neorv32_trng_get(uint16_t *data) {
|
|
|
|
int i;
|
|
const int max_try = 16;
|
|
uint32_t trng_data;
|
|
uint32_t rnd_data;
|
|
|
|
for(i=0; i<max_try; i++) {
|
|
|
|
trng_data = TRNG_DATA;
|
|
rnd_data = trng_data >> TRNG_DATA_LSB;
|
|
*data = (uint16_t)rnd_data;
|
|
|
|
if (trng_data & (1<<TRNG_DATA_VALID)) { // output data valid?
|
|
return 0; // valid
|
|
}
|
|
|
|
}
|
|
|
|
return 1; // invalid
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Try to find a valid TRNG tap configuration mask.
|
|
*
|
*
|
* @return Tap mask for configuring the TRNG. If return is zero, no valid tap mask was found.
|
* @param[in,out] data uint8_t pointer for storing random data word
|
|
* @return Data is valid when 0, stuck-at-zero error when 1, stuck-at-one error when 2, data not (yet) valid when 3
|
**************************************************************************/
|
**************************************************************************/
|
uint16_t neorv32_trng_find_tap_mask(void) {
|
int neorv32_trng_get(uint8_t *data) {
|
|
|
int j;
|
|
uint16_t tap_config16 = 0xfff0; // keep the lowest inverters without feedback
|
|
uint16_t trng_data;
|
|
int success = 0;
|
|
|
|
// tap mask is zero, try to find a nice one
|
uint32_t trng_ct_reg = TRNG_CT;
|
while (1) {
|
|
|
|
// good mask found?
|
if (trng_ct_reg & (1<<TRNG_CT_ERROR_0)) { // stuck at zero error
|
if ((success) || (tap_config16 <= 0x0008)) {
|
neorv32_trng_enable(); // reset TRNG
|
break;
|
return 1;
|
}
|
}
|
|
|
// generate a new tap
|
if (trng_ct_reg & (1<<TRNG_CT_ERROR_1)) { // stuck at one error
|
tap_config16 -= 0x0008;
|
neorv32_trng_enable(); // reset TRNG
|
|
return 2;
|
// install it
|
|
if (neorv32_trng_setup(tap_config16)) {
|
|
continue;
|
|
}
|
}
|
|
|
// does it work?
|
if ((trng_ct_reg & (1<<TRNG_CT_VALID)) == 0) { // output data valid (yet)?
|
success = 1;
|
return 3;
|
for (j=0; j < 100; j++) {
|
|
neorv32_cpu_delay_ms(1);
|
|
if (neorv32_trng_get(&trng_data)) { // stop testing on fail
|
|
success = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
}
|
|
|
return (uint16_t)tap_config16;
|
*data = (uint8_t)(trng_ct_reg >> TRNG_CT_DATA_LSB);
|
|
return 0; // valid data
|
}
|
}
|
|
|
|
|
No newline at end of file
|
No newline at end of file
|