-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathNHW_RRAMC.c
402 lines (344 loc) · 11.9 KB
/
NHW_RRAMC.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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* NRF54L
*
* RRAMC - Resistive random access memory controller
* &
* UICR - User information configuration registers
*
* A very simple model, which creates a memory mapped RRAMC and UICR area
* backed by either a file on disk or host RAM.
* The RRAM (and UICR) is memory is not mapped in the same addresses as in
* real HW. Accesses need to be done relative to nhw_RRAMC_get_RRAM_base_address()
* (or NRF_UICR_BASE for the UICR)
*
* Note: The SICR is not yet included
*
* Notes for the RRAM(C):
*
* * Reads and writes are instantaneous.
*
* * READY and READYNEXT are reset to 1 and never cleared.
*
* * Task, events and interrupts are not connected.
*
* * Writes are assumed always enabled and write buffering disabled.
* i.e. CONFIG, READYNEXTTIMEOUT are ignored,
* writes are immediately reflected in the RRAM,
* BUFSTATUS.EMPTY is reset to 1 and never cleared.
*
* * There is no model of the optional immutable boot region write protection
* (all RRAM can be written)
*
* * Reads do not go thru the CACHE
*
* * There is no models of the RRAM and controller power states
* (POWER.* are ignored)
*
* * There is no models of bit errors, or ECC corrections
*
* * ACCESSERRORADDR is not modeled (it is never set after reset)
*
* * Access port protection is not modeled. The UICR can always be erased.
*
*
* Notes for the UICR
* * The APPROTECT, SECUREAPPROTECT, AUXAPPROTECT, ERASEPROTECT
* and BOOTCONF are ignored.
* Their equivalent functionality is not implemented
*
*
* Implementation notes:
* This file includes models for a nrf54L RRAMController, the RRAM itself
* and of an empty UICR.
* And instantiates 1 set for the nrf54L15
* (and initializes them at startup and frees them on exit),
*/
#include <string.h>
#include <stdint.h>
#include "bs_tracing.h"
#include "bs_cmd_line.h"
#include "bs_dynargs.h"
#include "bs_oswrap.h"
#include "nsi_hw_scheduler.h"
#include "nsi_tasks.h"
#include "nsi_hws_models_if.h"
#include "NHW_common_types.h"
#include "NHW_config.h"
#include "NHW_peri_types.h"
#include "NHW_RRAMC.h"
#include "NHW_NVM_backend.h"
NRF_UICR_Type *NRF_UICR_regs_p[NHW_RRAMC_UICR_TOTAL_INST];
NRF_RRAMC_Type *NRF_RRAMC_regs_p[NHW_RRAMC_UICR_TOTAL_INST];
NRF_RRAMC_Type NRF_RRAMC_regs[NHW_RRAMC_UICR_TOTAL_INST] = {0};
struct hw_rramc_st_t {
NRF_RRAMC_Type *RRAMC_regs;
nvm_storage_state_t rram_st;
nvm_storage_state_t uicr_st;
uint rram_start_addr;
uint rram_size;
uint uicr_size;
};
static struct hw_rramc_st_t hw_rramc_st[NHW_RRAMC_UICR_TOTAL_INST];
struct nvmc_args_t {
struct nhw_nvm_st_args_t uicr[NHW_RRAMC_UICR_TOTAL_INST];
struct nhw_nvm_st_args_t rram[NHW_RRAMC_UICR_TOTAL_INST];
} nvmc_args;
/**
* Initialize the RRAM(C) and UICR models
*/
static void nhw_RRAMC_uicr_init(void)
{
uint rram_start_addr[NHW_RRAMC_UICR_TOTAL_INST] = NHW_RRAM_START_ADDR;
uint rram_size[NHW_RRAMC_UICR_TOTAL_INST] = NHW_RRAM_SIZE;
uint uicr_size[NHW_RRAMC_UICR_TOTAL_INST] = NHW_UICR_SIZE;
memset(NRF_RRAMC_regs, 0x00, sizeof(NRF_RRAMC_regs));
for (int inst = 0; inst < NHW_RRAMC_UICR_TOTAL_INST; inst++) {
struct hw_rramc_st_t *this = &hw_rramc_st[inst];
this->RRAMC_regs = &NRF_RRAMC_regs[inst];
NRF_RRAMC_regs_p[inst] = &NRF_RRAMC_regs[inst];
NRF_RRAMC_regs[inst].READY = 1;
NRF_RRAMC_regs[inst].READYNEXT = 1;
NRF_RRAMC_regs[inst].EVENTS_READY = 1;
NRF_RRAMC_regs[inst].EVENTS_READYNEXT = 1;
NRF_RRAMC_regs[inst].ACCESSERRORADDR = 0x00FFFFFF;
NRF_RRAMC_regs[inst].BUFSTATUS.WRITEBUFEMPTY = 1;
NRF_RRAMC_regs[inst].READYNEXTTIMEOUT = 0x00000080;
NRF_RRAMC_regs[inst].POWER.CONFIG = 0x00000100;
this->rram_start_addr = rram_start_addr[inst];
this->rram_size = rram_size[inst];
nhw_nvm_init_storage(&this->rram_st, &nvmc_args.rram[inst],
this->rram_size, "RRAM");
this->uicr_size = uicr_size[inst];
nhw_nvm_init_storage(&this->uicr_st, &nvmc_args.uicr[inst],
this->uicr_size, "UICR");
NRF_UICR_regs_p[inst] = (NRF_UICR_Type *)this->uicr_st.storage;
}
}
NSI_TASK(nhw_RRAMC_uicr_init, HW_INIT, 100);
/**
* Clean up the RRAM(C) and UICR model before program exit
*/
static void nhw_RRAMC_uicr_clean_up(void) {
for (int inst = 0; inst < NHW_RRAMC_UICR_TOTAL_INST; inst++) {
struct hw_rramc_st_t *this = &hw_rramc_st[inst];
nhw_nvm_clear_storage(&this->rram_st);
nhw_nvm_clear_storage(&this->uicr_st);
}
}
NSI_TASK(nhw_RRAMC_uicr_clean_up, ON_EXIT_PRE, 100);
/*
* Do the actual erase of the UICR area
*/
static void nhw_RRAMC_erase_uicr(uint inst){
struct hw_rramc_st_t *this = &hw_rramc_st[inst];
(void)memset(this->uicr_st.storage, 0xFF, this->uicr_st.size);
}
/*
* Do the actual erase of all RRAM and UICR areas
*/
static void nhw_RRAMC_erase_all(uint inst){
struct hw_rramc_st_t *this = &hw_rramc_st[inst];
nhw_RRAMC_erase_uicr(inst);
(void)memset(this->rram_st.storage, 0xFF, this->rram_st.size);
}
void nhw_RRAMC_regw_sideeffects_ERASEALL(uint inst) {
NRF_RRAMC_regs[inst].ERASE.ERASEALL &= 1;
if (NRF_RRAMC_regs[inst].ERASE.ERASEALL) {
NRF_RRAMC_regs[inst].ERASE.ERASEALL = 0;
nhw_RRAMC_erase_all(inst);
}
}
#define OUT_OF_RRAM_ERROR(addr) \
bs_trace_error_time_line("%s: Attempted access outside of RRAM and UICR areas (0x%X)\n",\
__func__, address)
/*
* Check if an address is in range of any RRAM or UICR
* and if so, set the inst, storage and offset accordingly.
*
* Where address is an address in either a "hard" RRAM address
* (meaning in the 0x00..00 range for nrf52, or also in the 0x010..00 range for nrf53)
* Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
* NRF_UICR_*_BASE)
*
* If the address is not in range, the function does not return, but produces an error
*/
static void nhw_RRAMC_address_location(uint32_t address, uint *inst, nvm_storage_state_t **storage, int *offset){
for (int i = 0; i < NHW_RRAMC_UICR_TOTAL_INST; i ++) {
*inst = i;
if ((address >= hw_rramc_st[i].rram_start_addr) \
&& (address < hw_rramc_st[i].rram_start_addr + hw_rramc_st[i].rram_size)) {
*storage = &hw_rramc_st[i].rram_st;
*offset = address - hw_rramc_st[i].rram_start_addr;
return;
}
if ((address >= (uint32_t)hw_rramc_st[i].uicr_st.storage) \
&& (address < (uint32_t)hw_rramc_st[i].uicr_st.storage + hw_rramc_st[i].uicr_size)) {
*storage = &hw_rramc_st[i].uicr_st;
*offset = address - (uint32_t)hw_rramc_st[i].uicr_st.storage;
return;
}
}
OUT_OF_RRAM_ERROR(address);
}
/*
* Write to a RRAM array (RRAM or UICR)
*
* Where address is an address in either a "hard" RRAM address
* (meaning in the 0x00..00 range)
* Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
* NRF_UICR_*_BASE)
*/
void nhw_RRAMC_write_word(uint32_t address, uint32_t value){
if ((address & 3) != 0){
bs_trace_error_line_time("%s: write to non word aligned address %u, "
"this would have hard-faulted in real HW\n",
__func__, address);
}
int offset;
nvm_storage_state_t *backend;
uint inst;
nhw_RRAMC_address_location(address, &inst, &backend, &offset);
*(uint32_t*)&backend->storage[offset] = value;
}
/*
* Write to a RRAM array (RRAM or UICR)
*
* Where address is an address in either a "hard" RRAM address
* (meaning in the 0x00..00 range)
* Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
* NRF_UICR_*_BASE)
*/
void nhw_RRAMC_write_halfword(uint32_t address, uint16_t value){
if ((address & 1) != 0){
bs_trace_error_line_time("%s: write to non half-word aligned address %u, "
"this would have hard-faulted in real HW\n",
__func__, address);
}
int offset;
nvm_storage_state_t *backend;
uint inst;
nhw_RRAMC_address_location(address, &inst, &backend, &offset);
*(uint16_t*)&backend->storage[offset] = value;
}
/*
* Write to a RRAM array (RRAM or UICR)
*
* Where address is an address in either a "hard" RRAM address
* (meaning in the 0x00..00 range)
* Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
* NRF_UICR_*_BASE)
*/
void nhw_RRAMC_write_byte(uint32_t address, uint8_t value){
int offset;
nvm_storage_state_t *backend;
uint inst;
nhw_RRAMC_address_location(address, &inst, &backend, &offset);
*(uint8_t*)&backend->storage[offset] = value;
}
/**
* Read from the RRAM array (RRAM or UICR)
*
* Where address is an address in either a "hard" RRAM address
* (meaning in the 0x00..00 range)
* Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
* NRF_UICR_*_BASE)
*
* This operation is instantaneous in simulation.
*/
uint32_t nhw_RRAMC_read_word(uint32_t address) {
int offset;
nvm_storage_state_t *backend;
uint inst;
nhw_RRAMC_address_location(address, &inst, &backend, &offset);
return *(uint32_t*)&backend->storage[offset];
}
uint16_t nhw_RRAMC_read_halfword(uint32_t address) {
int offset;
nvm_storage_state_t *backend;
uint inst;
nhw_RRAMC_address_location(address, &inst, &backend, &offset);
return *(uint16_t*)&backend->storage[offset];
}
uint8_t nhw_RRAMC_read_byte(uint32_t address) {
int offset;
nvm_storage_state_t *backend;
uint inst;
nhw_RRAMC_address_location(address, &inst, &backend, &offset);
return *(uint8_t*)&backend->storage[offset];
}
/**
* memcpy into RRAM/UICR array from <address> <size> bytes.
*
* Where address is an address in either a "hard" RRAM address
* (meaning in the 0x00..00 range)
* Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
* NRF_UICR_*_BASE)
*
* This is a convenience function in the model.
* It can be used from DMA controller models or the like.
*
* This operation is instantaneous in simulation.
* In real HW it is as "fast" as all those AHB accesses
* can be dispatched by the interconnect and handled by
* the RRAMC peripheral
*/
void nhw_RRAMC_write_buffer(uint32_t address, void *src, size_t size) {
int offset;
nvm_storage_state_t *backend;
uint inst;
nhw_RRAMC_address_location(address, &inst, &backend, &offset);
if (offset + size >= backend->size) {
OUT_OF_RRAM_ERROR(address + size);
}
(void)memcpy(&backend->storage[offset], src, size);
}
/**
* memcpy from the RRAM/UICR array from <address> <size> bytes.
*
* Where address is an address in either a "hard" RRAM address
* (meaning in the 0x00..00 range)
* Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
* NRF_UICR_*_BASE)
*
* This is a convenience function in the model.
* It can be used from DMA controller models or the like.
*
* This operation is instantaneous in simulation.
* In real HW it is as "fast" as all those AHB accesses
* can be dispatched by the interconnect and handled by
* the RRAMC peripheral
*/
void nhw_RRAMC_read_buffer(void *dest, uint32_t address, size_t size) {
int offset;
nvm_storage_state_t *backend;
uint inst;
nhw_RRAMC_address_location(address, &inst, &backend, &offset);
if (offset + size >= backend->size) {
OUT_OF_RRAM_ERROR(address + size);
}
(void)memcpy(dest, &backend->storage[offset], size);
}
void* nhw_RRAMC_get_RRAM_base_address(uint inst) {
return (void*)hw_rramc_st[inst].rram_st.storage;
}
NVM_BACKEND_PARAMS_CALLBACS(uicr, uicr[0])
NVM_BACKEND_PARAMS_CALLBACS(rram, rram[0])
static void RRAMC_register_cmd_args(void){
for (int i = 0; i < NHW_RRAMC_UICR_TOTAL_INST; i++) {
nvmc_args.uicr[i].in_ram = true;
nvmc_args.rram[i].in_ram = true;
}
static bs_args_struct_t args_struct_toadd[] = {
NVM_BACKEND_PARAMS(uicr, uicr[0], UICR),
NVM_BACKEND_PARAMS(rram, rram[0], RRAM),
NVM_BACKEND_PARAMS_ALIAS(flash, rram, rram[0], RRAM, "(Alias for rram_* paramaters) "),
ARG_TABLE_ENDMARKER
};
bs_add_extra_dynargs(args_struct_toadd);
}
NSI_TASK(RRAMC_register_cmd_args, PRE_BOOT_1, 100);