From f8b804187cfb43a95b33debd3c9d6a84412b4bb2 Mon Sep 17 00:00:00 2001 From: Braian PLAKU Date: Sat, 19 Sep 2026 10:37:22 +0200 Subject: [PATCH 1/5] pack: builder: take the erased byte value from the FLM without subregions too When the FLM has one sector size that covers the whole region, no subregions are created, and the region kept the 0xff default for erased_byte_value. Subregions get FlashDevice.valEmpty, and so does the region the debug sequence flash path clones, only this one did not. The flash builder pads the gaps in a page with that value. On flash that erases to 0x00, holes in a sparse hex file were therefore programmed as 0xff. Fixes #2025 --- pyocd/target/pack/flm_region_builder.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyocd/target/pack/flm_region_builder.py b/pyocd/target/pack/flm_region_builder.py index d680a022a..cfbbc1c62 100644 --- a/pyocd/target/pack/flm_region_builder.py +++ b/pyocd/target/pack/flm_region_builder.py @@ -157,6 +157,11 @@ def _update_flash_attributes( region._start = pack_algo.flash_start region._end = pack_algo.flash_start + pack_algo.flash_size - 1 + # The erased value comes from the FLM whether or not subregions get created. Without it + # the region keeps the 0xff default, and the flash builder pads pages with the wrong byte + # on flash that erases to something else. + region.attributes['erased_byte_value'] = pack_algo.flash_info.value_empty + # Don't need to create subregions if there is a single sector size and its range # starts at the same address and is equal or larger than the parent flash region. sector_sizes = list(pack_algo.iter_sector_size_ranges()) From ea0e1ff0ed8509a3daf9fd7005e2723abbd32401 Mon Sep 17 00:00:00 2001 From: Braian PLAKU Date: Sat, 19 Sep 2026 11:14:48 +0200 Subject: [PATCH 2/5] test: pack: check the erased byte value of a finalised flash region Both test FLMs erase to 0xff, the same as the region default, so the tests patch valEmpty to 0 to tell the two apart. One case without subregions, one with. --- test/unit/test_pack.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/unit/test_pack.py b/test/unit/test_pack.py index d80525af6..f7c03cdc6 100644 --- a/test/unit/test_pack.py +++ b/test/unit/test_pack.py @@ -337,6 +337,23 @@ def test_multiple_sector_size(self, builder: FlmFlashRegionBuilder, stm32f42mflm assert submap[4].sector_size == 0x10000 assert submap[5].sector_size == 0x20000 + # Both test FLMs erase to 0xff, which is also the region default, so pretend they erase to 0. + def test_single_sector_size_erased_value(self, builder: FlmFlashRegionBuilder, nrf5340appflm, monkeypatch): + monkeypatch.setattr(nrf5340appflm.flash_info, 'value_empty', 0x00) + flash = memory_map.FlashRegion(0, length=0x200000, flm=nrf5340appflm) + assert flash.erased_byte_value == 0xff + assert builder.finalise_region(flash) + assert not flash.has_subregions + assert flash.erased_byte_value == 0x00 + + def test_multiple_sector_size_erased_value(self, builder: FlmFlashRegionBuilder, stm32f42mflm, monkeypatch): + monkeypatch.setattr(stm32f42mflm.flash_info, 'value_empty', 0x00) + flash = memory_map.FlashRegion(0x08000000, length=0x200000, flm=stm32f42mflm) + assert builder.finalise_region(flash) + assert flash.has_subregions + assert flash.erased_byte_value == 0x00 + assert all(subregion.erased_byte_value == 0x00 for subregion in flash.submap) + def test_ram_select_default(self, builder: FlmFlashRegionBuilder, nrf5340appflm): flash = memory_map.FlashRegion(0, length=0x200000, flm=nrf5340appflm) builder.finalise_region(flash) From cdbec2707c77b6c7311e46fafeaef4e78455f60d Mon Sep 17 00:00:00 2001 From: Teo Mahnic Date: Wed, 7 Oct 2026 11:28:30 +0200 Subject: [PATCH 3/5] pack: builder: move erased_byte_value to single-sector case --- pyocd/target/pack/flm_region_builder.py | 6 +----- test/unit/test_pack.py | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/pyocd/target/pack/flm_region_builder.py b/pyocd/target/pack/flm_region_builder.py index cfbbc1c62..72c06b541 100644 --- a/pyocd/target/pack/flm_region_builder.py +++ b/pyocd/target/pack/flm_region_builder.py @@ -157,11 +157,6 @@ def _update_flash_attributes( region._start = pack_algo.flash_start region._end = pack_algo.flash_start + pack_algo.flash_size - 1 - # The erased value comes from the FLM whether or not subregions get created. Without it - # the region keeps the 0xff default, and the flash builder pads pages with the wrong byte - # on flash that erases to something else. - region.attributes['erased_byte_value'] = pack_algo.flash_info.value_empty - # Don't need to create subregions if there is a single sector size and its range # starts at the same address and is equal or larger than the parent flash region. sector_sizes = list(pack_algo.iter_sector_size_ranges()) @@ -176,6 +171,7 @@ def _update_flash_attributes( # even though there are subregions. region.attributes['page_size'] = page_size region.attributes['sector_size'] = sector_sizes[0][1] + region.attributes['erased_byte_value'] = pack_algo.flash_info.value_empty def _add_flash_subregions( self, diff --git a/test/unit/test_pack.py b/test/unit/test_pack.py index f7c03cdc6..476448695 100644 --- a/test/unit/test_pack.py +++ b/test/unit/test_pack.py @@ -337,7 +337,6 @@ def test_multiple_sector_size(self, builder: FlmFlashRegionBuilder, stm32f42mflm assert submap[4].sector_size == 0x10000 assert submap[5].sector_size == 0x20000 - # Both test FLMs erase to 0xff, which is also the region default, so pretend they erase to 0. def test_single_sector_size_erased_value(self, builder: FlmFlashRegionBuilder, nrf5340appflm, monkeypatch): monkeypatch.setattr(nrf5340appflm.flash_info, 'value_empty', 0x00) flash = memory_map.FlashRegion(0, length=0x200000, flm=nrf5340appflm) From f45d948cc6a6edd8e832b3e2001ee1ec6ff88805 Mon Sep 17 00:00:00 2001 From: Teo Mahnic Date: Wed, 7 Oct 2026 11:49:19 +0200 Subject: [PATCH 4/5] test: pack: update copyright year --- test/unit/test_pack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/test_pack.py b/test/unit/test_pack.py index 476448695..e4af9c531 100644 --- a/test/unit/test_pack.py +++ b/test/unit/test_pack.py @@ -1,5 +1,5 @@ # pyOCD debugger -# Copyright (c) 2019-2020 Arm Limited +# Copyright (c) 2019-2020,2026 Arm Limited # Copyright (c) 2021-2023 Chris Reed # SPDX-License-Identifier: Apache-2.0 # From 362ba580a387dba8134b78a93572c9ded4233aaf Mon Sep 17 00:00:00 2001 From: Teo Mahnic Date: Mon, 12 Oct 2026 10:54:24 +0200 Subject: [PATCH 5/5] pack: builder: set parent erased_byte_value when creating subregions --- pyocd/target/pack/flm_region_builder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyocd/target/pack/flm_region_builder.py b/pyocd/target/pack/flm_region_builder.py index 72c06b541..e532b6f88 100644 --- a/pyocd/target/pack/flm_region_builder.py +++ b/pyocd/target/pack/flm_region_builder.py @@ -167,8 +167,7 @@ def _update_flash_attributes( if create_subregions: self._add_flash_subregions(region, pack_algo, page_size, algo) else: - # Set attributes on parent flash region. The parent region still has to have these attributes - # even though there are subregions. + # Set parent flash region attributes without creating subregions. region.attributes['page_size'] = page_size region.attributes['sector_size'] = sector_sizes[0][1] region.attributes['erased_byte_value'] = pack_algo.flash_info.value_empty @@ -229,3 +228,4 @@ def _add_flash_subregions( # even though there are subregions. region.attributes['page_size'] = page_size region.attributes['sector_size'] = max_sector_size + region.attributes['erased_byte_value'] = pack_algo.flash_info.value_empty