summaryrefslogtreecommitdiff
path: root/sim
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2022-12-08 19:20:58 -0600
committerAlejandro Soto <alejandro@34project.org>2022-12-08 19:20:58 -0600
commit357acc5d82a2b04cf846d69826ec89671e78e759 (patch)
treec0fded1f5c5f18eb1c9e4df76d2497ad84c1f777 /sim
parentd6fff0eb1ce867192d30babb839fc09c30049f0b (diff)
Support gdb interrupts
Diffstat (limited to '')
-rw-r--r--sim/gdbstub.py52
-rwxr-xr-xsim/sim.py111
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''
diff --git a/sim/sim.py b/sim/sim.py
index 189ecfc..491ac43 100755
--- a/sim/sim.py
+++ b/sim/sim.py
@@ -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: