1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * NVMC - Non-volatile memory controller
9 * https://infocenter.nordicsemi.com/topic/ps_nrf52833/nvmc.html?cp=5_1_0_3_2
10 * https://infocenter.nordicsemi.com/topic/ps_nrf5340/nvmc.html?cp=4_0_0_6_20
11 * &
12 * UICR - User information configuration registers
13 * https://infocenter.nordicsemi.com/topic/ps_nrf52833/uicr.html?cp=5_1_0_3_4
14 * https://infocenter.nordicsemi.com/topic/ps_nrf5340/chapters/uicr/doc/uicr.html?cp=4_0_0_4_3_2
15 * https://infocenter.nordicsemi.com/topic/ps_nrf5340/chapters/uicr.network/doc/uicr.network.html?cp=4_0_0_5_3_1
16 *
17 * Notes for the NVMC:
18 * * The CPU is not stalled while doing flash operations, "while executing from flash"
19 * as we do not know what code would have been in flash or RAM, code is just
20 * assumed only in RAM for simplicity.
21 *
22 * * The model will not prevent you from writing too many times (more then n_write)
23 * the same address between erases
24 *
25 * * For nrf52s, the spec does not specify how much earlier READYNEXT is,
26 * and for nrf53 it is not mentioned in the documentation,
27 * so this model just sets it when the previous operation is done (together with READY)
28 *
29 * * The partial erase timer is fully accurate. Meaning, a partial erase always
30 * takes exactly ERASEPAGEPARTIALCFG ms.
31 *
32 * * The instruction cache does not have any kind of model.
33 * The ICACHECNF, IHIT, IMISS registers are not connected to anything,
34 * writes to them are ignored, reads read 0 (or whatever was written to them last)
35 *
36 * * Access port protection is not modeled. The UICR can always be erased.
37 *
38 * * There is no modeling of the power failure protection
39 *
40 * * (nRF53) CONFIGNS and CONFIG have the same abilities (including enabling a partial erase)
41 *
42 * * (nRF53) There is no handling or differentiation between secure and non secure areas
43 *
44 * * (nRF53) All registers are accessible from all SW (there is no differentiation
45 * between secure and not secure registers)
46 *
47 * * (nRF53) CONFIGNS is ignored so far. As we lack an SPU model,
48 * all Flash is assumed to be "secure" from the point of view that
49 * its access mode is only controller by CONFIG.
50 *
51 * Notes for the UICR
52 * * The PSELRESET[], APPROTECT, NFCPINS, DEBUGCTRL & REGOUT0 registers are ignored
53 * Their equivalent functionality is not implemented
54 *
55 * Possible future improvements:
56 * * Provide use/wear statistics per page and address.
57 * * Allow accumulating those statistics between runs (save stats to file)
58 * * Warn users if an address is written more than n_write between erases
59 *
60 *
61 * Implementation notes:
62 * This file includes models for a nrf52 and 53 flash and NVMController and of an empty
63 * UICR.
64 * And instantiates 1 set for the nrf52 and 2 sets (one per MCU) for the nrf53,
65 * (and initializes them at startup and frees them on exit),
66 * Note that this is partly described in the configuration (NHW_config.h), and partly
67 * "hardcoded" here for the target type (around command line parameters)
68 */
69
70 #include <string.h>
71 #include <stdint.h>
72 #include "bs_tracing.h"
73 #include "bs_cmd_line.h"
74 #include "bs_dynargs.h"
75 #include "bs_oswrap.h"
76 #include "nsi_hw_scheduler.h"
77 #include "nsi_tasks.h"
78 #include "nsi_hws_models_if.h"
79 #include "NHW_common_types.h"
80 #include "NHW_config.h"
81 #include "NHW_peri_types.h"
82 #include "NHW_NVMC.h"
83 #include "NHW_NVM_backend.h"
84
85 NRF_UICR_Type *NRF_UICR_regs_p[NHW_NVMC_UICR_TOTAL_INST];
86 NRF_NVMC_Type *NRF_NVMC_regs_p[NHW_NVMC_UICR_TOTAL_INST];
87 NRF_NVMC_Type NRF_NVMC_regs[NHW_NVMC_UICR_TOTAL_INST] = {0};
88 static bs_time_t Timer_NVMC = TIME_NEVER; //Time when the next flash operation will be completed
89
90 enum flash_op_t {flash_idle = 0, flash_write, flash_erase, flash_erase_partial, flash_erase_uicr, flash_erase_all};
91
92 struct hw_nvmc_st_t {
93 bs_time_t timer;
94 NRF_NVMC_Type *NVMC_regs;
95 nvm_storage_state_t flash_st;
96 nvm_storage_state_t uicr_st;
97 enum flash_op_t flash_op;
98 uint32_t erase_page;
99 bs_time_t *time_under_erase; //[flash_n_pages];
100 bool *page_erased; //[flash_n_pages];
101
102 uint flash_start_addr;
103 uint flash_size;
104 uint flash_page_size;
105 uint flash_n_pages;
106 uint uicr_size;
107 };
108
109 static struct hw_nvmc_st_t hw_nvmc_st[NHW_NVMC_UICR_TOTAL_INST];
110
111 struct nvmc_args_t {
112 struct nhw_nvm_st_args_t uicr[NHW_NVMC_UICR_TOTAL_INST];
113 struct nhw_nvm_st_args_t flash[NHW_NVMC_UICR_TOTAL_INST];
114 bool flash_erase_warnings;
115 } nvmc_args;
116
nhw_nvmc_find_next_event(void)117 static void nhw_nvmc_find_next_event(void) {
118 Timer_NVMC = hw_nvmc_st[0].timer;
119
120 for (int i = 1; i < NHW_NVMC_UICR_TOTAL_INST; i++) {
121 if (hw_nvmc_st[i].timer < Timer_NVMC) {
122 Timer_NVMC = hw_nvmc_st[i].timer;
123 }
124 }
125 nsi_hws_find_next_event();
126 }
127
128 /**
129 * Initialize the NVMC and UICR models
130 */
nhw_nvmc_uicr_init(void)131 static void nhw_nvmc_uicr_init(void)
132 {
133 uint flash_start_addr[NHW_NVMC_UICR_TOTAL_INST] = NHW_FLASH_START_ADDR;
134 uint flash_page_sizes[NHW_NVMC_UICR_TOTAL_INST] = NHW_FLASH_PAGESIZE;
135 uint flash_n_pages[NHW_NVMC_UICR_TOTAL_INST] = NHW_FLASH_N_PAGES;
136 uint uicr_size[NHW_NVMC_UICR_TOTAL_INST] = NHW_UICR_SIZE;
137
138 memset(NRF_NVMC_regs, 0x00, sizeof(NRF_NVMC_regs));
139
140 for (int inst = 0; inst < NHW_NVMC_UICR_TOTAL_INST; inst++) {
141 struct hw_nvmc_st_t *this = &hw_nvmc_st[inst];
142 this->NVMC_regs = &NRF_NVMC_regs[inst];
143 NRF_NVMC_regs_p[inst] = &NRF_NVMC_regs[inst];
144
145 NRF_NVMC_regs[inst].READY = 1;
146 NRF_NVMC_regs[inst].READYNEXT = 1;
147 NRF_NVMC_regs[inst].ERASEPAGEPARTIALCFG = 0x0000000A;
148
149 this->flash_op = flash_idle;
150 this->timer = TIME_NEVER;
151
152 this->flash_start_addr = flash_start_addr[inst];
153 this->flash_n_pages = flash_n_pages[inst];
154 this->flash_page_size = flash_page_sizes[inst];
155 this->flash_size = this->flash_n_pages * this->flash_page_size;
156
157 nhw_nvm_init_storage(&this->flash_st, &nvmc_args.flash[inst],
158 this->flash_size, "flash");
159
160 this->uicr_size = uicr_size[inst];
161 nhw_nvm_init_storage(&this->uicr_st, &nvmc_args.uicr[inst],
162 this->uicr_size, "UICR");
163
164 NRF_UICR_regs_p[inst] = (NRF_UICR_Type *)this->uicr_st.storage;
165
166 this->time_under_erase = (bs_time_t *)bs_calloc(this->flash_n_pages, sizeof(bs_time_t));
167 this->page_erased = (bool *)bs_malloc(this->flash_n_pages * sizeof(bool));
168 memset(this->page_erased, true, this->flash_n_pages * sizeof(bool));
169
170 if (nvmc_args.flash_erase_warnings) {
171 for (int i = 0; i < this->flash_size; i+=4) {
172 if (*(uint32_t*)(this->flash_st.storage + i) != 0) {
173 int page_size = this->flash_page_size;
174 this->page_erased[i/page_size] = false;
175 //Jump to next page start:
176 i = (i + page_size)/page_size*page_size;
177 }
178 }
179 }
180 }
181 nhw_nvmc_find_next_event();
182 }
183
184 NSI_TASK(nhw_nvmc_uicr_init, HW_INIT, 100);
185
186 /**
187 * Clean up the NVMC and UICR model before program exit
188 */
nhw_nvmc_uicr_clean_up(void)189 static void nhw_nvmc_uicr_clean_up(void) {
190 for (int inst = 0; inst < NHW_NVMC_UICR_TOTAL_INST; inst++) {
191 struct hw_nvmc_st_t *this = &hw_nvmc_st[inst];
192 nhw_nvm_clear_storage(&this->flash_st);
193 nhw_nvm_clear_storage(&this->uicr_st);
194
195 free(this->time_under_erase);
196 this->time_under_erase = NULL;
197
198 free(this->page_erased);
199 this->page_erased = NULL;
200 }
201 }
202
203 NSI_TASK(nhw_nvmc_uicr_clean_up, ON_EXIT_PRE, 100);
204
205 /*
206 * Complete the actual erase of a flash page
207 */
nhw_nvmc_complete_erase(uint inst)208 static void nhw_nvmc_complete_erase(uint inst) {
209 struct hw_nvmc_st_t *this = &hw_nvmc_st[inst];
210 uint erase_page = this->erase_page;
211 uint base_address = erase_page*this->flash_page_size;
212
213 memset(&this->flash_st.storage[base_address], 0xFF, this->flash_page_size);
214
215 this->time_under_erase[erase_page] = 0;
216 this->page_erased[erase_page] = true;
217 }
218
219 /*
220 * End of a partial erase (the full erase may not be yet completed)
221 */
nhw_nvmc_complete_erase_partial(uint inst)222 static void nhw_nvmc_complete_erase_partial(uint inst){
223 struct hw_nvmc_st_t *this = &hw_nvmc_st[inst];
224 if (this->time_under_erase[this->erase_page] >= NHW_NVMC_FLASH_T_ERASEPAGE) {
225 nhw_nvmc_complete_erase(inst);
226 }
227 }
228
229 /*
230 * Complete the actual erase of the UICR page
231 */
nhw_nvmc_complete_erase_uicr(uint inst)232 static void nhw_nvmc_complete_erase_uicr(uint inst){
233 struct hw_nvmc_st_t *this = &hw_nvmc_st[inst];
234 (void)memset(this->uicr_st.storage, 0xFF, this->uicr_st.size);
235 }
236
237 /*
238 * Complete the actual erase of all flash and UICR pages
239 */
nhw_nvmc_complete_erase_all(uint inst)240 static void nhw_nvmc_complete_erase_all(uint inst){
241 struct hw_nvmc_st_t *this = &hw_nvmc_st[inst];
242 nhw_nvmc_complete_erase_uicr(inst);
243 (void)memset(this->flash_st.storage, 0xFF, this->flash_st.size);
244
245 memset(this->time_under_erase, 0, this->flash_n_pages*sizeof(bs_time_t));
246 memset(this->page_erased, true, this->flash_n_pages*sizeof(bool));
247 }
248
249 /**
250 * Time has come when the programmed flash operation has finished
251 */
nhw_nvmc_timer_triggered(void)252 static void nhw_nvmc_timer_triggered(void){
253
254 for (int inst = 0; inst < NHW_NVMC_UICR_TOTAL_INST; inst++) {
255 struct hw_nvmc_st_t *this = &hw_nvmc_st[inst];
256 if (this->timer != Timer_NVMC) {
257 continue;
258 }
259 switch (this->flash_op) {
260 case flash_write:
261 //Nothing left to be done
262 break;
263 case flash_erase:
264 nhw_nvmc_complete_erase(inst);
265 break;
266 case flash_erase_partial:
267 nhw_nvmc_complete_erase_partial(inst);
268 break;
269 case flash_erase_uicr:
270 nhw_nvmc_complete_erase_uicr(inst);
271 break;
272 case flash_erase_all:
273 nhw_nvmc_complete_erase_all(inst);
274 break;
275 default:
276 bs_trace_error_time_line("%s: timer triggered with no pending "
277 "operation (%i)\n", __func__, this->flash_op);
278 break;
279 }
280
281 this->flash_op = flash_idle;
282
283 NRF_NVMC_regs[inst].READY = 1;
284 NRF_NVMC_regs[inst].READYNEXT = 1;
285 this->timer = TIME_NEVER;
286 }
287
288 nhw_nvmc_find_next_event();
289 }
290
291 NSI_HW_EVENT(Timer_NVMC, nhw_nvmc_timer_triggered, 50);
292
nhw_nvmc_time_to_ready(uint inst)293 bs_time_t nhw_nvmc_time_to_ready(uint inst) {
294 if (NRF_NVMC_regs[inst].READY) {
295 return 0;
296 } else {
297 return hw_nvmc_st[inst].timer - nsi_hws_get_time();
298 }
299 }
300
301 #define ERASE_ENABLED_CHECK(i, x) \
302 if ((NRF_NVMC_regs[i].CONFIG & NVMC_CONFIG_WEN_Msk) != NVMC_CONFIG_WEN_Een) { \
303 bs_trace_warning_line_time("%s: %s while erase is not enabled in " \
304 "NVMC[%i].CONFIG (%u), it will be ignored\n", \
305 __func__, x, i, NRF_NVMC_regs[i].CONFIG); \
306 return; \
307 }
308
309 #define ERASEPARTIAL_ENABLED_CHECK(i, x) \
310 if ((NRF_NVMC_regs[i].CONFIG & NVMC_CONFIG_WEN_Msk) != NVMC_CONFIG_WEN_PEen) { \
311 bs_trace_warning_line_time("%s: %s while partial erase is not enabled " \
312 "in NVMC[%i].CONFIG (%u), it will be ignored\n", \
313 __func__, x, i, NRF_NVMC_regs[i].CONFIG); \
314 return; \
315 }
316
317 #define BUSY_CHECK(i, x) \
318 if ( hw_nvmc_st[i].flash_op != flash_idle) { \
319 bs_trace_warning_line_time("%s: %s while the flash(%i) was already" \
320 " busy (%i), it will be ignored\n", \
321 __func__, x, i, hw_nvmc_st[inst].flash_op); \
322 return; \
323 }
324
325 #define CHECK_ERASE_ADDRESS(i, x) \
326 if ((x < hw_nvmc_st[i].flash_start_addr) \
327 || (x >= hw_nvmc_st[i].flash_start_addr + hw_nvmc_st[i].flash_size)) { \
328 bs_trace_error_time_line("%s : Attempted to erase an address (%u) " \
329 "outside of the flash (%i) area\n", __func__, x, i); \
330 } \
331 if (x % hw_nvmc_st[i].flash_page_size != 0) { \
332 bs_trace_warning_time_line("%s : Address (%u) is not at the start of the page " \
333 "just the page it contains will be erased\n", __func__, x); \
334 }
335
336 #define CHECK_PARTIAL_ERASE(i, addr, type) \
337 if (nvmc_args.flash_erase_warnings && hw_nvmc_st[i].time_under_erase[addr/hw_nvmc_st[i].flash_page_size] > 0){ \
338 bs_trace_warning_line_time("%s: %s in partially erased address (%i, %u, "\
339 "time_under_erase: %"PRItime" < %"PRItime")\n", \
340 __func__, type, i, addr, \
341 hw_nvmc_st[i].time_under_erase[addr/hw_nvmc_st[i].flash_page_size], \
342 NHW_NVMC_FLASH_T_ERASEPAGE); \
343 }
344
345 #define OUT_OF_FLASH_ERROR(addr) \
346 bs_trace_error_time_line("%s: Attempted access outside of flash and UICR areas (0x%X)\n",\
347 __func__, address)
348
nhw_nvmc_erase_page(uint inst,uint32_t address)349 void nhw_nvmc_erase_page(uint inst, uint32_t address){
350 ERASE_ENABLED_CHECK(inst, "ERASEPAGE");
351 BUSY_CHECK(inst, "ERASEPAGE");
352 CHECK_ERASE_ADDRESS(inst, address);
353
354 struct hw_nvmc_st_t *this = &hw_nvmc_st[inst];
355
356 this->flash_op = flash_erase;
357 NRF_NVMC_regs[inst].READY = 0;
358 NRF_NVMC_regs[inst].READYNEXT = 0;
359 this->erase_page = (address - this->flash_start_addr) / this->flash_page_size;
360 this->timer = nsi_hws_get_time() + NHW_NVMC_FLASH_T_ERASEPAGE;
361 nhw_nvmc_find_next_event();
362 }
363
364 #if (NHW_NVMC_HAS_ERASEREGS)
365 /* Note ERASEPCR1 is an alias to ERASEPAGE (same register) */
nhw_nvmc_regw_sideeffects_ERASEPAGE(uint inst)366 void nhw_nvmc_regw_sideeffects_ERASEPAGE(uint inst) {
367 nhw_nvmc_erase_page(inst, NRF_NVMC_regs[inst].ERASEPAGE);
368 }
369
nhw_nvmc_regw_sideeffects_ERASEPCR0(uint inst)370 void nhw_nvmc_regw_sideeffects_ERASEPCR0(uint inst) {
371 nhw_nvmc_erase_page(inst, NRF_NVMC_regs[inst].ERASEPCR0);
372 }
373
nhw_nvmc_regw_sideeffects_ERASEUICR(uint inst)374 void nhw_nvmc_regw_sideeffects_ERASEUICR(uint inst) {
375 NRF_NVMC_regs[inst].ERASEUICR &= 1;
376
377 if (NRF_NVMC_regs[inst].ERASEUICR) {
378 NRF_NVMC_regs[inst].ERASEUICR = 0;
379 ERASE_ENABLED_CHECK(inst, "ERASEUICR");
380 BUSY_CHECK(inst, "ERASEUICR");
381 struct hw_nvmc_st_t *this = &hw_nvmc_st[inst];
382
383 this->flash_op = flash_erase_uicr;
384 NRF_NVMC_regs[inst].READY = 0;
385 NRF_NVMC_regs[inst].READYNEXT = 0;
386 this->timer = nsi_hws_get_time() + NHW_NVMC_FLASH_T_ERASEPAGE;
387 nhw_nvmc_find_next_event();
388 }
389 }
390 #endif
391
nhw_nvmc_regw_sideeffects_ERASEALL(uint inst)392 void nhw_nvmc_regw_sideeffects_ERASEALL(uint inst) {
393 NRF_NVMC_regs[inst].ERASEALL &= 1;
394
395 if (NRF_NVMC_regs[inst].ERASEALL) {
396 NRF_NVMC_regs[inst].ERASEALL = 0;
397 ERASE_ENABLED_CHECK(inst, "ERASEALL");
398 BUSY_CHECK(inst, "ERASEALL");
399 struct hw_nvmc_st_t *this = &hw_nvmc_st[inst];
400
401 this->flash_op = flash_erase_all;
402 NRF_NVMC_regs[inst].READY = 0;
403 NRF_NVMC_regs[inst].READYNEXT = 0;
404 this->timer = nsi_hws_get_time() + NHW_NVMC_FLASH_T_ERASEALL;
405 nhw_nvmc_find_next_event();
406 }
407 }
408
nhw_nvmc_erase_page_partial(uint inst,uint32_t address)409 void nhw_nvmc_erase_page_partial(uint inst, uint32_t address) {
410 #if defined(NVMC_CONFIG_WEN_PEen)
411 ERASEPARTIAL_ENABLED_CHECK(inst, "ERASEPARTIAL");
412 #else
413 ERASE_ENABLED_CHECK(inst, "ERASEPARTIAL");
414 #endif
415 BUSY_CHECK(inst, "ERASEPARTIAL");
416 CHECK_ERASE_ADDRESS(inst, address);
417 struct hw_nvmc_st_t *this = &hw_nvmc_st[inst];
418
419 this->erase_page = (address - this->flash_start_addr)/this->flash_page_size;
420
421 this->flash_op = flash_erase_partial;
422 NRF_NVMC_regs[inst].READY = 0;
423 NRF_NVMC_regs[inst].READYNEXT = 0;
424
425 bs_time_t duration = NHW_NVMC_FLASH_PARTIAL_ERASE_FACTOR * NRF_NVMC_regs[inst].ERASEPAGEPARTIALCFG * 1000;
426
427 if (this->page_erased[this->erase_page] == false) {
428 this->time_under_erase[this->erase_page] += duration;
429 }
430 this->timer = nsi_hws_get_time() + duration;
431 nhw_nvmc_find_next_event();
432 }
433
434 #if (NHW_NVMC_HAS_ERASEREGS)
nhw_nvmc_regw_sideeffects_ERASEPAGEPARTIAL(uint inst)435 void nhw_nvmc_regw_sideeffects_ERASEPAGEPARTIAL(uint inst) {
436 nhw_nvmc_erase_page_partial(inst, NRF_NVMC_regs[inst].ERASEPAGEPARTIAL);
437 }
438 #endif
439
440 /*
441 * Check if an address is in range of any flash or UICR
442 * and if so, set the inst, storage and offset accordingly.
443 *
444 * Where address is an address in either a "hard" flash address
445 * (meaning in the 0x00..00 range for nrf52, or also in the 0x010..00 range for nrf53)
446 * Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
447 * NRF_UICR_BASE/NRF_UICR_S/NS_BASE)
448 *
449 * If the address is not in range, the function does not return, but produces an error
450 */
nhw_nvmc_address_location(uint32_t address,uint * inst,nvm_storage_state_t ** storage,int * offset)451 static void nhw_nvmc_address_location(uint32_t address, uint *inst, nvm_storage_state_t **storage, int *offset){
452 for (int i = 0; i < NHW_NVMC_UICR_TOTAL_INST; i ++) {
453 *inst = i;
454 if ((address >= hw_nvmc_st[i].flash_start_addr) \
455 && (address < hw_nvmc_st[i].flash_start_addr + hw_nvmc_st[i].flash_size)) {
456 *storage = &hw_nvmc_st[i].flash_st;
457 *offset = address - hw_nvmc_st[i].flash_start_addr;
458 return;
459 }
460 if ((address >= (uint32_t)hw_nvmc_st[i].uicr_st.storage) \
461 && (address < (uint32_t)hw_nvmc_st[i].uicr_st.storage + hw_nvmc_st[i].uicr_size)) {
462 *storage = &hw_nvmc_st[i].uicr_st;
463 *offset = address - (uint32_t)hw_nvmc_st[i].uicr_st.storage;
464 return;
465 }
466 }
467 OUT_OF_FLASH_ERROR(address);
468 }
469
470 /*
471 * Write to a flash array (flash or uicr)
472 *
473 * Where address is an address in either a "hard" flash address
474 * (meaning in the 0x00..00 range for nrf52, or also in the 0x010..00 range for nrf53)
475 * Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
476 * NRF_UICR_BASE/NRF_UICR_S/NS_BASE)
477 */
nhw_nmvc_write_word(uint32_t address,uint32_t value)478 void nhw_nmvc_write_word(uint32_t address, uint32_t value){
479 if ((address & 3) != 0){
480 bs_trace_error_line_time("%s: write to non word aligned address %u, "
481 "this would have hard-faulted in real HW\n",
482 __func__, address);
483 }
484
485 int offset;
486 nvm_storage_state_t *backend;
487 uint inst;
488
489 nhw_nvmc_address_location(address, &inst, &backend, &offset);
490
491 struct hw_nvmc_st_t *this = &hw_nvmc_st[inst];
492
493 BUSY_CHECK(inst, "write");
494
495 #if (NHW_NVMC_HAS_ERASEREGS == 0)
496 if (backend == &this->flash_st) {
497 if ((NRF_NVMC_regs[inst].CONFIG & NVMC_CONFIG_WEN_Msk) == NVMC_CONFIG_WEN_Een) {
498 if ((value == 0xFFFFFFFF) && (offset % this->flash_page_size == 0)) {
499 nhw_nvmc_erase_page(inst, address);
500 return;
501 }
502 }
503 if ((NRF_NVMC_regs[inst].CONFIG & NVMC_CONFIG_WEN_Msk) == NVMC_CONFIG_WEN_PEen) {
504 if ((value == 0xFFFFFFFF) && (offset % this->flash_page_size == 0)) {
505 nhw_nvmc_erase_page_partial(inst, address);
506 return;
507 }
508 }
509 }
510 #endif
511
512 if ((NRF_NVMC_regs[inst].CONFIG & NVMC_CONFIG_WEN_Msk) != NVMC_CONFIG_WEN_Wen) {
513 bs_trace_warning_line_time("%s: write while write is not enabled in "
514 "CONFIG (%u), it will be ignored\n",
515 __func__, NRF_NVMC_regs[inst].CONFIG);
516 return;
517 }
518
519 if (backend == &this->flash_st) {
520 CHECK_PARTIAL_ERASE(inst, offset, "write");
521 this->page_erased[offset/this->flash_page_size] = false;
522 }
523
524 /*
525 * Writing to flash clears to 0 bits which were one, but does not
526 * set to 1 bits which are 0.
527 */
528 *(uint32_t*)&backend->storage[offset] &= value;
529
530 this->flash_op = flash_write;
531 NRF_NVMC_regs[inst].READY = 0;
532 NRF_NVMC_regs[inst].READYNEXT = 0;
533
534 this->timer = nsi_hws_get_time() + NHW_NVMC_FLASH_T_WRITE;
535 nhw_nvmc_find_next_event();
536 }
537
538 /**
539 * Read from the flash array (flash or uicr)
540 *
541 * Where address is an address in either a "hard" flash address
542 * (meaning in the 0x00..00 range for nrf52, or also in the 0x010..00 range for nrf53)
543 * Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
544 * NRF_UICR_BASE/NRF_UICR_S/NS_BASE)
545 *
546 * This models the embedded CPU accessing the flash array for read
547 *
548 * This operation is instantaneous in simulation.
549 * In real HW it is "fast"
550 */
nhw_nmvc_read_word(uint32_t address)551 uint32_t nhw_nmvc_read_word(uint32_t address) {
552 int offset;
553 nvm_storage_state_t *backend;
554 uint inst;
555
556 nhw_nvmc_address_location(address, &inst, &backend, &offset);
557
558 struct hw_nvmc_st_t *this = &hw_nvmc_st[inst];
559
560 if (backend == &this->flash_st) {
561 CHECK_PARTIAL_ERASE(inst, offset, "read");
562 }
563
564 return *(uint32_t*)&backend->storage[offset];
565 }
566
nhw_nmvc_read_halfword(uint32_t address)567 uint16_t nhw_nmvc_read_halfword(uint32_t address) {
568 int offset;
569 nvm_storage_state_t *backend;
570 uint inst;
571
572 nhw_nvmc_address_location(address, &inst, &backend, &offset);
573
574 struct hw_nvmc_st_t *this = &hw_nvmc_st[inst];
575
576 if (backend == &this->flash_st) {
577 CHECK_PARTIAL_ERASE(inst, offset, "read");
578 }
579
580 return *(uint16_t*)&backend->storage[offset];
581 }
582
nhw_nmvc_read_byte(uint32_t address)583 uint8_t nhw_nmvc_read_byte(uint32_t address) {
584 int offset;
585 nvm_storage_state_t *backend;
586 uint inst;
587
588 nhw_nvmc_address_location(address, &inst, &backend, &offset);
589
590 struct hw_nvmc_st_t *this = &hw_nvmc_st[inst];
591
592 if (backend == &this->flash_st) {
593 CHECK_PARTIAL_ERASE(inst, offset, "read");
594 }
595
596 return *(uint8_t*)&backend->storage[offset];
597 }
598
599 /**
600 * memcpy from the flash/uicr array from <address> <size> bytes.
601 *
602 * Where address is an address in either a "hard" flash address
603 * (meaning in the 0x00..00 range for nrf52, or also in the 0x010..00 range for nrf53)
604 * Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
605 * NRF_UICR_BASE/NRF_UICR_S/NS_BASE)
606 *
607 * This is a convenience function in the model.
608 * It can be used from DMA controller models or the like.
609 *
610 * This operation is instantaneous in simulation.
611 * In real HW it is as "fast" as all those AHB accesses
612 * can be dispatched by the interconnect and handled by
613 * the NVMC peripheral
614 */
nhw_nmvc_read_buffer(void * dest,uint32_t address,size_t size)615 void nhw_nmvc_read_buffer(void *dest, uint32_t address, size_t size) {
616 int offset;
617 nvm_storage_state_t *backend;
618 uint inst;
619
620 nhw_nvmc_address_location(address, &inst, &backend, &offset);
621
622 struct hw_nvmc_st_t *this = &hw_nvmc_st[inst];
623
624 if ((backend == &this->flash_st) && (nvmc_args.flash_erase_warnings)) {
625 for (uint32_t i = offset; i < offset + size ; i+= this->flash_page_size) {
626 CHECK_PARTIAL_ERASE(inst, i, "read");
627 }
628 }
629
630 if (offset + size >= backend->size) {
631 OUT_OF_FLASH_ERROR(address + size);
632 }
633
634 (void)memcpy(dest, &backend->storage[offset], size);
635 }
636
nrfhw_nmvc_flash_get_base_address(uint inst)637 void* nrfhw_nmvc_flash_get_base_address(uint inst){
638 return (void*)&hw_nvmc_st[inst].flash_st.storage;
639 }
640
641 #if defined(NRF52833)
NVM_BACKEND_PARAMS_CALLBACS(uicr,uicr[0])642 NVM_BACKEND_PARAMS_CALLBACS(uicr, uicr[0])
643 NVM_BACKEND_PARAMS_CALLBACS(flash, flash[0])
644 #elif defined(NRF5340)
645 NVM_BACKEND_PARAMS_CALLBACS(flash, flash[1])
646 NVM_BACKEND_PARAMS_CALLBACS(uicr_app, uicr[0])
647 NVM_BACKEND_PARAMS_CALLBACS(flash_app, flash[0])
648 NVM_BACKEND_PARAMS_CALLBACS(uicr_net, uicr[1])
649 NVM_BACKEND_PARAMS_CALLBACS(flash_net, flash[1])
650 #endif
651
652 static void nvmc_register_cmd_args(void){
653 for (int i = 0; i < NHW_NVMC_UICR_TOTAL_INST; i++) {
654 nvmc_args.uicr[i].in_ram = true;
655 nvmc_args.flash[i].in_ram = true;
656 }
657
658 static bs_args_struct_t args_struct_toadd[] = {
659 #if defined(NRF52833)
660 NVM_BACKEND_PARAMS(uicr, uicr[0], UICR),
661 NVM_BACKEND_PARAMS(flash, flash[0], FLASH),
662 #elif defined(NRF5340)
663 NVM_BACKEND_PARAMS(uicr_app, uicr[0], UICR_APP),
664 NVM_BACKEND_PARAMS(flash_app, flash[0], FLASH_APP),
665 NVM_BACKEND_PARAMS(uicr_net, uicr[1], UICR_NET),
666 NVM_BACKEND_PARAMS(flash_net, flash[1], FLASH_NET),
667 { .is_switch = true,
668 .option = "flash_*",
669 .manual = true,
670 .type = 'b',
671 .descript = "All plain flash options are aliases for the network core flash"
672 },
673 NVM_BACKEND_PARAMS(flash, flash[1], FLASH_NET),
674 #endif
675 { .is_switch = true,
676 .option = "flash_erase_warnings",
677 .type = 'b',
678 .dest = (void*)&nvmc_args.flash_erase_warnings,
679 .descript = "Give warnings when accessing partially erased pages in any flash"
680 },
681 ARG_TABLE_ENDMARKER
682 };
683
684 bs_add_extra_dynargs(args_struct_toadd);
685 }
686
687 NSI_TASK(nvmc_register_cmd_args, PRE_BOOT_1, 100);
688