diff options
Diffstat (limited to '')
| -rw-r--r-- | sim/gdbstub.py | 47 | ||||
| -rwxr-xr-x | sim/sim.py | 67 |
2 files changed, 83 insertions, 31 deletions
diff --git a/sim/gdbstub.py b/sim/gdbstub.py index 3833da7..63bef9b 100644 --- a/sim/gdbstub.py +++ b/sim/gdbstub.py @@ -1,4 +1,4 @@ -import sys, socket +import sys, socket, traceback cycles = None enable_tty = True @@ -20,6 +20,15 @@ def fatal(): stop_reason = 'fatal' yield_to_gdb() +def do_output(text): + if text is None: + return not is_halted() + elif not client: + return False + + reply(b'O' + hexout(text.encode('ascii'))) + return True + buffer = b'' stop_reason = None @@ -27,11 +36,7 @@ def yield_to_gdb(): global client, buffer, stop_reason if not client: - print('Listening for gdb on', sock.getsockname(), file=sys.stderr) - client, peer = sock.accept() - print('Accepted connection from', peer, file=sys.stderr) - register_interrupt(client) stop_reason = 'reset' @@ -77,19 +82,19 @@ def yield_to_gdb(): client.send(b'+') if data == b'?': - out = stop_reply + replyout = stop_reply elif data == b'c' and not dead: return 'continue' elif data == b'D': - out = b'OK' + replyout = b'OK' elif data == b'g': - out = hexout(read_reg(gdb_reg(r)) for r in range(16)) + replyout = hexout(read_reg(gdb_reg(r)) for r in range(16)) elif data[0] == b'G': for reg, value in enumerate(hexin(data[1:])): write_reg(reg, value) elif data[0] == b'm'[0]: addr, length = (int(x, 16) for x in data[1:].split(b',')) - out = hexout(read_mem(addr, length, may_fail = True)) + replyout = hexout(read_mem(addr, length, may_fail = True)) elif data[0] == b'M'[0]: addrlen, data = data[1:].split(b':') addr, length = (int(x, 16) for x in addrlen.split(b',')) @@ -98,22 +103,34 @@ def yield_to_gdb(): assert len(data) == length write_mem(addr, data) - out = b'OK' + replyout = b'OK' elif data[0] == b'p'[0]: reg = gdb_reg(int(data[1:], 16)) - out = hexout(read_reg(reg) if reg is not None else None) + replyout = hexout(read_reg(reg) if reg is not None else None) elif data[0] == b'P'[0]: reg, value = data[1:].split(b'=') write_reg(gdb_reg(int(reg, 16)), hexin(value, single=True)) elif data == b's' and not dead: return 'step' + elif data.startswith(b'qRcmd,'): + try: + result = eval(bytes.fromhex(str(data.removeprefix(b'qRcmd,'), 'ascii'))) + except Exception: + result = None + out(traceback.format_exc()) + + if result is not None: + out(repr(result)) + + flush_out() + replyout = b'OK' else: - out = b'' + replyout = b'' - reply(out) + reply(replyout) -def reply(out): - client.send(b'$' + out + b'#' + hexout(sum(out) & 0xff, size=1)) +def reply(replyout): + client.send(b'$' + replyout + b'#' + hexout(sum(replyout) & 0xff, size=1)) def gdb_reg(n): if 0 <= n < 8: @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -import importlib.util, os, pathlib, random, selectors, signal, socket, subprocess, sys +import importlib.util, io, os, pathlib, random, selectors, signal, socket, subprocess, sys module_path, verilated, image = sys.argv[1:] test_name = pathlib.Path(module_path).stem @@ -77,6 +77,34 @@ all_regs = [ regs = {} read_reg = lambda r: regs.setdefault(r, 0) +output_buffer = None +def out(*args, **kwargs): + global output_buffer + + if do_output: + if output_buffer is None: + output_buffer = io.StringIO() + + print(*args, **kwargs, file=output_buffer) + if do_output(None): + flush_out() + else: + print(*args, **kwargs, file=sys.stderr) + +def flush_out(): + global do_output, output_buffer + if output_buffer and output_buffer: + text = output_buffer.getvalue() + output_buffer.close() + output_buffer = None + + try: + if do_output(text): + return + except: + do_output = None + print(text, file=sys.stderr) + def write_reg(reg, value): assert halted @@ -102,7 +130,7 @@ def recv_mem_dump(): dumped.append((int(base, 16) << 2, bytes.fromhex(data))) except ValueError: while_running() - print(f'{COLOR_BLUE}{line}{COLOR_RESET}') + out(f'{COLOR_BLUE}{line}{COLOR_RESET}') def read_mem(base, length, *, may_fail = False): fragments = [] @@ -180,12 +208,12 @@ def exit(*, success): if not success: while_running() if exec_args: - print('cmdline:', subprocess.list2cmdline(exec_args), file=sys.stderr) + out('cmdline:', subprocess.list2cmdline(exec_args)) status, color = ('passed', COLOR_GREEN) if success else (f'failed (seed: {seed})', COLOR_RED) - print( \ + out( \ f'{color}Test \'{COLOR_YELLOW}{test_name}{COLOR_RESET}{color}\' ' + - f'{status}{COLOR_RESET}', file=sys.stderr) + f'{status}{COLOR_RESET}') sys.exit(0 if success else 1) @@ -195,24 +223,24 @@ def dump_regs(): for reg, value in sorted(regs.items(), key=lambda item: order[item[0]]): if next_col > 0: - print(' ', end='', file=sys.stderr) + out(' ', end='') - print(f'{reg:<8} = 0x{value:08x}', end='', file=sys.stderr) + out(f'{reg:<8} = 0x{value:08x}', end='') if next_col == 3: - print(file=sys.stderr) + out() next_col = 0 else: next_col += 1 if next_col != 0: - print(file=sys.stderr) + out() printed_while_running = False def while_running(): global printed_while_running if not printed_while_running: - print( + out( f'{COLOR_BLUE}While running test \'{COLOR_YELLOW}{test_name}' + \ f'{COLOR_RESET}{COLOR_BLUE}\'{COLOR_RESET}') @@ -221,7 +249,7 @@ def while_running(): def test_assert(condition, message): if not condition: while_running() - print(f'{COLOR_RED}{message()}{COLOR_RESET}', file=sys.stderr) + out(f'{COLOR_RED}{message()}{COLOR_RESET}') if regs: dump_regs() @@ -271,9 +299,9 @@ def init_reg(r, value): init_regs[r] = unsigned(value) if test_name in os.getenv('SIM_SKIP', '').split(','): - print( \ + out( \ f'{COLOR_BLUE}Test \'{COLOR_YELLOW}{test_name}{COLOR_RESET}' + - f'{COLOR_BLUE}\' skipped{COLOR_RESET}', file=sys.stderr) + f'{COLOR_BLUE}\' skipped{COLOR_RESET}') exit(success=True) @@ -289,6 +317,9 @@ spec = importlib.util.spec_from_file_location('sim', module_path) module = importlib.util.module_from_spec(spec) prelude = { + 'out': out, + 'flush_out': flush_out, + 'is_halted': lambda: halted, 'read_reg': read_reg, 'write_reg': write_reg, 'read_mem': read_mem, @@ -296,6 +327,7 @@ prelude = { 'assert_reg': assert_reg, 'assert_mem': assert_mem, 'init_reg': init_reg, + 'dump_regs': dump_regs, 'split_dword': split_dword, 'register_interrupt': register_interrupt, } @@ -305,6 +337,7 @@ module.__dict__.update(prelude) spec.loader.exec_module(module) mem_dumps = module_get('mem_dumps', []) +do_output = module_get('do_output') if init := module_get('init'): init() @@ -391,7 +424,7 @@ def read_ctrl(): regs[reg] = int(value, 16) else: while_running() - print(f'{COLOR_BLUE}{line}{COLOR_RESET}') + out(f'{COLOR_BLUE}{line}{COLOR_RESET}') sel.register(sim_end_sock, selectors.EVENT_READ, read_ctrl) while not done: @@ -410,6 +443,8 @@ while not done: mode = halt() print('step' if mode == 'step' else 'continue', file=sim_end, flush=True) + flush_out() + if not halt: break @@ -425,7 +460,7 @@ if final := module_get('final'): if os.getenv('SIM_DUMP', ''): dump_regs() for rng in mem_dumps: - print(f'Memory range 0x{rng.start:08x}..0x{rng.stop:08x}') - print(hexdump(rng.start, read_mem(rng.start, rng.stop - rng.start))) + out(f'Memory range 0x{rng.start:08x}..0x{rng.stop:08x}') + out(hexdump(rng.start, read_mem(rng.start, rng.stop - rng.start))) exit(success=True) |
