feat: allow gui and gdbstub to run in parallel
This commit is contained in:
		 Submodule lib/zba-gdbstub updated: c1158b547e...6d6a109a08
									
								
							@@ -990,8 +990,7 @@ pub const Ppu = struct {
 | 
			
		||||
            cpu.handleInterrupt();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // See if HBlank DMA is present and not enabled
 | 
			
		||||
 | 
			
		||||
        // If we're not also in VBlank, attempt to run any pending DMA Reqs
 | 
			
		||||
        if (!self.dispstat.vblank.read())
 | 
			
		||||
            dma.onBlanking(cpu.bus, .HBlank);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										47
									
								
								src/main.zig
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								src/main.zig
									
									
									
									
									
								
							@@ -4,14 +4,17 @@ const known_folders = @import("known_folders");
 | 
			
		||||
const clap = @import("clap");
 | 
			
		||||
 | 
			
		||||
const config = @import("config.zig");
 | 
			
		||||
const emu = @import("core/emu.zig");
 | 
			
		||||
 | 
			
		||||
const Gui = @import("platform.zig").Gui;
 | 
			
		||||
const Bus = @import("core/Bus.zig");
 | 
			
		||||
const Arm7tdmi = @import("core/cpu.zig").Arm7tdmi;
 | 
			
		||||
const Scheduler = @import("core/scheduler.zig").Scheduler;
 | 
			
		||||
const FilePaths = @import("util.zig").FilePaths;
 | 
			
		||||
 | 
			
		||||
const FpsTracker = @import("util.zig").FpsTracker;
 | 
			
		||||
const Allocator = std.mem.Allocator;
 | 
			
		||||
const Atomic = std.atomic.Atomic;
 | 
			
		||||
 | 
			
		||||
const log = std.log.scoped(.Cli);
 | 
			
		||||
const width = @import("core/ppu.zig").width;
 | 
			
		||||
const height = @import("core/ppu.zig").height;
 | 
			
		||||
@@ -88,6 +91,10 @@ pub fn main() void {
 | 
			
		||||
        cpu.fastBoot();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var quit = Atomic(bool).init(false);
 | 
			
		||||
    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;
 | 
			
		||||
@@ -96,29 +103,33 @@ pub fn main() void {
 | 
			
		||||
        var emulator = wrapper.interface(allocator);
 | 
			
		||||
        defer emulator.deinit();
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
            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();
 | 
			
		||||
        log.info("Starting GDB Server Thread", .{});
 | 
			
		||||
 | 
			
		||||
        gui.run(&cpu, &scheduler) catch |e| exitln("failed to run gui thread: {}", .{e});
 | 
			
		||||
        const thread = std.Thread.spawn(.{}, Server.run, .{ &server, allocator, &quit }) catch |e| exitln("gdb server thread crashed: {}", .{e});
 | 
			
		||||
        defer thread.join();
 | 
			
		||||
 | 
			
		||||
        gui.run(.{
 | 
			
		||||
            .cpu = &cpu,
 | 
			
		||||
            .scheduler = &scheduler,
 | 
			
		||||
            .quit = &quit,
 | 
			
		||||
        }) catch |e| exitln("main thread panicked: {}", .{e});
 | 
			
		||||
    } else {
 | 
			
		||||
        var tracker = FpsTracker.init();
 | 
			
		||||
 | 
			
		||||
        const thread = std.Thread.spawn(.{}, emu.run, .{ &quit, &scheduler, &cpu, &tracker }) catch |e| exitln("emu thread panicked: {}", .{e});
 | 
			
		||||
        defer thread.join();
 | 
			
		||||
 | 
			
		||||
        gui.run(.{
 | 
			
		||||
            .cpu = &cpu,
 | 
			
		||||
            .scheduler = &scheduler,
 | 
			
		||||
            .tracker = &tracker,
 | 
			
		||||
            .quit = &quit,
 | 
			
		||||
        }) catch |e| exitln("main thread panicked: {}", .{e});
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -154,9 +154,17 @@ pub const Gui = struct {
 | 
			
		||||
        return tex_id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn run(self: *Self, cpu: *Arm7tdmi, scheduler: *Scheduler) !void {
 | 
			
		||||
        var quit = std.atomic.Atomic(bool).init(false);
 | 
			
		||||
        var tracker = FpsTracker.init();
 | 
			
		||||
    const RunOptions = struct {
 | 
			
		||||
        quit: *std.atomic.Atomic(bool),
 | 
			
		||||
        tracker: ?*FpsTracker = null,
 | 
			
		||||
        cpu: *Arm7tdmi,
 | 
			
		||||
        scheduler: *Scheduler,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    pub fn run(self: *Self, opt: RunOptions) !void {
 | 
			
		||||
        const cpu = opt.cpu;
 | 
			
		||||
        const tracker = opt.tracker;
 | 
			
		||||
        const quit = opt.quit;
 | 
			
		||||
 | 
			
		||||
        var buffer_ids = Self.generateBuffers();
 | 
			
		||||
        defer {
 | 
			
		||||
@@ -169,13 +177,15 @@ pub const Gui = struct {
 | 
			
		||||
        const tex_id = Self.generateTexture(cpu.bus.ppu.framebuf.get(.Renderer));
 | 
			
		||||
        defer gl.deleteTextures(1, &tex_id);
 | 
			
		||||
 | 
			
		||||
        const thread = try std.Thread.spawn(.{}, emu.run, .{ &quit, scheduler, cpu, &tracker });
 | 
			
		||||
        defer thread.join();
 | 
			
		||||
 | 
			
		||||
        var title_buf: [0x100]u8 = undefined;
 | 
			
		||||
 | 
			
		||||
        emu_loop: while (true) {
 | 
			
		||||
            var event: SDL.SDL_Event = undefined;
 | 
			
		||||
 | 
			
		||||
            // This might be true if the emu is running via a gdbstub server
 | 
			
		||||
            // and the gdb stub exits first
 | 
			
		||||
            if (quit.load(.Monotonic)) break :emu_loop;
 | 
			
		||||
 | 
			
		||||
            while (SDL.SDL_PollEvent(&event) != 0) {
 | 
			
		||||
                switch (event.type) {
 | 
			
		||||
                    SDL.SDL_QUIT => break :emu_loop,
 | 
			
		||||
@@ -238,9 +248,11 @@ pub const Gui = struct {
 | 
			
		||||
            gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, null);
 | 
			
		||||
            SDL.SDL_GL_SwapWindow(self.window);
 | 
			
		||||
 | 
			
		||||
            const dyn_title = std.fmt.bufPrintZ(&title_buf, "ZBA | {s} [Emu: {}fps] ", .{ self.title, tracker.value() }) catch unreachable;
 | 
			
		||||
            if (tracker) |t| {
 | 
			
		||||
                const dyn_title = std.fmt.bufPrintZ(&title_buf, "ZBA | {s} [Emu: {}fps] ", .{ self.title, t.value() }) catch unreachable;
 | 
			
		||||
                SDL.SDL_SetWindowTitle(self.window, dyn_title.ptr);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        quit.store(true, .Monotonic); // Terminate Emulator Thread
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user