diff --git a/src/bus/io.zig b/src/bus/io.zig index 54044e9..b20bbbc 100644 --- a/src/bus/io.zig +++ b/src/bus/io.zig @@ -5,13 +5,15 @@ const Bitfield = bitfield.Bitfield; const Bit = bitfield.Bit; pub const Io = struct { - dispcnt: Dispcnt, - dispstat: Dispstat, + dispcnt: DispCnt, + dispstat: DispStat, + vcount: VCount, pub fn init() @This() { return .{ .dispcnt = .{ .raw = 0x0000_0000 }, .dispstat = .{ .raw = 0x0000_0000 }, + .vcount = .{ .raw = 0x0000_0000 }, }; } @@ -48,7 +50,7 @@ pub const Io = struct { } }; -const Dispcnt = extern union { +const DispCnt = extern union { bg_mode: Bitfield(u16, 0, 3), frame_select: Bit(u16, 4), hblank_interraw_free: Bit(u16, 5), @@ -61,7 +63,7 @@ const Dispcnt = extern union { raw: u16, }; -const Dispstat = extern union { +const DispStat = extern union { vblank: Bit(u16, 0), hblank: Bit(u16, 1), vcount: Bit(u16, 2), @@ -71,3 +73,8 @@ const Dispstat = extern union { vcount_setting: Bitfield(u16, 8, 7), raw: u16, }; + +const VCount = extern union { + scanline: Bitfield(u16, 0, 8), + raw: u16, +}; diff --git a/src/ppu.zig b/src/ppu.zig index fcd85c1..c841779 100644 --- a/src/ppu.zig +++ b/src/ppu.zig @@ -2,6 +2,7 @@ const std = @import("std"); const Allocator = std.mem.Allocator; const Scheduler = @import("scheduler.zig").Scheduler; +const EventKind = @import("scheduler.zig").EventKind; pub const Ppu = struct { vram: Vram, @@ -9,6 +10,9 @@ pub const Ppu = struct { sched: *Scheduler, pub fn init(alloc: Allocator, sched: *Scheduler) !@This() { + // Queue first Hblank + sched.push(.{ .kind = .HBlank, .tick = sched.tick + 240 * 4 }); + return @This(){ .vram = try Vram.init(alloc), .palette = try Palette.init(alloc), diff --git a/src/scheduler.zig b/src/scheduler.zig index fc4d38c..58d16d3 100644 --- a/src/scheduler.zig +++ b/src/scheduler.zig @@ -25,7 +25,7 @@ pub const Scheduler = struct { self.queue.deinit(); } - pub fn handleEvent(self: *@This(), _: *Arm7tdmi, _: *Bus) void { + pub fn handleEvent(self: *@This(), _: *Arm7tdmi, bus: *Bus) void { const should_handle = if (self.queue.peek()) |e| self.tick >= e.tick else false; if (should_handle) { @@ -36,15 +36,55 @@ pub const Scheduler = struct { std.debug.panic("[Scheduler] Somehow, a u64 overflowed", .{}); }, .HBlank => { - std.debug.panic("[Scheduler] tick {}: Hblank", .{self.tick}); + std.log.debug("[Scheduler] tick {}: Hblank", .{self.tick}); + + // We've reached the end of a scanline + const scanline = bus.io.vcount.scanline.read(); + bus.io.vcount.scanline.write(scanline + 1); + + bus.io.dispstat.hblank.set(); + + if (scanline < 160) { + self.push(.{ .kind = .Visible, .tick = self.tick + (68 * 4) }); + } else { + self.push(.{ .kind = .VBlank, .tick = self.tick + (68 * 4) }); + } + }, + .Visible => { + std.log.debug("[Scheduler] tick {}: Visible", .{self.tick}); + + // Beginning of a Scanline + bus.io.dispstat.hblank.unset(); + bus.io.dispstat.vblank.unset(); + + self.push(.{ .kind = .HBlank, .tick = self.tick + (240 * 4) }); }, .VBlank => { - std.debug.panic("[Scheduler] tick {}: VBlank", .{self.tick}); + std.log.debug("[Scheduler] tick {}: VBlank", .{self.tick}); + + // Beginning of a Scanline, not visible though + bus.io.dispstat.hblank.unset(); + bus.io.dispstat.vblank.set(); + + const scanline = bus.io.vcount.scanline.read(); + bus.io.vcount.scanline.write(scanline + 1); + + if (scanline < 227) { + // Another Vblank Scanline + self.push(.{ .kind = .VBlank, .tick = self.tick + 68 * (308 * 4) }); + } else { + bus.io.vcount.scanline.write(0); // Reset Scanline + self.push(.{ .kind = .Visible, .tick = self.tick + 68 * (308 * 4) }); + } }, } } } + pub inline fn push(self: *@This(), event: Event) void { + self.queue.add(event) catch unreachable; + } + pub inline fn nextTimestamp(self: *@This()) u64 { if (self.queue.peek()) |e| { return e.tick; @@ -65,4 +105,5 @@ pub const EventKind = enum { HeatDeath, HBlank, VBlank, + Visible, };