Implement a GDBSTUB Server #6
|
@ -1 +1 @@
|
||||||
Subproject commit c1158b547e54d82f5ac7aba4cf372c6e061b1eab
|
Subproject commit 6d6a109a086361d300da675db8445ede74be58f6
|
|
@ -986,8 +986,7 @@ pub const Ppu = struct {
|
||||||
cpu.handleInterrupt();
|
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())
|
if (!self.dispstat.vblank.read())
|
||||||
dma.onBlanking(cpu.bus, .HBlank);
|
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 clap = @import("clap");
|
||||||
|
|
||||||
const config = @import("config.zig");
|
const config = @import("config.zig");
|
||||||
|
const emu = @import("core/emu.zig");
|
||||||
|
|
||||||
const Gui = @import("platform.zig").Gui;
|
const Gui = @import("platform.zig").Gui;
|
||||||
const Bus = @import("core/Bus.zig");
|
const Bus = @import("core/Bus.zig");
|
||||||
const Arm7tdmi = @import("core/cpu.zig").Arm7tdmi;
|
const Arm7tdmi = @import("core/cpu.zig").Arm7tdmi;
|
||||||
const Scheduler = @import("core/scheduler.zig").Scheduler;
|
const Scheduler = @import("core/scheduler.zig").Scheduler;
|
||||||
const FilePaths = @import("util.zig").FilePaths;
|
const FilePaths = @import("util.zig").FilePaths;
|
||||||
|
const FpsTracker = @import("util.zig").FpsTracker;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
const Atomic = std.atomic.Atomic;
|
||||||
|
|
||||||
const log = std.log.scoped(.Cli);
|
const log = std.log.scoped(.Cli);
|
||||||
const width = @import("core/ppu.zig").width;
|
const width = @import("core/ppu.zig").width;
|
||||||
const height = @import("core/ppu.zig").height;
|
const height = @import("core/ppu.zig").height;
|
||||||
|
@ -88,6 +91,10 @@ pub fn main() void {
|
||||||
cpu.fastBoot();
|
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) {
|
if (result.args.gdb) {
|
||||||
const Server = @import("gdbstub").Server;
|
const Server = @import("gdbstub").Server;
|
||||||
const EmuThing = @import("core/emu.zig").EmuThing;
|
const EmuThing = @import("core/emu.zig").EmuThing;
|
||||||
|
@ -96,29 +103,33 @@ pub fn main() void {
|
||||||
var emulator = wrapper.interface(allocator);
|
var emulator = wrapper.interface(allocator);
|
||||||
defer emulator.deinit();
|
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", .{});
|
log.info("Ready to connect", .{});
|
||||||
|
|
||||||
var server = Server.init(emulator) catch |e| exitln("failed to init gdb server: {}", .{e});
|
var server = Server.init(emulator) catch |e| exitln("failed to init gdb server: {}", .{e});
|
||||||
defer server.deinit(allocator);
|
defer server.deinit(allocator);
|
||||||
|
|
||||||
server.run(allocator) catch |e| exitln("gdb server crashed: {}", .{e});
|
log.info("Starting GDB Server Thread", .{});
|
||||||
} 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});
|
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;
|
return tex_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(self: *Self, cpu: *Arm7tdmi, scheduler: *Scheduler) !void {
|
const RunOptions = struct {
|
||||||
var quit = std.atomic.Atomic(bool).init(false);
|
quit: *std.atomic.Atomic(bool),
|
||||||
var tracker = FpsTracker.init();
|
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();
|
var buffer_ids = Self.generateBuffers();
|
||||||
defer {
|
defer {
|
||||||
|
@ -169,13 +177,15 @@ pub const Gui = struct {
|
||||||
const tex_id = Self.generateTexture(cpu.bus.ppu.framebuf.get(.Renderer));
|
const tex_id = Self.generateTexture(cpu.bus.ppu.framebuf.get(.Renderer));
|
||||||
defer gl.deleteTextures(1, &tex_id);
|
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;
|
var title_buf: [0x100]u8 = undefined;
|
||||||
|
|
||||||
emu_loop: while (true) {
|
emu_loop: while (true) {
|
||||||
var event: SDL.SDL_Event = undefined;
|
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) {
|
while (SDL.SDL_PollEvent(&event) != 0) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
SDL.SDL_QUIT => break :emu_loop,
|
SDL.SDL_QUIT => break :emu_loop,
|
||||||
|
@ -238,9 +248,11 @@ pub const Gui = struct {
|
||||||
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, null);
|
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, null);
|
||||||
SDL.SDL_GL_SwapWindow(self.window);
|
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);
|
SDL.SDL_SetWindowTitle(self.window, dyn_title.ptr);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
quit.store(true, .Monotonic); // Terminate Emulator Thread
|
quit.store(true, .Monotonic); // Terminate Emulator Thread
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue