chore: introduce zba-util
In an effort to reuse code between zba and zba-gdbstub, move common util code (like the SPSC Channel I implemented in this commit) in a new lib
This commit is contained in:
parent
72b702cb21
commit
11eae091db
|
@ -22,3 +22,6 @@
|
||||||
[submodule "lib/nfd-zig"]
|
[submodule "lib/nfd-zig"]
|
||||||
path = lib/nfd-zig
|
path = lib/nfd-zig
|
||||||
url = https://github.com/fabioarnold/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
|
||||||
|
|
|
@ -33,7 +33,7 @@ pub fn build(b: *std.build.Builder) void {
|
||||||
exe.addAnonymousModule("datetime", .{ .source_file = .{ .path = "lib/zig-datetime/src/main.zig" } });
|
exe.addAnonymousModule("datetime", .{ .source_file = .{ .path = "lib/zig-datetime/src/main.zig" } });
|
||||||
|
|
||||||
// Bitfield type from FlorenceOS: https://github.com/FlorenceOS/
|
// 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
|
// Argument Parsing Library
|
||||||
exe.addAnonymousModule("clap", .{ .source_file = .{ .path = "lib/zig-clap/clap.zig" } });
|
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
|
// OpenGL 3.3 Bindings
|
||||||
exe.addAnonymousModule("gl", .{ .source_file = .{ .path = "lib/gl.zig" } });
|
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
|
||||||
gdbstub.link(exe);
|
gdbstub.link(exe);
|
||||||
// NativeFileDialog(ue) Bindings
|
// NativeFileDialog(ue) Bindings
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 52ac8d952fe7c722e33a3237e465dcf258076613
|
|
@ -19,7 +19,7 @@ const log = std.log.scoped(.Bus);
|
||||||
|
|
||||||
const createDmaTuple = @import("bus/dma.zig").create;
|
const createDmaTuple = @import("bus/dma.zig").create;
|
||||||
const createTimerTuple = @import("bus/timer.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{
|
const timings: [2][0x10]u8 = [_][0x10]u8{
|
||||||
// BIOS, Unused, EWRAM, IWRAM, I/0, PALRAM, VRAM, OAM, ROM0, ROM0, ROM1, ROM1, ROM2, ROM2, SRAM, Unused
|
// BIOS, Unused, EWRAM, IWRAM, I/0, PALRAM, VRAM, OAM, ROM0, ROM0, ROM1, ROM1, ROM2, ROM2, SRAM, Unused
|
||||||
|
|
|
@ -14,7 +14,6 @@ const SoundFifo = std.fifo.LinearFifo(u8, .{ .Static = 0x20 });
|
||||||
|
|
||||||
const getHalf = util.getHalf;
|
const getHalf = util.getHalf;
|
||||||
const setHalf = util.setHalf;
|
const setHalf = util.setHalf;
|
||||||
const intToBytes = util.intToBytes;
|
|
||||||
|
|
||||||
const log = std.log.scoped(.APU);
|
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 {
|
pub fn push(self: *Self, value: u32) void {
|
||||||
if (!self.enabled) self.enable();
|
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 {
|
fn enable(self: *Self) void {
|
||||||
|
|
|
@ -3,7 +3,7 @@ const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const log = std.log.scoped(.Bios);
|
const log = std.log.scoped(.Bios);
|
||||||
|
|
||||||
const rotr = @import("../../util.zig").rotr;
|
const rotr = @import("zba-util").rotr;
|
||||||
const forceAlign = @import("../Bus.zig").forceAlign;
|
const forceAlign = @import("../Bus.zig").forceAlign;
|
||||||
|
|
||||||
/// Size of the BIOS in bytes
|
/// Size of the BIOS in bytes
|
||||||
|
|
|
@ -12,7 +12,7 @@ const getHalf = util.getHalf;
|
||||||
const setHalf = util.setHalf;
|
const setHalf = util.setHalf;
|
||||||
const setQuart = util.setQuart;
|
const setQuart = util.setQuart;
|
||||||
|
|
||||||
const rotr = @import("../../util.zig").rotr;
|
const rotr = @import("zba-util").rotr;
|
||||||
|
|
||||||
pub fn create() DmaTuple {
|
pub fn create() DmaTuple {
|
||||||
return .{ DmaController(0).init(), DmaController(1).init(), DmaController(2).init(), DmaController(3).init() };
|
return .{ DmaController(0).init(), DmaController(1).init(), DmaController(2).init(), DmaController(3).init() };
|
||||||
|
|
|
@ -2,7 +2,7 @@ const Bus = @import("../../Bus.zig");
|
||||||
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
|
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
|
||||||
const InstrFn = @import("../../cpu.zig").arm.InstrFn;
|
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 {
|
pub fn branch(comptime L: bool) InstrFn {
|
||||||
return struct {
|
return struct {
|
||||||
|
|
|
@ -2,8 +2,8 @@ const Bus = @import("../../Bus.zig");
|
||||||
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
|
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
|
||||||
const InstrFn = @import("../../cpu.zig").arm.InstrFn;
|
const InstrFn = @import("../../cpu.zig").arm.InstrFn;
|
||||||
|
|
||||||
const sext = @import("../../../util.zig").sext;
|
const sext = @import("zba-util").sext;
|
||||||
const rotr = @import("../../../util.zig").rotr;
|
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 {
|
pub fn halfAndSignedDataTransfer(comptime P: bool, comptime U: bool, comptime I: bool, comptime W: bool, comptime L: bool) InstrFn {
|
||||||
return struct {
|
return struct {
|
||||||
|
|
|
@ -7,7 +7,7 @@ const PSR = @import("../../cpu.zig").PSR;
|
||||||
|
|
||||||
const log = std.log.scoped(.PsrTransfer);
|
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 {
|
pub fn psrTransfer(comptime I: bool, comptime R: bool, comptime kind: u2) InstrFn {
|
||||||
return struct {
|
return struct {
|
||||||
|
|
|
@ -2,7 +2,7 @@ const Bus = @import("../../Bus.zig");
|
||||||
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
|
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
|
||||||
const InstrFn = @import("../../cpu.zig").arm.InstrFn;
|
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 {
|
pub fn singleDataSwap(comptime B: bool) InstrFn {
|
||||||
return struct {
|
return struct {
|
||||||
|
|
|
@ -3,7 +3,7 @@ const Bus = @import("../../Bus.zig");
|
||||||
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
|
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
|
||||||
const InstrFn = @import("../../cpu.zig").arm.InstrFn;
|
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 {
|
pub fn singleDataTransfer(comptime I: bool, comptime P: bool, comptime U: bool, comptime B: bool, comptime W: bool, comptime L: bool) InstrFn {
|
||||||
return struct {
|
return struct {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const Arm7tdmi = @import("../cpu.zig").Arm7tdmi;
|
const Arm7tdmi = @import("../cpu.zig").Arm7tdmi;
|
||||||
const CPSR = @import("../cpu.zig").PSR;
|
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 {
|
pub fn exec(comptime S: bool, cpu: *Arm7tdmi, opcode: u32) u32 {
|
||||||
var result: u32 = undefined;
|
var result: u32 = undefined;
|
||||||
|
|
|
@ -3,7 +3,7 @@ const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
|
||||||
const InstrFn = @import("../../cpu.zig").thumb.InstrFn;
|
const InstrFn = @import("../../cpu.zig").thumb.InstrFn;
|
||||||
|
|
||||||
const checkCond = @import("../../cpu.zig").checkCond;
|
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 {
|
pub fn fmt16(comptime cond: u4) InstrFn {
|
||||||
return struct {
|
return struct {
|
||||||
|
|
|
@ -2,8 +2,8 @@ const Bus = @import("../../Bus.zig");
|
||||||
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
|
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
|
||||||
const InstrFn = @import("../../cpu.zig").thumb.InstrFn;
|
const InstrFn = @import("../../cpu.zig").thumb.InstrFn;
|
||||||
|
|
||||||
const rotr = @import("../../../util.zig").rotr;
|
const rotr = @import("zba-util").rotr;
|
||||||
const sext = @import("../../../util.zig").sext;
|
const sext = @import("zba-util").sext;
|
||||||
|
|
||||||
pub fn fmt6(comptime rd: u3) InstrFn {
|
pub fn fmt6(comptime rd: u3) InstrFn {
|
||||||
return struct {
|
return struct {
|
||||||
|
|
|
@ -11,7 +11,7 @@ const emu = @import("core/emu.zig");
|
||||||
|
|
||||||
const Gui = @import("platform.zig").Gui;
|
const Gui = @import("platform.zig").Gui;
|
||||||
const Arm7tdmi = @import("core/cpu.zig").Arm7tdmi;
|
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 Allocator = std.mem.Allocator;
|
||||||
const GLuint = gl.GLuint;
|
const GLuint = gl.GLuint;
|
||||||
|
@ -43,7 +43,7 @@ pub const State = struct {
|
||||||
|
|
||||||
pub fn deinit(self: *@This(), allocator: Allocator) void {
|
pub fn deinit(self: *@This(), allocator: Allocator) void {
|
||||||
allocator.free(self.title);
|
allocator.free(self.title);
|
||||||
self.fps_hist.deinit(allocator);
|
allocator.free(self.fps_hist.buf);
|
||||||
|
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,9 +70,10 @@ pub fn main() void {
|
||||||
const paths = handleArguments(allocator, data_path, &result) catch |e| exitln("failed to handle cli arguments: {}", .{e});
|
const paths = handleArguments(allocator, data_path, &result) catch |e| exitln("failed to handle cli arguments: {}", .{e});
|
||||||
defer if (paths.save) |path| allocator.free(path);
|
defer if (paths.save) |path| allocator.free(path);
|
||||||
|
|
||||||
const log_file = if (config.config().debug.cpu_trace) blk: {
|
const log_file = switch (config.config().debug.cpu_trace) {
|
||||||
break :blk std.fs.cwd().createFile("zba.log", .{}) catch |e| exitln("failed to create trace log file: {}", .{e});
|
true => std.fs.cwd().createFile("zba.log", .{}) catch |e| exitln("failed to create trace log file: {}", .{e}),
|
||||||
} else null;
|
false => null,
|
||||||
|
};
|
||||||
defer if (log_file) |file| file.close();
|
defer if (log_file) |file| file.close();
|
||||||
|
|
||||||
// TODO: Take Emulator Init Code out of main.zig
|
// TODO: Take Emulator Init Code out of main.zig
|
||||||
|
|
107
src/util.zig
107
src/util.zig
|
@ -7,27 +7,6 @@ const Arm7tdmi = @import("core/cpu.zig").Arm7tdmi;
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
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 {
|
pub const FpsTracker = struct {
|
||||||
const Self = @This();
|
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
|
/// Creates a copy of a title with all Filesystem-invalid characters replaced
|
||||||
///
|
///
|
||||||
/// e.g. POKEPIN R/S to POKEPIN R_S
|
/// 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];
|
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue