use core::fmt;
use crate::ral::trng;
use crate::ral::{modify_reg, read_reg, write_reg};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum SampleMode {
VonNeumann = trng::MCTL::SAMP_MODE::RW::SAMP_MODE_0,
Raw = trng::MCTL::SAMP_MODE::RW::SAMP_MODE_1,
VonNeumannRaw = trng::MCTL::SAMP_MODE::RW::SAMP_MODE_2,
}
impl Default for SampleMode {
fn default() -> Self {
Self::VonNeumannRaw
}
}
pub struct Trng {
reg: trng::TRNG,
block: [u32; 16],
index: usize,
}
impl fmt::Debug for Trng {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TRNG")
.field("block", &self.block)
.field("index", &self.index)
.finish()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RetryCount(u32);
impl RetryCount {
pub const DEFAULT: u32 = 15;
pub fn new(retry_count: u32) -> Option<Self> {
(1..=15)
.contains(&retry_count)
.then_some(RetryCount(retry_count))
}
}
impl Default for RetryCount {
fn default() -> Self {
RetryCount(Self::DEFAULT)
}
}
impl Trng {
pub fn new(reg: trng::TRNG, sample_mode: SampleMode, retry_count: RetryCount) -> Self {
modify_reg!(trng, reg, MCTL, PRGM: 1);
modify_reg!(trng, reg, MCTL, RST_DEF: 1);
write_reg!(trng, reg, SCMISC, RTY_CT: retry_count.0, LRUN_MAX: 34);
write_reg!(trng, reg, SCML, MONO_MAX: 1384, MONO_RNG: 268); write_reg!(trng, reg, SCR1L, RUN1_MAX: 405, RUN1_RNG: 178); write_reg!(trng, reg, SCR2L, RUN2_MAX: 220, RUN2_RNG: 122); write_reg!(trng, reg, SCR3L, RUN3_MAX: 125, RUN3_RNG: 88); write_reg!(trng, reg, SCR4L, RUN4_MAX: 75, RUN4_RNG: 64); write_reg!(trng, reg, SCR5L, RUN5_MAX: 47, RUN5_RNG: 46); write_reg!(trng, reg, SCR6PL, RUN6P_MAX: 47, RUN6P_RNG: 46);
write_reg!(trng, reg, PKRMAX, PKR_MAX: 26912); write_reg!(trng, reg, PKRRNG, PKR_RNG: 2467);
write_reg!(trng, reg, FRQMAX, FRQ_MAX: 25600); write_reg!(trng, reg, FRQMIN, FRQ_MIN: 1600);
write_reg!(trng, reg, SDCTL, SAMP_SIZE: 2500, ENT_DLY: 3200); write_reg!(trng, reg, SBLIM, SB_LIM: 63);
modify_reg!(trng, reg, MCTL, SAMP_MODE: sample_mode as u32);
modify_reg!(trng, reg, MCTL, PRGM: 0);
read_reg!(trng, reg, ENT[15]);
Self {
reg,
block: [0; 16],
index: 16, }
}
pub fn next_u32(&mut self) -> nb::Result<u32, Error> {
self.retrieve_if_needed()?;
let data = nb::Result::Ok(self.block[self.index]);
self.index += 1;
data
}
fn retrieve_if_needed(&mut self) -> nb::Result<(), Error> {
if self.index >= self.block.len() {
self.retrieve()?;
self.index = 0;
}
Ok(())
}
fn retrieve(&mut self) -> nb::Result<(), Error> {
let mctl = read_reg!(trng, self.reg, MCTL);
if (mctl & trng::MCTL::ERR::mask) != 0 {
let flags = self.get_error_flags();
write_reg!(trng, self.reg, MCTL, mctl); return Err(nb::Error::Other(Error(flags)));
}
if (mctl & trng::MCTL::ENT_VAL::mask) == 0 {
return Err(nb::Error::WouldBlock); }
for idx in 0..self.reg.ENT.len() {
self.block[idx] = read_reg!(trng, self.reg, ENT[idx]);
}
read_reg!(trng, self.reg, ENT[0]);
Ok(())
}
fn get_error_flags(&self) -> ErrorFlags {
let status = read_reg!(trng, self.reg, STATUS) & 0xFFFF;
let mut flags = ErrorFlags::from_bits_truncate(status);
flags.set(
ErrorFlags::FCT_FAIL,
read_reg!(trng, self.reg, MCTL, FCT_FAIL) == 1,
);
flags
}
pub fn release_disabled(self) -> trng::TRNG {
modify_reg!(trng, self.reg, MCTL, PRGM: 1);
while read_reg!(trng, self.reg, MCTL, TSTOP_OK) == 0 {
core::hint::spin_loop();
}
self.reg
}
#[cfg(feature = "rand_core")]
pub fn into_rng(self) -> RngCoreWrapper {
RngCoreWrapper(self)
}
#[cfg(feature = "rand_core")]
fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
let mut data = [0; 4];
let mut index = 4;
for b in buffer.iter_mut() {
if index == 4 {
data = nb::block!(self.next_u32())?.to_be_bytes();
index = 0;
}
*b = data[index];
index += 1;
}
Ok(())
}
}
#[cfg(feature = "rand_core")]
pub struct RngCoreWrapper(Trng);
#[cfg(feature = "rand_core")]
impl RngCoreWrapper {
pub fn into_inner(self) -> Trng {
self.0
}
}
#[cfg(feature = "rand_core")]
impl rand_core::RngCore for RngCoreWrapper {
fn next_u32(&mut self) -> u32 {
let mut bytes = [0; 4];
self.fill_bytes(&mut bytes);
u32::from_be_bytes(bytes)
}
fn next_u64(&mut self) -> u64 {
let mut bytes = [0; 8];
self.fill_bytes(&mut bytes);
u64::from_be_bytes(bytes)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
self.try_fill_bytes(dest).expect("TRNG returned an error")
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
self.0.read(dest).map_err(|e| {
let code = e.0.bits | rand_core::Error::CUSTOM_START;
unsafe { core::num::NonZeroU32::new_unchecked(code).into() }
})
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Error(pub ErrorFlags);
bitflags::bitflags! {
pub struct ErrorFlags : u32 {
const TF1BR0 = 1 << 0;
const TF1BR1 = 1 << 1;
const TF2BR0 = 1 << 2;
const TF2BR1 = 1 << 3;
const TF3BR0 = 1 << 4;
const TF3BR1 = 1 << 5;
const TF4BR0 = 1 << 6;
const TF4BR1 = 1 << 7;
const TF5BR0 = 1 << 8;
const TF5BR1 = 1 << 9;
const TF6PBR0 = 1 << 10;
const TF6PBR1 = 1 << 11;
const TFSB = 1 << 12;
const TFLR = 1 << 13;
const TFP = 1 << 14;
const TFMB = 1 << 15;
const FCT_FAIL = 1 << 16;
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "An error occurred in the TRNG module")
}
}
#[cfg(feature = "eh02-unproven")]
impl eh02::blocking::rng::Read for Trng {
type Error = Error;
fn read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> {
let mut data = [0; 4];
let mut index = 4;
for b in buffer.iter_mut() {
if index == 4 {
data = nb::block!(self.next_u32())?.to_be_bytes();
index = 0;
}
*b = data[index];
index += 1;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::RetryCount;
#[test]
fn retry_count() {
assert!(RetryCount::new(0).is_none());
for count in 1..16 {
assert!(RetryCount::new(count).is_some());
}
assert!(RetryCount::new(16).is_none());
}
}