Compare commits

..

No commits in common. "a590048204dfba58728114eab6947c04b54a81e9" and "dfe94fb9316be87ed57ab2a2c5702b8d0152e2e9" have entirely different histories.

12 changed files with 81 additions and 118 deletions

View File

@ -1,7 +1,6 @@
const std = @import("std"); const std = @import("std");
const AudioDeviceId = @import("sdl2").SDL_AudioDeviceID; const AudioDeviceId = @import("sdl2").SDL_AudioDeviceID;
const Arm7tdmi = @import("cpu.zig").Arm7tdmi;
const Bios = @import("bus/Bios.zig"); const Bios = @import("bus/Bios.zig");
const Ewram = @import("bus/Ewram.zig"); const Ewram = @import("bus/Ewram.zig");
const GamePak = @import("bus/GamePak.zig"); const GamePak = @import("bus/GamePak.zig");
@ -19,6 +18,7 @@ const Allocator = std.mem.Allocator;
const log = std.log.scoped(.Bus); const log = std.log.scoped(.Bus);
const rotr = @import("util.zig").rotr; const rotr = @import("util.zig").rotr;
const Self = @This(); const Self = @This();
const panic_on_und_bus: bool = false; const panic_on_und_bus: bool = false;
@ -33,21 +33,19 @@ iwram: Iwram,
ewram: Ewram, ewram: Ewram,
io: Io, io: Io,
cpu: ?*Arm7tdmi,
sched: *Scheduler, sched: *Scheduler,
pub fn init(alloc: Allocator, sched: *Scheduler, paths: FilePaths) !Self { pub fn init(alloc: Allocator, sched: *Scheduler, dev: AudioDeviceId, paths: FilePaths) !Self {
return Self{ return Self{
.pak = try GamePak.init(alloc, paths.rom, paths.save), .pak = try GamePak.init(alloc, paths.rom, paths.save),
.bios = try Bios.init(alloc, paths.bios), .bios = try Bios.init(alloc, paths.bios),
.ppu = try Ppu.init(alloc, sched), .ppu = try Ppu.init(alloc, sched),
.apu = Apu.init(), .apu = Apu.init(dev),
.iwram = try Iwram.init(alloc), .iwram = try Iwram.init(alloc),
.ewram = try Ewram.init(alloc), .ewram = try Ewram.init(alloc),
.dma = DmaControllers.init(), .dma = DmaControllers.init(),
.tim = Timers.init(sched), .tim = Timers.init(sched),
.io = Io.init(), .io = Io.init(),
.cpu = null,
.sched = sched, .sched = sched,
}; };
} }
@ -76,29 +74,6 @@ fn isDmaRunning(self: *const Self) bool {
self.dma._3.active; self.dma._3.active;
} }
pub fn debugRead(self: *const Self, comptime T: type, address: u32) T {
const cached = self.sched.tick;
defer self.sched.tick = cached;
return self.read(T, address);
}
fn readOpenBus(self: *const Self, comptime T: type, address: u32) T {
if (self.cpu.?.cpsr.t.read()) {
log.err("TODO: {} open bus read in THUMB", .{T});
return 0;
}
const word = self.debugRead(u32, self.cpu.?.r[15] + 4);
return @truncate(T, rotr(u32, word, 8 * (address & 3)));
}
fn readBios(self: *const Self, comptime T: type, address: u32) T {
if (address < Bios.size) return self.bios.read(T, alignAddress(T, address));
return self.readOpenBus(T, address);
}
pub fn read(self: *const Self, comptime T: type, address: u32) T { pub fn read(self: *const Self, comptime T: type, address: u32) T {
const page = @truncate(u8, address >> 24); const page = @truncate(u8, address >> 24);
const align_addr = alignAddress(T, address); const align_addr = alignAddress(T, address);
@ -106,7 +81,7 @@ pub fn read(self: *const Self, comptime T: type, address: u32) T {
return switch (page) { return switch (page) {
// General Internal Memory // General Internal Memory
0x00 => self.readBios(T, address), 0x00 => self.bios.read(T, align_addr),
0x02 => self.ewram.read(T, align_addr), 0x02 => self.ewram.read(T, align_addr),
0x03 => self.iwram.read(T, align_addr), 0x03 => self.iwram.read(T, align_addr),
0x04 => io.read(self, T, align_addr), 0x04 => io.read(self, T, align_addr),
@ -130,7 +105,7 @@ pub fn read(self: *const Self, comptime T: type, address: u32) T {
break :blk @as(T, value) * multiplier; break :blk @as(T, value) * multiplier;
}, },
else => readOpenBus(self, T, address), else => undRead("Tried to read {} from 0x{X:0>8}", .{ T, address }),
}; };
} }

View File

@ -24,9 +24,9 @@ pub const Apu = struct {
dma_cnt: io.DmaSoundControl, dma_cnt: io.DmaSoundControl,
cnt: io.SoundControl, cnt: io.SoundControl,
dev: ?AudioDeviceId, dev: AudioDeviceId,
pub fn init() Self { pub fn init(dev: AudioDeviceId) Self {
return .{ return .{
.ch1 = ToneSweep.init(), .ch1 = ToneSweep.init(),
.ch2 = Tone.init(), .ch2 = Tone.init(),
@ -40,14 +40,10 @@ pub const Apu = struct {
.cnt = .{ .raw = 0 }, .cnt = .{ .raw = 0 },
.bias = .{ .raw = 0x0200 }, .bias = .{ .raw = 0x0200 },
.dev = null, .dev = dev,
}; };
} }
pub fn attachAudioDevice(self: *Self, dev: AudioDeviceId) void {
self.dev = dev;
}
pub fn setDmaCnt(self: *Self, value: u16) void { pub fn setDmaCnt(self: *Self, value: u16) void {
const new: io.DmaSoundControl = .{ .raw = value }; const new: io.DmaSoundControl = .{ .raw = value };
@ -87,7 +83,7 @@ pub const Apu = struct {
}, },
}; };
if (self.dev) |dev| _ = SDL.SDL_QueueAudio(dev, &samples, 2); _ = SDL.SDL_QueueAudio(self.dev, &samples, 2);
} }
}; };

View File

@ -2,9 +2,6 @@ const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const log = std.log.scoped(.Bios); const log = std.log.scoped(.Bios);
/// Size of the BIOS in bytes
pub const size = 0x4000;
const Self = @This(); const Self = @This();
buf: ?[]u8, buf: ?[]u8,

View File

@ -28,6 +28,7 @@ pub fn init(alloc: Allocator, rom_path: []const u8, save_path: ?[]const u8) !Sel
.backup = try Backup.init(alloc, kind, title, save_path), .backup = try Backup.init(alloc, kind, title, save_path),
}; };
pak.parseHeader(); pak.parseHeader();
log.info("Backup: {}", .{kind});
return pak; return pak;
} }

View File

@ -27,8 +27,6 @@ pub const Backup = struct {
flash: Flash, flash: Flash,
pub fn init(alloc: Allocator, kind: BackupKind, title: [12]u8, path: ?[]const u8) !Self { pub fn init(alloc: Allocator, kind: BackupKind, title: [12]u8, path: ?[]const u8) !Self {
log.info("Kind: {}", .{kind});
const buf_size: usize = switch (kind) { const buf_size: usize = switch (kind) {
.Sram => 0x8000, // 32K .Sram => 0x8000, // 32K
.Flash => 0x10000, // 64K .Flash => 0x10000, // 64K

View File

@ -5,9 +5,7 @@ const Bus = @import("Bus.zig");
const Bit = @import("bitfield").Bit; const Bit = @import("bitfield").Bit;
const Bitfield = @import("bitfield").Bitfield; const Bitfield = @import("bitfield").Bitfield;
const Scheduler = @import("scheduler.zig").Scheduler; const Scheduler = @import("scheduler.zig").Scheduler;
const FilePaths = @import("util.zig").FilePaths;
const Allocator = std.mem.Allocator;
const File = std.fs.File; const File = std.fs.File;
// ARM Instruction Groups // ARM Instruction Groups
@ -61,7 +59,7 @@ pub const Arm7tdmi = struct {
r: [16]u32, r: [16]u32,
sched: *Scheduler, sched: *Scheduler,
bus: Bus, bus: *Bus,
cpsr: PSR, cpsr: PSR,
spsr: PSR, spsr: PSR,
@ -79,11 +77,11 @@ pub const Arm7tdmi = struct {
log_buf: [0x100]u8, log_buf: [0x100]u8,
binary_log: bool, binary_log: bool,
pub fn init(alloc: Allocator, sched: *Scheduler, paths: FilePaths) !Self { pub fn init(sched: *Scheduler, bus: *Bus) Self {
var cpu: Arm7tdmi = .{ return .{
.r = [_]u32{0x00} ** 16, .r = [_]u32{0x00} ** 16,
.sched = sched, .sched = sched,
.bus = try Bus.init(alloc, sched, paths), .bus = bus,
.cpsr = .{ .raw = 0x0000_001F }, .cpsr = .{ .raw = 0x0000_001F },
.spsr = .{ .raw = 0x0000_0000 }, .spsr = .{ .raw = 0x0000_0000 },
.banked_fiq = [_]u32{0x00} ** 10, .banked_fiq = [_]u32{0x00} ** 10,
@ -93,12 +91,6 @@ pub const Arm7tdmi = struct {
.log_buf = undefined, .log_buf = undefined,
.binary_log = false, .binary_log = false,
}; };
cpu.bus.cpu = &cpu;
return cpu;
}
pub fn deinit(self: Self) void {
self.bus.deinit();
} }
pub fn useLogger(self: *Self, file: *const File, is_binary: bool) void { pub fn useLogger(self: *Self, file: *const File, is_binary: bool) void {
@ -258,13 +250,13 @@ pub const Arm7tdmi = struct {
const opcode = self.thumbFetch(); const opcode = self.thumbFetch();
if (enable_logging) if (self.log_file) |file| self.debug_log(file, opcode); if (enable_logging) if (self.log_file) |file| self.debug_log(file, opcode);
thumb_lut[thumbIdx(opcode)](self, &self.bus, opcode); thumb_lut[thumbIdx(opcode)](self, self.bus, opcode);
} else { } else {
const opcode = self.fetch(); const opcode = self.fetch();
if (enable_logging) if (self.log_file) |file| self.debug_log(file, opcode); if (enable_logging) if (self.log_file) |file| self.debug_log(file, opcode);
if (checkCond(self.cpsr, @truncate(u4, opcode >> 28))) { if (checkCond(self.cpsr, @truncate(u4, opcode >> 28))) {
arm_lut[armIdx(opcode)](self, &self.bus, opcode); arm_lut[armIdx(opcode)](self, self.bus, opcode);
} }
} }
} }

View File

@ -47,11 +47,13 @@ pub fn halfAndSignedDataTransfer(comptime P: bool, comptime U: bool, comptime I:
}, },
0b11 => { 0b11 => {
// LDRSH // LDRSH
result = if (address & 1 == 1) blk: { const value = if (address & 1 == 1) blk: {
break :blk sext(8, bus.read(u8, address)); break :blk sext(8, bus.read(u8, address));
} else blk: { } else blk: {
break :blk sext(16, bus.read(u16, address)); break :blk sext(16, bus.read(u16, address));
}; };
result = rotr(u32, value, 8 * (address & 1));
}, },
0b00 => unreachable, // SWP 0b00 => unreachable, // SWP
} }

View File

@ -45,11 +45,13 @@ pub fn format78(comptime op: u2, comptime T: bool) InstrFn {
}, },
0b11 => { 0b11 => {
// LDRSH // LDRSH
cpu.r[rd] = if (address & 1 == 1) blk: { const value = if (address & 1 == 1) blk: {
break :blk sext(8, bus.read(u8, address)); break :blk sext(8, bus.read(u8, address));
} else blk: { } else blk: {
break :blk sext(16, bus.read(u16, address)); break :blk sext(16, bus.read(u16, address));
}; };
cpu.r[rd] = rotr(u32, value, 8 * (address & 1));
}, },
} }
} else { } else {

View File

@ -32,42 +32,42 @@ const RunKind = enum {
LimitedBusy, LimitedBusy,
}; };
pub fn run(kind: RunKind, quit: *Atomic(bool), fps: *FpsAverage, sched: *Scheduler, cpu: *Arm7tdmi) void { pub fn run(kind: RunKind, quit: *Atomic(bool), fps: *FpsAverage, sched: *Scheduler, cpu: *Arm7tdmi, bus: *Bus) void {
switch (kind) { switch (kind) {
.Unlimited => runUnsync(quit, sched, cpu), .Unlimited => runUnsync(quit, sched, cpu, bus),
.Limited => runSync(quit, sched, cpu), .Limited => runSync(quit, sched, cpu, bus),
.UnlimitedFPS => runUnsyncFps(quit, fps, sched, cpu), .UnlimitedFPS => runUnsyncFps(quit, fps, sched, cpu, bus),
.LimitedFPS => runSyncFps(quit, fps, sched, cpu), .LimitedFPS => runSyncFps(quit, fps, sched, cpu, bus),
.LimitedBusy => runBusyLoop(quit, sched, cpu), .LimitedBusy => runBusyLoop(quit, sched, cpu, bus),
} }
} }
pub fn runFrame(sched: *Scheduler, cpu: *Arm7tdmi) void { pub fn runFrame(sched: *Scheduler, cpu: *Arm7tdmi, bus: *Bus) void {
const frame_end = sched.tick + cycles_per_frame; const frame_end = sched.tick + cycles_per_frame;
while (sched.tick < frame_end) { while (sched.tick < frame_end) {
if (cpu.bus.io.haltcnt == .Halt) sched.tick += 1; if (bus.io.haltcnt == .Halt) sched.tick += 1;
if (cpu.bus.io.haltcnt == .Execute) cpu.step(); if (bus.io.haltcnt == .Execute) cpu.step();
cpu.bus.handleDMATransfers(); bus.handleDMATransfers();
while (sched.tick >= sched.nextTimestamp()) { while (sched.tick >= sched.nextTimestamp()) {
sched.handleEvent(cpu); sched.handleEvent(cpu, bus);
} }
} }
} }
pub fn runUnsync(quit: *Atomic(bool), sched: *Scheduler, cpu: *Arm7tdmi) void { pub fn runUnsync(quit: *Atomic(bool), sched: *Scheduler, cpu: *Arm7tdmi, bus: *Bus) void {
log.info("Unsynchronized EmuThread has begun", .{}); log.info("Unsynchronized EmuThread has begun", .{});
while (!quit.load(.Unordered)) runFrame(sched, cpu); while (!quit.load(.Unordered)) runFrame(sched, cpu, bus);
} }
pub fn runSync(quit: *Atomic(bool), sched: *Scheduler, cpu: *Arm7tdmi) void { pub fn runSync(quit: *Atomic(bool), sched: *Scheduler, cpu: *Arm7tdmi, bus: *Bus) void {
log.info("Synchronized EmuThread has begun", .{}); log.info("Synchronized EmuThread has begun", .{});
var timer = Timer.start() catch unreachable; var timer = Timer.start() catch unreachable;
var wake_time: u64 = frame_period; var wake_time: u64 = frame_period;
while (!quit.load(.Unordered)) { while (!quit.load(.Unordered)) {
runFrame(sched, cpu); runFrame(sched, cpu, bus);
// Put the Thread to Sleep + Backup Spin Loop // Put the Thread to Sleep + Backup Spin Loop
// This saves on resource usage when frame limiting // This saves on resource usage when frame limiting
@ -78,24 +78,24 @@ pub fn runSync(quit: *Atomic(bool), sched: *Scheduler, cpu: *Arm7tdmi) void {
} }
} }
pub fn runUnsyncFps(quit: *Atomic(bool), fps: *FpsAverage, sched: *Scheduler, cpu: *Arm7tdmi) void { pub fn runUnsyncFps(quit: *Atomic(bool), fps: *FpsAverage, sched: *Scheduler, cpu: *Arm7tdmi, bus: *Bus) void {
log.info("Unsynchronized EmuThread with FPS Tracking has begun", .{}); log.info("Unsynchronized EmuThread with FPS Tracking has begun", .{});
var fps_timer = Timer.start() catch unreachable; var fps_timer = Timer.start() catch unreachable;
while (!quit.load(.Unordered)) { while (!quit.load(.Unordered)) {
runFrame(sched, cpu); runFrame(sched, cpu, bus);
fps.add(fps_timer.lap()); fps.add(fps_timer.lap());
} }
} }
pub fn runSyncFps(quit: *Atomic(bool), fps: *FpsAverage, sched: *Scheduler, cpu: *Arm7tdmi) void { pub fn runSyncFps(quit: *Atomic(bool), fps: *FpsAverage, sched: *Scheduler, cpu: *Arm7tdmi, bus: *Bus) void {
log.info("Synchronized EmuThread has begun", .{}); log.info("Synchronized EmuThread has begun", .{});
var timer = Timer.start() catch unreachable; var timer = Timer.start() catch unreachable;
var fps_timer = Timer.start() catch unreachable; var fps_timer = Timer.start() catch unreachable;
var wake_time: u64 = frame_period; var wake_time: u64 = frame_period;
while (!quit.load(.Unordered)) { while (!quit.load(.Unordered)) {
runFrame(sched, cpu); runFrame(sched, cpu, bus);
// Put the Thread to Sleep + Backup Spin Loop // Put the Thread to Sleep + Backup Spin Loop
// This saves on resource usage when frame limiting // This saves on resource usage when frame limiting
@ -109,13 +109,13 @@ pub fn runSyncFps(quit: *Atomic(bool), fps: *FpsAverage, sched: *Scheduler, cpu:
} }
} }
pub fn runBusyLoop(quit: *Atomic(bool), sched: *Scheduler, cpu: *Arm7tdmi) void { pub fn runBusyLoop(quit: *Atomic(bool), sched: *Scheduler, cpu: *Arm7tdmi, bus: *Bus) void {
log.info("Run EmuThread with spin-loop sync", .{}); log.info("Run EmuThread with spin-loop sync", .{});
var timer = Timer.start() catch unreachable; var timer = Timer.start() catch unreachable;
var wake_time: u64 = frame_period; var wake_time: u64 = frame_period;
while (!quit.load(.Unordered)) { while (!quit.load(.Unordered)) {
runFrame(sched, cpu); runFrame(sched, cpu, bus);
spinLoop(&timer, wake_time); spinLoop(&timer, wake_time);
// Update to the new wake time // Update to the new wake time

View File

@ -92,8 +92,10 @@ pub fn main() anyerror!void {
defer scheduler.deinit(); defer scheduler.deinit();
const paths = .{ .bios = bios_path, .rom = rom_path, .save = save_path }; const paths = .{ .bios = bios_path, .rom = rom_path, .save = save_path };
var cpu = try Arm7tdmi.init(alloc, &scheduler, paths); var bus = try Bus.init(alloc, &scheduler, audio_dev, paths);
cpu.bus.apu.attachAudioDevice(audio_dev); defer bus.deinit();
var cpu = Arm7tdmi.init(&scheduler, &bus);
cpu.fastBoot(); cpu.fastBoot();
const log_file: ?File = if (enable_logging) blk: { const log_file: ?File = if (enable_logging) blk: {
@ -108,10 +110,10 @@ pub fn main() anyerror!void {
var emu_rate = FpsAverage.init(); var emu_rate = FpsAverage.init();
// Create Emulator Thread // Create Emulator Thread
const emu_thread = try Thread.spawn(.{}, emu.run, .{ .LimitedFPS, &quit, &emu_rate, &scheduler, &cpu }); const emu_thread = try Thread.spawn(.{}, emu.run, .{ .LimitedFPS, &quit, &emu_rate, &scheduler, &cpu, &bus });
defer emu_thread.join(); defer emu_thread.join();
const title = correctTitle(cpu.bus.pak.title); const title = correctTitle(bus.pak.title);
var title_buf: [0x20]u8 = std.mem.zeroes([0x20]u8); var title_buf: [0x20]u8 = std.mem.zeroes([0x20]u8);
const window_title = try std.fmt.bufPrint(&title_buf, "ZBA | {s}", .{title}); const window_title = try std.fmt.bufPrint(&title_buf, "ZBA | {s}", .{title});
@ -143,38 +145,36 @@ pub fn main() anyerror!void {
switch (event.type) { switch (event.type) {
SDL.SDL_QUIT => break :emu_loop, SDL.SDL_QUIT => break :emu_loop,
SDL.SDL_KEYDOWN => { SDL.SDL_KEYDOWN => {
const io = &cpu.bus.io;
const key_code = event.key.keysym.sym; const key_code = event.key.keysym.sym;
switch (key_code) { switch (key_code) {
SDL.SDLK_UP => io.keyinput.up.unset(), SDL.SDLK_UP => bus.io.keyinput.up.unset(),
SDL.SDLK_DOWN => io.keyinput.down.unset(), SDL.SDLK_DOWN => bus.io.keyinput.down.unset(),
SDL.SDLK_LEFT => io.keyinput.left.unset(), SDL.SDLK_LEFT => bus.io.keyinput.left.unset(),
SDL.SDLK_RIGHT => io.keyinput.right.unset(), SDL.SDLK_RIGHT => bus.io.keyinput.right.unset(),
SDL.SDLK_x => io.keyinput.a.unset(), SDL.SDLK_x => bus.io.keyinput.a.unset(),
SDL.SDLK_z => io.keyinput.b.unset(), SDL.SDLK_z => bus.io.keyinput.b.unset(),
SDL.SDLK_a => io.keyinput.shoulder_l.unset(), SDL.SDLK_a => bus.io.keyinput.shoulder_l.unset(),
SDL.SDLK_s => io.keyinput.shoulder_r.unset(), SDL.SDLK_s => bus.io.keyinput.shoulder_r.unset(),
SDL.SDLK_RETURN => io.keyinput.start.unset(), SDL.SDLK_RETURN => bus.io.keyinput.start.unset(),
SDL.SDLK_RSHIFT => io.keyinput.select.unset(), SDL.SDLK_RSHIFT => bus.io.keyinput.select.unset(),
else => {}, else => {},
} }
}, },
SDL.SDL_KEYUP => { SDL.SDL_KEYUP => {
const io = &cpu.bus.io;
const key_code = event.key.keysym.sym; const key_code = event.key.keysym.sym;
switch (key_code) { switch (key_code) {
SDL.SDLK_UP => io.keyinput.up.set(), SDL.SDLK_UP => bus.io.keyinput.up.set(),
SDL.SDLK_DOWN => io.keyinput.down.set(), SDL.SDLK_DOWN => bus.io.keyinput.down.set(),
SDL.SDLK_LEFT => io.keyinput.left.set(), SDL.SDLK_LEFT => bus.io.keyinput.left.set(),
SDL.SDLK_RIGHT => io.keyinput.right.set(), SDL.SDLK_RIGHT => bus.io.keyinput.right.set(),
SDL.SDLK_x => io.keyinput.a.set(), SDL.SDLK_x => bus.io.keyinput.a.set(),
SDL.SDLK_z => io.keyinput.b.set(), SDL.SDLK_z => bus.io.keyinput.b.set(),
SDL.SDLK_a => io.keyinput.shoulder_l.set(), SDL.SDLK_a => bus.io.keyinput.shoulder_l.set(),
SDL.SDLK_s => io.keyinput.shoulder_r.set(), SDL.SDLK_s => bus.io.keyinput.shoulder_r.set(),
SDL.SDLK_RETURN => io.keyinput.start.set(), SDL.SDLK_RETURN => bus.io.keyinput.start.set(),
SDL.SDLK_RSHIFT => io.keyinput.select.set(), SDL.SDLK_RSHIFT => bus.io.keyinput.select.set(),
else => {}, else => {},
} }
}, },
@ -183,7 +183,7 @@ pub fn main() anyerror!void {
} }
// FIXME: Is it OK just to copy the Emulator's Frame Buffer to SDL? // FIXME: Is it OK just to copy the Emulator's Frame Buffer to SDL?
const buf_ptr = cpu.bus.ppu.framebuf.ptr; const buf_ptr = bus.ppu.framebuf.ptr;
_ = SDL.SDL_UpdateTexture(texture, null, buf_ptr, framebuf_pitch); _ = SDL.SDL_UpdateTexture(texture, null, buf_ptr, framebuf_pitch);
_ = SDL.SDL_RenderCopy(renderer, texture, null, null); _ = SDL.SDL_RenderCopy(renderer, texture, null, null);
SDL.SDL_RenderPresent(renderer); SDL.SDL_RenderPresent(renderer);

View File

@ -366,7 +366,7 @@ pub const Ppu = struct {
} }
// See if HBlank DMA is present and not enabled // See if HBlank DMA is present and not enabled
pollBlankingDma(&cpu.bus, .HBlank); pollBlankingDma(cpu.bus, .HBlank);
self.dispstat.hblank.set(); self.dispstat.hblank.set();
self.sched.push(.HBlank, self.sched.now() + (68 * 4) - late); self.sched.push(.HBlank, self.sched.now() + (68 * 4) - late);
@ -403,7 +403,7 @@ pub const Ppu = struct {
} }
// See if Vblank DMA is present and not enabled // See if Vblank DMA is present and not enabled
pollBlankingDma(&cpu.bus, .VBlank); pollBlankingDma(cpu.bus, .VBlank);
} }
if (scanline == 227) self.dispstat.vblank.unset(); if (scanline == 227) self.dispstat.vblank.unset();

View File

@ -29,7 +29,7 @@ pub const Scheduler = struct {
return self.tick; return self.tick;
} }
pub fn handleEvent(self: *Self, cpu: *Arm7tdmi) void { pub fn handleEvent(self: *Self, cpu: *Arm7tdmi, bus: *Bus) void {
if (self.queue.removeOrNull()) |event| { if (self.queue.removeOrNull()) |event| {
const late = self.tick - event.tick; const late = self.tick - event.tick;
@ -40,19 +40,19 @@ pub const Scheduler = struct {
}, },
.Draw => { .Draw => {
// The end of a VDraw // The end of a VDraw
cpu.bus.ppu.drawScanline(); bus.ppu.drawScanline();
cpu.bus.ppu.handleHDrawEnd(cpu, late); bus.ppu.handleHDrawEnd(cpu, late);
}, },
.TimerOverflow => |id| { .TimerOverflow => |id| {
switch (id) { switch (id) {
0 => cpu.bus.tim._0.handleOverflow(cpu, late), 0 => bus.tim._0.handleOverflow(cpu, late),
1 => cpu.bus.tim._1.handleOverflow(cpu, late), 1 => bus.tim._1.handleOverflow(cpu, late),
2 => cpu.bus.tim._2.handleOverflow(cpu, late), 2 => bus.tim._2.handleOverflow(cpu, late),
3 => cpu.bus.tim._3.handleOverflow(cpu, late), 3 => bus.tim._3.handleOverflow(cpu, late),
} }
}, },
.HBlank => cpu.bus.ppu.handleHBlankEnd(cpu, late), // The end of a HBlank .HBlank => bus.ppu.handleHBlankEnd(cpu, late), // The end of a HBlank
.VBlank => cpu.bus.ppu.handleHDrawEnd(cpu, late), // The end of a VBlank .VBlank => bus.ppu.handleHDrawEnd(cpu, late), // The end of a VBlank
} }
} }
} }