diff options
| author | Alejandro Soto <alejandro@34project.org> | 2022-12-08 19:20:58 -0600 |
|---|---|---|
| committer | Alejandro Soto <alejandro@34project.org> | 2022-12-08 19:20:58 -0600 |
| commit | 357acc5d82a2b04cf846d69826ec89671e78e759 (patch) | |
| tree | c0fded1f5c5f18eb1c9e4df76d2497ad84c1f777 /sim | |
| parent | d6fff0eb1ce867192d30babb839fc09c30049f0b (diff) | |
Support gdb interrupts
Diffstat (limited to '')
| -rw-r--r-- | sim/gdbstub.py | 52 | ||||
| -rwxr-xr-x | sim/sim.py | 111 |
2 files changed, 112 insertions, 51 deletions
diff --git a/sim/gdbstub.py b/sim/gdbstub.py index 8d20f39..914f717 100644 --- a/sim/gdbstub.py +++ b/sim/gdbstub.py @@ -3,29 +3,53 @@ import sys, socket cycles = None enable_tty = True start_halted = True +sock, client = None, None def init(): - global client + global sock sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('127.0.0.1', 1234)) sock.listen() - print('Listening for gdb on', sock.getsockname(), file=sys.stderr) - client, peer = sock.accept() - sock.close() - print('Accepted connection from', peer, file=sys.stderr) +def halt(): + return yield_to_gdb() + +def fatal(): + global stop_reason + stop_reason = 'fatal' + yield_to_gdb() buffer = b'' -haltFromStop = False +stop_reason = None -def halt(): - global buffer, haltFromStop +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' + + dead = stop_reason == 'fatal' + sendStop = True + + if stop_reason == 'break': + stop_reply = b'S05' + elif stop_reason == 'reset': + stop_reply = b'S05' + stop_reason = 'break' + sendStop = False + elif stop_reason == 'fatal': + stop_reply = b'S0a' - if haltFromStop: - reply(b'S05') + if sendStop: + reply(stop_reply) - haltFromStop = True while True: data = client.recv(4096) if not data: @@ -53,8 +77,8 @@ def halt(): client.send(b'+') if data == b'?': - out = b'S05' - elif data == b'c': + out = stop_reply + elif data == b'c' and not dead: return 'continue' elif data == b'D': out = b'OK' @@ -75,7 +99,7 @@ def halt(): 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) - elif data == b's': + elif data == b's' and not dead: return 'step' else: out = b'' @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -import importlib.util, os, pathlib, random, socket, subprocess, sys +import importlib.util, os, pathlib, random, selectors, signal, socket, subprocess, sys module_path, verilated, image = sys.argv[1:] test_name = pathlib.Path(module_path).stem @@ -258,17 +258,26 @@ if test_name in os.getenv('SIM_SKIP', '').split(','): exit(success=True) +sel = selectors.DefaultSelector() +def interrupt(): + if not halted: + process.send_signal(signal.SIGUSR1) + +def register_interrupt(source): + sel.register(source, selectors.EVENT_READ, interrupt) + spec = importlib.util.spec_from_file_location('sim', module_path) module = importlib.util.module_from_spec(spec) prelude = { - 'read_reg': read_reg, - 'read_mem': read_mem, - 'write_mem': write_mem, - 'assert_reg': assert_reg, - 'assert_mem': assert_mem, - 'init_reg': init_reg, - 'split_dword': split_dword, + 'read_reg': read_reg, + 'read_mem': read_mem, + 'write_mem': write_mem, + 'assert_reg': assert_reg, + 'assert_mem': assert_mem, + 'init_reg': init_reg, + 'split_dword': split_dword, + 'register_interrupt': register_interrupt, } prelude.update({k: v for k, v in all_regs}) @@ -308,8 +317,8 @@ for addr, filename in module_get('loads', {}).items(): if module_get('start_halted', False): exec_args.append('--start-halted') -sim_end, target_end = socket.socketpair() -sim_end = sim_end.makefile('rw') +sim_end_sock, target_end = socket.socketpair() +sim_end = sim_end_sock.makefile('rw') target_fd = target_end.fileno() exec_args.extend(['--control-fd', str(target_fd)]) @@ -327,36 +336,64 @@ target_end.close() in_regs = False halt = module_get('halt') -while True: - for line in sim_end: - line = line.strip() - if line == '=== halted ===': - break - if line == '=== dump-regs ===': - in_regs = True - elif line == '=== end-regs ===': - in_regs = False - elif line == '=== dump-mem ===': - recv_mem_dump() - elif not line: - continue - elif in_regs: - value, reg = line.split() - regs[reg] = int(value, 16) - else: - while_running() - print(f'{COLOR_BLUE}{line}{COLOR_RESET}') - else: +done = False +halted = False +faulted = False + +def read_ctrl(): + global done, halted, faulted, in_regs + + while True: + try: + sim_end_sock.setblocking(False) + line = next(sim_end) + except StopIteration: + done = True + return + finally: + sim_end_sock.setblocking(True) + + if line := line.strip(): + if line == '=== halted ===': + halted = True + break + elif line == '=== fault ===': + faulted = True + break + elif line == '=== dump-regs ===': + in_regs = True + elif line == '=== end-regs ===': + in_regs = False + elif line == '=== dump-mem ===': + recv_mem_dump() + elif in_regs: + value, reg = line.split() + regs[reg] = int(value, 16) + else: + while_running() + print(f'{COLOR_BLUE}{line}{COLOR_RESET}') + +sel.register(sim_end_sock, selectors.EVENT_READ, read_ctrl) +while not done: + events = sel.select() + for key, _ in events: + (key.data)() + + if faulted: + if fatal := module_get('fatal'): + fatal() + break + elif halted: + mode = None + if halt: + mode = halt() - mode = None - halted = True - if halt: - mode = halt() + print('step' if mode == 'step' else 'continue', file=sim_end, flush=True) + if not halt: + break - print('step' if mode == 'step' else 'continue', file=sim_end, flush=True) - if not halt: - break + halted = False process.wait(timeout=1) if process.returncode != 0: |
