Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Major core register refactoring #933

Merged
merged 7 commits into from
Aug 16, 2020
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
112 changes: 64 additions & 48 deletions pyocd/cache/register.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# pyOCD debugger
# Copyright (c) 2016-2019 Arm Limited
# Copyright (c) 2016-2020 Arm Limited
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -16,14 +16,8 @@

import logging

from ..coresight.cortex_m import (
CORE_REGISTER,
register_name_to_index,
is_fpu_register,
is_cfbp_subregister,
is_psr_subregister,
sysm_to_psr_mask
)
from ..core import exceptions
from ..coresight.cortex_m_core_registers import (CortexMCoreRegisterInfo, index_for_reg)
from .metrics import CacheMetrics

LOG = logging.getLogger(__name__)
Expand All @@ -41,21 +35,26 @@ class RegisterCache(object):
Same logic applies for XPSR submasks.
"""

CFBP_REGS = [ CORE_REGISTER['cfbp'],
CORE_REGISTER['control'],
CORE_REGISTER['faultmask'],
CORE_REGISTER['basepri'],
CORE_REGISTER['primask'],
]

XPSR_REGS = [ CORE_REGISTER['xpsr'],
CORE_REGISTER['apsr'],
CORE_REGISTER['iapsr'],
CORE_REGISTER['eapsr'],
CORE_REGISTER['ipsr'],
CORE_REGISTER['epsr'],
CORE_REGISTER['iepsr'],
]
CFBP_INDEX = index_for_reg('cfbp')
XPSR_INDEX = index_for_reg('xpsr')

CFBP_REGS = [index_for_reg(name) for name in [
'cfbp',
'control',
'faultmask',
'basepri',
'primask',
]]

XPSR_REGS = [index_for_reg(name) for name in [
'xpsr',
'apsr',
'iapsr',
'eapsr',
'ipsr',
'epsr',
'iepsr',
]]

def __init__(self, context, core):
self._context = context
Expand All @@ -74,30 +73,28 @@ def _dump_metrics(self):
LOG.debug("no accesses")

def _check_cache(self):
"""! @brief Invalidates the cache if needed and returns whether the core is running."""
if self._core.is_running():
LOG.debug("core is running; invalidating cache")
self._reset_cache()
return True
elif self._run_token != self._core.run_token:
self._dump_metrics()
LOG.debug("out of date run token; invalidating cache")
self._reset_cache()
self._run_token = self._core.run_token
return False

def _convert_and_check_registers(self, reg_list):
# convert to index only
reg_list = [register_name_to_index(reg) for reg in reg_list]

# Sanity check register values
for reg in reg_list:
if reg not in CORE_REGISTER.values():
raise ValueError("unknown reg: %d" % reg)
elif is_fpu_register(reg) and (not self._core.has_fpu):
raise ValueError("attempt to read FPU register without FPU")

reg_list = [index_for_reg(reg) for reg in reg_list]
self._core.check_reg_list(reg_list)
return reg_list

def read_core_registers_raw(self, reg_list):
self._check_cache()
# Invalidate the cache. If the core is still running, just read directly from it.
if self._check_cache():
return self._context.read_core_registers_raw(reg_list)

reg_list = self._convert_and_check_registers(reg_list)
reg_set = set(reg_list)
Expand All @@ -111,33 +108,43 @@ def read_core_registers_raw(self, reg_list):
reading_cfbp = any(r for r in read_list if r in self.CFBP_REGS)
reading_xpsr = any(r for r in read_list if r in self.XPSR_REGS)
if reading_cfbp:
if not CORE_REGISTER['cfbp'] in read_list:
read_list.append(CORE_REGISTER['cfbp'])
cfbp_index = read_list.index(CORE_REGISTER['cfbp'])
if not self.CFBP_INDEX in read_list:
read_list.append(self.CFBP_INDEX)
cfbp_index = read_list.index(self.CFBP_INDEX)
if reading_xpsr:
if not CORE_REGISTER['xpsr'] in read_list:
read_list.append(CORE_REGISTER['xpsr'])
xpsr_index = read_list.index(CORE_REGISTER['xpsr'])
if not self.XPSR_INDEX in read_list:
read_list.append(self.XPSR_INDEX)
xpsr_index = read_list.index(self.XPSR_INDEX)
self._metrics.misses += len(read_list)
values = self._context.read_core_registers_raw(read_list)

# Read registers not in the cache from the target.
if read_list:
try:
values = self._context.read_core_registers_raw(read_list)
except exceptions.CoreRegisterAccessError:
# Invalidate cache on register read error just to be safe.
self._reset_cache()
raise
else:
values = []

# Update all CFBP based registers.
if reading_cfbp:
v = values[cfbp_index]
self._cache[CORE_REGISTER['cfbp']] = v
self._cache[self.CFBP_INDEX] = v
for r in self.CFBP_REGS:
if r == CORE_REGISTER['cfbp']:
if r == self.CFBP_INDEX:
continue
self._cache[r] = (v >> ((-r - 1) * 8)) & 0xff

# Update all XPSR based registers.
if reading_xpsr:
v = values[xpsr_index]
self._cache[CORE_REGISTER['xpsr']] = v
self._cache[self.XPSR_INDEX] = v
for r in self.XPSR_REGS:
if r == CORE_REGISTER['xpsr']:
if r == self.XPSR_INDEX:
continue
self._cache[r] = v & sysm_to_psr_mask(r)
self._cache[r] = v & CortexMCoreRegisterInfo.get(r).psr_mask

# Build the results list in the same order as requested registers.
results = []
Expand All @@ -154,7 +161,11 @@ def read_core_registers_raw(self, reg_list):

# TODO only write dirty registers to target right before running.
def write_core_registers_raw(self, reg_list, data_list):
self._check_cache()
# Check and invalidate the cache. If the core is still running, just pass the writes
# to our context.
if self._check_cache():
self._context.write_core_registers_raw(reg_list, data_list)
return

reg_list = self._convert_and_check_registers(reg_list)
self._metrics.writes += len(reg_list)
Expand All @@ -177,7 +188,12 @@ def write_core_registers_raw(self, reg_list, data_list):
self._cache.pop(r, None)

# Write new register values to target.
self._context.write_core_registers_raw(reg_list, data_list)
try:
self._context.write_core_registers_raw(reg_list, data_list)
except exceptions.CoreRegisterAccessError:
# Invalidate cache on register write error just to be safe.
self._reset_cache()
raise

def invalidate(self):
self._reset_cache()
Expand Down
Loading