scripts: runner: add debug support to nios.py
Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
diff --git a/scripts/support/runner/nios2.py b/scripts/support/runner/nios2.py
index b18145a..480e1ed 100644
--- a/scripts/support/runner/nios2.py
+++ b/scripts/support/runner/nios2.py
@@ -2,11 +2,12 @@
#
# SPDX-License-Identifier: Apache-2.0
-'''Runner for NIOS II.'''
+'''Runner for NIOS II, based on quartus-flash.py and GDB.'''
from os import path
+import os
-from .core import ZephyrBinaryRunner, get_env_or_bail
+from .core import ZephyrBinaryRunner, NetworkPortHelper
class Nios2BinaryRunner(ZephyrBinaryRunner):
@@ -18,31 +19,62 @@
# over the JTAG and the CPU directly boots from __start. CONFIG_XIP
# and CONFIG_INCLUDE_RESET_VECTOR must be disabled."
- def __init__(self, hex_, cpu_sof, zephyr_base, debug=False):
+ def __init__(self, hex_name=None, elf_name=None, cpu_sof=None,
+ zephyr_base=None, gdb=None, tui=None, debug=False):
super(Nios2BinaryRunner, self).__init__(debug=debug)
- self.hex_ = hex_
+ self.hex_name = hex_name
+ self.elf_name = elf_name
self.cpu_sof = cpu_sof
self.zephyr_base = zephyr_base
+ self.gdb_cmd = [gdb] if gdb is not None else None
+ self.tui_arg = [tui] if tui is not None else []
def replaces_shell_script(shell_script, command):
- return command == 'flash' and shell_script == 'nios2.sh'
+ return (command in {'flash', 'debug', 'debugserver'} and
+ shell_script == 'nios2.sh')
def create_from_env(command, debug):
'''Create runner from environment.
- Required:
+ Required for 'flash', 'debug':
- O: build output directory
+
+ Required for 'flash':
+
- KERNEL_HEX_NAME: name of kernel binary in HEX format
- NIOS2_CPU_SOF: location of the CPU .sof data
- ZEPHYR_BASE: zephyr Git repository base directory
- '''
- hex_ = path.join(get_env_or_bail('O'),
- get_env_or_bail('KERNEL_HEX_NAME'))
- cpu_sof = get_env_or_bail('NIOS2_CPU_SOF')
- zephyr_base = get_env_or_bail('ZEPHYR_BASE')
- return Nios2BinaryRunner(hex_, cpu_sof, zephyr_base, debug=debug)
+ Required for 'debug':
+
+ - KERNEL_ELF_NAME: name of kernel binary in ELF format
+ - GDB: GDB executable
+
+ Optional for 'debug':
+
+ - TUI: one additional argument to GDB (e.g. -tui)
+ '''
+ cpu_sof = os.environ.get('NIOS2_CPU_SOF', None)
+ zephyr_base = os.environ.get('ZEPHYR_BASE', None)
+
+ o = os.environ.get('O', None)
+ hex_ = os.environ.get('KERNEL_HEX_NAME', None)
+ elf = os.environ.get('KERNEL_ELF_NAME', None)
+ hex_name = None
+ elf_name = None
+ if o is not None:
+ if hex_ is not None:
+ hex_name = path.join(o, hex_)
+ if elf is not None:
+ elf_name = path.join(o, elf)
+
+ gdb = os.environ.get('GDB', None)
+ tui = os.environ.get('TUI', None)
+
+ return Nios2BinaryRunner(hex_name=hex_name, elf_name=elf_name,
+ cpu_sof=cpu_sof, zephyr_base=zephyr_base,
+ gdb=gdb, tui=tui, debug=debug)
def run(self, command, **kwargs):
if command not in {'flash', 'debug', 'debugserver'}:
@@ -54,12 +86,54 @@
self.debug_debugserver(command, **kwargs)
def flash(self, **kwargs):
+ sof_msg = (
+ 'Cannot flash; '
+ 'Please set NIOS2_CPU_SOF variable to location of CPU .sof data')
+
+ if self.zephyr_base is None:
+ raise ValueError('Cannot flash; ZEPHYR_BASE is missing.')
+ if self.cpu_sof is None:
+ raise ValueError(sof_msg)
+ if self.hex_name is None:
+ raise ValueError('Cannot flash; .hex binary name is missing')
+
cmd = [path.join(self.zephyr_base, 'scripts', 'support',
'quartus-flash.py'),
'--sof', self.cpu_sof,
- '--kernel', self.hex_]
+ '--kernel', self.hex_name]
self.check_call(cmd)
- def debug_debugserver(command, **kwargs):
- raise NotImplementedError()
+ def print_gdbserver_message(self, gdb_port):
+ print('Nios II GDB server running on port {}'.format(gdb_port))
+
+ def debug_debugserver(self, command, **kwargs):
+ # Per comments in the shell script, the NIOSII GDB server
+ # doesn't exit gracefully, so it's better to explicitly search
+ # for an unused port. The script picks a random value in
+ # between 1024 and 49151, but we'll start with the
+ # "traditional" 3333 choice.
+ gdb_start = 3333
+ nh = NetworkPortHelper()
+ gdb_port = nh.get_unused_ports([gdb_start])[0]
+
+ server_cmd = (['nios2-gdb-server',
+ '--tcpport', str(gdb_port),
+ '--stop', '--reset-target'])
+
+ if command == 'debugserver':
+ self.print_gdbserver_message(gdb_port)
+ self.check_call(server_cmd)
+ else:
+ if self.elf_name is None:
+ raise ValueError('Cannot debug; elf is missing')
+ if self.gdb_cmd is None:
+ raise ValueError('Cannot debug; no gdb specified')
+
+ gdb_cmd = (self.gdb_cmd +
+ self.tui_arg +
+ [self.elf_name,
+ '-ex', 'target remote :{}'.format(gdb_port)])
+
+ self.print_gdbserver_message(gdb_port)
+ self.run_server_and_client(server_cmd, gdb_cmd)