diff --git a/.gitmodules b/.gitmodules index 9d0cf56..475af46 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,6 @@ [submodule "lib/nfd-zig"] path = lib/nfd-zig url = https://github.com/fabioarnold/nfd-zig +[submodule "lib/zba-util"] + path = lib/zba-util + url = https://git.musuka.dev/paoda/zba-util.git diff --git a/build.zig b/build.zig index 35fefea..1eabf6d 100644 --- a/build.zig +++ b/build.zig @@ -33,7 +33,7 @@ pub fn build(b: *std.build.Builder) void { exe.addAnonymousModule("datetime", .{ .source_file = .{ .path = "lib/zig-datetime/src/main.zig" } }); // Bitfield type from FlorenceOS: https://github.com/FlorenceOS/ - exe.addAnonymousModule("bitfield", .{ .source_file = .{ .path = "lib/util/bitfield.zig" } }); + exe.addAnonymousModule("bitfield", .{ .source_file = .{ .path = "lib/bitfield.zig" } }); // Argument Parsing Library exe.addAnonymousModule("clap", .{ .source_file = .{ .path = "lib/zig-clap/clap.zig" } }); @@ -44,6 +44,9 @@ pub fn build(b: *std.build.Builder) void { // OpenGL 3.3 Bindings exe.addAnonymousModule("gl", .{ .source_file = .{ .path = "lib/gl.zig" } }); + // ZBA utility code + exe.addAnonymousModule("zba-util", .{ .source_file = .{ .path = "lib/zba-util/src/lib.zig" } }); + // gdbstub gdbstub.link(exe); // NativeFileDialog(ue) Bindings diff --git a/lib/util/bitfield.zig b/lib/bitfield.zig similarity index 100% rename from lib/util/bitfield.zig rename to lib/bitfield.zig diff --git a/lib/zba-util b/lib/zba-util new file mode 160000 index 0000000..52ac8d9 --- /dev/null +++ b/lib/zba-util @@ -0,0 +1 @@ +Subproject commit 52ac8d952fe7c722e33a3237e465dcf258076613 diff --git a/src/core/Bus.zig b/src/core/Bus.zig index 925f1ba..0c2d3a8 100644 --- a/src/core/Bus.zig +++ b/src/core/Bus.zig @@ -19,7 +19,7 @@ const log = std.log.scoped(.Bus); const createDmaTuple = @import("bus/dma.zig").create; const createTimerTuple = @import("bus/timer.zig").create; -const rotr = @import("../util.zig").rotr; +const rotr = @import("zba-util").rotr; const timings: [2][0x10]u8 = [_][0x10]u8{ // BIOS, Unused, EWRAM, IWRAM, I/0, PALRAM, VRAM, OAM, ROM0, ROM0, ROM1, ROM1, ROM2, ROM2, SRAM, Unused diff --git a/src/core/apu.zig b/src/core/apu.zig index 8730290..89204f9 100644 --- a/src/core/apu.zig +++ b/src/core/apu.zig @@ -14,7 +14,6 @@ const SoundFifo = std.fifo.LinearFifo(u8, .{ .Static = 0x20 }); const getHalf = util.getHalf; const setHalf = util.setHalf; -const intToBytes = util.intToBytes; const log = std.log.scoped(.APU); @@ -557,7 +556,7 @@ pub fn DmaSound(comptime kind: DmaSoundKind) type { pub fn push(self: *Self, value: u32) void { if (!self.enabled) self.enable(); - self.fifo.write(&intToBytes(u32, value)) catch |e| log.err("{} Error: {}", .{ kind, e }); + self.fifo.write(std.mem.asBytes(&value)) catch |e| log.err("{} Error: {}", .{ kind, e }); } fn enable(self: *Self) void { diff --git a/src/core/bus/Bios.zig b/src/core/bus/Bios.zig index 6743ffc..51c6095 100644 --- a/src/core/bus/Bios.zig +++ b/src/core/bus/Bios.zig @@ -3,7 +3,7 @@ const std = @import("std"); const Allocator = std.mem.Allocator; const log = std.log.scoped(.Bios); -const rotr = @import("../../util.zig").rotr; +const rotr = @import("zba-util").rotr; const forceAlign = @import("../Bus.zig").forceAlign; /// Size of the BIOS in bytes diff --git a/src/core/bus/dma.zig b/src/core/bus/dma.zig index 7d75d18..9bc3274 100644 --- a/src/core/bus/dma.zig +++ b/src/core/bus/dma.zig @@ -12,7 +12,7 @@ const getHalf = util.getHalf; const setHalf = util.setHalf; const setQuart = util.setQuart; -const rotr = @import("../../util.zig").rotr; +const rotr = @import("zba-util").rotr; pub fn create() DmaTuple { return .{ DmaController(0).init(), DmaController(1).init(), DmaController(2).init(), DmaController(3).init() }; diff --git a/src/core/cpu/arm/branch.zig b/src/core/cpu/arm/branch.zig index b55782d..18d7b6e 100644 --- a/src/core/cpu/arm/branch.zig +++ b/src/core/cpu/arm/branch.zig @@ -2,7 +2,7 @@ const Bus = @import("../../Bus.zig"); const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; const InstrFn = @import("../../cpu.zig").arm.InstrFn; -const sext = @import("../../../util.zig").sext; +const sext = @import("zba-util").sext; pub fn branch(comptime L: bool) InstrFn { return struct { diff --git a/src/core/cpu/arm/half_signed_data_transfer.zig b/src/core/cpu/arm/half_signed_data_transfer.zig index cd205d9..e95c9c2 100644 --- a/src/core/cpu/arm/half_signed_data_transfer.zig +++ b/src/core/cpu/arm/half_signed_data_transfer.zig @@ -2,8 +2,8 @@ const Bus = @import("../../Bus.zig"); const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; const InstrFn = @import("../../cpu.zig").arm.InstrFn; -const sext = @import("../../../util.zig").sext; -const rotr = @import("../../../util.zig").rotr; +const sext = @import("zba-util").sext; +const rotr = @import("zba-util").rotr; pub fn halfAndSignedDataTransfer(comptime P: bool, comptime U: bool, comptime I: bool, comptime W: bool, comptime L: bool) InstrFn { return struct { diff --git a/src/core/cpu/arm/psr_transfer.zig b/src/core/cpu/arm/psr_transfer.zig index 3ee8791..8eba6f6 100644 --- a/src/core/cpu/arm/psr_transfer.zig +++ b/src/core/cpu/arm/psr_transfer.zig @@ -7,7 +7,7 @@ const PSR = @import("../../cpu.zig").PSR; const log = std.log.scoped(.PsrTransfer); -const rotr = @import("../../../util.zig").rotr; +const rotr = @import("zba-util").rotr; pub fn psrTransfer(comptime I: bool, comptime R: bool, comptime kind: u2) InstrFn { return struct { diff --git a/src/core/cpu/arm/single_data_swap.zig b/src/core/cpu/arm/single_data_swap.zig index 511cb7b..7a588f3 100644 --- a/src/core/cpu/arm/single_data_swap.zig +++ b/src/core/cpu/arm/single_data_swap.zig @@ -2,7 +2,7 @@ const Bus = @import("../../Bus.zig"); const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; const InstrFn = @import("../../cpu.zig").arm.InstrFn; -const rotr = @import("../../../util.zig").rotr; +const rotr = @import("zba-util").rotr; pub fn singleDataSwap(comptime B: bool) InstrFn { return struct { diff --git a/src/core/cpu/arm/single_data_transfer.zig b/src/core/cpu/arm/single_data_transfer.zig index 328699e..8a2e2d2 100644 --- a/src/core/cpu/arm/single_data_transfer.zig +++ b/src/core/cpu/arm/single_data_transfer.zig @@ -3,7 +3,7 @@ const Bus = @import("../../Bus.zig"); const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; const InstrFn = @import("../../cpu.zig").arm.InstrFn; -const rotr = @import("../../../util.zig").rotr; +const rotr = @import("zba-util").rotr; pub fn singleDataTransfer(comptime I: bool, comptime P: bool, comptime U: bool, comptime B: bool, comptime W: bool, comptime L: bool) InstrFn { return struct { diff --git a/src/core/cpu/barrel_shifter.zig b/src/core/cpu/barrel_shifter.zig index ecca44b..c5a6c81 100644 --- a/src/core/cpu/barrel_shifter.zig +++ b/src/core/cpu/barrel_shifter.zig @@ -1,7 +1,7 @@ const Arm7tdmi = @import("../cpu.zig").Arm7tdmi; const CPSR = @import("../cpu.zig").PSR; -const rotr = @import("../../util.zig").rotr; +const rotr = @import("zba-util").rotr; pub fn exec(comptime S: bool, cpu: *Arm7tdmi, opcode: u32) u32 { var result: u32 = undefined; diff --git a/src/core/cpu/thumb/branch.zig b/src/core/cpu/thumb/branch.zig index 4d00577..c531ac9 100644 --- a/src/core/cpu/thumb/branch.zig +++ b/src/core/cpu/thumb/branch.zig @@ -3,7 +3,7 @@ const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; const InstrFn = @import("../../cpu.zig").thumb.InstrFn; const checkCond = @import("../../cpu.zig").checkCond; -const sext = @import("../../../util.zig").sext; +const sext = @import("zba-util").sext; pub fn fmt16(comptime cond: u4) InstrFn { return struct { diff --git a/src/core/cpu/thumb/data_transfer.zig b/src/core/cpu/thumb/data_transfer.zig index b6c5246..b7cfd7f 100644 --- a/src/core/cpu/thumb/data_transfer.zig +++ b/src/core/cpu/thumb/data_transfer.zig @@ -2,8 +2,8 @@ const Bus = @import("../../Bus.zig"); const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; const InstrFn = @import("../../cpu.zig").thumb.InstrFn; -const rotr = @import("../../../util.zig").rotr; -const sext = @import("../../../util.zig").sext; +const rotr = @import("zba-util").rotr; +const sext = @import("zba-util").sext; pub fn fmt6(comptime rd: u3) InstrFn { return struct { diff --git a/src/imgui.zig b/src/imgui.zig index 5a6a82e..14454d5 100644 --- a/src/imgui.zig +++ b/src/imgui.zig @@ -11,7 +11,7 @@ const emu = @import("core/emu.zig"); const Gui = @import("platform.zig").Gui; const Arm7tdmi = @import("core/cpu.zig").Arm7tdmi; -const RingBuffer = @import("util.zig").RingBuffer; +const RingBuffer = @import("zba-util").RingBuffer; const Allocator = std.mem.Allocator; const GLuint = gl.GLuint; @@ -43,7 +43,7 @@ pub const State = struct { pub fn deinit(self: *@This(), allocator: Allocator) void { allocator.free(self.title); - self.fps_hist.deinit(allocator); + allocator.free(self.fps_hist.buf); self.* = undefined; } diff --git a/src/main.zig b/src/main.zig index 765cd27..541ad81 100644 --- a/src/main.zig +++ b/src/main.zig @@ -70,9 +70,10 @@ pub fn main() void { const paths = handleArguments(allocator, data_path, &result) catch |e| exitln("failed to handle cli arguments: {}", .{e}); defer if (paths.save) |path| allocator.free(path); - const log_file = if (config.config().debug.cpu_trace) blk: { - break :blk std.fs.cwd().createFile("zba.log", .{}) catch |e| exitln("failed to create trace log file: {}", .{e}); - } else null; + const log_file = switch (config.config().debug.cpu_trace) { + true => std.fs.cwd().createFile("zba.log", .{}) catch |e| exitln("failed to create trace log file: {}", .{e}), + false => null, + }; defer if (log_file) |file| file.close(); // TODO: Take Emulator Init Code out of main.zig diff --git a/src/util.zig b/src/util.zig index 85177bf..db49131 100644 --- a/src/util.zig +++ b/src/util.zig @@ -7,27 +7,6 @@ const Arm7tdmi = @import("core/cpu.zig").Arm7tdmi; const Allocator = std.mem.Allocator; -// Sign-Extend value of type `T` to type `U` -pub fn sext(comptime T: type, comptime U: type, value: T) T { - // U must have less bits than T - comptime std.debug.assert(@typeInfo(U).Int.bits <= @typeInfo(T).Int.bits); - - const iT = std.meta.Int(.signed, @typeInfo(T).Int.bits); - const ExtU = if (@typeInfo(U).Int.signedness == .unsigned) T else iT; - const shift_amt = @intCast(Log2Int(T), @typeInfo(T).Int.bits - @typeInfo(U).Int.bits); - - return @bitCast(T, @bitCast(iT, @as(ExtU, @truncate(U, value)) << shift_amt) >> shift_amt); -} - -/// See https://godbolt.org/z/W3en9Eche -pub inline fn rotr(comptime T: type, x: T, r: anytype) T { - if (@typeInfo(T).Int.signedness == .signed) - @compileError("cannot rotate signed integer"); - - const ar = @intCast(Log2Int(T), @mod(r, @typeInfo(T).Int.bits)); - return x >> ar | x << (1 +% ~ar); -} - pub const FpsTracker = struct { const Self = @This(); @@ -57,17 +36,6 @@ pub const FpsTracker = struct { } }; -pub fn intToBytes(comptime T: type, value: anytype) [@sizeOf(T)]u8 { - comptime std.debug.assert(@typeInfo(T) == .Int); - - var result: [@sizeOf(T)]u8 = undefined; - - var i: Log2Int(T) = 0; - while (i < result.len) : (i += 1) result[i] = @truncate(u8, value >> i * @bitSizeOf(u8)); - - return result; -} - /// Creates a copy of a title with all Filesystem-invalid characters replaced /// /// e.g. POKEPIN R/S to POKEPIN R_S @@ -317,78 +285,3 @@ pub const FrameBuffer = struct { return self.layers[if (dev == .Emulator) self.current else ~self.current]; } }; - -pub fn RingBuffer(comptime T: type) type { - return struct { - const Self = @This(); - const Index = usize; - const max_capacity = (@as(Index, 1) << @typeInfo(Index).Int.bits - 1) - 1; // half the range of index type - - const log = std.log.scoped(.RingBuffer); - - read: Index, - write: Index, - buf: []T, - - const Error = error{buffer_full}; - - pub fn init(buf: []T) Self { - std.debug.assert(std.math.isPowerOfTwo(buf.len)); // capacity must be a power of two - std.debug.assert(buf.len <= max_capacity); - - std.mem.set(T, buf, 0); - - return .{ .read = 0, .write = 0, .buf = buf }; - } - - pub fn deinit(self: *Self, allocator: Allocator) void { - allocator.free(self.buf); - self.* = undefined; - } - - pub fn push(self: *Self, value: T) Error!void { - if (self.isFull()) return error.buffer_full; - defer self.write += 1; - - self.buf[self.mask(self.write)] = value; - } - - pub fn pop(self: *Self) ?T { - if (self.isEmpty()) return null; - defer self.read += 1; - - return self.buf[self.mask(self.read)]; - } - - /// Returns the number of entries read - pub fn copy(self: *const Self, cpy: []T) Index { - const count = std.math.min(self.len(), cpy.len); - var start: Index = self.read; - - for (cpy, 0..) |*v, i| { - if (i >= count) break; - - v.* = self.buf[self.mask(start)]; - start += 1; - } - - return count; - } - - fn len(self: *const Self) Index { - return self.write - self.read; - } - - fn isFull(self: *const Self) bool { - return self.len() == self.buf.len; - } - - fn isEmpty(self: *const Self) bool { - return self.read == self.write; - } - - fn mask(self: *const Self, idx: Index) Index { - return idx & (self.buf.len - 1); - } - }; -}