Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions pyocd/coresight/ap.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,7 @@
## Offset of IDR register in an APv2.
APv2_IDR = 0xDFC

A32 = 0x0c
APSEL_SHIFT = 24
APSEL = 0xff000000
APBANKSEL = 0x000000f0
APSEL_APBANKSEL = APSEL | APBANKSEL

## @brief Mask for register address within the AP address space.
#
Expand Down Expand Up @@ -606,6 +602,10 @@ def __init__(
## Cached current CSW value.
self._cached_csw: int = -1

# Register the CSW cache with the DP so direct AP accesses can update it.
csw_address = self.address.address + self._reg_offset + MEM_AP_CSW
self.dp._cached_ap_cb[csw_address] = self._update_cache

## Original CSW value read during init().
self.original_csw: Optional[int] = None

Expand Down Expand Up @@ -1047,8 +1047,6 @@ def write_reg(self, addr: int, data: int) -> None:
TRACE.debug("write_ap:%06d cached (ap=0x%x; addr=0x%08x) = 0x%08x",
num, self.address.nominal_address, addr, data)
return
self._cached_csw = data

try:
self.dp.write_ap(self.address.address + addr, data)
except exceptions.ProbeError:
Expand All @@ -1067,12 +1065,15 @@ def restore_original_csw_if_cached_modified(self) -> None:
return
if self._cached_csw != -1 and self._cached_csw != self.original_csw:
self.write_reg(self._reg_offset + MEM_AP_CSW, self.original_csw)
self._cached_csw = self.original_csw

def _invalidate_cache(self) -> None:
"""@brief Invalidate cached registers associated with this AP."""
self._cached_csw = -1

def _update_cache(self, value: int) -> None:
"""@brief Update cached value after an AP register access."""
self._cached_csw = value

def _reset_did_occur(self, notification: Notification) -> None:
"""@brief Handles reset notifications to invalidate CSW cache."""
# We clear the cache on all resets just to be safe.
Expand Down
21 changes: 17 additions & 4 deletions pyocd/coresight/dap.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# pyOCD debugger
# Copyright (c) 2015-2020,2025 Arm Limited
# Copyright (c) 2015-2020,2025-2026 Arm Limited
# Copyright (c) 2021-2023 Chris Reed
# Copyright (c) 2022 Clay McClure
# Copyright (c) 2022 Toshiba Electronic Devices & Storage Corporation
Expand Down Expand Up @@ -29,7 +29,6 @@
from ..core.target_delegate import DelegateHavingMixIn
from ..probe.debug_probe import DebugProbe
from ..probe.swj import SWJSequenceSender
from .ap import APSEL_APBANKSEL
from ..utility.sequencer import CallSequence
from ..utility.timeout import Timeout

Expand Down Expand Up @@ -86,6 +85,11 @@

# DP SELECT register fields.
SELECT_DPBANKSEL_MASK = 0x0000000f
# ADIv5 AP SELECT register fields.
SELECT_APSEL_MASK = 0xff000000
SELECT_APBANKSEL_MASK = 0x000000f0
SELECT_AP_MASK = SELECT_APSEL_MASK | SELECT_APBANKSEL_MASK
# ADIv6 AP SELECT register fields.
SELECT_APADDR_MASK = 0xfffffff0

DPIDR_REVISION_MASK = 0xf0000000
Expand Down Expand Up @@ -316,6 +320,7 @@ def __init__(self, probe: DebugProbe, target: Target) -> None:
self.aps: Dict[APAddressBase, AccessPort] = {}
self._access_number: int = 0
self._cached_dp_select: Optional[int] = None
self._cached_ap_cb: Dict[int, Callable[[int], None]] = {}
self._protocol: Optional[DebugProbe.Protocol] = None
self._probe_managed_ap_select: bool = False
self._probe_managed_dpbanksel: bool = False
Expand Down Expand Up @@ -723,7 +728,6 @@ def _write_dp_select(self, mask: int, value: int) -> None:

# Update the SELECT register and cache.
self.write_dp(DP_SELECT, select)
self._cached_dp_select = select

def _set_dpbanksel(self, addr: int, is_write: bool) -> bool:
"""@brief Updates the DPBANKSEL field of the SELECT register as required.
Expand Down Expand Up @@ -836,13 +840,20 @@ def write_dp(self, addr: int, data: int) -> None:
try:
TRACE.debug("write_dp:%06d (addr=0x%08x) = 0x%08x", num, addr, data)
self.probe.write_dp(addr & DPADDR_MASK, data)
# Update cached DP SELECT if writing to it.
if (addr & DPADDR_MASK) == DP_SELECT:
self._cached_dp_select = data
except exceptions.TargetError as error:
self._handle_error(error, num)
raise
finally:
if did_lock:
self.unlock()

def _update_ap_cache(self, addr: int, value: int) -> None:
if (cb := self._cached_ap_cb.get(addr)) is not None:
cb(value)

def _select_ap(self, addr: int) -> bool:
"""@brief Write DP_SELECT to choose the given AP.

Expand All @@ -858,7 +869,7 @@ def _select_ap(self, addr: int) -> bool:
# Write DP SELECT to select the probe.
self.lock()
if self.adi_version == ADIVersion.ADIv5:
self._write_dp_select(APSEL_APBANKSEL, addr & APSEL_APBANKSEL)
self._write_dp_select(SELECT_AP_MASK, addr & SELECT_AP_MASK)
elif self.adi_version == ADIVersion.ADIv6:
self._write_dp_select(SELECT_APADDR_MASK, addr & SELECT_APADDR_MASK)
else:
Expand All @@ -875,6 +886,7 @@ def write_ap(self, addr: int, data: int) -> None:
did_lock = self._select_ap(addr)
TRACE.debug("write_ap:%06d (addr=0x%08x) = 0x%08x", num, addr, data)
self.probe.write_ap(addr, data)
self._update_ap_cache(addr, data)
except exceptions.TargetError as error:
self._handle_error(error, num)
raise
Expand Down Expand Up @@ -920,6 +932,7 @@ def read_ap(self, addr: int, now: bool = True) -> Union[int, Callable[[], int]]:
def read_ap_cb() -> int:
try:
result = result_cb()
self._update_ap_cache(addr, result)
TRACE.debug("read_ap:%06d %s(addr=0x%08x) -> 0x%08x", num, "" if now else "...", addr, result)
return result
except exceptions.TargetError as error:
Expand Down
5 changes: 1 addition & 4 deletions pyocd/probe/jlink_probe.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# pyOCD debugger
# Copyright (c) 2020,2025 Arm Limited
# Copyright (c) 2020,2025-2026 Arm Limited
# Copyright (c) 2021-2022 Chris Reed
# Copyright (c) 2023 Marian Muller Rebeyrol
# Copyright (c) 2026 Christophe Dufaza
Expand Down Expand Up @@ -50,9 +50,6 @@ class JLinkProbe(DebugProbe):

# Bitmasks for AP register address fields.
A32 = 0x0000000c
APBANKSEL = 0x000000f0
APSEL = 0xff000000
APSEL_APBANKSEL = APSEL | APBANKSEL

@classmethod
def _get_jlink(cls) -> Optional[pylink.JLink]:
Expand Down
11 changes: 7 additions & 4 deletions pyocd/probe/stlink_probe.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# pyOCD debugger
# Copyright (c) 2018-2020,2022 Arm Limited
# Copyright (c) 2018-2020,2022,2026 Arm Limited
# Copyright (c) 2021-2023 Chris Reed
# SPDX-License-Identifier: Apache-2.0
#
Expand All @@ -24,7 +24,7 @@
from ..core.memory_interface import MemoryInterface
from ..core.plugin import Plugin
from ..core.options import OptionInfo
from ..coresight.ap import (APVersion, APSEL, APSEL_SHIFT, APv1Address)
from ..coresight.ap import (APVersion, APv1Address)
from .stlink.usb import STLinkUSBInterface
from .stlink.stlink import STLink
from .stlink.detect.factory import create_mbed_detector
Expand All @@ -38,6 +38,9 @@
class StlinkProbe(DebugProbe):
"""@brief Wraps an STLink as a DebugProbe."""

APSEL_SHIFT = 24
APSEL_MASK = 0xff000000

_board_id: Optional[str]

# Shared cache for the STLink Mbed board IDs read from MSD volumes.
Expand Down Expand Up @@ -228,7 +231,7 @@ def write_dp(self, addr, data):
self._link.write_dap_register(STLink.DP_PORT, addr, data)

def read_ap(self, addr, now=True):
apsel = (addr & APSEL) >> APSEL_SHIFT
apsel = (addr & self.APSEL_MASK) >> self.APSEL_SHIFT
result = self._link.read_dap_register(apsel, addr & 0xffff)

def read_ap_result_callback():
Expand All @@ -237,7 +240,7 @@ def read_ap_result_callback():
return result if now else read_ap_result_callback

def write_ap(self, addr, data):
apsel = (addr & APSEL) >> APSEL_SHIFT
apsel = (addr & self.APSEL_MASK) >> self.APSEL_SHIFT
self._link.write_dap_register(apsel, addr & 0xffff, data)

def read_ap_multiple(self, addr, count=1, now=True):
Expand Down
Loading