chore: improve code clarity
This commit is contained in:
		
							
								
								
									
										19
									
								
								src/Bus.zig
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								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 }), | ||||
|   | ||||
							
								
								
									
										14
									
								
								src/cpu.zig
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								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(); | ||||
|   | ||||
							
								
								
									
										48
									
								
								src/ppu.zig
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								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]; | ||||
|     } | ||||
| }; | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user