1 /* 2 * Copyright (c) 2017 Oticon A/S 3 * Copyright (c) 2023 Nordic Semiconductor ASA 4 * 5 * SPDX-License-Identifier: Apache-2.0 6 */ 7 #include "NRF_RNG.h" 8 #include <string.h> 9 #include <stdbool.h> 10 #include "time_machine_if.h" 11 #include "NRF_HW_model_top.h" 12 #include "NRF_PPI.h" 13 #include "irq_ctrl.h" 14 #include "bs_rand_main.h" 15 16 /* 17 * RNG — Random number generator 18 * https://infocenter.nordicsemi.com/topic/ps_nrf52833/rng.html?cp=4_1_0_5_18 19 * 20 * Very rough model 21 */ 22 23 NRF_RNG_Type NRF_RNG_regs; 24 bs_time_t Timer_RNG = TIME_NEVER; //Time when the next random number will be ready 25 26 static bool RNG_hw_started = false; 27 static bool RNG_INTEN = false; //interrupt enable 28 29 /** 30 * Initialize the RNG model 31 */ nrf_rng_init()32void nrf_rng_init(){ 33 memset(&NRF_RNG_regs, 0, sizeof(NRF_RNG_regs)); 34 RNG_hw_started = false; 35 RNG_INTEN = false; 36 Timer_RNG = TIME_NEVER; 37 } 38 39 /** 40 * Clean up the RNG model before program exit 41 */ nrf_rng_clean_up()42void nrf_rng_clean_up(){ 43 44 } 45 nrf_rng_schedule_next(bool first_time)46static void nrf_rng_schedule_next(bool first_time){ 47 bs_time_t delay = 0; 48 49 if ( first_time ) { 50 delay = 128; 51 } 52 53 if ( NRF_RNG_regs.CONFIG ){ //Bias correction enabled 54 delay += 120; 55 /* 56 * The spec says that the delay is unpredictable yet it does not 57 * provide any indication of what kind of random distribution to 58 * expect => I just assume the value is always the average(?) they 59 * provide 60 */ 61 } else { 62 delay += 30; 63 } 64 Timer_RNG = tm_get_hw_time() + delay; 65 66 nrf_hw_find_next_timer_to_trigger(); 67 } 68 69 /** 70 * TASK_START triggered handler 71 */ nrf_rng_task_start()72void nrf_rng_task_start(){ 73 if (RNG_hw_started) { 74 return; 75 } 76 RNG_hw_started = true; 77 78 nrf_rng_schedule_next(true); 79 } 80 81 /** 82 * TASK_STOP triggered handler 83 */ nrf_rng_task_stop()84void nrf_rng_task_stop(){ 85 RNG_hw_started = false; 86 Timer_RNG = TIME_NEVER; 87 nrf_hw_find_next_timer_to_trigger(); 88 } 89 90 nrf_rng_regw_sideeffects_TASK_START()91void nrf_rng_regw_sideeffects_TASK_START(){ 92 if ( NRF_RNG_regs.TASKS_START ) { 93 NRF_RNG_regs.TASKS_START = 0; 94 nrf_rng_task_start(); 95 } 96 } 97 nrf_rng_regw_sideeffects_TASK_STOP()98void nrf_rng_regw_sideeffects_TASK_STOP(){ 99 if ( NRF_RNG_regs.TASKS_STOP ) { 100 NRF_RNG_regs.TASKS_STOP = 0; 101 nrf_rng_task_stop(); 102 } 103 } 104 nrf_rng_regw_sideeffects_INTENSET()105void nrf_rng_regw_sideeffects_INTENSET(){ 106 if ( NRF_RNG_regs.INTENSET ) { 107 RNG_INTEN = true; 108 } 109 } 110 nrf_rng_regw_sideeffects_INTENCLEAR()111void nrf_rng_regw_sideeffects_INTENCLEAR(){ 112 if ( NRF_RNG_regs.INTENCLR ) { 113 RNG_INTEN = false; 114 NRF_RNG_regs.INTENSET = 0; 115 NRF_RNG_regs.INTENCLR = 0; 116 } 117 } 118 119 /** 120 * Handle any register side effect (by inspecting the registers states) 121 * (deprecated) 122 */ nrf_rng_regw_sideeffects()123void nrf_rng_regw_sideeffects(){ 124 125 nrf_rng_regw_sideeffects_TASK_START(); 126 127 nrf_rng_regw_sideeffects_TASK_STOP(); 128 129 nrf_rng_regw_sideeffects_INTENSET(); 130 131 nrf_rng_regw_sideeffects_INTENCLEAR(); 132 } 133 134 /** 135 * Time has come when a new random number is ready 136 */ nrf_rng_timer_triggered()137void nrf_rng_timer_triggered(){ 138 139 NRF_RNG_regs.VALUE = bs_random_uint32(); 140 //A proper random number even if CONFIG is not set to correct the bias 141 142 if ( NRF_RNG_regs.SHORTS & 1 ) { 143 nrf_rng_task_stop(); 144 } else { 145 nrf_rng_schedule_next(false); 146 } 147 148 NRF_RNG_regs.EVENTS_VALRDY = 1; 149 nrf_ppi_event(RNG_EVENTS_VALRDY); 150 if ( RNG_INTEN ){ 151 hw_irq_ctrl_set_irq(RNG_IRQn); 152 //Note: there is no real need to delay the interrupt a delta 153 } 154 } 155