scripts: west: introduce Lauterbach TRACE32 runner

This patch introduces a West runner for flashing and debugging with
Lauterbach TRACE32 debuggers. The runner consists of a wrapper around
TRACE32 software, and allows a Zephyr board to execute a custom start-up
script (Practice Script) for the different commands supported, including
the ability to pass extra arguments from CMake. Is up to the board using
this runner to define the actions performed on each command.

The `debug` command launches TRACE32 GUI to allow debug the Zephyr
application, while the `flash` command hides the GUI and executes the
start-up script in a background process.

Signed-off-by: Manuel Arguelles <manuel.arguelles@nxp.com>
This commit is contained in:
Manuel Arguelles 2022-08-07 04:25:52 +07:00 committed by Carles Cufí
parent 1dd312fd17
commit 31b3993d58
5 changed files with 217 additions and 0 deletions

View file

@ -0,0 +1,6 @@
# Copyright 2022 NXP
# SPDX-License-Identifier: Apache-2.0
board_set_flasher_ifnset(trace32)
board_set_debugger_ifnset(trace32)
board_finalize_runner_args(trace32)

View file

@ -255,6 +255,58 @@ These debug host tools are compatible with the following debug probes:
Check if your SoC is listed in `pyOCD Supported Devices`_.
.. _lauterbach-trace32-debug-host-tools:
Lauterbach TRACE32 Debug Host Tools
***********************************
`Lauterbach TRACE32`_ is a product line of microprocessor development tools,
debuggers and real-time tracer with support for JTAG, SWD, NEXUS or ETM over
multiple core architectures, including Arm Cortex-A/-R/-M, RISC-V, Xtensa, etc.
Zephyr allows users to develop and program boards with Lauterbach TRACE32
support using :ref:`west <west-flashing>`.
The runner consists of a wrapper around TRACE32 software, and allows a Zephyr
board to execute a custom start-up script (Practice Script) for the different
commands supported, including the ability to pass extra arguments from CMake.
Is up to the board using this runner to define the actions performed on each
command.
Install Lauterbach TRACE32 Software
-----------------------------------
Download Lauterbach TRACE32 software from the `Lauterbach TRACE32 download website`_
(registration required) and follow the installation steps described in
`Lauterbach TRACE32 Installation Guide`_.
Flashing and Debugging
----------------------
Set the :ref:`environment variable <env_vars>` :envvar:`T32_DIR` to the TRACE32
system directory. Then execute ``west flash`` or ``west debug`` commands to
flash or debug the Zephyr application as detailed in :ref:`west-build-flash-debug`.
The ``debug`` command launches TRACE32 GUI to allow debug the Zephyr
application, while the ``flash`` command hides the GUI and perform all
operations in the background.
By default, the ``t32`` runner will launch TRACE32 using the default
configuration file named ``config.t32`` located in the TRACE32 system
directory. To use a different configuration file, supply the argument
``--config CONFIG`` to the runner, for example:
.. code-block:: console
west flash --config myconfig.t32
For more options, run ``west flash --context -r t32`` to print the usage.
Zephyr RTOS Awareness
---------------------
To enable Zephyr RTOS awareness follow the steps described in
`Lauterbach TRACE32 Zephyr OS Awareness Manual`_.
.. _J-Link Software and Documentation Pack:
https://www.segger.com/downloads/jlink/#J-LinkSoftwareAndDocumentationPack
@ -272,3 +324,15 @@ Check if your SoC is listed in `pyOCD Supported Devices`_.
.. _OpenOCD Windows:
http://gnutoolchains.com/arm-eabi/openocd/
.. _Lauterbach TRACE32:
https://www.lauterbach.com/
.. _Lauterbach TRACE32 download website:
http://www.lauterbach.com/download_trace32.html
.. _Lauterbach TRACE32 Installation Guide:
https://www2.lauterbach.com/pdf/installation.pdf
.. _Lauterbach TRACE32 Zephyr OS Awareness Manual:
https://www2.lauterbach.com/pdf/rtos_zephyr.pdf

View file

@ -48,6 +48,7 @@ _names = [
'spi_burn',
'stm32cubeprogrammer',
'stm32flash',
'trace32',
'xtensa',
# Keep this list sorted by runner name; don't add to the end.
]

View file

@ -0,0 +1,145 @@
# Copyright 2022 NXP
# SPDX-License-Identifier: Apache-2.0
'''Runner for Lauterbach TRACE32.'''
import argparse
import os
import platform
import subprocess
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import List, Optional
from runners.core import BuildConfiguration, RunnerCaps, RunnerConfig, ZephyrBinaryRunner
DEFAULT_T32_CONFIG = Path('config.t32')
class TRACE32BinaryRunner(ZephyrBinaryRunner):
'''
Runner front-end for Lauterbach TRACE32.
The runner is a wrapper around Lauterbach TRACE32 PowerView. It executes a Lauterbach Practice
script (.cmm) after launching the debugger, which should be located at
zephyr/boards/<board>/support/<command>.cmm, where <board> is the board directory and <command>
is the name of the west runner command executed (e.g. flash or debug). Extra arguments can be
passed to the startup script by using the command line option --startup-args.
'''
def __init__(self,
cfg: RunnerConfig,
t32_cfg: Path,
arch: str,
startup_args: List[str] = None,
timeout: int = 60) -> None:
super(TRACE32BinaryRunner, self).__init__(cfg)
self.arch = arch
self.t32_cfg = t32_cfg
self.t32_exec: Optional[Path] = None
self.startup_dir = Path(cfg.board_dir) / 'support'
self.startup_args = startup_args
self.timeout = timeout
@classmethod
def name(cls) -> str:
return 'trace32'
@classmethod
def capabilities(cls) -> RunnerCaps:
return RunnerCaps(commands={'flash', 'debug'})
@classmethod
def do_add_parser(cls, parser: argparse.ArgumentParser) -> None:
parser.add_argument('--arch',
default='auto',
choices=('auto', 'arm', 'riscv', 'xtensa'),
help='Target architecture. Set to "auto" to select the architecture '
'based on CONFIG_ARCH value')
parser.add_argument('--config',
default=DEFAULT_T32_CONFIG,
type=Path,
help='Override TRACE32 configuration file path. Can be a relative path '
'to T32_DIR environment variable, or an absolute path')
parser.add_argument('--startup-args',
nargs='*',
help='Arguments to pass to the start-up script')
parser.add_argument('--timeout',
default=60,
type=int,
help='Timeout, in seconds, of the flash operation')
@classmethod
def do_create(cls, cfg: RunnerConfig, args: argparse.Namespace) -> 'TRACE32BinaryRunner':
build_conf = BuildConfiguration(cfg.build_dir)
if args.arch == 'auto':
arch = build_conf.get('CONFIG_ARCH').replace('"', '')
# there is a single binary for all ARM architectures
arch = arch.replace('arm64', 'arm')
else:
arch = args.arch
return TRACE32BinaryRunner(cfg, args.config, arch, startup_args=args.startup_args,
timeout=args.timeout)
def do_run(self, command, **kwargs) -> None:
t32_dir = os.environ.get('T32_DIR')
if not t32_dir:
raise RuntimeError('T32_DIR environment variable undefined')
if platform.system() == 'Windows':
os_name = 'windows64'
suffix = '.exe'
elif platform.system() == 'Linux':
os_name = 'pc_linux64'
suffix = ''
else:
raise RuntimeError('Host OS not supported by this runner')
self.t32_exec = Path(t32_dir) / 'bin' / os_name / f't32m{self.arch}{suffix}'
if not self.t32_exec.exists():
raise RuntimeError(f'Cannot find Lauterbach executable at {self.t32_exec}')
if not self.t32_cfg.is_absolute():
self.t32_cfg = Path(t32_dir) / self.t32_cfg
if not self.t32_cfg.exists():
raise RuntimeError(f'Cannot find Lauterbach configuration at {self.t32_cfg}')
startup_script = self.startup_dir / f'{command}.cmm'
if not startup_script.exists():
raise RuntimeError(f'Cannot find start-up script at {startup_script}')
if command == 'flash':
self.flash(**kwargs)
elif command == 'debug':
self.debug(**kwargs)
def flash(self, **kwargs) -> None:
with TemporaryDirectory(suffix='t32') as tmp_dir:
# use a temporary config file, based on the provided configuration,
# to hide the TRACE32 software graphical interface
cfg_content = f'{self.t32_cfg.read_text()}\n\nSCREEN=OFF\n'
tmp_cfg = Path(tmp_dir) / DEFAULT_T32_CONFIG.name
tmp_cfg.write_text(cfg_content)
cmd = self.get_launch_command('flash', cfg=tmp_cfg)
self.logger.info(f'Launching TRACE32: {" ".join(cmd)}')
try:
self.check_call(cmd, timeout=self.timeout)
self.logger.info('Finished')
except subprocess.TimeoutExpired:
self.logger.error(f'Timed out after {self.timeout} seconds')
def debug(self, **kwargs) -> None:
cmd = self.get_launch_command('debug')
self.logger.info(f'Launching TRACE32: {" ".join(cmd)}')
self.check_call(cmd)
def get_launch_command(self, command_name: str, cfg: Path = None) -> List[str]:
cmd = [
str(self.t32_exec),
'-c', str(cfg if cfg else self.t32_cfg),
'-s', str(self.startup_dir / f'{command_name}.cmm')
]
if self.startup_args:
cmd.extend(self.startup_args)
return cmd

View file

@ -38,5 +38,6 @@ def test_runner_imports():
'spi_burn',
'stm32cubeprogrammer',
'stm32flash',
'trace32',
'xtensa'))
assert runner_names == expected