diff --git a/src/core/cpu.zig b/src/core/cpu.zig index c7a44f7..edab894 100644 --- a/src/core/cpu.zig +++ b/src/core/cpu.zig @@ -6,6 +6,7 @@ const Bit = @import("bitfield").Bit; const Bitfield = @import("bitfield").Bitfield; const Scheduler = @import("scheduler.zig").Scheduler; const FilePaths = @import("util.zig").FilePaths; +const Logger = @import("util.zig").Logger; const File = std.fs.File; @@ -225,7 +226,7 @@ pub const thumb = struct { } }; -const enable_logging = false; +const cpu_logging = @import("emu.zig").cpu_logging; const log = std.log.scoped(.Arm7Tdmi); pub const Arm7tdmi = struct { @@ -247,9 +248,7 @@ pub const Arm7tdmi = struct { banked_spsr: [5]PSR, - log_file: ?*const File, - log_buf: [0x100]u8, - binary_log: bool, + logger: ?Logger, pub fn init(sched: *Scheduler, bus: *Bus) Self { return Self{ @@ -261,15 +260,12 @@ pub const Arm7tdmi = struct { .banked_fiq = [_]u32{0x00} ** 10, .banked_r = [_]u32{0x00} ** 12, .banked_spsr = [_]PSR{.{ .raw = 0x0000_0000 }} ** 5, - .log_file = null, - .log_buf = undefined, - .binary_log = false, + .logger = null, }; } - pub fn useLogger(self: *Self, file: *const File, is_binary: bool) void { - self.log_file = file; - self.binary_log = is_binary; + pub fn attach(self: *Self, log_file: std.fs.File) void { + self.logger = Logger.init(log_file); } inline fn bankedIdx(mode: Mode, kind: BankedKind) usize { @@ -426,12 +422,12 @@ pub const Arm7tdmi = struct { pub fn step(self: *Self) void { if (self.cpsr.t.read()) { const opcode = self.fetch(u16); - if (enable_logging) if (self.log_file) |file| self.debug_log(file, opcode); + if (cpu_logging) self.logger.?.mgbaLog(self, opcode); thumb.lut[thumbIdx(opcode)](self, self.bus, opcode); } else { const opcode = self.fetch(u32); - if (enable_logging) if (self.log_file) |file| self.debug_log(file, opcode); + if (cpu_logging) self.logger.?.mgbaLog(self, opcode); if (checkCond(self.cpsr, @truncate(u4, opcode >> 28))) { arm.lut[armIdx(opcode)](self, self.bus, opcode); @@ -509,14 +505,6 @@ pub const Arm7tdmi = struct { return self.r[15] + 4; } - fn debug_log(self: *const Self, file: *const File, opcode: u32) void { - if (self.binary_log) { - self.skyLog(file) catch unreachable; - } else { - self.mgbaLog(file, opcode) catch unreachable; - } - } - pub fn panic(self: *const Self, comptime format: []const u8, args: anytype) noreturn { var i: usize = 0; while (i < 16) : (i += 4) { @@ -574,25 +562,6 @@ pub const Arm7tdmi = struct { }; } - fn skyLog(self: *const Self, file: *const File) !void { - var buf: [18 * @sizeOf(u32)]u8 = undefined; - - // Write Registers - var i: usize = 0; - while (i < 0x10) : (i += 1) { - skyWrite(&buf, i, self.r[i]); - } - - skyWrite(&buf, 0x10, self.cpsr.raw); - skyWrite(&buf, 0x11, if (self.hasSPSR()) self.spsr.raw else self.cpsr.raw); - _ = try file.writeAll(&buf); - } - - fn skyWrite(buf: []u8, i: usize, num: u32) void { - const j = @sizeOf(u32) * i; - std.mem.writeIntSliceNative(u32, buf[j..(j + @sizeOf(u32))], num); - } - fn mgbaLog(self: *const Self, file: *const File, opcode: u32) !void { const thumb_fmt = "{X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} cpsr: {X:0>8} | {X:0>4}:\n"; const arm_fmt = "{X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} cpsr: {X:0>8} | {X:0>8}:\n"; diff --git a/src/core/emu.zig b/src/core/emu.zig index 0f88133..4b4f1f1 100644 --- a/src/core/emu.zig +++ b/src/core/emu.zig @@ -14,6 +14,7 @@ const Allocator = std.mem.Allocator; const sync_audio = false; const sync_video: RunKind = .UnlimitedFPS; +pub const cpu_logging = false; // 228 Lines which consist of 308 dots (which are 4 cycles long) const cycles_per_frame: u64 = 228 * (308 * 4); //280896 diff --git a/src/core/util.zig b/src/core/util.zig index fdb127f..38a9fd8 100644 --- a/src/core/util.zig +++ b/src/core/util.zig @@ -1,6 +1,7 @@ const std = @import("std"); const builtin = @import("builtin"); const Log2Int = std.math.Log2Int; +const Arm7tdmi = @import("cpu.zig").Arm7tdmi; // Sign-Extend value of type `T` to type `U` pub fn sext(comptime T: type, comptime U: type, value: T) T { @@ -112,3 +113,64 @@ pub fn writeUndefined(log: anytype, comptime format: []const u8, args: anytype) log.warn(format, args); if (builtin.mode == .Debug) std.debug.panic("TODO: Implement I/O Register", .{}); } + +pub const Logger = struct { + const Self = @This(); + + buf: std.io.BufferedWriter(4096 << 2, std.fs.File.Writer), + + pub fn init(file: std.fs.File) Self { + return .{ + .buf = .{ .unbuffered_writer = file.writer() }, + }; + } + + pub fn print(self: *Self, comptime format: []const u8, args: anytype) !void { + try self.buf.writer().print(format, args); + } + + pub fn mgbaLog(self: *Self, arm7tdmi: *const Arm7tdmi, opcode: u32) void { + const fmt_base = "{X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} {X:0>8} cpsr: {X:0>8} | "; + const thumb_fmt = fmt_base ++ "{X:0>4}:\n"; + const arm_fmt = fmt_base ++ "{X:0>8}:\n"; + + if (arm7tdmi.cpsr.t.read()) { + if (opcode >> 11 == 0x1E) { + // Instruction 1 of a BL Opcode, print in ARM mode + const low = arm7tdmi.bus.debugRead(u16, arm7tdmi.r[15]); + const bl_opcode = @as(u32, opcode) << 16 | low; + + self.print(arm_fmt, Self.fmtArgs(arm7tdmi, bl_opcode)) catch @panic("failed to write to log file"); + } else { + self.print(thumb_fmt, Self.fmtArgs(arm7tdmi, opcode)) catch @panic("failed to write to log file"); + } + } else { + self.print(arm_fmt, Self.fmtArgs(arm7tdmi, opcode)) catch @panic("failed to write to log file"); + } + } + + fn fmtArgs(arm7tdmi: *const Arm7tdmi, opcode: u32) FmtArgTuple { + return .{ + arm7tdmi.r[0], + arm7tdmi.r[1], + arm7tdmi.r[2], + arm7tdmi.r[3], + arm7tdmi.r[4], + arm7tdmi.r[5], + arm7tdmi.r[6], + arm7tdmi.r[7], + arm7tdmi.r[8], + arm7tdmi.r[9], + arm7tdmi.r[10], + arm7tdmi.r[11], + arm7tdmi.r[12], + arm7tdmi.r[13], + arm7tdmi.r[14], + arm7tdmi.r[15], + arm7tdmi.cpsr.raw, + opcode, + }; + } +}; + +const FmtArgTuple = std.meta.Tuple(&.{ u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32 }); diff --git a/src/main.zig b/src/main.zig index acf82e2..62a2518 100644 --- a/src/main.zig +++ b/src/main.zig @@ -14,6 +14,7 @@ const Allocator = std.mem.Allocator; const log = std.log.scoped(.CLI); const width = @import("core/ppu.zig").width; const height = @import("core/ppu.zig").height; +const arm7tdmi_logging = @import("core/emu.zig").cpu_logging; pub const log_level = if (builtin.mode != .Debug) .info else std.log.default_level; // TODO: Reimpl Logging @@ -48,6 +49,10 @@ pub fn main() anyerror!void { var arm7tdmi = Arm7tdmi.init(&scheduler, &bus); + const log_file: ?std.fs.File = if (arm7tdmi_logging) try std.fs.cwd().createFile("zba.log", .{}) else null; + defer if (log_file) |file| file.close(); + + if (log_file) |file| arm7tdmi.attach(file); bus.attach(&arm7tdmi); // TODO: Shrink Surface (only CPSR and r15?) if (paths.bios == null) arm7tdmi.fastBoot();