Skip to content

Commit c72ef63

Browse files
de-nordicrghaddab
authored andcommitted
[nrf fromtree] drivers/flash_simulator: Add support for non-erase device
The commit adds support for testing non-explicite-erase device on Flash Simulator. This is addition to already supported explicit erase before write, aka Flash, type of device behaviour. Signed-off-by: Dominik Ermel <[email protected]> (cherry picked from commit ff81b52)
1 parent db093b2 commit c72ef63

File tree

4 files changed

+205
-1
lines changed

4 files changed

+205
-1
lines changed

drivers/flash/Kconfig.simulator

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,32 @@ config FLASH_SIMULATOR_UNALIGNED_READ
2222
Disable this option only if you want to simulate
2323
a specific FLASH interface that requires aligned read access.
2424

25+
config FLASH_SIMULATOR_EXPLICIT_ERASE
26+
bool "Program-erase device"
27+
select FLASH_HAS_EXPLICIT_ERASE
28+
default y
29+
help
30+
Explicit erase (non-erase-on-write) Flash, which is device that requires erase
31+
to erase-value prior to write as it only allows to change bits from erase-value
32+
to the opposite.
33+
34+
config FLASH_SIMULATOR_RAMLIKE
35+
bool
36+
default y if !FLASH_SIMULATOR_EXPLICIT_ERASE
37+
select FLASH_HAS_NO_EXPLICIT_ERASE
38+
select FLASH_SIMULATOR_DOUBLE_WRITES
39+
help
40+
This is used for setting FLASH_HAS_NO_EXPLICIT_ERASE.
41+
2542
config FLASH_SIMULATOR_DOUBLE_WRITES
2643
bool "Allow program units to be programmed more than once"
2744
help
2845
If selected, writing to a non-erased program unit will succeed, otherwise, it will return an error.
2946
Keep in mind that write operations can only change value of a bit from erase-value to the
3047
opposite.
48+
This option does not impact FLASH_SIMULATOR_RAMLIKE.
49+
In case when FLASH_SIMULATOR_EXPLICIT_ERASE is selected multiple writes to the same bit
50+
but only change from erase-value to opposite will be registered.
3151

3252
config FLASH_SIMULATOR_SIMULATE_TIMING
3353
bool "Hardware timing simulation"

drivers/flash/flash_simulator.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,12 @@ static const struct flash_driver_api flash_sim_api;
162162

163163
static const struct flash_parameters flash_sim_parameters = {
164164
.write_block_size = FLASH_SIMULATOR_PROG_UNIT,
165-
.erase_value = FLASH_SIMULATOR_ERASE_VALUE
165+
.erase_value = FLASH_SIMULATOR_ERASE_VALUE,
166+
.caps = {
167+
#if !defined(CONFIG_FLASH_SIMULATOR_EXPLICIT_ERASE)
168+
.no_explicit_erase = false,
169+
#endif
170+
},
166171
};
167172

168173
static int flash_range_is_valid(const struct device *dev, off_t offset,
@@ -226,8 +231,12 @@ static int flash_sim_write(const struct device *dev, const off_t offset,
226231

227232
FLASH_SIM_STATS_INC(flash_sim_stats, flash_write_calls);
228233

234+
#if defined(CONFIG_FLASH_SIMULATOR_EXPLICIT_ERASE)
229235
/* check if any unit has been already programmed */
230236
memset(buf, FLASH_SIMULATOR_ERASE_VALUE, sizeof(buf));
237+
#else
238+
memcpy(buf, MOCK_FLASH(offset), sizeof(buf));
239+
#endif
231240
for (uint32_t i = 0; i < len; i += FLASH_SIMULATOR_PROG_UNIT) {
232241
if (memcmp(buf, MOCK_FLASH(offset + i), sizeof(buf))) {
233242
FLASH_SIM_STATS_INC(flash_sim_stats, double_writes);
@@ -265,10 +274,14 @@ static int flash_sim_write(const struct device *dev, const off_t offset,
265274
#endif /* CONFIG_FLASH_SIMULATOR_STATS */
266275

267276
/* only pull bits to zero */
277+
#if IS_ENABLED(CONFIG_FLASH_SIMULATOR_EXPLICIT_ERASE)
268278
#if FLASH_SIMULATOR_ERASE_VALUE == 0xFF
269279
*(MOCK_FLASH(offset + i)) &= *((uint8_t *)data + i);
270280
#else
271281
*(MOCK_FLASH(offset + i)) |= *((uint8_t *)data + i);
282+
#endif
283+
#else
284+
*(MOCK_FLASH(offset + i)) = *((uint8_t *)data + i);
272285
#endif
273286
}
274287

tests/drivers/flash_simulator/flash_sim_impl/src/main.c

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
#include <zephyr/drivers/flash.h>
99
#include <zephyr/device.h>
1010

11+
/* Warning: The test has been written for testing boards with single
12+
* instance of Flash Simulator device only.
13+
*/
14+
1115
/* configuration derived from DT */
1216
#ifdef CONFIG_ARCH_POSIX
1317
#define SOC_NV_FLASH_NODE DT_CHILD(DT_INST(0, zephyr_sim_flash), flash_0)
@@ -75,6 +79,44 @@ static void test_check_pattern32(off_t start, uint32_t (*pattern_gen)(void),
7579
}
7680
}
7781

82+
/* ret < 0 is errno; ret == 1 is bad value in flash */
83+
static int test_check_erase(const struct device *dev, off_t offset, size_t size)
84+
{
85+
uint8_t buf[FLASH_SIMULATOR_PROG_UNIT];
86+
int rc;
87+
int i = 0;
88+
89+
BUILD_ASSERT(sizeof(buf) >= FLASH_SIMULATOR_PROG_UNIT);
90+
91+
i = 0;
92+
while (i < size) {
93+
size_t chunk = MIN(size - i, sizeof(buf));
94+
/* The memset is done to set buf to something else than
95+
* FLASH_SIMULATOR_ERASE_VALUE, as we are trying to chek
96+
* whether that is what is now in the memory.
97+
*/
98+
memset(buf, ~FLASH_SIMULATOR_ERASE_VALUE, sizeof(buf));
99+
rc = flash_read(flash_dev, offset + i,
100+
buf, chunk);
101+
if (rc < 0) {
102+
TC_PRINT("Unexpected flash_read fail @ %ld",
103+
(long)(offset + i));
104+
return rc;
105+
}
106+
do {
107+
if ((uint8_t)buf[i & (sizeof(buf) - 1)] !=
108+
(uint8_t)FLASH_SIMULATOR_ERASE_VALUE) {
109+
TC_PRINT("Flash not erased at %ld\n",
110+
(long)(offset + i));
111+
return 1;
112+
}
113+
++i;
114+
--chunk;
115+
} while (chunk);
116+
}
117+
return 0;
118+
}
119+
78120
/* Get access to the device and erase it ready for testing*/
79121
static void test_init(void)
80122
{
@@ -259,6 +301,8 @@ ZTEST(flash_sim_api, test_align)
259301
zassert_equal(-EINVAL, rc, "Unexpected error code (%d)", rc);
260302
}
261303

304+
#if !IS_ENABLED(CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES) && \
305+
!IS_ENABLED(CONFIG_FLASH_SIMULATOR_RAMLIKE)
262306
ZTEST(flash_sim_api, test_double_write)
263307
{
264308
int rc;
@@ -282,6 +326,122 @@ ZTEST(flash_sim_api, test_double_write)
282326
&data, sizeof(data));
283327
zassert_equal(-EIO, rc, "Unexpected error code (%d)", rc);
284328
}
329+
#endif
330+
331+
#if IS_ENABLED(CONFIG_FLASH_SIMULATOR_RAMLIKE)
332+
ZTEST(flash_sim_api, test_ramlike)
333+
{
334+
/* Within code below there is assumption that the src size is
335+
* equal or greater than the FLASH_SIMULATOR_PROG_UNIT
336+
* (write-block-size) of device.
337+
*/
338+
const uint8_t src[] = "Hello world! This is test string";
339+
uint8_t buf[FLASH_SIMULATOR_PROG_UNIT];
340+
/* Round up to next write-block-size */
341+
int max = (sizeof(src) + FLASH_SIMULATOR_PROG_UNIT - 1) &
342+
~(FLASH_SIMULATOR_PROG_UNIT - 1);
343+
int rc;
344+
int i = 0;
345+
int is = 0; /* The index within src */
346+
347+
BUILD_ASSERT(sizeof(src) >= FLASH_SIMULATOR_PROG_UNIT);
348+
349+
/* Scrub memory with something constant */
350+
memset(buf, FLASH_SIMULATOR_ERASE_VALUE, sizeof(buf));
351+
while (i < max) {
352+
rc = flash_write(flash_dev, FLASH_SIMULATOR_BASE_OFFSET + i,
353+
buf, sizeof(buf));
354+
zassert_equal(0, rc, "flash_write should succeed");
355+
i += sizeof(buf);
356+
}
357+
358+
/* Check the scrubbing */
359+
zassert_equal(0, test_check_erase(flash_dev, FLASH_SIMULATOR_BASE_OFFSET, max),
360+
"Area not erased");
361+
362+
/* Now write something new */
363+
i = 0;
364+
while (i < max) {
365+
do {
366+
buf[i & (sizeof(buf) - 1)] = src[is];
367+
++i;
368+
++is;
369+
370+
/* Continue writing from the beginning of the src */
371+
if (is >= sizeof(src)) {
372+
is = 0;
373+
}
374+
} while (i & (sizeof(buf) - 1));
375+
rc = flash_write(flash_dev, FLASH_SIMULATOR_BASE_OFFSET + i - sizeof(buf),
376+
buf, sizeof(buf));
377+
zassert_equal(0, rc, "flash_write should succeed");
378+
}
379+
380+
/* Check the write */
381+
i = 0;
382+
is = 0;
383+
while (i < max) {
384+
rc = flash_read(flash_dev, FLASH_SIMULATOR_BASE_OFFSET + i,
385+
buf, sizeof(buf));
386+
zassert_equal(0, rc, "flash_read should succeed");
387+
do {
388+
zassert_equal((uint8_t)src[is], (uint8_t)buf[i & (sizeof(buf) - 1)],
389+
"Expected src and buf to match at index %d\n", i);
390+
++i;
391+
++is;
392+
/* Src has wrapped around */
393+
if (is >= sizeof(src)) {
394+
is = 0;
395+
}
396+
} while (i & (sizeof(buf) - 1));
397+
zassert_equal(0, rc, "Unexpected value read");
398+
}
399+
400+
/* Because we are checking random access writes, we are now going to
401+
* write binary not of the same data we have just written. If this would be
402+
* program-erase type memory, where you can only change from erase value
403+
* to opposite, such write would render incorrect data in memory,
404+
* but this is random access device so we should get exactly what we write.
405+
*/
406+
i = 0;
407+
is = 0;
408+
while (i < max) {
409+
do {
410+
buf[i & (sizeof(buf) - 1)] = ~src[is];
411+
++i;
412+
++is;
413+
414+
/* Continue writing from the beginning of the src */
415+
if (is >= sizeof(src)) {
416+
is = 0;
417+
}
418+
} while (i & (sizeof(buf) - 1));
419+
rc = flash_write(flash_dev, FLASH_SIMULATOR_BASE_OFFSET + i - sizeof(buf),
420+
buf, sizeof(buf));
421+
zassert_equal(0, rc, "flash_write should succeed");
422+
}
423+
424+
/* Check the write */
425+
i = 0;
426+
is = 0;
427+
while (i < max) {
428+
rc = flash_read(flash_dev, FLASH_SIMULATOR_BASE_OFFSET + i,
429+
buf, sizeof(buf));
430+
zassert_equal(0, rc, "flash_read should succeed");
431+
do {
432+
zassert_equal((uint8_t)~src[is], (uint8_t)buf[i & (sizeof(buf) - 1)],
433+
"Expected src and buf to match at index %d\n", i);
434+
++i;
435+
++is;
436+
/* Src has wrapped around */
437+
if (is >= sizeof(src)) {
438+
is = 0;
439+
}
440+
} while (i & (sizeof(buf) - 1));
441+
zassert_equal(0, rc, "Unexpected value read");
442+
}
443+
}
444+
#endif
285445

286446
ZTEST(flash_sim_api, test_get_erase_value)
287447
{

tests/drivers/flash_simulator/flash_sim_impl/testcase.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@ tests:
1313
- nucleo_f411re
1414
integration_platforms:
1515
- qemu_x86
16+
drivers.flash.flash_simulator.ramlike:
17+
extra_args: CONFIG_FLASH_SIMULATOR_EXPLICIT_ERASE=n
18+
platform_allow:
19+
- qemu_x86
20+
- native_posix
21+
- native_posix/native/64
22+
- native_sim
23+
- native_sim/native/64
24+
- nucleo_f411re
25+
integration_platforms:
26+
- qemu_x86
1627
drivers.flash.flash_simulator.qemu_erase_value_0x00:
1728
extra_args: DTC_OVERLAY_FILE=boards/qemu_x86_ev_0x00.overlay
1829
platform_allow: qemu_x86

0 commit comments

Comments
 (0)