1# Copyright (c) 2017 Linaro Limited. 2# 3# SPDX-License-Identifier: Apache-2.0 4 5'''Runner for NIOS II, based on quartus-flash.py and GDB.''' 6 7from runners.core import ZephyrBinaryRunner, NetworkPortHelper 8 9 10class Nios2BinaryRunner(ZephyrBinaryRunner): 11 '''Runner front-end for NIOS II.''' 12 13 # From the original shell script: 14 # 15 # "XXX [flash] only support[s] cases where the .elf is sent 16 # over the JTAG and the CPU directly boots from __start. CONFIG_XIP 17 # and CONFIG_INCLUDE_RESET_VECTOR must be disabled." 18 19 def __init__(self, cfg, quartus_py=None, cpu_sof=None, tui=False): 20 super().__init__(cfg) 21 self.hex_name = cfg.hex_file 22 self.elf_name = cfg.elf_file 23 self.cpu_sof = cpu_sof 24 self.quartus_py = quartus_py 25 self.gdb_cmd = [cfg.gdb] if cfg.gdb else None 26 self.tui_arg = ['-tui'] if tui else [] 27 28 @classmethod 29 def name(cls): 30 return 'nios2' 31 32 @classmethod 33 def do_add_parser(cls, parser): 34 # TODO merge quartus-flash.py script into this file. 35 parser.add_argument('--quartus-flash', required=True) 36 parser.add_argument('--cpu-sof', required=True, 37 help='path to the the CPU .sof data') 38 parser.add_argument('--tui', default=False, action='store_true', 39 help='if given, GDB uses -tui') 40 41 @classmethod 42 def do_create(cls, cfg, args): 43 return Nios2BinaryRunner(cfg, 44 quartus_py=args.quartus_flash, 45 cpu_sof=args.cpu_sof, 46 tui=args.tui) 47 48 def do_run(self, command, **kwargs): 49 if command == 'flash': 50 self.flash(**kwargs) 51 else: 52 self.debug_debugserver(command, **kwargs) 53 54 def flash(self, **kwargs): 55 if self.quartus_py is None: 56 raise ValueError('Cannot flash; --quartus-flash not given.') 57 if self.cpu_sof is None: 58 raise ValueError('Cannot flash; --cpu-sof not given.') 59 self.ensure_output('hex') 60 61 self.logger.info('Flashing file: {}'.format(self.hex_name)) 62 cmd = [self.quartus_py, 63 '--sof', self.cpu_sof, 64 '--kernel', self.hex_name] 65 self.require(cmd[0]) 66 self.check_call(cmd) 67 68 def print_gdbserver_message(self, gdb_port): 69 self.logger.info('Nios II GDB server running on port {}'. 70 format(gdb_port)) 71 72 def debug_debugserver(self, command, **kwargs): 73 # Per comments in the shell script, the NIOSII GDB server 74 # doesn't exit gracefully, so it's better to explicitly search 75 # for an unused port. The script picks a random value in 76 # between 1024 and 49151, but we'll start with the 77 # "traditional" 3333 choice. 78 gdb_start = 3333 79 nh = NetworkPortHelper() 80 gdb_port = nh.get_unused_ports([gdb_start])[0] 81 82 server_cmd = (['nios2-gdb-server', 83 '--tcpport', str(gdb_port), 84 '--stop', '--reset-target']) 85 self.require(server_cmd[0]) 86 87 if command == 'debugserver': 88 self.print_gdbserver_message(gdb_port) 89 self.check_call(server_cmd) 90 else: 91 if self.elf_name is None: 92 raise ValueError('Cannot debug; elf is missing') 93 if self.gdb_cmd is None: 94 raise ValueError('Cannot debug; no gdb specified') 95 96 gdb_cmd = (self.gdb_cmd + 97 self.tui_arg + 98 [self.elf_name, 99 '-ex', 'target remote :{}'.format(gdb_port)]) 100 self.require(gdb_cmd[0]) 101 102 self.print_gdbserver_message(gdb_port) 103 self.run_server_and_client(server_cmd, gdb_cmd) 104