1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * NRF54L
9 *
10 * RRAMC - Resistive random access memory controller
11 * &
12 * UICR - User information configuration registers
13 *
14 * A very simple model, which creates a memory mapped RRAMC and UICR area
15 * backed by either a file on disk or host RAM.
16 * The RRAM (and UICR) is memory is not mapped in the same addresses as in
17 * real HW. Accesses need to be done relative to nhw_RRAMC_get_RRAM_base_address()
18 * (or NRF_UICR_BASE for the UICR)
19 *
20 * Note: The SICR is not yet included
21 *
22 * Notes for the RRAM(C):
23 *
24 * * Reads and writes are instantaneous.
25 *
26 * * READY and READYNEXT are reset to 1 and never cleared.
27 *
28 * * Task, events and interrupts are not connected.
29 *
30 * * Writes are assumed always enabled and write buffering disabled.
31 * i.e. CONFIG, READYNEXTTIMEOUT are ignored,
32 * writes are immediately reflected in the RRAM,
33 * BUFSTATUS.EMPTY is reset to 1 and never cleared.
34 *
35 * * There is no model of the optional immutable boot region write protection
36 * (all RRAM can be written)
37 *
38 * * Reads do not go thru the CACHE
39 *
40 * * There is no models of the RRAM and controller power states
41 * (POWER.* are ignored)
42 *
43 * * There is no models of bit errors, or ECC corrections
44 *
45 * * ACCESSERRORADDR is not modeled (it is never set after reset)
46 *
47 * * Access port protection is not modeled. The UICR can always be erased.
48 *
49 *
50 * Notes for the UICR
51 * * The APPROTECT, SECUREAPPROTECT, AUXAPPROTECT, ERASEPROTECT
52 * and BOOTCONF are ignored.
53 * Their equivalent functionality is not implemented
54 *
55 *
56 * Implementation notes:
57 * This file includes models for a nrf54L RRAMController, the RRAM itself
58 * and of an empty UICR.
59 * And instantiates 1 set for the nrf54L15
60 * (and initializes them at startup and frees them on exit),
61 */
62
63 #include <string.h>
64 #include <stdint.h>
65 #include "bs_tracing.h"
66 #include "bs_cmd_line.h"
67 #include "bs_dynargs.h"
68 #include "bs_oswrap.h"
69 #include "nsi_hw_scheduler.h"
70 #include "nsi_tasks.h"
71 #include "nsi_hws_models_if.h"
72 #include "NHW_common_types.h"
73 #include "NHW_config.h"
74 #include "NHW_peri_types.h"
75 #include "NHW_RRAMC.h"
76 #include "NHW_NVM_backend.h"
77
78 NRF_UICR_Type *NRF_UICR_regs_p[NHW_RRAMC_UICR_TOTAL_INST];
79 NRF_RRAMC_Type *NRF_RRAMC_regs_p[NHW_RRAMC_UICR_TOTAL_INST];
80 NRF_RRAMC_Type NRF_RRAMC_regs[NHW_RRAMC_UICR_TOTAL_INST] = {0};
81
82 struct hw_rramc_st_t {
83 NRF_RRAMC_Type *RRAMC_regs;
84 nvm_storage_state_t rram_st;
85 nvm_storage_state_t uicr_st;
86
87 uint rram_start_addr;
88 uint rram_size;
89 uint uicr_size;
90 };
91
92 static struct hw_rramc_st_t hw_rramc_st[NHW_RRAMC_UICR_TOTAL_INST];
93
94 struct nvmc_args_t {
95 struct nhw_nvm_st_args_t uicr[NHW_RRAMC_UICR_TOTAL_INST];
96 struct nhw_nvm_st_args_t rram[NHW_RRAMC_UICR_TOTAL_INST];
97 } nvmc_args;
98
99 /**
100 * Initialize the RRAM(C) and UICR models
101 */
nhw_RRAMC_uicr_init(void)102 static void nhw_RRAMC_uicr_init(void)
103 {
104 uint rram_start_addr[NHW_RRAMC_UICR_TOTAL_INST] = NHW_RRAM_START_ADDR;
105 uint rram_size[NHW_RRAMC_UICR_TOTAL_INST] = NHW_RRAM_SIZE;
106 uint uicr_size[NHW_RRAMC_UICR_TOTAL_INST] = NHW_UICR_SIZE;
107
108 memset(NRF_RRAMC_regs, 0x00, sizeof(NRF_RRAMC_regs));
109
110 for (int inst = 0; inst < NHW_RRAMC_UICR_TOTAL_INST; inst++) {
111 struct hw_rramc_st_t *this = &hw_rramc_st[inst];
112 this->RRAMC_regs = &NRF_RRAMC_regs[inst];
113 NRF_RRAMC_regs_p[inst] = &NRF_RRAMC_regs[inst];
114
115 NRF_RRAMC_regs[inst].READY = 1;
116 NRF_RRAMC_regs[inst].READYNEXT = 1;
117 NRF_RRAMC_regs[inst].EVENTS_READY = 1;
118 NRF_RRAMC_regs[inst].EVENTS_READYNEXT = 1;
119 NRF_RRAMC_regs[inst].ACCESSERRORADDR = 0x00FFFFFF;
120 NRF_RRAMC_regs[inst].BUFSTATUS.WRITEBUFEMPTY = 1;
121 NRF_RRAMC_regs[inst].READYNEXTTIMEOUT = 0x00000080;
122 NRF_RRAMC_regs[inst].POWER.CONFIG = 0x00000100;
123
124 this->rram_start_addr = rram_start_addr[inst];
125 this->rram_size = rram_size[inst];
126
127 nhw_nvm_init_storage(&this->rram_st, &nvmc_args.rram[inst],
128 this->rram_size, "RRAM");
129
130 this->uicr_size = uicr_size[inst];
131 nhw_nvm_init_storage(&this->uicr_st, &nvmc_args.uicr[inst],
132 this->uicr_size, "UICR");
133
134 NRF_UICR_regs_p[inst] = (NRF_UICR_Type *)this->uicr_st.storage;
135 }
136 }
137
138 NSI_TASK(nhw_RRAMC_uicr_init, HW_INIT, 100);
139
140 /**
141 * Clean up the RRAM(C) and UICR model before program exit
142 */
nhw_RRAMC_uicr_clean_up(void)143 static void nhw_RRAMC_uicr_clean_up(void) {
144 for (int inst = 0; inst < NHW_RRAMC_UICR_TOTAL_INST; inst++) {
145 struct hw_rramc_st_t *this = &hw_rramc_st[inst];
146 nhw_nvm_clear_storage(&this->rram_st);
147 nhw_nvm_clear_storage(&this->uicr_st);
148 }
149 }
150
151 NSI_TASK(nhw_RRAMC_uicr_clean_up, ON_EXIT_PRE, 100);
152
153 /*
154 * Do the actual erase of the UICR area
155 */
nhw_RRAMC_erase_uicr(uint inst)156 static void nhw_RRAMC_erase_uicr(uint inst){
157 struct hw_rramc_st_t *this = &hw_rramc_st[inst];
158 (void)memset(this->uicr_st.storage, 0xFF, this->uicr_st.size);
159 }
160
161 /*
162 * Do the actual erase of all RRAM and UICR areas
163 */
nhw_RRAMC_erase_all(uint inst)164 static void nhw_RRAMC_erase_all(uint inst){
165 struct hw_rramc_st_t *this = &hw_rramc_st[inst];
166 nhw_RRAMC_erase_uicr(inst);
167 (void)memset(this->rram_st.storage, 0xFF, this->rram_st.size);
168 }
169
nhw_RRAMC_regw_sideeffects_ERASEALL(uint inst)170 void nhw_RRAMC_regw_sideeffects_ERASEALL(uint inst) {
171 NRF_RRAMC_regs[inst].ERASE.ERASEALL &= 1;
172
173 if (NRF_RRAMC_regs[inst].ERASE.ERASEALL) {
174 NRF_RRAMC_regs[inst].ERASE.ERASEALL = 0;
175 nhw_RRAMC_erase_all(inst);
176 }
177 }
178
179 #define OUT_OF_RRAM_ERROR(addr) \
180 bs_trace_error_time_line("%s: Attempted access outside of RRAM and UICR areas (0x%X)\n",\
181 __func__, address)
182
183 /*
184 * Check if an address is in range of any RRAM or UICR
185 * and if so, set the inst, storage and offset accordingly.
186 *
187 * Where address is an address in either a "hard" RRAM address
188 * (meaning in the 0x00..00 range for nrf52, or also in the 0x010..00 range for nrf53)
189 * Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
190 * NRF_UICR_*_BASE)
191 *
192 * If the address is not in range, the function does not return, but produces an error
193 */
nhw_RRAMC_address_location(uint32_t address,uint * inst,nvm_storage_state_t ** storage,int * offset)194 static void nhw_RRAMC_address_location(uint32_t address, uint *inst, nvm_storage_state_t **storage, int *offset){
195 for (int i = 0; i < NHW_RRAMC_UICR_TOTAL_INST; i ++) {
196 *inst = i;
197 if ((address >= hw_rramc_st[i].rram_start_addr) \
198 && (address < hw_rramc_st[i].rram_start_addr + hw_rramc_st[i].rram_size)) {
199 *storage = &hw_rramc_st[i].rram_st;
200 *offset = address - hw_rramc_st[i].rram_start_addr;
201 return;
202 }
203 if ((address >= (uint32_t)hw_rramc_st[i].uicr_st.storage) \
204 && (address < (uint32_t)hw_rramc_st[i].uicr_st.storage + hw_rramc_st[i].uicr_size)) {
205 *storage = &hw_rramc_st[i].uicr_st;
206 *offset = address - (uint32_t)hw_rramc_st[i].uicr_st.storage;
207 return;
208 }
209 }
210 OUT_OF_RRAM_ERROR(address);
211 }
212
213 /*
214 * Write to a RRAM array (RRAM or UICR)
215 *
216 * Where address is an address in either a "hard" RRAM address
217 * (meaning in the 0x00..00 range)
218 * Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
219 * NRF_UICR_*_BASE)
220 */
nhw_RRAMC_write_word(uint32_t address,uint32_t value)221 void nhw_RRAMC_write_word(uint32_t address, uint32_t value){
222 if ((address & 3) != 0){
223 bs_trace_error_line_time("%s: write to non word aligned address %u, "
224 "this would have hard-faulted in real HW\n",
225 __func__, address);
226 }
227
228 int offset;
229 nvm_storage_state_t *backend;
230 uint inst;
231
232 nhw_RRAMC_address_location(address, &inst, &backend, &offset);
233
234 *(uint32_t*)&backend->storage[offset] = value;
235 }
236
237 /*
238 * Write to a RRAM array (RRAM or UICR)
239 *
240 * Where address is an address in either a "hard" RRAM address
241 * (meaning in the 0x00..00 range)
242 * Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
243 * NRF_UICR_*_BASE)
244 */
nhw_RRAMC_write_halfword(uint32_t address,uint16_t value)245 void nhw_RRAMC_write_halfword(uint32_t address, uint16_t value){
246 if ((address & 1) != 0){
247 bs_trace_error_line_time("%s: write to non half-word aligned address %u, "
248 "this would have hard-faulted in real HW\n",
249 __func__, address);
250 }
251
252 int offset;
253 nvm_storage_state_t *backend;
254 uint inst;
255
256 nhw_RRAMC_address_location(address, &inst, &backend, &offset);
257
258 *(uint16_t*)&backend->storage[offset] = value;
259 }
260
261 /*
262 * Write to a RRAM array (RRAM or UICR)
263 *
264 * Where address is an address in either a "hard" RRAM address
265 * (meaning in the 0x00..00 range)
266 * Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
267 * NRF_UICR_*_BASE)
268 */
nhw_RRAMC_write_byte(uint32_t address,uint8_t value)269 void nhw_RRAMC_write_byte(uint32_t address, uint8_t value){
270 int offset;
271 nvm_storage_state_t *backend;
272 uint inst;
273
274 nhw_RRAMC_address_location(address, &inst, &backend, &offset);
275
276 *(uint8_t*)&backend->storage[offset] = value;
277 }
278
279 /**
280 * Read from the RRAM array (RRAM or UICR)
281 *
282 * Where address is an address in either a "hard" RRAM address
283 * (meaning in the 0x00..00 range)
284 * Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
285 * NRF_UICR_*_BASE)
286 *
287 * This operation is instantaneous in simulation.
288 */
nhw_RRAMC_read_word(uint32_t address)289 uint32_t nhw_RRAMC_read_word(uint32_t address) {
290 int offset;
291 nvm_storage_state_t *backend;
292 uint inst;
293
294 nhw_RRAMC_address_location(address, &inst, &backend, &offset);
295
296 return *(uint32_t*)&backend->storage[offset];
297 }
298
nhw_RRAMC_read_halfword(uint32_t address)299 uint16_t nhw_RRAMC_read_halfword(uint32_t address) {
300 int offset;
301 nvm_storage_state_t *backend;
302 uint inst;
303
304 nhw_RRAMC_address_location(address, &inst, &backend, &offset);
305
306 return *(uint16_t*)&backend->storage[offset];
307 }
308
nhw_RRAMC_read_byte(uint32_t address)309 uint8_t nhw_RRAMC_read_byte(uint32_t address) {
310 int offset;
311 nvm_storage_state_t *backend;
312 uint inst;
313
314 nhw_RRAMC_address_location(address, &inst, &backend, &offset);
315
316 return *(uint8_t*)&backend->storage[offset];
317 }
318
319 /**
320 * memcpy into RRAM/UICR array from <address> <size> bytes.
321 *
322 * Where address is an address in either a "hard" RRAM address
323 * (meaning in the 0x00..00 range)
324 * Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
325 * NRF_UICR_*_BASE)
326 *
327 * This is a convenience function in the model.
328 * It can be used from DMA controller models or the like.
329 *
330 * This operation is instantaneous in simulation.
331 * In real HW it is as "fast" as all those AHB accesses
332 * can be dispatched by the interconnect and handled by
333 * the RRAMC peripheral
334 */
nhw_RRAMC_write_buffer(uint32_t address,void * src,size_t size)335 void nhw_RRAMC_write_buffer(uint32_t address, void *src, size_t size) {
336 int offset;
337 nvm_storage_state_t *backend;
338 uint inst;
339
340 nhw_RRAMC_address_location(address, &inst, &backend, &offset);
341
342 if (offset + size >= backend->size) {
343 OUT_OF_RRAM_ERROR(address + size);
344 }
345
346 (void)memcpy(&backend->storage[offset], src, size);
347 }
348
349 /**
350 * memcpy from the RRAM/UICR array from <address> <size> bytes.
351 *
352 * Where address is an address in either a "hard" RRAM address
353 * (meaning in the 0x00..00 range)
354 * Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
355 * NRF_UICR_*_BASE)
356 *
357 * This is a convenience function in the model.
358 * It can be used from DMA controller models or the like.
359 *
360 * This operation is instantaneous in simulation.
361 * In real HW it is as "fast" as all those AHB accesses
362 * can be dispatched by the interconnect and handled by
363 * the RRAMC peripheral
364 */
nhw_RRAMC_read_buffer(void * dest,uint32_t address,size_t size)365 void nhw_RRAMC_read_buffer(void *dest, uint32_t address, size_t size) {
366 int offset;
367 nvm_storage_state_t *backend;
368 uint inst;
369
370 nhw_RRAMC_address_location(address, &inst, &backend, &offset);
371
372 if (offset + size >= backend->size) {
373 OUT_OF_RRAM_ERROR(address + size);
374 }
375
376 (void)memcpy(dest, &backend->storage[offset], size);
377 }
378
nhw_RRAMC_get_RRAM_base_address(uint inst)379 void* nhw_RRAMC_get_RRAM_base_address(uint inst) {
380 return (void*)hw_rramc_st[inst].rram_st.storage;
381 }
382
NVM_BACKEND_PARAMS_CALLBACS(uicr,uicr[0])383 NVM_BACKEND_PARAMS_CALLBACS(uicr, uicr[0])
384 NVM_BACKEND_PARAMS_CALLBACS(rram, rram[0])
385
386 static void RRAMC_register_cmd_args(void){
387 for (int i = 0; i < NHW_RRAMC_UICR_TOTAL_INST; i++) {
388 nvmc_args.uicr[i].in_ram = true;
389 nvmc_args.rram[i].in_ram = true;
390 }
391
392 static bs_args_struct_t args_struct_toadd[] = {
393 NVM_BACKEND_PARAMS(uicr, uicr[0], UICR),
394 NVM_BACKEND_PARAMS(rram, rram[0], RRAM),
395 NVM_BACKEND_PARAMS_ALIAS(flash, rram, rram[0], RRAM, "(Alias for rram_* paramaters) "),
396 ARG_TABLE_ENDMARKER
397 };
398
399 bs_add_extra_dynargs(args_struct_toadd);
400 }
401
402 NSI_TASK(RRAMC_register_cmd_args, PRE_BOOT_1, 100);
403