From caaa60d1a87d030ac6d8c268b69be762d45b5b23 Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Tue, 27 Dec 2022 05:41:19 -0600 Subject: [PATCH] fix: rotate unaligned reads on BIOS open-bus --- src/core/Bus.zig | 8 ++++---- src/core/bus/Bios.zig | 31 +++++++++++++++++++++++++------ 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/core/Bus.zig b/src/core/Bus.zig index 2613a80..0c06f83 100644 --- a/src/core/Bus.zig +++ b/src/core/Bus.zig @@ -227,7 +227,7 @@ fn dbgSlowRead(self: *const Self, comptime T: type, unaligned_address: u32) T { // General Internal Memory 0x00 => blk: { if (address < Bios.size) - break :blk self.bios.dbgRead(T, self.cpu.r[15], address); + break :blk self.bios.dbgRead(T, self.cpu.r[15], unaligned_address); break :blk self.openBus(T, address); }, @@ -347,7 +347,7 @@ fn slowRead(self: *Self, comptime T: type, unaligned_address: u32) T { // General Internal Memory 0x00 => blk: { if (address < Bios.size) - break :blk self.bios.read(T, self.cpu.r[15], address); + break :blk self.bios.read(T, self.cpu.r[15], unaligned_address); break :blk self.openBus(T, address); }, @@ -437,11 +437,11 @@ inline fn rotateBy(comptime T: type, address: u32) u32 { u32 => address & 3, u16 => address & 1, u8 => 0, - else => @compileError("Backup: Unsupported write width"), + else => @compileError("Unsupported write width"), }; } -inline fn forceAlign(comptime T: type, address: u32) u32 { +pub inline fn forceAlign(comptime T: type, address: u32) u32 { return switch (T) { u32 => address & ~@as(u32, 3), u16 => address & ~@as(u32, 1), diff --git a/src/core/bus/Bios.zig b/src/core/bus/Bios.zig index 89677a0..80dae9f 100644 --- a/src/core/bus/Bios.zig +++ b/src/core/bus/Bios.zig @@ -3,6 +3,9 @@ const std = @import("std"); const Allocator = std.mem.Allocator; const log = std.log.scoped(.Bios); +const rotr = @import("../../util.zig").rotr; +const forceAlign = @import("../Bus.zig").forceAlign; + /// Size of the BIOS in bytes pub const size = 0x4000; const Self = @This(); @@ -12,19 +15,35 @@ allocator: Allocator, addr_latch: u32, -pub fn read(self: *Self, comptime T: type, r15: u32, addr: u32) T { +// 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.debug("Rejected read since r15=0x{X:0>8}", .{r15}); - return @truncate(T, self._read(T, self.addr_latch)); + 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))); } -pub fn dbgRead(self: *const Self, comptime T: type, r15: u32, addr: u32) T { - if (r15 < Self.size) return self._read(T, addr); - return @truncate(T, self._read(T, self.addr_latch + 8)); +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