From 9dcecc0d58fa63d138052ce66fa354b66a9e2021 Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Fri, 21 Oct 2022 05:12:27 -0300 Subject: [PATCH] fix: move code in scheduler to ppu --- src/ppu.zig | 55 +++++++++++++++++++++++++++++ src/scheduler.zig | 90 +++++------------------------------------------ 2 files changed, 63 insertions(+), 82 deletions(-) diff --git a/src/ppu.zig b/src/ppu.zig index 8b247be..6071d6a 100644 --- a/src/ppu.zig +++ b/src/ppu.zig @@ -3,12 +3,14 @@ const io = @import("bus/io.zig"); const EventKind = @import("scheduler.zig").EventKind; const Scheduler = @import("scheduler.zig").Scheduler; +const Arm7tdmi = @import("cpu.zig").Arm7tdmi; const Bit = @import("bitfield").Bit; const Bitfield = @import("bitfield").Bitfield; const Allocator = std.mem.Allocator; const log = std.log.scoped(.PPU); +const pollBlankingDma = @import("bus/dma.zig").pollBlankingDma; pub const width = 240; pub const height = 160; @@ -351,6 +353,59 @@ pub const Ppu = struct { }, }; } + + pub fn handleHDrawEnd(self: *Self, cpu: *Arm7tdmi) void { + // Transitioning to a Hblank + if (self.dispstat.hblank_irq.read()) { + cpu.bus.io.irq.hblank.set(); + cpu.handleInterrupt(); + } + + // See if HBlank DMA is present and not enabled + pollBlankingDma(cpu.bus, .HBlank); + + self.dispstat.hblank.set(); + self.sched.push(.HBlank, self.sched.now() + (68 * 4)); + } + + pub fn handleHBlankEnd(self: *Self, cpu: *Arm7tdmi) void { + // The End of a Hblank (During Draw or Vblank) + const old_scanline = self.vcount.scanline.read(); + const scanline = (old_scanline + 1) % 228; + + self.vcount.scanline.write(scanline); + self.dispstat.hblank.unset(); + + // Perform Vc == VcT check + const coincidence = scanline == self.dispstat.vcount_trigger.read(); + self.dispstat.coincidence.write(coincidence); + + if (coincidence and self.dispstat.vcount_irq.read()) { + cpu.bus.io.irq.coincidence.set(); + cpu.handleInterrupt(); + } + + if (scanline < 160) { + // Transitioning to another Draw + self.sched.push(.Draw, self.sched.now() + (240 * 4)); + } else { + // Transitioning to a Vblank + if (scanline == 160) { + self.dispstat.vblank.set(); + + if (self.dispstat.vblank_irq.read()) { + cpu.bus.io.irq.vblank.set(); + cpu.handleInterrupt(); + } + + // See if Vblank DMA is present and not enabled + pollBlankingDma(cpu.bus, .VBlank); + } + + if (scanline == 227) self.dispstat.vblank.unset(); + self.sched.push(.VBlank, self.sched.now() + (240 * 4)); + } + } }; const Palette = struct { diff --git a/src/scheduler.zig b/src/scheduler.zig index 4a17e08..1239e9e 100644 --- a/src/scheduler.zig +++ b/src/scheduler.zig @@ -1,7 +1,5 @@ const std = @import("std"); -const pollBlankingDma = @import("bus/dma.zig").pollBlankingDma; - const Bus = @import("Bus.zig"); const Arm7tdmi = @import("cpu.zig").Arm7tdmi; @@ -32,92 +30,18 @@ pub const Scheduler = struct { } pub fn handleEvent(self: *Self, cpu: *Arm7tdmi, bus: *Bus) void { - const should_handle = if (self.queue.peek()) |e| self.tick >= e.tick else false; - const stat = &bus.ppu.dispstat; - const vcount = &bus.ppu.vcount; - const irq = &bus.io.irq; - - if (should_handle) { - const event = self.queue.remove(); - // log.debug("Handle {} @ tick = {}", .{ event.kind, self.tick }); - + if (self.queue.removeOrNull()) |event| { switch (event.kind) { .HeatDeath => { log.err("A u64 overflowered. This *actually* should never happen.", .{}); unreachable; }, - .HBlank => { - // The End of a Hblank (During Draw or Vblank) - const old_scanline = vcount.scanline.read(); - const scanline = (old_scanline + 1) % 228; - - vcount.scanline.write(scanline); - stat.hblank.unset(); - - // Perform Vc == VcT check - const coincidence = scanline == stat.vcount_trigger.read(); - stat.coincidence.write(coincidence); - - if (coincidence and stat.vcount_irq.read()) { - irq.coincidence.set(); - cpu.handleInterrupt(); - } - - if (scanline < 160) { - // Transitioning to another Draw - self.push(.Draw, self.tick + (240 * 4)); - } else { - // Transitioning to a Vblank - if (scanline == 160) { - stat.vblank.set(); - - if (stat.vblank_irq.read()) { - irq.vblank.set(); - cpu.handleInterrupt(); - } - - // See if Vblank DMA is present and not enabled - pollBlankingDma(bus, .VBlank); - } - - if (scanline == 227) stat.vblank.unset(); - self.push(.VBlank, self.tick + (240 * 4)); - } - }, .Draw => { - // The end of a Draw + // The end of a VDraw bus.ppu.drawScanline(); - - // Transitioning to a Hblank - if (bus.ppu.dispstat.hblank_irq.read()) { - bus.io.irq.hblank.set(); - cpu.handleInterrupt(); - } - - // See if Hblank DMA is present and not enabled - pollBlankingDma(bus, .HBlank); - - bus.ppu.dispstat.hblank.set(); - self.push(.HBlank, self.tick + (68 * 4)); - }, - .VBlank => { - // The end of a Vblank - - // Transitioning to a Hblank - if (bus.ppu.dispstat.hblank_irq.read()) { - bus.io.irq.hblank.set(); - cpu.handleInterrupt(); - } - - // See if Hblank DMA is present and not enabled - pollBlankingDma(bus, .HBlank); - - bus.ppu.dispstat.hblank.set(); - self.push(.HBlank, self.tick + (68 * 4)); + bus.ppu.handleHDrawEnd(cpu); }, .TimerOverflow => |id| { - // log.warn("TIM{} Overflowed", .{id}); - switch (id) { 0 => bus.io.tim0.handleOverflow(cpu, &bus.io), 1 => bus.io.tim1.handleOverflow(cpu, &bus.io), @@ -125,6 +49,8 @@ pub const Scheduler = struct { 3 => bus.io.tim3.handleOverflow(cpu, &bus.io), } }, + .HBlank => bus.ppu.handleHBlankEnd(cpu), // The end of a HBlank + .VBlank => bus.ppu.handleHDrawEnd(cpu), // The end of a VBlank } } } @@ -153,9 +79,9 @@ pub const Scheduler = struct { } pub fn nextTimestamp(self: *Self) u64 { - if (self.queue.peek()) |e| { - return e.tick; - } else unreachable; + if (self.queue.peek()) |e| return e.tick; + + unreachable; // There's always the HeatDeath event scheduled } };