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