Compare commits

...

3 Commits

6 changed files with 96 additions and 11 deletions

3
.gitmodules vendored
View File

@ -13,3 +13,6 @@
[submodule "lib/zig-toml"] [submodule "lib/zig-toml"]
path = lib/zig-toml path = lib/zig-toml
url = https://github.com/aeronavery/zig-toml url = https://github.com/aeronavery/zig-toml
[submodule "lib/zba-gdbstub"]
path = lib/zba-gdbstub
url = https://git.musuka.dev/paoda/zba-gdbstub

View File

@ -1,8 +0,0 @@
{
"recommendations": [
"augusterame.zls-vscode",
"usernamehw.errorlens",
"vadimcn.vscode-lldb",
"dan-c-underwood.arm"
]
}

View File

@ -1,6 +1,8 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const Sdk = @import("lib/SDL.zig/Sdk.zig"); const Sdk = @import("lib/SDL.zig/Sdk.zig");
const Gdbstub = @import("lib/zba-gdbstub/build.zig");
pub fn build(b: *std.build.Builder) void { pub fn build(b: *std.build.Builder) void {
// Minimum Zig Version // Minimum Zig Version
@ -43,6 +45,9 @@ pub fn build(b: *std.build.Builder) void {
// OpenGL 3.3 Bindings // OpenGL 3.3 Bindings
exe.addPackagePath("gl", "lib/gl.zig"); exe.addPackagePath("gl", "lib/gl.zig");
// gdbstub
Gdbstub.link(exe);
// Zig SDL Bindings: https://github.com/MasterQ32/SDL.zig // Zig SDL Bindings: https://github.com/MasterQ32/SDL.zig
const sdk = Sdk.init(b); const sdk = Sdk.init(b);
sdk.link(exe, .dynamic); sdk.link(exe, .dynamic);

1
lib/zba-gdbstub Submodule

@ -0,0 +1 @@
Subproject commit 4bca44e5f2a4aa19361b51b7617a21f46f88eef4

View File

@ -163,3 +163,59 @@ fn sleep(timer: *Timer, wake_time: u64) ?u64 {
fn spinLoop(timer: *Timer, wake_time: u64) void { fn spinLoop(timer: *Timer, wake_time: u64) void {
while (true) if (timer.read() > wake_time) break; 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);
}
}
};

View File

@ -22,6 +22,7 @@ const params = clap.parseParamsComptime(
\\-h, --help Display this help and exit. \\-h, --help Display this help and exit.
\\-s, --skip Skip BIOS. \\-s, --skip Skip BIOS.
\\-b, --bios <str> Optional path to a GBA BIOS ROM. \\-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. \\<str> Path to the GBA GamePak ROM.
\\ \\
); );
@ -87,10 +88,37 @@ pub fn main() void {
cpu.fastBoot(); cpu.fastBoot();
} }
var gui = Gui.init(&bus.pak.title, &bus.apu, width, height) catch |e| exitln("failed to init gui: {}", .{e}); if (result.args.gdb) {
defer gui.deinit(); 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, &params, clap.parsers.default)) !FilePaths { pub fn handleArguments(allocator: Allocator, data_path: []const u8, result: *const clap.Result(clap.Help, &params, clap.parsers.default)) !FilePaths {