diff --git a/src/bus/io.zig b/src/bus/io.zig index c817a7d..21b8aa2 100644 --- a/src/bus/io.zig +++ b/src/bus/io.zig @@ -184,12 +184,12 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { 0x0400_001C => bus.ppu.setBgOffsets(3, value), 0x0400_0020 => bus.ppu.aff.bg[0].writePaPb(value), 0x0400_0024 => bus.ppu.aff.bg[0].writePcPd(value), - 0x0400_0028 => bus.ppu.aff.bg[0].x.raw = value, - 0x0400_002C => bus.ppu.aff.bg[0].y.raw = value, + 0x0400_0028 => bus.ppu.aff.bg[0].x = @bitCast(i32, value), + 0x0400_002C => bus.ppu.aff.bg[0].y = @bitCast(i32, value), 0x0400_0030 => bus.ppu.aff.bg[1].writePaPb(value), 0x0400_0034 => bus.ppu.aff.bg[1].writePcPd(value), - 0x0400_0038 => bus.ppu.aff.bg[1].x.raw = value, - 0x0400_003C => bus.ppu.aff.bg[1].y.raw = value, + 0x0400_0038 => bus.ppu.aff.bg[1].x = @bitCast(i32, value), + 0x0400_003C => bus.ppu.aff.bg[1].y = @bitCast(i32, value), 0x0400_0040 => log.debug("Wrote 0x{X:0>8} to WIN0H and WIN1H", .{value}), 0x0400_0044 => log.debug("Wrote 0x{X:0>8} to WIN0V and WIN1V", .{value}), 0x0400_0048 => log.debug("Wrote 0x{X:0>8} to WININ and WINOUT", .{value}), @@ -270,22 +270,22 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { 0x0400_001A => bus.ppu.bg[2].vofs.raw = value, 0x0400_001C => bus.ppu.bg[3].hofs.raw = value, 0x0400_001E => bus.ppu.bg[3].vofs.raw = value, - 0x0400_0020 => bus.ppu.aff.bg[0].pa.raw = value, - 0x0400_0022 => bus.ppu.aff.bg[0].pb.raw = value, - 0x0400_0024 => bus.ppu.aff.bg[0].pc.raw = value, - 0x0400_0026 => bus.ppu.aff.bg[0].pd.raw = value, - 0x0400_0028 => bus.ppu.aff.bg[0].x.raw = bus.ppu.aff.bg[0].x.raw & 0xFFFF_0000 | value, - 0x0400_002A => bus.ppu.aff.bg[0].x.raw = bus.ppu.aff.bg[0].x.raw & 0x0000_FFFF | (@as(u32, value) << 16), - 0x0400_002C => bus.ppu.aff.bg[0].y.raw = bus.ppu.aff.bg[0].y.raw & 0xFFFF_0000 | value, - 0x0400_002E => bus.ppu.aff.bg[0].y.raw = bus.ppu.aff.bg[0].y.raw & 0x0000_FFFF | (@as(u32, value) << 16), - 0x0400_0030 => bus.ppu.aff.bg[1].pa.raw = value, - 0x0400_0032 => bus.ppu.aff.bg[1].pb.raw = value, - 0x0400_0034 => bus.ppu.aff.bg[1].pc.raw = value, - 0x0400_0036 => bus.ppu.aff.bg[1].pd.raw = value, - 0x0400_0038 => bus.ppu.aff.bg[1].x.raw = bus.ppu.aff.bg[1].x.raw & 0xFFFF_0000 | value, - 0x0400_003A => bus.ppu.aff.bg[1].x.raw = bus.ppu.aff.bg[1].x.raw & 0x0000_FFFF | (@as(u32, value) << 16), - 0x0400_003C => bus.ppu.aff.bg[1].y.raw = bus.ppu.aff.bg[1].y.raw & 0xFFFF_0000 | value, - 0x0400_003E => bus.ppu.aff.bg[1].y.raw = bus.ppu.aff.bg[1].y.raw & 0x0000_FFFF | (@as(u32, value) << 16), + 0x0400_0020 => bus.ppu.aff.bg[0].pa = @bitCast(i16, value), + 0x0400_0022 => bus.ppu.aff.bg[0].pb = @bitCast(i16, value), + 0x0400_0024 => bus.ppu.aff.bg[0].pc = @bitCast(i16, value), + 0x0400_0026 => bus.ppu.aff.bg[0].pd = @bitCast(i16, value), + 0x0400_0028 => bus.ppu.aff.bg[0].x = @bitCast(i32, @bitCast(u32, bus.ppu.aff.bg[0].x) & 0xFFFF_0000 | value), + 0x0400_002A => bus.ppu.aff.bg[0].x = @bitCast(i32, @bitCast(u32, bus.ppu.aff.bg[0].x) & 0x0000_FFFF | (@as(u32, value) << 16)), + 0x0400_002C => bus.ppu.aff.bg[0].y = @bitCast(i32, @bitCast(u32, bus.ppu.aff.bg[0].y) & 0xFFFF_0000 | value), + 0x0400_002E => bus.ppu.aff.bg[0].y = @bitCast(i32, @bitCast(u32, bus.ppu.aff.bg[0].y) & 0x0000_FFFF | (@as(u32, value) << 16)), + 0x0400_0030 => bus.ppu.aff.bg[1].pa = @bitCast(i16, value), + 0x0400_0032 => bus.ppu.aff.bg[1].pb = @bitCast(i16, value), + 0x0400_0034 => bus.ppu.aff.bg[1].pc = @bitCast(i16, value), + 0x0400_0036 => bus.ppu.aff.bg[1].pd = @bitCast(i16, value), + 0x0400_0038 => bus.ppu.aff.bg[1].x = @bitCast(i32, @bitCast(u32, bus.ppu.aff.bg[1].x) & 0xFFFF_0000 | value), + 0x0400_003A => bus.ppu.aff.bg[1].x = @bitCast(i32, @bitCast(u32, bus.ppu.aff.bg[1].x) & 0x0000_FFFF | (@as(u32, value) << 16)), + 0x0400_003C => bus.ppu.aff.bg[1].y = @bitCast(i32, @bitCast(u32, bus.ppu.aff.bg[1].y) & 0xFFFF_0000 | value), + 0x0400_003E => bus.ppu.aff.bg[1].y = @bitCast(i32, @bitCast(u32, bus.ppu.aff.bg[1].y) & 0x0000_FFFF | (@as(u32, value) << 16)), 0x0400_0040 => log.debug("Wrote 0x{X:0>4} to WIN0H", .{value}), 0x0400_0042 => log.debug("Wrote 0x{X:0>4} to WIN1H", .{value}), 0x0400_0044 => log.debug("Wrote 0x{X:0>4} to WIN0V", .{value}), @@ -561,20 +561,6 @@ pub const BackgroundOffset = extern union { raw: u16, }; -pub const BackgroundRefPoint = extern union { - fractional: Bitfield(u32, 0, 8), - integer: Bitfield(u32, 8, 19), - sign: Bit(u32, 27), - raw: u32, -}; - -pub const BackgroundRotScaleParam = extern union { - fractional: Bitfield(u16, 0, 8), - integer: Bitfield(u16, 8, 7), - sign: Bit(u32, 15), - raw: u16, -}; - /// Read / Write const InterruptRequest = extern union { vblank: Bit(u16, 0), diff --git a/src/ppu.zig b/src/ppu.zig index 1bc7fd1..6f38256 100644 --- a/src/ppu.zig +++ b/src/ppu.zig @@ -201,6 +201,14 @@ pub const Ppu = struct { if (pal_id != 0) self.scanline_buf[@bitCast(u9, x)] = self.palette.read(u16, 0x200 + pal_id * 2); } + fn drawAffineBackground(self: *Self, comptime n: u3) void { + comptime std.debug.assert(n == 2 or n == 3); // Only BG2 and BG3 can be affine + + // Update BG?X/Y + self.aff.bg[n - 2].x_latch += self.aff.bg[n - 2].pb >> 8; + self.aff.bg[n - 2].y_latch += self.aff.bg[n - 2].pc >> 8; + } + fn drawBackround(self: *Self, comptime n: u3) void { // A Tile in a charblock is a byte, while a Screen Entry is a halfword const charblock_len: u32 = 0x4000; @@ -458,6 +466,9 @@ pub const Ppu = struct { cpu.handleInterrupt(); } + self.aff.bg[0].latchRefPoints(); + self.aff.bg[1].latchRefPoints(); + // See if Vblank DMA is present and not enabled pollBlankingDma(&cpu.bus, .VBlank); } @@ -656,33 +667,45 @@ const AffineBackground = struct { const AffineBackgroundRegisters = struct { const Self = @This(); - x: io.BackgroundRefPoint, - y: io.BackgroundRefPoint, + x: i32, + y: i32, - pa: io.BackgroundRotScaleParam, - pb: io.BackgroundRotScaleParam, - pc: io.BackgroundRotScaleParam, - pd: io.BackgroundRotScaleParam, + pa: i16, + pb: i16, + pc: i16, + pd: i16, + + x_latch: ?i32, + y_latch: ?i32, fn init() Self { return .{ - .x = .{ .raw = 0 }, - .y = .{ .raw = 0 }, - .pa = .{ .raw = 0 }, - .pb = .{ .raw = 0 }, - .pc = .{ .raw = 0 }, - .pd = .{ .raw = 0 }, + .x = 0, + .y = 0, + .pa = 0, + .pb = 0, + .pc = 0, + .pd = 0, + + .x_latch = null, + .y_latch = null, }; } pub fn writePaPb(self: *Self, value: u32) void { - self.pa.raw = @truncate(u16, value); - self.pb.raw = @truncate(u16, value >> 16); + self.pa = @bitCast(i16, @truncate(u16, value)); + self.pb = @bitCast(i16, @truncate(u16, value >> 16)); } pub fn writePcPd(self: *Self, value: u32) void { - self.pc.raw = @truncate(u16, value); - self.pd.raw = @truncate(u16, value >> 16); + self.pc = @bitCast(i16, @truncate(u16, value)); + self.pd = @bitCast(i16, @truncate(u16, value >> 16)); + } + + // Every Vblank BG?X/Y registers are latched + fn latchRefPoints(self: *Self) void { + self.x_latch = self.x; + self.y_latch = self.y; } };