zba/src/core/bus/Bios.zig

88 lines
2.6 KiB
Zig
Raw Normal View History

2022-01-07 23:33:49 +00:00
const std = @import("std");
const Allocator = std.mem.Allocator;
2022-04-08 19:48:43 +00:00
const log = std.log.scoped(.Bios);
2022-04-14 02:21:25 +00:00
const rotr = @import("zba-util").rotr;
const forceAlign = @import("../Bus.zig").forceAlign;
2022-04-14 02:21:25 +00:00
/// Size of the BIOS in bytes
pub const size = 0x4000;
2022-01-07 23:33:49 +00:00
const Self = @This();
2022-02-04 05:55:14 +00:00
buf: ?[]u8,
2022-09-03 21:30:48 +00:00
allocator: Allocator,
2022-01-07 23:33:49 +00:00
2022-12-27 12:42:06 +00:00
addr_latch: u32 = 0,
2022-05-27 23:04:45 +00:00
// https://github.com/ITotalJustice/notorious_beeg/issues/106
pub fn read(self: *Self, comptime T: type, r15: u32, address: u32) T {
if (r15 < Self.size) {
const addr = forceAlign(T, address);
self.addr_latch = addr;
return self._read(T, addr);
}
log.warn("Open Bus! Read from 0x{X:0>8}, but PC was 0x{X:0>8}", .{ address, r15 });
const value = self._read(u32, self.addr_latch);
return @truncate(T, rotr(u32, value, 8 * rotateBy(T, address)));
}
fn rotateBy(comptime T: type, address: u32) u32 {
return switch (T) {
u8 => address & 3,
u16 => address & 2,
u32 => 0,
else => @compileError("bios: unsupported read width"),
};
}
pub fn dbgRead(self: *const Self, comptime T: type, r15: u32, address: u32) T {
if (r15 < Self.size) return self._read(T, forceAlign(T, address));
const value = self._read(u32, self.addr_latch);
return @truncate(T, rotr(u32, value, 8 * rotateBy(T, address)));
}
/// Read without the GBA safety checks
fn _read(self: *const Self, comptime T: type, addr: u32) T {
const buf = self.buf orelse std.debug.panic("[BIOS] ZBA tried to read {} from 0x{X:0>8} but not BIOS was present", .{ T, addr });
return switch (T) {
u32, u16, u8 => std.mem.readIntSliceLittle(T, buf[addr..][0..@sizeOf(T)]),
else => @compileError("BIOS: Unsupported read width"),
};
}
pub fn write(_: *Self, comptime T: type, addr: u32, value: T) void {
@setCold(true);
log.debug("Tried to write {} 0x{X:} to 0x{X:0>8} ", .{ T, value, addr });
}
2022-09-03 21:30:48 +00:00
pub fn init(allocator: Allocator, maybe_path: ?[]const u8) !Self {
2022-12-27 12:42:06 +00:00
if (maybe_path == null) return .{ .buf = null, .allocator = allocator };
const path = maybe_path.?;
2022-08-26 19:05:04 +00:00
2022-12-27 12:42:06 +00:00
const buf = try allocator.alloc(u8, Self.size);
errdefer allocator.free(buf);
2022-01-07 23:33:49 +00:00
2022-12-27 12:42:06 +00:00
const file = try std.fs.cwd().openFile(path, .{});
defer file.close();
const file_len = try file.readAll(buf);
if (file_len != Self.size) log.err("Expected BIOS to be {}B, was {}B", .{ Self.size, file_len });
return Self{ .buf = buf, .allocator = allocator };
2022-01-07 23:33:49 +00:00
}
pub fn reset(self: *Self) void {
self.addr_latch = 0;
}
2022-08-29 05:32:41 +00:00
pub fn deinit(self: *Self) void {
2022-09-03 21:30:48 +00:00
if (self.buf) |buf| self.allocator.free(buf);
2022-08-29 05:32:41 +00:00
self.* = undefined;
2022-01-07 23:33:49 +00:00
}