feat: allow gui and gdbstub to run in parallel
This commit is contained in:
parent
12d6a89922
commit
94243711df
|
@ -1 +1 @@
|
|||
Subproject commit c1158b547e54d82f5ac7aba4cf372c6e061b1eab
|
||||
Subproject commit 6d6a109a086361d300da675db8445ede74be58f6
|
|
@ -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,8 +248,10 @@ 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;
|
||||
SDL.SDL_SetWindowTitle(self.window, dyn_title.ptr);
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue