Compare commits

...

2 Commits

5 changed files with 56 additions and 31 deletions

@ -1 +1 @@
Subproject commit c1158b547e54d82f5ac7aba4cf372c6e061b1eab Subproject commit 6d6a109a086361d300da675db8445ede74be58f6

View File

@ -200,15 +200,18 @@ pub const EmuThing = struct {
const cpu = self.cpu; const cpu = self.cpu;
const sched = self.scheduler; const sched = self.scheduler;
// Is true when we have executed one (1) instruction
var did_step: bool = false;
// TODO: How can I make it easier to keep this in lock-step with runFrame? // TODO: How can I make it easier to keep this in lock-step with runFrame?
while (true) { while (!did_step) {
if (!cpu.stepDmaTransfer()) { if (!cpu.stepDmaTransfer()) {
if (cpu.isHalted()) { if (cpu.isHalted()) {
// Fast-forward to next Event // Fast-forward to next Event
sched.tick = sched.queue.peek().?.tick; sched.tick = sched.queue.peek().?.tick;
} else { } else {
cpu.step(); cpu.step();
break; // this function won't return until we've actually stepped once did_step = true;
} }
} }

View File

@ -990,8 +990,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);

View File

@ -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});
} }
} }

View File

@ -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
} }