feat: add gdb support to zba
This commit is contained in:
		 Submodule lib/zba-gdbstub updated: 08bf0f9201...4bca44e5f2
									
								
							@@ -163,3 +163,59 @@ fn sleep(timer: *Timer, wake_time: u64) ?u64 {
 | 
			
		||||
fn spinLoop(timer: *Timer, wake_time: u64) void {
 | 
			
		||||
    while (true) if (timer.read() > wake_time) break;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub const EmuThing = struct {
 | 
			
		||||
    const Self = @This();
 | 
			
		||||
    const Interface = @import("gdbstub").Emulator;
 | 
			
		||||
 | 
			
		||||
    cpu: *Arm7tdmi,
 | 
			
		||||
    scheduler: *Scheduler,
 | 
			
		||||
 | 
			
		||||
    pub fn init(cpu: *Arm7tdmi, scheduler: *Scheduler) Self {
 | 
			
		||||
        return .{ .cpu = cpu, .scheduler = scheduler };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn interface(self: *Self) Interface {
 | 
			
		||||
        return Interface.init(self);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn read(self: *const Self, addr: u32) u8 {
 | 
			
		||||
        return self.cpu.bus.dbgRead(u8, addr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn write(self: *Self, addr: u32, value: u8) void {
 | 
			
		||||
        _ = value;
 | 
			
		||||
        _ = self;
 | 
			
		||||
        _ = addr;
 | 
			
		||||
 | 
			
		||||
        std.debug.panic("TODO: Implement Debug Writes?", .{});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn registers(self: *const Self) *[16]u32 {
 | 
			
		||||
        return &self.cpu.r;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn cpsr(self: *const Self) u32 {
 | 
			
		||||
        return self.cpu.cpsr.raw;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn step(self: *Self) void {
 | 
			
		||||
        const cpu = self.cpu;
 | 
			
		||||
        const sched = self.scheduler;
 | 
			
		||||
 | 
			
		||||
        // TODO: How can I make it easier to keep this in lock-step with runFrame?
 | 
			
		||||
        while (true) {
 | 
			
		||||
            if (!cpu.stepDmaTransfer()) {
 | 
			
		||||
                if (cpu.isHalted()) {
 | 
			
		||||
                    // Fast-forward to next Event
 | 
			
		||||
                    sched.tick = sched.queue.peek().?.tick;
 | 
			
		||||
                } else {
 | 
			
		||||
                    cpu.step();
 | 
			
		||||
                    break; // this function won't return until we've actually stepped once
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (sched.tick >= sched.nextTimestamp()) sched.handleEvent(cpu);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										34
									
								
								src/main.zig
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								src/main.zig
									
									
									
									
									
								
							@@ -22,6 +22,7 @@ const params = clap.parseParamsComptime(
 | 
			
		||||
    \\-h, --help            Display this help and exit.
 | 
			
		||||
    \\-s, --skip            Skip BIOS.
 | 
			
		||||
    \\-b, --bios <str>      Optional path to a GBA BIOS ROM.
 | 
			
		||||
    \\ --gdb                Run ZBA from the context of a GDB Server
 | 
			
		||||
    \\<str>                 Path to the GBA GamePak ROM.
 | 
			
		||||
    \\
 | 
			
		||||
);
 | 
			
		||||
@@ -87,10 +88,37 @@ pub fn main() void {
 | 
			
		||||
        cpu.fastBoot();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var gui = Gui.init(&bus.pak.title, &bus.apu, width, height) catch |e| exitln("failed to init gui: {}", .{e});
 | 
			
		||||
    defer gui.deinit();
 | 
			
		||||
    if (result.args.gdb) {
 | 
			
		||||
        const Server = @import("gdbstub").Server;
 | 
			
		||||
        const EmuThing = @import("core/emu.zig").EmuThing;
 | 
			
		||||
 | 
			
		||||
    gui.run(&cpu, &scheduler) catch |e| exitln("failed to run gui thread: {}", .{e});
 | 
			
		||||
        var emu_thing = EmuThing.init(&cpu, &scheduler);
 | 
			
		||||
        const emulator = emu_thing.interface();
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
            const frames_per_second: usize = 60;
 | 
			
		||||
            const emu = @import("core/emu.zig");
 | 
			
		||||
 | 
			
		||||
            var i: usize = 0;
 | 
			
		||||
            while (i < frames_per_second * 120) : (i += 1) {
 | 
			
		||||
                emu.runFrame(&scheduler, &cpu);
 | 
			
		||||
 | 
			
		||||
                std.debug.print("Frame {:0>3}/{:0>3}\r", .{ i, frames_per_second * 120 });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        log.info("Ready to connect", .{});
 | 
			
		||||
 | 
			
		||||
        var server = Server.init(emulator) catch |e| exitln("failed to init gdb server: {}", .{e});
 | 
			
		||||
        defer server.deinit(allocator);
 | 
			
		||||
 | 
			
		||||
        server.run(allocator) catch |e| exitln("gdb server crashed: {}", .{e});
 | 
			
		||||
    } else {
 | 
			
		||||
        var gui = Gui.init(&bus.pak.title, &bus.apu, width, height) catch |e| exitln("failed to init gui: {}", .{e});
 | 
			
		||||
        defer gui.deinit();
 | 
			
		||||
 | 
			
		||||
        gui.run(&cpu, &scheduler) catch |e| exitln("failed to run gui thread: {}", .{e});
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn handleArguments(allocator: Allocator, data_path: []const u8, result: *const clap.Result(clap.Help, ¶ms, clap.parsers.default)) !FilePaths {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user