diff --git a/lib/zba-gdbstub b/lib/zba-gdbstub index 479319e..eb8e517 160000 --- a/lib/zba-gdbstub +++ b/lib/zba-gdbstub @@ -1 +1 @@ -Subproject commit 479319e7cad78c3fd38b6865c56e9fe9e78d495c +Subproject commit eb8e5175bd9738e92d10c47f75abb174f3624082 diff --git a/src/core/emu.zig b/src/core/emu.zig index 1ae155f..de275cb 100644 --- a/src/core/emu.zig +++ b/src/core/emu.zig @@ -403,3 +403,128 @@ pub fn fastBoot(system: System) void { cpu.bank.spsr[Bank.spsrIdx(.Supervisor)] = .{ .raw = 0x0000_0000 }; } } + +pub const debug = struct { + const Interface = @import("gdbstub").Emulator; + const Server = @import("gdbstub").Server; + const AtomicBool = std.atomic.Atomic(bool); + const log = std.log.scoped(.gdbstub); + + const nds7 = struct { + const target: []const u8 = + \\ + \\ armv4t + \\ + \\ + \\ + \\ + \\ + \\ + \\ + \\ + \\ + \\ + \\ + \\ + \\ + \\ + \\ + \\ + \\ + \\ + \\ + \\ + \\ + ; + + // Remember that a lot of memory regions are mirrored + const memory_map: []const u8 = + \\ + \\ + \\ + \\ + \\ + \\ + \\ + \\ + \\ + \\ + ; + }; + + // FIXME: for now, assume ARM7 + pub const Wrapper = struct { + system: System, + scheduler: *Scheduler, + + pub fn init(system: System, scheduler: *Scheduler) @This() { + return .{ .system = system, .scheduler = scheduler }; + } + + pub fn interface(self: *@This(), allocator: Allocator) Interface { + return Interface.init(allocator, self); + } + + // FIXME: What about ICTM? DTCM? + pub fn read(self: *const @This(), addr: u32) u8 { + return self.system.bus7.dbgRead(u8, addr); + } + + pub fn write(self: *@This(), addr: u32, value: u8) void { + self.system.bus7.dbgWrite(u8, addr, value); + } + + pub fn registers(self: *const @This()) *[16]u32 { + return &self.system.arm7tdmi.r; + } + + pub fn cpsr(self: *const @This()) u32 { + return self.system.arm7tdmi.cpsr.raw; + } + + pub fn step(self: *@This()) void { + const scheduler = self.scheduler; + const system = self.system; + + var did_step: bool = false; + + // TODO: keep in lockstep with runFrame + while (true) { + if (did_step) break; + + switch (isHalted(system)) { + .both => scheduler.tick = scheduler.peekTimestamp(), + inline else => |halt| { + if (!dma9.step(system.arm946es) and comptime halt != .arm9) { + system.arm946es.step(); + system.arm946es.step(); + } + + if (!dma7.step(system.arm7tdmi) and comptime halt != .arm7) { + system.arm7tdmi.step(); + did_step = true; + } + }, + } + + if (scheduler.check()) |ev| { + const late = scheduler.tick - ev.tick; + scheduler.handle(system, ev, late); + } + } + } + }; + + pub fn run(allocator: Allocator, system: System, scheduler: *Scheduler, should_quit: *AtomicBool) !void { + var wrapper = Wrapper.init(system, scheduler); + + var emu_interface = wrapper.interface(allocator); + defer emu_interface.deinit(); + + var server = try Server.init(emu_interface, .{ .target = nds7.target, .memory_map = nds7.memory_map }); + defer server.deinit(allocator); + + const thread = try std.Thread.spawn(.{}, Server.run, .{ &server, allocator, should_quit }); + defer thread.join(); + } +}; diff --git a/src/main.zig b/src/main.zig index 5d4a9e5..6cbc7b6 100644 --- a/src/main.zig +++ b/src/main.zig @@ -68,11 +68,17 @@ pub fn main() !void { emu.fastBoot(system); - var ui = try Ui.init(allocator); - defer ui.deinit(allocator); + if (result.args.gdb == 0) { + var ui = try Ui.init(allocator); + defer ui.deinit(allocator); - ui.setTitle(rom_title); - try ui.run(&scheduler, system); + ui.setTitle(rom_title); + try ui.run(&scheduler, system); + } else { + var should_quit: std.atomic.Atomic(bool) = std.atomic.Atomic(bool).init(false); + + try emu.debug.run(allocator, system, &scheduler, &should_quit); + } } fn handlePositional(result: ClapResult) ![]const u8 {