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