summaryrefslogtreecommitdiff
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
parentd6fff0eb1ce867192d30babb839fc09c30049f0b (diff)
Support gdb interrupts
Diffstat (limited to '')
-rw-r--r--sim/gdbstub.py52
-rwxr-xr-xsim/sim.py111
-rw-r--r--tb/top/conspiracion.cpp133
3 files changed, 184 insertions, 112 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:
diff --git a/tb/top/conspiracion.cpp b/tb/top/conspiracion.cpp
index f222e54..099baf3 100644
--- a/tb/top/conspiracion.cpp
+++ b/tb/top/conspiracion.cpp
@@ -1,4 +1,5 @@
#include <climits>
+#include <csignal>
#include <cstdio>
#include <cstdint>
#include <cstdlib>
@@ -33,6 +34,8 @@
namespace
{
+ volatile sig_atomic_t async_halt = 0;
+
constexpr const char *gp_regs[30] =
{
[0] = "r0",
@@ -157,6 +160,11 @@ namespace
return stream;
}
+
+ void async_halt_handler(int)
+ {
+ async_halt = 1;
+ }
}
int main(int argc, char **argv)
@@ -381,7 +389,7 @@ int main(int argc, char **argv)
tick();
tick();
- if(top.breakpoint)
+ if(top.breakpoint || (!(time & ((1 << 8) - 1)) && async_halt)) [[unlikely]]
{
top.halt = 1;
}
@@ -446,91 +454,94 @@ int main(int argc, char **argv)
std::fputs("=== end-mem ===\n", ctrl);
};
+ std::signal(SIGUSR1, async_halt_handler);
+
unsigned i = 0;
// Abuse unsigned overflow (cycles is UINT_MAX by default)
while(!failed && i + 1 <= *cycles)
{
- for(; i + 1 <= *cycles; ++i)
+ do
{
cycle();
if(failed || top.cpu_halted) [[unlikely]]
{
- break;
+ goto halt_or_fail;
}
- }
+ } while(++i + 1 <= *cycles);
- if(top.cpu_halted)
- {
- top.step = 0;
- top.halt = 0;
+ break;
- do_reg_dump();
- std::fputs("=== halted ===\n", ctrl);
+halt_or_fail:
+ top.step = 0;
+ top.halt = 0;
- char *line = nullptr;
- std::size_t buf_size = 0;
+ do_reg_dump();
+ std::fprintf(ctrl, "=== %s ===\n", failed ? "fault" : "halted");
+
+ char *line = nullptr;
+ std::size_t buf_size = 0;
- while(true)
+ while(true)
+ {
+ ssize_t read = getline(&line, &buf_size, ctrl);
+ if(read == -1)
{
- ssize_t read = getline(&line, &buf_size, ctrl);
- if(read == -1)
+ if(!std::feof(ctrl))
{
- if(!std::feof(ctrl))
- {
- std::perror("getline()");
- failed = true;
- }
-
- break;
+ std::perror("getline()");
+ failed = true;
}
- if(read > 0 && line[read - 1] == '\n')
- {
- line[read - 1] = '\0';
- }
+ break;
+ }
- const char *cmd = std::strtok(line, " ");
- if(!std::strcmp(cmd, "continue"))
- {
- break;
- } else if(!std::strcmp(cmd, "step"))
- {
- top.step = 1;
- break;
- } else if(!std::strcmp(cmd, "dump-mem"))
- {
- mem_region dump = {};
- std::sscanf(std::strtok(nullptr, " "), "%zu", &dump.start);
- std::sscanf(std::strtok(nullptr, " "), "%zu", &dump.length);
- do_mem_dump(&dump, 1);
- } else if(!std::strcmp(cmd, "patch-mem"))
- {
- std::uint32_t addr;
- std::sscanf(std::strtok(nullptr, " "), "%u", &addr);
+ if(read > 0 && line[read - 1] == '\n')
+ {
+ line[read - 1] = '\0';
+ }
+
+ const char *cmd = std::strtok(line, " ");
+ if(!std::strcmp(cmd, "continue"))
+ {
+ break;
+ } else if(!std::strcmp(cmd, "step"))
+ {
+ top.step = 1;
+ break;
+ } else if(!std::strcmp(cmd, "dump-mem"))
+ {
+ mem_region dump = {};
+ std::sscanf(std::strtok(nullptr, " "), "%zu", &dump.start);
+ std::sscanf(std::strtok(nullptr, " "), "%zu", &dump.length);
+ do_mem_dump(&dump, 1);
+ } else if(!std::strcmp(cmd, "patch-mem"))
+ {
+ std::uint32_t addr;
+ std::sscanf(std::strtok(nullptr, " "), "%u", &addr);
- const char *data = std::strtok(nullptr, " ");
- std::size_t length = std::strlen(data);
+ const char *data = std::strtok(nullptr, " ");
+ std::size_t length = std::strlen(data);
- while(data && length >= 8)
- {
- std::uint32_t word;
- std::sscanf(data, "%08x", &word);
+ while(data && length >= 8)
+ {
+ std::uint32_t word;
+ std::sscanf(data, "%08x", &word);
- data += 8;
- length -= 8;
+ data += 8;
+ length -= 8;
- word = (word & 0xff) << 24
- | ((word >> 8) & 0xff) << 16
- | ((word >> 16) & 0xff) << 8
- | ((word >> 24) & 0xff);
+ word = (word & 0xff) << 24
+ | ((word >> 8) & 0xff) << 16
+ | ((word >> 16) & 0xff) << 8
+ | ((word >> 24) & 0xff);
- avl.patch(addr++, word);
- }
+ avl.patch(addr++, word);
}
}
-
- std::free(line);
}
+
+ std::free(line);
+ async_halt = 0;
}
if(!no_tty)
@@ -543,7 +554,7 @@ int main(int argc, char **argv)
trace.close();
}
- if(dump_regs || failed)
+ if(dump_regs)
{
do_reg_dump();
}