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()32 void 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()42 void nrf_rng_clean_up(){
43 
44 }
45 
nrf_rng_schedule_next(bool first_time)46 static 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()72 void 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()84 void 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()91 void 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()98 void 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()105 void nrf_rng_regw_sideeffects_INTENSET(){
106   if ( NRF_RNG_regs.INTENSET ) {
107     RNG_INTEN = true;
108   }
109 }
110 
nrf_rng_regw_sideeffects_INTENCLEAR()111 void 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()123 void 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()137 void 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