Skip to content

Commit

Permalink
debug: sequences: support pname on DebugPort* sequences (pyocd#1607)
Browse files Browse the repository at this point in the history
  • Loading branch information
flit authored Aug 13, 2023
1 parent 419a894 commit bb5aaf0
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 19 deletions.
10 changes: 8 additions & 2 deletions docs/open_cmsis_pack_support.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,15 @@ Only top-level sequences can be disabled individually. If a debug sequence is ca
This section documents details of the debug sequence engine provided by pyOCD, supported features, and any notable differences with other debuggers (primarily Keil MDK, which provided the first implementation and against which Packs are generally most thoroughly tested by their authors).


### CPU-specific DebugPort sequences
### Core-specific sequences

Like all other debug sequences, `DebugPortSetup`, `DebugPortStart`, and `DebugPortStop` can be customised per CPU core. If a DFP has multiple CPU-specific instances of these sequences, they may behave differently in pyOCD than other debuggers. Many debuggers only "connect" to a single CPU chosen by the user when debugging or running a project. PyOCD is somewhat different in that it connects to the device as a whole, and then debugs a chosen core after the connection is established (which more closely reflects the hardware situation).
The DFP debug sequence architecture is currently based on the fact that most debuggers only "connect" to a single CPU core chosen by the user when debugging or running a project. All debug sequences can be customised per core, and there can be separate sequences for each core.

PyOCD is somewhat different in that it connects to the device as a whole, and then debugs one or more cores after the connection is established. This more closely reflects the hardware situation.

This primarily impacts the `DebugPortSetup`, `DebugPortStart`, `DebugPortStop`, and `DebugDeviceUnlock` debug sequences that affect the entire SoC. These relate to the connect procedure for the Arm ADI DP (Debug Port) used for SWD/JTAG communications. While most sequences can be run separately for each core, these are run only once per target connection. The core-specific variant that is selected can affect the rest of the debugging session. (Technically, this is also true for debuggers that are presented as debugging a single core, in cases where a second instance of that debugger can be started to debug another core. But, the way it's presented to the user is different.)

The `primary_core` session option is used to select which core-specific version of the `DebugPort*`/`DebugDeviceUnlock` sequences is run during the target connection process. For all other sequences, the core-specific version that is run depends on which core is performing the action.


### Custom default reset sequences
Expand Down
8 changes: 4 additions & 4 deletions pyocd/coresight/coresight_target.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# pyOCD debugger
# Copyright (c) 2015-2020 Arm Limited
# Copyright (c) 2021-2022 Chris Reed
# Copyright (c) 2021-2023 Chris Reed
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -163,7 +163,7 @@ def primary_core_pname(self) -> str:
raise exceptions.Error(f"invalid 'primary_core' session option '{primary_core}' "
f"(valid values are {', '.join(str(i) for i, _ in enumerate(ap_map.values()))})")

def _call_pre_discovery_debug_sequence(self, sequence: str) -> bool:
def call_pre_discovery_debug_sequence(self, sequence: str) -> bool:
"""@brief Run a debug sequence before discovery has been performed.
The primary core's pname cannot be looked up via the `node_name` property of the core
Expand Down Expand Up @@ -192,7 +192,7 @@ def unlock_device(self) -> None:
if self.delegate_implements('unlock_device'):
self.call_delegate('unlock_device')
else:
self._call_pre_discovery_debug_sequence('DebugDeviceUnlock')
self.call_pre_discovery_debug_sequence('DebugDeviceUnlock')

def create_discoverer(self) -> None:
"""@brief Init task to create the discovery object.
Expand All @@ -215,7 +215,7 @@ def pre_connect(self) -> None:
# Set the state variable indicating we're running ResetHardware for pre-reset, used
# by the debug sequence delegate's get_connection_type() method.
self.session.context_state.is_performing_pre_reset = True
if not self._call_pre_discovery_debug_sequence('ResetHardware'):
if not self.call_pre_discovery_debug_sequence('ResetHardware'):
self.dp.reset()
finally:
self.session.context_state.is_performing_pre_reset = False
Expand Down
25 changes: 12 additions & 13 deletions pyocd/coresight/dap.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

import logging
from enum import Enum
from typing import (Callable, Dict, List, NamedTuple, Optional, Sequence, Tuple, TYPE_CHECKING, Union, overload)
from typing import (cast, Callable, Dict, List, NamedTuple, Optional, Sequence, Tuple, TYPE_CHECKING, Union, overload)
from typing_extensions import Literal

from ..core import (exceptions, memory_interface)
Expand Down Expand Up @@ -439,23 +439,22 @@ def _get_probe_capabilities(self) -> None:
self._probe_supports_apv2_addresses = (DebugProbe.Capability.APv2_ADDRESSES in caps)
self._have_probe_capabilities = True

# Usually when we call a debug sequence, we first check if the sequence exists. For the below
# methods, we rely on .call_pre_discovery_debug_sequence() to do this for us.
def connect_debug_port_hook(self) -> Optional[bool]:
if self.has_debug_sequence('DebugPortSetup'):
assert self.debug_sequence_delegate
self.debug_sequence_delegate.run_sequence('DebugPortSetup')
return True
from .coresight_target import CoreSightTarget
cst = cast(CoreSightTarget, self.session.target)
return cst.call_pre_discovery_debug_sequence('DebugPortSetup')

def enable_debug_port_hook(self) -> Optional[bool]:
if self.has_debug_sequence('DebugPortStart'):
assert self.debug_sequence_delegate
self.debug_sequence_delegate.run_sequence('DebugPortStart')
return True
from .coresight_target import CoreSightTarget
cst = cast(CoreSightTarget, self.session.target)
return cst.call_pre_discovery_debug_sequence('DebugPortStart')

def disable_debug_port_hook(self) -> Optional[bool]:
if self.has_debug_sequence('DebugPortStop'):
assert self.debug_sequence_delegate
self.debug_sequence_delegate.run_sequence('DebugPortStop')
return True
from .coresight_target import CoreSightTarget
cst = cast(CoreSightTarget, self.session.target)
return cst.call_pre_discovery_debug_sequence('DebugPortStop')

def _connect(self) -> None:
# Connect the probe.
Expand Down

0 comments on commit bb5aaf0

Please sign in to comment.