Infineon: Switch to 1.9.0 code base, add xmc7000 family support, refactor memory layer
diff --git a/boot/cypress/scripts/feature.py b/boot/cypress/scripts/feature.py
new file mode 100644
index 0000000..4bc428c
--- /dev/null
+++ b/boot/cypress/scripts/feature.py
@@ -0,0 +1,251 @@
+"""
+Copyright 2023 Cypress Semiconductor Corporation (an Infineon company)
+or an affiliate of Cypress Semiconductor Corporation. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+
+import sys
+import json
+import click
+
+def load_json(file_path):
+    """
+    Loads JSON from file.
+    """
+
+    data_json = None
+
+    try:
+        with open(file_path, encoding="utf-8") as file:
+            data_json = json.load(file)
+
+    except FileNotFoundError:
+        print(f'\nERROR: Cannot find {file_path}')
+        sys.exit(-1)
+
+    return data_json
+
+
+class FieldsValidator:
+    """
+        Validation of required fields and their cross-dependencies.
+    """
+
+    @staticmethod
+    def validate(feature_json, properties_json):
+        """
+            Check 'target' and properties of a platform.
+        """
+        p_target = properties_json.get('target')
+        if p_target is None:
+            raise AttributeError('Field "target" must be present in platform_properties.json')
+
+        f_target = feature_json.get('target')
+        if f_target is None:
+            raise AttributeError('Field "target" must be present in a feature_config.json')
+
+        if f_target not in p_target:
+            raise AttributeError('Target in feature config is not correct.'
+                                    ' It must be among the target list of platform_properties.json')
+
+        f_security_setup = feature_json.get('security_setup')
+        p_security_setup = properties_json.get('security_setup')
+
+        if f_security_setup:
+
+            if p_security_setup is None:
+                raise AttributeError("This platform doesn't have any 'secure_setup' features")
+
+            if f_security_setup.get('hw_rollback_prot'):
+                if p_security_setup.get('hw_rollback_prot') is None:
+                    raise AttributeError("This platform doesn't have HW anti roll-back counter")
+
+            if f_security_setup.get('hw_crypto_acceleration'):
+                if p_security_setup.get('hw_crypto_acceleration') is None:
+                    raise AttributeError("The platform doesn't support HW crypto acceleration")
+
+            if f_security_setup.get('validate_upgrade').get('value') is False:
+                raise AttributeError("Deactivation of image validation during the upgrade \
+                                        process isn't implemented yet")
+
+
+class FeatureProcessor:
+
+    """
+        The general handler of all needed fields and filling the new mk-file.
+    """
+
+    settings_dict = {
+        'validate_boot'             :   'MCUBOOT_SKIP_IMAGE_VALIDATION',
+        'validate_upgrade'          :   'MCUBOOT_SKIP_UPGRADE_VALIDATION',
+        'dependency_check'          :   'MCUBOOT_DEPENDENCY_CHECK',
+        'serial_logging'            :   'MCUBOOT_LOG_LEVEL',
+        'hw_rollback_prot'          :   'USE_HW_ROLLBACK_PROT',
+        'hw_crypto_acceleration'    :   "USE_CRYPTO_HW",
+        'sw_downgrade_prev'         :   'USE_SW_DOWNGRADE_PREV',
+        'ram_app_staging'           :   'USE_STAGE_RAM_APPS',
+        'xip'                       :   'USE_XIP',
+        'image_encryption'          :   'ENC_IMG',
+        'fault_injection_hardening' :   'FIH_PROFILE_LEVEL',
+        'combine_hex'               :   'COMBINE_HEX',
+        'hw_key'                    :   'USE_HW_KEY'
+    }
+
+    debug_level_dict = {
+        'off'       :   '_OFF',
+        'error'     :   '_ERROR',
+        'warning'   :   '_WARNING',
+        'info'      :   '_INFO',
+        'debug'     :   '_DEBUG'
+    }
+
+    fih_level_dict = {
+        'off'       :   'OFF',
+        'low'       :   'LOW',
+        'medium'    :   'MEDIUM',
+        'high'      :   'HIGH'
+    }
+
+    def __init__(self, output_name):
+        self.out_f = output_name
+
+    @staticmethod
+    def generate_header_guard():
+        """
+            Print header line at the begining of a mk-file
+        """
+        guard_lines = ('# AUTO-GENERATED FILE, DO NOT EDIT.'
+                        ' ALL CHANGES WILL BE LOST! #\n\n')
+
+        return guard_lines
+
+    @staticmethod
+    def insert_res(val_to_check) -> str:
+        """
+            Simlpe check result and return the string with value.
+        """
+        return f' := {1 if val_to_check else 0}\n'
+
+    @staticmethod
+    def insert_inverted_res(val_to_check) -> str:
+        """
+            Simlpe check result and return the string with inverted value.
+        """
+        return f' := {0 if val_to_check else 1}\n'
+
+    def __prnt_dict_primitive_key(self, dict_feature_config, settings_dict_key, f_out):
+        """
+            Print kyes of 'feature_config' with bool type of 'value'
+        """
+        val = dict_feature_config.get(settings_dict_key).get('value')
+
+        if isinstance(val, bool):
+
+            # invert because variable use 'skip' command
+            need_invertion = set(("validate_boot", "validate_upgrade"))
+
+            f_out.write(self.settings_dict[settings_dict_key])
+
+            if settings_dict_key not in need_invertion:
+                f_out.write(FeatureProcessor.insert_res(val))
+            else:
+                f_out.write(FeatureProcessor.insert_inverted_res(val))
+
+
+    def __gen_fih_level(self, fih_value):
+        """
+            Print only FIH_
+        """
+        res = f"{self.settings_dict['fault_injection_hardening']} ?= "\
+              f"{self.fih_level_dict[fih_value]}\n"
+
+        return res
+
+    def __gen_debug_level(self, logging_value):
+        """
+            Print only MCUBOOT_LOG_LEVEL
+        """
+        param_txt = self.settings_dict['serial_logging']
+        res_str = f"{param_txt} ?= {param_txt}{self.debug_level_dict[logging_value]}\n"
+
+        return res_str
+
+
+    def __handle_dictionary(self, f_dict, f_out):
+        """
+            Handle any dictionary of 'feature_config'
+        """
+        dont_print_list = set(("validation_key", "version", "description", "target"))
+
+        for k in f_dict:
+
+            if k not in dont_print_list:
+                self.__prnt_dict_primitive_key(f_dict, k, f_out)
+
+            if k == 'fault_injection_hardening':
+                f_out.write(self.__gen_fih_level(f_dict.get(k).get("value")))
+
+            if k == 'serial_logging':
+                f_out.write(self.__gen_debug_level(f_dict.get(k).get("value")))
+
+
+    def make_file_generate(self, feature_json):
+        """
+            Processing all keys and creation of a mk-file
+        """
+
+        with open(self.out_f, "w", encoding='UTF-8') as f_out:
+            f_out.write(FeatureProcessor.generate_header_guard())
+
+            f_security_setup_dict = feature_json.get('security_setup')
+
+            # handling of 'security_setup' section
+            if f_security_setup_dict:
+                self.__handle_dictionary(f_security_setup_dict, f_out)
+
+            self.__handle_dictionary(feature_json, f_out)
+
+
+@click.group()
+def cli():
+    """
+        Feature config parser to run from CLI
+    """
+
+@cli.command()
+@click.option('-f', '--feature_config', required=True,
+              help='feature configuration file path')
+@click.option('-p', '--platform_properties', required=True,
+              help='platform properties file path')
+@click.option('-n', '--output_name', required=True,
+              help='the name of the make file that will be generated')
+
+
+def run(feature_config, platform_properties, output_name):
+    """
+        The main CLI command to run mk-file generation
+    """
+
+    feature_config_json = load_json(feature_config)
+    platform_properties_json = load_json(platform_properties)
+
+    FieldsValidator.validate(feature_config_json, platform_properties_json)
+
+    fprocessor = FeatureProcessor(output_name)
+    fprocessor.make_file_generate(feature_config_json)
+
+
+if __name__ == '__main__':
+    cli()
diff --git a/boot/cypress/scripts/find_cysectools.py b/boot/cypress/scripts/find_cysectools.py
index 9aae88e..7bea0fc 100644
--- a/boot/cypress/scripts/find_cysectools.py
+++ b/boot/cypress/scripts/find_cysectools.py
@@ -17,7 +17,7 @@
 import subprocess
 import sys
 
-package = 'cysecuretools' 
+package = 'cysecuretools'
 
 def find_cysectools(package_name):
 
diff --git a/boot/cypress/scripts/flashmap.py b/boot/cypress/scripts/flashmap.py
deleted file mode 100644
index 856e430..0000000
--- a/boot/cypress/scripts/flashmap.py
+++ /dev/null
@@ -1,935 +0,0 @@
-"""MCUBoot Flash Map Converter (JSON to .h)
-Copyright (c) 2022 Infineon Technologies AG
-"""
-
-import sys
-import getopt
-import json
-
-# Supported Platforms
-cm0pCore = {
-    'cortex-m0+': 'CM0P',
-    'cm0+': 'CM0P',
-    'm0+': 'CM0P',
-    'cortex-m0p': 'CM0P',
-    'cm0p': 'CM0P',
-    'm0p': 'CM0P',
-    'cortex-m0plus': 'CM0P',
-    'cm0plus': 'CM0P',
-    'm0plus': 'CM0P'
-}
-
-cm4Core = {
-    'cortex-m4': 'CM4',
-    'cm4': 'CM4',
-    'm4': 'CM4'
-}
-
-cm33Core = {
-    'cortex-m33': 'CM33',
-    'cm33': 'CM33',
-    'm33': 'CM33'
-}
-
-allCores_PSOC_06x = {**cm0pCore, **cm4Core}
-
-common_PSOC_061 = {
-    'flashAddr': 0x10000000,
-    'eraseSize': 0x200,  # 512 bytes
-    'smifAddr': 0x18000000,
-    'smifSize': 0x8000000,  # i.e., window size
-    'VTAlign': 0x400,  # Vector Table alignment
-    'allCores': cm4Core,
-    'bootCore': 'Cortex-M4',
-    'appCore': 'Cortex-M4'
-}
-
-common_PSOC_06x = {
-    'flashAddr': 0x10000000,
-    'eraseSize': 0x200,  # 512 bytes
-    'smifAddr': 0x18000000,
-    'smifSize': 0x8000000,  # i.e., window size
-    'VTAlign': 0x400,  # Vector Table alignment
-    'allCores': allCores_PSOC_06x,
-    'bootCore': 'Cortex-M0+',
-    'appCore': 'Cortex-M4'
-}
-
-platDict = {
-    'PSOC_061_2M': {
-        'flashSize': 0x200000,  # 2 MBytes
-        **common_PSOC_061
-    },
-    'PSOC_061_1M': {
-        'flashSize': 0x100000,  # 1 MByte
-        **common_PSOC_061
-    },
-    'PSOC_061_512K': {
-        'flashSize': 0x80000,  # 512 KBytes
-        **common_PSOC_061
-    },
-
-    'PSOC_062_2M': {
-        'flashSize': 0x200000,  # 2 MBytes
-        **common_PSOC_06x
-    },
-    'PSOC_062_1M': {
-        'flashSize': 0x100000,  # 1 MByte
-        **common_PSOC_06x
-    },
-    'PSOC_062_512K': {
-        'flashSize': 0x80000,  # 512 KBytes
-        **common_PSOC_06x
-    },
-
-    'PSOC_063_1M': {
-        'flashSize': 0x100000,  # 1 MByte
-        **common_PSOC_06x
-    },
-
-    'CYW20829': {
-        'flashSize': 0,  # n/a
-        'smifAddr': 0x60000000,
-        'smifSize': 0x8000000,  # i.e., window size
-        'VTAlign': 0x200,  # Vector Table alignment
-        'allCores': cm33Core,
-        'bootCore': 'Cortex-M33',
-        'appCore': 'Cortex-M33',
-        'bitsPerCnt': False
-    },
-
-
-}
-
-# Supported SPI Flash ICs
-flashDict = {
-    # Fudan
-    'FM25Q04': {
-        'flashSize': 0x80000,  # 4 Mbits
-        'eraseSize': 0x1000,  # 128 uniform sectors with 4K-byte each
-    },
-    'FM25W04': {
-        'flashSize': 0x80000,  # 4 Mbits
-        'eraseSize': 0x1000,  # 128 uniform sectors with 4K-byte each
-    },
-    'FM25Q08': {
-        'flashSize': 0x100000,  # 8 Mbits
-        'eraseSize': 0x1000,  # 256 uniform sectors with 4K-byte each
-    },
-    'FM25W08': {
-        'flashSize': 0x100000,  # 8 Mbits
-        'eraseSize': 0x1000,  # 256 uniform sectors with 4K-byte each
-    },
-    # Puya
-    'P25Q05H': {
-        'flashSize': 0x10000,  # 512 Kbits
-        'eraseSize': 0x1000,  # Uniform 4K-byte Sector Erase
-    },
-    'P25Q10H': {
-        'flashSize': 0x20000,  # 1 Mbit
-        'eraseSize': 0x1000,  # Uniform 4K-byte Sector Erase
-    },
-    'P25Q20H': {
-        'flashSize': 0x40000,  # 2 Mbits
-        'eraseSize': 0x1000,  # Uniform 4K-byte Sector Erase
-    },
-    'P25Q40H': {
-        'flashSize': 0x80000,  # 4 Mbits
-        'eraseSize': 0x1000,  # Uniform 4K-byte Sector Erase
-    },
-    # Infineon
-    'S25HS256T': {
-        'flashSize': 0x2000000,  # 256 Mbits
-        'eraseSize': 0x40000,  # Uniform Sector Architecture
-    },
-    'S25HS512T': {
-        'flashSize': 0x4000000,  # 512 Mbits
-        'eraseSize': 0x40000,  # Uniform Sector Architecture
-    },
-    'S25HS01GT': {
-        'flashSize': 0x8000000,  # 1 Gbit
-        'eraseSize': 0x40000,  # Uniform Sector Architecture
-    }
-}
-
-
-def is_overlap(fa1off, fa1size, fa2off, fa2size, align):
-    """Check if two flash areas on the same device overlap"""
-    mask = align - 1
-    assert align > 0 and (align & mask) == 0  # ensure align is a power of 2
-    fa1end = (fa1off + fa1size + mask) & ~mask
-    fa2end = (fa2off + fa2size + mask) & ~mask
-    fa1off = fa1off & ~mask
-    fa2off = fa2off & ~mask
-    return fa1off < fa2end and fa2off < fa1end
-
-
-def is_same_mem(fa1addr, fa2addr):
-    """Check if two addresses belong to the same memory"""
-    if fa1addr is None or fa2addr is None:
-        return False
-    mask = 0xFF000000
-    return (fa1addr & mask) == (fa2addr & mask)
-
-
-class CmdLineParams:
-    """Command line parameters"""
-
-    def __init__(self):
-        self.plat_id = ''
-        self.in_file = ''
-        self.out_file = ''
-        self.img_id = None
-        self.policy = None
-        self.set_core = False
-
-        usage = 'USAGE:\n' + sys.argv[0] + \
-                ''' -p <platform> -i <flash_map.json> -o <flash_map.h> -d <img_id>
-
-OPTIONS:
--h  --help       Display the usage information
--p  --platform=  Target (e.g., PSOC_062_512K)
--i  --ifile=     JSON flash map file
--o  --ofile=     C header file to be generated
--d  --img_id     ID of application to build
--c  --policy     Policy file in JSON format
--m  --core       Detect and set Cortex-M CORE
-'''
-
-        try:
-            opts, unused = getopt.getopt(
-                sys.argv[1:], 'hi:o:p:d:c:m',
-                ['help', 'platform=', 'ifile=', 'ofile=', 'img_id=', 'policy=', 'core'])
-            if len(unused) > 0:
-                print(usage, file=sys.stderr)
-                sys.exit(1)
-        except getopt.GetoptError:
-            print(usage, file=sys.stderr)
-            sys.exit(1)
-
-        for opt, arg in opts:
-            if opt in ('-h', '--help'):
-                print(usage, file=sys.stderr)
-                sys.exit()
-            elif opt in ('-p', '--platform'):
-                self.plat_id = arg
-            elif opt in ('-i', '--ifile'):
-                self.in_file = arg
-            elif opt in ('-o', '--ofile'):
-                self.out_file = arg
-            elif opt in ('-d', '--img_id'):
-                self.img_id = arg
-            elif opt in ('-c', '--policy'):
-                self.policy = arg
-            elif opt in ('-m', '--core'):
-                self.set_core = True
-
-        if len(self.in_file) == 0 or len(self.out_file) == 0:
-            print(usage, file=sys.stderr)
-            sys.exit(1)
-
-
-class AreaList:
-    """List of flash areas"""
-
-    def __init__(self, plat, flash, use_overwrite):
-        self.plat = plat
-        self.flash = flash
-        self.use_overwrite = use_overwrite
-        self.areas = []
-        self.peers = {}
-        self.trailers = {}
-        self.internal_flash = False
-        self.external_flash = False
-        self.external_flash_xip = False
-
-    def get_min_erase_size(self):
-        """Calculate minimum erase block size for int./ext. Flash """
-        return self.plat['eraseSize'] if self.plat['flashSize'] > 0 \
-            else self.flash['eraseSize']
-
-    def get_img_trailer_size(self):
-        """Calculate image trailer size"""
-        return self.get_min_erase_size()
-
-    def process_int_area(self, title, fa_addr, fa_size,
-                         img_trailer_size, shared_slot):
-        """Process internal flash area"""
-        fa_device_id = 'FLASH_DEVICE_INTERNAL_FLASH'
-        fa_off = fa_addr - self.plat['flashAddr']
-        if img_trailer_size is not None:
-            if self.use_overwrite:
-                if shared_slot:
-                    print('Shared slot', title,
-                          'is not supported in OVERWRITE mode',
-                          file=sys.stderr)
-                    sys.exit(7)
-            else:
-                # Check trailer alignment (start at the sector boundary)
-                align = (fa_off + fa_size - img_trailer_size) % \
-                        self.plat['eraseSize']
-                if align != 0:
-                    fa_addr += self.plat['eraseSize'] - align
-                    if fa_addr + fa_size <= \
-                            self.plat['flashAddr'] + self.plat['flashSize']:
-                        print('Misaligned', title,
-                              '- suggested address', hex(fa_addr),
-                              file=sys.stderr)
-                    else:
-                        print('Misaligned', title, file=sys.stderr)
-                    sys.exit(7)
-        else:
-            # Check alignment (flash area should start at the sector boundary)
-            if fa_off % self.plat['eraseSize'] != 0:
-                print('Misaligned', title, file=sys.stderr)
-                sys.exit(7)
-        slot_sectors = int((fa_off % self.plat['eraseSize'] +
-                            fa_size + self.plat['eraseSize'] - 1) //
-                           self.plat['eraseSize'])
-        return fa_device_id, fa_off, slot_sectors
-
-    def process_ext_area(self, title, fa_addr, fa_size,
-                         img_trailer_size, shared_slot):
-        """Process external flash area"""
-        if self.flash is None:
-            print('Unspecified SPI Flash IC',
-                  file=sys.stderr)
-            sys.exit(3)
-        if fa_addr + fa_size <= \
-                self.plat['smifAddr'] + self.flash['flashSize']:
-            flash_idx = 'CY_BOOT_EXTERNAL_DEVICE_INDEX'
-            fa_device_id = f'FLASH_DEVICE_EXTERNAL_FLASH({flash_idx})'
-            fa_off = fa_addr - self.plat['smifAddr']
-        else:
-            print('Misfitting', title, file=sys.stderr)
-            sys.exit(7)
-        if img_trailer_size is not None:
-            if self.use_overwrite:
-                if shared_slot:
-                    print('Shared slot', title,
-                          'is not supported in OVERWRITE mode',
-                          file=sys.stderr)
-                    sys.exit(7)
-            else:
-                # Check trailer alignment (start at the sector boundary)
-                align = (fa_off + fa_size - img_trailer_size) % \
-                        self.flash['eraseSize']
-                if align != 0:
-                    peer_addr = self.peers.get(fa_addr)
-                    if shared_slot:
-                        # Special case when using both int. and ext. memory
-                        if self.plat['flashSize'] > 0 and \
-                                align % self.plat['eraseSize'] == 0:
-                            print('Note:', title, 'requires', align,
-                                  'padding bytes before trailer',
-                                  file=sys.stderr)
-                        else:
-                            print('Misaligned', title, file=sys.stderr)
-                            sys.exit(7)
-                    elif is_same_mem(fa_addr, peer_addr) and \
-                            fa_addr % self.flash['eraseSize'] == \
-                            peer_addr % self.flash['eraseSize']:
-                        pass  # postpone checking
-                    else:
-                        fa_addr += self.flash['eraseSize'] - align
-                        if fa_addr + fa_size <= \
-                                self.plat['smifAddr'] + self.flash['flashSize']:
-                            print('Misaligned', title,
-                                  '- suggested address', hex(fa_addr),
-                                  file=sys.stderr)
-                        else:
-                            print('Misaligned', title, file=sys.stderr)
-                        sys.exit(7)
-        else:
-            # Check alignment (flash area should start at the sector boundary)
-            if fa_off % self.flash['eraseSize'] != 0:
-                print('Misaligned', title, file=sys.stderr)
-                sys.exit(7)
-        slot_sectors = int((fa_off % self.flash['eraseSize'] +
-                            fa_size + self.flash['eraseSize'] - 1) //
-                           self.flash['eraseSize'])
-        self.external_flash = True
-        if self.flash['XIP']:
-            self.external_flash_xip = True
-        return fa_device_id, fa_off, slot_sectors
-
-    def chk_area(self, fa_addr, fa_size, peer_addr=None):
-        """Check area location (internal/external flash)"""
-        if peer_addr is not None:
-            self.peers[peer_addr] = fa_addr
-        fa_limit = fa_addr + fa_size
-        if self.plat['flashSize'] and \
-                fa_addr >= self.plat['flashAddr'] and \
-                fa_limit <= self.plat['flashAddr'] + self.plat['flashSize']:
-            # Internal flash
-            self.internal_flash = True
-
-    def add_area(self, title,
-                 fa_id, fa_addr, fa_size,
-                 img_trailer_size=None, shared_slot=False):
-        """Add flash area to AreaList.
-        Internal/external flash is detected by address.
-        Returns number of sectors in a slot"""
-        if fa_size == 0:
-            print('Empty', title, file=sys.stderr)
-            sys.exit(7)
-
-        fa_limit = fa_addr + fa_size
-        if self.plat['flashSize'] and \
-                fa_addr >= self.plat['flashAddr'] and \
-                fa_limit <= self.plat['flashAddr'] + self.plat['flashSize']:
-            # Internal flash
-            fa_device_id, fa_off, slot_sectors = self.process_int_area(
-                title, fa_addr, fa_size, img_trailer_size, shared_slot)
-            align = self.plat['eraseSize']
-        elif self.plat['smifSize'] and \
-                fa_addr >= self.plat['smifAddr'] and \
-                fa_limit <= self.plat['smifAddr'] + self.plat['smifSize']:
-            # External flash
-            fa_device_id, fa_off, slot_sectors = self.process_ext_area(
-                title, fa_addr, fa_size, img_trailer_size, shared_slot)
-            align = self.flash['eraseSize']
-        else:
-            print('Invalid', title, file=sys.stderr)
-            sys.exit(7)
-
-        if shared_slot:
-            assert img_trailer_size is not None
-            tr_addr = fa_addr + fa_size - img_trailer_size
-            tr_name = self.trailers.get(tr_addr)
-            if tr_name is not None:
-                print('Same trailer address for', title, 'and', tr_name,
-                      file=sys.stderr)
-                sys.exit(7)
-            self.trailers[tr_addr] = title
-
-        # Ensure no flash areas on this device will overlap, except the
-        # shared slot
-        for area in self.areas:
-            if fa_device_id == area['fa_device_id']:
-                over = is_overlap(fa_off, fa_size,
-                                  area['fa_off'], area['fa_size'],
-                                  align)
-                if shared_slot and area['shared_slot']:
-                    if not over:  # images in shared slot should overlap
-                        print(title, 'is not shared with', area['title'],
-                              file=sys.stderr)
-                        sys.exit(7)
-                elif over:
-                    print(title, 'overlaps with', area['title'],
-                          file=sys.stderr)
-                    sys.exit(7)
-
-        self.areas.append({'title': title,
-                           'shared_slot': shared_slot,
-                           'fa_id': fa_id,
-                           'fa_device_id': fa_device_id,
-                           'fa_off': fa_off,
-                           'fa_size': fa_size})
-        return slot_sectors
-
-    def generate_c_source(self, params):
-        """Generate C source"""
-        c_array = 'flash_areas'
-
-        try:
-            with open(params.out_file, "w", encoding='UTF-8') as out_f:
-                out_f.write('/* AUTO-GENERATED FILE, DO NOT EDIT.'
-                            ' ALL CHANGES WILL BE LOST! */\n')
-                out_f.write(f'/* Platform: {params.plat_id} */\n')
-                out_f.write("#ifndef CY_FLASH_MAP_H\n")
-                out_f.write("#define CY_FLASH_MAP_H\n\n")
-
-                if self.plat.get('bitsPerCnt'):
-                    out_f.write('#ifdef NEED_FLASH_MAP\n')
-                out_f.write(f'static struct flash_area {c_array}[] = {{\n')
-                comma = len(self.areas)
-                area_count = 0
-                for area in self.areas:
-                    comma -= 1
-                    if area['fa_id'] is not None:
-                        sss = ' /* Shared secondary slot */' \
-                            if area['shared_slot'] else ''
-                        out_f.writelines('\n'.join([
-                            '    {' + sss,
-                            f"        .fa_id        = {area['fa_id']},",
-                            f"        .fa_device_id = {area['fa_device_id']},",
-                            f"        .fa_off       = {hex(area['fa_off'])}U,",
-                            f"        .fa_size      = {hex(area['fa_size'])}U",
-                            '    },' if comma else '    }', '']))
-                        area_count += 1
-                out_f.write('};\n\n'
-                            'struct flash_area *boot_area_descs[] = {\n')
-                for area_index in range(area_count):
-                    out_f.write(f'    &{c_array}[{area_index}U],\n')
-                out_f.write('    NULL\n};\n')
-
-                if self.plat.get('bitsPerCnt'):
-                    out_f.write('#endif /* NEED_FLASH_MAP */\n')
-                    out_f.close()
-
-                    # inserted here to fix misra 'header guard'
-                    list_counters = process_policy_20829(params.policy)
-                    if list_counters is not None:
-                        form_max_counter_array(list_counters, params.out_file)
-                    with open(params.out_file, "a", encoding='UTF-8') as out_f:
-                        out_f.write("#endif /* CY_FLASH_MAP_H */\n")
-                else:
-                    out_f.write("#endif /* CY_FLASH_MAP_H */\n")
-
-        except (FileNotFoundError, OSError):
-            print('Cannot create', params.out_file, file=sys.stderr)
-            sys.exit(4)
-
-
-def cvt_dec_or_hex(val, desc):
-    """Convert (hexa)decimal string to number"""
-    try:
-        return int(val, 0)
-    except ValueError:
-        print('Invalid value', val, 'for', desc, file=sys.stderr)
-        sys.exit(6)
-
-
-def get_val(obj, attr):
-    """Get JSON 'value'"""
-    obj = obj[attr]
-    try:
-        return cvt_dec_or_hex(obj['value'], obj['description'])
-    except KeyError as key:
-        print('Malformed JSON:', key,
-              'is missing in', "'" + attr + "'",
-              file=sys.stderr)
-        sys.exit(5)
-
-
-def get_bool(obj, attr, def_val=False):
-    """Get JSON boolean value (returns def_val if it is missing)"""
-    ret_val = def_val
-    obj = obj.get(attr)
-    if obj is not None:
-        try:
-            val = str(obj['value']).lower()
-            desc = obj['description']
-            if val == 'true':
-                ret_val = True
-            elif val == 'false':
-                ret_val = False
-            else:
-                print('Invalid value', val, 'for', desc, file=sys.stderr)
-                sys.exit(6)
-        except KeyError as key:
-            print('Malformed JSON:', key,
-                  'is missing in', "'" + attr + "'",
-                  file=sys.stderr)
-            sys.exit(5)
-    return ret_val
-
-
-def get_str(obj, attr, def_val=None):
-    """Get JSON string value (returns def_val if it is missing)"""
-    ret_val = def_val
-    obj = obj.get(attr)
-    if obj is not None:
-        try:
-            ret_val = str(obj['value'])
-        except KeyError as key:
-            print('Malformed JSON:', key,
-                  'is missing in', "'" + attr + "'",
-                  file=sys.stderr)
-            sys.exit(5)
-    return ret_val
-
-
-class AddrSize:
-    """Bootloader area"""
-
-    def __init__(self, bootloader, addr_name, size_name):
-        self.fa_addr = get_val(bootloader, addr_name)
-        self.fa_size = get_val(bootloader, size_name)
-
-
-def calc_status_size(boot_swap_status_row_sz, max_img_sectors,
-                     img_number, scratch_flag=True):
-    """Estimate status size, see swap_status.h"""
-    boot_swap_status_cnt_sz = 4
-    boot_swap_status_crc_sz = 4
-    boot_swap_status_mgcrec_sz = 4
-    boot_swap_status_trailer_size = 64
-    boot_swap_status_payld_sz = \
-        boot_swap_status_row_sz - boot_swap_status_mgcrec_sz - \
-        boot_swap_status_cnt_sz - boot_swap_status_crc_sz
-    boot_swap_status_sect_rows_num = \
-        int((max_img_sectors - 1) //
-            boot_swap_status_payld_sz) + 1
-    boot_swap_status_trail_rows_num = \
-        int((boot_swap_status_trailer_size - 1) //
-            boot_swap_status_payld_sz) + 1
-    boot_swap_status_d_size = \
-        boot_swap_status_row_sz * \
-        (boot_swap_status_sect_rows_num + boot_swap_status_trail_rows_num)
-    boot_swap_status_mult = 2
-    boot_swap_status_size = boot_swap_status_mult * boot_swap_status_d_size
-    status_zone_cnt = 2 * img_number
-    if scratch_flag:
-        status_zone_cnt += 1
-    return boot_swap_status_size * status_zone_cnt
-
-
-def process_json(in_file):
-    """Process JSON"""
-    try:
-        with open(in_file, encoding='UTF-8') as in_f:
-            try:
-                flash_map = json.load(in_f)
-            except ValueError:
-                print('Cannot parse', in_file, file=sys.stderr)
-                sys.exit(4)
-    except (FileNotFoundError, OSError):
-        print('Cannot open', in_file, file=sys.stderr)
-        sys.exit(4)
-    flash = flash_map.get('external_flash')
-    if flash is not None:
-        flash = flash[0]
-        model = flash.get('model')
-        mode = flash.get('mode')
-        if model is not None:
-            try:
-                flash = flashDict[model]
-            except KeyError:
-                print('Supported SPI Flash ICs are:',
-                      ', '.join(flashDict.keys()),
-                      file=sys.stderr)
-                sys.exit(3)
-        else:
-            try:
-                flash = {'flashSize': cvt_dec_or_hex(flash['flash-size'],
-                                                     'flash-size'),
-                         'eraseSize': cvt_dec_or_hex(flash['erase-size'],
-                                                     'erase-size')}
-            except KeyError as key:
-                print('Malformed JSON:', key,
-                      "is missing in 'external_flash'",
-                      file=sys.stderr)
-                sys.exit(3)
-        flash.update({'XIP': str(mode).upper() == 'XIP'})
-    return flash_map['boot_and_upgrade'], flash
-
-
-def process_images(area_list, boot_and_upgrade):
-    """Process images"""
-    app_count = 0
-    slot_sectors_max = 0
-    all_shared = get_bool(boot_and_upgrade['bootloader'], 'shared_slot')
-    any_shared = all_shared
-    app_core = None
-    apps_flash_map = [None, ]
-
-    for stage in range(2):
-        for app_index in range(1, 5):
-
-            app_flash_map = {}
-
-            try:
-                app_ident = f'application_{app_index}'
-                application = boot_and_upgrade[app_ident]
-                try:
-                    primary_addr = get_val(application, 'address')
-                    primary_size = get_val(application, 'size')
-                    secondary_addr = get_val(application, 'upgrade_address')
-                    secondary_size = get_val(application, 'upgrade_size')
-                except KeyError as key:
-                    print('Malformed JSON:', key, 'is missing',
-                          file=sys.stderr)
-                    sys.exit(5)
-                if stage == 0:
-                    if primary_size != secondary_size:
-                        print('Primary and secondary slot sizes'
-                              ' are different for', app_ident,
-                              file=sys.stderr)
-                        sys.exit(6)
-                    area_list.chk_area(primary_addr, primary_size)
-                    area_list.chk_area(secondary_addr, secondary_size,
-                                       primary_addr)
-                    if application.get('core') is None:
-                        if app_index == 1:
-                            app_core = area_list.plat['appCore']
-                    elif app_index > 1:
-                        print('"core" makes sense only for the 1st app',
-                              file=sys.stderr)
-                        sys.exit(6)
-                    else:
-                        app_core = get_str(application, 'core',
-                                           area_list.plat['appCore'])
-                    if app_index == 1:
-                        app_core = area_list.plat['allCores'].get(app_core.lower())
-                        if app_core is None:
-                            print('Unknown "core"', file=sys.stderr)
-                            sys.exit(6)
-                else:
-                    slot_sectors_max = max(
-                        slot_sectors_max,
-                        area_list.add_area(
-                            f'{app_ident} (primary slot)',
-                            f'FLASH_AREA_IMG_{app_index}_PRIMARY',
-                            primary_addr, primary_size,
-                            area_list.get_img_trailer_size()))
-                    shared_slot = get_bool(application, 'shared_slot', all_shared)
-                    any_shared = any_shared or shared_slot
-                    slot_sectors_max = max(
-                        slot_sectors_max,
-                        area_list.add_area(
-                            f'{app_ident} (secondary slot)',
-                            f'FLASH_AREA_IMG_{app_index}_SECONDARY',
-                            secondary_addr, secondary_size,
-                            area_list.get_img_trailer_size(),
-                            shared_slot))
-
-                    app_slot_prim = {"address": hex(primary_addr), "size": hex(primary_size)}
-                    app_slot_sec = {"address": hex(secondary_addr), "size": hex(secondary_size)}
-
-                    app_flash_map.update({"primary": app_slot_prim, "secondary": app_slot_sec})
-                    apps_flash_map.append(app_flash_map)
-
-                app_count = app_index
-
-            except KeyError:
-                break
-        if app_count == 0:
-            print('Malformed JSON: no application(s) found',
-                  file=sys.stderr)
-            sys.exit(5)
-
-    return app_core, app_count, slot_sectors_max, apps_flash_map, any_shared
-
-def process_policy_20829(in_policy):
-    """Process policy file to get data of NV-counter"""
-    list_counters = None
-
-    try:
-        with open(in_policy, encoding='UTF-8') as in_f:
-            try:
-                policy = json.load(in_f)
-            except ValueError:
-                print('\nERROR: Cannot parse', in_policy,'\n', file=sys.stderr)
-                sys.exit(4)
-            finally:
-                in_f.close()
-    except (FileNotFoundError, OSError):
-        print('Cannot open', in_policy, file=sys.stderr)
-        sys.exit(4)
-
-    try:
-        nv_cnt = policy["device_policy"]['reprovisioning']['nv_counter']
-        list_values = nv_cnt["value"]
-        list_counters = nv_cnt["bits_per_cnt"]
-    except KeyError:
-        print("\nERROR: Check path to 'nv_counter' and its correctness in policy file", in_policy,
-            ".\n", file=sys.stderr)
-        sys.exit(2)
-
-    #Check correctness of NV-counter
-    try:
-        len_list_value = len(list_values)
-        len_list_counters = len(list_counters)
-    except TypeError:
-        print("\nERROR: Fields 'value' and 'bits_per_cnt' of 'nv_counter' in policy file",
-            in_policy,"must be arrays.\n", file=sys.stderr)
-        sys.exit(2)
-
-    if len_list_value != len_list_counters:
-        print("\nERROR: Fields 'value' and 'bits_per_cnt' of 'nv_counter' in policy file",
-            in_policy,"must have the same size.\n", file=sys.stderr)
-        sys.exit(2)
-
-    sum_all_counters = 0
-    for i in range(len_list_value):
-        sum_all_counters += list_counters[i]
-        if list_values[i] > list_counters[i]:
-            print("\nERROR: Field 'value' cannot be more then 'bits_per_cnt'.", file=sys.stderr)
-            print("Check 'nv_counter' in policy file", in_policy,"\n", file=sys.stderr)
-            sys.exit(2)
-
-    sum_all_bit_nv_counter = 32
-    if sum_all_counters != sum_all_bit_nv_counter:
-        print("\nERROR: The sum of all 'bits_per_cnt' must be equal to 32.", file=sys.stderr)
-        print("Check 'nv_counter' in policy file", in_policy,"\n", file=sys.stderr)
-        sys.exit(2)
-
-    return list_counters
-
-
-def form_max_counter_array(in_list, out_file):
-    '''Write bit_per_count array to output file
-    There is expected, that "out_file" already exists'''
-
-    out_array_str = "\n#ifdef NEED_MAX_COUNTERS\nstatic const uint8_t bits_per_cnt[] = {"
-
-    #in_list is checked in prior function 'process_policy()'
-    for i, list_member in enumerate(in_list):
-        out_array_str += str(list_member)
-        if i < len(in_list) - 1:
-            out_array_str += ", "
-    out_array_str += "};\n#endif\n"
-
-    try:
-        with open(out_file, "a", encoding='UTF-8') as out_f:
-            out_f.write(out_array_str)
-    except (FileNotFoundError, OSError):
-        print('\nERROR: Cannot open ', out_file, file=sys.stderr)
-        sys.exit(7)
-
-
-def main():
-    """Flash map converter"""
-    params = CmdLineParams()
-
-    try:
-        plat = platDict[params.plat_id]
-    except KeyError:
-        print('Supported platforms are:', ', '.join(platDict.keys()),
-              file=sys.stderr)
-        sys.exit(2)
-
-    try:
-        boot_and_upgrade, flash = process_json(params.in_file)
-        bootloader = boot_and_upgrade['bootloader']
-        boot = AddrSize(bootloader, 'address', 'size')
-    except KeyError as key:
-        print('Malformed JSON:', key, 'is missing',
-              file=sys.stderr)
-        sys.exit(5)
-
-    try:
-        scratch = AddrSize(bootloader, 'scratch_address', 'scratch_size')
-    except KeyError:
-        scratch = None
-
-    try:
-        swap_status = AddrSize(bootloader, 'status_address', 'status_size')
-    except KeyError:
-        swap_status = None
-
-    # Create flash areas
-    area_list = AreaList(plat, flash, scratch is None and swap_status is None)
-    area_list.add_area('bootloader', 'FLASH_AREA_BOOTLOADER',
-                       boot.fa_addr, boot.fa_size)
-
-    # Service RAM app (optional)
-    service_app = boot_and_upgrade.get('service_app')
-    app_binary = None
-    input_params = None
-    app_desc = None
-    if service_app is not None:
-        if plat['flashSize'] > 0:
-            print('service_app is unsupported on this platform',
-                  file=sys.stderr)
-            sys.exit(7)
-        try:
-            app_binary = AddrSize(service_app, 'address', 'size')
-            input_params = AddrSize(service_app, 'params_address', 'params_size')
-            app_desc = AddrSize(service_app, 'desc_address', 'desc_size')
-            if input_params.fa_addr != app_binary.fa_addr + app_binary.fa_size or \
-                    app_desc.fa_addr != input_params.fa_addr + input_params.fa_size or \
-                    app_desc.fa_size != 0x20:
-                print('Malformed service_app definition', file=sys.stderr)
-                sys.exit(7)
-            area_list.add_area('service_app', None, app_binary.fa_addr,
-                               app_binary.fa_size + input_params.fa_size + app_desc.fa_size)
-        except KeyError as key:
-            print('Malformed JSON:', key, 'is missing',
-                  file=sys.stderr)
-            sys.exit(5)
-
-    # Fill flash areas
-    app_core, app_count, slot_sectors_max, apps_flash_map, shared_slot = \
-        process_images(area_list, boot_and_upgrade)
-
-    cy_img_hdr_size = 0x400
-    app_start = int(apps_flash_map[1].get("primary").get("address"), 0) + cy_img_hdr_size
-
-    if app_start % plat['VTAlign'] != 0:
-        print('Starting address', apps_flash_map[1].get("primary").get("address"),
-              '+', hex(cy_img_hdr_size),
-              'must be aligned to', hex(plat['VTAlign']),
-              file=sys.stderr)
-        sys.exit(7)
-
-    slot_sectors_max = max(slot_sectors_max, 32)
-
-    if swap_status is not None:
-        status_size_min = calc_status_size(area_list.get_min_erase_size(),
-                                           slot_sectors_max,
-                                           app_count,
-                                           scratch is not None)
-
-        if swap_status.fa_size < status_size_min:
-            print('Insufficient swap status area - suggested size',
-                  hex(status_size_min),
-                  file=sys.stderr)
-            sys.exit(7)
-        area_list.add_area('swap status partition',
-                           'FLASH_AREA_IMAGE_SWAP_STATUS',
-                           swap_status.fa_addr, swap_status.fa_size)
-
-    if scratch is not None:
-        area_list.add_area('scratch area',
-                           'FLASH_AREA_IMAGE_SCRATCH',
-                           scratch.fa_addr, scratch.fa_size)
-
-    # Compare size 'bit_per_cnt' and number of images.
-    # 'service_app' is used only when HW rollback counter exists
-    if plat.get('bitsPerCnt') is not None and service_app is not None:
-        plat['bitsPerCnt'] = True
-        list_counters = process_policy_20829(params.policy)
-        if list_counters is not None and len(list_counters) != app_count:
-            print("\nERROR: 'bits_per_cnt' must be present for each image!",
-                file=sys.stderr)
-            print("Please, check secure provisioning and reprovisioning policies.\n",
-                file=sys.stderr)
-            sys.exit(7)
-
-
-    # Image id parameter is not used for MCUBootApp
-    if params.img_id is None:
-        area_list.generate_c_source(params)
-
-    # Report necessary values back to make
-    print('# AUTO-GENERATED FILE, DO NOT EDIT. ALL CHANGES WILL BE LOST!')
-    print('BOOTLOADER_SIZE :=', hex(boot.fa_size))
-    if params.set_core:
-        print('CORE :=', plat['allCores'][plat['bootCore'].lower()])
-    print('APP_CORE :=', app_core)
-
-    if params.img_id is not None:
-        primary_img_start = apps_flash_map[int(params.img_id)].get("primary").get("address")
-        secondary_img_start = apps_flash_map[int(params.img_id)].get("secondary").get("address")
-        slot_size = apps_flash_map[int(params.img_id)].get("primary").get("size")
-
-        print('PRIMARY_IMG_START := ' + primary_img_start)
-        print('SECONDARY_IMG_START := ' + secondary_img_start)
-        print('SLOT_SIZE := ' + slot_size)
-    else:
-        print('MCUBOOT_IMAGE_NUMBER :=', app_count)
-        print('MAX_IMG_SECTORS :=', slot_sectors_max)
-
-    if area_list.use_overwrite:
-        print('USE_OVERWRITE := 1')
-    if area_list.external_flash:
-        print('USE_EXTERNAL_FLASH := 1')
-        if area_list.external_flash_xip:
-            print('USE_XIP := 1')
-    if shared_slot:
-        print('USE_SHARED_SLOT := 1')
-    if service_app is not None:
-        print('PLATFORM_SERVICE_APP_OFFSET :=',
-              hex(app_binary.fa_addr - plat['smifAddr']))
-        print('PLATFORM_SERVICE_APP_INPUT_PARAMS_OFFSET :=',
-              hex(input_params.fa_addr - plat['smifAddr']))
-        print('PLATFORM_SERVICE_APP_DESC_OFFSET :=',
-              hex(app_desc.fa_addr - plat['smifAddr']))
-        print('USE_HW_ROLLBACK_PROT := 1')
-
-
-if __name__ == '__main__':
-    main()
diff --git a/boot/cypress/scripts/memorymap.py b/boot/cypress/scripts/memorymap.py
new file mode 100644
index 0000000..5511c9a
--- /dev/null
+++ b/boot/cypress/scripts/memorymap.py
@@ -0,0 +1,1434 @@
+"""MCUBoot Flash Map Converter (JSON to .h)
+Copyright (c) 2022 Infineon Technologies AG
+"""
+
+import sys
+import getopt
+import json
+from enum import Enum
+import os.path
+
+class Error(Enum):
+    ''' Application error codes '''
+    ARG             = 1
+    POLICY          = 2
+    FLASH           = 3
+    IO              = 4
+    JSON            = 5
+    VALUE           = 6
+    CONFIG_MISMATCH = 7
+
+SERVICE_APP_SZ = 0x20
+
+c_array = 'flash_areas'
+
+# Supported Platforms
+cm0pCore = {
+    'cortex-m0+': 'CM0P',
+    'cm0+': 'CM0P',
+    'm0+': 'CM0P',
+    'cortex-m0p': 'CM0P',
+    'cm0p': 'CM0P',
+    'm0p': 'CM0P',
+    'cortex-m0plus': 'CM0P',
+    'cm0plus': 'CM0P',
+    'm0plus': 'CM0P'
+}
+
+cm4Core = {
+    'cortex-m4': 'CM4',
+    'cm4': 'CM4',
+    'm4': 'CM4'
+}
+
+cm33Core = {
+    'cortex-m33': 'CM33',
+    'cm33': 'CM33',
+    'm33': 'CM33'
+}
+
+cm7Core = {
+    'cortex-m7': 'CM7',
+    'cm7': 'CM7',
+    'm7': 'CM7'
+}
+
+allCores_PSOC_06x = {**cm0pCore, **cm4Core}
+
+common_PSOC_061 = {
+    'flashAddr': 0x10000000,
+    'eraseSize': 0x200,  # 512 bytes
+    'smifAddr': 0x18000000,
+    'smifSize': 0x8000000,  # i.e., window size
+    'VTAlign': 0x400,  # Vector Table alignment
+    'allCores': cm4Core,
+    'bootCore': 'Cortex-M4',
+    'appCore': 'Cortex-M4'
+}
+
+common_PSOC_06x = {
+    'flashAddr': 0x10000000,
+    'eraseSize': 0x200,  # 512 bytes
+    'smifAddr': 0x18000000,
+    'smifSize': 0x8000000,  # i.e., window size
+    'VTAlign': 0x400,  # Vector Table alignment
+    'allCores': allCores_PSOC_06x,
+    'bootCore': 'Cortex-M0+',
+    'appCore': 'Cortex-M4'
+}
+
+common_XMC7000 = {
+    'flashAddr': 0x10000000,
+    'eraseSize': 0x8000,  # 512 bytes
+    'smifAddr': 0x18000000,
+    'smifSize': 0x8000000,  # i.e., window size
+    'VTAlign': 0x400,  # Vector Table alignment
+    'allCores': cm7Core,
+    'bootCore': 'Cortex-M7',
+    'appCore': 'Cortex-M7'
+}
+
+common_PSE84 = {
+    'flashAddr': 0x32000000,
+    'flashSize': 0x40000,
+    'eraseSize': 0x20,  # 32 bytes
+    'smifAddr': 0x60000000, #secure address 
+    'smifSize': 0x4000000,  # i.e., window size
+    'VTAlign': 0x400,  # Vector Table alignment
+    'allCores': cm33Core,
+    'bootCore': 'Cortex-M33',
+    'appCore': 'Cortex-M33'
+}
+
+platDict = {
+    'PSOC_061_2M': {
+        'flashSize': 0x200000,  # 2 MBytes
+        **common_PSOC_061
+    },
+    'PSOC_061_1M': {
+        'flashSize': 0x100000,  # 1 MByte
+        **common_PSOC_061
+    },
+    'PSOC_061_512K': {
+        'flashSize': 0x80000,  # 512 KBytes
+        **common_PSOC_061
+    },
+
+    'PSOC_062_2M': {
+        'flashSize': 0x200000,  # 2 MBytes
+        **common_PSOC_06x
+    },
+    'PSOC_062_1M': {
+        'flashSize': 0x100000,  # 1 MByte
+        **common_PSOC_06x
+    },
+    'PSOC_062_512K': {
+        'flashSize': 0x80000,  # 512 KBytes
+        **common_PSOC_06x
+    },
+
+    'PSOC_063_1M': {
+        'flashSize': 0x100000,  # 1 MByte
+        **common_PSOC_06x
+    },
+
+    'XMC7200': {
+        'flashSize': 0x100000,  # 1 MByte
+        **common_XMC7000
+    },
+
+    'XMC7100': {
+        'flashSize': 0x100000,  # 1 MByte
+        **common_PSOC_06x
+    },
+
+    'CYW20829': {
+        'flashSize': 0,  # n/a
+        'smifAddr': 0x60000000,
+        'smifSize': 0x8000000,  # i.e., window size
+        'VTAlign': 0x200,  # Vector Table alignment
+        'allCores': cm33Core,
+        'bootCore': 'Cortex-M33',
+        'appCore': 'Cortex-M33',
+        'bitsPerCnt': False
+    },
+
+    'PSE84_L4': {
+        **common_PSE84
+    },
+
+    'PSE84_L2': {
+        **common_PSE84
+    }
+}
+
+# Supported SPI Flash ICs
+flashDict = {
+    # Fudan
+    'FM25Q04': {
+        'flashSize': 0x80000,  # 4 Mbits
+        'eraseSize': 0x1000,  # 128 uniform sectors with 4K-byte each
+    },
+    'FM25W04': {
+        'flashSize': 0x80000,  # 4 Mbits
+        'eraseSize': 0x1000,  # 128 uniform sectors with 4K-byte each
+    },
+    'FM25Q08': {
+        'flashSize': 0x100000,  # 8 Mbits
+        'eraseSize': 0x1000,  # 256 uniform sectors with 4K-byte each
+    },
+    'FM25W08': {
+        'flashSize': 0x100000,  # 8 Mbits
+        'eraseSize': 0x1000,  # 256 uniform sectors with 4K-byte each
+    },
+    # Puya
+    'P25Q05H': {
+        'flashSize': 0x10000,  # 512 Kbits
+        'eraseSize': 0x1000,  # Uniform 4K-byte Sector Erase
+    },
+    'P25Q10H': {
+        'flashSize': 0x20000,  # 1 Mbit
+        'eraseSize': 0x1000,  # Uniform 4K-byte Sector Erase
+    },
+    'P25Q20H': {
+        'flashSize': 0x40000,  # 2 Mbits
+        'eraseSize': 0x1000,  # Uniform 4K-byte Sector Erase
+    },
+    'P25Q40H': {
+        'flashSize': 0x80000,  # 4 Mbits
+        'eraseSize': 0x1000,  # Uniform 4K-byte Sector Erase
+    },
+    # Infineon
+    'S25HS256T': {
+        'flashSize': 0x2000000,  # 256 Mbits
+        'eraseSize': 0x40000,  # Uniform Sector Architecture
+    },
+    'S25HS512T': {
+        'flashSize': 0x4000000,  # 512 Mbits
+        'eraseSize': 0x40000,  # Uniform Sector Architecture
+    },
+    'S25HS01GT': {
+        'flashSize': 0x8000000,  # 1 Gbit
+        'eraseSize': 0x40000,  # Uniform Sector Architecture
+    }
+}
+
+
+def is_overlap(fa1off, fa1size, fa2off, fa2size, align):
+    """Check if two flash areas on the same device overlap"""
+    mask = align - 1
+    assert align > 0 and (align & mask) == 0  # ensure align is a power of 2
+    fa1end = (fa1off + fa1size + mask) & ~mask
+    fa2end = (fa2off + fa2size + mask) & ~mask
+    fa1off = fa1off & ~mask
+    fa2off = fa2off & ~mask
+    return fa1off < fa2end and fa2off < fa1end
+
+
+def is_same_mem(fa1addr, fa2addr):
+    """Check if two addresses belong to the same memory"""
+    if fa1addr is None or fa2addr is None:
+        return False
+    mask = 0xFF000000
+    return (fa1addr & mask) == (fa2addr & mask)
+
+
+class CmdLineParams:
+    """Command line parameters"""
+
+    def __init__(self):
+        self.plat_id = ''
+        self.in_file = ''
+        self.out_file = ''
+        self.fa_file = ''
+        self.img_id = None
+        self.policy = None
+        self.set_core = False
+        self.image_boot_config = False
+
+        usage = 'USAGE:\n' + sys.argv[0] + \
+                ''' -p <platform> -i <flash_map.json> -o <memorymap.c> -a <memorymap.h> -d <img_id> -c <policy.json>
+
+OPTIONS:
+-h  --help       Display the usage information
+-p  --platform=  Target (e.g., PSOC_062_512K)
+-i  --ifile=     JSON flash map file
+-o  --ofile=     C file to be generated
+-a  --fa_file=   path where to create 'memorymap.h'
+-d  --img_id     ID of application to build
+-c  --policy     Policy file in JSON format
+-m  --core       Detect and set Cortex-M CORE
+-x  --image_boot_config Generate image boot config structure
+'''
+
+        try:
+            opts, unused = getopt.getopt(
+                sys.argv[1:], 'hi:o:a:p:d:c:x:m',
+                ['help', 'platform=', 'ifile=', 'ofile=', "fa_file=", 'img_id=', 'policy=', 'core', 'image_boot_config'])
+        except getopt.GetoptError:
+            print(usage, file=sys.stderr)
+            sys.exit(Error.ARG)
+
+        for opt, arg in opts:
+            if opt in ('-h', '--help'):
+                print(usage, file=sys.stderr)
+                sys.exit()
+            elif opt in ('-p', '--platform'):
+                self.plat_id = arg
+            elif opt in ('-i', '--ifile'):
+                self.in_file = arg
+            elif opt in ('-o', '--ofile'):
+                self.out_file = arg
+            elif opt in ('-a', '--fa_file'):
+                self.fa_file = arg
+            elif opt in ('-d', '--img_id'):
+                self.img_id = arg
+            elif opt in ('-c', '--policy'):
+                self.policy = arg
+            elif opt in ('-m', '--core'):
+                self.set_core = True
+            elif opt in ('x', '--image_boot_config'):
+                self.image_boot_config = True
+
+        if len(self.in_file) == 0 or len(self.out_file) == 0 or len(self.fa_file) == 0:
+            print(usage, file=sys.stderr)
+            sys.exit(Error.ARG)
+
+
+class AreaList:
+    '''
+    A List of flash areas
+    ...
+
+    Attributes
+    ----------
+    plat : dict
+        Platform settings
+
+    flash : dict
+        External flash settings
+
+    use_overwrite : bool
+        Overwrite configuration in use
+
+    areas : list
+        Flash area parameter list
+
+    peers : set
+        Peers
+
+    trailers : set
+        Flash area trailers
+
+    internal_flash : bool
+        Internal flash in use
+
+    external_flash : bool
+        External flash in use
+
+    external_flash_xip : bool
+        External XIP in use
+
+    Methods
+    -------
+    get_min_erase_size:
+        Calculate minimum erase block size for int./ext. Flash
+
+    get_img_trailer_size:
+        Calculate image trailer size
+
+    process_int_area:
+        Process internal flash area
+
+    process_ext_area:
+        Process external flash area
+
+    chk_area:
+        Check area location (internal/external flash)
+
+    add_area:
+        Add flash area to AreaList.
+        Internal/external flash is detected by address.
+
+    generate_c_source:
+        Generate C source
+
+    create_flash_area_id:
+        Creates flash_area_id.h file.
+    '''
+
+    def __init__(self, plat, flash, use_overwrite):
+        self.plat = plat
+        self.flash = flash
+        self.use_overwrite = use_overwrite
+        self.areas = []
+        self.peers = {}
+        self.trailers = {}
+        self.internal_flash = False
+        self.external_flash = False
+        self.external_flash_xip = False
+
+    def get_min_erase_size(self):
+        '''Calculate minimum erase block size for int./ext. Flash '''
+        return self.plat['eraseSize'] if self.plat['flashSize'] > 0 \
+            else self.flash['eraseSize']
+
+    def get_img_trailer_size(self):
+        '''Calculate image trailer size'''
+        return self.get_min_erase_size()
+
+    def process_int_area(self, title, addr, fa_size,
+                         img_trailer_size, shared_slot):
+        '''
+        Process internal flash area
+        Parameters:
+        ----------
+        title : str
+            Area name
+
+        addr : int
+            Area address
+
+        fa_size : int
+            Area size
+
+        img_trailer_size : int
+            Trailer size
+
+        shared_slot : bool
+            Shared slot option in use
+
+        Returns:
+        ----------
+        fa_device_id : str
+
+        fa_off : int
+
+        slot_sectors : int
+        '''
+        fa_device_id = 'FLASH_DEVICE_INTERNAL_FLASH'
+        fa_off = addr - self.plat['flashAddr']
+        if img_trailer_size is not None:
+            if self.use_overwrite:
+                if shared_slot:
+                    print('Shared slot', title,
+                          'is not supported in OVERWRITE mode',
+                          file=sys.stderr)
+                    sys.exit(Error.CONFIG_MISMATCH)
+            else:
+                # Check trailer alignment (start at the sector boundary)
+                align = (fa_off + fa_size - img_trailer_size) % \
+                        self.plat['eraseSize']
+                if align != 0:
+                    addr += self.plat['eraseSize'] - align
+                    if addr + fa_size <= \
+                            self.plat['flashAddr'] + self.plat['flashSize']:
+                        print('Misaligned', title,
+                              '- suggested address', hex(addr),
+                              file=sys.stderr)
+                    else:
+                        print('Misaligned', title, file=sys.stderr)
+                    sys.exit(Error.CONFIG_MISMATCH)
+        else:
+            # Check alignment (flash area should start at the sector boundary)
+            if fa_off % self.plat['eraseSize'] != 0:
+                print('Misaligned', title, file=sys.stderr)
+                sys.exit(Error.CONFIG_MISMATCH)
+        slot_sectors = int((fa_off % self.plat['eraseSize'] +
+                            fa_size + self.plat['eraseSize'] - 1) //
+                           self.plat['eraseSize'])
+        return fa_device_id, fa_off, slot_sectors
+
+    def process_ext_area(self, title, addr, fa_size,
+                         img_trailer_size, shared_slot):
+        '''
+        Process external flash area
+        Parameters:
+        ----------
+        title : str
+            Area name
+
+        addr : int
+            Area address
+
+        fa_size : int
+            Area size
+
+        img_trailer_size : int
+            Trailer size
+
+        shared_slot : bool
+            Shared slot option in use
+
+        Returns:
+        ----------
+        fa_device_id : str
+
+        fa_off : int
+
+        slot_sectors : int
+        '''
+        if self.flash is None:
+            print('Unspecified SPI Flash IC',
+                  file=sys.stderr)
+            sys.exit(Error.FLASH)
+        if addr + fa_size <= \
+                self.plat['smifAddr'] + self.flash['flashSize']:
+            flash_idx = 'CY_BOOT_EXTERNAL_DEVICE_INDEX'
+            fa_device_id = f'FLASH_DEVICE_EXTERNAL_FLASH({flash_idx})'
+            fa_off = addr - self.plat['smifAddr']
+        else:
+            print('Misfitting', title, file=sys.stderr)
+            sys.exit(Error.CONFIG_MISMATCH)
+        if img_trailer_size is not None:
+            if self.use_overwrite:
+                if shared_slot:
+                    print('Shared slot', title,
+                          'is not supported in OVERWRITE mode',
+                          file=sys.stderr)
+                    sys.exit(Error.CONFIG_MISMATCH)
+            else:
+                # Check trailer alignment (start at the sector boundary)
+                align = (fa_off + fa_size - img_trailer_size) % \
+                        self.flash['eraseSize']
+                if align != 0:
+                    peer_addr = self.peers.get(addr)
+                    if shared_slot:
+                        # Special case when using both int. and ext. memory
+                        if self.plat['flashSize'] > 0 and \
+                                align % self.plat['eraseSize'] == 0:
+                            print('Note:', title, 'requires', align,
+                                  'padding bytes before trailer',
+                                  file=sys.stderr)
+                        else:
+                            print('Misaligned', title, file=sys.stderr)
+                            sys.exit(Error.CONFIG_MISMATCH)
+                    elif is_same_mem(addr, peer_addr) and \
+                            addr % self.flash['eraseSize'] == \
+                            peer_addr % self.flash['eraseSize']:
+                        pass  # postpone checking
+                    else:
+                        addr += self.flash['eraseSize'] - align
+                        if addr + fa_size <= \
+                                self.plat['smifAddr'] + self.flash['flashSize']:
+                            print('Misaligned', title,
+                                  '- suggested address', hex(addr),
+                                  file=sys.stderr)
+                        else:
+                            print('Misaligned', title, file=sys.stderr)
+                        sys.exit(Error.CONFIG_MISMATCH)
+        else:
+            # Check alignment (flash area should start at the sector boundary)
+            if fa_off % self.flash['eraseSize'] != 0:
+                print('Misaligned', title, file=sys.stderr)
+                sys.exit(Error.CONFIG_MISMATCH)
+        slot_sectors = int((fa_off % self.flash['eraseSize'] +
+                            fa_size + self.flash['eraseSize'] - 1) //
+                           self.flash['eraseSize'])
+        self.external_flash = True
+        if self.flash['XIP']:
+            self.external_flash_xip = True
+        return fa_device_id, fa_off, slot_sectors
+
+    def chk_area(self, addr, fa_size, peer_addr=None):
+        '''
+        Check area location (internal/external flash)
+        Parameters:
+        ----------
+        addr : int
+            Area address
+
+        fa_size : int
+            Area size
+
+        peer_addr : bool (optional)
+            Shared slot option in use
+
+        Returns:
+        ----------
+        None
+        '''
+        if peer_addr is not None:
+            self.peers[peer_addr] = addr
+        fa_limit = addr + fa_size
+        if self.plat['flashSize'] and \
+                addr >= self.plat['flashAddr'] and \
+                fa_limit <= self.plat['flashAddr'] + self.plat['flashSize']:
+            # Internal flash
+            self.internal_flash = True
+
+    def add_area(self, title,
+                 fa_id, addr, fa_size,
+                 img_trailer_size=None, shared_slot=False):
+        '''
+        Add flash area to AreaList.
+        Internal/external flash is detected by address.
+        Parameters:
+        ----------
+        title : str
+            Area name
+
+        fa_id : str
+            Area id
+
+        addr : int
+            Area address
+
+        fa_size : int
+            Area size
+
+        img_trailer_size : int
+            Trailer size (optional)
+
+        shared_slot : bool
+            Shared slot option in use (optional)
+
+        Returns:
+        ----------
+        slot_sectors : int
+            Number of sectors in a slot
+        '''
+        if fa_size == 0:
+            print('Empty', title, file=sys.stderr)
+            sys.exit(Error.CONFIG_MISMATCH)
+
+        fa_limit = addr + fa_size
+        if self.plat['flashSize'] and \
+                addr >= self.plat['flashAddr'] and \
+                fa_limit <= self.plat['flashAddr'] + self.plat['flashSize']:
+            # Internal flash
+            fa_device_id, fa_off, slot_sectors = self.process_int_area(
+                title, addr, fa_size, img_trailer_size, shared_slot)
+            align = self.plat['eraseSize']
+        elif self.plat['smifSize'] and \
+                addr >= self.plat['smifAddr'] and \
+                fa_limit <= self.plat['smifAddr'] + self.plat['smifSize']:
+            # External flash
+            fa_device_id, fa_off, slot_sectors = self.process_ext_area(
+                title, addr, fa_size, img_trailer_size, shared_slot)
+            align = self.flash['eraseSize']
+        else:
+            print('Invalid', title, file=sys.stderr)
+            sys.exit(Error.CONFIG_MISMATCH)
+
+        if shared_slot:
+            assert img_trailer_size is not None
+            tr_addr = addr + fa_size - img_trailer_size
+            tr_name = self.trailers.get(tr_addr)
+            if tr_name is not None:
+                print('Same trailer address for', title, 'and', tr_name,
+                      file=sys.stderr)
+                sys.exit(Error.CONFIG_MISMATCH)
+            self.trailers[tr_addr] = title
+
+        # Ensure no flash areas on this device will overlap, except the
+        # shared slot
+        for area in self.areas:
+            if fa_device_id == area['fa_device_id']:
+                over = is_overlap(fa_off, fa_size,
+                                  area['fa_off'], area['fa_size'],
+                                  align)
+                if shared_slot and area['shared_slot']:
+                    if not over:  # images in shared slot should overlap
+                        print(title, 'is not shared with', area['title'],
+                              file=sys.stderr)
+                        sys.exit(Error.CONFIG_MISMATCH)
+                elif over:
+                    print(title, 'overlaps with', area['title'],
+                          file=sys.stderr)
+                    sys.exit(Error.CONFIG_MISMATCH)
+
+        self.areas.append({'title': title,
+                           'shared_slot': shared_slot,
+                           'fa_id': fa_id,
+                           'fa_device_id': fa_device_id,
+                           'fa_off': fa_off,
+                           'fa_size': fa_size})
+        return slot_sectors
+
+    def generate_c_source(self, params):
+        '''
+        Generate C source
+        Parameters:
+        ----------
+        params : CmdLineParams
+            Application parameters
+
+        Returns:
+        ----------
+        None
+        '''
+        c_array = 'flash_areas'
+
+        try:
+            with open(params.out_file, "w", encoding='UTF-8') as out_f:
+
+                out_f.write(f'#include "{params.fa_file}"\n')
+                out_f.write(f'#include "flash_map_backend.h"\n\n')
+                out_f.write(f'#include "flash_map_backend_platform.h"\n\n')
+                out_f.write(f'struct flash_area {c_array}[] = {{\n')
+                comma = len(self.areas)
+                area_count = 0
+                for area in self.areas:
+                    comma -= 1
+                    if area['fa_id'] is not None:
+                        sss = ' /* Shared secondary slot */' \
+                            if area['shared_slot'] else ''
+                        out_f.writelines('\n'.join([
+                            '    {' + sss,
+                            f"        .fa_id        = {area['fa_id']},",
+                            f"        .fa_device_id = {area['fa_device_id']},",
+                            f"        .fa_off       = {hex(area['fa_off'])}U,",
+                            f"        .fa_size      = {hex(area['fa_size'])}U",
+                            '    },' if comma else '    }', '']))
+                        area_count += 1
+                out_f.write('};\n\n'
+                            'struct flash_area *boot_area_descs[] = {\n')
+                for area_index in range(area_count):
+                    out_f.write(f'    &{c_array}[{area_index}U],\n')
+                out_f.write('    NULL\n};\n')                
+                out_f.close()
+
+        except (FileNotFoundError, OSError):
+            print('Cannot create', params.out_file, file=sys.stderr)
+            sys.exit(Error.IO)
+
+    def create_flash_area_id(self, img_number, params):
+        """ Get 'img_number' and generate flash_area_id.h file' """
+
+        #check if params.fa_file already exists and it has FLASH_AREA_ID
+        if os.path.exists(params.fa_file):
+            with open(params.fa_file, "r", encoding='UTF-8') as fa_f:
+                content = fa_f.read()
+                res = content.find(f"FLASH_AREA_IMG_{img_number}_SECONDARY")
+                if res != -1:
+                    fa_f.close()
+                    return
+
+                fa_f.close()
+
+        try:
+            with open(params.fa_file, "w", encoding='UTF-8') as fa_f:
+                fa_f.write("#ifndef MEMORYMAP_H\n")
+                fa_f.write("#define MEMORYMAP_H\n\n")
+                fa_f.write('/* AUTO-GENERATED FILE, DO NOT EDIT.'
+                            ' ALL CHANGES WILL BE LOST! */\n')
+                fa_f.write(f'#include "flash_map_backend.h"\n\n')
+
+                fa_f.write(f'extern struct flash_area {c_array}[];\n')
+                fa_f.write(f'extern struct flash_area *boot_area_descs[];\n')
+
+                #we always have BOOTLOADER and IMG_1_
+                fa_f.write("#define FLASH_AREA_BOOTLOADER          ( 0u)\n\n")
+                fa_f.write("#define FLASH_AREA_IMG_1_PRIMARY       ( 1u)\n")
+                fa_f.write("#define FLASH_AREA_IMG_1_SECONDARY     ( 2u)\n\n")
+
+                fa_f.write("#define FLASH_AREA_IMAGE_SCRATCH       ( 3u)\n")
+                fa_f.write("#define FLASH_AREA_IMAGE_SWAP_STATUS   ( 7u)\n\n")
+
+                for img in range(2, img_number + 1):
+                    """ img_id_primary and img_id_secondary must be aligned with the
+                        flash_area_id, calculated in the functions
+                        __STATIC_INLINE uint8_t FLASH_AREA_IMAGE_PRIMARY(uint32_t img_idx) and
+                        __STATIC_INLINE uint8_t FLASH_AREA_IMAGE_SECONDARY(uint32_t img_idx),
+                        in boot/cypress/platforms/memory/sysflash/sysflash.h
+                    """
+
+                    slots_for_image = 2
+                    img_id_primary = None
+                    img_id_secondary = None
+
+                    if img == 2:
+                        img_id_primary = int(slots_for_image * img)
+                        img_id_secondary = int(slots_for_image * img + 1)
+
+                    #number 7 is used for FLASH_AREA_IMAGE_SWAP_STATUS, so the next is 8
+                    if img >= 3:
+                        img_id_primary = int(slots_for_image * img + 2)
+                        img_id_secondary = int(slots_for_image * img + 3)
+
+                    fa_f.write(f"#define FLASH_AREA_IMG_{img}_PRIMARY       ( {img_id_primary}u)\n")
+                    fa_f.write(f"#define FLASH_AREA_IMG_{img}_SECONDARY     ( {img_id_secondary}u)\n\n")
+                
+                if self.plat.get('bitsPerCnt'):
+                    fa_f.close()
+                    
+                    list_counters = process_policy_20829(params.policy)
+                    if list_counters is not None:
+                        form_max_counter_array(list_counters, params.fa_file)
+                else:
+                    fa_f.write("#endif /* MEMORYMAP_H */")
+                fa_f.close()
+
+        except (FileNotFoundError, OSError):
+            print('\nERROR: Cannot create ', params.fa_file, file=sys.stderr)
+            sys.exit(Error.IO)
+
+
+def cvt_dec_or_hex(val, desc):
+    """Convert (hexa)decimal string to number"""
+    try:
+        return int(val, 0)
+    except ValueError:
+        print('Invalid value', val, 'for', desc, file=sys.stderr)
+        sys.exit(Error.VALUE)
+
+
+def get_val(obj, attr):
+    """Get JSON 'value'"""
+    obj = obj[attr]
+    try:
+        return cvt_dec_or_hex(obj['value'], obj['description'])
+    except KeyError as key:
+        print('Malformed JSON:', key,
+              'is missing in', "'" + attr + "'",
+              file=sys.stderr)
+        sys.exit(Error.JSON)
+
+
+def get_bool(obj, attr, def_val=False):
+    """Get JSON boolean value (returns def_val if it is missing)"""
+    ret_val = def_val
+    obj = obj.get(attr)
+    if obj is not None:
+        try:
+            val = str(obj['value']).lower()
+            desc = obj['description']
+            if val == 'true':
+                ret_val = True
+            elif val == 'false':
+                ret_val = False
+            else:
+                print('Invalid value', val, 'for', desc, file=sys.stderr)
+                sys.exit(Error.VALUE)
+        except KeyError as key:
+            print('Malformed JSON:', key,
+                  'is missing in', "'" + attr + "'",
+                  file=sys.stderr)
+            sys.exit(Error.JSON)
+    return ret_val
+
+
+def get_str(obj, attr, def_val=None):
+    """Get JSON string value (returns def_val if it is missing)"""
+    ret_val = def_val
+    obj = obj.get(attr)
+    if obj is not None:
+        try:
+            ret_val = str(obj['value'])
+        except KeyError as key:
+            print('Malformed JSON:', key,
+                  'is missing in', "'" + attr + "'",
+                  file=sys.stderr)
+            sys.exit(Error.JSON)
+    return ret_val
+
+
+class AddrSize:
+    """Bootloader area"""
+
+    def __init__(self, bootloader, addr_name, size_name):
+        self.addr = get_val(bootloader, addr_name)
+        self.size = get_val(bootloader, size_name)
+
+
+def calc_status_size(boot_swap_status_row_sz, max_img_sectors,
+                     img_number, scratch_flag=True):
+    """Estimate status size, see swap_status.h"""
+    boot_swap_status_cnt_sz = 4
+    boot_swap_status_crc_sz = 4
+    boot_swap_status_mgcrec_sz = 4
+    boot_swap_status_trailer_size = 64
+    boot_swap_status_payld_sz = \
+        boot_swap_status_row_sz - boot_swap_status_mgcrec_sz - \
+        boot_swap_status_cnt_sz - boot_swap_status_crc_sz
+    boot_swap_status_sect_rows_num = \
+        int((max_img_sectors - 1) //
+            boot_swap_status_payld_sz) + 1
+    boot_swap_status_trail_rows_num = \
+        int((boot_swap_status_trailer_size - 1) //
+            boot_swap_status_payld_sz) + 1
+    boot_swap_status_d_size = \
+        boot_swap_status_row_sz * \
+        (boot_swap_status_sect_rows_num + boot_swap_status_trail_rows_num)
+    boot_swap_status_mult = 2
+    boot_swap_status_size = boot_swap_status_mult * boot_swap_status_d_size
+    status_zone_cnt = 2 * img_number
+    if scratch_flag:
+        status_zone_cnt += 1
+    return boot_swap_status_size * status_zone_cnt
+
+
+def process_json(in_file):
+    """Process JSON"""
+    try:
+        with open(in_file, encoding='UTF-8') as in_f:
+            try:
+                flash_map = json.load(in_f)
+            except ValueError:
+                print('Cannot parse', in_file, file=sys.stderr)
+                sys.exit(Error.IO)
+    except (FileNotFoundError, OSError):
+        print('Cannot open', in_file, file=sys.stderr)
+        sys.exit(Error.IO)
+    flash = flash_map.get('external_flash')
+    if flash is not None:
+        flash = flash[0]
+        model = flash.get('model')
+        mode = flash.get('mode')
+        if model is not None:
+            try:
+                flash = flashDict[model]
+            except KeyError:
+                print('Supported SPI Flash ICs are:',
+                      ', '.join(flashDict.keys()),
+                      file=sys.stderr)
+                sys.exit(Error.FLASH)
+        else:
+            try:
+                flash = {'flashSize': cvt_dec_or_hex(flash['flash-size'],
+                                                     'flash-size'),
+                         'eraseSize': cvt_dec_or_hex(flash['erase-size'],
+                                                     'erase-size')}
+            except KeyError as key:
+                print('Malformed JSON:', key,
+                      "is missing in 'external_flash'",
+                      file=sys.stderr)
+                sys.exit(Error.FLASH)
+        flash.update({'XIP': str(mode).upper() == 'XIP'})
+    return flash_map.get('boot_and_upgrade', None), flash_map.get('ram_app_staging', None), flash
+
+def process_boot_type(boot_and_upgrade):
+    image_boot_mode = []
+
+    for app_index in range(1, 5):
+        app_ident = f'application_{app_index}'
+        application = boot_and_upgrade.get(app_ident)
+
+        if application:
+            ram = application.get('ram', application.get('ram_boot'))
+
+            if ram:
+                image_boot_mode.append(
+                    {
+                        'mode': 'IMAGE_BOOT_MODE_FLASH' if application.get('ram') else 'IMAGE_BOOT_MODE_RAM',
+                        'address': ram.get('address', {}).get('value', 0),
+                        'size': ram.get('size', {}).get('value', 0),
+                    }
+                )
+
+    return image_boot_mode
+
+def generate_boot_type(image_boot_mode):
+    c_file = "image_boot_config.c"
+    h_file = "image_boot_config.h"
+    try:
+        with open(c_file, "w", encoding='UTF-8') as out_f:
+            out_f.write('/* AUTO-GENERATED FILE, DO NOT EDIT.'
+                        ' ALL CHANGES WILL BE LOST! */\n')
+            
+            out_f.write(f'#include "{h_file}"\n')
+            out_f.write('\nimage_boot_config_t image_boot_config[BOOT_IMAGE_NUMBER] = {\n')
+            for mode in image_boot_mode:
+                out_f.writelines('\n'.join([
+                    '\t{\n'
+                    f"\t\t.mode     = {mode['mode']},",
+                    f"\t\t.address  = {mode['address']},",
+                    f"\t\t.size     = {mode['size']},",
+                    '\t},\n']))
+            out_f.write('};\n')
+
+        with open(h_file, "w", encoding='UTF-8') as out_f:
+            out_f.write('/* AUTO-GENERATED FILE, DO NOT EDIT.'
+                        ' ALL CHANGES WILL BE LOST! */\n')
+            out_f.write('#ifndef IMAGE_BOOT_CONFIG_H\n')
+            out_f.write('#define IMAGE_BOOT_CONFIG_H\n')
+            out_f.write('#include "bootutil/bootutil.h"\n')
+            out_f.writelines('\n'.join([
+                ' ',
+                'typedef enum',
+                '{',
+                    '\tIMAGE_BOOT_MODE_FLASH = 0U,',
+                    '\tIMAGE_BOOT_MODE_RAM = 1U,',
+                '} image_boot_mode_t;',
+                '',
+                'typedef struct image_boot_config_s {',
+                    '\timage_boot_mode_t mode;',
+                    '\tuint32_t address;',
+                    '\tuint32_t size;',
+                '} image_boot_config_t;',
+                '',
+                'extern image_boot_config_t image_boot_config[BOOT_IMAGE_NUMBER];'
+            ]))
+            out_f.write('\n#endif /* IMAGE_BOOT_CONFIG_H */\n')
+
+    except (FileNotFoundError, OSError):
+        print('Cannot create', out_f, file=sys.stderr)
+        sys.exit(Error.IO)
+                         
+
+def process_images(area_list, boot_and_upgrade):
+    """Process images"""
+    app_count = 0
+    slot_sectors_max = 0
+    all_shared = get_bool(boot_and_upgrade['bootloader'], 'shared_slot')
+    any_shared = all_shared
+    app_core = None
+    apps_flash_map = [None, ]
+    apps_ram_map = [None, ]
+
+    for stage in range(2):
+        for app_index in range(1, 5):
+
+            app_flash_map = {}
+            app_ram_map = {}
+            app_ram_boot = False
+
+            try:
+                app_ident = f'application_{app_index}'
+                application = boot_and_upgrade[app_ident]
+
+                try:
+                    flash = application['flash']
+                except KeyError:
+                    #Backward compatibility
+                    flash = application
+
+                try:
+                    config = application['config']
+                except KeyError:
+                    #Backward compatibility
+                    config = application
+
+                try:
+                    ram = application['ram']
+                except KeyError:
+                    try:
+                        ram = application['ram_boot']
+                        app_ram_boot = True
+                    except KeyError:
+                        ram = None
+
+                try:
+                    primary_addr = get_val(flash, 'address')
+                    primary_size = get_val(flash, 'size')
+                    secondary_addr = get_val(flash, 'upgrade_address')
+                    secondary_size = get_val(flash, 'upgrade_size')
+
+                    if ram is not None:
+                        app_ram_addr = get_val(ram, 'address')
+                        app_ram_size = get_val(ram, 'size')
+                    else:
+                        app_ram_addr = None
+                        app_ram_size = None
+
+                except KeyError as key:
+                    print('Malformed JSON:', key, 'is missing',
+                          file=sys.stderr)
+                    sys.exit(Error.JSON)
+                if stage == 0:
+                    if primary_size != secondary_size:
+                        print('Primary and secondary slot sizes'
+                              ' are different for', app_ident,
+                              file=sys.stderr)
+                        sys.exit(Error.VALUE)
+                    area_list.chk_area(primary_addr, primary_size)
+                    area_list.chk_area(secondary_addr, secondary_size,
+                                       primary_addr)
+                    if config is None or config.get('core') is None:
+                        if app_index == 1:
+                            app_core = area_list.plat['appCore']
+                    elif app_index > 1:
+                        print('"core" makes sense only for the 1st app',
+                              file=sys.stderr)
+                        sys.exit(Error.VALUE)
+                    else:
+                        app_core = get_str(config, 'core',
+                                           area_list.plat['appCore'])
+                    if app_index == 1:
+                        app_core = area_list.plat['allCores'].get(app_core.lower())
+                        if app_core is None:
+                            print('Unknown "core"', file=sys.stderr)
+                            sys.exit(Error.VALUE)
+                else:
+                    slot_sectors_max = max(
+                        slot_sectors_max,
+                        area_list.add_area(
+                            f'{app_ident} (primary slot)',
+                            f'FLASH_AREA_IMG_{app_index}_PRIMARY',
+                            primary_addr, primary_size,
+                            area_list.get_img_trailer_size()))
+                    shared_slot = get_bool(flash, 'shared_slot', all_shared)
+                    any_shared = any_shared or shared_slot
+                    slot_sectors_max = max(
+                        slot_sectors_max,
+                        area_list.add_area(
+                            f'{app_ident} (secondary slot)',
+                            f'FLASH_AREA_IMG_{app_index}_SECONDARY',
+                            secondary_addr, secondary_size,
+                            area_list.get_img_trailer_size(),
+                            shared_slot))
+
+                    app_slot_prim = {"address": hex(primary_addr), "size": hex(primary_size)}
+                    app_slot_sec = {"address": hex(secondary_addr), "size": hex(secondary_size)}
+
+                    app_flash_map.update({"primary": app_slot_prim, "secondary": app_slot_sec})
+                    apps_flash_map.append(app_flash_map)
+
+                    if ram is not None:
+                        app_ram_map.update({"address": app_ram_addr
+                                            , "size": app_ram_size
+                                            , "ram_boot": app_ram_boot})
+                        apps_ram_map.append(app_ram_map)
+                    else:
+                        apps_ram_map = None
+
+                app_count = app_index
+
+            except KeyError:
+                break
+        if app_count == 0:
+            print('Malformed JSON: no application(s) found',
+                  file=sys.stderr)
+            sys.exit(Error.JSON)
+
+    return app_core, app_count, slot_sectors_max, apps_flash_map, apps_ram_map, any_shared
+
+
+def process_policy_20829(in_policy):
+    """Process policy file to get data of NV-counter"""
+    list_counters = None
+
+    try:
+        with open(in_policy, encoding='UTF-8') as in_f:
+            try:
+                policy = json.load(in_f)
+            except ValueError:
+                print('\nERROR: Cannot parse', in_policy,'\n', file=sys.stderr)
+                sys.exit(Error.IO)
+            finally:
+                in_f.close()
+    except (FileNotFoundError, OSError):
+        print('Cannot open', in_policy, file=sys.stderr)
+        sys.exit(Error.IO)
+
+    try:
+        nv_cnt = policy["device_policy"]['reprovisioning']['nv_counter']
+        list_values = nv_cnt["value"]
+        list_counters = nv_cnt["bits_per_cnt"]
+    except KeyError:
+        print("\nERROR: Check path to 'nv_counter' and its correctness in policy file", in_policy,
+            ".\n", file=sys.stderr)
+        sys.exit(Error.POLICY)
+
+    #Check correctness of NV-counter
+    try:
+        len_list_value = len(list_values)
+        len_list_counters = len(list_counters)
+    except TypeError:
+        print("\nERROR: Fields 'value' and 'bits_per_cnt' of 'nv_counter' in policy file",
+            in_policy,"must be arrays.\n", file=sys.stderr)
+        sys.exit(Error.POLICY)
+
+    if len_list_value != len_list_counters:
+        print("\nERROR: Fields 'value' and 'bits_per_cnt' of 'nv_counter' in policy file",
+            in_policy,"must have the same size.\n", file=sys.stderr)
+        sys.exit(Error.POLICY)
+
+    sum_all_counters = 0
+    for i in range(len_list_value):
+        sum_all_counters += list_counters[i]
+        if list_values[i] > list_counters[i]:
+            print("\nERROR: Field 'value' cannot be more then 'bits_per_cnt'.", file=sys.stderr)
+            print("Check 'nv_counter' in policy file", in_policy,"\n", file=sys.stderr)
+            sys.exit(Error.POLICY)
+
+    sum_all_bit_nv_counter = 32
+    if sum_all_counters != sum_all_bit_nv_counter:
+        print("\nERROR: The sum of all 'bits_per_cnt' must be equal to 32.", file=sys.stderr)
+        print("Check 'nv_counter' in policy file", in_policy,"\n", file=sys.stderr)
+        sys.exit(Error.POLICY)
+
+    return list_counters
+
+
+def form_max_counter_array(in_list, out_file):
+    '''Write bit_per_count array to output file
+    There is expected, that "out_file" already exists'''
+
+    #ifdef here is needed to fix Rule 12.2 MISRA violation
+    out_array_str = "\n#ifdef NEED_MAX_COUNTERS\nstatic const uint8_t bits_per_cnt[] = {"
+
+    #in_list is checked in prior function 'process_policy()'
+    for i, list_member in enumerate(in_list):
+        out_array_str += str(list_member)
+        if i < len(in_list) - 1:
+            out_array_str += ", "
+    out_array_str += "};\n#endif\n"
+
+    try:
+        with open(out_file, "a", encoding='UTF-8') as out_f:
+            out_f.write(out_array_str)
+            out_f.write("\n#endif /* MEMORYMAP_H */")
+    except (FileNotFoundError, OSError):
+        print('\nERROR: Cannot open ', out_file, file=sys.stderr)
+        sys.exit(Error.CONFIG_MISMATCH)
+
+
+def main():
+    """Flash map converter"""
+    params = CmdLineParams()
+
+    try:
+        plat = platDict[params.plat_id]
+    except KeyError:
+        print('Supported platforms are:', ', '.join(platDict.keys()),
+              file=sys.stderr)
+        sys.exit(Error.POLICY)
+
+    try:
+        boot_and_upgrade, ram_app_staging, flash = process_json(params.in_file)
+        bootloader = boot_and_upgrade['bootloader']
+        try:
+            bootloader_config = bootloader['config']
+        except KeyError:
+            #Backward compatibility
+            bootloader_config = bootloader
+
+        if ram_app_staging is not None:
+            try:
+                ram_app_staging_size = get_val(ram_app_staging, 'size')
+                ram_app_staging_ext_mem_addr = get_val(ram_app_staging, 'external_mememory_address')
+                ram_app_staging_sram_stage_addr = get_val(ram_app_staging, 'sram_stage_address')
+                ram_app_staging_reset_trigger = get_bool(ram_app_staging, 'reset_after_staging')
+            except KeyError:
+                ram_app_staging = None
+
+        try:
+            bootloader_flash = bootloader['flash']
+        except KeyError:
+            #Backward compatibility
+            bootloader_flash = bootloader
+
+        try:
+            bootloader_ram = bootloader['ram']
+        except KeyError:
+            #Backward compatibility
+            bootloader_ram = bootloader
+
+        boot_flash_area = AddrSize(bootloader_flash, 'address', 'size')
+        boot_ram_area = AddrSize(bootloader_ram, 'address', 'size')
+    except KeyError as key:
+        print('Malformed JSON:', key, 'is missing',
+              file=sys.stderr)
+        sys.exit(Error.JSON)
+
+    try:
+        scratch = AddrSize(bootloader_flash, 'scratch_address', 'scratch_size')
+    except KeyError:
+        scratch = None
+
+    try:
+        swap_status = AddrSize(bootloader_flash, 'status_address', 'status_size')
+    except KeyError:
+        swap_status = None
+
+    try:
+        bootloader_shared_data = bootloader['shared_data']
+        boot_shared_data_area = AddrSize(bootloader_shared_data, 'address', 'size')
+    except KeyError:
+        boot_shared_data_area = None
+
+    try:
+        bootloader_startup = get_bool(bootloader_config, 'startup')
+    except KeyError:
+        bootloader_startup = None
+
+    try:
+        ram_app_area = AddrSize(bootloader_config['ram_boot'], 'address', 'size')
+    except  KeyError:
+        ram_app_area = None
+
+
+    # Create flash areas
+    area_list = AreaList(plat, flash, scratch is None and swap_status is None)
+    area_list.add_area('bootloader', 'FLASH_AREA_BOOTLOADER',
+                       boot_flash_area.addr, boot_flash_area.size)
+
+    # Service RAM app (optional)
+    service_app = boot_and_upgrade.get('service_app')
+    app_binary = None
+    input_params = None
+    app_desc = None
+    if service_app is not None:
+        if plat['flashSize'] > 0:
+            print('service_app is unsupported on this platform',
+                  file=sys.stderr)
+            sys.exit(Error.CONFIG_MISMATCH)
+        try:
+            app_binary = AddrSize(service_app, 'address', 'size')
+            input_params = AddrSize(service_app, 'params_address', 'params_size')
+            app_desc = AddrSize(service_app, 'desc_address', 'desc_size')
+            if input_params.addr != app_binary.addr + app_binary.size or \
+                    app_desc.addr != input_params.addr + input_params.size or \
+                    app_desc.size != SERVICE_APP_SZ:
+                print('Malformed service_app definition', file=sys.stderr)
+                sys.exit(Error.CONFIG_MISMATCH)
+            area_list.add_area('service_app', None, app_binary.addr,
+                               app_binary.size + input_params.size + app_desc.size)
+        except KeyError as key:
+            print('Malformed JSON:', key, 'is missing',
+                  file=sys.stderr)
+            sys.exit(Error.JSON)
+
+    # Fill flash areas
+    app_core, app_count, slot_sectors_max, apps_flash_map, apps_ram_map, shared_slot = \
+        process_images(area_list, boot_and_upgrade)
+
+    if params.image_boot_config:
+        image_boot_mode = process_boot_type(boot_and_upgrade)
+
+        if image_boot_mode:
+            generate_boot_type(image_boot_mode)
+
+    cy_img_hdr_size = 0x400
+    app_start = int(apps_flash_map[1].get("primary").get("address"), 0) + cy_img_hdr_size
+
+    if app_start % plat['VTAlign'] != 0:
+        print('Starting address', apps_flash_map[1].get("primary").get("address"),
+              '+', hex(cy_img_hdr_size),
+              'must be aligned to', hex(plat['VTAlign']),
+              file=sys.stderr)
+        sys.exit(Error.CONFIG_MISMATCH)
+
+    slot_sectors_max = max(slot_sectors_max, 32)
+
+    if swap_status is not None:
+        status_size_min = calc_status_size(area_list.get_min_erase_size(),
+                                           slot_sectors_max,
+                                           app_count,
+                                           scratch is not None)
+
+        if swap_status.size < status_size_min:
+            print('Insufficient swap status area - suggested size',
+                  hex(status_size_min),
+                  file=sys.stderr)
+            sys.exit(Error.CONFIG_MISMATCH)
+        area_list.add_area('swap status partition',
+                           'FLASH_AREA_IMAGE_SWAP_STATUS',
+                           swap_status.addr, swap_status.size)
+
+    if scratch is not None:
+        area_list.add_area('scratch area',
+                           'FLASH_AREA_IMAGE_SCRATCH',
+                           scratch.addr, scratch.size)
+
+    # Compare size 'bit_per_cnt' and number of images.
+    # 'service_app' is used only when HW rollback counter exists
+    if plat.get('bitsPerCnt') is not None and service_app is not None:
+        plat['bitsPerCnt'] = True
+        list_counters = process_policy_20829(params.policy)
+        if list_counters is not None and len(list_counters) != app_count:
+            print("\nERROR: 'bits_per_cnt' must be present for each image!",
+                file=sys.stderr)
+            print("Please, check secure provisioning and reprovisioning policies.\n",
+                file=sys.stderr)
+            sys.exit(Error.CONFIG_MISMATCH)
+
+    # Image id parameter is not used for MCUBootApp
+    if params.img_id is None:
+        area_list.generate_c_source(params)
+
+    area_list.create_flash_area_id(app_count, params)
+
+    # Report necessary values back to make
+    print('# AUTO-GENERATED FILE, DO NOT EDIT. ALL CHANGES WILL BE LOST!')
+    if params.set_core:
+        print('CORE :=', plat['allCores'][plat['bootCore'].lower()])
+
+    if ram_app_staging is not None:
+        print('USE_STAGE_RAM_APPS := 1')
+        print('RAM_APP_STAGING_EXT_MEM_ADDR := ', hex(ram_app_staging_ext_mem_addr))
+        print('RAM_APP_STAGING_SRAM_MEM_ADDR :=', hex(ram_app_staging_sram_stage_addr))
+        print('RAM_APP_STAGING_SIZE := ', hex(ram_app_staging_size))
+        if ram_app_staging_reset_trigger is True:
+            print('RAM_APP_RESET_TRIGGER := 1')
+
+    if bootloader_startup is True:
+        print('BOOTLOADER_STARTUP := 1')
+
+    if ram_app_area is not None:
+        print('USE_MCUBOOT_RAM_LOAD := 1')
+        print('IMAGE_EXECUTABLE_RAM_START :=', hex(ram_app_area.addr))
+        print('IMAGE_EXECUTABLE_RAM_SIZE :=', hex(ram_app_area.size))
+
+    if boot_shared_data_area is not None:
+        print('USE_MEASURED_BOOT := 1')
+        print('USE_DATA_SHARING := 1')
+        print('BOOT_SHARED_DATA_ADDRESS :=', hex(boot_shared_data_area.addr)+'U')
+        print('BOOT_SHARED_DATA_SIZE :=', hex(boot_shared_data_area.size)+'U')
+        print('BOOT_SHARED_DATA_RECORD_SIZE :=', hex(boot_shared_data_area.size)+'U')
+
+    print('BOOTLOADER_ORIGIN :=', hex(boot_flash_area.addr))
+    print('BOOTLOADER_SIZE :=', hex(boot_flash_area.size))
+    print('BOOTLOADER_RAM_ORIGIN :=', hex(boot_ram_area.addr))
+    print('BOOTLOADER_RAM_SIZE :=', hex(boot_ram_area.size))
+    print('APP_CORE :=', app_core)
+
+    if params.img_id is not None:
+        primary_img_start = apps_flash_map[int(params.img_id)].get("primary").get("address")
+        secondary_img_start = apps_flash_map[int(params.img_id)].get("secondary").get("address")
+        slot_size = apps_flash_map[int(params.img_id)].get("primary").get("size")
+
+        if apps_ram_map:
+            image_ram_address = apps_ram_map[int(params.img_id)].get("address")
+            image_ram_size = apps_ram_map[int(params.img_id)].get("size")
+            image_ram_boot = apps_ram_map[int(params.img_id)].get("ram_boot")
+            if image_ram_address and image_ram_size:
+                print('IMG_RAM_ORIGIN := ' + hex(image_ram_address))
+                print('IMG_RAM_SIZE := ' + hex(image_ram_size))
+                if image_ram_boot is True:
+                    print('USE_MCUBOOT_RAM_LOAD := 1')
+
+        print('PRIMARY_IMG_START := ' + primary_img_start)
+        print('SECONDARY_IMG_START := ' + secondary_img_start)
+        print('SLOT_SIZE := ' + slot_size)
+    else:
+        if apps_ram_map:
+            ram_load_counter = 0
+            for img in apps_ram_map:
+                if img is not None and img.get("ram_boot"):
+                    ram_load_counter += 1
+
+            if ram_load_counter != 0:
+                if ram_load_counter == 1 and app_count == 1:
+                    print('USE_MCUBOOT_RAM_LOAD := 1')
+                    print(f'IMAGE_EXECUTABLE_RAM_START := {hex(apps_ram_map[1].get("address"))}')
+                    print(f'IMAGE_EXECUTABLE_RAM_SIZE := {hex(apps_ram_map[1].get("size"))}')
+                else:
+                    print('USE_MCUBOOT_MULTI_MEMORY_LOAD := 1')
+
+        print('MAX_IMG_SECTORS :=', slot_sectors_max)
+
+    print('MCUBOOT_IMAGE_NUMBER :=', app_count)
+    if area_list.external_flash:
+        print('USE_EXTERNAL_FLASH := 1')
+    if area_list.external_flash_xip:
+        print('USE_XIP := 1')
+
+    if area_list.use_overwrite:
+        print('USE_OVERWRITE := 1')
+    if shared_slot:
+        print('USE_SHARED_SLOT := 1')
+    if service_app is not None:
+        print('PLATFORM_SERVICE_APP_OFFSET :=',
+              hex(app_binary.addr - plat['smifAddr']))
+        print('PLATFORM_SERVICE_APP_INPUT_PARAMS_OFFSET :=',
+              hex(input_params.addr - plat['smifAddr']))
+        print('PLATFORM_SERVICE_APP_DESC_OFFSET :=',
+              hex(app_desc.addr - plat['smifAddr']))
+        print('USE_HW_ROLLBACK_PROT := 1')
+
+
+if __name__ == '__main__':
+    main()
diff --git a/boot/cypress/scripts/memorymap_rework.py b/boot/cypress/scripts/memorymap_rework.py
new file mode 100644
index 0000000..47e681e
--- /dev/null
+++ b/boot/cypress/scripts/memorymap_rework.py
@@ -0,0 +1,582 @@
+"""
+Copyright 2023 Cypress Semiconductor Corporation (an Infineon company)
+or an affiliate of Cypress Semiconductor Corporation. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import sys
+import json
+import click
+
+APP_LIMIT = 8
+
+settings_dict = {
+        'overwrite'                 :   'USE_OVERWRITE'
+    ,   'swap'                      :   'USE_SWAP'
+    ,   'status'                    :   'USE_STATUS'
+    ,   'scratch'                   :   'USE_SCRATCH'
+    ,   'measured_boot'             :   'USE_MEASURED_BOOT'
+    ,   'data_sharing'              :   'USE_DATA_SHARING'
+    ,   'ram_load'                  :   'USE_MCUBOOT_RAM_LOAD'
+    ,   'multi_memory_load'         :   'USE_MCUBOOT_MULTI_MEMORY_LOAD'
+    ,   'shared_slot'               :   'USE_SHARED_SLOT'
+    ,   'ram_load_address'          :   'IMAGE_EXECUTABLE_RAM_START'
+    ,   'ram_load_size'             :   'IMAGE_EXECUTABLE_RAM_SIZE'
+    ,   'shared_data_address'       :   'BOOT_SHARED_DATA_ADDRESS'
+    ,   'shared_data_size'          :   'BOOT_SHARED_DATA_SIZE'
+    ,   'shared_data_record_size'   :   'BOOT_SHARED_DATA_RECORD_SIZE'
+    ,   'bootloader_app_address'    :   'BOOTLOADER_ORIGIN'
+    ,   'bootloader_app_size'       :   'BOOTLOADER_SIZE'
+    ,   'bootloader_ram_address'    :   'BOOTLOADER_RAM_ORIGIN'
+    ,   'bootloader_ram_size'       :   'BOOTLOADER_RAM_SIZE'
+    ,   'application_count'         :   'MCUBOOT_IMAGE_NUMBER'
+    ,   'boot_image'                :   'BOOT_IMAGE_NUMBER'
+    ,   'sectors_count'             :   'MAX_IMG_SECTORS'
+    ,   'core'                      :   'CORE'
+    ,   'image_ram_address'         :   'IMG_RAM_ORIGIN'
+    ,   'image_ram_size'            :   'IMG_RAM_SIZE'
+    ,   'primary_image_start'       :   'PRIMARY_IMG_START'
+    ,   'secondary_image_start'     :   'SECONDARY_IMG_START'
+    ,   'image_size'                :   'SLOT_SIZE'
+}
+
+def header_guard_generate(file):
+    file.write('/* AUTO-GENERATED FILE, DO NOT EDIT.'
+                    ' ALL CHANGES WILL BE LOST! */\n')
+    file.write("#pragma once\n\n")
+
+def is_overlap(x : int, y : int) -> bool:
+    if x.start == x.stop or y.start == y.stop:
+        return False
+    return x.start < y.stop and y.start < x.stop
+
+def is_aligned(addr : int, sz : int) -> bool:
+    ''' Check address alignment '''
+    return addr % sz == 0
+
+class Memory:
+    ''' Memory handler '''
+    def __init__(self, addr, sz):
+        self.addr   : int = addr
+        self.sz     : int = sz
+
+    def overlaps_with(self, other) -> bool:
+        ''' Check Memory for intersection
+            @return Bool
+        '''
+        first = range(self.addr, self.addr + self.sz)
+        second = range(other.addr, other.addr + other.sz)
+
+        return is_overlap(first, second)
+
+    def fits_with(self, other) -> bool:
+        '''
+
+        '''
+        return \
+            self.addr >= other.addr and \
+            self.addr + self.sz <= other.addr + other.sz
+
+class MemoryRegion(Memory):
+    ''' Memory region handler '''
+    def __init__(self, addr, sz, erase_sz, erase_val, type):
+        super().__init__(addr, sz)
+        self.erase_sz   : int   = erase_sz
+        self.erase_val  : int   = erase_val
+        self.type               = type
+
+class BootloaderLayout:
+    '''
+        Handler for bootloader memory layout
+    '''
+    def __init__(self):
+        self.bootloader_area    : Memory    = None
+        self.ram                : Memory    = None
+        self.scratch_area       : Memory    = None
+        self.status_area        : Memory    = None
+        self.shared_data        : Memory    = None
+        self.shared_upgrade     : Memory    = None
+        self.core_name          : int       = None
+
+    @property
+    def has_shared_upgrade(self) -> bool:
+        return self.shared_upgrade is not None
+
+    @property
+    def has_shared_data(self) -> bool:
+        return self.shared_data is not None
+
+    @property
+    def has_scratch_area(self) -> bool:
+        return self.scratch_area is not None
+
+    @property
+    def has_status_area(self) -> bool:
+        return self.status_area is not None
+
+    def parse(self, section : json):
+        '''
+            Parse JSON section and init fields.
+        '''
+        try:
+            fields = ('bootloader_area', 'scratch_area', 'status_area', \
+                      'shared_data', 'shared_upgrade', 'ram')
+            for field in fields:
+                area = section.get(field)
+                if area:
+                    setattr(self, field, Memory(int(area['address'], 0),
+                                                int(area['size'], 0)))
+
+            core = section.get('core')
+            if core:
+                self.core_name = core
+
+        except KeyError as key:
+            print('Malformed JSON:', key, 'is missing')
+
+class MemoryAreaConfig:
+    '''
+        Handler for flash area configuration
+    '''
+    def __init__(self, area_name, device_name, offset, size):
+        self.fa_id          : str   = area_name
+        self.fa_device_id   : str   = device_name
+        self.fa_off         : int   = offset
+        self.fa_size        : int   = size
+
+class ApplicationLayout:
+    '''
+        Handler for application memory layout
+    '''
+    def __init__(self):
+        self.boot_area      : Memory        = None
+        self.upgrade_area   : Memory        = None
+        self.ram            : Memory        = None
+        self.ram_boot       : Memory        = None
+        self.core_name      : str           = None
+
+    @property
+    def has_ram_boot(self) -> bool:
+        return self.ram_boot is not None
+
+    @property
+    def has_upgrade_area(self) -> bool:
+        return self.upgrade_area is not None
+
+    def overlaps_with(self, other) -> bool:
+        return \
+            self.boot_area.overlaps_with(other.boot_area) or \
+            self.upgrade_area.overlaps_with(other.upgrade_area)
+
+    def parse(self, section : json):
+        '''
+            Parse JSON section and init fields.
+        '''
+        try:
+            slots = section['slots']
+            boot_address = int(slots['boot'], 0)
+            upgrade_address =  int(slots['upgrade'], 0)
+            slot_size = int(slots['size'], 0)
+
+            self.boot_area = Memory(boot_address, slot_size)
+            self.upgrade_area = Memory(upgrade_address, slot_size)
+
+            fields = ('ram', 'ram_boot')
+            for field in fields:
+                area = section.get(field)
+                if area:
+                    setattr(self, field, Memory(int(area['address'], 0),
+                                                int(area['size'], 0)))
+
+            core = section.get('core')
+            if core:
+                self.core_name = core
+
+        except KeyError as key:
+            print('Malformed JSON:', key, 'is missing')
+
+class MemoryMap:
+    '''
+        General handler
+    '''
+    def __init__(self):
+        self.boot_layout    : BootloaderLayout      = None
+        self.regions        : MemoryRegion          = []
+        self.region_types   : str                   = []
+        self.apps           : ApplicationLayout     = []
+        self.primary_slots  : str                   = []
+        self.secondary_slots: str                   = []
+        self.mem_areas      : MemoryAreaConfig      = []
+        self.param_dict                             = {}
+        self.map_json       : json                  = None
+        self.platform_json  : json                  = None
+        self.output_folder                          = None
+        self.output_name                            = None
+        self.max_sectors                            = 32
+
+    def __apps_init(self):
+        for image_number in range(1, APP_LIMIT):
+            app_ident   = f'application_{image_number}'
+            section     = self.map_json.get(app_ident)
+
+            if section:
+                app_layout = ApplicationLayout()
+                app_layout.parse(section)
+
+                self.apps.append(app_layout)
+            else:
+                break
+
+    def __boot_layout_init(self):
+        self.boot_layout = BootloaderLayout()
+        self.boot_layout.parse(self.map_json['bootloader'])
+
+    def __memory_regions_init(self):
+        memory_regions = self.platform_json['memory_regions']
+        for region in memory_regions:
+            try:
+                addr        = int(region['address'], 0)
+                size        = int(region['size'], 0)
+                erase_size  = int(region['erase_size'], 0)
+                erase_value = int(region['erase_value'], 0)
+                type        = str(region['type'])
+
+                if type not in self.region_types:
+                    self.region_types.append(type)
+
+                self.regions.append(MemoryRegion(addr, size, erase_size, erase_value, type))
+            except KeyError as key:
+                print('Malformed JSON:', key, 'is missing')
+
+        # Check regions for overlap
+        for this in self.regions:
+            for other in self.regions:
+                if this is other:
+                    continue
+                if this.overlaps_with(other):
+                    # TODO: Notify regions overlap
+                    raise Exception()
+
+    def __memory_area_find_region_id(self, area : Memory) -> int:
+        for region_id, region in enumerate(self.regions):
+            if area.fits_with(region):
+                return region_id
+        return None
+
+    def __memory_area_config_create(self, key):
+        param_dict = self.param_dict
+        area = param_dict[key][0]
+        area_name = param_dict[key][1]
+
+        region_id = self.__memory_area_find_region_id(area)
+        region = self.regions[region_id]
+        region_name = region.type
+
+        offset = area.addr - region.addr
+        size = area.sz
+
+        area_config = MemoryAreaConfig(area_name,\
+                                       region_name, \
+                                       offset, \
+                                       size)
+
+        self.mem_areas.append(area_config)
+
+        # Update max sectors
+        slot_sectors = int((offset % region.erase_sz +
+                            size + region.erase_sz - 1) //
+                            region.erase_sz)
+
+        self.max_sectors = max(self.max_sectors, slot_sectors)
+
+    def __memory_areas_create(self):
+        # Generate FA indexes
+        param_dict = self.param_dict
+        bootloader_area = self.boot_layout.bootloader_area
+        main_app = self.apps[0]
+        boot_area = main_app.boot_area
+        upgrade_area = main_app.upgrade_area
+        scratch_area = self.boot_layout.scratch_area
+
+        param_dict.update({'bootloader': [bootloader_area, 'FLASH_AREA_BOOTLOADER', 0]})
+        param_dict.update({'app_1_boot': [boot_area, 'FLASH_AREA_IMG_1_PRIMARY', 1]})
+        param_dict.update({'app_1_upgrade': [upgrade_area, 'FLASH_AREA_IMG_1_SECONDARY', 2]})
+
+        self.primary_slots.append('FLASH_AREA_IMG_1_PRIMARY')
+        self.secondary_slots.append('FLASH_AREA_IMG_1_SECONDARY')
+
+        # Generate scratch area index
+        if self.boot_layout.has_scratch_area:
+            param_dict.update({'scratch_area': [scratch_area, 'FLASH_AREA_IMAGE_SCRATCH', 3]})
+
+        # Generate multiple app area indexes
+        multi_app_area_idx = 4
+        if len(self.apps) > 1:
+            for app_id, app in enumerate(self.apps[1:], 1):
+                idx = multi_app_area_idx + (app_id-1) * 2
+                app_num = app_id + 1
+                key = f'app_{app_num}_boot'
+                fmt = f'FLASH_AREA_IMG_{app_num}_PRIMARY'
+                param_dict.update({key: [app.boot_area, fmt, idx]})
+
+                self.primary_slots.append(fmt)
+
+                key = f'app_{app_num}_upgrade'
+                fmt = f'FLASH_AREA_IMG_{app_num}_SECONDARY'
+                param_dict.update({key: [app.upgrade_area, fmt, idx+1]})
+
+                self.secondary_slots.append(fmt)
+
+        # Generate status area indexes
+        if self.boot_layout.has_status_area:
+            area = self.boot_layout.status_area
+            idx = multi_app_area_idx + (len(self.apps)-1) * 2
+            fmt = 'FLASH_AREA_IMAGE_SWAP_STATUS'
+            param_dict.update({'status_area': [area, fmt, idx]})
+
+        # Create areas
+        for key in param_dict:
+            self.__memory_area_config_create(key)
+
+    def __source_gen(self):
+        path = f'{self.output_folder}/{self.output_name}.c'
+        include = f'{self.output_name}.h'
+
+        with open(path, "w", encoding='UTF-8') as f_out:
+            f_out.write(f'#include "{include}"\n')
+            f_out.write(f'#include "flash_map_backend.h"\n\n')
+            f_out.write('struct flash_device flash_devices[] =\n')
+            f_out.write('{\n')
+            for region in self.regions:
+                f_out.write('\t{\n')
+                f_out.write(f'\t\t.address      = {hex(region.addr)}U,\n')
+                f_out.write(f'\t\t.size         = {hex(region.sz)}U,\n')
+                f_out.write(f'\t\t.erase_size   = {hex(region.erase_sz)}U,\n')
+                f_out.write(f'\t\t.erase_val    = {hex(region.erase_val)}U,\n')
+                f_out.write(f'\t\t.device_id    = {str(region.type)},\n')
+                f_out.write('\t},\n')
+            f_out.write('};\n\n')
+
+            f_out.write(f'struct flash_area flash_areas[] =\n')
+            f_out.write('{\n')
+            for area in self.mem_areas:
+                f_out.writelines('\n'.join([
+                    '\t{',
+                    f"\t\t.fa_id        = {area.fa_id},",
+                    f"\t\t.fa_device_id = {area.fa_device_id},",
+                    f"\t\t.fa_off       = {hex(area.fa_off)}U,",
+                    f"\t\t.fa_size      = {hex(area.fa_size)}U,",
+                    '\t},\n']))
+            f_out.write('};\n\n')
+
+            f_out.write('struct flash_area *boot_area_descs[] =\n')
+            f_out.write('{\n')
+            for index, area in enumerate(self.mem_areas):
+                f_out.write(f'\t&flash_areas[{index}U],\n')
+            f_out.write('\tNULL\n};\n\n')
+
+            f_out.write('uint8_t memory_areas_primary[] =\n')
+            f_out.write('{\n')
+            for slot in self.primary_slots:
+                f_out.write(f'\t{slot}, ')
+            f_out.write('\n};\n\n')
+
+            f_out.write('uint8_t memory_areas_secondary[] =\n')
+            f_out.write('{\n')
+            for slot in self.secondary_slots:
+                f_out.write(f'\t{slot}, ')
+            f_out.write('\n};\n\n')
+
+    def __header_gen(self):
+        path = f'{self.output_folder}/{self.output_name}.h'
+        with open(path, "w", encoding='UTF-8') as f_out:
+            header_guard_generate(f_out)
+
+            f_out.write(f'#include <stdint.h>\n')
+            f_out.write(f'#include "flash_map_backend.h"\n\n')
+            f_out.write(f'#define MEMORYMAP_GENERATED_AREAS 1\n\n')
+            f_out.write('extern struct flash_device flash_devices[];\n')
+            f_out.write('extern struct flash_area *boot_area_descs[];\n\n')
+            f_out.write('extern uint8_t memory_areas_primary[];\n')
+            f_out.write('extern uint8_t memory_areas_secondary[];\n\n')
+
+            f_out.write('enum \n{\n')
+            for id, type in enumerate(self.region_types):
+                f_out.write(f'\t{type} = {id}U,\n')
+            f_out.write('};\n\n')
+
+            f_out.write('enum \n{\n')
+            for area_param in self.param_dict.values():
+                f_out.write(f'\t{area_param[1]} = {area_param[2]}U,\n')
+            f_out.write('};\n\n')
+
+    def __bootloader_mk_file_gen(self):
+        boot = self.boot_layout
+        # Upgrade mode
+        if boot.scratch_area is None and boot.status_area is None:
+            print(settings_dict['overwrite'], ':= 1')
+        else:
+            print(settings_dict['overwrite'], ':= 0')
+            print(settings_dict['swap'], ':= 1')
+            print(settings_dict['scratch'], f':= {0 if boot.scratch_area is None else 1}')
+            print(settings_dict['status'], f':= {0 if boot.status_area is None else 1}')
+        print('# Shared data')
+        if boot.shared_data is not None:
+            shared_data = boot.shared_data
+            print(settings_dict['measured_boot'], ':= 1')
+            print(settings_dict['data_sharing'], ':= 1')
+
+            print(f'{settings_dict["shared_data_address"]} :=', hex(shared_data.addr))
+            print(f'{settings_dict["shared_data_size"]} :=', hex(shared_data.sz))
+            print(f'{settings_dict["shared_data_record_size"]} :=', hex(shared_data.sz))
+
+        print('# Bootloader app area')
+        print(f'{settings_dict["bootloader_app_address"]} :=', hex(boot.bootloader_area.addr))
+        print(f'{settings_dict["bootloader_app_size"]} :=', hex(boot.bootloader_area.sz))
+
+        print('# Bootloader ram area')
+        if boot.ram is not None:
+            print(f'{settings_dict["bootloader_ram_address"]} :=', hex(boot.ram.addr))
+            print(f'{settings_dict["bootloader_ram_size"]} :=', hex(boot.ram.sz))
+
+        print('# Application area')
+        for id, app in enumerate(self.apps):
+            print(f'APPLICATION_{id+1}_BOOT_SLOT_ADDRESS := {hex(app.boot_area.addr)}')
+            print(f'APPLICATION_{id+1}_BOOT_SLOT_SIZE := {hex(app.boot_area.sz)}')
+            print(f'APPLICATION_{id+1}_UPGRADE_SLOT_ADDRESS := {hex(app.upgrade_area.addr)}')
+            print(f'APPLICATION_{id+1}_UPGRADE_SLOT_SIZE := {hex(app.upgrade_area.sz)}')
+
+        print('# Ram load')
+        # Ram load single
+        if len(self.apps) == 1:
+            if self.apps[0].ram_boot is not None:
+                ram_boot = self.apps[0].ram_boot
+                print(settings_dict['ram_load'], ':= 1')
+                print(f'{settings_dict["ram_load_address"]} :=', hex(ram_boot.addr))
+                print(f'{settings_dict["ram_load_size"]} :=', hex(ram_boot.sz))
+        else:
+        # Ram load multiple
+            ram_boot_counter = 0
+            ram_addr_overlap_counter = 0
+
+            for app1 in self.apps:
+                for app2 in self.apps:
+                    if app1 is app2:
+                        continue
+                    if app1.overlaps_with(app2):
+                        ram_addr_overlap_counter += 1
+
+            for id, app in enumerate(self.apps):
+                if app.ram_boot is not None:
+                    ram_boot_counter += 1
+                    ram_boot = app.ram_boot
+
+                    print(f'APPLICATION_{id+1}_RAM_LOAD_ADDRESS := {hex(ram_boot.addr)}')
+                    print(f'APPLICATION_{id+1}_RAM_LOAD_SIZE := {hex(ram_boot.sz)}')
+
+            if ram_boot_counter != 0:
+                print(settings_dict['ram_load'], ':= 1')
+
+                if ram_boot_counter != len(self.apps) or ram_addr_overlap_counter == 0:
+                    print(settings_dict['multi_memory_load'], ':= 1')
+
+        print('# Mcuboot')
+        print(settings_dict['application_count'], f'= {len(self.apps)}')
+        print(settings_dict['sectors_count'], f'= {self.max_sectors}')
+
+    def __application_mk_file_gen(self):
+        app = self.apps[self.app_id-1]
+        boot = self.boot_layout
+        # Upgrade mode
+        if boot.scratch_area is None and boot.status_area is None:
+            print(settings_dict['overwrite'], ':= 1')
+        else:
+            print(settings_dict['overwrite'], ':= 0')
+            print(settings_dict['swap'], ':= 1')
+            print(settings_dict['scratch'], f':= {0 if boot.scratch_area is None else 1}')
+            print(settings_dict['status'], f':= {0 if boot.status_area is None else 1}')
+
+        print(settings_dict['application_count'], f'= {len(self.apps)}')
+        print(settings_dict['boot_image'], ':=', self.app_id)
+        print(settings_dict['primary_image_start'], ':=', hex(app.boot_area.addr))
+        print(settings_dict['secondary_image_start'], ':=', hex(app.upgrade_area.addr))
+        print(settings_dict['image_size'], ':=', hex(app.boot_area.sz))
+        if app.ram_boot:
+            print(settings_dict['ram_load'], ':= 1')
+        if app.ram:
+            print(settings_dict['image_ram_address'], ':=',  hex(app.ram.addr))
+            print(settings_dict['image_ram_size'], ':=',  hex(app.ram.sz))
+        if app.core_name:
+            print(settings_dict['core'], ':=',  app.core_name)
+
+    def parse(self, memory_map, platform_config, output_folder, output_name, app_id):
+        try:
+            with open(memory_map, "r", encoding='UTF-8') as f_in:
+                self.map_json = json.load(f_in)
+
+            with open(platform_config, "r", encoding='UTF-8') as f_in:
+                self.platform_json = json.load(f_in)
+
+            self.output_folder  = output_folder
+            self.output_name    = output_name
+
+            if app_id is not None:
+                self.app_id = int(app_id)
+
+            self.__memory_regions_init()
+            self.__boot_layout_init()
+            self.__apps_init()
+            self.__memory_areas_create()
+
+            self.__source_gen()
+            self.__header_gen()
+
+            if app_id is None:
+                self.__bootloader_mk_file_gen()
+            else:
+                self.__application_mk_file_gen()
+
+        except (FileNotFoundError, OSError):
+            print('\nERROR: Cannot open ', f_in, file=sys.stderr)
+            sys.exit(-1)
+
+
+@click.group()
+def cli():
+    '''
+        Memory map layout parser-configurator
+    '''
+
+@cli.command()
+@click.option('-i', '--memory_config', required=True,
+              help='memory configuration file path')
+@click.option('-p', '--platform_config', required=True,
+              help='platform configuration file path')
+@click.option('-n', '--output_name', required=True,
+              help='generated areas path')
+@click.option('-o', '--output_folder', required=True,
+              help='generated regions path')
+@click.option('-d', '--image_id', required=False,
+              help='application image number')
+
+def run(memory_config, platform_config, output_folder, output_name, image_id):
+    map = MemoryMap()
+    map.parse(memory_config,
+              platform_config,
+              output_folder,
+              output_name,
+              image_id)
+
+if __name__ == '__main__':
+    cli()
\ No newline at end of file