From 5ea888f68cf7a958aae91dcb487667a72078ec5a Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Tue, 4 Jan 2022 03:29:56 -0600 Subject: [PATCH] feat(bus): implement Palette RAM and DISPSTAT --- src/bus.zig | 10 +++++----- src/bus/io.zig | 31 ++++++++++++++++++++++++------- src/ppu.zig | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/src/bus.zig b/src/bus.zig index ba0acd0..8f13e50 100644 --- a/src/bus.zig +++ b/src/bus.zig @@ -37,7 +37,7 @@ pub const Bus = struct { 0x0400_0000...0x0400_03FE => self.read32(addr), // Internal Display Memory - 0x0500_0000...0x0500_03FF => std.debug.panic("[Bus:32] read from 0x{X:} in BG/OBJ Palette RAM", .{addr}), + 0x0500_0000...0x0500_03FF => self.ppu.palette.get32(@as(usize, addr - 0x0500_0000)), 0x0600_0000...0x0601_7FFF => self.ppu.vram.get32(@as(usize, addr - 0x0600_0000)), 0x0700_0000...0x0700_03FF => std.debug.panic("[Bus:32] read from 0x{X:} in OAM", .{addr}), @@ -63,7 +63,7 @@ pub const Bus = struct { 0x0400_0000...0x0400_03FE => std.debug.panic("[Bus:32] wrote 0x{X:} to 0x{X:} in I/O", .{ word, addr }), // Internal Display Memory - 0x0500_0000...0x0500_03FF => std.debug.panic("[Bus:32] wrote 0x{X:} to 0x{X:} in BG/OBJ Palette RAM", .{ word, addr }), + 0x0500_0000...0x0500_03FF => self.ppu.palette.set32(@as(usize, addr - 0x0500_0000), word), 0x0600_0000...0x0601_7FFF => self.ppu.vram.set32(@as(usize, addr - 0x0600_0000), word), 0x0700_0000...0x0700_03FF => std.debug.panic("[Bus:32] wrote 0x{X:} to 0x{X:} in OAM", .{ word, addr }), @@ -80,7 +80,7 @@ pub const Bus = struct { 0x0400_0000...0x0400_03FE => self.io.read16(addr), // Internal Display Memory - 0x0500_0000...0x0500_03FF => std.debug.panic("[Bus:16] read from 0x{X:} in BG/OBJ Palette RAM", .{addr}), + 0x0500_0000...0x0500_03FF => self.ppu.palette.get16(@as(usize, addr - 0x0500_0000)), 0x0600_0000...0x0601_7FFF => self.ppu.vram.get16(@as(usize, addr - 0x0600_0000)), 0x0700_0000...0x0700_03FF => std.debug.panic("[Bus:16] read from 0x{X:} in OAM", .{addr}), @@ -105,7 +105,7 @@ pub const Bus = struct { 0x0400_0000...0x0400_03FE => self.io.write16(addr, halfword), // Internal Display Memory - 0x0500_0000...0x0500_03FF => std.debug.panic("[Bus:16] write 0x{X:} to 0x{X:} in BG/OBJ Palette RAM", .{ halfword, addr }), + 0x0500_0000...0x0500_03FF => self.ppu.palette.set16(@as(usize, addr - 0x0500_0000), halfword), 0x0600_0000...0x0601_7FFF => self.ppu.vram.set16(@as(usize, addr - 0x0600_0000), halfword), 0x0700_0000...0x0700_03FF => std.debug.panic("[Bus:16] write 0x{X:} to 0x{X:} in OAM", .{ halfword, addr }), @@ -122,7 +122,7 @@ pub const Bus = struct { 0x0400_0000...0x0400_03FE => self.io.read8(addr), // Internal Display Memory - 0x0500_0000...0x0500_03FF => std.debug.panic("[Bus:8] read from 0x{X:} in BG/OBJ Palette RAM", .{addr}), + 0x0500_0000...0x0500_03FF => self.ppu.palette.get8(@as(usize, addr - 0x0500_0000)), 0x0600_0000...0x0601_7FFF => self.ppu.vram.get8(@as(usize, addr - 0x0600_0000)), 0x0700_0000...0x0700_03FF => std.debug.panic("[Bus:8] read from 0x{X:} in OAM", .{addr}), diff --git a/src/bus/io.zig b/src/bus/io.zig index 9ae59a7..54044e9 100644 --- a/src/bus/io.zig +++ b/src/bus/io.zig @@ -6,37 +6,43 @@ const Bit = bitfield.Bit; pub const Io = struct { dispcnt: Dispcnt, + dispstat: Dispstat, pub fn init() @This() { return .{ - .dispcnt = .{ .val = 0x0000_0000 }, + .dispcnt = .{ .raw = 0x0000_0000 }, + .dispstat = .{ .raw = 0x0000_0000 }, }; } pub fn read32(self: *const @This(), addr: u32) u32 { return switch (addr) { - 0x0400_0000 => @as(u32, self.dispcnt.val), + 0x0400_0000 => @as(u32, self.dispcnt.raw), + 0x0400_0004 => @as(u32, self.dispstat.raw), else => std.debug.panic("[I/O:32] tried to read from {X:}", .{addr}), }; } pub fn read16(self: *const @This(), addr: u32) u16 { return switch (addr) { - 0x0400_0000 => self.dispcnt.val, + 0x0400_0000 => self.dispcnt.raw, + 0x0400_0004 => self.dispstat.raw, else => std.debug.panic("[I/O:16] tried to read from {X:}", .{addr}), }; } pub fn write16(self: *@This(), addr: u32, halfword: u16) void { switch (addr) { - 0x0400_0000 => self.dispcnt.val = halfword, + 0x0400_0000 => self.dispcnt.raw = halfword, + 0x0400_0004 => self.dispstat.raw = halfword, else => std.debug.panic("[I/O:16] tried to write 0x{X:} to 0x{X:}", .{ halfword, addr }), } } pub fn read8(self: *const @This(), addr: u32) u8 { return switch (addr) { - 0x0400_0000 => @truncate(u8, self.dispcnt.val), + 0x0400_0000 => @truncate(u8, self.dispcnt.raw), + 0x0400_0004 => @truncate(u8, self.dispstat.raw), else => std.debug.panic("[I/O:8] tried to read from {X:}", .{addr}), }; } @@ -45,12 +51,23 @@ pub const Io = struct { const Dispcnt = extern union { bg_mode: Bitfield(u16, 0, 3), frame_select: Bit(u16, 4), - hblank_interval_free: Bit(u16, 5), + hblank_interraw_free: Bit(u16, 5), obj_mapping: Bit(u16, 6), forced_blank: Bit(u16, 7), bg_enable: Bitfield(u16, 8, 4), obj_enable: Bit(u16, 12), win_enable: Bitfield(u16, 13, 2), obj_win_enable: Bit(u16, 15), - val: u16, + raw: u16, +}; + +const Dispstat = extern union { + vblank: Bit(u16, 0), + hblank: Bit(u16, 1), + vcount: Bit(u16, 2), + vblank_irq: Bit(u16, 3), + hblank_irq: Bit(u16, 4), + vcount_irq: Bit(u16, 5), + vcount_setting: Bitfield(u16, 8, 7), + raw: u16, }; diff --git a/src/ppu.zig b/src/ppu.zig index e149c0b..70738c7 100644 --- a/src/ppu.zig +++ b/src/ppu.zig @@ -4,10 +4,12 @@ const Allocator = std.mem.Allocator; pub const Ppu = struct { vram: Vram, + palette: Palette, pub fn init(alloc: Allocator) !@This() { return @This(){ .vram = try Vram.init(alloc), + .palette = try Palette.init(alloc), }; } @@ -16,6 +18,44 @@ pub const Ppu = struct { } }; +const Palette = struct { + buf: []u8, + alloc: Allocator, + + fn init(alloc: Allocator) !@This() { + return @This(){ + .buf = try alloc.alloc(u8, 0x400), + .alloc = alloc, + }; + } + + fn deinit(self: *@This()) void { + self.alloc.free(self.buf); + } + + pub inline fn get32(self: *const @This(), idx: usize) u32 { + return (@as(u32, self.get16(idx + 2)) << 16) | @as(u32, self.get16(idx)); + } + + pub inline fn set32(self: *@This(), idx: usize, word: u32) void { + self.set16(idx + 2, @truncate(u16, word >> 16)); + self.set16(idx, @truncate(u16, word)); + } + + pub inline fn get16(self: *const @This(), idx: usize) u16 { + return (@as(u16, self.buf[idx + 1]) << 8) | @as(u16, self.buf[idx]); + } + + pub inline fn set16(self: *@This(), idx: usize, halfword: u16) void { + self.buf[idx + 1] = @truncate(u8, halfword >> 8); + self.buf[idx] = @truncate(u8, halfword); + } + + pub inline fn get8(self: *const @This(), idx: usize) u8 { + return self.buf[idx]; + } +}; + const Vram = struct { buf: []u8, alloc: Allocator,