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