diff --git a/src/core/nds9/io.zig b/src/core/nds9/io.zig index bd0dc63..6fe726b 100644 --- a/src/core/nds9/io.zig +++ b/src/core/nds9/io.zig @@ -78,7 +78,7 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T { // Timers 0x0400_0100...0x0400_010E => warn("TODO: impl timer", .{}), - 0x0400_0004 => bus.ppu.engines[0].dispstat.raw, + 0x0400_0004 => bus.ppu.io.nds9.dispstat.raw, 0x0400_0130 => bus.io.keyinput.load(.Monotonic), 0x0400_0180 => @truncate(bus.io.shr.ipc._nds9.sync.raw), diff --git a/src/core/ppu.zig b/src/core/ppu.zig index b50c10a..c85d1c1 100644 --- a/src/core/ppu.zig +++ b/src/core/ppu.zig @@ -23,10 +23,20 @@ pub const Ppu = struct { io: Io = .{}, - const Io = struct { - const types = @import("nds9/io.zig"); + pub const Io = struct { + const ty = @import("nds9/io.zig"); - powcnt: types.PowCnt = .{ .raw = 0x0000_0000 }, + nds9: struct { + dispstat: ty.Dispstat = .{ .raw = 0x0000_0000 }, + vcount: ty.Vcount = .{ .raw = 0x0000_0000 }, + } = .{}, + + nds7: struct { + dispstat: ty.Dispstat = .{ .raw = 0x0000_0000 }, + vcount: ty.Vcount = .{ .raw = 0x0000_0000 }, + } = .{}, + + powcnt: ty.PowCnt = .{ .raw = 0x0000_0000 }, }; pub fn init(allocator: Allocator, vram: *Vram) !@This() { @@ -42,22 +52,21 @@ pub const Ppu = struct { pub fn drawScanline(self: *@This(), bus: *System.Bus9) void { if (self.io.powcnt.engine2d_a.read()) - self.engines[0].drawScanline(bus, &self.fb, &self.io.powcnt); + self.engines[0].drawScanline(bus, &self.fb, &self.io); if (self.io.powcnt.engine2d_b.read()) - self.engines[1].drawScanline(bus, &self.fb, &self.io.powcnt); + self.engines[1].drawScanline(bus, &self.fb, &self.io); } /// HDraw -> HBlank pub fn onHdrawEnd(self: *@This(), scheduler: *Scheduler, late: u64) void { - inline for (&self.engines) |*engine| { - std.debug.assert(engine.dispstat.hblank.read() == false); - std.debug.assert(engine.dispstat.vblank.read() == false); + std.debug.assert(self.io.nds9.dispstat.hblank.read() == false); + std.debug.assert(self.io.nds9.dispstat.vblank.read() == false); - // TODO: Signal HBlank IRQ + self.io.nds9.dispstat.hblank.set(); + self.io.nds7.dispstat.hblank.set(); - engine.dispstat.hblank.set(); - } + // TODO: Signal HBlank IRQ const dots_in_hblank = 99; scheduler.push(.{ .nds9 = .hblank }, dots_in_hblank * cycles_per_dot -| late); @@ -65,14 +74,13 @@ pub const Ppu = struct { // VBlank -> HBlank (Still VBlank) pub fn onVblankEnd(self: *@This(), scheduler: *Scheduler, late: u64) void { - inline for (&self.engines) |*engine| { - std.debug.assert(!engine.dispstat.hblank.read()); - std.debug.assert(engine.vcount.scanline.read() == 262 or engine.dispstat.vblank.read()); + std.debug.assert(!self.io.nds9.dispstat.hblank.read()); + std.debug.assert(self.io.nds9.vcount.scanline.read() == 262 or self.io.nds9.dispstat.vblank.read()); - // TODO: Signal HBlank IRQ + self.io.nds9.dispstat.hblank.set(); + self.io.nds7.dispstat.hblank.set(); - engine.dispstat.hblank.set(); - } + // TODO: Signal HBlank IRQ const dots_in_hblank = 99; scheduler.push(.{ .nds9 = .hblank }, dots_in_hblank * cycles_per_dot -| late); @@ -82,28 +90,29 @@ pub const Ppu = struct { pub fn onHblankEnd(self: *@This(), scheduler: *Scheduler, late: u64) void { const scanline_total = 263; // 192 visible, 71 blanking - std.debug.assert(self.engines[0].vcount.scanline.read() == self.engines[1].vcount.scanline.read()); + const prev_scanline = self.io.nds9.vcount.scanline.read(); + const scanline = (prev_scanline + 1) % scanline_total; - inline for (&self.engines) |*engine| { - const prev_scanline = engine.vcount.scanline.read(); - const scanline = (prev_scanline + 1) % scanline_total; + self.io.nds9.vcount.scanline.write(scanline); + self.io.nds7.vcount.scanline.write(scanline); - engine.vcount.scanline.write(scanline); - engine.dispstat.hblank.unset(); + self.io.nds9.dispstat.hblank.unset(); + self.io.nds7.dispstat.hblank.unset(); - const coincidence = scanline == engine.dispstat.lyc.read(); - engine.dispstat.coincidence.write(coincidence); + { + const coincidence = scanline == self.io.nds9.dispstat.lyc.read(); + self.io.nds9.dispstat.coincidence.write(coincidence); + } + { + const coincidence = scanline == self.io.nds7.dispstat.lyc.read(); + self.io.nds7.dispstat.coincidence.write(coincidence); } - - const scanline = self.engines[0].vcount.scanline.read(); // TODO: LYC == LY IRQ if (scanline < 192) { - inline for (&self.engines) |*engine| { - std.debug.assert(engine.dispstat.vblank.read() == false); - std.debug.assert(engine.dispstat.hblank.read() == false); - } + std.debug.assert(self.io.nds9.dispstat.vblank.read() == false); + std.debug.assert(self.io.nds9.dispstat.hblank.read() == false); // Draw Another Scanline const dots_in_hdraw = 256; @@ -114,17 +123,17 @@ pub const Ppu = struct { // Transition from Hblank to Vblank self.fb.swap(); - inline for (&self.engines) |*engine| - engine.dispstat.vblank.set(); + self.io.nds9.dispstat.vblank.set(); + self.io.nds7.dispstat.vblank.set(); // TODO: Signal VBlank IRQ } if (scanline == 262) { - inline for (&self.engines) |*engine| { - engine.dispstat.vblank.unset(); - std.debug.assert(engine.dispstat.vblank.read() == (scanline != 262)); - } + self.io.nds9.dispstat.vblank.unset(); + self.io.nds7.dispstat.vblank.unset(); + + std.debug.assert(self.io.nds9.dispstat.vblank.read() == (scanline != 262)); } const dots_in_vblank = 256; diff --git a/src/core/ppu/engine.zig b/src/core/ppu/engine.zig index ab25cb5..3be65b6 100644 --- a/src/core/ppu/engine.zig +++ b/src/core/ppu/engine.zig @@ -6,10 +6,7 @@ const FrameBuffer = @import("../ppu.zig").FrameBuffer; const DispcntA = @import("../nds9/io.zig").DispcntA; const DispcntB = @import("../nds9/io.zig").DispcntB; -const Dispstat = @import("../nds9/io.zig").Dispstat; -const Vcount = @import("../nds9/io.zig").Vcount; - -const PowCnt = @import("../nds9/io.zig").PowCnt; +const Ppu = @import("../ppu.zig").Ppu; const width = @import("../ppu.zig").screen_width; const height = @import("../ppu.zig").screen_height; @@ -32,17 +29,15 @@ fn Engine(comptime kind: EngineKind) type { return struct { dispcnt: Type(DispcntA, DispcntB) = .{ .raw = 0x0000_0000 }, - dispstat: Dispstat = .{ .raw = 0x0000_0000 }, - vcount: Vcount = .{ .raw = 0x0000_0000 }, - pub fn drawScanline(self: *@This(), bus: *Bus, fb: *FrameBuffer, powcnt: *PowCnt) void { + pub fn drawScanline(self: *@This(), bus: *Bus, fb: *FrameBuffer, io: *Ppu.Io) void { const disp_mode = self.dispcnt.display_mode.read(); switch (disp_mode) { 0 => { // Display Off const buf = switch (kind) { - .a => if (powcnt.display_swap.read()) fb.top(.back) else fb.btm(.back), - .b => if (powcnt.display_swap.read()) fb.btm(.back) else fb.top(.back), + .a => if (io.powcnt.display_swap.read()) fb.top(.back) else fb.btm(.back), + .b => if (io.powcnt.display_swap.read()) fb.btm(.back) else fb.top(.back), }; @memset(buf, 0xFF); // set everything to white @@ -52,8 +47,8 @@ fn Engine(comptime kind: EngineKind) type { if (kind == .b) return; // TODO: Master Brightness can still affect this mode - const scanline: u32 = self.vcount.scanline.read(); - const buf = if (powcnt.display_swap.read()) fb.top(.back) else fb.btm(.back); + const scanline: u32 = io.nds9.vcount.scanline.read(); + const buf = if (io.powcnt.display_swap.read()) fb.top(.back) else fb.btm(.back); const scanline_buf = blk: { const rgba_ptr: *[width * height]u32 = @ptrCast(@alignCast(buf));