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:
Rekai Nyangadzayi Musuka 2023-03-10 00:05:31 -06:00
parent 72b702cb21
commit 11eae091db
19 changed files with 28 additions and 128 deletions

3
.gitmodules vendored
View File

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

View File

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

1
lib/zba-util Submodule

@ -0,0 +1 @@
Subproject commit 52ac8d952fe7c722e33a3237e465dcf258076613

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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