Skip to content

Commit bd673c1

Browse files
authored
cbuild-run: update CbuildRun properties and add more debug logging (#1797)
1 parent eb64f42 commit bd673c1

File tree

1 file changed

+97
-71
lines changed

1 file changed

+97
-71
lines changed

pyocd/target/pack/cbuild_run.py

Lines changed: 97 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,19 @@ def _cbuild_target_update_processor_name(self) -> None:
127127
processors_map[core.name] = proc
128128
break
129129

130+
if LOG.isEnabledFor(logging.INFO):
131+
core_info = f"core {core.core_number}: {core.name} r{core.cpu_revision}p{core.cpu_patch}"
132+
if core.node_name != core.name:
133+
core_info += f", pname: {core.node_name}"
134+
LOG.info(core_info)
135+
130136
if processors_map:
131137
self._cbuild_device.processors_map = processors_map
132138

133139
@staticmethod
134140
def _cbuild_target_start_processor(self) -> None:
135141
"""@brief Updates the primary processor, based on 'start-pname' node in .cbuild-run.yml"""
136-
start_pname = self._cbuild_device.debugger.get('start-pname')
142+
start_pname = self._cbuild_device.start_pname
137143
if start_pname is not None and self.primary_core_pname != start_pname:
138144
core_number = next((core.core_number for core in self.cores.values() if core.node_name == start_pname), None)
139145
if core_number is not None:
@@ -152,7 +158,7 @@ def _cbuild_target_configure_core_reset(self) -> None:
152158
try:
153159
proc_info = self._cbuild_device.processors_ap_map[core_ap_addr]
154160
except KeyError:
155-
LOG.debug("core #%d not specified", core_num)
161+
LOG.debug("core %d not specified", core_num)
156162
continue
157163

158164
# Get this processor's list of sequences.
@@ -181,7 +187,7 @@ def is_reset_sequence_enabled(name: str) -> bool:
181187
updated_reset_types.add(Target.ResetType.SW_CORE) # type:ignore
182188

183189
core._supported_reset_types = updated_reset_types
184-
LOG.debug("updated DFP core #%d reset types: %s", core_num, core._supported_reset_types)
190+
LOG.debug("Updated core %d reset types: %s", core_num, core._supported_reset_types)
185191

186192
default_reset_seq = proc_info.default_reset_sequence
187193

@@ -192,22 +198,22 @@ def is_reset_sequence_enabled(name: str) -> bool:
192198
if default_reset_seq in sequences:
193199
# Custom reset sequence, not yet supported by pyocd.
194200
LOG.warning("DFP device definition error: custom reset sequences are not yet supported "
195-
"by pyocd; core #%d (%s) requested default reset sequence %s",
196-
core_num, proc_info.name, default_reset_seq)
201+
"by pyocd; core %d requested default reset sequence %s",
202+
core_num, default_reset_seq)
197203
else:
198204
# Invalid/unknown default reset sequence.
199205
LOG.warning("DFP device definition error: specified default reset sequence %s "
200-
"for core #%d (%s) does not exist",
201-
default_reset_seq, core_num, proc_info.name)
206+
"for core %d does not exist",
207+
default_reset_seq, core_num)
202208

203209
# Handle multicore debug mode causing secondary cores to default to processor reset.
204210
did_force_core_reset = False
205211
if (self.session.options.get('enable_multicore_debug')
206212
and (core_num != self.session.options.get('primary_core'))):
207213
if not is_reset_sequence_enabled('ResetProcessor'):
208214
LOG.warning("Multicore debug mode cannot select processor reset for secondary core "
209-
"#%d (%s) because it is disabled by the DFP; using emulated processor "
210-
"reset instead", core_num, proc_info.name)
215+
"%d because it is disabled by the DFP; using emulated processor "
216+
"reset instead", core_num)
211217
core.default_reset_type = Target.ResetType.SW_EMULATED
212218
continue
213219
else:
@@ -219,8 +225,8 @@ def is_reset_sequence_enabled(name: str) -> bool:
219225
# Only log a warning if we didn't decide to use core reset due to multicore mode.
220226
if not did_force_core_reset:
221227
LOG.warning("DFP device definition conflict: specified default reset sequence %s "
222-
"for core #%d (%s) is disabled by the DFP",
223-
default_reset_seq, core_num, proc_info.name)
228+
"for core #%d is disabled by the DFP",
229+
default_reset_seq, core_num)
224230

225231
# Map from disabled default to primary and secondary fallbacks.
226232
RESET_FALLBACKS: Dict[str, Tuple[str, str]] = {
@@ -237,13 +243,12 @@ def is_reset_sequence_enabled(name: str) -> bool:
237243
default_reset_seq = fallbacks[1]
238244
else:
239245
LOG.warning("DFP device definition conflict: all reset types are disabled for "
240-
"core #%d (%s) by the DFP; using emulated core reset",
246+
"core %d by the DFP; using emulated core reset",
241247
default_reset_seq, core_num)
242248
core.default_reset_type = Target.ResetType.SW_EMULATED
243249
continue
244250

245-
LOG.info("Setting core #%d (%s) default reset sequence to %s",
246-
core_num, proc_info.name, default_reset_seq)
251+
LOG.debug("Setting core %d default reset sequence to %s", core_num, default_reset_seq)
247252
core.default_reset_type = RESET_SEQUENCE_TO_TYPE_MAP[default_reset_seq]
248253

249254
@staticmethod
@@ -275,33 +280,40 @@ def __init__(self, yml_path: str) -> None:
275280
"""@brief Reads a .cbuild-run.yml file and validates its content."""
276281
self._data: Dict[str, Any] = {}
277282
self._valid: bool = False
283+
self._device: Optional[str] = None
284+
self._vendor: Optional[str] = None
278285
self._vars: Optional[Dict[str, str]] = None
279286
self._sequences: Optional[List[dict]] = None
287+
self._debugger: Optional[Dict[str, Any]] = None
280288
self._debug_topology: Optional[Dict[str, Any]] = None
281289
self._memory_map: Optional[MemoryMap] = None
290+
self._programming: Optional[List[dict]] = None
282291
self._valid_dps: List[int] = []
283292
self._apids: Dict[int, APAddressBase] = {}
284293
self._uses_apv2: bool = False
285294
self._built_apid_map: bool = False
286295
self._processors_map: Dict[str, ProcessorInfo] = {}
287296
self._processors_ap_map: Dict[APAddressBase, ProcessorInfo] = {}
288297
self._use_default_memory_map: bool = True
298+
self._system_resources: Optional[Dict[str, list]] = None
299+
self._system_descriptions: Optional[List[dict]] = None
300+
self._device_pack: Optional[List[str]] = None
289301

290302
try:
291303
# Normalize the path to ensure compatibility across platforms.
292304
yml_path = os.path.normpath(yml_path)
293305
with open(yml_path, 'r') as yml_file:
294306
yml_data = yaml.safe_load(yml_file)
295-
if 'cbuild-run' in yml_data:
296-
self._data = yml_data['cbuild-run']
297-
self._cmsis_pack_root()
298-
self._valid = True
299-
else:
300-
raise CbuildRunError(f"Invalid .cbuild-run.yml file '{yml_path}'")
301-
# Set cbuild-run path as the current working directory.
302-
base_path = Path(yml_path).parent
303-
os.chdir(base_path)
304-
LOG.debug("Working directory set to '%s'", os.getcwd())
307+
if 'cbuild-run' in yml_data:
308+
self._data = yml_data['cbuild-run']
309+
self._cmsis_pack_root()
310+
self._valid = True
311+
else:
312+
raise CbuildRunError(f"Invalid .cbuild-run.yml file '{yml_path}'")
313+
# Set cbuild-run path as the current working directory.
314+
base_path = Path(yml_path).parent
315+
os.chdir(base_path)
316+
LOG.debug("Working directory set to: '%s'", os.getcwd())
305317
except IOError as err:
306318
LOG.error("Error attempting to access .cbuild-run.yml file '%s': %s", yml_path, err)
307319

@@ -330,18 +342,19 @@ def _cmsis_pack_root(self) -> None:
330342
else:
331343
raise CbuildRunError(f"Unsupported platform '{system}' for CMSIS_PACK_ROOT. "
332344
"Please set the CMSIS_PACK_ROOT environment variable manually.")
345+
LOG.debug("CMSIS_PACK_ROOT set to: '%s'", os.environ['CMSIS_PACK_ROOT'])
333346

334347
@property
335348
def target(self) -> str:
336349
"""@brief Target identifier string.
337350
338351
Read `device` field from .cbuild-run.yml file, without 'vendor'.
339352
"""
340-
if self._valid:
353+
if self._device is None:
341354
device = self._data.get('device', '')
342-
return device.split('::')[1] if '::' in device else device
343-
else:
344-
return ''
355+
self._device = device.split('::')[1] if '::' in device else device
356+
LOG.info("Target device: %s", self._device)
357+
return self._device
345358

346359
@property
347360
def part_number(self) -> str:
@@ -353,11 +366,11 @@ def vendor(self) -> str:
353366
354367
Read 'vendor' part of `device` field from .cbuild-run.yml file.
355368
"""
356-
if self._valid and ('device' in self._data):
369+
if self._vendor is None:
357370
device = self._data.get('device', '')
358-
return device.split('::')[0] if '::' in device else ''
359-
else:
360-
return ''
371+
self._vendor = device.split('::')[0] if '::' in device else ''
372+
LOG.debug("Vendor: %s", self._vendor)
373+
return self._vendor
361374

362375
@property
363376
def families(self) -> List[str]:
@@ -387,6 +400,7 @@ def svd(self) -> Optional[IO[bytes]]:
387400
if desc['type'] == 'svd':
388401
norm_path = os.path.normpath(desc['file'])
389402
svd_path = Path(os.path.expandvars(norm_path))
403+
LOG.debug("SVD path: %s", svd_path)
390404
return io.BytesIO(svd_path.read_bytes())
391405
except (KeyError, IndexError):
392406
LOG.error("Could not locate SVD in cbuild-run system-descriptions.")
@@ -411,26 +425,24 @@ def output(self) -> Dict[str, Optional[int]]:
411425
offset = f.get('load-offset')
412426
# Add filename and it's offset to return value
413427
load_files[f['file']] = offset
414-
428+
LOG.debug("Loadable file: %s", f['file'])
415429
return load_files
416430

417431
@property
418432
def debug_sequences(self) -> List[dict]:
419433
"""@brief Debug sequences node."""
420-
if self._valid and ('debug-sequences' in self._data):
421-
if self._sequences is None:
422-
self._sequences = self._data.get('debug-sequences', [])
423-
return self._sequences
424-
return []
434+
if self._sequences is None:
435+
self._sequences = self._data.get('debug-sequences', [])
436+
LOG.debug("Read %d debug sequences", len(self._sequences))
437+
return self._sequences
425438

426439
@property
427440
def debug_vars(self) -> Dict[str, str]:
428441
"""@brief Debug variables."""
429-
if self._valid and ('debug-vars' in self._data):
430-
if self._vars is None:
431-
self._vars = self._data.get('debug-vars', {})
432-
return self._vars
433-
return {}
442+
if self._vars is None:
443+
self._vars = self._data.get('debug-vars', {})
444+
LOG.debug("Read debug variables")
445+
return self._vars
434446

435447
@property
436448
def valid_dps(self) -> List[int]:
@@ -463,6 +475,7 @@ def processors_map(self) -> Dict[str, ProcessorInfo]:
463475
@processors_map.setter
464476
def processors_map(self, proc_map: Dict[str, ProcessorInfo]) -> None:
465477
self._processors_map = proc_map
478+
LOG.debug("Updated processors map")
466479

467480
@property
468481
def processors_ap_map(self) -> Dict[APAddressBase, ProcessorInfo]:
@@ -477,60 +490,72 @@ def processors_ap_map(self) -> Dict[APAddressBase, ProcessorInfo]:
477490
@property
478491
def programming(self) -> List[dict]:
479492
"""@brief Programming section of cbuild-run."""
480-
if self._valid:
481-
return self._data.get('programming', [])
482-
return []
493+
if self._programming is None:
494+
self._programming = self._data.get('programming', [])
495+
LOG.debug("Read %d programming algorithms", len(self._programming))
496+
return self._programming
483497

484498
@property
485499
def debugger(self) -> Dict[str, Any]:
486500
"""@brief Debugger section of cbuild-run."""
487-
if self._valid:
488-
return self._data.get('debugger', {})
489-
return {}
501+
if self._debugger is None:
502+
self._debugger = self._data.get('debugger', {})
503+
LOG.debug("Read debugger configuration: %s", self._debugger)
504+
return self._debugger
490505

491506
@property
492507
def debugger_clock(self) -> Optional[int]:
493508
"""@brief Debugger clock frequency in Hz."""
494-
return self.debugger.get('clock', None)
509+
_debugger_clock = self.debugger.get('clock')
510+
if _debugger_clock is not None:
511+
LOG.debug("Debugger clock frequency: %s Hz", _debugger_clock)
512+
return _debugger_clock
495513

496514
@property
497515
def start_pname(self) -> Optional[str]:
498516
"""@brief Selected start processor name."""
499-
pname = self.debugger.get('start-pname')
500-
return pname
517+
_start_pname = self.debugger.get('start-pname')
518+
if _start_pname is not None:
519+
LOG.info("start-pname: %s", _start_pname)
520+
return _start_pname
501521

502522
@property
503523
def system_resources(self) -> Dict[str, list]:
504524
"""@brief System Resources section of cbuild-run."""
505-
if self._valid:
506-
return self._data.get('system-resources', {})
507-
return {}
525+
if self._system_resources is None:
526+
self._system_resources = self._data.get('system-resources', {})
527+
LOG.debug("Read system resources")
528+
return self._system_resources
508529

509530
@property
510531
def system_descriptions(self) -> List[dict]:
511532
"""@brief System Descriptions section of cbuild-run."""
512-
if self._valid:
513-
return self._data.get('system-descriptions', [])
514-
return []
533+
if self._system_descriptions is None:
534+
self._system_descriptions = self._data.get('system-descriptions', [])
535+
LOG.debug("Read system description files")
536+
return self._system_descriptions
515537

516538
@property
517539
def debug_topology(self) -> Dict[str, Any]:
518540
"""@brief Debug Topology section of cbuild-run."""
519-
if self._valid and ('debug-topology' in self._data):
520-
if self._debug_topology is None:
521-
self._debug_topology = self._data.get('debug-topology', {})
522-
return self._debug_topology
523-
return {}
541+
if self._debug_topology is None:
542+
self._debug_topology = self._data.get('debug-topology', {})
543+
LOG.debug("Read debug topology")
544+
return self._debug_topology
524545

525546
@property
526547
def device_pack(self) -> List[str]:
527548
"""@brief Value of 'device-pack' (DFP) prefixed with CMSIS_PACK_ROOT."""
528-
if self._valid and ('device-pack' in self._data):
529-
vendor, _pack = self._data['device-pack'].split('::', 1)
530-
name, version = _pack.split('@', 1)
531-
pack = os.path.normpath(f"${{CMSIS_PACK_ROOT}}/{vendor}/{name}/{version}")
532-
return [os.path.expandvars(pack)]
533-
return []
549+
if self._device_pack is None:
550+
if 'device-pack' in self._data:
551+
vendor, _pack = self._data['device-pack'].split('::', 1)
552+
name, version = _pack.split('@', 1)
553+
pack = os.path.normpath(f"${{CMSIS_PACK_ROOT}}/{vendor}/{name}/{version}")
554+
self._device_pack = [os.path.expandvars(pack)]
555+
else:
556+
self._device_pack = []
557+
LOG.debug("Device pack: %s", self._device_pack)
558+
return self._device_pack
534559

535560
def populate_target(self, target: Optional[str] = None) -> None:
536561
"""@brief Generates and populates the target defined by the .cbuild-run.yml file."""
@@ -581,6 +606,7 @@ def _fill_memory_gap(region: dict, start: int, end: int) -> dict:
581606

582607
# Create a copy of PDSC and user-defined memory regions from system resources
583608
defined_memory = deepcopy(self.system_resources.get('memory', []))
609+
LOG.debug("Read defined memory regions")
584610
# Mark memory as 'defined'
585611
for memory in defined_memory:
586612
memory['defined'] = True
@@ -910,10 +936,10 @@ def get_root_scope(self, context: DebugSequenceExecutionContext) -> Scope:
910936
# Make all vars read-only.
911937
self._debugvars.freeze()
912938

913-
if LOG.isEnabledFor(logging.INFO):
939+
if LOG.isEnabledFor(logging.DEBUG):
914940
for name in sorted(self._debugvars.variables):
915941
value = self._debugvars.get(name)
916-
LOG.info("debugvar '%s' = %#x (%d)", name, value, value)
942+
LOG.debug("debugvar '%s' = %#x (%d)", name, value, value)
917943

918944
return self._debugvars
919945

0 commit comments

Comments
 (0)