-
Notifications
You must be signed in to change notification settings - Fork 12
/
NHW_RNG.c
151 lines (124 loc) · 3.92 KB
/
NHW_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
/*
* 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=5_1_0_5_18
* https://infocenter.nordicsemi.com/topic/ps_nrf5340/rng.html?cp=4_0_0_6_26
*
* Compatible with 52833 & 5340
*
* Note:
* 1. The delay to produce a value is constant (though bias correction increases time)
*
* 2. The spec says that the delay is unpredictable but it does not provide any indication
* of what kind of random distribution to expect => The model just assumes the value is
* always the average(?) the spec provides
*
* 3. The produced random value is always "good enough".
* The bias correction has no effect on the random value quality
*/
#include <string.h>
#include <stdbool.h>
#include "NHW_config.h"
#include "NHW_peri_types.h"
#include "NHW_common_types.h"
#include "NHW_templates.h"
#include "NHW_RNG.h"
#include "NHW_xPPI.h"
#include "nsi_hw_scheduler.h"
#include "irq_ctrl.h"
#include "bs_rand_main.h"
#include "nsi_tasks.h"
#include "nsi_hws_models_if.h"
NRF_RNG_Type NRF_RNG_regs;
static 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
#if (NHW_HAS_DPPI)
/* Mapping of peripheral instance to DPPI instance */
static uint nhw_RNG_dppi_map[NHW_RNG_TOTAL_INST] = NHW_RNG_DPPI_MAP;
#endif
/**
* Initialize the RNG model
*/
static void nhw_rng_init(void) {
memset(&NRF_RNG_regs, 0, sizeof(NRF_RNG_regs));
RNG_hw_started = false;
RNG_INTEN = false;
Timer_RNG = TIME_NEVER;
}
NSI_TASK(nhw_rng_init, HW_INIT, 100);
static void nhw_rng_schedule_next(bool first_time){
bs_time_t delay = 0;
if (first_time) {
delay = NHW_RNG_tRNG_START;
}
//See Note 1.
if (NRF_RNG_regs.CONFIG & RNG_CONFIG_DERCEN_Msk){ //Bias correction enabled
delay += NHW_RNG_tRNG_BC;
} else {
delay += NHW_RNG_tRNG_RAW;
}
Timer_RNG = nsi_hws_get_time() + delay;
nsi_hws_find_next_event();
}
static void nhw_RNG_eval_interrupt(uint inst) {
static bool rng_int_line[NHW_RNG_TOTAL_INST]; /* Is the RNG currently driving its interrupt line high */
/* Mapping of peripheral instance to {int controller instance, int number} */
static struct nhw_irq_mapping nhw_rng_irq_map[NHW_RNG_TOTAL_INST] = NHW_RNG_INT_MAP;
bool new_int_line = false;
if (NRF_RNG_regs.EVENTS_VALRDY && (RNG_INTEN & RNG_INTENCLR_VALRDY_Msk)){
new_int_line = true;
}
hw_irq_ctrl_toggle_level_irq_line_if(&rng_int_line[inst],
new_int_line,
&nhw_rng_irq_map[inst]);
}
/**
* TASK_START triggered handler
*/
void nhw_RNG_TASK_START(void) {
if (RNG_hw_started) {
return;
}
RNG_hw_started = true;
nhw_rng_schedule_next(true);
}
/**
* TASK_STOP triggered handler
*/
void nhw_RNG_TASK_STOP(void) {
RNG_hw_started = false;
Timer_RNG = TIME_NEVER;
nsi_hws_find_next_event();
}
NHW_SIDEEFFECTS_TASKS_si(RNG, START)
NHW_SIDEEFFECTS_TASKS_si(RNG, STOP)
#if (NHW_HAS_DPPI)
NHW_SIDEEFFECTS_SUBSCRIBE_si(RNG, START)
NHW_SIDEEFFECTS_SUBSCRIBE_si(RNG, STOP)
#endif /* NHW_HAS_DPPI */
NHW_SIDEEFFECTS_INTSET_si(RNG, NRF_RNG_regs., RNG_INTEN)
NHW_SIDEEFFECTS_INTCLR_si(RNG, NRF_RNG_regs., RNG_INTEN)
NHW_SIDEEFFECTS_EVENTS(RNG)
static NHW_SIGNAL_EVENT_si(RNG, VALRDY)
static void nhw_RNG_signal_VALRDY(uint periph_inst) {
if (NRF_RNG_regs.SHORTS & RNG_SHORTS_VALRDY_STOP_Msk) {
nhw_RNG_TASK_STOP();
}
nhw_RNG_signal_EVENTS_VALRDY(periph_inst);
}
/**
* Time has come when a new random number is ready
*/
static void nhw_rng_timer_triggered(void) {
//We generate a proper random number even if CONFIG is not set to correct the bias:
NRF_RNG_regs.VALUE = bs_random_uint32();
nhw_rng_schedule_next(false);
nhw_RNG_signal_VALRDY(0);
}
NSI_HW_EVENT(Timer_RNG, nhw_rng_timer_triggered, 50);