You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
4.2 KiB
137 lines
4.2 KiB
# Copyright (c) 2021, Telink Semiconductor |
|
# |
|
# SPDX-License-Identifier: Apache-2.0 |
|
|
|
import os |
|
import re |
|
import subprocess |
|
import time |
|
|
|
from runners.core import BuildConfiguration, RunnerCaps, ZephyrBinaryRunner |
|
|
|
|
|
class SpiBurnBinaryRunner(ZephyrBinaryRunner): |
|
'''Runner front-end for SPI_burn.''' |
|
|
|
def __init__(self, cfg, addr, spiburn, iceman, timeout, gdb_port, gdb_ex, erase=False): |
|
super().__init__(cfg) |
|
|
|
self.spiburn = spiburn |
|
self.iceman = iceman |
|
self.addr = addr |
|
self.timeout = int(timeout) |
|
self.erase = bool(erase) |
|
self.gdb_port = gdb_port |
|
self.gdb_ex = gdb_ex |
|
|
|
@classmethod |
|
def name(cls): |
|
return 'spi_burn' |
|
|
|
@classmethod |
|
def capabilities(cls): |
|
return RunnerCaps(commands={'flash', 'debug'}, erase=True, flash_addr=True) |
|
|
|
@classmethod |
|
def do_add_parser(cls, parser): |
|
parser.add_argument('--addr', default='0x0', |
|
help='start flash address to write') |
|
parser.add_argument('--timeout', default=10, |
|
help='ICEman connection establishing timeout in seconds') |
|
parser.add_argument('--telink-tools-path', help='path to Telink flash tools') |
|
parser.add_argument('--gdb-port', default='1111', help='Port to connect for gdb-client') |
|
parser.add_argument('--gdb-ex', default='', nargs='?', help='Additional gdb commands to run') |
|
|
|
@classmethod |
|
def do_create(cls, cfg, args): |
|
|
|
if args.telink_tools_path: |
|
spiburn = f'{args.telink_tools_path}/flash/bin/SPI_burn' |
|
iceman = f'{args.telink_tools_path}/ice/ICEman' |
|
else: |
|
# If telink_tools_path arg is not specified then pass to tools shall be specified in PATH |
|
spiburn = 'SPI_burn' |
|
iceman = 'ICEman' |
|
|
|
# Get flash address offset |
|
if args.dt_flash == 'y': |
|
build_conf = BuildConfiguration(cfg.build_dir) |
|
address = hex(cls.get_flash_address(args, build_conf) - build_conf['CONFIG_FLASH_BASE_ADDRESS']) |
|
else: |
|
address = args.addr |
|
|
|
return SpiBurnBinaryRunner(cfg, address, spiburn, iceman, args.timeout, args.gdb_port, args.gdb_ex, args.erase) |
|
|
|
def do_run(self, command, **kwargs): |
|
|
|
self.require(self.spiburn) |
|
|
|
# Find path to ICEman with require call |
|
self.iceman_path = self.require(self.iceman) |
|
|
|
if command == "flash": |
|
self._flash() |
|
|
|
elif command == "debug": |
|
self._debug() |
|
|
|
else: |
|
self.logger.error(f'{command} not supported!') |
|
|
|
def start_iceman(self): |
|
|
|
# Start ICEman as background process |
|
self.ice_process = self.popen_ignore_int(["./ICEman", '-Z', 'v5', '-l', 'aice_sdp.cfg'], |
|
cwd=os.path.dirname(self.iceman_path), |
|
stdout=subprocess.PIPE) |
|
|
|
# Wait till it ready or exit by timeout |
|
start = time.time() |
|
while True: |
|
out = self.ice_process.stdout.readline() |
|
if b'ICEman is ready to use.' in out: |
|
break |
|
if time.time() - start > self.timeout: |
|
raise RuntimeError("TIMEOUT: ICEman is not ready") |
|
|
|
def stop_iceman(self): |
|
# Kill ICEman subprocess |
|
self.ice_process.terminate() |
|
|
|
def _flash(self): |
|
|
|
try: |
|
|
|
# Start ICEman |
|
self.start_iceman() |
|
|
|
# Compose flash command |
|
cmd_flash = [self.spiburn, '--addr', str(self.addr), '--image', self.cfg.bin_file] |
|
|
|
if self.erase: |
|
cmd_flash += ["--erase-all"] |
|
|
|
# Run SPI burn flash tool |
|
self.check_call(cmd_flash) |
|
|
|
finally: |
|
self.stop_iceman() |
|
|
|
def _debug(self): |
|
|
|
try: |
|
|
|
# Start ICEman |
|
self.start_iceman() |
|
|
|
# format -ex commands |
|
gdb_ex = re.split("(-ex) ", self.gdb_ex)[1::] |
|
|
|
# Compose gdb command |
|
client_cmd = [self.cfg.gdb, self.cfg.elf_file, '-ex', f'target remote :{self.gdb_port}'] + gdb_ex |
|
|
|
# Run gdb |
|
self.run_client(client_cmd) |
|
|
|
finally: |
|
self.stop_iceman()
|
|
|