From eea25b487c02626dfad9a807be6dfaf140ff0d94 Mon Sep 17 00:00:00 2001 From: Teo Mahnic Date: Fri, 5 Dec 2025 14:11:59 +0100 Subject: [PATCH 1/2] target: pack: handle cores not specified in CMSIS packs --- pyocd/target/pack/cbuild_run.py | 36 +++++++++++++------------- pyocd/target/pack/pack_target.py | 44 ++++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 20 deletions(-) diff --git a/pyocd/target/pack/cbuild_run.py b/pyocd/target/pack/cbuild_run.py index 40882e7ea..cd431f543 100644 --- a/pyocd/target/pack/cbuild_run.py +++ b/pyocd/target/pack/cbuild_run.py @@ -124,26 +124,28 @@ def _cbuild_target_update_processor_name(self) -> None: Maps discovered cores to known processors to ensure consistent naming. """ - processors_map = {} + ap_to_proc = {proc.ap_address: proc for proc in self._cbuild_device.processors_map.values()} + info_logging_enabled = LOG.isEnabledFor(logging.INFO) + for core in self.cores.values(): - if core.node_name is None or core.node_name == 'Unknown': + if core.node_name in ('Unknown', None): core.node_name = core.name - for proc in self._cbuild_device.processors_map.values(): - if ('Unknown' in proc.name) and (proc.ap_address == core.ap.address): - proc.name = core.name - processors_map[core.name] = proc - break + proc = ap_to_proc.get(core.ap.address) + if proc is not None and 'Unknown' in proc.name: + # Remove old processor entry with 'Unknown' name + self._cbuild_device.processors_map.pop(proc.name, None) + # Update processor name + proc.name = core.name + # Insert new processor entry with correct name + self._cbuild_device.processors_map[core.name] = proc - if LOG.isEnabledFor(logging.INFO): + if info_logging_enabled: core_info = f"core {core.core_number}: {core.name} r{core.cpu_revision}p{core.cpu_patch}" if core.node_name != core.name: core_info += f", pname: {core.node_name}" LOG.info(core_info) - if processors_map: - self._cbuild_device.processors_map = processors_map - @staticmethod def _cbuild_target_configure_core_reset(self) -> None: """@brief Configures default reset types for each core, based on .cbuild-run.yml.""" @@ -166,8 +168,11 @@ def _cbuild_target_configure_core_reset(self) -> None: @staticmethod def _cbuild_target_add_core(_self, core: CoreTarget) -> None: """@brief Override to set node name of added core to its pname.""" - pname = _self._cbuild_device.processors_ap_map[cast('CortexM', core).ap.address].name - core.node_name = pname + proc = _self._cbuild_device.processors_ap_map.get(cast('CortexM', core).ap.address) + if proc is not None: + core.node_name = proc.name + else: + LOG.info("Found core without 'pname' description (core %s)", core.core_number) CoreSightTarget.add_core(_self, core) @staticmethod @@ -437,11 +442,6 @@ def processors_map(self) -> Dict[str, ProcessorInfo]: self._build_aps_map() return self._processors_map - @processors_map.setter - def processors_map(self, proc_map: Dict[str, ProcessorInfo]) -> None: - self._processors_map = proc_map - LOG.debug("Updated processors map") - @property def processors_ap_map(self) -> Dict[APAddressBase, ProcessorInfo]: """@brief Map of AP address objects and processor info objects.""" diff --git a/pyocd/target/pack/pack_target.py b/pyocd/target/pack/pack_target.py index 90b27dffc..76cb1e90c 100644 --- a/pyocd/target/pack/pack_target.py +++ b/pyocd/target/pack/pack_target.py @@ -391,11 +391,49 @@ def _pack_target__init__(self, session: Session) -> None: # type:ignore self.debug_sequence_delegate = PackDebugSequenceDelegate(self, self._pack_device) + @staticmethod + def _pack_target_create_init_sequence(_self) -> CallSequence: + """@brief Creates an initialization call sequence for runtime-configured targets. + + Extends the standard discovery sequence to configure processor names. + """ + seq = super(_self.__class__, _self).create_init_sequence() + seq.wrap_task('discovery', + lambda seq: seq.insert_after('create_cores', + ('update_processor_name', _self.update_processor_name) + ) + ) + return seq + + @staticmethod + def _pack_target_update_processor_name(_self) -> None: + """@brief Updates processor names post-discovery based on Access Port (AP) addresses. + + Maps discovered cores to known processors to ensure consistent naming. + """ + ap_to_proc = {proc.ap_address: proc for proc in _self._pack_device.processors_map.values()} + + for core in _self.cores.values(): + if core.node_name in ('Unknown', None): + core.node_name = core.name + + proc = ap_to_proc.get(core.ap.address) + if proc is not None and 'Unknown' in proc.name: + # Remove old processor entry with 'Unknown' name + _self._pack_device.processors_map.pop(proc.name, None) + # Update processor name + proc.name = core.name + # Insert new processor entry with correct name + _self._pack_device.processors_map[core.name] = proc + @staticmethod def _pack_target_add_core(_self, core: CoreTarget) -> None: """@brief Override to set node name of added core to its pname.""" - pname = _self._pack_device.processors_ap_map[cast(CortexM, core).ap.address].name - core.node_name = pname + proc = _self._pack_device.processors_ap_map.get(cast(CortexM, core).ap.address) + if proc is not None: + core.node_name = proc.name + else: + LOG.info("Found core without 'pname' description (core %s)", core.core_number) CoreSightTarget.add_core(_self, core) @staticmethod @@ -445,6 +483,8 @@ def _generate_pack_target_class(dev: CmsisPackDevice) -> Optional[type]: targetClass = type(subclassName, (superklass,), { "_pack_device": dev, "__init__": _PackTargetMethods._pack_target__init__, + "create_init_sequence": _PackTargetMethods._pack_target_create_init_sequence, + "update_processor_name": _PackTargetMethods._pack_target_update_processor_name, "add_core": _PackTargetMethods._pack_target_add_core, "add_target_command_groups": _PackTargetMethods._pack_target_add_target_command_groups, }) From 0ac588ab98b13ef38376fd70c03980df0b138dc6 Mon Sep 17 00:00:00 2001 From: Teo Mahnic Date: Fri, 5 Dec 2025 14:47:20 +0100 Subject: [PATCH 2/2] cbuild-run: update typing information --- pyocd/target/pack/cbuild_run.py | 37 +++++++++++++++++---------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/pyocd/target/pack/cbuild_run.py b/pyocd/target/pack/cbuild_run.py index cd431f543..7994b7b32 100644 --- a/pyocd/target/pack/cbuild_run.py +++ b/pyocd/target/pack/cbuild_run.py @@ -34,6 +34,7 @@ from ...core import exceptions from ...core.target import Target from ...core.memory_map import (MemoryMap, MemoryType, MEMORY_TYPE_CLASS_MAP) +from ...coresight.cortex_m import CortexM from ...probe.debug_probe import DebugProbe from ...debug.svd.loader import SVDFile from ...utility.cmdline import convert_reset_type @@ -103,42 +104,42 @@ def _cbuild_target_init(self, session: "Session") -> None: self.debug_sequence_delegate = CbuildRunDebugSequenceDelegate(self, self._cbuild_device) @staticmethod - def _cbuild_target_create_init_sequence(self) -> CallSequence: + def _cbuild_target_create_init_sequence(_self) -> CallSequence: """@brief Creates an initialization call sequence for runtime-configured targets. Extends the standard discovery sequence to configure processor names and reset behavior after core discovery. """ - seq = super(self.__class__, self).create_init_sequence() + seq = super(_self.__class__, _self).create_init_sequence() seq.wrap_task('discovery', lambda seq: seq.insert_after('create_cores', - ('update_processor_name', self.update_processor_name), - ('configure_core_reset', self.configure_core_reset) + ('update_processor_name', _self.update_processor_name), + ('configure_core_reset', _self.configure_core_reset) ) ) return seq @staticmethod - def _cbuild_target_update_processor_name(self) -> None: + def _cbuild_target_update_processor_name(_self) -> None: """@brief Updates processor names post-discovery based on Access Port (AP) addresses. Maps discovered cores to known processors to ensure consistent naming. """ - ap_to_proc = {proc.ap_address: proc for proc in self._cbuild_device.processors_map.values()} + ap_to_proc = {proc.ap_address: proc for proc in _self._cbuild_device.processors_map.values()} info_logging_enabled = LOG.isEnabledFor(logging.INFO) - for core in self.cores.values(): + for core in _self.cores.values(): if core.node_name in ('Unknown', None): core.node_name = core.name proc = ap_to_proc.get(core.ap.address) if proc is not None and 'Unknown' in proc.name: # Remove old processor entry with 'Unknown' name - self._cbuild_device.processors_map.pop(proc.name, None) + _self._cbuild_device.processors_map.pop(proc.name, None) # Update processor name proc.name = core.name # Insert new processor entry with correct name - self._cbuild_device.processors_map[core.name] = proc + _self._cbuild_device.processors_map[core.name] = proc if info_logging_enabled: core_info = f"core {core.core_number}: {core.name} r{core.cpu_revision}p{core.cpu_patch}" @@ -147,14 +148,14 @@ def _cbuild_target_update_processor_name(self) -> None: LOG.info(core_info) @staticmethod - def _cbuild_target_configure_core_reset(self) -> None: + def _cbuild_target_configure_core_reset(_self) -> None: """@brief Configures default reset types for each core, based on .cbuild-run.yml.""" - reset_configuration = self._cbuild_device.debugger.get('reset', []) + reset_configuration = _self._cbuild_device.debugger.get('reset', []) if not reset_configuration: # No reset configuration provided. return None - for core in self.cores.values(): + for core in _self.cores.values(): if any('pname' in r for r in reset_configuration): reset = next((r['type'] for r in reset_configuration if r.get('pname') == core.node_name), None) else: @@ -168,7 +169,7 @@ def _cbuild_target_configure_core_reset(self) -> None: @staticmethod def _cbuild_target_add_core(_self, core: CoreTarget) -> None: """@brief Override to set node name of added core to its pname.""" - proc = _self._cbuild_device.processors_ap_map.get(cast('CortexM', core).ap.address) + proc = _self._cbuild_device.processors_ap_map.get(cast(CortexM, core).ap.address) if proc is not None: core.node_name = proc.name else: @@ -176,8 +177,8 @@ def _cbuild_target_add_core(_self, core: CoreTarget) -> None: CoreSightTarget.add_core(_self, core) @staticmethod - def _cbuild_target_get_output(self) -> Dict[str, Optional[int]]: - return self._cbuild_device.output + def _cbuild_target_get_output(_self) -> Dict[str, Tuple[str, Optional[int]]]: + return _self._cbuild_device.output @staticmethod def _cbuild_target_add_target_command_groups(_self, command_set: CommandSet): @@ -800,17 +801,17 @@ def get_svd_path(pname: Optional[str] = None) -> Optional[str]: return svd_path _processors = {} - for processor in self.debug_topology.get('processors', {}): + for processor in self.debug_topology.get('processors', []): apid = processor.get('apid') pname = processor.get('pname', 'Unknown') reset_sequence = processor.get('reset-sequence', 'ResetSystem') if apid is not None: _processors[apid] = (pname, reset_sequence) - for debugport in self.debug_topology.get('debugports', {}): + for debugport in self.debug_topology.get('debugports', []): dpid = debugport.get('dpid', 0) self._valid_dps.append(dpid) - for accessport in debugport.get('accessports', {}): + for accessport in debugport.get('accessports', []): apid = accessport.get('apid', 0) if 'address' in accessport: