blob: 6dbffa30dbd9bd0a00d2a02e6994e34c09df66ed [file] [log] [blame]
# Copyright (c) 2020 Synopsys.
#
# SPDX-License-Identifier: Apache-2.0
'''Runners for Synopsys Metaware Debugger(mdb).'''
import shutil
import os
from os import path
from runners.core import ZephyrBinaryRunner, RunnerCaps
# normally we should create class with common functionality inherited from
# ZephyrBinaryRunner and inherit MdbNsimBinaryRunner and MdbHwBinaryRunner
# from it. However as we do lookup for runners with
# ZephyrBinaryRunner.__subclasses__() such sub-sub-classes won't be found.
# So, we move all common functionality to helper functions instead.
def is_simulation_run(mdb_runner):
return mdb_runner.nsim_args != ''
def is_hostlink_used(mdb_runner):
return mdb_runner.build_conf.getboolean('CONFIG_UART_HOSTLINK')
def is_flash_cmd_need_exit_immediately(mdb_runner):
if is_simulation_run(mdb_runner):
# for nsim, we can't run and quit immediately
return False
elif is_hostlink_used(mdb_runner):
# if hostlink is used we can't run and quit immediately, as we still need MDB process
# attached to process hostlink IO
return False
else:
return True
def smp_core_order(mdb_runner, id):
if is_simulation_run(mdb_runner):
# for simulation targets we start cores in direct order (core 0 first, core 1 second, etc...)
# otherwise we face mismatch arcnum (code ID) with ARConnect ID and core ID in instruction traces
return id
else:
# for HW targets we want to start the primary core last, to avoid ARConnect initialization interfere
# with secondary cores startup - so we reverse start order
return mdb_runner.cores - 1 - id
def mdb_do_run(mdb_runner, command):
commander = "mdb64"
mdb_runner.require(commander)
mdb_basic_options = ['-nooptions', '-nogoifmain', '-toggle=include_local_symbols=1']
# remove previous .sc.project folder which has temporary settings
# for MDB. This is useful for troubleshooting situations with
# unexpected behavior of the debugger
mdb_cfg_dir = path.join(mdb_runner.build_dir, '.sc.project')
if path.exists(mdb_cfg_dir):
shutil.rmtree(mdb_cfg_dir)
# nsim
if is_simulation_run(mdb_runner):
mdb_target = ['-nsim', '@' + mdb_runner.nsim_args]
# hardware target
else:
if mdb_runner.jtag == 'digilent':
mdb_target = ['-digilent']
if mdb_runner.dig_device: mdb_target += [mdb_runner.dig_device]
else:
# \todo: add support of other debuggers
raise ValueError('unsupported jtag adapter {}'.format(mdb_runner.jtag))
if command == 'flash':
if is_flash_cmd_need_exit_immediately(mdb_runner):
mdb_run = ['-run', '-cmd=-nowaitq run', '-cmd=quit', '-cl']
else:
mdb_run = ['-run', '-cl']
elif command == 'debug':
# use mdb gui to debug
mdb_run = ['-OKN']
if mdb_runner.cores == 1:
# single core's mdb command is different with multicores
mdb_cmd = [commander] + mdb_basic_options + mdb_target + mdb_run + [mdb_runner.elf_name]
elif 1 < mdb_runner.cores <= 12:
mdb_multifiles = '-multifiles='
for i in range(mdb_runner.cores):
mdb_sub_cmd = [commander] + ['-pset={}'.format(i + 1), '-psetname=core{}'.format(i)]
# -prop=download=2 is used for SMP application debug, only the 1st core
# will download the shared image.
if i > 0: mdb_sub_cmd += ['-prop=download=2']
mdb_sub_cmd += mdb_basic_options + mdb_target + [mdb_runner.elf_name]
mdb_runner.check_call(mdb_sub_cmd, cwd=mdb_runner.build_dir)
mdb_multifiles += ('core{}' if i == 0 else ',core{}').format(smp_core_order(mdb_runner, i))
# to enable multi-core aware mode for use with the MetaWare debugger,
# need to set the NSIM_MULTICORE environment variable to a non-zero value
if is_simulation_run(mdb_runner):
os.environ["NSIM_MULTICORE"] = '1'
mdb_cmd = [commander] + [mdb_multifiles] + mdb_run
else:
raise ValueError('unsupported cores {}'.format(mdb_runner.cores))
mdb_runner.call(mdb_cmd, cwd=mdb_runner.build_dir)
class MdbNsimBinaryRunner(ZephyrBinaryRunner):
'''Runner front-end for nSIM via mdb.'''
def __init__(self, cfg, cores=1, nsim_args=''):
super().__init__(cfg)
self.jtag = ''
self.cores = int(cores)
if nsim_args != '':
self.nsim_args = path.join(cfg.board_dir, 'support', nsim_args)
else:
self.nsim_args = ''
self.elf_name = cfg.elf_file
self.build_dir = cfg.build_dir
self.dig_device = ''
@classmethod
def name(cls):
return 'mdb-nsim'
@classmethod
def capabilities(cls):
return RunnerCaps(commands={'flash', 'debug'})
@classmethod
def do_add_parser(cls, parser):
parser.add_argument('--cores', default=1,
help='''choose the cores that target has, e.g.
--cores=1''')
parser.add_argument('--nsim_args', default='',
help='''if given, arguments for nsim simulator
through mdb which should be in
<board_dir>/support, e.g. --nsim-args=
mdb_em.args''')
@classmethod
def do_create(cls, cfg, args):
return MdbNsimBinaryRunner(
cfg,
cores=args.cores,
nsim_args=args.nsim_args)
def do_run(self, command, **kwargs):
mdb_do_run(self, command)
class MdbHwBinaryRunner(ZephyrBinaryRunner):
'''Runner front-end for mdb.'''
def __init__(self, cfg, cores=1, jtag='digilent', dig_device=''):
super().__init__(cfg)
self.jtag = jtag
self.cores = int(cores)
self.nsim_args = ''
self.elf_name = cfg.elf_file
if dig_device != '':
self.dig_device = '-prop=dig_device=' + dig_device
else:
self.dig_device = ''
self.build_dir = cfg.build_dir
@classmethod
def name(cls):
return 'mdb-hw'
@classmethod
def capabilities(cls):
return RunnerCaps(commands={'flash', 'debug'})
@classmethod
def do_add_parser(cls, parser):
parser.add_argument('--jtag', default='digilent',
help='''choose the jtag interface for hardware
targets, e.g. --jtag=digilent for digilent
jtag adapter''')
parser.add_argument('--cores', default=1,
help='''choose the number of cores that target has,
e.g. --cores=1''')
parser.add_argument('--dig-device', default='',
help='''choose the specific digilent device to
connect, this is useful when multiple
targets are connected''')
@classmethod
def do_create(cls, cfg, args):
return MdbHwBinaryRunner(
cfg,
cores=args.cores,
jtag=args.jtag,
dig_device=args.dig_device)
def do_run(self, command, **kwargs):
mdb_do_run(self, command)