From c100d64fcbfa3ff0ed33e16bbc91eb886ce698cb Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Sat, 9 Apr 2022 19:15:12 -0300 Subject: [PATCH] chore: tick scheduler on memory access --- src/Bus.zig | 6 +++++- src/bus/timer.zig | 22 ++++++++-------------- src/cpu.zig | 11 ++++++----- src/emu.zig | 3 +-- src/ppu.zig | 10 +++++----- src/scheduler.zig | 16 +++++++++------- 6 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/Bus.zig b/src/Bus.zig index 181d6e3..c428fdf 100644 --- a/src/Bus.zig +++ b/src/Bus.zig @@ -29,9 +29,10 @@ dma: DmaControllers, tim: Timers, iwram: Iwram, ewram: Ewram, - io: Io, +sched: *Scheduler, + pub fn init(alloc: Allocator, sched: *Scheduler, rom_path: []const u8, bios_path: ?[]const u8, save_path: ?[]const u8) !Self { return Self{ .pak = try GamePak.init(alloc, rom_path, save_path), @@ -43,6 +44,7 @@ pub fn init(alloc: Allocator, sched: *Scheduler, rom_path: []const u8, bios_path .dma = DmaControllers.init(), .tim = Timers.init(sched), .io = Io.init(), + .sched = sched, }; } @@ -57,6 +59,7 @@ pub fn deinit(self: Self) void { pub fn read(self: *const Self, comptime T: type, address: u32) T { const page = @truncate(u8, address >> 24); const align_addr = alignAddress(T, address); + self.sched.tick += 1; return switch (page) { // General Internal Memory @@ -91,6 +94,7 @@ pub fn read(self: *const Self, comptime T: type, address: u32) T { pub fn write(self: *Self, comptime T: type, address: u32, value: T) void { const page = @truncate(u8, address >> 24); const align_addr = alignAddress(T, address); + self.sched.tick += 1; switch (page) { // General Internal Memory diff --git a/src/bus/timer.zig b/src/bus/timer.zig index d57a34e..14c07c9 100644 --- a/src/bus/timer.zig +++ b/src/bus/timer.zig @@ -81,13 +81,13 @@ fn Timer(comptime id: u2) type { // Reload on Rising edge self._counter = self._reload; - if (!new.cascade.read()) self.scheduleOverflow(); + if (!new.cascade.read()) self.scheduleOverflow(0); } self.cnt.raw = halfword; } - pub fn handleOverflow(self: *Self, cpu: *Arm7tdmi) void { + pub fn handleOverflow(self: *Self, cpu: *Arm7tdmi, late: u64) void { // Fire IRQ if enabled const io = &cpu.bus.io; const tim = &cpu.bus.tim; @@ -107,21 +107,15 @@ fn Timer(comptime id: u2) type { switch (id) { 0 => if (tim._1.cnt.cascade.read()) { tim._1._counter +%= 1; - - if (tim._1._counter == 0) - tim._1.handleOverflow(cpu); + if (tim._1._counter == 0) tim._1.handleOverflow(cpu, late); }, 1 => if (tim._2.cnt.cascade.read()) { tim._2._counter +%= 1; - - if (tim._2._counter == 0) - tim._2.handleOverflow(cpu); + if (tim._2._counter == 0) tim._2.handleOverflow(cpu, late); }, 2 => if (tim._3.cnt.cascade.read()) { tim._3._counter +%= 1; - - if (tim._3._counter == 0) - tim._3.handleOverflow(cpu); + if (tim._3._counter == 0) tim._3.handleOverflow(cpu, late); }, 3 => {}, // There is no Timer for TIM3 to "cascade" to, } @@ -129,15 +123,15 @@ fn Timer(comptime id: u2) type { // Reschedule Timer if we're not cascading if (!self.cnt.cascade.read()) { self._counter = self._reload; - self.scheduleOverflow(); + self.scheduleOverflow(late); } } - fn scheduleOverflow(self: *Self) void { + fn scheduleOverflow(self: *Self, late: u64) void { const when = (@as(u64, 0x10000) - self._counter) * self.frequency(); self._start_timestamp = self.sched.now(); - self.sched.push(.{ .TimerOverflow = id }, self.sched.now() + when); + self.sched.push(.{ .TimerOverflow = id }, self.sched.now() + when - late); } fn frequency(self: *const Self) u16 { diff --git a/src/cpu.zig b/src/cpu.zig index a288664..4f910bc 100644 --- a/src/cpu.zig +++ b/src/cpu.zig @@ -245,12 +245,15 @@ pub const Arm7tdmi = struct { self.cpsr.raw = 0x6000001F; } - pub fn step(self: *Self) u64 { + pub fn step(self: *Self) void { // If we're processing a DMA (not Sound or Blanking) the CPU is disabled - if (self.handleDMATransfers()) return 1; + if (self.handleDMATransfers()) return; // If we're halted, the cpu is disabled - if (self.bus.io.haltcnt == .Halt) return 1; + if (self.bus.io.haltcnt == .Halt) { + self.sched.tick += 1; + return; + } if (self.cpsr.t.read()) { const opcode = self.thumbFetch(); @@ -265,8 +268,6 @@ pub const Arm7tdmi = struct { arm_lut[armIdx(opcode)](self, self.bus, opcode); } } - - return 1; } pub fn handleInterrupt(self: *Self) void { diff --git a/src/emu.zig b/src/emu.zig index 74db05d..58fecbf 100644 --- a/src/emu.zig +++ b/src/emu.zig @@ -46,8 +46,7 @@ pub fn runFrame(sched: *Scheduler, cpu: *Arm7tdmi, bus: *Bus) void { const frame_end = sched.tick + cycles_per_frame; while (sched.tick < frame_end) { - sched.tick += 1; - _ = cpu.step(); + cpu.step(); while (sched.tick >= sched.nextTimestamp()) { sched.handleEvent(cpu, bus); diff --git a/src/ppu.zig b/src/ppu.zig index 0d708d8..be8c039 100644 --- a/src/ppu.zig +++ b/src/ppu.zig @@ -358,7 +358,7 @@ pub const Ppu = struct { }; } - pub fn handleHDrawEnd(self: *Self, cpu: *Arm7tdmi) void { + pub fn handleHDrawEnd(self: *Self, cpu: *Arm7tdmi, late: u64) void { // Transitioning to a Hblank if (self.dispstat.hblank_irq.read()) { cpu.bus.io.irq.hblank.set(); @@ -369,10 +369,10 @@ pub const Ppu = struct { pollBlankingDma(cpu.bus, .HBlank); self.dispstat.hblank.set(); - self.sched.push(.HBlank, self.sched.now() + (68 * 4)); + self.sched.push(.HBlank, self.sched.now() + (68 * 4) - late); } - pub fn handleHBlankEnd(self: *Self, cpu: *Arm7tdmi) void { + pub fn handleHBlankEnd(self: *Self, cpu: *Arm7tdmi, late: u64) void { // The End of a Hblank (During Draw or Vblank) const old_scanline = self.vcount.scanline.read(); const scanline = (old_scanline + 1) % 228; @@ -391,7 +391,7 @@ pub const Ppu = struct { if (scanline < 160) { // Transitioning to another Draw - self.sched.push(.Draw, self.sched.now() + (240 * 4)); + self.sched.push(.Draw, self.sched.now() + (240 * 4) - late); } else { // Transitioning to a Vblank if (scanline == 160) { @@ -407,7 +407,7 @@ pub const Ppu = struct { } if (scanline == 227) self.dispstat.vblank.unset(); - self.sched.push(.VBlank, self.sched.now() + (240 * 4)); + self.sched.push(.VBlank, self.sched.now() + (240 * 4) - late); } } }; diff --git a/src/scheduler.zig b/src/scheduler.zig index 52f43b8..a586fba 100644 --- a/src/scheduler.zig +++ b/src/scheduler.zig @@ -31,6 +31,8 @@ pub const Scheduler = struct { pub fn handleEvent(self: *Self, cpu: *Arm7tdmi, bus: *Bus) void { if (self.queue.removeOrNull()) |event| { + const late = self.tick - event.tick; + switch (event.kind) { .HeatDeath => { log.err("A u64 overflowered. This *actually* should never happen.", .{}); @@ -39,18 +41,18 @@ pub const Scheduler = struct { .Draw => { // The end of a VDraw bus.ppu.drawScanline(); - bus.ppu.handleHDrawEnd(cpu); + bus.ppu.handleHDrawEnd(cpu, late); }, .TimerOverflow => |id| { switch (id) { - 0 => bus.tim._0.handleOverflow(cpu), - 1 => bus.tim._1.handleOverflow(cpu), - 2 => bus.tim._2.handleOverflow(cpu), - 3 => bus.tim._3.handleOverflow(cpu), + 0 => bus.tim._0.handleOverflow(cpu, late), + 1 => bus.tim._1.handleOverflow(cpu, late), + 2 => bus.tim._2.handleOverflow(cpu, late), + 3 => bus.tim._3.handleOverflow(cpu, late), } }, - .HBlank => bus.ppu.handleHBlankEnd(cpu), // The end of a HBlank - .VBlank => bus.ppu.handleHDrawEnd(cpu), // The end of a VBlank + .HBlank => bus.ppu.handleHBlankEnd(cpu, late), // The end of a HBlank + .VBlank => bus.ppu.handleHDrawEnd(cpu, late), // The end of a VBlank } } }