chore: move util.zig
This commit is contained in:
@@ -12,7 +12,7 @@ const Apu = @import("apu.zig").Apu;
|
||||
const DmaTuple = @import("bus/dma.zig").DmaTuple;
|
||||
const TimerTuple = @import("bus/timer.zig").TimerTuple;
|
||||
const Scheduler = @import("scheduler.zig").Scheduler;
|
||||
const FilePaths = @import("util.zig").FilePaths;
|
||||
const FilePaths = @import("../util.zig").FilePaths;
|
||||
|
||||
const io = @import("bus/io.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
@@ -20,7 +20,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("../util.zig").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
|
||||
|
@@ -1,7 +1,7 @@
|
||||
const std = @import("std");
|
||||
const SDL = @import("sdl2");
|
||||
const io = @import("bus/io.zig");
|
||||
const util = @import("util.zig");
|
||||
const util = @import("../util.zig");
|
||||
|
||||
const Arm7tdmi = @import("cpu.zig").Arm7tdmi;
|
||||
const Scheduler = @import("scheduler.zig").Scheduler;
|
||||
@@ -9,7 +9,7 @@ const Scheduler = @import("scheduler.zig").Scheduler;
|
||||
const SoundFifo = std.fifo.LinearFifo(u8, .{ .Static = 0x20 });
|
||||
const AudioDeviceId = SDL.SDL_AudioDeviceID;
|
||||
|
||||
const intToBytes = @import("util.zig").intToBytes;
|
||||
const intToBytes = @import("../util.zig").intToBytes;
|
||||
const log = std.log.scoped(.APU);
|
||||
|
||||
pub const host_sample_rate = 1 << 15;
|
||||
|
@@ -2,8 +2,8 @@ const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const log = std.log.scoped(.Backup);
|
||||
|
||||
const escape = @import("../util.zig").escape;
|
||||
const span = @import("../util.zig").span;
|
||||
const escape = @import("../../util.zig").escape;
|
||||
const span = @import("../../util.zig").span;
|
||||
|
||||
const backup_kinds = [6]Needle{
|
||||
.{ .str = "EEPROM_V", .kind = .Eeprom },
|
||||
|
@@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const util = @import("../util.zig");
|
||||
const util = @import("../../util.zig");
|
||||
|
||||
const DmaControl = @import("io.zig").DmaControl;
|
||||
const Bus = @import("../Bus.zig");
|
||||
|
@@ -3,7 +3,7 @@ const builtin = @import("builtin");
|
||||
const timer = @import("timer.zig");
|
||||
const dma = @import("dma.zig");
|
||||
const apu = @import("../apu.zig");
|
||||
const util = @import("../util.zig");
|
||||
const util = @import("../../util.zig");
|
||||
|
||||
const Bit = @import("bitfield").Bit;
|
||||
const Bitfield = @import("bitfield").Bitfield;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const util = @import("../util.zig");
|
||||
const util = @import("../../util.zig");
|
||||
|
||||
const TimerControl = @import("io.zig").TimerControl;
|
||||
const Io = @import("io.zig").Io;
|
||||
|
@@ -1,12 +1,12 @@
|
||||
const std = @import("std");
|
||||
const util = @import("util.zig");
|
||||
const util = @import("../util.zig");
|
||||
|
||||
const Bus = @import("Bus.zig");
|
||||
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 FilePaths = @import("../util.zig").FilePaths;
|
||||
const Logger = @import("../util.zig").Logger;
|
||||
|
||||
const File = std.fs.File;
|
||||
|
||||
@@ -125,7 +125,7 @@ pub const thumb = struct {
|
||||
const swi = @import("cpu/thumb/software_interrupt.zig").fmt17;
|
||||
const branch = @import("cpu/thumb/branch.zig");
|
||||
|
||||
/// Determine index into THUMB InstrFn LUT
|
||||
/// Determine index into THUMB InstrFn LUT
|
||||
fn idx(opcode: u16) u10 {
|
||||
return @truncate(u10, opcode >> 6);
|
||||
}
|
||||
|
@@ -4,7 +4,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("../../../util.zig").sext;
|
||||
|
||||
pub fn branch(comptime L: bool) InstrFn {
|
||||
return struct {
|
||||
|
@@ -4,8 +4,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("../../../util.zig").sext;
|
||||
const rotr = @import("../../../util.zig").rotr;
|
||||
|
||||
pub fn halfAndSignedDataTransfer(comptime P: bool, comptime U: bool, comptime I: bool, comptime W: bool, comptime L: bool) InstrFn {
|
||||
return struct {
|
||||
|
@@ -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("../../../util.zig").rotr;
|
||||
|
||||
pub fn psrTransfer(comptime I: bool, comptime R: bool, comptime kind: u2) InstrFn {
|
||||
return struct {
|
||||
|
@@ -4,7 +4,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("../../../util.zig").rotr;
|
||||
|
||||
pub fn singleDataSwap(comptime B: bool) InstrFn {
|
||||
return struct {
|
||||
|
@@ -1,12 +1,12 @@
|
||||
const std = @import("std");
|
||||
const util = @import("../../util.zig");
|
||||
const util = @import("../../../util.zig");
|
||||
|
||||
const shifter = @import("../barrel_shifter.zig");
|
||||
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("../../../util.zig").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 {
|
||||
|
@@ -3,7 +3,7 @@ const std = @import("std");
|
||||
const Arm7tdmi = @import("../cpu.zig").Arm7tdmi;
|
||||
const CPSR = @import("../cpu.zig").PSR;
|
||||
|
||||
const rotr = @import("../util.zig").rotr;
|
||||
const rotr = @import("../../util.zig").rotr;
|
||||
|
||||
pub fn execute(comptime S: bool, cpu: *Arm7tdmi, opcode: u32) u32 {
|
||||
var result: u32 = undefined;
|
||||
|
@@ -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("../../../util.zig").sext;
|
||||
|
||||
pub fn fmt16(comptime cond: u4) InstrFn {
|
||||
return struct {
|
||||
|
@@ -4,7 +4,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 rotr = @import("../../../util.zig").rotr;
|
||||
const sext = @import("../../../util.zig").sext;
|
||||
|
||||
pub fn fmt6(comptime rd: u3) InstrFn {
|
||||
return struct {
|
||||
@@ -16,8 +17,6 @@ pub fn fmt6(comptime rd: u3) InstrFn {
|
||||
}.inner;
|
||||
}
|
||||
|
||||
const sext = @import("../../util.zig").sext;
|
||||
|
||||
pub fn fmt78(comptime op: u2, comptime T: bool) InstrFn {
|
||||
return struct {
|
||||
fn inner(cpu: *Arm7tdmi, bus: *Bus, opcode: u16) void {
|
||||
|
@@ -4,8 +4,8 @@ const SDL = @import("sdl2");
|
||||
const Bus = @import("Bus.zig");
|
||||
const Scheduler = @import("scheduler.zig").Scheduler;
|
||||
const Arm7tdmi = @import("cpu.zig").Arm7tdmi;
|
||||
const FpsTracker = @import("util.zig").FpsTracker;
|
||||
const FilePaths = @import("util.zig").FilePaths;
|
||||
const FpsTracker = @import("../util.zig").FpsTracker;
|
||||
const FilePaths = @import("../util.zig").FilePaths;
|
||||
|
||||
const Timer = std.time.Timer;
|
||||
const Thread = std.Thread;
|
||||
|
@@ -1,232 +0,0 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const Log2Int = std.math.Log2Int;
|
||||
const Arm7tdmi = @import("cpu.zig").Arm7tdmi;
|
||||
|
||||
const allow_unhandled_io = @import("emu.zig").allow_unhandled_io;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/// 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();
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn tick(self: *Self) void {
|
||||
_ = self.count.fetchAdd(1, .Monotonic);
|
||||
}
|
||||
|
||||
pub fn value(self: *Self) u32 {
|
||||
if (self.timer.read() >= std.time.ns_per_s) {
|
||||
self.fps = self.count.swap(0, .SeqCst);
|
||||
self.timer.reset();
|
||||
}
|
||||
|
||||
return self.fps;
|
||||
}
|
||||
};
|
||||
|
||||
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 is an Uppercase ASCII string which is
|
||||
/// null-padded to 12 bytes
|
||||
///
|
||||
/// This function returns a slice of the ASCII string without the null terminator(s)
|
||||
/// (essentially, a proper Zig/Rust/Any modern language String)
|
||||
pub fn span(title: *const [12]u8) []const u8 {
|
||||
const end = std.mem.indexOfScalar(u8, title, '\x00');
|
||||
return title[0 .. end orelse title.len];
|
||||
}
|
||||
|
||||
test "span" {
|
||||
var example: *const [12]u8 = "POKEMON_EMER";
|
||||
try std.testing.expectEqualSlices(u8, "POKEMON_EMER", span(example));
|
||||
|
||||
example = "POKEMON_EME\x00";
|
||||
try std.testing.expectEqualSlices(u8, "POKEMON_EME", span(example));
|
||||
|
||||
example = "POKEMON_EM\x00\x00";
|
||||
try std.testing.expectEqualSlices(u8, "POKEMON_EM", span(example));
|
||||
|
||||
example = "POKEMON_E\x00\x00\x00";
|
||||
try std.testing.expectEqualSlices(u8, "POKEMON_E", span(example));
|
||||
|
||||
example = "POKEMON_\x00\x00\x00\x00";
|
||||
try std.testing.expectEqualSlices(u8, "POKEMON_", span(example));
|
||||
|
||||
example = "POKEMON\x00\x00\x00\x00\x00";
|
||||
try std.testing.expectEqualSlices(u8, "POKEMON", span(example));
|
||||
|
||||
example = "POKEMO\x00\x00\x00\x00\x00\x00";
|
||||
try std.testing.expectEqualSlices(u8, "POKEMO", span(example));
|
||||
|
||||
example = "POKEM\x00\x00\x00\x00\x00\x00\x00";
|
||||
try std.testing.expectEqualSlices(u8, "POKEM", span(example));
|
||||
|
||||
example = "POKE\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||
try std.testing.expectEqualSlices(u8, "POKE", span(example));
|
||||
|
||||
example = "POK\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||
try std.testing.expectEqualSlices(u8, "POK", span(example));
|
||||
|
||||
example = "PO\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||
try std.testing.expectEqualSlices(u8, "PO", span(example));
|
||||
|
||||
example = "P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||
try std.testing.expectEqualSlices(u8, "P", span(example));
|
||||
|
||||
example = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||
try std.testing.expectEqualSlices(u8, "", span(example));
|
||||
}
|
||||
|
||||
/// Creates a copy of a title with all Filesystem-invalid characters replaced
|
||||
///
|
||||
/// e.g. POKEPIN R/S to POKEPIN R_S
|
||||
pub fn escape(title: [12]u8) [12]u8 {
|
||||
var ret: [12]u8 = title;
|
||||
|
||||
//TODO: Add more replacements
|
||||
std.mem.replaceScalar(u8, &ret, '/', '_');
|
||||
std.mem.replaceScalar(u8, &ret, '\\', '_');
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
pub const FilePaths = struct {
|
||||
rom: []const u8,
|
||||
bios: ?[]const u8,
|
||||
save: ?[]const u8,
|
||||
};
|
||||
|
||||
pub const io = struct {
|
||||
pub const read = struct {
|
||||
pub fn todo(comptime log: anytype, comptime format: []const u8, args: anytype) u8 {
|
||||
log.debug(format, args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pub fn undef(comptime T: type, log: anytype, comptime format: []const u8, args: anytype) ?T {
|
||||
log.warn(format, args);
|
||||
if (builtin.mode == .Debug and !allow_unhandled_io) std.debug.panic("TODO: Implement I/O Register", .{});
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
pub const write = struct {
|
||||
pub fn undef(log: anytype, comptime format: []const u8, args: anytype) void {
|
||||
log.warn(format, args);
|
||||
if (builtin.mode == .Debug and !allow_unhandled_io) std.debug.panic("TODO: Implement I/O Register", .{});
|
||||
}
|
||||
};
|
||||
};
|
||||
pub fn readUndefined(log: anytype, comptime format: []const u8, args: anytype) u8 {
|
||||
log.warn(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.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, cpu: *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 (cpu.cpsr.t.read()) {
|
||||
if (opcode >> 11 == 0x1E) {
|
||||
// Instruction 1 of a BL Opcode, print in ARM mode
|
||||
const low = cpu.bus.dbgRead(u16, cpu.r[15]);
|
||||
const bl_opcode = @as(u32, opcode) << 16 | low;
|
||||
|
||||
self.print(arm_fmt, Self.fmtArgs(cpu, bl_opcode)) catch @panic("failed to write to log file");
|
||||
} else {
|
||||
self.print(thumb_fmt, Self.fmtArgs(cpu, opcode)) catch @panic("failed to write to log file");
|
||||
}
|
||||
} else {
|
||||
self.print(arm_fmt, Self.fmtArgs(cpu, opcode)) catch @panic("failed to write to log file");
|
||||
}
|
||||
}
|
||||
|
||||
fn fmtArgs(cpu: *const Arm7tdmi, opcode: u32) FmtArgTuple {
|
||||
return .{
|
||||
cpu.r[0],
|
||||
cpu.r[1],
|
||||
cpu.r[2],
|
||||
cpu.r[3],
|
||||
cpu.r[4],
|
||||
cpu.r[5],
|
||||
cpu.r[6],
|
||||
cpu.r[7],
|
||||
cpu.r[8],
|
||||
cpu.r[9],
|
||||
cpu.r[10],
|
||||
cpu.r[11],
|
||||
cpu.r[12],
|
||||
cpu.r[13],
|
||||
cpu.r[14],
|
||||
cpu.r[15],
|
||||
cpu.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 });
|
Reference in New Issue
Block a user