zba/src/util.zig

115 lines
3.1 KiB
Zig
Raw Normal View History

2021-12-29 21:09:00 +00:00
const std = @import("std");
const builtin = @import("builtin");
const Log2Int = std.math.Log2Int;
2021-12-29 21:09:00 +00:00
// 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 = @intCast(Log2Int(T), @typeInfo(T).Int.bits - @typeInfo(U).Int.bits);
return @bitCast(T, @bitCast(iT, @as(ExtU, @truncate(U, value)) << shift) >> shift);
2021-12-29 21:09:00 +00:00
}
/// See https://godbolt.org/z/W3en9Eche
2022-04-08 05:13:41 +00:00
pub inline fn rotr(comptime T: type, x: T, r: anytype) T {
if (@typeInfo(T).Int.signedness == .signed)
@compileError("cannot rotate signed integer");
2022-04-08 05:13:41 +00:00
const ar = @intCast(Log2Int(T), @mod(r, @typeInfo(T).Int.bits));
return x >> ar | x << (1 +% ~ar);
}
2022-05-23 15:38:44 +00:00
pub const FpsTracker = struct {
const Self = @This();
fps: u32,
count: std.atomic.Atomic(u32),
timer: std.time.Timer,
pub fn init() Self {
return .{
.fps = 0,
.count = std.atomic.Atomic(u32).init(0),
.timer = std.time.Timer.start() catch unreachable,
};
}
2022-05-28 00:50:16 +00:00
pub fn tick(self: *Self) void {
_ = self.count.fetchAdd(1, .Monotonic);
}
pub fn value(self: *Self) u32 {
2022-05-28 00:50:16 +00:00
if (self.timer.read() >= std.time.ns_per_s) {
self.fps = self.count.swap(0, .SeqCst);
self.timer.reset();
}
return self.fps;
}
};
2022-03-18 09:27:37 +00:00
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;
}
/// The Title from the GBA Cartridge may be null padded to a maximum
2022-04-08 05:13:58 +00:00
/// length of 12 bytes.
///
2022-04-08 05:13:58 +00:00
/// This function returns a slice of everything just before the first
/// `\0`
pub fn asString(title: [12]u8) []const u8 {
var len = title.len;
for (title) |char, i| {
if (char == 0) {
len = i;
break;
}
}
return title[0..len];
}
2022-04-08 05:13:58 +00:00
/// Copies a Title and returns either an identical or similar
/// array consisting of ASCII that won't make any file system angry
///
/// e.g. POKEPIN R/S to POKEPIN R_S
pub fn escape(title: [12]u8) [12]u8 {
var result: [12]u8 = title;
for (result) |*char| {
if (char.* == '/' or char.* == '\\') char.* = '_';
if (char.* == 0) break;
}
return result;
}
pub const FilePaths = struct {
rom: []const u8,
bios: ?[]const u8,
save: ?[]const u8,
};
pub fn readUndefined(log: anytype, comptime format: []const u8, args: anytype) u8 {
log.debug(format, args);
if (builtin.mode == .Debug) std.debug.panic("TODO: Implement I/O Register", .{});
return 0;
}
pub fn writeUndefined(log: anytype, comptime format: []const u8, args: anytype) void {
log.debug(format, args);
if (builtin.mode == .Debug) std.debug.panic("TODO: Implement I/O Register", .{});
}