fix(ppu): engines don't have unique vcount + dispstat (cpus do)
This commit is contained in:
		@@ -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),
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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));
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user