feat: allow gdb writes to certain mem regions
This commit is contained in:
		 Submodule lib/zba-gdbstub updated: 82bad92fcf...81ff227ea7
									
								
							
							
								
								
									
										148
									
								
								src/core/Bus.zig
									
									
									
									
									
								
							
							
						
						
									
										148
									
								
								src/core/Bus.zig
									
									
									
									
									
								
							@@ -198,55 +198,6 @@ fn fillReadTableExternal(self: *Self, addr: u32) ?*anyopaque {
 | 
			
		||||
    return &self.pak.buf[masked_addr];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn dbgRead(self: *const Self, comptime T: type, unaligned_address: u32) T {
 | 
			
		||||
    const bits = @typeInfo(std.math.IntFittingRange(0, page_size - 1)).Int.bits;
 | 
			
		||||
    const page = unaligned_address >> bits;
 | 
			
		||||
    const offset = unaligned_address & (page_size - 1);
 | 
			
		||||
 | 
			
		||||
    // We're doing some serious out-of-bounds open-bus reads
 | 
			
		||||
    if (page >= table_len) return self.openBus(T, unaligned_address);
 | 
			
		||||
 | 
			
		||||
    if (self.read_table[page]) |some_ptr| {
 | 
			
		||||
        // We have a pointer to a page, cast the pointer to it's underlying type
 | 
			
		||||
        const Ptr = [*]const T;
 | 
			
		||||
        const ptr = @ptrCast(Ptr, @alignCast(@alignOf(std.meta.Child(Ptr)), some_ptr));
 | 
			
		||||
 | 
			
		||||
        // Note: We don't check array length, since we force align the
 | 
			
		||||
        // lower bits of the address as the GBA would
 | 
			
		||||
        return ptr[forceAlign(T, offset) / @sizeOf(T)];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return self.dbgSlowRead(T, unaligned_address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn dbgSlowRead(self: *const Self, comptime T: type, unaligned_address: u32) T {
 | 
			
		||||
    const page = @truncate(u8, unaligned_address >> 24);
 | 
			
		||||
    const address = forceAlign(T, unaligned_address);
 | 
			
		||||
 | 
			
		||||
    return switch (page) {
 | 
			
		||||
        // General Internal Memory
 | 
			
		||||
        0x00 => blk: {
 | 
			
		||||
            if (address < Bios.size)
 | 
			
		||||
                break :blk self.bios.dbgRead(T, self.cpu.r[15], unaligned_address);
 | 
			
		||||
 | 
			
		||||
            break :blk self.openBus(T, address);
 | 
			
		||||
        },
 | 
			
		||||
        0x02 => unreachable, // handled by fastmem
 | 
			
		||||
        0x03 => unreachable, // handled by fastmem
 | 
			
		||||
        0x04 => self.readIo(T, address),
 | 
			
		||||
 | 
			
		||||
        // Internal Display Memory
 | 
			
		||||
        0x05 => unreachable, // handled by fastmem
 | 
			
		||||
        0x06 => unreachable, // handled by fastmem
 | 
			
		||||
        0x07 => unreachable, // handled by fastmem
 | 
			
		||||
 | 
			
		||||
        // External Memory (Game Pak)
 | 
			
		||||
        0x08...0x0D => self.pak.dbgRead(T, address),
 | 
			
		||||
        0x0E...0x0F => self.readBackup(T, unaligned_address),
 | 
			
		||||
        else => self.openBus(T, address),
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn readIo(self: *const Self, comptime T: type, address: u32) T {
 | 
			
		||||
    return io.read(self, T, address) orelse self.openBus(T, address);
 | 
			
		||||
}
 | 
			
		||||
@@ -336,6 +287,27 @@ pub fn read(self: *Self, comptime T: type, unaligned_address: u32) T {
 | 
			
		||||
    return self.slowRead(T, unaligned_address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn dbgRead(self: *const Self, comptime T: type, unaligned_address: u32) T {
 | 
			
		||||
    const bits = @typeInfo(std.math.IntFittingRange(0, page_size - 1)).Int.bits;
 | 
			
		||||
    const page = unaligned_address >> bits;
 | 
			
		||||
    const offset = unaligned_address & (page_size - 1);
 | 
			
		||||
 | 
			
		||||
    // We're doing some serious out-of-bounds open-bus reads
 | 
			
		||||
    if (page >= table_len) return self.openBus(T, unaligned_address);
 | 
			
		||||
 | 
			
		||||
    if (self.read_table[page]) |some_ptr| {
 | 
			
		||||
        // We have a pointer to a page, cast the pointer to it's underlying type
 | 
			
		||||
        const Ptr = [*]const T;
 | 
			
		||||
        const ptr = @ptrCast(Ptr, @alignCast(@alignOf(std.meta.Child(Ptr)), some_ptr));
 | 
			
		||||
 | 
			
		||||
        // Note: We don't check array length, since we force align the
 | 
			
		||||
        // lower bits of the address as the GBA would
 | 
			
		||||
        return ptr[forceAlign(T, offset) / @sizeOf(T)];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return self.dbgSlowRead(T, unaligned_address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn slowRead(self: *Self, comptime T: type, unaligned_address: u32) T {
 | 
			
		||||
    @setCold(true);
 | 
			
		||||
 | 
			
		||||
@@ -366,6 +338,34 @@ fn slowRead(self: *Self, comptime T: type, unaligned_address: u32) T {
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn dbgSlowRead(self: *const Self, comptime T: type, unaligned_address: u32) T {
 | 
			
		||||
    const page = @truncate(u8, unaligned_address >> 24);
 | 
			
		||||
    const address = forceAlign(T, unaligned_address);
 | 
			
		||||
 | 
			
		||||
    return switch (page) {
 | 
			
		||||
        // General Internal Memory
 | 
			
		||||
        0x00 => blk: {
 | 
			
		||||
            if (address < Bios.size)
 | 
			
		||||
                break :blk self.bios.dbgRead(T, self.cpu.r[15], unaligned_address);
 | 
			
		||||
 | 
			
		||||
            break :blk self.openBus(T, address);
 | 
			
		||||
        },
 | 
			
		||||
        0x02 => unreachable, // handled by fastmem
 | 
			
		||||
        0x03 => unreachable, // handled by fastmem
 | 
			
		||||
        0x04 => self.readIo(T, address),
 | 
			
		||||
 | 
			
		||||
        // Internal Display Memory
 | 
			
		||||
        0x05 => unreachable, // handled by fastmem
 | 
			
		||||
        0x06 => unreachable, // handled by fastmem
 | 
			
		||||
        0x07 => unreachable, // handled by fastmem
 | 
			
		||||
 | 
			
		||||
        // External Memory (Game Pak)
 | 
			
		||||
        0x08...0x0D => self.pak.dbgRead(T, address),
 | 
			
		||||
        0x0E...0x0F => self.readBackup(T, unaligned_address),
 | 
			
		||||
        else => self.openBus(T, address),
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn readBackup(self: *const Self, comptime T: type, unaligned_address: u32) T {
 | 
			
		||||
    const value = self.pak.backup.read(unaligned_address);
 | 
			
		||||
 | 
			
		||||
@@ -406,6 +406,31 @@ pub fn write(self: *Self, comptime T: type, unaligned_address: u32, value: T) vo
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Mostly Identical to `Bus.write`, slowmeme is handled by `Bus.dbgSlowWrite`
 | 
			
		||||
pub fn dbgWrite(self: *Self, comptime T: type, unaligned_address: u32, value: T) void {
 | 
			
		||||
    const bits = @typeInfo(std.math.IntFittingRange(0, page_size - 1)).Int.bits;
 | 
			
		||||
    const page = unaligned_address >> bits;
 | 
			
		||||
    const offset = unaligned_address & (page_size - 1);
 | 
			
		||||
 | 
			
		||||
    // We're doing some serious out-of-bounds open-bus writes, they do nothing though
 | 
			
		||||
    if (page >= table_len) return;
 | 
			
		||||
 | 
			
		||||
    if (self.write_tables[@boolToInt(T == u8)][page]) |some_ptr| {
 | 
			
		||||
        // We have a pointer to a page, cast the pointer to it's underlying type
 | 
			
		||||
        const Ptr = [*]T;
 | 
			
		||||
        const ptr = @ptrCast(Ptr, @alignCast(@alignOf(std.meta.Child(Ptr)), some_ptr));
 | 
			
		||||
 | 
			
		||||
        // Note: We don't check array length, since we force align the
 | 
			
		||||
        // lower bits of the address as the GBA would
 | 
			
		||||
        ptr[forceAlign(T, offset) / @sizeOf(T)] = value;
 | 
			
		||||
    } else {
 | 
			
		||||
        // we can return early if this is an 8-bit OAM write
 | 
			
		||||
        if (T == u8 and @truncate(u8, unaligned_address >> 24) == 0x07) return;
 | 
			
		||||
 | 
			
		||||
        self.dbgSlowWrite(T, unaligned_address, value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn slowWrite(self: *Self, comptime T: type, unaligned_address: u32, value: T) void {
 | 
			
		||||
    @setCold(true);
 | 
			
		||||
 | 
			
		||||
@@ -431,6 +456,31 @@ fn slowWrite(self: *Self, comptime T: type, unaligned_address: u32, value: T) vo
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn dbgSlowWrite(self: *Self, comptime T: type, unaligned_address: u32, value: T) void {
 | 
			
		||||
    @setCold(true);
 | 
			
		||||
 | 
			
		||||
    const page = @truncate(u8, unaligned_address >> 24);
 | 
			
		||||
    const address = forceAlign(T, unaligned_address);
 | 
			
		||||
 | 
			
		||||
    switch (page) {
 | 
			
		||||
        // General Internal Memory
 | 
			
		||||
        0x00 => self.bios.write(T, address, value),
 | 
			
		||||
        0x02 => unreachable, // completely handled by fastmem
 | 
			
		||||
        0x03 => unreachable, // completely handled by fastmem
 | 
			
		||||
        0x04 => return, // FIXME: Let debug writes mess with I/O
 | 
			
		||||
 | 
			
		||||
        // Internal Display Memory
 | 
			
		||||
        0x05 => self.ppu.palette.write(T, address, value),
 | 
			
		||||
        0x06 => self.ppu.vram.write(T, self.ppu.dispcnt, address, value),
 | 
			
		||||
        0x07 => unreachable, // completely handled by fastmem
 | 
			
		||||
 | 
			
		||||
        // External Memory (Game Pak)
 | 
			
		||||
        0x08...0x0D => return, // FIXME: Debug Write to Backup/GPIO w/out messing with state
 | 
			
		||||
        0x0E...0x0F => return, // FIXME: Debug Write to Backup w/out messing with state
 | 
			
		||||
        else => {},
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline fn rotateBy(comptime T: type, address: u32) u32 {
 | 
			
		||||
    return switch (T) {
 | 
			
		||||
        u32 => address & 3,
 | 
			
		||||
 
 | 
			
		||||
@@ -184,11 +184,7 @@ pub const EmuThing = struct {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn write(self: *Self, addr: u32, value: u8) void {
 | 
			
		||||
        _ = value;
 | 
			
		||||
        _ = self;
 | 
			
		||||
        _ = addr;
 | 
			
		||||
 | 
			
		||||
        std.debug.panic("TODO: Implement Debug Writes?", .{});
 | 
			
		||||
        self.cpu.bus.dbgWrite(u8, addr, value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn registers(self: *const Self) *[16]u32 {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user