diff --git a/src/Bus.zig b/src/Bus.zig index da3876b..198fc4f 100644 --- a/src/Bus.zig +++ b/src/Bus.zig @@ -7,14 +7,15 @@ const Ppu = @import("ppu.zig").Ppu; const Scheduler = @import("scheduler.zig").Scheduler; const Allocator = std.mem.Allocator; +const Self = @This(); pak: GamePak, bios: Bios, ppu: Ppu, io: Io, -pub fn init(alloc: Allocator, sched: *Scheduler, path: []const u8) !@This() { - return @This(){ +pub fn init(alloc: Allocator, sched: *Scheduler, path: []const u8) !Self { + return Self{ .pak = try GamePak.init(alloc, path), .bios = try Bios.init(alloc, "./bin/gba_bios.bin"), // TODO: don't hardcode this + bundle open-sorce Boot ROM .ppu = try Ppu.init(alloc, sched), @@ -22,13 +23,13 @@ pub fn init(alloc: Allocator, sched: *Scheduler, path: []const u8) !@This() { }; } -pub fn deinit(self: @This()) void { +pub fn deinit(self: Self) void { self.pak.deinit(); self.bios.deinit(); self.ppu.deinit(); } -pub fn read32(self: *const @This(), addr: u32) u32 { +pub fn read32(self: *const Self, addr: u32) u32 { return switch (addr) { // General Internal Memory 0x0000_0000...0x0000_3FFF => self.bios.get32(@as(usize, addr)), @@ -53,7 +54,7 @@ pub fn read32(self: *const @This(), addr: u32) u32 { }; } -pub fn write32(self: *@This(), addr: u32, word: u32) void { +pub fn write32(self: *Self, addr: u32, word: u32) void { // TODO: write32 can write to GamePak Flash switch (addr) { @@ -71,7 +72,7 @@ pub fn write32(self: *@This(), addr: u32, word: u32) void { } } -pub fn read16(self: *const @This(), addr: u32) u16 { +pub fn read16(self: *const Self, addr: u32) u16 { return switch (addr) { // General Internal Memory 0x0000_0000...0x0000_3FFF => self.bios.get16(@as(usize, addr)), @@ -96,7 +97,7 @@ pub fn read16(self: *const @This(), addr: u32) u16 { }; } -pub fn write16(self: *@This(), addr: u32, halfword: u16) void { +pub fn write16(self: *Self, addr: u32, halfword: u16) void { // TODO: write16 can write to GamePak Flash switch (addr) { // General Internal Memory @@ -113,7 +114,7 @@ pub fn write16(self: *@This(), addr: u32, halfword: u16) void { } } -pub fn read8(self: *const @This(), addr: u32) u8 { +pub fn read8(self: *const Self, addr: u32) u8 { return switch (addr) { // General Internal Memory 0x0000_0000...0x0000_3FFF => self.bios.get8(@as(usize, addr)), @@ -139,7 +140,7 @@ pub fn read8(self: *const @This(), addr: u32) u8 { }; } -pub fn write8(_: *@This(), addr: u32, byte: u8) void { +pub fn write8(_: *Self, addr: u32, byte: u8) void { switch (addr) { // General Internal Memory 0x0200_0000...0x0203_FFFF => std.debug.panic("[Bus:8] write 0x{X:} to 0x{X:} in IWRAM", .{ byte, addr }), diff --git a/src/cpu.zig b/src/cpu.zig index eb7c0ec..ae61306 100644 --- a/src/cpu.zig +++ b/src/cpu.zig @@ -16,12 +16,14 @@ pub const InstrFn = fn (*Arm7tdmi, *Bus, u32) void; const arm_lut: [0x1000]InstrFn = populate(); pub const Arm7tdmi = struct { + const Self = @This(); + r: [16]u32, sched: *Scheduler, bus: *Bus, cpsr: CPSR, - pub fn init(sched: *Scheduler, bus: *Bus) @This() { + pub fn init(sched: *Scheduler, bus: *Bus) Self { return .{ .r = [_]u32{0x00} ** 16, .sched = sched, @@ -30,7 +32,7 @@ pub const Arm7tdmi = struct { }; } - pub fn skipBios(self: *@This()) void { + pub fn skipBios(self: *Self) void { self.r[0] = 0x08000000; self.r[1] = 0x000000EA; // GPRs 2 -> 12 *should* already be 0 initialized @@ -43,7 +45,7 @@ pub const Arm7tdmi = struct { self.cpsr.raw = 0x6000001F; } - pub inline fn step(self: *@This()) u64 { + pub inline fn step(self: *Self) u64 { const opcode = self.fetch(); // self.mgbaLog(opcode); @@ -51,17 +53,17 @@ pub const Arm7tdmi = struct { return 1; } - fn fetch(self: *@This()) u32 { + fn fetch(self: *Self) u32 { const word = self.bus.read32(self.r[15]); self.r[15] += 4; return word; } - pub fn fakePC(self: *const @This()) u32 { + pub fn fakePC(self: *const Self) u32 { return self.r[15] + 4; } - fn mgbaLog(self: *const @This(), opcode: u32) void { + fn mgbaLog(self: *const Self, opcode: u32) void { const stderr = std.io.getStdErr().writer(); std.debug.getStderrMutex().lock(); defer std.debug.getStderrMutex().unlock(); diff --git a/src/ppu.zig b/src/ppu.zig index e49f4af..3db2db5 100644 --- a/src/ppu.zig +++ b/src/ppu.zig @@ -11,17 +11,19 @@ pub const buf_pitch = width * @sizeOf(u16); const buf_len = buf_pitch * height; pub const Ppu = struct { + const Self = @This(); + vram: Vram, palette: Palette, sched: *Scheduler, frame_buf: []u8, alloc: Allocator, - pub fn init(alloc: Allocator, sched: *Scheduler) !@This() { + pub fn init(alloc: Allocator, sched: *Scheduler) !Self { // Queue first Hblank - sched.push(.{ .kind = .Draw, .tick = sched.tick + 240 * 4 }); + sched.push(.Draw, sched.tick + (240 * 4)); - return @This(){ + return Self{ .vram = try Vram.init(alloc), .palette = try Palette.init(alloc), .sched = sched, @@ -30,13 +32,13 @@ pub const Ppu = struct { }; } - pub fn deinit(self: @This()) void { + pub fn deinit(self: Self) void { self.alloc.free(self.frame_buf); self.vram.deinit(); self.palette.deinit(); } - pub fn drawScanline(self: *@This(), io: *const Io) void { + pub fn drawScanline(self: *Self, io: *const Io) void { const bg_mode = io.dispcnt.bg_mode.read(); const scanline = io.vcount.scanline.read(); @@ -54,77 +56,81 @@ pub const Ppu = struct { }; const Palette = struct { + const Self = @This(); + buf: []u8, alloc: Allocator, - fn init(alloc: Allocator) !@This() { - return @This(){ + fn init(alloc: Allocator) !Self { + return Self{ .buf = try alloc.alloc(u8, 0x400), .alloc = alloc, }; } - fn deinit(self: @This()) void { + fn deinit(self: Self) void { self.alloc.free(self.buf); } - pub inline fn get32(self: *const @This(), idx: usize) u32 { + pub inline fn get32(self: *const Self, idx: usize) u32 { return (@as(u32, self.get16(idx + 2)) << 16) | @as(u32, self.get16(idx)); } - pub inline fn set32(self: *@This(), idx: usize, word: u32) void { + pub inline fn set32(self: *Self, idx: usize, word: u32) void { self.set16(idx + 2, @truncate(u16, word >> 16)); self.set16(idx, @truncate(u16, word)); } - pub inline fn get16(self: *const @This(), idx: usize) u16 { + pub inline fn get16(self: *const Self, idx: usize) u16 { return (@as(u16, self.buf[idx + 1]) << 8) | @as(u16, self.buf[idx]); } - pub inline fn set16(self: *@This(), idx: usize, halfword: u16) void { + pub inline fn set16(self: *Self, idx: usize, halfword: u16) void { self.buf[idx + 1] = @truncate(u8, halfword >> 8); self.buf[idx] = @truncate(u8, halfword); } - pub inline fn get8(self: *const @This(), idx: usize) u8 { + pub inline fn get8(self: *const Self, idx: usize) u8 { return self.buf[idx]; } }; const Vram = struct { + const Self = @This(); + buf: []u8, alloc: Allocator, - fn init(alloc: Allocator) !@This() { - return @This(){ + fn init(alloc: Allocator) !Self { + return Self{ .buf = try alloc.alloc(u8, 0x18000), .alloc = alloc, }; } - fn deinit(self: @This()) void { + fn deinit(self: Self) void { self.alloc.free(self.buf); } - pub inline fn get32(self: *const @This(), idx: usize) u32 { + pub inline fn get32(self: *const Self, idx: usize) u32 { return (@as(u32, self.get16(idx + 2)) << 16) | @as(u32, self.get16(idx)); } - pub inline fn set32(self: *@This(), idx: usize, word: u32) void { + pub inline fn set32(self: *Self, idx: usize, word: u32) void { self.set16(idx + 2, @truncate(u16, word >> 16)); self.set16(idx, @truncate(u16, word)); } - pub inline fn get16(self: *const @This(), idx: usize) u16 { + pub inline fn get16(self: *const Self, idx: usize) u16 { return (@as(u16, self.buf[idx + 1]) << 8) | @as(u16, self.buf[idx]); } - pub inline fn set16(self: *@This(), idx: usize, halfword: u16) void { + pub inline fn set16(self: *Self, idx: usize, halfword: u16) void { self.buf[idx + 1] = @truncate(u8, halfword >> 8); self.buf[idx] = @truncate(u8, halfword); } - pub inline fn get8(self: *const @This(), idx: usize) u8 { + pub inline fn get8(self: *const Self, idx: usize) u8 { return self.buf[idx]; } }; diff --git a/src/scheduler.zig b/src/scheduler.zig index 4bda5a6..6e91fb5 100644 --- a/src/scheduler.zig +++ b/src/scheduler.zig @@ -8,29 +8,28 @@ const PriorityQueue = std.PriorityQueue; const Allocator = std.mem.Allocator; pub const Scheduler = struct { + const Self = @This(); + tick: u64, queue: PriorityQueue(Event, void, lessThan), - pub fn init(alloc: Allocator) @This() { - var scheduler = Scheduler{ .tick = 0, .queue = PriorityQueue(Event, void, lessThan).init(alloc, {}) }; + pub fn init(alloc: Allocator) Self { + var sched = Self{ .tick = 0, .queue = PriorityQueue(Event, void, lessThan).init(alloc, {}) }; + sched.push(.HeatDeath, std.math.maxInt(u64)); - scheduler.queue.add(.{ - .kind = EventKind.HeatDeath, - .tick = std.math.maxInt(u64), - }) catch unreachable; - - return scheduler; + return sched; } - pub fn deinit(self: @This()) void { + pub fn deinit(self: Self) void { self.queue.deinit(); } - pub fn handleEvent(self: *@This(), _: *Arm7tdmi, bus: *Bus) void { + pub fn handleEvent(self: *Self, _: *Arm7tdmi, bus: *Bus) void { const should_handle = if (self.queue.peek()) |e| self.tick >= e.tick else false; if (should_handle) { const event = self.queue.remove(); + std.log.info("[Scheduler] Handle {} at {} ticks", .{ event.kind, self.tick }); switch (event.kind) { .HeatDeath => { @@ -49,11 +48,11 @@ pub const Scheduler = struct { if (new_scanline < 160) { // Transitioning to another Draw - self.push(.{ .kind = .Draw, .tick = self.tick + (240 * 4) }); + self.push(.Draw, self.tick + (240 * 4)); } else { // Transitioning to a Vblank bus.io.dispstat.vblank.set(); - self.push(.{ .kind = .VBlank, .tick = self.tick + (308 * 4) }); + self.push(.VBlank, self.tick + (308 * 4)); } }, .Draw => { @@ -61,7 +60,7 @@ pub const Scheduler = struct { // Transitioning to a Hblank bus.io.dispstat.hblank.set(); - self.push(.{ .kind = .HBlank, .tick = self.tick + (68 * 4) }); + self.push(.HBlank, self.tick + (68 * 4)); }, .VBlank => { // The end of a Vblank @@ -72,24 +71,24 @@ pub const Scheduler = struct { if (new_scanline < 228) { // Transition to another Vblank - self.push(.{ .kind = .VBlank, .tick = self.tick + (308 * 4) }); + self.push(.VBlank, self.tick + (308 * 4)); } else { // Transition to another Draw bus.io.vcount.scanline.write(0); // Reset Scanline bus.io.dispstat.vblank.unset(); - self.push(.{ .kind = .Draw, .tick = self.tick + (240 * 4) }); + self.push(.Draw, self.tick + (240 * 4)); } }, } } } - pub inline fn push(self: *@This(), event: Event) void { - self.queue.add(event) catch unreachable; + pub inline fn push(self: *Self, kind: EventKind, end: u64) void { + self.queue.add(.{ .kind = kind, .tick = end }) catch unreachable; } - pub inline fn nextTimestamp(self: *@This()) u64 { + pub inline fn nextTimestamp(self: *Self) u64 { if (self.queue.peek()) |e| { return e.tick; } else unreachable;